various fixes
[electrum-server.git] / server.py
1 #!/usr/bin/env python
2 # Copyright(C) 2012 thomasv@gitorious
3
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as
6 # published by the Free Software Foundation, either version 3 of the
7 # License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public
15 # License along with this program.  If not, see
16 # <http://www.gnu.org/licenses/agpl.html>.
17
18 import ConfigParser
19 import logging
20 import socket
21 import sys
22 import time
23 import threading
24 import traceback
25
26 import json
27
28 logging.basicConfig()
29
30 if sys.maxsize <= 2**32:
31     print "Warning: it looks like you are using a 32bit system. You may experience crashes caused by mmap"
32
33
34 def attempt_read_config(config, filename):
35     try:
36         with open(filename, 'r') as f:
37             config.readfp(f)
38     except IOError:
39         pass
40
41
42 def create_config():
43     config = ConfigParser.ConfigParser()
44     # set some defaults, which will be overwritten by the config file
45     config.add_section('server')
46     config.set('server', 'banner', 'Welcome to Electrum!')
47     config.set('server', 'host', 'localhost')
48     config.set('server', 'report_host', '')
49     config.set('server', 'stratum_tcp_port', '50001')
50     config.set('server', 'stratum_http_port', '8081')
51     config.set('server', 'stratum_tcp_ssl_port', '')
52     config.set('server', 'stratum_http_ssl_port', '')
53     config.set('server', 'report_stratum_tcp_port', '')
54     config.set('server', 'report_stratum_http_port', '')
55     config.set('server', 'report_stratum_tcp_ssl_port', '')
56     config.set('server', 'report_stratum_http_ssl_port', '')
57     config.set('server', 'ssl_certfile', '')
58     config.set('server', 'ssl_keyfile', '')
59     config.set('server', 'password', '')
60     config.set('server', 'irc', 'yes')
61     config.set('server', 'irc_nick', '')
62     config.set('server', 'coin', '')
63     config.set('server', 'datadir', '')
64
65     # use leveldb as default
66     config.set('server', 'backend', 'leveldb')
67     config.add_section('leveldb')
68     config.set('leveldb', 'path', '/dev/shm/electrum_db')
69     config.set('leveldb', 'pruning_limit', '100')
70
71     for path in ('/etc/', ''):
72         filename = path + 'electrum.conf'
73         attempt_read_config(config, filename)
74
75     try:
76         with open('/etc/electrum.banner', 'r') as f:
77             config.set('server', 'banner', f.read())
78     except IOError:
79         pass
80
81     return config
82
83
84 def run_rpc_command(command, stratum_tcp_port):
85     try:
86         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
87         s.connect((host, int(stratum_tcp_port)))
88     except:
89         print "cannot connect to server."
90         return
91
92     method = 'server.' + command
93     request = json.dumps({'id': 0, 'method': method, 'params': [password]})
94     s.send(request + '\n')
95     msg = ''
96     while True:
97         o = s.recv(1024)
98         if not o: break
99         msg += o
100         if msg.find('\n') != -1:
101             break
102     s.close()
103     r = json.loads(msg).get('result')
104
105     if command == 'info':
106         now = time.time()
107         print 'type           address   sub  version  time'
108         for item in r:
109             print '%4s   %15s   %3s  %7s  %.2f' % (item.get('name'),
110                                                    item.get('address'),
111                                                    item.get('subscriptions'),
112                                                    item.get('version'),
113                                                    (now - item.get('time')),
114                                                    )
115     else:
116         print r
117
118
119 if __name__ == '__main__':
120     config = create_config()
121     password = config.get('server', 'password')
122     host = config.get('server', 'host')
123     stratum_tcp_port = config.get('server', 'stratum_tcp_port')
124     stratum_http_port = config.get('server', 'stratum_http_port')
125     stratum_tcp_ssl_port = config.get('server', 'stratum_tcp_ssl_port')
126     stratum_http_ssl_port = config.get('server', 'stratum_http_ssl_port')
127     ssl_certfile = config.get('server', 'ssl_certfile')
128     ssl_keyfile = config.get('server', 'ssl_keyfile')
129
130     if stratum_tcp_ssl_port or stratum_http_ssl_port:
131         assert ssl_certfile and ssl_keyfile
132
133     if len(sys.argv) > 1:
134         run_rpc_command(sys.argv[1], stratum_tcp_port)
135         sys.exit(0)
136
137     from processor import Dispatcher, print_log
138     from backends.irc import ServerProcessor
139
140     backend_name = config.get('server', 'backend')
141     if backend_name == 'abe':
142         from backends.abe import BlockchainProcessor
143     elif backend_name == 'libbitcoin':
144         from backends.libbitcoin import BlockchainProcessor
145     elif backend_name == 'leveldb':
146         from backends.bitcoind import BlockchainProcessor
147     else:
148         print "Unknown backend '%s' specified\n" % backend_name
149         sys.exit(1)
150
151     for i in xrange(5):
152         print ""
153     print_log("Starting Electrum server on", host)
154
155     # Create hub
156     dispatcher = Dispatcher(config)
157     shared = dispatcher.shared
158
159     # Create and register processors
160     chain_proc = BlockchainProcessor(config, shared)
161     dispatcher.register('blockchain', chain_proc)
162
163     server_proc = ServerProcessor(config)
164     dispatcher.register('server', server_proc)
165
166     transports = []
167     # Create various transports we need
168     if stratum_tcp_port:
169         from transports.stratum_tcp import TcpServer
170         tcp_server = TcpServer(dispatcher, host, int(stratum_tcp_port), False, None, None)
171         transports.append(tcp_server)
172
173     if stratum_tcp_ssl_port:
174         from transports.stratum_tcp import TcpServer
175         tcp_server = TcpServer(dispatcher, host, int(stratum_tcp_ssl_port), True, ssl_certfile, ssl_keyfile)
176         transports.append(tcp_server)
177
178     if stratum_http_port:
179         from transports.stratum_http import HttpServer
180         http_server = HttpServer(dispatcher, host, int(stratum_http_port), False, None, None)
181         transports.append(http_server)
182
183     if stratum_http_ssl_port:
184         from transports.stratum_http import HttpServer
185         http_server = HttpServer(dispatcher, host, int(stratum_http_ssl_port), True, ssl_certfile, ssl_keyfile)
186         transports.append(http_server)
187
188     for server in transports:
189         server.start()
190
191     while not shared.stopped():
192         try:
193             time.sleep(1)
194         except:
195             shared.stop()
196
197     print_log("Electrum Server stopped")