]> jfr.im git - erebus.git/blob - modules/sockets.py
sockets - use channel's bot if on channel
[erebus.git] / modules / sockets.py
1 # Erebus IRC bot - Author: Erebus Team
2 # vim: fileencoding=utf-8
3 # This file is released into the public domain; see http://unlicense.org/
4
5 # Note: this module doesn't do any kind of authentication, so anyone who can connect to the bound port can spam you.
6
7 # module info
8 modinfo = {
9 'author': 'Erebus Team',
10 'license': 'public domain',
11 'compatible': [0],
12 'depends': [],
13 'softdeps': [],
14 }
15
16 # preamble
17 import modlib
18 lib = modlib.modlib(__name__)
19 def modstart(parent, *args, **kwargs):
20 gotParent(parent)
21 return lib.modstart(parent, *args, **kwargs)
22 modstop = lib.modstop
23
24 # module code
25
26 def gotParent(parent):
27 for bindto, channel in parent.cfg.items('sockets'):
28 @lib.bind(bindto, data=channel)
29 class BasicServer(object):
30 def __init__(self, sock, data):
31 # NB neither directly referencing `channel`, nor trying to pass it through a default-arg-to-a-lambda like the python docs suggest, works here.
32 # Yay python. At least passing it via bind works.
33 self.chan = data
34 self.buffer = b''
35 self.sock = sock
36
37 def getdata(self):
38 recvd = self.sock.recv(8192)
39 if recvd == b"": # EOF
40 if len(self.buffer) != 0:
41 # Process what's left in the buffer. We'll get called again after.
42 remaining_buf = self.buffer.decode('utf-8', 'backslashreplace')
43 self.buffer = b""
44 return [remaining_buf]
45 else:
46 # Nothing left in the buffer. Return None to signal the core to close this socket.
47 return None
48 self.buffer += recvd
49 lines = []
50
51 while b"\n" in self.buffer:
52 pieces = self.buffer.split(b"\n", 1)
53 s = pieces[0].decode('utf-8', 'backslashreplace').rstrip("\r")
54 lines.append(pieces[0].decode('utf-8', 'backslashreplace'))
55 self.buffer = pieces[1]
56
57 return lines
58
59 def parse(self, line):
60 try:
61 bot = lib.parent.channel(self.chan).bot
62 except AttributeError: # <class 'AttributeError'> 'NoneType' object has no attribute 'bot'
63 bot = lib.parent.randbot()
64 maxlen = bot.maxmsglen() - len("PRIVMSG :") - len(self.chan)
65 while len(line) > maxlen:
66 cutat = line.rfind(' ', 0, maxlen)
67 if cutat == -1:
68 cutat = maxlen
69 bot.msg(self.chan, line[0:cutat])
70 line = line[cutat:].strip()
71 bot.msg(self.chan, line)
72
73 def send(self, line):
74 if lib.parent.parent.cfg.getboolean('debug', 'io'):
75 lib.parent.log(str(self), 'O', line)
76 self.sock.sendall(line.encode('utf-8', 'backslashreplace')+b"\r\n")
77
78 def _getsockerr(self):
79 try: # SO_ERROR might not exist on all platforms
80 return self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
81 except:
82 return None
83
84 def __str__(self):
85 return '%s#%d' % (__name__, self.sock.fileno())
86 def __repr__(self):
87 return '<%s #%d %s:%d>' % ((__name__, self.sock.fileno())+self.sock.getpeername())