def generate_static(App, writefile): # prepare main_html ... mfn = os.path.realpath(__file__) mfn = os.path.dirname(mfn) if hasattr(App, 'main_html_file_path'): main_html_file_path = App.main_html_file_path else: main_html_file_path = None if not main_html_file_path: ffn = os.path.join(mfn, 'main.html') else: ffn = main_html_file_path lines = [] with open(ffn, 'r') as f: for l in f: if l.strip() == '<body onload="init_communication()">': l = '<body>' if l.lstrip().startswith('-->'): fnjs = l.split()[1].strip() if fnjs in ['js/classy.js', 'js/weba.js']: mfn = os.path.realpath(__file__) mfn = os.path.dirname(mfn) fnjs = os.path.join(mfn, fnjs) with open(fnjs, 'r') as fjs: l = fjs.read() lines.append(l) continue if fnjs == 'include': if hasattr(App, 'include'): for i in App.include: lines.append('<script src="'+i+'"></script>\n') continue if fnjs == 'meta': if hasattr(App, 'meta'): for m in App.meta: js = '<meta ' for a, v in m.items(): js += a+'="'+v+'" ' js += '>\n' lines.append(js) continue if fnjs != 'websocket': continue lines.append(l) main_html = ''.join(lines) static_html = [] for l in lines: if l.lstrip().startswith('-->'): rdoc = RemoteDocument() app = App() app.initialize(remote_document=rdoc, main_html=main_html) l = rdoc.pop_all_code() static_html.append(l) static_html = ''.join(static_html) with open(writefile, 'w') as f: f.write(static_html)
def initialize(self, **kwargs): log.info('Initiallizing a websocket handler!') try: self.id = _generate_session_id() self.remotedocument = RemoteDocument() self.closed = True self.session_id = None self.tab_id = None self.vendor_type = None self.shared_data = kwargs['shared_data'] self.session_data_store = kwargs['session_data_store'] self.tab_data_store = kwargs['tab_data_store'] self.session_data = None self.tab_data = None self.local_doc = kwargs['local_doc_class']() self.local_doc_initialized = False self.sharedhandlers = kwargs['shared_wshandlers'] self.sharedhandlers[self.id] = self self.is_new_tab = None self.is_new_session = None self.main_html = kwargs['main_html'] except: log.exception('Initialization of websocket handler failed!')
class WebSocketHandler(webalchemy.tornado.websocket.WebSocketHandler): @gen.coroutine def initialize(self, **kwargs): log.info('Initiallizing a websocket handler!') try: self.id = _generate_session_id() self.remotedocument = RemoteDocument() self.closed = True self.session_id = None self.tab_id = None self.vendor_type = None self.shared_data = kwargs['shared_data'] self.session_data_store = kwargs['session_data_store'] self.tab_data_store = kwargs['tab_data_store'] self.session_data = None self.tab_data = None self.local_doc = kwargs['local_doc_class']() self.local_doc_initialized = False self.sharedhandlers = kwargs['shared_wshandlers'] self.sharedhandlers[self.id] = self self.is_new_tab = None self.is_new_session = None self.main_html = kwargs['main_html'] except: log.exception('Initialization of websocket handler failed!') @gen.coroutine def open(self, *varargs): self.closed = False log.info('WebSocket opened') self.getargs = varargs @gen.coroutine def handle_binary_message(self, message): # TODO: implement this! raise NotImplementedError @gen.coroutine def on_message(self, message): log.info('Message received:\n' + message) try: if not isinstance(message, str): log.info('binary data') yield self.handle_binary_message(message) elif not self.local_doc_initialized: log.info('Initializing local document...') self.session_id = message.split(':')[1] self.is_new_session = False if self.session_id == 'null': log.info('initializing new session...') self.is_new_session = True self.session_id = self.id self.remotedocument.inline('set_cookie("webalchemy","' + self.session_id + '",3);\n') self.tab_id = message.split(':')[3] self.is_new_tab = False if self.tab_id == '': log.info('initializing new tab...') self.tab_id = self.id self.remotedocument.inline('window.name="' + self.tab_id + '";\n') self.is_new_tab = True self.vendor_type = message.split(':')[-1] self.remotedocument.set_vendor_prefix(self.vendor_type) self.session_data = self.session_data_store.get_store(self.session_id) self.tab_data = self.tab_data_store.get_store(self.tab_id) r = self.local_doc.initialize(remote_document=self.remotedocument, comm_handler=self, session_id=self.session_id, tab_id=self.tab_id, shared_data=self.shared_data, session_data=self.session_data, tab_data=self.tab_data, is_new_tab=self.is_new_tab, is_new_session=self.is_new_session, getargs=self.getargs, main_html=self.main_html) if r is not None: yield r self.local_doc_initialized = True else: if message.startswith('rpc: '): yield self.handle_js_to_py_rpc_message(message) elif message != 'done': log.info('Passing message to document inmessage...') r = self.local_doc.inmessage(message) if r is not None: yield r elif message != 'done': raise Exception('bad message received: '+str(message)) yield self.flush_dom() except: log.exception('Failed handling message:') @gen.coroutine def send_data(self, text, data): # TODO: implement! # will have to have a binary format for both text and binary data # also change the handling in the client raise NotImplementedError @gen.coroutine def flush_dom(self): code = self.remotedocument.pop_all_code() if code != '': log.info('FLUSHING DOM WITH FOLLOWING MESSAGE:\n' + code) # this is good to simulate latency #yield async_delay(2) self.write_message(code) else: log.info('FLUSHING DOM: **NOTHING TO FLUSH**') @gen.coroutine def please_reload(self): self.write_message('location.reload();\n') self.close() @gen.coroutine def msg_to_sessions(self, msg, send_to_self=False, to_session_ids=None): log.info('Sending message to sessions ' + str(len(self.sharedhandlers)) + ' documents in process:') log.info('Message: ' + msg) if not to_session_ids: lst = self.sharedhandlers.keys() else: lst = to_session_ids for k in lst: h = self.sharedhandlers[k] if h is not self or send_to_self: try: r = h.local_doc.outmessage(self.id, msg) if r is not None: yield r yield h.flush_dom() except: log.exception('Failed handling outmessage. Exception:') @gen.coroutine def on_close(self): self.closed = True log.info('WebSocket closed') log.info('Removing shared doc') del self.sharedhandlers[self.id] if hasattr(self.local_doc, 'onclose'): log.info('Calling local document onclose:') try: r = self.local_doc.onclose() if r is not None: yield r except: log.exception('Failed handling local document onclose. Exception:') @gen.coroutine def prepare_session_for_general_reload(self): if hasattr(self.local_doc, 'prepare_session_for_general_reload'): log.info('preparing session for reload...') r = self.local_doc.prepare_session_for_general_reload() if r is not None: yield r @gen.coroutine def handle_js_to_py_rpc_message(self, msg): log.info('Handling message as js->py RPC call') pnum, *etc = msg[5:].split(',') pnum = int(pnum) args_len = etc[:pnum] args_txt = ''.join(etc[pnum:]) args = [] curr_pos = 0 for ln in args_len: ln = int(ln) args.append(args_txt[curr_pos:curr_pos + ln]) curr_pos += ln rep, *args = args wr = self.remotedocument.jsrpcweakrefs[rep] fn = wr() if fn is None: del self.remotedocument.jsrpcweakrefs[rep] log.info('Calling local function: ' + str(fn)) log.info('With args: ' + str(args)) try: r = fn(self.id, *args) if r is not None: yield r except: log.exception('JS RPC call failed') @gen.coroutine def rpc(self, f, *varargs, send_to_self=False, to_session_ids=None, **kwargs): log.info('Sending py->py rpc: ' + f.__name__) log.info('PARAMS: varargs: ' + str(varargs) + ' kwargs: ' + str(kwargs)) if not to_session_ids: lst = self.sharedhandlers.keys() else: lst = to_session_ids log.info('lst=' + str(lst)) log.info('self.id=' + self.id) for k in lst: h = self.sharedhandlers[k] if h is not self or send_to_self: try: r = getattr(h.local_doc, f.__name__)(self.id, *varargs, **kwargs) if r is not None: yield r yield h.flush_dom() except: log.exception('PY RPC call failed for target session: ' + k)