'pruning' flag
[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 from version import VERSION
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.stratum_tcp_ssl_port = config.get('server','stratum_tcp_ssl_port')
19         self.stratum_http_ssl_port = config.get('server','stratum_http_ssl_port')
20         self.peers = {}
21         self.host = config.get('server','host')
22         self.nick = config.get('server', 'irc_nick')
23         if not self.nick: self.nick = random_string(10)
24         self.prepend = 'E_'
25         if config.get('server', 'coin') == 'litecoin':
26             self.prepend = 'EL_'
27         self.pruning = config.get('server', 'backend') == 'leveldb'
28         self.nick = self.prepend + self.nick
29
30     def get_peers(self):
31         return self.peers.values()
32
33
34     def getname(self):
35         s = 'v' + VERSION + ' '
36         if self.pruning: s += 'p '
37         if self.stratum_tcp_port:
38             s += 't' + self.stratum_tcp_port + ' ' 
39         if self.stratum_http_port:
40             s += 'h' + self.stratum_http_port + ' '
41         if self.stratum_tcp_port:
42             s += 's' + self.stratum_tcp_ssl_port + ' ' 
43         if self.stratum_http_port:
44             s += 'g' + self.stratum_http_ssl_port + ' '
45         return s
46
47
48     def run(self):
49         ircname = self.getname()
50
51         while not self.processor.shared.stopped():
52             try:
53                 s = socket.socket()
54                 s.connect(('irc.freenode.net', 6667))
55             except:
56                 time.sleep(10)
57                 continue
58
59             try:
60                 s.send('USER electrum 0 * :' + self.host + ' ' + ircname + '\n')
61                 s.send('NICK ' + self.nick + '\n')
62                 s.send('JOIN #electrum\n')
63                 sf = s.makefile('r', 0)
64                 t = 0
65                 while not self.processor.shared.stopped():
66                     line = sf.readline()
67                     line = line.rstrip('\r\n')
68                     line = line.split()
69                     if not line: continue
70                     if line[0]=='PING': 
71                         s.send('PONG '+line[1]+'\n')
72                     elif '353' in line: # answer to /names
73                         k = line.index('353')
74                         for item in line[k+1:]:
75                             if item.startswith(self.prepend):
76                                 s.send('WHO %s\n'%item)
77                     elif '352' in line: # answer to /who
78                         # warning: this is a horrible hack which apparently works
79                         k = line.index('352')
80                         ip = line[k+4]
81                         ip = socket.gethostbyname(ip)
82                         name = line[k+6]
83                         host = line[k+9]
84                         ports  = line[k+10:]
85                         self.peers[name] = (ip, host, ports)
86                     if time.time() - t > 5*60:
87                         self.processor.push_response({'method':'server.peers', 'params':[self.get_peers()]})
88                         s.send('NAMES #electrum\n')
89                         t = time.time()
90                         self.peers = {}
91             except:
92                 traceback.print_exc(file=sys.stdout)
93             finally:
94                 sf.close()
95                 s.close()
96
97         print "quitting IRC"
98
99
100
101 class ServerProcessor(Processor):
102
103     def __init__(self, config):
104         Processor.__init__(self)
105         self.daemon = True
106         self.banner = config.get('server','banner')
107         self.password = config.get('server','password')
108
109         if config.get('server', 'irc') == 'yes':
110             self.irc = IrcThread(self, config)
111         else: 
112             self.irc = None
113
114
115     def get_peers(self):
116         if self.irc:
117             return self.irc.get_peers()
118         else:
119             return []
120
121
122     def run(self):
123         if self.irc:
124             self.irc.start()
125         Processor.run(self)
126
127     def process(self, request):
128         method = request['method']
129         params = request['params']
130         result = None
131
132         if method in ['server.stop', 'server.info']:
133             try:
134                 password = request['params'][0]
135             except:
136                 password = None
137
138             if password != self.password:
139                 response = { 'id':request['id'], 'result':None,  'error':'incorrect password'}
140                 self.push_response(response)
141                 return
142
143         if method == 'server.banner':
144             result = self.banner.replace('\\n','\n')
145
146         elif method == 'server.peers.subscribe':
147             result = self.get_peers()
148
149         elif method == 'server.version':
150             result = VERSION
151
152         elif method == 'server.stop':
153             self.shared.stop()
154             result = 'stopping, please wait until all threads terminate.'
155
156         elif method == 'server.info':
157             result = map(lambda s: { "time":s.time, 
158                                      "name":s.name,
159                                      "address":s.address, 
160                                      "version":s.version, 
161                                      "subscriptions":len(s.subscriptions)}, 
162                          self.dispatcher.request_dispatcher.get_sessions())
163
164         elif method == 'server.cache':
165             p = self.dispatcher.request_dispatcher.processors['blockchain']
166             result = len(repr(p.store.tx_cache))
167
168         elif method == 'server.load':
169             p = self.dispatcher.request_dispatcher.processors['blockchain']
170             result = p.queue.qsize()
171
172         else:
173             print "unknown method", request
174
175         if result!='':
176             response = { 'id':request['id'], 'result':result }
177             self.push_response(response)
178