From 7a91c49acf460cf941eecd6503972ccc0a5384aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 23 Jun 2012 13:38:34 +0200 Subject: [PATCH] Add hotswap server reload --- prompt.py | 17 ++++++++++ server.py | 95 ++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 80 insertions(+), 32 deletions(-) diff --git a/prompt.py b/prompt.py index e0cc6db..4ab9c88 100644 --- a/prompt.py +++ b/prompt.py @@ -275,6 +275,22 @@ def connect(cmds, servers): else: print (" Please SELECT a server or give its name in argument.") +def hotswap(cmds, servers): + """Reload a server class""" + global MODS, selectedServer + if len(cmds) > 1: + print ("hotswap: apply only on selected server") + elif selectedServer is not None: + del servers[selectedServer.id] + srv = server.Server(selectedServer.node, selectedServer.nick, selectedServer.owner, selectedServer.realname, selectedServer.s) + srv.update_mods(MODS) + servers[srv.id] = srv + selectedServer.kill() + selectedServer = srv + selectedServer.start() + else: + print (" Please SELECT a server or give its name in argument.") + def join(cmds, servers): """Join or leave a channel""" rd = 1 @@ -382,6 +398,7 @@ CAPS = { 'exit': end, #Alias for quit 'reset': end, #Reload the prompt 'load': load, #Load a servers or module configuration file + 'hotswap': hotswap, #Reload the server class without closing the socket 'close': close, #Disconnect and remove a server from the list 'unload': unload, #Unload a module and remove it from the list 'select': select, #Select a server diff --git a/server.py b/server.py index c1038c8..ec5fdad 100644 --- a/server.py +++ b/server.py @@ -9,36 +9,52 @@ message = __import__("message") imp.reload(message) class Server(threading.Thread): - def __init__(self, server, nick, owner, realname): + def __init__(self, node, nick, owner, realname, socket = None): self.stop = False self.stopping = threading.Event() - self.connected = False self.nick = nick self.owner = owner self.realname = realname - - if server.hasAttribute("server"): - self.host = server.getAttribute("server") - else: - self.host = "localhost" - if server.hasAttribute("port"): - self.port = int(server.getAttribute("port")) - else: - self.port = 6667 - if server.hasAttribute("password"): - self.password = server.getAttribute("password") - else: - self.password = None + self.s = socket + self.connected = self.s is not None + self.node = node self.listen_nick = True - self.partner = "nbr23" self.channels = list() - for channel in server.getChilds(): + for channel in node.getNodes("channel"): self.channels.append(channel.getAttribute("name")) threading.Thread.__init__(self) + @property + def host(self): + if self.node.hasAttribute("server"): + return self.node["server"] + else: + return "localhost" + + @property + def port(self): + if self.node.hasAttribute("port"): + return self.node.getInt("port") + else: + return "6667" + + @property + def password(self): + if self.node.hasAttribute("password"): + return self.node["password"] + else: + return None + + @property + def partner(self): + if self.node.hasAttribute("partner"): + return self.node["partner"] + else: + return None + @property def id(self): return self.host + ":" + str(self.port) @@ -50,6 +66,8 @@ class Server(threading.Thread): self.s.send ((":%s %s %s :%s%s" % (me, cmd, to, line, endl)).encode ()) def send_msg_final(self, channel, msg, cmd = "PRIVMSG", endl = "\r\n"): + if channel == self.nick: + print ("\033[1;35mWarning:\033[0m Nemubot talks to himself: %s" % msg) if msg is not None and channel is not None: for line in msg.split("\n"): if line != "": @@ -86,6 +104,17 @@ class Server(threading.Thread): else: return False + def kill(self): + if self.connected: + self.stop = True + self.connected = False + #Send a message in order to close the socket + self.s.send(("WHO %s\r\n" % self.nick).encode ()) + self.stopping.wait() + return True + else: + return False + def join(self, channel): if channel is not None and self.connected: self.channels.append(channel) @@ -114,20 +143,21 @@ class Server(threading.Thread): print (" Already connected.") def run(self): - self.s = socket.socket() #Create the socket - self.s.connect((self.host, self.port)) #Connect to server - self.stopping.clear() - self.connected = True + if not self.connected: + self.s = socket.socket() #Create the socket + self.s.connect((self.host, self.port)) #Connect to server + self.stopping.clear() + self.connected = True - if self.password != None: - self.s.send(b"PASS " + self.password.encode () + b"\r\n") - self.s.send(("NICK %s\r\n" % self.nick).encode ()) - self.s.send(("USER %s %s bla :%s\r\n" % (self.nick, self.host, self.realname)).encode ()) - print ("Connection to %s:%d completed" % (self.host, self.port)) + if self.password != None: + self.s.send(b"PASS " + self.password.encode () + b"\r\n") + self.s.send(("NICK %s\r\n" % self.nick).encode ()) + self.s.send(("USER %s %s bla :%s\r\n" % (self.nick, self.host, self.realname)).encode ()) + print ("Connection to %s:%d completed" % (self.host, self.port)) - if len(self.channels) > 0: - self.s.send(("JOIN %s\r\n" % ' '.join (self.channels)).encode ()) - print ("Listen to channels: %s" % ' '.join (self.channels)) + if len(self.channels) > 0: + self.s.send(("JOIN %s\r\n" % ' '.join (self.channels)).encode ()) + print ("Listen to channels: %s" % ' '.join (self.channels)) readbuffer = "" #Here we store all the messages from server while not self.stop: @@ -154,9 +184,10 @@ class Server(threading.Thread): print ("\033[1;31mERROR:\033[0m occurred during the processing of the message: %s"%line) exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback) - self.s.close() - self.connected = False - print ("Server `%s' successfully stopped." % self.id) + if self.connected: + self.s.close() + self.connected = False + print ("Server `%s' successfully stopped." % self.id) self.stopping.set() #Rearm Thread threading.Thread.__init__(self)