import transports earlier
[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', 'no')
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, stratum_tcp_port))
88     except:
89         print "cannot connect to server."
90         return
91
92     method = 'server.' + command
93     params = [password]
94     if len(sys.argv) > 2:
95         params.append(sys.argv[2])
96     
97     request = json.dumps({'id': 0, 'method': method, 'params': params})
98     s.send(request + '\n')
99     msg = ''
100     while True:
101         o = s.recv(1024)
102         if not o: break
103         msg += o
104         if msg.find('\n') != -1:
105             break
106     s.close()
107     r = json.loads(msg).get('result')
108
109     if command == 'info':
110         now = time.time()
111         print 'type           address         sub  version  time'
112         for item in r:
113             print '%4s   %21s   %3s  %7s  %.2f' % (item.get('name'),
114                                                    item.get('address'),
115                                                    item.get('subscriptions'),
116                                                    item.get('version'),
117                                                    (now - item.get('time')),
118                                                    )
119     else:
120         print r
121
122
123 if __name__ == '__main__':
124     config = create_config()
125     password = config.get('server', 'password')
126     host = config.get('server', 'host')
127     stratum_tcp_port = config.getint('server', 'stratum_tcp_port')
128     stratum_http_port = config.getint('server', 'stratum_http_port')
129     stratum_tcp_ssl_port = config.getint('server', 'stratum_tcp_ssl_port')
130     stratum_http_ssl_port = config.getint('server', 'stratum_http_ssl_port')
131     ssl_certfile = config.get('server', 'ssl_certfile')
132     ssl_keyfile = config.get('server', 'ssl_keyfile')
133
134     if stratum_tcp_ssl_port or stratum_http_ssl_port:
135         assert ssl_certfile and ssl_keyfile
136
137     if len(sys.argv) > 1:
138         run_rpc_command(sys.argv[1], stratum_tcp_port)
139         sys.exit(0)
140
141     try:
142         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
143         s.connect((host, stratum_tcp_port))
144         s.close()
145         is_running = True
146     except:
147         is_running = False
148
149     if is_running:
150         print "server already running"
151         sys.exit(1)
152
153
154     from processor import Dispatcher, print_log
155     from backends.irc import ServerProcessor
156     from transports.stratum_tcp import TcpServer
157     from transports.stratum_http import HttpServer
158
159     backend_name = config.get('server', 'backend')
160     if backend_name == 'libbitcoin':
161         from backends.libbitcoin import BlockchainProcessor
162     elif backend_name == 'leveldb':
163         from backends.bitcoind import BlockchainProcessor
164     else:
165         print "Unknown backend '%s' specified\n" % backend_name
166         sys.exit(1)
167
168     print "\n\n\n\n\n"
169     print_log("Starting Electrum server on", host)
170
171     # Create hub
172     dispatcher = Dispatcher(config)
173     shared = dispatcher.shared
174
175     # Create and register processors
176     chain_proc = BlockchainProcessor(config, shared)
177     dispatcher.register('blockchain', chain_proc)
178
179     server_proc = ServerProcessor(config)
180     dispatcher.register('server', server_proc)
181
182     transports = []
183     # Create various transports we need
184     if stratum_tcp_port:
185         tcp_server = TcpServer(dispatcher, host, stratum_tcp_port, False, None, None)
186         transports.append(tcp_server)
187
188     if stratum_tcp_ssl_port:
189         tcp_server = TcpServer(dispatcher, host, stratum_tcp_ssl_port, True, ssl_certfile, ssl_keyfile)
190         transports.append(tcp_server)
191
192     if stratum_http_port:
193         http_server = HttpServer(dispatcher, host, stratum_http_port, False, None, None)
194         transports.append(http_server)
195
196     if stratum_http_ssl_port:
197         http_server = HttpServer(dispatcher, host, stratum_http_ssl_port, True, ssl_certfile, ssl_keyfile)
198         transports.append(http_server)
199
200     for server in transports:
201         server.start()
202
203     while not shared.stopped():
204         try:
205             time.sleep(1)
206         except:
207             shared.stop()
208
209     server_proc.join()
210     chain_proc.join()
211     print_log("Electrum Server stopped")