33# Remote entry point for Tilde based on websockets
44# Author: Evgeny Blokhin
55
6- # TODO render HTML entirely at the client
7-
86import os , sys
97import math
108import time
2321
2422from tilde .core .settings import settings , GUI_URL_TPL
2523from tilde .core .api import API
26- from tilde .parsers import HASH_LENGTH
2724from tilde .core .common import html_formula , extract_chemical_symbols , str2html , num2name , generate_cif
2825import tilde .core .model as model
29- from tilde .berlinium import Async_Connection , add_redirection , eplotter , wrap_cell
26+ from tilde .berlinium import add_redirection , eplotter , wrap_cell , Async_Connection as Connection
3027
3128
3229logging .basicConfig (level = logging .WARNING )
3330
3431CURRENT_TITLE = settings ['title' ] if settings ['title' ] else 'API version ' + API .version
35- DB_TITLE = settings ['db' ]['default_sqlite_db' ] if settings ['db' ]['engine' ] == 'sqlite' else settings ['db' ]['dbname' ]
32+ DB_TITLE = settings ['db' ]['default_sqlite_db' ] if settings ['db' ]['engine' ] == 'sqlite' else settings ['db' ]['dbname' ] + '@' + settings [ 'db' ][ 'engine' ]
3633settings ['no_parse' ] = True
37- Tilde = API (settings )
34+ work = API (settings )
3835
3936class BerliniumGUIProvider :
4037 @staticmethod
4138 def login (req , client_id , db_session ):
4239 data = {
4340 'title' : CURRENT_TITLE ,
4441 'debug_regime' : settings ['debug_regime' ],
45- 'version' : Tilde .version ,
46- 'cats' : Tilde .hierarchy_groups
42+ 'version' : work .version ,
43+ 'cats' : work .hierarchy_groups ,
44+ 'dbsize' : work .count (db_session )
4745 }
4846 Connection .Clients [client_id ].authorized = True
4947
5048 if not req .get ('settings' ): req ['settings' ] = {}
5149
5250 # *client-side* settings
53- if req ['settings' ].get ('colnum' ) not in [50 , 100 , 250 ]: req ['settings' ]['colnum' ] = 100
54- if type (req ['settings' ].get ('cols' )) is not list or not 1 <= len (req ['settings' ].get ('cols' )) <= 40 : return (None , 'Invalid settings!' )
51+ if req ['settings' ].get ('colnum' ) not in [50 , 100 , 250 ]:
52+ req ['settings' ]['colnum' ] = 100
53+
54+ if type (req ['settings' ].get ('cols' )) is not list or not 1 <= len (req ['settings' ].get ('cols' )) <= 40 :
55+ return (None , 'Invalid settings!' )
5556
5657 for i in ['cols' , 'colnum' ]:
5758 Connection .Clients [client_id ].usettings [i ] = req ['settings' ].get (i )
5859
5960 # all available columns are compiled here and sent to user to select between them
6061 avcols = []
61- for entity in Tilde .hierarchy :
62+ for entity in work .hierarchy :
6263
6364 if entity ['has_column' ]:
6465 enabled = True if entity ['cid' ] in req ['settings' ]['cols' ] else False
@@ -76,16 +77,25 @@ def browse(req, client_id, db_session):
7677 data = {'html' : '' , 'count' : 0 , 'msg' : None }
7778 error = None
7879
79- try : start , sortby = int (req .get ('start' , 0 )), int (req .get ('sortby' , 0 ))
80- except ValueError : return (data , 'Sorry, unknown parameters in request' )
80+ try :
81+ start , sortby = int (req .get ('start' , 0 )), int (req .get ('sortby' , 0 ))
82+ except ValueError :
83+ return (data , 'Sorry, unknown parameters in request' )
84+
8185 start *= Connection .Clients [client_id ].usettings ['colnum' ]
8286 stop = start + Connection .Clients [client_id ].usettings ['colnum' ]
83- if sortby == 0 : sortby = model .Metadata .chemical_formula
84- elif sortby == 1 : sortby = model .Metadata .location
85- else : return (data , 'Unknown sorting requested!' )
87+
88+ if sortby == 0 :
89+ sortby = model .Metadata .chemical_formula
90+ elif sortby == 1 :
91+ sortby = model .Metadata .location
92+ else :
93+ return (data , 'Unknown sorting requested!' )
8694
8795 if req .get ('hashes' ):
88- if not isinstance (req ['hashes' ], list ) or len (req ['hashes' ][0 ]) != HASH_LENGTH : return (data , 'Invalid request!' )
96+ if not isinstance (req ['hashes' ], list ) or len (req ['hashes' ][0 ]) > 100 :
97+ return (data , 'Invalid request!' )
98+
8999 proposition = req ['hashes' ]
90100 data ['count' ] = len (proposition )
91101 proposition = proposition [start :stop ]
@@ -94,16 +104,23 @@ def browse(req, client_id, db_session):
94104 if req .get ('conditions' ):
95105 join_exception = None
96106 for c in req ['conditions' ]:
97- if not 'cid' in c or not 'min' in c or not 'max' in c : return (data , 'Invalid request!' )
98- try : entity = [x for x in Tilde .hierarchy if x ['cid' ] == int (c ['cid' ])][0 ]
99- except IndexError : return (data , 'Invalid category choice!' )
100- if not entity ['has_slider' ]: return (data , 'Invalid category choice!' )
107+ if not 'cid' in c or not 'min' in c or not 'max' in c :
108+ return (data , 'Invalid request!' )
109+ try :
110+ entity = [x for x in work .hierarchy if x ['cid' ] == int (c ['cid' ])][0 ]
111+ except IndexError :
112+ return (data , 'Invalid category choice!' )
113+ if not entity ['has_slider' ]:
114+ return (data , 'Invalid category choice!' )
101115
102116 cls , attr = entity ['has_slider' ].split ('.' )
103117 orm_inst = getattr (getattr (model , cls ), attr )
104118 clauses .append (orm_inst .between (c ['min' ], c ['max' ]))
105- if cls == 'Lattice' : join_exception = cls
106- else : clauses .append (getattr (getattr (model , cls ), 'checksum' ) == model .Calculation .checksum )
119+
120+ if cls == 'Lattice' :
121+ join_exception = cls
122+ else :
123+ clauses .append (getattr (getattr (model , cls ), 'checksum' ) == model .Calculation .checksum )
107124
108125 if join_exception == 'Lattice' :
109126 # Lattice objects require special join clause:
@@ -141,14 +158,14 @@ def browse(req, client_id, db_session):
141158 if not proposition : return (data , 'Invalid request!' )
142159
143160 html_output , res_count = '' , 0
144- html_output = '<thead><tr><th class=not-sortable><input type="checkbox" id="d_cb_all"></th>'
145- for entity in Tilde .hierarchy :
161+ html_output = '<thead><tr><th class=" not-sortable" ><input type="checkbox" id="d_cb_all"></th>'
162+ for entity in work .hierarchy :
146163 if entity ['has_column' ] and entity ['cid' ] in Connection .Clients [client_id ].usettings ['cols' ]:
147164 catname = str2html (entity ['html' ]) if entity ['html' ] else entity ['category' ][0 ].upper () + entity ['category' ][1 :]
148165
149- plottable = '<input class=sc type=checkbox />' if entity ['plottable' ] else ''
166+ plottable = '<input class="sc" type=" checkbox" />' if entity ['plottable' ] else ''
150167
151- html_output += '<th rel=' + str (entity ['cid' ]) + '><span>' + catname + '</span>' + plottable + '</th>'
168+ html_output += '<th rel=" ' + str (entity ['cid' ]) + '" ><span>' + catname + '</span>' + plottable + '</th>'
152169 #if Connection.Clients[client_id].usettings['objects_expand']: html_output += '<th class="not-sortable">More...</th>'
153170 html_output += '</tr></thead><tbody>'
154171
@@ -160,20 +177,20 @@ def browse(req, client_id, db_session):
160177 res_count += 1
161178 data_obj = json .loads (row )
162179
163- html_output += '<tr id=i_' + checksum + '>'
164- html_output += '<td><input type=checkbox id=d_cb_' + checksum + ' class=SHFT_cb></td>'
180+ html_output += '<tr id=" i_' + checksum + '" data-filename="' + data_obj . get ( 'location' , '' ). split ( os . sep )[ - 1 ] + '" >'
181+ html_output += '<td><input type=" checkbox" id=" d_cb_' + checksum + '" class=" SHFT_cb" ></td>'
165182
166- for entity in Tilde .hierarchy :
167- if not entity ['has_column' ]: continue
168- if not entity [ 'cid' ] in Connection . Clients [ client_id ]. usettings [ 'cols' ]: continue
183+ for entity in work .hierarchy :
184+ if not entity ['has_column' ] or entity [ 'cid' ] not in Connection . Clients [ client_id ]. usettings [ 'cols' ]:
185+ continue
169186
170- html_output += wrap_cell (entity , data_obj , Tilde .hierarchy_values , table_view = True )
187+ html_output += wrap_cell (entity , data_obj , work .hierarchy_values , table_view = True )
171188
172189 #if Connection.Clients[client_id].usettings['objects_expand']: html_output += "<td class=objects_expand><strong>click by row</strong></td>"
173190 html_output += '</tr>'
174191 html_output += '</tbody>'
175192
176- if not res_count : return ({'msg' : 'No objects found. ' }, error )
193+ if not res_count : return ({'msg' : 'No objects found' }, error )
177194
178195 data ['html' ] = html_output
179196 return (data , error )
@@ -187,12 +204,14 @@ def tags(req, client_id, db_session):
187204 if not tids :
188205 searchables = []
189206 for tid , cid , topic in db_session .query (model .Topic .tid , model .Topic .cid , model .Topic .topic ).order_by (model .Topic .topic ).all (): # FIXME assure there are checksums on such tid!
190- try : entity = [x for x in Tilde .hierarchy if x ['cid' ] == cid ][0 ]
191- except IndexError : return (None , 'Schema and data do not match: different versions of code and database?' )
207+ try :
208+ entity = [x for x in work .hierarchy if x ['cid' ] == cid ][0 ]
209+ except IndexError :
210+ return (None , 'Schema and data do not match: different versions of code and database?' )
192211
193212 if not entity .get ('creates_topic' ): continue # FIXME rewrite in SQL
194213
195- topic = num2name (topic , entity , Tilde .hierarchy_values )
214+ topic = num2name (topic , entity , work .hierarchy_values )
196215 searchables .append ((tid , topic ))
197216
198217 if not entity .get ('has_facet' ): continue
@@ -218,7 +237,7 @@ def tags(req, client_id, db_session):
218237 'content' : [ topic_dict ]
219238 })
220239
221- for entity in Tilde .hierarchy :
240+ for entity in work .hierarchy :
222241 if entity ['has_slider' ]:
223242 cls , attr = entity ['has_slider' ].split ('.' )
224243 orm_inst = getattr (getattr (model , cls ), attr )
@@ -234,7 +253,7 @@ def tags(req, client_id, db_session):
234253 })
235254
236255 categs .sort (key = lambda x : x ['sort' ])
237- categs = {'blocks' : categs , 'cats' : Tilde .hierarchy_groups , 'searchables' : searchables }
256+ categs = {'blocks' : categs , 'cats' : work .hierarchy_groups , 'searchables' : searchables }
238257
239258 else :
240259 params = {}
@@ -251,16 +270,20 @@ def tags(req, client_id, db_session):
251270
252271 @staticmethod
253272 def summary (req , client_id , db_session ):
254- if len (req ['datahash' ]) != HASH_LENGTH : return (None , 'Invalid request!' )
273+ if len (req ['datahash' ]) > 100 : return (None , 'Invalid request!' )
255274
256275 step = - 1
257276 clauses = [model .Lattice .struct_id == model .Structure .struct_id , model .Structure .checksum == req ['datahash' ]]
258277
259- if step != - 1 : clauses .append (model .Structure .step == step )
260- else : clauses .append (model .Structure .final == True )
278+ if step != - 1 :
279+ clauses .append (model .Structure .step == step )
280+ else :
281+ clauses .append (model .Structure .final == True )
261282
262- try : struct_id , a11 , a12 , a13 , a21 , a22 , a23 , a31 , a32 , a33 = db_session .query (model .Lattice .struct_id , model .Lattice .a11 , model .Lattice .a12 , model .Lattice .a13 , model .Lattice .a21 , model .Lattice .a22 , model .Lattice .a23 , model .Lattice .a31 , model .Lattice .a32 , model .Lattice .a33 ).filter (and_ (* clauses )).one ()
263- except NoResultFound : return (None , 'Nothing found!' )
283+ try :
284+ struct_id , a11 , a12 , a13 , a21 , a22 , a23 , a31 , a32 , a33 = db_session .query (model .Lattice .struct_id , model .Lattice .a11 , model .Lattice .a12 , model .Lattice .a13 , model .Lattice .a21 , model .Lattice .a22 , model .Lattice .a23 , model .Lattice .a31 , model .Lattice .a32 , model .Lattice .a33 ).filter (and_ (* clauses )).one ()
285+ except NoResultFound :
286+ return (None , 'Nothing found!' )
264287
265288 symbols , positions , is_final = [], [], False # TODO
266289 cell = [[a11 , a12 , a13 ], [a21 , a22 , a23 ], [a31 , a32 , a33 ]]
@@ -269,18 +292,17 @@ def summary(req, client_id, db_session):
269292 positions .append ([x , y , z ])
270293 cif = generate_cif (Atoms (symbols = symbols , cell = cell , positions = positions , pbc = True )) # TODO
271294
272- info = db_session .query (model .Grid .info ) \
273- . filter ( model . Grid . checksum == req [ 'datahash' ]). one ( )
295+ info = db_session .query (model .Grid .info ). filter ( model . Grid . checksum == req [ 'datahash' ]). one ()
296+ info = json . loads ( info [ 0 ] )
274297
275298 summary = []
276- info = json .loads (info [0 ])
277299
278- for entity in Tilde .hierarchy :
300+ for entity in work .hierarchy :
279301 if not entity ['has_summary_contrb' ]: continue # additional control to avoid redundancy
280302 #if entity['cid'] > 2000: # TODO apps
281303
282304 catname = str2html (entity ['html' ]) if entity ['html' ] else entity ['category' ].capitalize ()
283- summary .append ( {'category' : catname , 'sort' : entity .get ('sort' , 1000 ), 'content' : wrap_cell (entity , info , Tilde .hierarchy_values )} )
305+ summary .append ( {'category' : catname , 'sort' : entity .get ('sort' , 1000 ), 'content' : wrap_cell (entity , info , work .hierarchy_values )} )
284306
285307 summary .sort (key = lambda x : x ['sort' ])
286308
@@ -296,9 +318,11 @@ def summary(req, client_id, db_session):
296318 def optstory (req , client_id , db_session ):
297319 data , error = None , None
298320
299- try : tresholds = db_session .query (model .Struct_optimisation .tresholds ) \
321+ try :
322+ tresholds = db_session .query (model .Struct_optimisation .tresholds ) \
300323 .filter (model .Struct_optimisation .checksum == req ['datahash' ]).one ()
301- except NoResultFound : return (None , 'Nothing found!' )
324+ except NoResultFound :
325+ return (None , 'Nothing found!' )
302326
303327 data = eplotter ( task = 'optstory' , data = json .loads (tresholds [0 ]) )
304328
@@ -308,9 +332,11 @@ def optstory(req, client_id, db_session):
308332 def estory (req , client_id , db_session ):
309333 data , error = None , None
310334
311- try : convergence = db_session .query (model .Energy .convergence ) \
335+ try :
336+ convergence = db_session .query (model .Energy .convergence ) \
312337 .filter (model .Energy .checksum == req ['datahash' ]).one ()
313- except NoResultFound : return (None , 'Nothing found!' )
338+ except NoResultFound :
339+ return (None , 'Nothing found!' )
314340
315341 data = eplotter ( task = 'convergence' , data = json .loads (convergence [0 ]) )
316342
@@ -331,7 +357,6 @@ def settings(req, client_id, db_session):
331357
332358
333359if __name__ == "__main__" :
334- Connection = Async_Connection
335360 Connection .GUIProvider = BerliniumGUIProvider
336361 DuplexRouter = SockJSRouter (Connection )
337362
@@ -341,9 +366,12 @@ def settings(req, client_id, db_session):
341366 )
342367 application .listen (settings ['webport' ], address = '0.0.0.0' )
343368
344- logging .warning ("%s (%s backend): http://127.0.0.1:%s" % (CURRENT_TITLE , settings ['db' ]['engine' ], settings ['webport' ]))
369+ logging .warning ("%s serves http://127.0.0.1:%s" % (CURRENT_TITLE , settings ['webport' ]))
370+ logging .warning ("DB is %s" % DB_TITLE )
345371 logging .warning ("Connections are %s" % Connection .Type )
346372 logging .warning ("Press Ctrl+C to quit" )
347373
348- try : ioloop .IOLoop .instance ().start ()
349- except KeyboardInterrupt : pass
374+ try :
375+ ioloop .IOLoop .instance ().start ()
376+ except KeyboardInterrupt :
377+ pass
0 commit comments