-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.py
149 lines (120 loc) · 4.12 KB
/
main.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import json
import enaml
import pandas as pd
import tornado.web
import tornado.websocket
import tornado.ioloop
from web.core.app import WebApplication
with enaml.imports():
from viewer import Viewer
log = tornado.web.app_log
SMD_COMPONENTS = pd.read_csv('smd-components.csv')
# Update man
MANUFACTURERS = {
'Agi': 'Agilent (was HP)',
'Fch': 'Fairchild',
'HP': 'Hewlett-Packard (Now Agilent)',
'Inf': 'Infineon',
'ITT': 'ITT Semiconductors',
'MC': 'Mini-Circuits',
'Mot': 'Motorola (ON Semi)',
'Nat': 'National Semiconductor',
'Nec': 'NEC',
'NJRC': 'New Japan Radio Co',
'ON': 'ON Semiconductors',
'Phi': 'Philips',
'Roh': 'Rohm',
'SGS': 'SGS-Thompson',
'Sie': 'Siemens (now Infineon)',
'Sil': 'Siliconix (Vishay-Silliconix)',
'Tem': 'Temic Semiconductors',
'Tfk': 'Telefunken (Vishay-Telefunken)',
'Tok': 'Toko Inc.',
'Zet': 'Zetex',
}
SMD_COMPONENTS.replace({'Manufacturer': MANUFACTURERS}, inplace=True)
# Holds the rendered view so a websocket can retrieve it later
CACHE = {}
class ViewerHandler(tornado.web.RequestHandler):
def get(self):
viewer = Viewer(
request=self.request,
response=self,
dataframe=SMD_COMPONENTS,
)
# Store the viewer in the cache
CACHE[viewer.id] = viewer
self.write(viewer.render())
class ViewerWebSocket(tornado.websocket.WebSocketHandler):
viewer = None
def open(self):
# Store the viewer in the cache
id = self.get_argument("id")
if id not in CACHE:
log.error(f"Viewer with id={id} does not exist!")
self.write_message(json.dumps({'type': 'reload'}))
return
# Get a viewer reference
self.viewer = CACHE[id]
# Setup an observer to watch changes on the enaml view
self.viewer.observe('modified', self.on_dom_modified)
def on_message(self, message):
""" When we get an event from js, lookup the node and invoke the
action on the enaml node.
"""
change = json.loads(message)
log.debug(f'Update from js: {change}')
try:
# Lookup the node
id = change.get('id')
if not id:
return
nodes = self.viewer.xpath('//*[@id=$id]', id=id)
if not nodes:
return # Unknown node
node = nodes[0]
# Trigger the change on the enaml node
if change.get('type') and change.get('name'):
if change['type'] == 'event':
trigger = getattr(node, change['name'])
trigger()
elif change['type'] == 'update':
# Trigger the update
setattr(node, change['name'], change['value'])
else:
log.warning(f"Unhandled event {self} {node}: {change}")
except Exception as e:
msg = {'type': 'error', 'message': f'{e}'}
self.write_message(json.dumps(msg))
def on_dom_modified(self, change):
""" When an event from enaml occurs, send it out the websocket
so the client's browser can update accordingly.
"""
log.debug(f'Update from enaml: {change}')
self.write_message(json.dumps(change['value']))
def on_close(self):
log.debug(f'WebSocket {self} closed')
viewer = self.viewer
if viewer is not None:
viewer.unobserve('modified', self.on_dom_modified)
id = viewer.id
if id in CACHE:
del CACHE[id]
def run():
# Needed to create enaml components
enaml_app = WebApplication()
log.setLevel('DEBUG')
# Start the tornado app
app = tornado.web.Application([
(r'/', ViewerHandler),
(r'/websocket/', ViewerWebSocket),
(r'/static/(.*)', tornado.web.StaticFileHandler, {
'path': os.path.dirname(__file__)}),
])
port = int(os.environ.get('PORT', 5000))
app.listen(port)
print(f"Listening on http://localhost:{port}")
tornado.ioloop.IOLoop.current().start()
if __name__ == '__main__':
run()