3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-12-25 12:12:53 +01:00

Merge pull request #38 from GLolol/multinet-v2

Multinet support
This commit is contained in:
James Lu 2015-07-10 11:21:28 -07:00
commit dba20d4efc
6 changed files with 71 additions and 38 deletions

View File

@ -67,17 +67,18 @@ testconf = {'bot':
'realname': 'PyLink Service Client', 'realname': 'PyLink Service Client',
'loglevel': 'DEBUG', 'loglevel': 'DEBUG',
}, },
'server': 'servers':
{ {'unittest':
'netname': 'fakeirc', {
'ip': '0.0.0.0', 'ip': '0.0.0.0',
'port': 7000, 'port': 7000,
'recvpass': "abcd", 'recvpass': "abcd",
'sendpass': "abcd", 'sendpass': "abcd",
'protocol': "null", 'protocol': "null",
'hostname': "pylink.unittest", 'hostname': "pylink.unittest",
'sid': "9PY", 'sid': "9PY",
'channels': ["#pylink"], 'channels': ["#pylink"],
},
}, },
} }

55
main.py
View File

@ -6,16 +6,19 @@ import socket
import time import time
import sys import sys
from collections import defaultdict from collections import defaultdict
import threading
from log import log from log import log
import conf import conf
import classes import classes
import utils
class Irc(): class Irc():
def __init__(self, proto, conf): def __init__(self, netname, proto, conf):
# threading.Thread.__init__(self)
# Initialize some variables # Initialize some variables
self.connected = False self.connected = False
self.name = conf['server']['netname'] self.name = netname
self.conf = conf self.conf = conf
# Server, channel, and user indexes to be populated by our protocol module # Server, channel, and user indexes to be populated by our protocol module
self.servers = {} self.servers = {}
@ -38,7 +41,7 @@ class Irc():
self.maxnicklen = 30 self.maxnicklen = 30
self.prefixmodes = 'ov' self.prefixmodes = 'ov'
self.serverdata = conf['server'] self.serverdata = conf['servers'][netname]
self.sid = self.serverdata["sid"] self.sid = self.serverdata["sid"]
self.botdata = conf['bot'] self.botdata = conf['bot']
self.proto = proto self.proto = proto
@ -49,12 +52,20 @@ class Irc():
port = self.serverdata["port"] port = self.serverdata["port"]
log.info("Connecting to network %r on %s:%s", self.name, ip, port) log.info("Connecting to network %r on %s:%s", self.name, ip, port)
self.socket = socket.socket() self.socket = socket.socket()
self.socket.setblocking(0)
self.socket.settimeout(60)
self.socket.connect((ip, port)) self.socket.connect((ip, port))
self.proto.connect(self) self.proto.connect(self)
self.loaded = [] self.loaded = []
self.load_plugins() self.load_plugins()
reading_thread = threading.Thread(target = self.run)
self.connected = True self.connected = True
self.run() reading_thread.start()
def disconnect(self):
self.connected = False
self.socket.shutdown()
self.socket.close()
def run(self): def run(self):
buf = "" buf = ""
@ -67,19 +78,19 @@ class Irc():
break break
while '\n' in buf: while '\n' in buf:
line, buf = buf.split('\n', 1) line, buf = buf.split('\n', 1)
log.debug("<- %s", line) log.debug("(%s) <- %s", self.name, line)
proto.handle_events(self, line) proto.handle_events(self, line)
except socket.error as e: except (socket.error, classes.ProtocolError) as e:
log.error('Received socket.error: %s, exiting.', str(e)) log.error('Disconnected from network %r: %s: %s, exiting.',
break self.name, type(e).__name__, str(e))
sys.exit(1) self.disconnect()
def send(self, data): def send(self, data):
# Safeguard against newlines in input!! Otherwise, each line gets # Safeguard against newlines in input!! Otherwise, each line gets
# treated as a separate command, which is particularly nasty. # treated as a separate command, which is particularly nasty.
data = data.replace('\n', ' ') data = data.replace('\n', ' ')
data = data.encode("utf-8") + b"\n" data = data.encode("utf-8") + b"\n"
log.debug("-> %s", data.decode("utf-8").strip("\n")) log.debug("(%s) -> %s", self.name, data.decode("utf-8").strip("\n"))
self.socket.send(data) self.socket.send(data)
def load_plugins(self): def load_plugins(self):
@ -103,17 +114,17 @@ if __name__ == '__main__':
if conf.conf['login']['password'] == 'changeme': if conf.conf['login']['password'] == 'changeme':
log.critical("You have not set the login details correctly! Exiting...") log.critical("You have not set the login details correctly! Exiting...")
sys.exit(2) sys.exit(2)
protoname = conf.conf['server']['protocol']
protocols_folder = [os.path.join(os.getcwd(), 'protocols')] protocols_folder = [os.path.join(os.getcwd(), 'protocols')]
try: for network in conf.conf['servers']:
moduleinfo = imp.find_module(protoname, protocols_folder) protoname = conf.conf['servers'][network]['protocol']
proto = imp.load_source(protoname, moduleinfo[1]) try:
except ImportError as e: moduleinfo = imp.find_module(protoname, protocols_folder)
if str(e).startswith('No module named'): proto = imp.load_source(protoname, moduleinfo[1])
log.critical('Failed to load protocol module %r: the file could not be found.', protoname) except ImportError as e:
if str(e).startswith('No module named'):
log.critical('Failed to load protocol module %r: the file could not be found.', protoname)
else:
log.critical('Failed to load protocol module: import error %s', protoname, str(e))
sys.exit(2)
else: else:
log.critical('Failed to load protocol module: import error %s', protoname, str(e)) utils.networkobjects[network] = Irc(network, proto, conf.conf)
sys.exit(2)
else:
irc_obj = Irc(proto, conf.conf)

