restructuring: each processor has its own queue
[electrum-server.git] / backends / irc / __init__.py
1 import threading, socket, traceback, time, sys
2
3 def random_string(N):
4     import random, string
5     return ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(N))
6
7 from processor import Processor
8
9
10 class IrcThread(threading.Thread):
11
12     def __init__(self, processor, config):
13         threading.Thread.__init__(self)
14         self.processor = processor
15         self.daemon = True
16         self.stratum_tcp_port = config.get('server','stratum_tcp_port')
17         self.stratum_http_port = config.get('server','stratum_http_port')
18         self.peers = {}
19         self.host = config.get('server','host')
20         self.nick = config.get('server', 'irc_nick')
21         if not self.nick: self.nick = random_string(10)
22
23     def get_peers(self):
24         return self.peers.values()
25
26
27     def getname(self):
28         s = ''
29         if self.stratum_tcp_port:
30             s += 't' + self.stratum_tcp_port + ' ' 
31         if self.stratum_http_port:
32             s += 'h' + self.stratum_http_port + ' '
33         return s
34
35
36     def run(self):
37         ircname = self.getname()
38
39         while not self.processor.shared.stopped():
40             try:
41                 s = socket.socket()
42                 s.connect(('irc.freenode.net', 6667))
43                 s.send('USER electrum 0 * :' + self.host + ' ' + ircname + '\n')
44                 s.send('NICK E_' + self.nick + '\n')
45                 s.send('JOIN #electrum\n')
46                 sf = s.makefile('r', 0)
47                 t = 0
48                 while not self.processor.shared.stopped():
49                     line = sf.readline()
50                     line = line.rstrip('\r\n')
51                     line = line.split()
52                     if line[0]=='PING': 
53                         s.send('PONG '+line[1]+'\n')
54                     elif '353' in line: # answer to /names
55                         k = line.index('353')
56                         for item in line[k+1:]:
57                             if item[0:2] == 'E_':
58                                 s.send('WHO %s\n'%item)
59                     elif '352' in line: # answer to /who
60                         # warning: this is a horrible hack which apparently works
61                         k = line.index('352')
62                         ip = line[k+4]
63                         ip = socket.gethostbyname(ip)
64                         name = line[k+6]
65                         host = line[k+9]
66                         ports  = line[k+10:]
67                         self.peers[name] = (ip, host, ports)
68                     if time.time() - t > 5*60:
69                         self.processor.push_response({'method':'server.peers', 'params':[self.get_peers()]})
70                         s.send('NAMES #electrum\n')
71                         t = time.time()
72                         self.peers = {}
73             except:
74                 traceback.print_exc(file=sys.stdout)
75             finally:
76                 sf.close()
77                 s.close()
78
79         print "quitting IRC"
80
81
82
83 class ServerProcessor(Processor):
84
85     def __init__(self, config):
86         Processor.__init__(self)
87         self.daemon = True
88         self.banner = config.get('server','banner')
89         self.password = config.get('server','password')
90
91         if config.get('server', 'irc') == 'yes':
92             self.irc = IrcThread(self, config)
93         else: 
94             self.irc = None
95
96
97     def get_peers(self):
98         if self.irc:
99             return self.irc.get_peers()
100         else:
101             return []
102
103
104     def run(self):
105         if self.irc:
106             self.irc.start()
107         Processor.run(self)
108
109     def process(self, request):
110         method = request['method']
111         params = request['params']
112         result = None
113
114         if method in ['server.stop', 'server.info']:
115             try:
116                 password = request['params'][0]
117             except:
118                 password = None
119
120             if password != self.password:
121                 response = { 'id':request['id'], 'result':None,  'error':'incorrect password'}
122                 self.push_response(response)
123                 return
124
125         if method == 'server.banner':
126             result = self.banner.replace('\\n','\n')
127
128         elif method == 'server.peers.subscribe':
129             result = self.get_peers()
130
131         elif method == 'server.version':
132             result = 'ok'
133
134         elif method == 'server.stop':
135             self.shared.stop()
136             result = 'ok'
137
138         elif method == 'server.info':
139             result = map(lambda s: { "time":s.time, 
140                                      "name":s.name,
141                                      "address":s.address, 
142                                      "version":s.version, 
143                                      "subscriptions":len(s.subscriptions)}, 
144                          self.dispatcher.request_dispatcher.get_sessions())
145
146         else:
147             print "unknown method", request
148
149         if result!='':
150             response = { 'id':request['id'], 'result':result }
151             self.push_response(response)
152