def post(self): message_obj = json.loads(self.request.body) from_client_id = message_obj['fromClientId'] assert (self.session.user_id == int(from_client_id.split('|')[0])) room_id = message_obj['chatRoomId'] message_obj['fromUsernameAsWritten'] = self.session.username_as_written try: chat_room_obj = chat_room_module.ChatRoomModel.get_by_id(room_id) if chat_room_obj: self.handle_message_room(chat_room_obj, from_client_id, message_obj) else: logging.error('Unknown room_id %d' % room_id) raise Exception('unknownRoomId') http_helpers.set_http_ok_json_response(self.response, {}) except: status_string = 'Server error' http_status_code = 500 logging_function = logging.error http_helpers.set_error_json_response_and_write_log( self.response, status_string, logging_function, http_status_code, self.request)
def handle_message_client(self, from_client_id, message_obj): # This function passes a message from one user in a given "room" to the other user in the same room. # It is used for exchanging sdp (session description protocol) data for setting up sessions, as well # as for passing video and other information from one user to the other. to_client_id = message_obj['toClientId'] message_type = message_obj['messageType'] message_payload = message_obj['messagePayload'] message_obj['fromUsernameAsWritten'] = self.session.username_as_written if message_type == 'videoExchangeStatusMsg': logging.info('clientId %s videoElementsEnabledAndCameraAccessRequested is: %s ' % (from_client_id, message_payload['videoElementsEnabledAndCameraAccessRequested'])) if message_payload['videoElementsEnabledAndCameraAccessRequested'] == 'doVideoExchange': video_setup.VideoSetup.txn_add_user_id_to_video_elements_enabled_client_ids(from_client_id, to_client_id ) send_video_call_settings_to_participants(from_client_id, to_client_id) else: assert message_payload['videoElementsEnabledAndCameraAccessRequested'] == 'hangupVideoExchange' or \ message_payload['videoElementsEnabledAndCameraAccessRequested'] == 'denyVideoExchange' video_setup.VideoSetup.txn_remove_user_id_from_video_elements_enabled_client_ids(from_client_id, to_client_id ) if message_type == 'sdp' and message_payload['type'] == 'offer': # This is just for debugging logging.info('sdp offer. Payload: %s' % repr(message_payload)) logging.info('\n***\nSending message to client %s: %s\n' % (to_client_id, json.dumps(message_obj))) channel.send_message(to_client_id, json.dumps(message_obj)) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): client_id = self.session.client_obj.key.id() expire_dt = datetime.datetime.utcnow() + datetime.timedelta( minutes=constants.turn_relay_timeout_minutes) expire_ts = int(time.mktime((expire_dt).timetuple())) expire_datetime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expire_ts)) logging.debug('turn rest expires at %s (epoch value %d)' % (expire_datetime, expire_ts)) uris = [] for option in turn_uri_combinations: uris.append("turn:%s:%s?transport=%s" % (constants.turn_ip, option[0], option[1])) turn_username = "******" % (expire_ts, client_id) turn_password = b64encode( hmac.new(constants.turn_shared_secret, turn_username, hashlib.sha1).digest()) response_dict = { 'turn_username': turn_username, 'turn_password': turn_password, 'uris': uris } http_helpers.set_http_ok_json_response(self.response, response_dict)
def get(self, chat_room_name_from_url=None): chat_room_name_from_url = chat_room_name_from_url.decode('utf8') chat_room_name_normalized = chat_room_name_from_url.lower() if chat_room_name_normalized: logging.info('Query for room name: ' + chat_room_name_normalized) chat_room_obj = ChatRoomModel.query(ChatRoomModel.chat_room_name_normalized == chat_room_name_normalized).get() if chat_room_obj: response_dict = { 'chatRoomName': chat_room_name_normalized, 'roomIsRegistered': True, 'numInRoom': chat_room_obj.get_occupancy(), } logging.info('Found room: ' + repr(chat_room_obj)) else: response_dict = { 'chatRoomName': chat_room_name_normalized, 'roomIsRegistered' : False, 'numInRoom': 0 } logging.info('Room name is available: ' + chat_room_name_normalized) http_helpers.set_http_ok_json_response(self.response, response_dict) else: err_status = 'ErrorChatRoomNameRequired' # log this error for further analysis status_reporting.log_call_stack_and_traceback(logging.error, extra_info = err_status) http_helpers.set_http_error_json_response(self.response, err_status)
def get(self, username_from_url=None): username_from_url = username_from_url.decode('utf8') username_normalized = username_from_url.lower() if username_normalized: logging.info('Query for username: '******'usernameNormalized': username_normalized, 'usernameAvailable': False, } logging.info('Username taken: ' + repr(user_obj)) else: response_dict = { 'usernameNormalized': username_normalized, 'usernameAvailable': True, } logging.info('Username is available: ' + username_normalized) http_helpers.set_http_ok_json_response(self.response, response_dict) else: err_status = 'ErrorUsernameRequired' # log this error for further analysis status_reporting.log_call_stack_and_traceback(logging.error, extra_info = err_status) http_helpers.set_http_error_json_response(self.response, err_status)
def post(self): client_id = self.request.get('from') client_obj = clients.ClientModel.get_by_id(client_id) logging.warning('client_id: %s has been disconnected' % client_id) if client_obj: video_setup.VideoSetup.remove_video_setup_objects_containing_client_id(client_id) for chat_room_obj_key in client_obj.list_of_open_chat_rooms_keys: chat_room_obj = chat_room_obj_key.get() if chat_room_obj.has_client(client_id): # Remove the client from the room. However, notice that we don't remove the room from the client's # list_of_open_chat_rooms_keys, because if the channel comes back, we want the client to automatically # join the rooms that he previously had open. chat_room_obj = chat_room_obj.txn_remove_client_from_room(client_id) # This client has disconnected from the room, so we want to send an update to the remote # clients informing them of the new room status. messaging.send_room_occupancy_to_clients(chat_room_obj, chat_room_obj.room_members_client_ids, recompute_members_from_scratch=True) else: logging.info('Room %s (%d) does not have client %s - probably already removed' % (chat_room_obj.chat_room_name_normalized, chat_room_obj.key.id(), client_id)) http_helpers.set_http_ok_json_response(self.response, {})
def get(self): num_clients_removed = self.cleanup_expired_clients() if num_clients_removed >= NUM_OBJECTS_TO_REMOVE_AT_A_TIME: time.sleep(5.0) # just in case it takes a few milliseconds for the DB to get updated taskqueue.add(queue_name = 'cleanup-sessions-queue', url='/_lx/admin/cleanup_expired_clients/') http_helpers.set_http_ok_json_response(self.response, {'CleanupExpiredClients': 'OK'})
def post(self): data_object = json.loads(self.request.body) client_id = data_object['clientId'] assert self.session.user_id == int(client_id.split('|')[0]) room_id = data_object['chatRoomId'] chat_room_obj = chat_room_module.ChatRoomModel.get_by_id(room_id) self.add_client_to_room(chat_room_obj, client_id) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): data_object = json.loads(self.request.body) client_id = data_object['clientId'] assert self.session.user_id == int(client_id.split('|')[0]) logging.debug('CreateClientOnServer called for client_id: %s' % client_id) client_obj = clients.ClientModel.get_by_id(client_id) if not client_obj: clients.ClientModel.txn_create_new_client_object(client_id) http_helpers.set_http_ok_json_response(self.response, {})
def get(self): num_clients_removed = self.cleanup_expired_clients() if num_clients_removed >= NUM_OBJECTS_TO_REMOVE_AT_A_TIME: time.sleep( 5.0 ) # just in case it takes a few milliseconds for the DB to get updated taskqueue.add(queue_name='cleanup-sessions-queue', url='/_lx/admin/cleanup_expired_clients/') http_helpers.set_http_ok_json_response(self.response, {'CleanupExpiredClients': 'OK'})
def post(self): message_obj = self.session.post_body_json message_type = message_obj['messageType'] presence_state_name = message_obj['messagePayload']['presenceStateName'] currently_open_chat_room_id = message_obj['messagePayload']['currentlyOpenChatRoomId'] client_obj = self.session.client_obj client_id = client_obj.key.id() # We only update the user presence in the case that this is posted to as an acknowledgement # of a heartbeat. If we were to update presence state in other cases, then the memcache and other timeouts # that are synchronized to the heartbeat timing would be incorrect (eg. This function is also called when # the user changes rooms so that they receive an updated list of room members, but that doesn't mean # that their channel is currently up an running -- the channel is only proven to be up if we have received # an ackHeartBeat message from the client, as the client sends ackHeartBeat as a response to a # synAckHeartBeat message that is sent on the channel) if message_type == 'ackHeartbeat': # Get the previous presence state, so that we can detect if a user was offline, which would mean # that they need to be added back to all of the rooms that they previously had open. previous_presence_state = client_obj.get_current_presence_state() # Important to update the presence state before adding the client to the rooms, so that they will not # be immediately removed from the rooms in the event that we generate a new room members list (which # would remove offline clients) at the same time that we are attempting to add the client back to all of the # rooms that he previously had open. client_obj.store_current_presence_state(presence_state_name) if previous_presence_state == 'PRESENCE_OFFLINE': # Since the client was offline, they (should) have already been removed from all rooms that they # previously had open. Add them back to all rooms since we now know that they are alive. logging.info('Client %s had state %s, and is now getting added back to all previously ' 'open rooms. New client state is %s' % (client_id, previous_presence_state, presence_state_name)) AddClientToRoom.add_client_to_all_previously_open_rooms(client_obj) # Chat room that the client is currently looking at needs an up-to-date view of # clients and their activity. Other rooms do not need to be updated as often since the client is not looking # at these other rooms right now. Send the client an updated list of the currently viewed room members. if currently_open_chat_room_id is not None: chat_room_obj = chat_room_module.ChatRoomModel.get_by_id(currently_open_chat_room_id) if message_type == 'ackHeartbeat' and client_id not in chat_room_obj.room_members_client_ids: # This should not happen, as the above code should have added the client back to any rooms # that they opened as soon as he sent a message during a time when his state was # considered PRESENCE_OFFLINE. logging.error("client_id %s not in chat room %s even though he is requesting an update for that " "room." % (client_id, currently_open_chat_room_id)) messaging.send_room_occupancy_to_clients(chat_room_obj, [client_id,], recompute_members_from_scratch=False) http_helpers.set_http_ok_json_response(self.response, {})
def handle_message_room(self, chat_room_obj, from_client_id, message_obj): # This function passes a message from one user in a given "room" to the other user in the same room. # It is used for exchanging sdp (session description protocol) data for setting up sessions, as well # as for passing video and other information from one user to the other. # If to_client_id is "sendMsgToEveryoneInTheChatRoom", then the message will be sent to all room members, otherwise it will be sent # only to the indicated client. to_client_ids_list = chat_room_obj.get_list_of_other_client_ids(from_client_id) for to_client_id in to_client_ids_list: channel.send_message(to_client_id, json.dumps(message_obj)) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): duration_minutes = constants.channel_duration_minutes client_id = self.session.client_obj.key.id() channel_token = channel.create_channel(str(client_id), duration_minutes) logging.debug('New channel token created for client_id: %s' % client_id) response_dict = { 'channelToken': channel_token, } # Finally, send the http response. http_helpers.set_http_ok_json_response(self.response, response_dict)
def handle_message_room(self, chat_room_obj, from_client_id, message_obj): # This function passes a message from one user in a given "room" to the other user in the same room. # It is used for exchanging sdp (session description protocol) data for setting up sessions, as well # as for passing video and other information from one user to the other. # If to_client_id is "sendMsgToEveryoneInTheChatRoom", then the message will be sent to all room members, otherwise it will be sent # only to the indicated client. to_client_ids_list = chat_room_obj.get_list_of_other_client_ids( from_client_id) for to_client_id in to_client_ids_list: channel.send_message(to_client_id, json.dumps(message_obj)) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): client_id = self.session.client_obj.key.id() # Just send a short simple response so that the client can verify if the channel is up. response_message_obj = { 'fromClientId': client_id, # channel-services expects fromClientId to be specified. 'messageType': 'synAckHeartBeat' # use handshaking terminology for naming } logging.debug('Heartbeat synchronization received from client_id %s. ' 'Synchronization acknowledgement returned to same client on channel api' % (client_id)) channel.send_message(client_id, json.dumps(response_message_obj)) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): message_obj = json.loads(self.request.body) from_client_id = message_obj['fromClientId'] assert(self.session.user_id == int(from_client_id.split('|')[0])) try: self.handle_message_client(from_client_id, message_obj) http_helpers.set_http_ok_json_response(self.response, {}) except: status_string = 'Unknown server error' http_status_code = 500 logging_function = logging.error http_helpers.set_error_json_response_and_write_log(self.response, status_string, logging_function, http_status_code, self.request)
def post(self): try: room_dict = json.loads(self.request.body) # Need to get the URL encoded data from utf8. Note that json encoded data appears to already be decoded. # Convert camel case keys to underscore (standard python) keys room_dict = utils.convert_dict(room_dict, utils.camel_to_underscore) chat_room_name_as_written = room_dict['chat_room_name_as_written'] chat_room_name_normalized = chat_room_name_as_written.lower() room_dict['chat_room_name_normalized'] = chat_room_name_normalized # Make sure that the room name is valid before continuing. # These errors should be rare since these values are # already formatted to be within bounds and characters checked by the client-side javascript. # Only if the user has somehow bypassed the javascript checks should we receive values that don't # conform to the constraints that we have placed. if not constants.valid_chat_room_name_regex_compiled.match(chat_room_name_as_written): raise Exception('Room name regexp did not match') if len(chat_room_name_as_written) > constants.room_max_chars or len(chat_room_name_as_written) < constants.room_min_chars: raise Exception('Room name length of %s is out of range' % len(chat_room_name_as_written)) response_dict = {} user_id = int(room_dict['user_id']) assert self.session.user_id == user_id # If this is a new room, then the room_creator_user_key will be stored in the room # object as the "creator" of the room room_creator_user_key = ndb.Key('UserModel', user_id) chat_room_obj = ChatRoomModel.create_or_get_room(chat_room_name_normalized, room_dict, room_creator_user_key) response_dict['chatRoomNameNormalized'] = chat_room_name_normalized response_dict['chatRoomId'] = chat_room_obj.key.id() response_dict['statusString'] = 'roomJoined' http_helpers.set_http_ok_json_response(self.response, response_dict) except: # Unknown exception - provide feedback to the user to indicate that the room was not created or entered into err_status = 'ErrorUnableToCreateOrEnterRoom' # log this error for further analysis status_reporting.log_call_stack_and_traceback(logging.error, extra_info = err_status) http_helpers.set_http_ok_json_response(self.response, {'statusString': err_status})
def post(self): post_body_json = json.loads(self.request.body) client_id = post_body_json['clientId'] room_id = post_body_json['chatRoomId'] chat_room_obj = chat_room_module.ChatRoomModel.get_by_id(room_id) chat_room_obj = chat_room_obj.txn_remove_client_from_room(client_id) client_obj = clients.ClientModel.get_by_id(client_id) if client_obj: client_obj.txn_remove_room_from_client_status_tracker(chat_room_obj.key) messaging.send_room_occupancy_to_clients(chat_room_obj, chat_room_obj.room_members_client_ids, recompute_members_from_scratch=True) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): message_obj = json.loads(self.request.body) from_client_id = message_obj['fromClientId'] assert (self.session.user_id == int(from_client_id.split('|')[0])) try: self.handle_message_client(from_client_id, message_obj) http_helpers.set_http_ok_json_response(self.response, {}) except: status_string = 'Unknown server error' http_status_code = 500 logging_function = logging.error http_helpers.set_error_json_response_and_write_log( self.response, status_string, logging_function, http_status_code, self.request)
def post(self): data_object = json.loads(self.request.body) username_as_written = data_object['usernameAsWritten'] username_normalized = username_as_written.lower() auth_id = 'username:'******'t rely on auth_id because it is a list # containing various logins that the user may wish to use - such as email address, user name, perhaps # a facebook login token, etc. # Not necessary to include username in the unique_properties, since it will be included # in the "auth_id" in the create_user function, which will ensure that it is unique. unique_properties = None expiration_datetime = datetime.datetime.utcnow() + datetime.timedelta(minutes=constants.unregistered_user_token_session_expiry_minutes) user_created_bool, user_obj = users.UserModel.create_user(auth_id, unique_properties, username_normalized=username_normalized, username_as_written=username_as_written, registered_user_bool=False, expiration_datetime=expiration_datetime) if user_created_bool: user_id = user_obj.key.id() logging.info('New user object created. user_id: %d' % user_id) # close any active session the user has since he is trying to login # if self.session.is_active(): # self.session.terminate() # # # Writing a value to the session causes a new session to be created. # self.session.user_id = user_obj.key.id() # # self.redirect(self.uri_for('main')) jwt_token = token_sessions.generate_jwt_token(user_obj.key.id(), user_obj.username_as_written, expiration_datetime) response_dict = { 'token': jwt_token, } http_helpers.set_http_ok_json_response(self.response, response_dict) else: err_msg = 'Failed to create username %s', username_normalized logging.error(err_msg) http_helpers.set_http_error_json_response(self.response, err_msg, http_status_code=403)
def handle_message_client(self, from_client_id, message_obj): # This function passes a message from one user in a given "room" to the other user in the same room. # It is used for exchanging sdp (session description protocol) data for setting up sessions, as well # as for passing video and other information from one user to the other. to_client_id = message_obj['toClientId'] message_type = message_obj['messageType'] message_payload = message_obj['messagePayload'] message_obj['fromUsernameAsWritten'] = self.session.username_as_written if message_type == 'videoExchangeStatusMsg': logging.info( 'clientId %s videoElementsEnabledAndCameraAccessRequested is: %s ' % (from_client_id, message_payload[ 'videoElementsEnabledAndCameraAccessRequested'])) if message_payload[ 'videoElementsEnabledAndCameraAccessRequested'] == 'doVideoExchange': video_setup.VideoSetup.txn_add_user_id_to_video_elements_enabled_client_ids( from_client_id, to_client_id) send_video_call_settings_to_participants( from_client_id, to_client_id) else: assert message_payload['videoElementsEnabledAndCameraAccessRequested'] == 'hangupVideoExchange' or \ message_payload['videoElementsEnabledAndCameraAccessRequested'] == 'denyVideoExchange' video_setup.VideoSetup.txn_remove_user_id_from_video_elements_enabled_client_ids( from_client_id, to_client_id) if message_type == 'sdp' and message_payload['type'] == 'offer': # This is just for debugging logging.info('sdp offer. Payload: %s' % repr(message_payload)) logging.info('\n***\nSending message to client %s: %s\n' % (to_client_id, json.dumps(message_obj))) channel.send_message(to_client_id, json.dumps(message_obj)) http_helpers.set_http_ok_json_response(self.response, {})
def post(self): client_id = self.session.client_obj.key.id() expire_dt = datetime.datetime.utcnow() + datetime.timedelta(minutes=constants.turn_relay_timeout_minutes) expire_ts = int(time.mktime((expire_dt).timetuple())) expire_datetime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expire_ts)) logging.debug('turn rest expires at %s (epoch value %d)' % (expire_datetime, expire_ts)) uris = [] for option in turn_uri_combinations: uris.append("turn:%s:%s?transport=%s" % (constants.turn_ip, option[0], option[1])) turn_username = "******" % (expire_ts, client_id) turn_password = b64encode(hmac.new(constants.turn_shared_secret, turn_username, hashlib.sha1).digest()) response_dict = { 'turn_username': turn_username, 'turn_password': turn_password, 'uris': uris } http_helpers.set_http_ok_json_response(self.response, response_dict)
def post(self): message_obj = json.loads(self.request.body) from_client_id = message_obj['fromClientId'] assert(self.session.user_id == int(from_client_id.split('|')[0])) room_id = message_obj['chatRoomId'] message_obj['fromUsernameAsWritten'] = self.session.username_as_written try: chat_room_obj = chat_room_module.ChatRoomModel.get_by_id(room_id) if chat_room_obj: self.handle_message_room(chat_room_obj, from_client_id, message_obj) else: logging.error('Unknown room_id %d' % room_id) raise Exception('unknownRoomId') http_helpers.set_http_ok_json_response(self.response, {}) except: status_string = 'Server error' http_status_code = 500 logging_function = logging.error http_helpers.set_error_json_response_and_write_log(self.response, status_string, logging_function, http_status_code, self.request)
def post(self, logging_fn): client_error_string = self.format_main_response(logging_fn) logging_fn(client_error_string) http_helpers.set_http_ok_json_response(self.response, {})
def post(self, logging_fn): client_error_string = self.format_main_response(logging_fn) logging_fn(client_error_string) http_helpers.set_http_ok_json_response(self.response, {})