def serve_handler(self, handler, values): def invoke_handler(handler, sock): try: handler(sock, **values) finally: sock.close() th = Thread(target=invoke_handler, args=(handler, self,)) th.setDaemon(True) th.start() try: fd = uwsgi.connection_fd() while not self.evt_close.is_set(): uwsgi.wait_fd_read(fd, 0.3) uwsgi.suspend() _fd = uwsgi.ready_fd() msg = uwsgi.websocket.recv_nb() if msg: self.q_recv.put(msg) try: msg = self.q.get(True, 0.1) if msg: uwsgi.websocket_send(msg) except Empty: pass finally: self.close() th.join() return []
def application(env, start_response): # complete the handshake uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) r = redis.StrictRedis(host='redis-gandamu', port=6379, db=0) channel = r.pubsub() channel.subscribe('portfolio') websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() while True: uwsgi.wait_fd_read(websocket_fd, 3) uwsgi.wait_fd_read(redis_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd > -1: if fd == websocket_fd: msg = uwsgi.websocket_recv_nb() if msg: r.publish('portfolio', msg) elif fd == redis_fd: msg = channel.parse_response() # only interested in user messages t = 'message' if sys.version_info[0] > 2: t = b'message' if msg[0] == t: json = msg[2].decode('utf-8') uwsgi.websocket_send("%s" % json) # uwsgi.websocket_send("[%s] %s" % (time.time(), msg)) else: # on timeout call websocket_recv_nb again to manage ping/pong msg = uwsgi.websocket_recv_nb() if msg: r.publish('portfolio', msg)
def wait(self): # Remove context as we are switching between green thread # (and therefore websocket request) self.ws._pop_context() uwsgi.wait_fd_read(self.websocket_fd, 3) uwsgi.wait_fd_read(self.db_fd, 5) uwsgi.suspend() # Restoring request context for all other operations self.ws._push_context() fd = uwsgi.ready_fd() if fd == self.websocket_fd: return "websocket" if fd == self.db_fd: return "db" # Try ping / ponging the websocket in case of error return "timeout"
def recv(server, sock): while not sock.evt_open.is_set(): time.sleep(0.05) if hasattr(server, 'on_open'): server.on_open(self) try: fd = uwsgi.connection_fd() while not sock.evt_close.is_set(): uwsgi.wait_fd_read(fd, 1.0) uwsgi.suspend() _fd = uwsgi.ready_fd() msg = uwsgi.websocket_recv_nb() if msg: frame = (1, OP_TEXT, msg) server.on_message(sock, frame) finally: sock.evt_close.set()
def wsSubData_nb(self): """Websocket subscribe redis pubsub nonbolocking. Keepalive websocket connection with client.""" uwsgi.websocket_handshake(self.environ['HTTP_SEC_WEBSOCKET_KEY'], self.environ.get('HTTP_ORIGIN', '')) channel = self.r.pubsub() channel.subscribe(self.channel) channel.parse_response() websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() while True: uwsgi.wait_fd_read(websocket_fd, 3) uwsgi.wait_fd_read(redis_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd > -1: if fd == websocket_fd: uwsgi.websocket_recv_nb() elif fd == redis_fd: wsdata = channel.parse_response()[2] uwsgi.websocket_send(wsdata) else: uwsgi.websocket_recv_nb() time.sleep(1)
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() logging.info('connection established') try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] != 'ping': logging.info('command received: %s' % cmd['method']) if cmd['method'] == 'request': request_method(cmd, cursor) elif cmd['method'] == 'attach': attach_method(cmd, cursor, db_connection, env) elif cmd['method'] == 'detach': detach_method(cmd, cursor, db_connection, env) except Warning as err: logging.error(str(err)) # uwsgi.websocket_send(json.dumps({ # "method": "log", # "args": { # "level": "warning", # "message": err.diag.message_primary # } # })) elif fd == db_conn_fd: handle_db_notifications(db_connection) else: logging.info('timeout reached') # This is never reached # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except (OSError, IOError) as err: logging.info('connection closed (role: %s)' % env['DB_USER']) return []
def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type','text/html')]) output = """ <!doctype html> <html> <head> <meta charset="utf-8"> <script language="Javascript"> var s = new WebSocket("%s://%s/foobar/"); s.onopen = function() { console.log("connected !!!"); s.send("hello"); }; s.onmessage = function(e) { var bb = document.getElementById('blackboard') var html = bb.innerHTML; bb.innerHTML = html + '<br/>' + e.data; }; s.onerror = function(e) { console.log(e); } s.onclose = function(e) { console.log("connection closed"); } function invia() { var value = document.getElementById('testo').value; s.send(value); } </script> </head> <body> <h1>WebSocket</h1> <input type="text" id="testo"/> <input type="button" value="invia" onClick="invia();"/> <div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto"> </div> </body> </html> """ % (ws_scheme, env['HTTP_HOST']) return output.encode() elif env['PATH_INFO'] == '/favicon.ico': return "" elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) print("websockets...") msg_srv_fd = uwsgi.async_connect("127.0.0.1:8888") websocket_fd = uwsgi.connection_fd() while True: uwsgi.wait_fd_read(websocket_fd, 3) uwsgi.wait_fd_read(msg_srv_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd > -1: if fd == websocket_fd: msg = uwsgi.websocket_recv_nb() print("got message over ws: {}".format(msg)) if msg: uwsgi.send(msg_srv_fd, msg) elif fd == msg_srv_fd: msg = uwsgi.recv(msg_srv_fd) print("got message over msg_srv: {}".format(msg)) uwsgi.websocket_send("[%s] %s" % (time.time(), msg.decode())) else: # on timeout call websocket_recv_nb again to manage ping/pong msg = uwsgi.websocket_recv_nb() print("ws ping/pong") if msg: print("got message over ws: {}".format(msg)) uwsgi.send(msg_srv_fd, msg)
def uwsgi_pypy_wait_fd_read(fd, timeout=0): wsgi_req = uwsgi_pypy_current_wsgi_req(); if lib.async_add_fd_read(wsgi_req, fd, timeout) < 0: raise Exception("unable to add fd %d to the event queue" % fd) uwsgi.wait_fd_read = uwsgi_pypy_wait_fd_read """ uwsgi.wait_fd_write(fd, timeout=0) """ def uwsgi_pypy_wait_fd_write(fd, timeout=0): wsgi_req = uwsgi_pypy_current_wsgi_req(); if lib.async_add_fd_write(wsgi_req, fd, timeout) < 0: raise Exception("unable to add fd %d to the event queue" % fd) uwsgi.wait_fd_write = uwsgi_pypy_wait_fd_write """ uwsgi.ready_fd() """ def uwsgi_pypy_ready_fd(): wsgi_req = uwsgi_pypy_current_wsgi_req(); return lib.uwsgi_ready_fd(wsgi_req) uwsgi.ready_fd = uwsgi_pypy_ready_fd """ uwsgi.send(fd=None,data) """ def uwsgi_pypy_send(*args): if len(args) == 0: raise ValueError("uwsgi.send() takes at least 1 argument") elif len(args) == 1:
def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) output = """ <html> <head> <script language="Javascript"> var s = new WebSocket("%s://%s/foobar/"); s.onopen = function() { alert("connected !!!"); s.send("ciao"); }; s.onmessage = function(e) { var bb = document.getElementById('blackboard') var html = bb.innerHTML; bb.innerHTML = html + '<br/>' + e.data; }; s.onerror = function(e) { alert(e); } s.onclose = function(e) { alert("connection closed"); } function invia() { var value = document.getElementById('testo').value; s.send(value); } </script> </head> <body> <h1>WebSocket</h1> <input type="text" id="testo"/> <input type="button" value="invia" onClick="invia();"/> <div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto"> </div> </body> </html> """ % (ws_scheme, env['HTTP_HOST']) if sys.version_info[0] > 2: return output.encode('latin1') return output elif env['PATH_INFO'] == '/favicon.ico': return "" elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) print("websockets...") r = redis.StrictRedis(host='localhost', port=6379, db=0) channel = r.pubsub() channel.subscribe('foobar') websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() while True: uwsgi.wait_fd_read(websocket_fd, 3) uwsgi.wait_fd_read(redis_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd > -1: if fd == websocket_fd: msg = uwsgi.websocket_recv_nb() if msg: r.publish('foobar', msg) elif fd == redis_fd: msg = channel.parse_response() print(msg) # only interested in user messages t = 'message' if sys.version_info[0] > 2: t = b'message' if msg[0] == t: uwsgi.websocket_send("[%s] %s" % (time.time(), msg)) else: # on timeout call websocket_recv_nb again to manage ping/pong msg = uwsgi.websocket_recv_nb() if msg: r.publish('foobar', msg)
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() logging.info('connection established') try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] != 'ping': logging.info('command received: %s' % cmd['method']) if cmd['method'] == 'request': request_method(cmd, cursor) elif cmd['method'] == 'attach': attach_method(cmd, cursor, db_connection, env) elif cmd['method'] == 'detach': detach_method(cmd, cursor, db_connection, env) except Warning as err: logging.error(str(err)) # uwsgi.websocket_send(json.dumps({ # "method": "log", # "args": { # "level": "warning", # "message": err.diag.message_primary # } # })) elif fd == db_conn_fd: handle_db_notifications(db_connection) else: logging.info( 'timeout reached') # This is never reached # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except (OSError, IOError) as err: logging.info('connection closed (role: %s)' % env['DB_USER']) return []
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) session_id = get_session_id(request, cursor) logging.info('event/table/session/row/%s:connected (role: %s)' % (session_id, env['DB_USER'])) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() cursor.execute('listen "event/table/session/rows/%i"' % session_id) try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] == 'subscribe': selector, type = cmd['args']['selector'].rsplit(':', 1) cursor.execute("select event.subscribe_session(%s, %s, %s);", (session_id, selector, type)) elif cmd['method'] == 'unsubscribe': selector, type = cmd['args']['selector'].rsplit(':', 1) cursor.execute("select event.unsubscribe_session(%s, %s, %s);", (session_id, selector, type)) except Warning as err: logging.error(str(err)) uwsgi.websocket_send(json.dumps({ "method": "log", "args": { "level": "warning", "message": err.diag.message_primary } })) elif fd == db_conn_fd: db_connection.poll() if db_connection.notifies: del db_connection.notifies[:] cursor.execute(''' select * from event.session_queued_events_json(%s) ''', (session_id,)) qe_ids = [] logging.info('event/table/session/row/%s:flushing_queue (role: %s)' % (session_id, env['DB_USER'])) for row in cursor: uwsgi.websocket_send(json.dumps(row.event_json)) logging.info('event/table/session/row/%s:sent_json (role: %s)' % (session_id, env['DB_USER'])) qe_ids.append(row.queued_event_id) cursor.execute(''' delete from event.queued_event qe where qe.id = any(%s) ''', (qe_ids,)) else: # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except OSError as err: logging.info('event/table/session/row/%s:disconnected (role: %s)' % (session_id, env['DB_USER'])) return []
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) session_id = get_session_id(request, cursor) logging.info('event/table/session/row/%s:connected (role: %s)' % (session_id, env['DB_USER'])) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() cursor.execute('listen "event/table/session/rows/%i"' % session_id) try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] == 'subscribe': selector, type = cmd['args'][ 'selector'].rsplit(':', 1) cursor.execute( "select event.subscribe_session(%s, %s, %s);", (session_id, selector, type)) elif cmd['method'] == 'unsubscribe': selector, type = cmd['args'][ 'selector'].rsplit(':', 1) cursor.execute( "select event.unsubscribe_session(%s, %s, %s);", (session_id, selector, type)) except Warning as err: logging.error(str(err)) uwsgi.websocket_send( json.dumps({ "method": "log", "args": { "level": "warning", "message": err.diag.message_primary } })) elif fd == db_conn_fd: db_connection.poll() if db_connection.notifies: del db_connection.notifies[:] cursor.execute( ''' select * from event.session_queued_events_json(%s) ''', (session_id, )) qe_ids = [] logging.info( 'event/table/session/row/%s:flushing_queue (role: %s)' % (session_id, env['DB_USER'])) for row in cursor: uwsgi.websocket_send(json.dumps( row.event_json)) logging.info( 'event/table/session/row/%s:sent_json (role: %s)' % (session_id, env['DB_USER'])) qe_ids.append(row.queued_event_id) cursor.execute( ''' delete from event.queued_event qe where qe.id = any(%s) ''', (qe_ids, )) else: # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except OSError as err: logging.info( 'event/table/session/row/%s:disconnected (role: %s)' % (session_id, env['DB_USER'])) return []
def get(self): def handle_request(r, msg): """Handle request for more messages received from websocket.""" request = json.loads(msg) first = int(request["first_id"]) last = int(request["last_id"]) # Don't fetch more than 50 messages at once: if (last > 0 and (last - 50 > first)) or (last < 0): first = last - 50 pickled_messages = r.lrange(REDIS_MESSAGES_KEY, first, last) messages = [] for pickled_message in pickled_messages: message = pickle.loads(pickled_message) messages.append(message) uwsgi.websocket_send(encode_messages(messages)) # The first thing we need to do is take what seems like a normal HTTP # request and upgrade it to be a websocket request: uwsgi.websocket_handshake(os.getenv('HTTP_SEC_WEBSOCKET_KEY', ''), os.getenv('HTTP_ORIGIN', '')) # Open a connection to the Redis server, and ask to be notified of any # messages on the channel REDIS_CHANNEL: r = redis.StrictRedis(host='localhost', port=6379, db=0) channel = r.pubsub() channel.subscribe(REDIS_CHANNEL) # We then want to go to sleep and wait for messages either from Redis, # or from this websocket. So we need to know their file descriptors: websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() while True: # Setup both FDs with epoll so we can wait for messages. Wake up # every 3 seconds to ensure that ping messages get exchanged on the # websocket connection to keep it alive: uwsgi.wait_fd_read(websocket_fd, 3) uwsgi.wait_fd_read(redis_fd) # Put thread to sleep until message arrives or timeout. Note that # if you do not use a suspend engine (such as ugreen) this will just # immediately return without suspending, nothing will work, and you # will get horribly confused. uwsgi.suspend() fd = uwsgi.ready_fd() if fd > -1: if fd == websocket_fd: try: msg = uwsgi.websocket_recv_nb() if msg: handle_request(r, msg) except IOError, e: # Websocket has failed in some way (such as a browser # reload), just close it and let the app re-open if it # is still there to do so: return elif fd == redis_fd: # Got a message from Redis, pass it on to the browser # through the websocket. msg = channel.parse_response() # Redis sends both control messages and user messages # through this fd. Send only user-generated messages to all # clients: if msg[0] == b'message': uwsgi.websocket_send(msg[2]) else: # We got a timeout. Call websocket_recv_nb again to manage # ping/pong: try: msg = uwsgi.websocket_recv_nb() if msg: handle_request(r, msg) except IOError, e: # Websocket has failed in some way (such as a browser # reload), just close it and let the app re-open if it is # still there to do so: return
def application(env, start_response): request = Request(env) try: uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) except OSError as err: logging.info('handshake_failed') else: with cursor_for_request(request) as cursor: db_connection = cursor.connection db_connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) db_conn_fd = db_connection.fileno() websocket_fd = uwsgi.connection_fd() logging.info('connection established') try: while True: uwsgi.wait_fd_read(websocket_fd) uwsgi.wait_fd_read(db_conn_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd == websocket_fd: cmd_json = uwsgi.websocket_recv_nb() if cmd_json: cmd = json.loads(cmd_json.decode('utf-8')) if cmd: try: if cmd['method'] != 'ping': logging.info('command received: %s' % cmd['method']) if cmd['method'] == 'request': logging.info( 'websocket endpoint request: %s, %s, %s, %s' % ( cmd['verb'], # HTTP method - GET, POST, PATCH, DELETE cmd['uri'], # selector - '/relation/widget/dependency_js' ImmutableMultiDict( json.loads(cmd['query']) ), # query string arguments - including event.session id json.dumps( cmd['data']) # post data )) cursor.execute( 'select status, message, response, mimetype from endpoint.request2(%s, %s, %s::json, %s::json);', ( cmd['verb'], # HTTP method - GET, POST, PATCH, DELETE cmd['uri'], # selector - '/relation/widget/dependency_js' json.dumps( ImmutableMultiDict( json.loads( cmd['query']) ).to_dict(flat=False) ), # query string arguments - including event.session id json.dumps( cmd['data']) # post data )) result = cursor.fetchone() uwsgi.websocket_send('''{ "method": "response", "request_id": "%s", "data": %s }''' % (cmd['request_id'], result.response)) elif cmd['method'] == 'attach': session_id = cmd['session_id'] if session_id is not None: cursor.execute( 'select event.session_attach(%s);', (session_id, )) logging.info( 'session attached: %s (role: %s)' % (session_id, env['DB_USER'])) handle_db_notifications( db_connection) uwsgi.websocket_send('''{ "method": "response", "request_id": "%s", "data": "true" }''' % (cmd['request_id'], )) elif cmd['method'] == 'detach': session_id = cmd['session_id'] if session_id is not None: cursor.execute( 'select event.session_detach(%s);', (session_id, )) logging.info( 'session detached: %s (role: %s)' % (session_id, env['DB_USER'])) uwsgi.websocket_send('''{ "method": "response", "request_id": "%s", "data": "true" }''' % (cmd['request_id'], )) #uwsgi.websocket_send('''{ # "method": "response", # "request_id": "%s", # "data": %s #}''' % (cmd['request_id'], result.response)) except Warning as err: logging.error(str(err)) # uwsgi.websocket_send(json.dumps({ # "method": "log", # "args": { # "level": "warning", # "message": err.diag.message_primary # } # })) elif fd == db_conn_fd: handle_db_notifications(db_connection) else: logging.info( 'timeout reached') # This is never reached # handle timeout of above wait_fd_read for ping/pong uwsgi.websocket_recv_nb() except (OSError, IOError) as err: logging.info('connection closed (role: %s)' % env['DB_USER']) return []