From 176e8a48e716628c4d9a2e6aa95bd779b1734c7c Mon Sep 17 00:00:00 2001 From: c1de0x Date: Sun, 6 May 2012 23:21:23 -0700 Subject: [PATCH] config,irc,thud: use new config mechanism as per #5 --- config.py | 20 ++---- irc.py | 5 +- thud.py | 197 ++++++++++++------------------------------------------ 3 files changed, 50 insertions(+), 172 deletions(-) diff --git a/config.py b/config.py index aa727c7..99a272e 100644 --- a/config.py +++ b/config.py @@ -8,7 +8,6 @@ def __init__(self,parent=None, data=None,filename=None): self._filename = filename if self._filename: self.readfile() - print self._data self._children = [] self._parse() @@ -85,6 +84,10 @@ def get_with_fallback(self, key,default=None): return self._parent.get_with_fallback(key,default) return default + def get(self, key, default=None): + if key in self._data: + return self._data[key] + return default def __repr__(self): res = "" for k,v in self._data.items(): @@ -102,19 +105,4 @@ def __repr__(self): -x = Config(filename="c1.user") -print "-----" - -y = x.by_path("networks/ref=f0f/channels/name=#f0f1") -#print y -#print y.get_root() -x.staatat = 1 -print x.staatat -print y.staatat - -print -print -print x.networks - - # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/irc.py b/irc.py index 9b6f382..4d90dab 100644 --- a/irc.py +++ b/irc.py @@ -366,7 +366,10 @@ def handle_server_JOIN(self, source, message, prefix, code, args): print "SERVER JOIN: %s" % message name = args[0] if name not in self.channels: - self.channels[name] = ChannelBuffer(name,self,self.server.config.channel_configs.get(name,self.server.config)) + config = self.server.config.by_path("channels/name=%s" % name) + if not config: + config = self.server.config + self.channels[name] = ChannelBuffer(name,self,config) self.host = host_from_prefix(prefix) self.channels[name].add_join(message,prefix,code,args) diff --git a/thud.py b/thud.py index 7c9f200..53a76f2 100755 --- a/thud.py +++ b/thud.py @@ -13,6 +13,7 @@ from datetime import datetime import irc +import config class ThudException(Exception): pass @@ -21,143 +22,39 @@ class AuthenticationFailed(ThudException): class NoSuchNetwork(ThudException): pass -class NetworkConfig(object): - def __init__(self,config,user): - self.config = config - self.user = user - @property - def uri(self): - return self.config["uri"] - @property - def ref(self): - return self.config["ref"] - @property - def nick(self): - return self.config.get("nick",self.user.nick) - @property - def realname(self): - return self.config.get("realname",self.user.realname) - @property - def autoconnect(self): - return self.config.get("autoconnect",False) - @property - def channel_configs(self): - if "channels" in self.config: - return {c["name"].lower(): ChannelConfig(c,self) for c in self.config['channels']} - return {} - @property - def password(self): - return self.config.get("password","") - @property - def log_enable(self): - return self.config.get("log_enable",self.user.log_enable) - @property - def backlog_depth(self): - return self.config.get("backlog_depth",self.user.backlog_depth) - @property - def query_backlog_depth(self): - return self.config.get("query_backlog_depth",self.user.query_backlog_depth) - -class ChannelConfig(object): - def __init__(self,config,networkconfig): - self.config = config - self.networkconfig = networkconfig - @property - def name(self): - return self.config["name"] - @property - def key(self): - return self.config.get("key","") - @property - def log_enable(self): - return self.config.get("log_enable",self.networkconfig.log_enable) - @property - def backlog_depth(self): - return self.config.get("backlog_depth",self.networkconfig.backlog_depth) - - class User(object): """ This is the central class in thud. A User instance acts as a central point for all clients and server connections. All messages pass through here. """ - def __init__(self, bouncer, configfile): + def __init__(self, bouncer, config): self.bouncer = bouncer - self.configfile = configfile - with open(self.configfile,'rt') as f: - self.config = yaml.load(f.read()) + self.config = config self.server_connections = {} #key is ref self.server_caches = {} #key is ref self.clients = {} # key is resource self.logger = [] # no need for keys here - def save_config(self): - with open(self.configfile,'wt') as f: - f.write(yaml.dump(config)) - @property - def name(self): - return self.config.get('name').lower() - @property - def realname(self): - return self.config.get('realname',self.name) - @property - def network_configs(self): - return {c["ref"].lower(): NetworkConfig(c,self) for c in self.config['networks']} - def get_server_config(self, ref): - return self.network_configs.get(ref,None) - @property - def nick(self): - return self.config["nick"] - @property - def realname(self): - return self.config.get("realname",self.name) - @property - def password(self): - return self.config.get("password") - @property - def backlog_depth(self): - return self.config.get("backlog_depth",self.bouncer.backlog_depth) - @property - def query_backlog_depth(self): - return self.config.get("query_backlog_depth",self.bouncer.query_backlog_depth) - @property - def log_enable(self): - return self.config.get("log_enable",self.bouncer.log_enable) - def authenticate_client(self, password): """ Called when a downstream client connects and is attempting to authenticate """ - return pwd_context.verify(password, self.password) + return pwd_context.verify(password, self.config.password) def server_connected(self, server): """ Called when one of the server connections has successfully connected to the server server """ - print "[%s] SERVER CONNECTED FOR %s" % (self.name,server.config.uri) + print "[%s] SERVER CONNECTED FOR %s" % (self.config.name,server.config.uri) self.server_connections[server.config.ref] = server server.register_callback(CALLBACK_MESSAGE, self.server_message) server.register_callback(CALLBACK_DISCONNECTED, self.server_disconnected) if not server.config.ref in self.server_caches: self.server_caches[server.config.ref] = irc.Cache(self) - - base = IRCLogger() - base.read_config(self.config) - base.server = server.config.ref - self.server_caches[server.config.ref].add_logger(None, base) - - for channel in server.config.channel_configs.values(): - if channel.log_enable == False: - self.server_caches[server.config.ref].add_logger(channel.name, None) - continue - logger = base.clone() - logger.read_config(channel.config) - logger.name = channel.name - self.server_caches[server.config.ref].add_logger(channel.name, logger) self.server_caches[server.config.ref].set_server(server) server.register_callback(CALLBACK_MESSAGE,server.cache.process_server_message) - + # we need to do a USER and NICK command to the server here. - if server.config.password: - self.server_send(server,"PASS %s" % server.config.password) + if server.config.get("password"): + self.server_send(server,"PASS %s" % server.config.get("password")) self.server_send(server,"NICK %s" % server.config.nick) self.server_send(server,"USER %s 0 * :%s" % (server.config.nick, server.config.realname)) # we should join all channels: - for channel in server.config.channel_configs.values(): + for channel in server.config.channels: self.server_send(server,"JOIN %s %s" % (channel.name, channel.key)) self.server_send(server,"MODE %s" % channel.name) self.server_send(server,"WHO %s" % channel.name) @@ -165,11 +62,11 @@ def server_connected(self, server): return server def server_send(self, server, line): """ Convenience function used to send messages to an server server """ - print "[%s][%s] SERVER_SEND: %s" % (self.name,server.config.uri,line) + print "[%s][%s] SERVER_SEND: %s" % (self.config.name,server.config.uri,line) server.sendLine(line) def server_message(self, server, line): """ Called when a message is received from an server connection. This message will usually be delivered to all clients, and may also be cached.""" - print "[%s][%s] SERVER_RECV: %s" % (self.name,server.config.uri,line) + print "[%s][%s] SERVER_RECV: %s" % (self.config.name,server.config.uri,line) for resource,client in self.clients.items(): if client.serverref == server.config.ref: client.sendLine(line) @@ -177,18 +74,18 @@ def server_message(self, server, line): def server_disconnected(self, server): """ Called when one of the server connections disconnects for whatever reason """ del self.server_connections[server.config.ref] - print "[%s] SERVER DISCONNECTED FOR %s" % (self.name,server.config.uri) + print "[%s] SERVER DISCONNECTED FOR %s" % (self.config.name,server.config.uri) server.config.reconnect_attempts = 0 self.server_reconnect(server.config) return server def server_reconnect(self, networkconfig): if networkconfig.reconnect_attempts == 3: - print "[%s] ABORTING RECONNECT TO %s" % (self.name, networkconfig.uri) + print "[%s] ABORTING RECONNECT TO %s" % (self.config.name, networkconfig.uri) return - print "[%s] ATTEMPTING RECONNECT TO %s ..." % (self.name, networkconfig.uri) - d = self.bouncer.connect_server(networkconfig) + print "[%s] ATTEMPTING RECONNECT TO %s ..." % (self.config.name, networkconfig.uri) + d = self.bouncer.connect_server(networkconfig,self) def __connected(server): - return server.config.user.server_connected(server) + return server.user.server_connected(server) def __error(server): networkconfig.reconnect_attempts += 1 reactor.callLater(pow(2,networkconfig.reconnect_attempts), self.server_reconnect, networkconfig) @@ -213,10 +110,10 @@ def client_connected(self, client, token): client.register_callback(CALLBACK_DISCONNECTED,self.client_disconnected) self.clients[resource] = client if not serverref in self.server_connections: - networkconfig = self.get_server_config(serverref) + networkconfig = self.config.by_path("networks/ref=%s" % serverref) if networkconfig: # connect on demand - print "[%s] ON DEMAND CONNECTING TO SERVER %s" % (self.name,networkconfig.uri) - d = self.bouncer.connect_server(networkconfig) + print "[%s] ON DEMAND CONNECTING TO SERVER %s" % (self.config.name,networkconfig.uri) + d = self.bouncer.connect_server(networkconfig,self) def __connected(server): res = self.server_connected(server) return res @@ -226,7 +123,7 @@ def __connected(server): return client def client_message(self, client, line): """ Called when a message is received from a client. This message will usually be relayed to the relevant server, although it might be diverted to the cache instead. """ - print "[%s][%s][%s] CLIENT_RECV: %s" % (self.name,client.serverref,client.resource,line) + print "[%s][%s][%s] CLIENT_RECV: %s" % (self.config.name,client.serverref,client.resource,line) if not client.serverref in self.server_connections: print "---> PUTTING OFF FOR 1 SECOND TO GIVE THE SERVER A CHANCE TO COMPLETE CONNECTION!" @@ -237,58 +134,47 @@ def client_message(self, client, line): self.server_connections[client.serverref].sendLine(line) def client_disconnected(self, client): """ Called when a client disconnectes for this user.""" - print "[%s][%s] CLIENT_DISCONNECTED" % (self.name,client.serverref) + print "[%s][%s] CLIENT_DISCONNECTED" % (self.config.name,client.serverref) del self.clients[client.resource] - - class IRCBouncer: def __init__(self,port,configpath="."): self.users = {} self.process_server_config("%s/thud.conf" % configpath) factory = IRCClientConnectionFactory(self) - if self.config["ssl_enable"]: - print "LISTENING ON PORT %d for SSL" % self.config["ssl_port"] + if self.config.ssl_enable: + print "LISTENING ON PORT %d for SSL" % self.config.ssl_port try: - reactor.listenSSL(self.config["ssl_port"], factory, ssl.DefaultOpenSSLContextFactory(self.config["ssl_key"], self.config["ssl_cert"])) - except Exception,e: - print "FAILED TO LISTEN FOR SSL: %s" % e + reactor.listenSSL(self.config.ssl_port, factory, ssl.DefaultOpenSSLContextFactory(self.config.ssl_key, self.config.ssl_cert)) + except Exception,e: + print "FAILED TO LISTEN FOR SSL: %s" % e - if self.config["tcp_enable"]: - print "LISTENING ON PORT %d for TCP" % self.config["tcp_port"] - reactor.listenTCP(self.config["tcp_port"], factory) + if self.config.tcp_enable: + print "LISTENING ON PORT %d for TCP" % self.config.tcp_port + reactor.listenTCP(self.config.tcp_port, factory) for user_file in glob.glob("%s/*.user" % configpath): self.process_user_config(user_file) - @property - def log_enable(self): - return self.config.get("log_enable",None) - @property - def backlog_depth(self): - return self.config.get("backlog_depth",100) - @property - def query_backlog_depth(self): - return self.config.get("query_backlog_depth",self.backlog_depth) - - def process_server_config(self, config): + def process_server_config(self, filename): print "PROCESSING SERVER CONFIG" - self.config = yaml.load(open(config, "r").read()) + self.config = config.Config(filename=filename) - def process_user_config(self, config): - user = User(self,config) - print "PROCESSING USER CONFIG FOR %s" % user.name - self.users[user.name] = user - for ref, networkconfig in user.network_configs.items(): - print "\t", ref, networkconfig.uri, networkconfig.autoconnect and "AUTOCONNECT" or "ONDEMAND" + def process_user_config(self, filename): + userconfig = config.Config(filename=filename,parent=self.config) + user = User(self,userconfig) + print "PROCESSING USER CONFIG FOR %s" % user.config.name + self.users[user.config.name] = user + for networkconfig in user.config.networks: + print "\t", networkconfig.ref, networkconfig.uri, networkconfig.autoconnect and "AUTOCONNECT" or "ONDEMAND" if networkconfig.autoconnect: - d = self.connect_server(networkconfig) + d = self.connect_server(networkconfig,user) def __connected(server): - return server.config.user.server_connected(server) + return server.user.server_connected(server) d.addCallback(__connected) - def connect_server(self, networkconfig): + def connect_server(self, networkconfig, user): uri = networkconfig.uri m = re.match("(?:(?P[a-zA-i0-9]+)://)?(?P[a-zA-Z0-9.-]+)(?:[:](?P[0-9]+))?/?",uri) parts = m.groupdict() @@ -306,6 +192,7 @@ def connect_server(self, networkconfig): def __connected(server): print "SERVER_CONNECTED!" server.config = networkconfig + server.user = user return server d.addCallback(__connected) return d