Nemubot had now a shell.
server.py extends now Thread
This commit is contained in:
parent
3aaa4446b4
commit
d7b4e198a5
|
@ -38,6 +38,9 @@ class ModuleBase:
|
||||||
def load(self):
|
def load(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
return self.save() and self.load()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -64,3 +67,6 @@ class ModuleBase:
|
||||||
|
|
||||||
def parselisten(self, msg):
|
def parselisten(self, msg):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def parseadmin(self, msg):
|
||||||
|
return False
|
||||||
|
|
18
message.py
18
message.py
|
@ -16,7 +16,7 @@ BANLIST = []
|
||||||
CREDITS = {}
|
CREDITS = {}
|
||||||
filename = ""
|
filename = ""
|
||||||
|
|
||||||
def load_module(datas_path):
|
def load(datas_path):
|
||||||
global BANLIST, CREDITS, filename
|
global BANLIST, CREDITS, filename
|
||||||
CREDITS = dict ()
|
CREDITS = dict ()
|
||||||
|
|
||||||
|
@ -341,21 +341,17 @@ class Message:
|
||||||
self.send_snd("No help for command %s" % self.cmd[1])
|
self.send_snd("No help for command %s" % self.cmd[1])
|
||||||
else:
|
else:
|
||||||
self.send_snd("Pour me demander quelque chose, commencez votre message par mon nom ; je réagis à certain messages commençant par !, consulter l'aide de chaque module :")
|
self.send_snd("Pour me demander quelque chose, commencez votre message par mon nom ; je réagis à certain messages commençant par !, consulter l'aide de chaque module :")
|
||||||
for im in mods.keys():
|
for im in mods:
|
||||||
self.send_snd(" - !help %s: %s" % (im, mods[im].help_tiny ()))
|
self.send_snd(" - !help %s: %s" % (im.name, im.help_tiny ()))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for im in mods.keys():
|
for im in mods:
|
||||||
if im == "alias":
|
if im.parseanswer(self):
|
||||||
continue
|
|
||||||
if mods[im].parseanswer(self):
|
|
||||||
return
|
return
|
||||||
if mods["alias"].parseanswer(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for im in mods.keys():
|
for im in mods:
|
||||||
if mods[im].parselisten(self):
|
if im.parselisten(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
41
nemubot.py
41
nemubot.py
|
@ -5,24 +5,22 @@ import sys
|
||||||
import signal
|
import signal
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import imp
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from xml.dom.minidom import parse
|
from xml.dom.minidom import parse
|
||||||
|
|
||||||
imports = ["birthday", "qd", "events", "youtube", "watchWebsite", "soutenance", "whereis", "alias"]
|
|
||||||
imports_launch = ["watchWebsite", "events"]
|
|
||||||
mods = {}
|
|
||||||
import server, message
|
|
||||||
|
|
||||||
if len(sys.argv) != 2 and len(sys.argv) != 3:
|
if len(sys.argv) != 2 and len(sys.argv) != 3:
|
||||||
print ("This script takes exactly 1 arg: a XML config file")
|
print ("This script takes exactly 1 arg: a XML config file")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
imports = ["birthday", "qd", "events", "youtube", "watchWebsite", "soutenance", "whereis", "alias"]
|
||||||
|
imports_launch = ["watchWebsite", "events"]
|
||||||
|
mods = {}
|
||||||
|
|
||||||
def onSignal(signum, frame):
|
def onClose():
|
||||||
print ("\nSIGINT receive, saving states and close")
|
"""Call when the bot quit; saving all modules"""
|
||||||
|
|
||||||
for imp in mods.keys():
|
for imp in mods.keys():
|
||||||
mods[imp].save_module ()
|
mods[imp].save_module ()
|
||||||
|
|
||||||
|
@ -33,36 +31,43 @@ def onSignal(signum, frame):
|
||||||
message.save_module ()
|
message.save_module ()
|
||||||
|
|
||||||
sys.exit (0)
|
sys.exit (0)
|
||||||
|
|
||||||
|
def onSignal(signum, frame):
|
||||||
|
print ("\nSIGINT receive, saving states and close")
|
||||||
|
onClose()
|
||||||
signal.signal(signal.SIGINT, onSignal)
|
signal.signal(signal.SIGINT, onSignal)
|
||||||
|
|
||||||
|
#Define working directory
|
||||||
if len(sys.argv) == 3:
|
if len(sys.argv) == 3:
|
||||||
basedir = sys.argv[2]
|
basedir = sys.argv[2]
|
||||||
else:
|
else:
|
||||||
basedir = "./"
|
basedir = "./"
|
||||||
|
|
||||||
|
#Load base modules
|
||||||
|
server = __import__ ("server")
|
||||||
|
message = __import__ ("message")
|
||||||
|
message.load (basedir + "/datas/")
|
||||||
|
|
||||||
|
#Read configuration XML file
|
||||||
dom = parse(sys.argv[1])
|
dom = parse(sys.argv[1])
|
||||||
config = dom.getElementsByTagName('config')[0]
|
config = dom.getElementsByTagName('config')[0]
|
||||||
servers = dict ()
|
servers = dict ()
|
||||||
|
|
||||||
message.load_module (basedir + "/datas/")
|
#Load modules
|
||||||
|
|
||||||
for imp in imports:
|
for imp in imports:
|
||||||
mod = __import__ (imp)
|
mod = __import__ (imp)
|
||||||
mods[imp] = mod
|
mods[imp] = mod
|
||||||
mod.load_module (basedir + "/datas/")
|
|
||||||
|
|
||||||
for serveur in config.getElementsByTagName('server'):
|
for serveur in config.getElementsByTagName('server'):
|
||||||
srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname'))
|
srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname'))
|
||||||
srv.launch(mods, basedir + "/datas/")
|
srv.launch(mods, basedir + "/datas/")
|
||||||
servers[srv.id] = srv
|
servers[srv.id] = srv
|
||||||
|
|
||||||
for imp in imports_launch:
|
|
||||||
mod = __import__ (imp)
|
|
||||||
mod.launch (servers)
|
|
||||||
|
|
||||||
print ("Nemubot ready, my PID is %i!" % (os.getpid()))
|
print ("Nemubot ready, my PID is %i!" % (os.getpid()))
|
||||||
prompt=""
|
|
||||||
while prompt != "quit":
|
|
||||||
prompt=sys.stdin.readlines ()
|
|
||||||
|
|
||||||
sys.exit(0)
|
prompt = __import__ ("prompt")
|
||||||
|
while prompt.launch(servers):
|
||||||
|
imp.reload(prompt)
|
||||||
|
|
||||||
|
onClose()
|
||||||
|
|
149
prompt.py
Normal file
149
prompt.py
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import sys
|
||||||
|
import shlex
|
||||||
|
import traceback
|
||||||
|
import _thread
|
||||||
|
from xml.dom.minidom import parse
|
||||||
|
|
||||||
|
import server
|
||||||
|
|
||||||
|
selectedServer = None
|
||||||
|
MODS = list()
|
||||||
|
|
||||||
|
def parsecmd(msg):
|
||||||
|
"""Parse the command line"""
|
||||||
|
try:
|
||||||
|
cmds = shlex.split(msg)
|
||||||
|
if len(cmds) > 0:
|
||||||
|
cmds[0] = cmds[0].lower()
|
||||||
|
return cmds
|
||||||
|
except:
|
||||||
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
|
sys.stdout.write (traceback.format_exception_only(exc_type, exc_value)[0])
|
||||||
|
return None
|
||||||
|
|
||||||
|
def run(cmds, servers):
|
||||||
|
"""Launch the command"""
|
||||||
|
if cmds[0] in CAPS:
|
||||||
|
return CAPS[cmds[0]](cmds, servers)
|
||||||
|
else:
|
||||||
|
print ("Unknown command: `%s'" % cmds[0])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def getPS1():
|
||||||
|
"""Get the PS1 associated to the selected server"""
|
||||||
|
if selectedServer is None:
|
||||||
|
return "nemubot"
|
||||||
|
else:
|
||||||
|
return selectedServer.id
|
||||||
|
|
||||||
|
def launch(servers):
|
||||||
|
"""Launch the prompt"""
|
||||||
|
ret = ""
|
||||||
|
cmds = list()
|
||||||
|
while ret != "quit" and ret != "reset":
|
||||||
|
sys.stdout.write("\033[0;33m%s§\033[0m " % getPS1())
|
||||||
|
sys.stdout.flush()
|
||||||
|
try:
|
||||||
|
cmds = parsecmd(sys.stdin.readline().strip())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
cmds = parsecmd("quit")
|
||||||
|
if cmds is not None and len(cmds) > 0:
|
||||||
|
try:
|
||||||
|
ret = run(cmds, servers)
|
||||||
|
except:
|
||||||
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
|
sys.stdout.write (traceback.format_exception_only(exc_type, exc_value)[0])
|
||||||
|
return ret == "reset"
|
||||||
|
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# #
|
||||||
|
# Permorming functions #
|
||||||
|
# #
|
||||||
|
##########################
|
||||||
|
|
||||||
|
def load(cmds, servers):
|
||||||
|
if len(cmds) > 1:
|
||||||
|
for f in cmds[1:]:
|
||||||
|
dom = parse(f)
|
||||||
|
config = dom.getElementsByTagName('config')[0]
|
||||||
|
for serveur in config.getElementsByTagName('server'):
|
||||||
|
srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname'))
|
||||||
|
if srv.id not in servers:
|
||||||
|
servers[srv.id] = srv
|
||||||
|
print (" Server `%s' successfully added." % srv.id)
|
||||||
|
else:
|
||||||
|
print (" Server `%s' already added, skiped." % srv.id)
|
||||||
|
else:
|
||||||
|
print ("Not enough arguments. `load' takes an filename.")
|
||||||
|
return
|
||||||
|
|
||||||
|
def select(cmds, servers):
|
||||||
|
global selectedServer
|
||||||
|
if len(cmds) == 2 and cmds[1] != "None" and cmds[1] != "nemubot" and cmds[1] != "none":
|
||||||
|
if cmds[1] in servers:
|
||||||
|
selectedServer = servers[cmds[1]]
|
||||||
|
else:
|
||||||
|
print ("select: server `%s' not found." % cmds[1])
|
||||||
|
else:
|
||||||
|
selectedServer = None
|
||||||
|
return
|
||||||
|
|
||||||
|
def liste(cmds, servers):
|
||||||
|
if len(cmds) > 1:
|
||||||
|
for l in cmds[1:]:
|
||||||
|
l = l.lower()
|
||||||
|
if l == "server" or l == "servers":
|
||||||
|
for srv in servers.keys():
|
||||||
|
print (" - %s ;" % srv)
|
||||||
|
else:
|
||||||
|
print (" Unknown list `%s'" % l)
|
||||||
|
else:
|
||||||
|
print (" Please give a list to show: servers, ...")
|
||||||
|
|
||||||
|
def connect(cmds, servers):
|
||||||
|
if len(cmds) > 1:
|
||||||
|
for s in cmds[1:]:
|
||||||
|
if s in servers:
|
||||||
|
servers[s].launch(MODS)
|
||||||
|
else:
|
||||||
|
print ("connect: server `%s' not found." % s)
|
||||||
|
|
||||||
|
elif selectedServer is not None:
|
||||||
|
selectedServer.launch(MODS)
|
||||||
|
else:
|
||||||
|
print (" Please SELECT a server or give its name in argument.")
|
||||||
|
|
||||||
|
def disconnect(cmds, servers):
|
||||||
|
if len(cmds) > 1:
|
||||||
|
for s in cmds[1:]:
|
||||||
|
if s in servers:
|
||||||
|
if not servers[s].disconnect():
|
||||||
|
print ("disconnect: server `%s' already disconnected." % s)
|
||||||
|
else:
|
||||||
|
print ("disconnect: server `%s' not found." % s)
|
||||||
|
elif selectedServer is not None:
|
||||||
|
if not selectedServer.disconnect():
|
||||||
|
print ("disconnect: server `%s' already disconnected." % selectedServer.id)
|
||||||
|
else:
|
||||||
|
print (" Please SELECT a server or give its name in argument.")
|
||||||
|
|
||||||
|
def end(cmds, servers):
|
||||||
|
if cmds[0] == "reset":
|
||||||
|
return "reset"
|
||||||
|
else:
|
||||||
|
for srv in servers.keys():
|
||||||
|
servers[srv].disconnect()
|
||||||
|
return "quit"
|
||||||
|
|
||||||
|
#Register build-ins
|
||||||
|
CAPS = {
|
||||||
|
'quit': end,
|
||||||
|
'exit': end,
|
||||||
|
'reset': end,
|
||||||
|
'load': load,
|
||||||
|
'select': select,
|
||||||
|
'list': liste,
|
||||||
|
'connect': connect,
|
||||||
|
'disconnect': disconnect,
|
||||||
|
}
|
86
server.py
86
server.py
|
@ -1,18 +1,16 @@
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import socket
|
import socket
|
||||||
import _thread
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import message
|
import message
|
||||||
|
|
||||||
#class WaitedAnswer:
|
class Server(threading.Thread):
|
||||||
# def __init__(self, channel):
|
|
||||||
# self.channel = channel
|
|
||||||
# self.module
|
|
||||||
|
|
||||||
class Server:
|
|
||||||
def __init__(self, server, nick, owner, realname):
|
def __init__(self, server, nick, owner, realname):
|
||||||
|
self.stop = False
|
||||||
|
self.stopping = threading.Event()
|
||||||
|
self.connected = False
|
||||||
self.nick = nick
|
self.nick = nick
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
self.realname = realname
|
self.realname = realname
|
||||||
|
@ -30,8 +28,6 @@ class Server:
|
||||||
else:
|
else:
|
||||||
self.password = None
|
self.password = None
|
||||||
|
|
||||||
self.waited_answer = list()
|
|
||||||
|
|
||||||
self.listen_nick = True
|
self.listen_nick = True
|
||||||
self.partner = "nbr23"
|
self.partner = "nbr23"
|
||||||
|
|
||||||
|
@ -39,6 +35,8 @@ class Server:
|
||||||
for channel in server.getElementsByTagName('channel'):
|
for channel in server.getElementsByTagName('channel'):
|
||||||
self.channels.append(channel.getAttribute("name"))
|
self.channels.append(channel.getAttribute("name"))
|
||||||
|
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
return self.host + ":" + str(self.port)
|
return self.host + ":" + str(self.port)
|
||||||
|
@ -65,43 +63,35 @@ class Server:
|
||||||
self.send_msg (channel, msg, cmd, endl)
|
self.send_msg (channel, msg, cmd, endl)
|
||||||
|
|
||||||
|
|
||||||
def register_answer(self, channel, ):
|
|
||||||
self.waited_answer.append(channel)
|
|
||||||
|
|
||||||
def launch(self, mods, datas_dir):
|
|
||||||
self.datas_dir = datas_dir
|
|
||||||
_thread.start_new_thread(self.connect, (mods,))
|
|
||||||
|
|
||||||
def accepted_channel(self, channel):
|
def accepted_channel(self, channel):
|
||||||
if self.listen_nick:
|
if self.listen_nick:
|
||||||
return self.channels.count(channel) or channel == self.nick
|
return self.channels.count(channel) or channel == self.nick
|
||||||
else:
|
else:
|
||||||
return self.channels.count(channel)
|
return self.channels.count(channel)
|
||||||
|
|
||||||
def read(self, mods):
|
def disconnect(self):
|
||||||
self.readbuffer = "" #Here we store all the messages from server
|
if self.connected:
|
||||||
while 1:
|
self.stop = True
|
||||||
try:
|
self.s.shutdown(socket.SHUT_RDWR)
|
||||||
self.readbuffer = self.readbuffer + self.s.recv(1024).decode() #recieve server messages
|
self.stopping.wait()
|
||||||
except UnicodeDecodeError:
|
return True
|
||||||
print ("ERREUR de décodage unicode")
|
else:
|
||||||
continue
|
return False
|
||||||
temp = self.readbuffer.split("\n")
|
|
||||||
self.readbuffer = temp.pop( )
|
|
||||||
|
|
||||||
for line in temp:
|
def launch(self, mods):
|
||||||
msg = message.Message (self, line)
|
if not self.connected:
|
||||||
try:
|
self.stop = False
|
||||||
msg.treat (mods)
|
#self.datas_dir = datas_dir #DEPRECATED
|
||||||
except:
|
self.mods = mods
|
||||||
print ("Une erreur est survenue lors du traitement du message : %s"%line)
|
self.start()
|
||||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
else:
|
||||||
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
print (" Already connected.")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
def connect(self, mods):
|
|
||||||
self.s = socket.socket( ) #Create the socket
|
self.s = socket.socket( ) #Create the socket
|
||||||
self.s.connect((self.host, self.port)) #Connect to server
|
self.s.connect((self.host, self.port)) #Connect to server
|
||||||
|
self.stopping.clear()
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
if self.password != None:
|
if self.password != None:
|
||||||
self.s.send(b"PASS " + self.password.encode () + b"\r\n")
|
self.s.send(b"PASS " + self.password.encode () + b"\r\n")
|
||||||
|
@ -112,4 +102,26 @@ class Server:
|
||||||
self.s.send(("JOIN %s\r\n" % ' '.join (self.channels)).encode ())
|
self.s.send(("JOIN %s\r\n" % ' '.join (self.channels)).encode ())
|
||||||
print ("Listen to channels: %s" % ' '.join (self.channels))
|
print ("Listen to channels: %s" % ' '.join (self.channels))
|
||||||
|
|
||||||
self.read(mods)
|
readbuffer = "" #Here we store all the messages from server
|
||||||
|
while not self.stop:
|
||||||
|
try:
|
||||||
|
readbuffer = readbuffer + self.s.recv(1024).decode() #recieve server messages
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print ("ERREUR de décodage unicode")
|
||||||
|
continue
|
||||||
|
temp = readbuffer.split("\n")
|
||||||
|
readbuffer = temp.pop( )
|
||||||
|
|
||||||
|
for line in temp:
|
||||||
|
msg = message.Message (self, line)
|
||||||
|
try:
|
||||||
|
msg.treat (self.mods)
|
||||||
|
except:
|
||||||
|
print ("Une erreur est survenue lors du traitement du message : %s"%line)
|
||||||
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
|
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
||||||
|
self.connected = False
|
||||||
|
print ("Server `%s' successfully stopped." % self.id)
|
||||||
|
self.stopping.set()
|
||||||
|
#Rearm Thread
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user