View File

@ -150,9 +150,31 @@ def modeServer(irc, numeric, target, modes):
a list of (mode, arg) tuples, in the format of utils.parseModes() output. a list of (mode, arg) tuples, in the format of utils.parseModes() output.
""" """
if not utils.isInternalServer(irc, numeric): if not utils.isInternalServer(irc, numeric):
raise LookupError('No such PyLink PseudoClient exists.') raise LookupError('No such PyLink PseudoServer exists.')
_sendModes(irc, numeric, target, modes) _sendModes(irc, numeric, target, modes)
def killServer(irc, numeric, target, reason):
"""<irc object> <server SID> <target> <reason>
Sends a kill to <target> from a PyLink PseudoServer.
"""
if not utils.isInternalServer(irc, numeric):
raise LookupError('No such PyLink PseudoServer exists.')
_sendFromServer(irc, numeric, 'KILL %s :%s' % (target, reason))
# We don't need to call removeClient here, since the remote server
# will send a QUIT from the target if the command succeeds.
def killClient(irc, numeric, target, reason):
"""<irc object> <client numeric> <target> <reason>
Sends a kill to <target> from a PyLink PseudoClient.
"""
if not utils.isInternalClient(irc, numeric):
raise LookupError('No such PyLink PseudoClient exists.')
_sendFromServer(irc, numeric, 'KILL %s :%s' % (target, reason))
# We don't need to call removeClient here, since the remote server
# will send a QUIT from the target if the command succeeds.
def messageClient(irc, numeric, target, text): def messageClient(irc, numeric, target, text):
"""<irc object> <client numeric> <text> """<irc object> <client numeric> <text>

View File

@ -9,7 +9,7 @@ import unittest
# Yes, we're going to even test the testing classes. Testception? I think so. # Yes, we're going to even test the testing classes. Testception? I think so.
class TestFakeIRC(unittest.TestCase): class TestFakeIRC(unittest.TestCase):
def setUp(self): def setUp(self):
self.irc = classes.FakeIRC(classes.FakeProto(), classes.testconf) self.irc = classes.FakeIRC('unittest', classes.FakeProto(), classes.testconf)
def testFakeIRC(self): def testFakeIRC(self):
self.irc.run('this should do nothing') self.irc.run('this should do nothing')

View File

@ -11,7 +11,7 @@ import utils
class TestProtoInspIRCd(unittest.TestCase): class TestProtoInspIRCd(unittest.TestCase):
def setUp(self): def setUp(self):
self.irc = classes.FakeIRC(inspircd, classes.testconf) self.irc = classes.FakeIRC('unittest', inspircd, classes.testconf)
self.proto = self.irc.proto self.proto = self.irc.proto
self.sdata = self.irc.serverdata self.sdata = self.irc.serverdata
# This is to initialize ourself as an internal PseudoServer, so we can spawn clients # This is to initialize ourself as an internal PseudoServer, so we can spawn clients
@ -56,8 +56,6 @@ class TestProtoInspIRCd(unittest.TestCase):
self.assertIn(u, self.irc.channels['#channel'].users) self.assertIn(u, self.irc.channels['#channel'].users)
# Non-existant user. # Non-existant user.
self.assertRaises(LookupError, self.proto.joinClient, self.irc, '9PYZZZZZZ', '#test') self.assertRaises(LookupError, self.proto.joinClient, self.irc, '9PYZZZZZZ', '#test')
# Invalid channel.
self.assertRaises(ValueError, self.proto.joinClient, self.irc, u, 'aaaa')
def testPartClient(self): def testPartClient(self):
u = self.u u = self.u

View File

@ -8,6 +8,7 @@ global bot_commands, command_hooks
# This should be a mapping of command names to functions # This should be a mapping of command names to functions
bot_commands = {} bot_commands = {}
command_hooks = defaultdict(list) command_hooks = defaultdict(list)
networkobjects = {}
class TS6UIDGenerator(): class TS6UIDGenerator():
"""TS6 UID Generator module, adapted from InspIRCd source """TS6 UID Generator module, adapted from InspIRCd source