Skip to content

Commit

Permalink
config,irc,thud: use new config mechanism as per #5
Browse files Browse the repository at this point in the history
  • Loading branch information
c1de0x committed May 7, 2012
1 parent 975b73c commit 176e8a4
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 172 deletions.
20 changes: 4 additions & 16 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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():
Expand All @@ -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
5 changes: 4 additions & 1 deletion irc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
197 changes: 42 additions & 155 deletions thud.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from datetime import datetime

import irc
import config

class ThudException(Exception):
pass
Expand All @@ -21,174 +22,70 @@ 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()

This comment has been minimized.

Copy link
@c1de0x

c1de0x May 7, 2012

Author Contributor

also ditched a bunch of sven's logger stuf, which wasn't really functional anyways. Not worth moving over to the new config mechanism.

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)

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)

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)
Expand All @@ -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
Expand All @@ -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!"
Expand All @@ -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<proto>[a-zA-i0-9]+)://)?(?P<host>[a-zA-Z0-9.-]+)(?:[:](?P<port>[0-9]+))?/?",uri)
parts = m.groupdict()
Expand All @@ -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
Expand Down

0 comments on commit 176e8a4

Please sign in to comment.