1+ from nodejs .io import *
2+ from nodejs .os import *
3+ from nodejs .tornado import *
4+
5+ #import os, sys, subprocess, json
6+
7+ PATHS = dict (
8+ webroot = os .path .abspath ('tests' ),
9+ pythonjs = os .path .abspath ('pythonjs' ),
10+ bindings = os .path .abspath ('bindings' ),
11+ runtime = os .path .abspath ('pythonjs.js' ),
12+ )
13+
14+
15+
16+ def python_to_pythonjs ( src , callback ):
17+ path = '/tmp/input1.py'
18+ open ( path , 'w' ).write ( src )
19+ args = [
20+ os .path .join ( PATHS ['pythonjs' ], 'python_to_pythonjs.py' ),
21+ path
22+ ]
23+ p = subprocess .call ('python2' , args , callback = callback )
24+
25+ def pythonjs_to_javascript ( src , callback ):
26+ path = '/tmp/input2.py'
27+ open ( path , 'w' ).write ( src )
28+ args = [
29+ os .path .join ( PATHS ['pythonjs' ], 'pythonjs.py' ),
30+ path
31+ ]
32+ p = subprocess .call ('python2' , args , callback = callback )
33+
34+ def python_to_javascript (source , callback ):
35+ func = lambda data : pythonjs_to_javascript (data , callback )
36+ python_to_pythonjs ( source , func )
37+
38+
39+
40+ #########################################################
41+ def get_main_page ():
42+ print 'get_main_page......'
43+ root = PATHS ['webroot' ]
44+ r = ['<html><head><title>index</title></head><body>' ]
45+ r .append ( '<ul>' )
46+ files = os .listdir ( root )
47+ files .sort ()
48+ for name in files :
49+ path = os .path .join ( root , name )
50+ if os .path .isfile ( path ):
51+ r .append ( '<a href="%s"><li>%s</li></a>' % (name ,name ) )
52+ r .append ('</ul>' )
53+ r .append ('</body></html>' )
54+ return '' .join (r )
55+
56+
57+ def convert_python_html_document ( data ):
58+ '''
59+ rewrites html document, converts python scripts into javascript.
60+ example:
61+ <script type="text/python" closure="true">
62+ print("hello world")
63+ </script>
64+
65+ Note:
66+ we need to parse and compile any python binding scripts that appear in the head,
67+ because later scripts may use classes from the bindings, and we need have the
68+ AST introspected data available here to properly inline and for operator overloading.
69+ '''
70+ doc = list ()
71+ script = None
72+ use_closure = False
73+ for line in data .splitlines ():
74+ if line .strip ().startswith ('<script' ):
75+ if 'src="bindings/' in line :
76+ doc .append ( line )
77+ a ,b ,c = line .split ('"' )
78+ if b .endswith ('.py' ): ## make sure the module is cached ##
79+ name = b .split ('/' )[- 1 ]
80+ path = os .path .join ( PATHS ['bindings' ], name )
81+ src = open (path , 'rb' ).read ().decode ('utf-8' )
82+ pyjs = python_to_pythonjs ( src , module = name .split ('.' )[0 ] )
83+ print (pyjs )
84+ print ('_' * 80 )
85+
86+ elif 'type="text/python"' in line :
87+ if 'closure="true"' in line .lower (): use_closure = True
88+ else : use_closure = False
89+ doc .append ( '<script type="text/javascript">' )
90+ script = list ()
91+ else :
92+ doc .append ( line )
93+
94+ elif line .strip () == '</script>' :
95+ if script :
96+ src = '\n ' .join ( script )
97+ js = python_to_javascript ( src , closure_compiler = use_closure , debug = True )
98+ doc .append ( js )
99+ doc .append ( line )
100+ script = None
101+
102+ elif isinstance ( script , list ):
103+ script .append ( line )
104+
105+ else :
106+ doc .append ( line )
107+
108+ return '\n ' .join ( doc )
109+
110+
111+
112+
113+
114+ UploadDirectory = '/tmp'
115+ ResourcePaths = []
116+ if os .path .isdir ( os .path .expanduser ('~/blockly-read-only' ) ):
117+ ResourcePaths .append ( os .path .expanduser ('~/blockly-read-only' ) )
118+
119+ class MainHandler ( tornado .web .RequestHandler ):
120+ def get (self , path = None ):
121+ print ('path' , path )
122+ if not path :
123+ self .write ( get_main_page () )
124+ elif path == 'pythonscript.js' or path == 'pythonjs.js' :
125+ data = open ( PATHS ['runtime' ], 'rb' ).read ()
126+ self .set_header ("Content-Type" , "text/javascript; charset=utf-8" )
127+ self .set_header ("Content-Length" , len (data ))
128+ self .write (data )
129+ elif path .startswith ('bindings/' ):
130+ name = path .split ('/' )[- 1 ]
131+ local_path = os .path .join ( PATHS ['bindings' ], name )
132+
133+ if os .path .isfile ( local_path ):
134+ data = open (local_path , 'rb' ).read ()
135+ else :
136+ raise tornado .web .HTTPError (404 )
137+
138+ if path .endswith ('.py' ):
139+ print ('converting python binding to javascript' , name )
140+ module = name .split ('.' )[0 ]
141+ data = python_to_javascript ( data .decode ('utf-8' ), closure_compiler = False , module = module )
142+
143+
144+ self .set_header ("Content-Type" , "text/javascript; charset=utf-8" )
145+ self .set_header ("Content-Length" , len (data ))
146+ self .write ( data )
147+
148+ elif path .startswith ('uploads/' ):
149+ name = path .split ('/' )[- 1 ]
150+ local_path = os .path .join ( UploadDirectory , name )
151+
152+ if os .path .isfile ( local_path ):
153+ data = open (local_path , 'rb' ).read ()
154+ else :
155+ raise tornado .web .HTTPError (404 )
156+
157+ self .set_header ("Content-Length" , len (data ))
158+ self .write ( data )
159+
160+ else :
161+ local_path = os .path .join ( PATHS ['webroot' ], path )
162+ if os .path .isfile ( local_path ):
163+ data = open (local_path , 'rb' ).read ()
164+ if path .endswith ( '.html' ):
165+ data = convert_python_html_document ( data .decode ('utf-8' ) )
166+ self .set_header ("Content-Type" , "text/html; charset=utf-8" )
167+ elif path .endswith ('.py' ):
168+ data = python_to_javascript ( data .decode ('utf-8' ), closure_compiler = True )
169+ self .set_header ("Content-Type" , "text/html; charset=utf-8" )
170+
171+ self .set_header ("Content-Length" , len (data ))
172+ self .write ( data )
173+
174+ else :
175+ found = False
176+ for root in ResourcePaths :
177+ local_path = os .path .join ( root , path )
178+ if os .path .isfile (local_path ):
179+ data = open (local_path , 'rb' ).read ()
180+ self .set_header ("Content-Length" , len (data ))
181+ self .write ( data )
182+ found = True
183+ break
184+
185+ if not found :
186+ print ( 'FILE NOT FOUND' )
187+ self .finish ()
188+
189+
190+ LIBS = dict (
191+ three = {
192+ 'three.min.js' : os .path .expanduser ( '~/three.js/build/three.min.js' ),
193+ 'FlyControls.js' : os .path .expanduser ( '~/three.js/examples/js/controls/FlyControls.js' ),
194+ 'OrbitControls.js' : os .path .expanduser ( '~/three.js/examples/js/controls/OrbitControls.js' ),
195+ 'TrackballControls.js' : os .path .expanduser ( '~/three.js/examples/js/controls/TrackballControls.js' ),
196+
197+ },
198+ tween = {'tween.min.js' : os .path .expanduser ( '~/tween.js/build/tween.min.js' )},
199+ fonts = {
200+ 'gentilis_bold.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/gentilis_bold.typeface.js' ),
201+ 'gentilis_regular.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/gentilis_regular.typeface.js' ),
202+ 'optimer_bold.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/optimer_bold.typeface.js' ),
203+ 'optimer_regular.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/optimer_regular.typeface.js' ),
204+ 'helvetiker_bold.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/helvetiker_bold.typeface.js' ),
205+ 'helvetiker_regular.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/helvetiker_regular.typeface.js' ),
206+ 'droid_sans_regular.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/droid/droid_sans_regular.typeface.js' ),
207+ 'droid_sans_bold.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/droid/droid_sans_bold.typeface.js' ),
208+ 'droid_serif_regular.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/droid/droid_serif_regular.typeface.js' ),
209+ 'droid_serif_bold.typeface.js' : os .path .expanduser ( '~/three.js/examples/fonts/droid/droid_serif_bold.typeface.js' ),
210+ },
211+ ace = {
212+ 'ace.js' : os .path .expanduser ( '~/ace-builds/src-noconflict/ace.js' ),
213+ 'theme-monokai.js' :os .path .expanduser ( '~/ace-builds/src-noconflict/theme-monokai.js' ),
214+ 'mode-python.js' :os .path .expanduser ( '~/ace-builds/src-noconflict/mode-python.js' ),
215+ 'mode-javascript.js' :os .path .expanduser ( '~/ace-builds/src-noconflict/mode-javascript.js' ),
216+ 'worker-javascript.js' :os .path .expanduser ( '~/ace-builds/src-noconflict/worker-javascript.js' ),
217+ },
218+ physijs = {
219+ 'physi.js' : os .path .expanduser ( '~/Physijs/physi.js' ),
220+ 'physijs_worker.js' : os .path .expanduser ( '~/Physijs/physijs_worker.js' ),
221+ },
222+ ammo = {
223+ 'ammo.js' : os .path .expanduser ( '~/Physijs/examples/js/ammo.js' ),
224+ },
225+ pixi = {
226+ 'pixi.js' : os .path .expanduser ( '~/pixi.js/bin/pixi.js' ),
227+ }
228+
229+ )
230+
231+ class LibsHandler ( tornado .web .RequestHandler ):
232+ def get (self , path = None ):
233+ print ('path' , path )
234+ module , name = path .split ('/' )
235+ assert module in LIBS
236+ assert name in LIBS [ module ]
237+ if os .path .isfile ( LIBS [module ][name ] ):
238+ data = open ( LIBS [module ][name ], 'rb' ).read ()
239+ else :
240+ raise tornado .web .HTTPError (404 )
241+
242+ self .set_header ("Content-Type" , "text/javascript; charset=utf-8" )
243+ self .set_header ("Content-Length" , len (data ))
244+ self .write ( data )
245+
246+
247+ class WebSocketHandler (tornado .websocket .WebSocketHandler ):
248+ def open (self ):
249+ print ( self .request .connection )
250+
251+ def on_message (self , msg , flags = None ):
252+ if hasattr (self .ws_connection , 'previous_command' ) and self .ws_connection .previous_command and self .ws_connection .previous_command .get ('binary' , False ):
253+ if self .ws_connection .previous_command ['command' ] == 'upload' :
254+ path = os .path .join (
255+ UploadDirectory ,
256+ self .ws_connection .previous_command ['file_name' ]
257+ )
258+ f = open ( path , 'wb' )
259+ f .write ( msg )
260+ f .close ()
261+
262+ self .ws_connection .previous_command = None
263+
264+ else :
265+ print ('on json message' , msg )
266+
267+ ob = json .loads ( msg )
268+ if isinstance (ob , dict ):
269+ if 'command' in ob :
270+ if ob ['command' ] == 'compile' :
271+ js = python_to_javascript ( ob ['code' ] )
272+ self .write_message ( {'eval' :js })
273+ elif ob ['command' ] == 'upload' :
274+ print ('ready for upload...' )
275+ print ( ob ['file_name' ] )
276+
277+ self .ws_connection .previous_command = ob
278+
279+ else :
280+ self .write_message ('"hello client"' )
281+
282+ def on_close (self ):
283+ print ('websocket closed' )
284+ if self .ws_connection :
285+ self .close ()
286+
287+
288+ Handlers = [
289+ ('/websocket' , WebSocketHandler ),
290+ ('/libs/' , LibsHandler ),
291+ ('/' , MainHandler )
292+ ]
293+
294+
295+
296+ app = tornado .web .Application ( Handlers )
297+ app .listen ( 8080 )
0 commit comments