28e60d9c32b82dbba0509274ffc837751b11b7dc
[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 not line: continue
53                     if line[0]=='PING': 
54                         s.send('PONG '+line[1]+'\n')
55                     elif '353' in line: # answer to /names
56                         k = line.index('353')
57                         for item in line[k+1:]:
58                             if item[0:2] == 'E_':
59                                 s.send('WHO %s\n'%item)
60                     elif '352' in line: # answer to /who
61                         # warning: this is a horrible hack which apparently works
62                         k = line.index('352')
63                         ip = line[k+4]
64                         ip = socket.gethostbyname(ip)
65                         name = line[k+6]
66                         host = line[k+9]
67                         ports  = line[k+10:]
68                         self.peers[name] = (ip, host, ports)
69                     if time.time() - t > 5*60:
70                         self.processor.push_response({'method':'server.peers', 'params':[self.get_peers()]})
71                         s.send('NAMES #electrum\n')
72                         t = time.time()
73                         self.peers = {}
74             except:
75                 traceback.print_exc(file=sys.stdout)
76             finally:
77                 sf.close()
78                 s.close()
79
80         print "quitting IRC"
81
82
83
84 class ServerProcessor(Processor):
85
86     def __init__(self, config):
87         Processor.__init__(self)
88         self.daemon = True
89         self.banner = config.get('server','banner')
90         self.password = config.get('server','password')
91
92         if config.get('server', 'irc') == 'yes':
93             self.irc = IrcThread(self, config)
94         else: 
95             self.irc = None
96
97
98     def get_peers(self):
99         if self.irc:
100             return self.irc.get_peers()
101         else:
102             return []
103
104
105     def run(self):
106         if self.irc:
107             self.irc.start()
108         Processor.run(self)
109
110     def process(self, request):
111         method = request['method']
112         params = request['params']
113         result = None
114
115         if method in ['server.stop', 'server.info']:
116             try:
117                 password = request['params'][0]
118             except:
119                 password = None
120
121             if password != self.password:
122                 response = { 'id':request['id'], 'result':None,  'error':'incorrect password'}
123                 self.push_response(response)
124                 return
125
126         if method == 'server.banner':
127             result = self.banner.replace('\\n','\n')
128
129         elif method == 'server.peers.subscribe':
130             result = self.get_peers()
131
132         elif method == 'server.version':
133             result = 'ok'
134
135         elif method == 'server.stop':
136             self.shared.stop()
137             result = 'ok'
138
139         elif method == 'server.info':
140             result = map(lambda s: { "time":s.time, 
141                                      "name":s.name,
142                                      "address":s.address, 
143                                      "version":s.version, 
144                                      "subscriptions":len(s.subscriptions)}, 
145                          self.dispatcher.request_dispatcher.get_sessions())
146
147         elif method == 'server.load':
148             p = self.dispatcher.request_dispatcher.processors['blockchain']
149             result = p.queue.qsize()
150
151         else:
152             print "unknown method", request
153
154         if result!='':
155             response = { 'id':request['id'], 'result':result }
156             self.push_response(response)
157