]>
jfr.im git - erebus.git/blob - modules/sockets.py
1 # Erebus IRC bot - Author: Erebus Team
2 # vim: fileencoding=utf-8
3 # Configurable sockets module. DO NOT USE without understanding the risks
4 # This file is released into the public domain; see http://unlicense.org/
6 # Note: this module doesn't do any kind of authentication, so anyone who can connect to the bound port can spam you.
9 To use - add in bot.config something like:
12 127.0.0.1:1337 = #example
14 The left side is the address to listen on and the right side is the channel to send to.
15 The exmaple will send incoming lines/packets on localhost, port 1337 to channel #example
17 The full syntax for the address is:
18 [unix:]</path/to/socket>
19 [udp|tcp:][<ip>:]<port>
24 Unix domain socket: /path
25 Unix domain socket: unix:/path
26 TCP socket (all interfaces): 1337
27 TCP socket (one interface): 127.0.0.1:1337
28 UDP socket (all interfaces): udp:1337
29 UDP socket (one interface): udp:127.0.0.1:1337
34 'author': 'Erebus Team',
35 'license': 'public domain',
43 lib
= modlib
.modlib(__name__
)
44 def modstart(parent
, *args
, **kwargs
):
46 return lib
.modstart(parent
, *args
, **kwargs
)
51 def gotParent(parent
):
52 for bindto
, channel
in parent
.cfg
.items('sockets'):
53 @lib.bind(bindto
, data
=channel
)
54 class BasicServer(object):
55 def __init__(self
, sock
, data
):
56 # NB neither directly referencing `channel`, nor trying to pass it through a default-arg-to-a-lambda like the python docs suggest, works here.
57 # Yay python. At least passing it via bind works.
63 recvd
= self
.sock
.recv(8192)
64 if recvd
== b
"": # EOF
65 if len(self
.buffer) != 0:
66 # Process what's left in the buffer. We'll get called again after.
67 remaining_buf
= self
.buffer.decode('utf-8', 'backslashreplace')
69 return [remaining_buf
]
71 # Nothing left in the buffer. Return None to signal the core to close this socket.
76 while b
"\n" in self
.buffer:
77 pieces
= self
.buffer.split(b
"\n", 1)
78 s
= pieces
[0].decode('utf-8', 'backslashreplace').rstrip("\r")
79 lines
.append(pieces
[0].decode('utf-8', 'backslashreplace'))
80 self
.buffer = pieces
[1]
84 def parse(self
, line
):
86 bot
= lib
.parent
.channel(self
.chan
).bot
87 except AttributeError: # <class 'AttributeError'> 'NoneType' object has no attribute 'bot'
88 bot
= lib
.parent
.randbot()
89 maxlen
= bot
.maxmsglen() - len("PRIVMSG :") - len(self
.chan
)
90 while len(line
) > maxlen
:
91 cutat
= line
.rfind(' ', 0, maxlen
)
94 bot
.msg(self
.chan
, line
[0:cutat
])
95 line
= line
[cutat
:].strip()
96 bot
.msg(self
.chan
, line
)
99 if lib
.parent
.parent
.cfg
.getboolean('debug', 'io'):
100 lib
.parent
.log(str(self
), 'O', line
)
101 self
.sock
.sendall(line
.encode('utf-8', 'backslashreplace')+b
"\r\n")
103 def _getsockerr(self
):
104 try: # SO_ERROR might not exist on all platforms
105 return self
.socket
.getsockopt(socket
.SOL_SOCKET
, socket
.SO_ERROR
)
110 return '%s#%d' % (__name__
, self
.sock
.fileno())
112 return '<%s #%d %s:%d>' % ((__name__
, self
.sock
.fileno())+self
.sock
.getpeername())