forked from arlolra/bulb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
executable file
·123 lines (90 loc) · 3.56 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python
import sys
import json
import functools
from twisted.python import log
from twisted.internet import reactor, defer
from twisted.web import static, server
from autobahn.twisted.resource import WebSocketResource
from autobahn.twisted.websocket import WebSocketServerProtocol, \
WebSocketServerFactory
import txtorcon
class WSProtocol(WebSocketServerProtocol):
@defer.inlineCallbacks
def onOpen(self):
self.factory.register(self)
conn = self.factory.tor_protocol
info = yield conn.get_info('version', 'dormant', 'process/pid',
'process/user', 'address', 'status/version/current',
'net/listeners/socks')
conf = yield conn.get_conf('ExitPolicy', 'Address', 'SocksPort')
info.update(conf)
self.factory.broadcast(json.dumps({'type': 'info',
'data': info}))
def connectionLost(self, reason):
WebSocketServerProtocol.connectionLost(self, reason)
self.factory.unregister(self)
class WSFactory(WebSocketServerFactory):
def __init__(self, url, control_connection):
WebSocketServerFactory.__init__(self, url)
self.clients = []
self.tor_protocol = control_connection
def register(self, client):
if client not in self.clients:
print("Registering client {}".format(client.peer))
self.clients.append(client)
def unregister(self, client):
if client in self.clients:
print("Unregistering client {}".format(client.peer))
self.clients.remove(client)
def broadcast(self, msg):
msg = str(msg).encode('utf8')
for c in self.clients:
c.sendMessage(msg)
def bandwidth_event(factory, data):
## could use stem to parse the event payload, but it's just two
## ints.
r, w = map(int, data.split())
factory.broadcast(json.dumps({
"type": "bw",
"data": dict(read=r, written=w)
}))
def an_error(failure):
print "Error:", failure.getErrorMessage()
reactor.stop() # scorch the earth!
def setup_complete(connection):
print "Connected to Tor (or launched our own)", connection
factory = WSFactory("ws://localhost:9000", connection)
factory.protocol = WSProtocol
connection.add_event_listener('BW', functools.partial(bandwidth_event, factory))
root = static.File("public/")
resource = WebSocketResource(factory)
root.putChild("ws", resource)
reactor.listenTCP(9000, server.Site(root))
def progress(*args):
'''percent, tag, description'''
print '%2f%%: %s: %s' % args
def main(launch_tor=False):
log.startLogging(sys.stdout)
control_port = 9051
if launch_tor:
control_port = 9151
config = txtorcon.TorConfig()
config.ControlPort = control_port
config.SocksPort = 0
d = txtorcon.launch_tor(config, reactor, progress_updates=progress)
## launch_tor returns a TorProcessProtocol
## ...so we grab out the TorControlProtocol instance in order
## to simply use the same callback on "d" below
d.addCallback(lambda pp: pp.tor_protocol)
else:
## if build_state=True, then we get a TorState() object back
d = txtorcon.build_tor_connection((reactor, '127.0.0.1', control_port),
build_state=False)
d.addCallback(setup_complete).addErrback(an_error)
try:
reactor.run()
except KeyboardInterrupt:
pass # ctrl+c
if __name__ == '__main__':
main()