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