927e62de7b4febe551610010dd4b27818612a98a
[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', '50002')
52     config.set('server', 'stratum_http_ssl_port', '8082')
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', 'password', '')
58     config.set('server', 'irc', 'yes')
59     config.set('server', 'irc_nick', '')
60     config.set('server', 'coin', '')
61     config.set('server', 'datadir', '')
62     config.add_section('database')
63     config.set('database', 'type', 'psycopg2')
64     config.set('database', 'database', 'abe')
65     config.set('database', 'limit', '1000')
66     config.set('server', 'backend', 'abe')
67
68     for path in ('/etc/', ''):
69         filename = path + 'electrum.conf'
70         attempt_read_config(config, filename)
71
72     try:
73         with open('/etc/electrum.banner', 'r') as f:
74             config.set('server', 'banner', f.read())
75     except IOError:
76         pass
77
78     return config
79
80
81 def run_rpc_command(command, stratum_tcp_port):
82     try:
83         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
84         s.connect((host, int(stratum_tcp_port)))
85     except:
86         print "cannot connect to server."
87         return
88
89     method = 'server.' + command
90     request = json.dumps({'id': 0, 'method': method, 'params': [password]})
91     s.send(request + '\n')
92     msg = ''
93     while True:
94         o = s.recv(1024)
95         msg += o
96         if msg.find('\n') != -1:
97             break
98     s.close()
99     r = json.loads(msg).get('result')
100
101     if command == 'info':
102         now = time.time()
103         print 'type           address   sub  version  time'
104         for item in r:
105             print '%4s   %15s   %3s  %7s  %.2f' % (item.get('name'),
106                                                    item.get('address'),
107                                                    item.get('subscriptions'),
108                                                    item.get('version'),
109                                                    (now - item.get('time')),
110                                                    )
111     else:
112         print r
113
114
115 if __name__ == '__main__':
116     config = create_config()
117     password = config.get('server', 'password')
118     host = config.get('server', 'host')
119     stratum_tcp_port = config.get('server', 'stratum_tcp_port')
120     stratum_http_port = config.get('server', 'stratum_http_port')
121     stratum_tcp_ssl_port = config.get('server', 'stratum_tcp_ssl_port')
122     stratum_http_ssl_port = config.get('server', 'stratum_http_ssl_port')
123     ssl_certfile = config.get('server', 'ssl_certfile')
124     ssl_keyfile = config.get('server', 'ssl_keyfile')
125
126     if stratum_tcp_ssl_port or stratum_http_ssl_port:
127         assert ssl_certfile and ssl_keyfile
128
129     if len(sys.argv) > 1:
130         run_rpc_command(sys.argv[1], stratum_tcp_port)
131         sys.exit(0)
132
133     from processor import Dispatcher, print_log
134     from backends.irc import ServerProcessor
135
136     backend_name = config.get('server', 'backend')
137     if backend_name == 'abe':
138         from backends.abe import BlockchainProcessor
139     elif backend_name == 'libbitcoin':
140         from backends.libbitcoin import BlockchainProcessor
141     elif backend_name == 'leveldb':
142         from backends.bitcoind import BlockchainProcessor
143     else:
144         print "Unknown backend '%s' specified\n" % backend_name
145         sys.exit(1)
146
147     for i in xrange(5):
148         print ""
149     print_log("Starting Electrum server on", host)
150
151     # Create hub
152     dispatcher = Dispatcher(config)
153     shared = dispatcher.shared
154
155     # Create and register processors
156     chain_proc = BlockchainProcessor(config, shared)
157     dispatcher.register('blockchain', chain_proc)
158
159     server_proc = ServerProcessor(config)
160     dispatcher.register('server', server_proc)
161
162     transports = []
163     # Create various transports we need
164     if stratum_tcp_port:
165         from transports.stratum_tcp import TcpServer
166         tcp_server = TcpServer(dispatcher, host, int(stratum_tcp_port), False, None, None)
167         transports.append(tcp_server)
168
169     if stratum_tcp_ssl_port:
170         from transports.stratum_tcp import TcpServer
171         tcp_server = TcpServer(dispatcher, host, int(stratum_tcp_ssl_port), True, ssl_certfile, ssl_keyfile)
172         transports.append(tcp_server)
173
174     if stratum_http_port:
175         from transports.stratum_http import HttpServer
176         http_server = HttpServer(dispatcher, host, int(stratum_http_port), False, None, None)
177         transports.append(http_server)
178
179     if stratum_http_ssl_port:
180         from transports.stratum_http import HttpServer
181         http_server = HttpServer(dispatcher, host, int(stratum_http_ssl_port), True, ssl_certfile, ssl_keyfile)
182         transports.append(http_server)
183
184     for server in transports:
185         server.start()
186
187     while not shared.stopped():
188         try:
189             time.sleep(1)
190         except:
191             shared.stop()
192
193     print_log("Electrum Server stopped")