]>
Commit | Line | Data |
---|---|---|
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 | # module info | |
6 | modinfo = { | |
7 | 'author': 'Erebus Team', | |
8 | 'license': 'public domain', | |
9 | 'compatible': [0], | |
10 | 'depends': [], | |
11 | 'softdeps': ['help'], | |
12 | } | |
13 | ||
14 | # preamble | |
15 | import modlib | |
16 | lib = modlib.modlib(__name__) | |
17 | modstart = lib.modstart | |
18 | modstop = lib.modstop | |
19 | ||
20 | # module code | |
21 | ||
22 | # Note: bind_* does all of the following: | |
23 | # - create a socket `sock = socket.socket()` | |
24 | # - bind the socket `sock.bind()` | |
25 | # - listen on the socket `sock.listen()` | |
26 | # - accept `sock.accept()` | |
27 | # | |
28 | # Once a connection is accepted, your class is instantiated with the client socket. | |
29 | # - When data comes in on the client socket, your `getdata` method will be called. It should return a list of strings. | |
30 | # - For each element in the list returned by `getdata`, `parse` will be called. | |
31 | # - When the socket is being closed by the bot (f.e. your module is unloaded), the optional method `closing` will be called. | |
32 | # Then the bot will call `sock.shutdown()` and `sock.close()` for you. | |
33 | # XXX error handling? what happens when the other side closes the socket? | |
34 | # | |
35 | # You can interact with the rest of the bot through `lib.parent`. | |
36 | @lib.bind_tcp('0.0.0.0', 12543) | |
37 | class BasicServer(object): | |
38 | def __init__(self, sock): | |
39 | self.buffer = b'' | |
40 | self.sock = sock | |
41 | ||
42 | def getdata(self): | |
43 | recvd = self.sock.recv(8192) | |
44 | if recvd == b"": | |
45 | if len(self.buffer) != 0: | |
46 | # Process what's left in the buffer. We'll get called again after. | |
47 | remaining_buf = self.buffer.decode('utf-8', 'backslashreplace') | |
48 | self.buffer = b"" | |
49 | return [remaining_buf] | |
50 | else: | |
51 | # Nothing left in the buffer. Return None to signal the core to close this socket. | |
52 | return None | |
53 | self.buffer += recvd | |
54 | lines = [] | |
55 | ||
56 | while b"\n" in self.buffer: | |
57 | pieces = self.buffer.split(b"\n", 1) | |
58 | s = pieces[0].decode('utf-8', 'backslashreplace').rstrip("\r") | |
59 | lines.append(pieces[0].decode('utf-8', 'backslashreplace')) | |
60 | self.buffer = pieces[1] | |
61 | ||
62 | return lines | |
63 | ||
64 | def parse(self, line): | |
65 | peer = self.sock.getpeername() | |
66 | lib.parent.randbot().msg('#', "%s:%d says: %s" % (peer[0], peer[1], line)) | |
67 | ||
68 | def send(self, line): | |
69 | self.socket.sendall(line.encode('utf-8', 'backslashreplace')+b"\r\n") | |
70 | ||
71 | def _getsockerr(self): | |
72 | try: # SO_ERROR might not exist on all platforms | |
73 | return self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) | |
74 | except: | |
75 | return None |