+# Erebus IRC bot - Author: Erebus Team
+# vim: fileencoding=utf-8
+# This file is released into the public domain; see http://unlicense.org/
+
+# module info
+modinfo = {
+ 'author': 'Erebus Team',
+ 'license': 'public domain',
+ 'compatible': [0],
+ 'depends': [],
+ 'softdeps': ['help'],
+}
+
+# preamble
+import modlib
+lib = modlib.modlib(__name__)
+modstart = lib.modstart
+modstop = lib.modstop
+
+# module code
+
+# Note: bind_* does all of the following:
+# - create a socket `sock = socket.socket()`
+# - bind the socket `sock.bind()`
+# - listen on the socket `sock.listen()`
+# - accept `sock.accept()`
+#
+# Once a connection is accepted, your class is instantiated with the client socket.
+# - When data comes in on the client socket, your `getdata` method will be called. It should return a list of strings.
+# - For each element in the list returned by `getdata`, `parse` will be called.
+# - When the socket is being closed by the bot (f.e. your module is unloaded), the optional method `closing` will be called.
+# Then the bot will call `sock.shutdown()` and `sock.close()` for you.
+# XXX error handling? what happens when the other side closes the socket?
+#
+# You can interact with the rest of the bot through `lib.parent`.
+@lib.bind_tcp('0.0.0.0', 12543)
+class BasicServer(object):
+ def __init__(self, sock):
+ self.buffer = b''
+ self.sock = sock
+
+ def getdata(self):
+ recvd = self.sock.recv(8192)
+ if recvd == b"":
+ if len(self.buffer) != 0:
+ # Process what's left in the buffer. We'll get called again after.
+ remaining_buf = self.buffer.decode('utf-8', 'backslashreplace')
+ self.buffer = b""
+ return [remaining_buf]
+ else:
+ # Nothing left in the buffer. Return None to signal the core to close this socket.
+ return None
+ self.buffer += recvd
+ lines = []
+
+ while b"\n" in self.buffer:
+ pieces = self.buffer.split(b"\n", 1)
+ s = pieces[0].decode('utf-8', 'backslashreplace').rstrip("\r")
+ lines.append(pieces[0].decode('utf-8', 'backslashreplace'))
+ self.buffer = pieces[1]
+
+ return lines
+
+ def parse(self, line):
+ peer = self.sock.getpeername()
+ lib.parent.randbot().msg('#', "%s:%d says: %s" % (peer[0], peer[1], line))
+
+ def send(self, line):
+ self.socket.sendall(line.encode('utf-8', 'backslashreplace')+b"\r\n")
+
+ def _getsockerr(self):
+ try: # SO_ERROR might not exist on all platforms
+ return self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
+ except:
+ return None