def _check_session_timeout_routine(self): while True: if self._session_timeout > 0: # session timeout check is enable now = get_monotonic_time() timeout_sessions = [] for session in self._sessions.values(): if now - session.last_activity > self._session_timeout: timeout_sessions.append(session) for session in timeout_sessions: self._sessions.pop(session.session_id, None) # avoid future usage # kick out all timeout session for session in timeout_sessions: try: self._kick_timeout_sessions(session) except Exception as e: log.exception( 'Failed to kick out the timeout session "{}"'. format(session.session_id)) timeout_sessions.clear() delta_time = get_monotonic_time() - now if delta_time < TIMEOUT_CHECK_INTERVAL: gevent.sleep(TIMEOUT_CHECK_INTERVAL - delta_time) else: # session timeout check is disable, just None loop gevent.sleep(TIMEOUT_CHECK_INTERVAL)
def pingpong(self): try: if self._ws_client is None: self._ws_client = WSClient(self.url, self._recv_msg_cbk, self._close_cbk, protocols=['janus-protocol']) ping_start_ts = get_monotonic_time() self.send_request(self._ws_client, create_janus_msg('ping')) ping_end_ts = get_monotonic_time() ping_latency = ping_end_ts - ping_start_ts if self._hwm_threshold and ping_latency > self._hwm_threshold: self.set_status(JANUS_SERVER_STATUS_HWM) else: self.set_status(JANUS_SERVER_STATUS_NORMAL) except Exception as e: if self._has_destroy: return log.warning('Poll janus server({}) failed: {}'.format(self.url, e)) self.set_status(JANUS_SERVER_STATUS_ABNORMAL) if self._ws_client: try: self._ws_client.close() except Exception: pass self._ws_client = None
def send_message(self, message, timeout=30): """ send message :param message: object which can be encoded by msg_encoder (by default json encoder) :param timeout: send timeout in second, if timeout, gevent.Timeout exception will be raised :return: """ if self.server_terminated: raise Exception('Already closed: {0}'.format(self)) if self._pingpong_trigger: self._last_active_ts = get_monotonic_time() with gevent.Timeout(seconds=timeout): self.send(self._msg_encoder.encode(message), binary=False)
def received_message(self, message): if self._pingpong_trigger: self._last_active_ts = get_monotonic_time() if message.is_text: # log.debug('Received message from {0}: {1}'.format(self, message)) if self._recv_msg_cbk: try: self._recv_msg_cbk( self, self._msg_decoder.decode(str(message)), self._on_recv_msg_cbk_greenlet_exception) except Exception: log.exception( 'Failed to handle received msg on {0}'.format(self)) raise
def _pingpong_check_routine(self): while not self.server_terminated: gevent.sleep(1) if self.server_terminated: break now = get_monotonic_time() # check pingpong timeout if self._ping_ts: if now - self._ping_ts > self._pingpong_timeout: log.debug( 'Close ws connection ({}) because of no pong'.format( self)) self.close() break # send ping if idle if self._last_active_ts and now - self._last_active_ts >= self._pingpong_trigger: try: self.ping('') self._last_active_ts = self._ping_ts = get_monotonic_time() except Exception as e: log.error('Fail to send ping on {}: {}'.format( self, str(e))) self.close() break
def opened(self): # patch socket.sendall to protect it with lock, # in order to prevent sending data from multiple greenlets concurrently lock = RLock() _sendall = self.sock.sendall def sendall(data): lock.acquire() try: _sendall(data) except Exception: raise finally: lock.release() self.sock.sendall = sendall # start check idle if self._pingpong_trigger: self._last_active_ts = get_monotonic_time() self._pingpong_check_greenlet = gevent.spawn( self._pingpong_check_routine) # create app try: if not self.environ.get('QUERY_STRING'): query = {} else: query = urllib.parse.parse_qs(self.environ['QUERY_STRING'], keep_blank_values=True) for key, value in query.items(): query[key] = value[0] self._recv_msg_cbk = self.environ['app.recv_msg_cbk'] self._closed_cbk = self.environ['app.closed_cbk'] log.info('Created {0}'.format(self)) except Exception: log.exception('Failed to create app for {0}'.format(self)) raise
def check_idle(self): try: if self._has_destroy: return if self._server_status == JANUS_SERVER_STATUS_ABNORMAL: # server abnormal, pass idel check return if self._handle is None: # not connect server, connect first self.connect_server() handle = self._handle # 1. get room list reply_data, reply_jsep = _send_backend_message( handle, {'request': 'list'}) room_list_info = reply_data.get('list', []) # 2. find out idle rooms and timeout rooms now = get_monotonic_time() idle_rooms = {} timeout_room_ids = [] for room_info in room_list_info: room_id = int(room_info.get('room', 0)) if room_id == 0: continue # pass invalid or in-service room elif not room_info.get('description', '').startswith( self.des_filwter): continue # pass not januscloud-created room elif room_info.get('num_participants', 1) > 0: continue # not idle # this is a idle room idle_ts = self._idle_rooms.get(room_id, 0) if idle_ts == 0: # new idle room idle_rooms[room_id] = now elif now - idle_ts > self.destroy_timeout: # timeout room timeout_room_ids.append(room_id) else: # old idle room idle_rooms[room_id] = idle_ts self._idle_rooms = idle_rooms # 3. destroy the timeout rooms for room_id in timeout_room_ids: # auto destroy the idle room log.warning( 'Sweeper found the backend idle room {}, destroy it'. format(room_id)) handle.send_message({'request': 'destroy', 'room': room_id}) except Exception as e: if self._handle: handle = self._handle self._handle = None handle.detach() # ignore all exception when check log.debug( 'Videoroom sweeper check failed on server "{}" : {}. Retry in {} secs' .format(self.url, str(e), self.check_interval)) pass
def ponged(self, pong): self._ping_ts = 0 self._last_active_ts = get_monotonic_time()
def activate(self): self.last_activity = get_monotonic_time()
def __init__(self, session_id, transport=None): self.session_id = session_id self.ts = transport self._handles = {} self.last_activity = get_monotonic_time() self._has_destroyed = False