Example #1
0
    async def leave_group(self, request, context):
        try:
            leave_member = request.leave_member
            leave_member_by = request.leave_member_by

            new_member_status = "removed"
            if leave_member.id == leave_member_by.id:
                new_member_status = "leaved"

            group = GroupService().get_group_info(request.group_id)
            group_clients = json.loads(group.group_clients)

            leave_member_in_group = False
            leave_member_by_in_group = False
            for e in group_clients:
                if e['id'] == leave_member.id:
                    leave_member_in_group = True
                    e['status'] = new_member_status
                if e['id'] == leave_member_by.id:
                    leave_member_by_in_group = True
            if not leave_member_in_group:
                raise Exception(Message.LEAVED_MEMBER_NOT_IN_GROUP)
            if not leave_member_by_in_group and new_member_status == "removed":
                raise Exception(Message.REMOVER_MEMBER_NOT_IN_GROUP)

            # update field group_clients first
            logger.info("New group client: {}".format(group_clients))
            group.group_clients = json.dumps(group_clients)
            group.updated_by = leave_member_by.id
            group.update()

            owner_workspace_domain = get_owner_workspace_domain()

            # wait for service to leave group, and return base response if no exception occured
            if (group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain):
                await self.service.leave_group_not_owner(
                    leave_member,
                    leave_member_by,
                    group,
                )
            else:
                await self.service.leave_group_owner(
                    leave_member,
                    leave_member_by,
                    group,
                )

            return group_messages.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.LEAVE_GROUP_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #2
0
 async def GroupGetClientKey(self, request, context):
     try:
         group_id = request.groupId
         client_id = request.clientId
         # get group first
         group = GroupService().get_group_obj(group_id)
         owner_workspace_domain = get_owner_workspace_domain()
         if group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain:
             owner_workspace_group_id = group.owner_group_id
             obj_resp = self.service.group_by_owner_get_client_key(owner_workspace_group_id, client_id)
             if obj_resp is not None:
                 response = signal_pb2.GroupGetClientKeyResponse(
                     groupId=obj_resp.group_id,
                     clientKey=signal_pb2.GroupClientKeyObject(
                         clientId=obj_resp.client_id,
                         deviceId=obj_resp.device_id,
                         clientKeyDistribution=obj_resp.client_key
                     )
                 )
                 return response
             else:
                 obj_resp = ClientSignal(group.owner_workspace_domain).group_get_client_key(group.owner_group_id, client_id)
                 return obj_resp
         else:
             obj_resp = self.service.group_get_client_key(group_id, client_id)
             if obj_resp is not None:
                 if obj_resp.client_workspace_domain and obj_resp.client_workspace_domain != owner_workspace_domain:
                     obj_resp = ClientSignal(obj_resp.client_workspace_domain).workspace_group_get_client_key(obj_resp.client_workspace_group_id, obj_resp.client_id)
                     return obj_resp
                 else:
                     response = signal_pb2.GroupGetClientKeyResponse(
                         groupId=obj_resp.group_id,
                         clientKey=signal_pb2.GroupClientKeyObject(
                             clientId=obj_resp.client_id,
                             deviceId=obj_resp.device_id,
                             clientKeyDistribution=obj_resp.client_key
                         )
                     )
                     return response
         raise Exception(Message.CLIENT_SIGNAL_KEY_NOT_FOUND)
     except Exception as e:
         errors = [Message.get_error_object(Message.CLIENT_SIGNAL_KEY_NOT_FOUND)]
         context.set_details(json.dumps(
             errors, default=lambda x: x.__dict__))
         context.set_code(grpc.StatusCode.NOT_FOUND)
Example #3
0
 async def workspace_get_messages_in_group(self, request, context):
     try:
         logger.info("workspace_get_messages_in_group")
         owner_workspace_domain = get_owner_workspace_domain()
         group = GroupService().get_group_info(request.group_id)
         if group.owner_workspace_domain is None or group.owner_workspace_domain == owner_workspace_domain:
             obj_res = self.service.get_message_in_group(request.client_id, request.group_id, request.off_set, request.last_message_at)
         else:
             raise Exception(Message.GET_MESSAGE_IN_GROUP_FAILED)
         return obj_res
     except Exception as e:
         logger.error(e)
         if not e.args or e.args[0] not in Message.msg_dict:
             errors = [Message.get_error_object(Message.GET_MESSAGE_IN_GROUP_FAILED)]
         else:
             errors = [Message.get_error_object(e.args[0])]
         context.set_details(json.dumps(
             errors, default=lambda x: x.__dict__))
         context.set_code(grpc.StatusCode.INTERNAL)
Example #4
0
    async def get_messages_in_group(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            client_id = introspect_token['sub']

            group_id = request.group_id
            off_set = request.off_set
            last_message_at = request.last_message_at

            owner_workspace_domain = get_owner_workspace_domain()
            group = GroupService().get_group_info(group_id)

            if group and group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain:
                workspace_request = message_pb2.WorkspaceGetMessagesInGroupRequest(
                    group_id = group.owner_group_id,
                    client_id = client_id,
                    off_set = request.off_set,
                    last_message_at = request.last_message_at
                )
                obj_res = ClientMessage(group.owner_workspace_domain).workspace_get_messages_in_group(workspace_request)
                if obj_res and obj_res.lst_message:
                    for obj in obj_res.lst_message:
                        obj.group_id = group_id
                        obj.client_workspace_domain = owner_workspace_domain
                    return obj_res
                else:
                    raise
            else:
                obj_res = self.service.get_message_in_group(client_id, group_id, off_set, last_message_at)
                return obj_res
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                # TODO: change message when got error
                errors = [Message.get_error_object(Message.GET_MESSAGE_IN_GROUP_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #5
0
    async def update_call_to_group_not_owner(self, request, group, from_client_id):
        logger.info("update_call_to_group_not_owner")

        client_id = request.client_id
        update_type = request.update_type
        from_client_username = ""
        from_client_avatar = ""
        owner_workspace_domain = get_owner_workspace_domain()

        # update call to owner server, response ọbject push notification
        lst_client = GroupService().get_clients_in_group_owner(group.owner_group_id)
        for client in lst_client:
            if client.User.id == from_client_id:
                from_client_username = client.User.display_name
                from_client_avatar = client.User.avatar
            else:
                # ret_val = NotifyInAppService().notify_client_update_call(update_type, client.GroupClientKey.client_id, from_client_id, client.GroupClientKey.group_id)
                # if not ret_val:
                push_payload = {
                    'notify_type': update_type,
                    'group_id': str(client.GroupClientKey.group_id),
                    'from_client_id': from_client_id,
                    'from_client_name': from_client_username,
                    'from_client_avatar': from_client_avatar,
                    'client_id': client_id
                }
                await NotifyPushService().push_voip_client(client.GroupClientKey.client_id, push_payload)

        request = video_call_pb2.WorkspaceUpdateCallRequest(
            from_client_id=from_client_id,
            from_client_name=from_client_username,
            from_client_avatar=from_client_avatar,
            from_client_workspace_domain=owner_workspace_domain,
            client_id=client_id,
            group_id=group.owner_group_id,
            update_type=update_type
        )
        obj_res = ClientVideoCall(group.owner_workspace_domain).workspace_update_call(request)
        return video_call_pb2.BaseResponse()
Example #6
0
    async def update_call(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            from_client_id = introspect_token['sub']
            group_id = request.group_id

            owner_workspace_domain = get_owner_workspace_domain()

            group = GroupService().get_group_info(group_id)
            if group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain:
                return await self.update_call_to_group_not_owner(request, group, from_client_id)
            else:
                return await self.update_call_to_group_owner(request, from_client_id)
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_UPDATE_CALL_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #7
0
    async def Publish(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            user_id = introspect_token['sub']

            owner_workspace_domain = get_owner_workspace_domain()
            group = GroupService().get_group_info(request.groupId)

            if group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain:
                res_obj = await self.publish_to_group_not_owner(request, user_id, group)
                return res_obj
            else:
                res_obj = await self.publish_to_group_owner(request, user_id, group)
                return res_obj
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_PUBLISH_MESSAGE_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #8
0
 def __init__(self):
     self.service_group = GroupService()
     self.push_service = NotifyPushService()
Example #9
0
    async def add_member(self, request, context):
        try:
            group = GroupService().get_group_info(request.group_id)
            group_clients = json.loads(group.group_clients)
            added_member_info = request.added_member_info
            adding_member_info = request.adding_member_info

            #get workspace is active in group
            workspace_domains = list(set(
                [e['workspace_domain'] for e in group_clients
                 if ('status' not in e or
                     ('status' in e and e['status'] in ['active']))]
            ))
            logger.info(workspace_domains)

            #check added and adding member in group
            adding_member_in_group = False
            for e in group_clients:
                if 'status' not in e or e['status'] in ['active']:
                    if e['id'] == added_member_info.id:
                        raise Exception(Message.ADDED_USER_IS_ALREADY_MEMBER)
                    if e['id'] == adding_member_info.id:
                        adding_member_in_group = True
            if not adding_member_in_group:
                raise Exception(Message.ADDER_MEMBER_NOT_IN_GROUP)

            # new group clients
            new_group_clients = []
            is_old_member = False
            for e in group_clients:
                if e['id'] == added_member_info.id:
                    e['status'] = 'active'  # turn into active member
                    is_old_member = True
                new_group_clients.append(e)
            if not is_old_member:
                added_member_info.status = 'active'
                new_group_clients.append(
                    MessageToDict(
                        added_member_info,
                        preserving_proto_field_name=True
                    )
                )

            # update group members first
            group.group_clients = json.dumps(new_group_clients)
            group.updated_by = adding_member_info.id
            group.updated_at = datetime.datetime.now()
            group.update()

            owner_workspace_domain = get_owner_workspace_domain()

            # wait for service to add member to group, and return base response if no exception occured
            if (group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain):
                await self.service.add_member_to_group_not_owner(
                    added_member_info,
                    adding_member_info,
                    group,
                )
            else:
                await self.service.add_member_to_group_owner(
                    added_member_info,
                    adding_member_info,
                    group
                )

            return group_messages.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.ADD_MEMBER_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #10
0
    async def publish_to_group_not_owner(self, request, from_client_id, group):
        logger.info("publish_to_group_not_owner from client_id {}, group_id={}".format(from_client_id, str(group.id)))

        owner_workspace_domain = get_owner_workspace_domain()
        message_id = str(uuid.uuid4())
        created_at = datetime.now()

        message_res_object = message_pb2.MessageObjectResponse(
            id=message_id,
            client_id=request.clientId,
            group_id=group.id,
            group_type=group.group_type,
            from_client_id=from_client_id,
            from_client_workspace_domain=owner_workspace_domain,
            message=request.message,
            created_at=int(created_at.timestamp() * 1000),
            sender_message=request.sender_message
        )

        # publish message to user in this server first
        lst_client = GroupService().get_clients_in_group_owner(group.owner_group_id)
        push_service = NotifyPushService()

        for client in lst_client:
            for notify_token in client.User.tokens:
                if client.User is None:
                    continue
                device_id = notify_token.device_id
                logger.info('device_id in real loop in handle {}'.format(device_id))
                if client.GroupClientKey.client_id == from_client_id and device_id == request.from_client_device_id:
                    continue
                message_channel = "message/{}/{}".format(client.GroupClientKey.client_id, device_id)

                new_message_res_object = deepcopy(message_res_object)
                new_message_res_object.group_id = client.GroupClientKey.group_id
                new_message_res_object.client_id = client.GroupClientKey.client_id

                if message_channel in client_message_queue:
                    client_message_queue[message_channel].put(new_message_res_object)
                else:
                    if new_message_res_object.group_type == 'peer' and new_message_res_object.client_id == from_client_id:
                        logger.info('using sender_message')
                        message_content = base64.b64encode(request.sender_message).decode('utf-8')
                    else:
                        logger.info('using message')
                        message_content = base64.b64encode(new_message_res_object.message).decode('utf-8')
                    message = {
                        'id': new_message_res_object.id,
                        'client_id': new_message_res_object.client_id,
                        'client_workspace_domain': owner_workspace_domain,
                        'created_at': new_message_res_object.created_at,
                        'from_client_id': new_message_res_object.from_client_id,
                        'from_client_workspace_domain': new_message_res_object.from_client_workspace_domain,
                        'group_id': client.GroupClientKey.group_id,
                        'group_type': new_message_res_object.group_type,
                        'message': message_content
                    }
                    await push_service.push_text_to_client_with_device(client.GroupClientKey.client_id, device_id, title="",
                                                           body="You have a new message",
                                                           from_client_id=new_message_res_object.from_client_id,
                                                           notify_type="new_message",
                                                           data=json.dumps(message),
                                                           from_client_device_id=request.from_client_device_id)
                    continue

        # pubish message to owner server
        request1 = message_pb2.WorkspacePublishRequest(
            from_client_id=from_client_id,
            from_client_workspace_domain=owner_workspace_domain,
            client_id=request.clientId,
            group_id=group.owner_group_id,
            group_type=group.group_type,
            message_id=message_id,
            message=request.message,
            created_at=int(created_at.timestamp() * 1000),
            sender_message=request.sender_message,
            from_client_device_id=request.from_client_device_id,
        )
        res_object = ClientMessage(group.owner_workspace_domain).workspace_publish_message(request1)
        if res_object is None:
            logger.error("send message to client failed")
        return message_res_object
Example #11
0
 def __init__(self, *kwargs):
     self.service = GroupService()
Example #12
0
    async def publish_to_group_owner(self, request, from_client_id, group):
        logger.info("publish_to_group_owner from client_id {}, group_id={}".format(from_client_id, str(group.id)))

        owner_workspace_domain = get_owner_workspace_domain()
        # store message here
        message_id = str(uuid.uuid4())
        created_at = datetime.now()

        message_res_object = MessageService().store_message(
            message_id=message_id,
            created_at=created_at,
            group_id=group.id,
            group_type=group.group_type,
            from_client_id=from_client_id,
            from_client_workspace_domain=owner_workspace_domain,
            client_id=request.clientId,
            message=request.message,
            sender_message=request.sender_message
        )
        lst_client = GroupService().get_clients_in_group(group.id)
        push_service = NotifyPushService()

        for client in lst_client:
            if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                if client.User is None:
                    continue

                new_message_res_object = deepcopy(message_res_object)
                new_message_res_object.client_id = client.GroupClientKey.client_id
                for notify_token in client.User.tokens:
                    device_id = notify_token.device_id
                    logger.info('device_id in real loop in handle {}'.format(device_id))
                    if client.GroupClientKey.client_id == from_client_id and device_id == request.from_client_device_id:
                        continue
                    message_channel = "message/{}/{}".format(client.GroupClientKey.client_id, device_id)
                    if message_channel in client_message_queue:
                        logger.info('message channel in handle {}'.format(message_channel))
                        client_message_queue[message_channel].put(new_message_res_object)
                    else:
                        if new_message_res_object.group_type == 'peer' and new_message_res_object.client_id == from_client_id:
                            logger.info('using sender_message')
                            message_content = base64.b64encode(request.sender_message).decode('utf-8')
                        else:
                            logger.info('using message')
                            message_content = base64.b64encode(new_message_res_object.message).decode('utf-8')
                        message = {
                            'id': new_message_res_object.id,
                            'client_id': new_message_res_object.client_id,
                            'client_workspace_domain': owner_workspace_domain,
                            'created_at': new_message_res_object.created_at,
                            'from_client_id': new_message_res_object.from_client_id,
                            'from_client_workspace_domain': owner_workspace_domain,
                            'group_id': new_message_res_object.group_id,
                            'group_type': new_message_res_object.group_type,
                            'message': message_content
                        }
                        await push_service.push_text_to_client_with_device(client.GroupClientKey.client_id, device_id, title="",
                                                               body="You have a new message",
                                                               from_client_id=new_message_res_object.from_client_id,
                                                               notify_type="new_message",
                                                               data=json.dumps(message),
                                                               from_client_device_id=request.from_client_device_id)
                            # continue
            else:
                # call to other server
                logger.info('push to client {} in server {}'.format(message_res_object.client_id, client.GroupClientKey.client_workspace_domain))
                request2 = message_pb2.WorkspacePublishRequest(
                    from_client_id=message_res_object.from_client_id,
                    from_client_workspace_domain=owner_workspace_domain,
                    client_id=message_res_object.client_id,
                    group_id=client.GroupClientKey.client_workspace_group_id,
                    group_type=message_res_object.group_type,
                    message_id=message_res_object.id,
                    message=message_res_object.message,
                    created_at=message_res_object.created_at,
                    updated_at=message_res_object.updated_at,
                    from_client_device_id=request.from_client_device_id,
                    sender_message=request.sender_message
                )
                message_res_object2 = ClientMessage(
                    client.GroupClientKey.client_workspace_domain).workspace_publish_message(request2)
                if message_res_object2 is None:
                    logger.error("send message to client failed")

        return message_res_object
Example #13
0
    async def workspace_publish(self, request, context):
        try:
            logger.info("workspace_publish from client_id {}".format(request.from_client_id))
            owner_workspace_domain = get_owner_workspace_domain()
            group = GroupService().get_group_info(request.group_id)
            if group.owner_workspace_domain is None or group.owner_workspace_domain == owner_workspace_domain:
                # store message here
                MessageService().store_message(
                    message_id=request.message_id,
                    created_at=datetime.now(),
                    group_id=request.group_id,
                    group_type=request.group_type,
                    from_client_id=request.from_client_id,
                    from_client_workspace_domain=request.from_client_workspace_domain,
                    client_id=request.client_id,
                    message=request.message,
                    sender_message=request.sender_message
                )

            new_message = message_pb2.MessageObjectResponse(
                id=request.message_id,
                client_id=request.client_id,
                group_id=request.group_id,
                group_type=request.group_type,
                from_client_id=request.from_client_id,
                from_client_workspace_domain=request.from_client_workspace_domain,
                message=request.message,
                created_at=request.created_at,
                updated_at=request.updated_at,
                sender_message=request.sender_message
            )
            # push notification for other client
            lst_client = GroupService().get_clients_in_group(request.group_id)
            for client in lst_client:
                if client.GroupClientKey.client_workspace_domain != request.from_client_workspace_domain:
                    if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                        if client.User is None:
                            continue
                        for notify_token in client.User.tokens:
                            device_id = notify_token.device_id
                            logger.info('device_id in real loop in handle {}'.format(device_id))
                            if client.GroupClientKey.client_id == request.from_client_id and device_id == request.from_client_device_id:
                                continue
                            message_channel = "message/{}/{}".format(client.GroupClientKey.client_id, device_id)
                            new_message_res_object = deepcopy(new_message)
                            new_message_res_object.client_id = client.GroupClientKey.client_id

                            if message_channel in client_message_queue:
                                logger.info('message channel in handle {}'.format(message_channel))
                                client_message_queue[message_channel].put(new_message_res_object)
                            else:
                                if new_message_res_object.group_type == 'peer' and new_message_res_object.client_id == request.from_client_id:
                                    logger.info('using sender_message')
                                    message_content = base64.b64encode(request.sender_message).decode('utf-8')
                                else:
                                    logger.info('using message')
                                    message_content = base64.b64encode(new_message_res_object.message).decode('utf-8')
                                push_service = NotifyPushService()
                                message = {
                                    'id': new_message_res_object.id,
                                    'client_id': new_message_res_object.client_id,
                                    'client_workspace_domain': get_owner_workspace_domain(),
                                    'created_at': new_message_res_object.created_at,
                                    'from_client_id': new_message_res_object.from_client_id,
                                    'from_client_workspace_domain': new_message_res_object.from_client_workspace_domain,
                                    'group_id': new_message_res_object.group_id,
                                    'group_type': request.group_type,
                                    'message': message_content
                                }
                                await push_service.push_text_to_client_with_device(client.GroupClientKey.client_id, device_id, title="",
                                                                       body="You have a new message",
                                                                       from_client_id=new_message.from_client_id,
                                                                       notify_type="new_message",
                                                                       data=json.dumps(message),
                                                                       from_client_device_id=request.from_client_device_id)
                                continue
                    else:
                        # call to other server
                        request.group_id = client.GroupClientKey.client_workspace_group_id
                        res_object = ClientMessage(
                            client.GroupClientKey.client_workspace_domain).workspace_publish_message(request)
                        if res_object is None:
                            logger.error("Workspace Publish Message to client failed")
            return new_message

        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_PUBLISH_MESSAGE_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #14
0
    async def workspace_video_call(self, request, context):
        try:
            logger.info("workspace_video_call")

            from_client_id = request.from_client_id
            from_client_name = request.from_client_name
            if request.from_client_avatar:
                from_client_avatar = request.from_client_avatar
            else:
                from_client_avatar = ""
            group_id = request.group_id
            client_id = request.client_id

            server_info = ServerInfoService().get_server_info()
            webrtc_token = secrets.token_hex(10)

            group_obj = GroupService().get_group_info(group_id)
            group_obj.group_rtc_token = webrtc_token
            group_obj.update()
            # register webrtc
            self.service_group.register_webrtc_token(webrtc_token)
            #  create room
            self.service_group.create_rtc_group(group_id, webrtc_token)
            logger.info('janus webrtc token={}'.format(webrtc_token))
            client_ws_url = get_system_config()['janus_webrtc'].get('client_ws_url')

            # send push notification to all member of group
            lst_client_in_groups = self.service_group.get_clients_in_group(group_id)
            # list token for each device type

            owner_workspace_domain = get_owner_workspace_domain()

            for client in lst_client_in_groups:
                if client.GroupClientKey.client_workspace_domain != request.from_client_workspace_domain:
                    push_payload = {
                        'notify_type': 'request_call',
                        'call_type': request.call_type,
                        'group_id': str(request.group_id),
                        'group_name': group_obj.group_name if group_obj.group_name else '',
                        'group_type': group_obj.group_type if group_obj.group_type else '',
                        'group_rtc_token': webrtc_token,
                        'group_rtc_url': client_ws_url,
                        'group_rtc_id': str(group_id),
                        'from_client_id': from_client_id,
                        'from_client_name': from_client_name,
                        'from_client_avatar': from_client_avatar,
                        'client_id': client_id,
                        'stun_server': server_info.stun_server,
                        'turn_server': server_info.turn_server
                    }
                    logger.info(push_payload)
                    if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                        await NotifyPushService().push_voip_client(client.User.id, push_payload)
                    else:
                        new_push_payload = deepcopy(push_payload)
                        new_push_payload['group_id'] = str(client.GroupClientKey.client_workspace_group_id)
                        logger.info(new_push_payload)
                        ClientPush(client.GroupClientKey.client_workspace_domain).push_voip(client.User.id,
                                                                                            json.dumps(new_push_payload))

            stun_server_obj = json.loads(server_info.stun_server)
            stun_server = video_call_pb2.StunServer(
                server=stun_server_obj["server"],
                port=stun_server_obj["port"]
            )
            turn_server_obj = json.loads(server_info.turn_server)
            turn_server = video_call_pb2.TurnServer(
                server=turn_server_obj["server"],
                port=turn_server_obj["port"],
                type=turn_server_obj["type"],
                user=turn_server_obj["user"],
                pwd=turn_server_obj["pwd"]
            )
            return video_call_pb2.ServerResponse(
                group_rtc_url=client_ws_url,
                group_rtc_id=group_id,
                group_rtc_token=webrtc_token,
                stun_server=stun_server,
                turn_server=turn_server,
            )
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_REQUEST_CALL_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #15
0
class GroupController(BaseController):
    def __init__(self, *kwargs):
        self.service = GroupService()

    @request_logged
    async def create_group(self, request, context):
        try:
            group_name = request.group_name
            group_type = request.group_type
            lst_client = request.lst_client
            obj_res = self.service.add_group(group_name, group_type, lst_client, request.created_by_client_id)

            return obj_res
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CREATE_GROUP_CHAT_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def create_group_workspace(self, request, context):
        try:
            group_name = request.group_name
            group_type = request.group_type
            from_client_id = request.from_client_id
            client_id = request.client_id
            lst_client = request.lst_client
            owner_group_id = request.owner_group_id
            owner_workspace_domain = request.owner_workspace_domain
            obj_res = self.service.add_group_workspace(group_name, group_type, from_client_id, client_id, lst_client, owner_group_id,
                                                       owner_workspace_domain)

            return obj_res
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CREATE_GROUP_CHAT_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def get_group(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            client_id = introspect_token['sub']
            group_id = request.group_id
            obj_res = self.service.get_group(group_id, client_id)

            if obj_res is not None:
                return obj_res
            else:
                raise Exception(Message.GROUP_CHAT_NOT_FOUND)
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.GET_GROUP_CHAT_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def search_groups(self, request, context):
        try:
            keyword = request.keyword
            obj_res = self.service.search_group(keyword)
            return obj_res
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.SEARCH_GROUP_CHAT_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    @auth_required
    async def get_joined_groups(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            client_id = introspect_token['sub']
            obj_res = self.service.get_joined_group(client_id)
            return obj_res
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.REGISTER_CLIENT_SIGNAL_KEY_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def join_group(self, request, context):
        try:
            # TODO: implement this function
            pass
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.REGISTER_CLIENT_SIGNAL_KEY_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)


    @request_logged
    async def add_member(self, request, context):
        try:
            group = GroupService().get_group_info(request.group_id)
            group_clients = json.loads(group.group_clients)
            added_member_info = request.added_member_info
            adding_member_info = request.adding_member_info

            #get workspace is active in group
            workspace_domains = list(set(
                [e['workspace_domain'] for e in group_clients
                 if ('status' not in e or
                     ('status' in e and e['status'] in ['active']))]
            ))
            logger.info(workspace_domains)

            #check added and adding member in group
            adding_member_in_group = False
            for e in group_clients:
                if 'status' not in e or e['status'] in ['active']:
                    if e['id'] == added_member_info.id:
                        raise Exception(Message.ADDED_USER_IS_ALREADY_MEMBER)
                    if e['id'] == adding_member_info.id:
                        adding_member_in_group = True
            if not adding_member_in_group:
                raise Exception(Message.ADDER_MEMBER_NOT_IN_GROUP)

            # new group clients
            new_group_clients = []
            is_old_member = False
            for e in group_clients:
                if e['id'] == added_member_info.id:
                    e['status'] = 'active'  # turn into active member
                    is_old_member = True
                new_group_clients.append(e)
            if not is_old_member:
                added_member_info.status = 'active'
                new_group_clients.append(
                    MessageToDict(
                        added_member_info,
                        preserving_proto_field_name=True
                    )
                )

            # update group members first
            group.group_clients = json.dumps(new_group_clients)
            group.updated_by = adding_member_info.id
            group.updated_at = datetime.datetime.now()
            group.update()

            owner_workspace_domain = get_owner_workspace_domain()

            # wait for service to add member to group, and return base response if no exception occured
            if (group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain):
                await self.service.add_member_to_group_not_owner(
                    added_member_info,
                    adding_member_info,
                    group,
                )
            else:
                await self.service.add_member_to_group_owner(
                    added_member_info,
                    adding_member_info,
                    group
                )

            return group_messages.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.ADD_MEMBER_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def workspace_add_member(self, request, context):
        try:
            added_member_info = request.added_member_info
            adding_member_info = request.adding_member_info
            owner_group = request.owner_group

            response = await self.service.workspace_add_member(
                added_member_info,
                adding_member_info,
                owner_group
            )
            return response
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.ADD_MEMBER_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def leave_group(self, request, context):
        try:
            leave_member = request.leave_member
            leave_member_by = request.leave_member_by

            new_member_status = "removed"
            if leave_member.id == leave_member_by.id:
                new_member_status = "leaved"

            group = GroupService().get_group_info(request.group_id)
            group_clients = json.loads(group.group_clients)

            leave_member_in_group = False
            leave_member_by_in_group = False
            for e in group_clients:
                if e['id'] == leave_member.id:
                    leave_member_in_group = True
                    e['status'] = new_member_status
                if e['id'] == leave_member_by.id:
                    leave_member_by_in_group = True
            if not leave_member_in_group:
                raise Exception(Message.LEAVED_MEMBER_NOT_IN_GROUP)
            if not leave_member_by_in_group and new_member_status == "removed":
                raise Exception(Message.REMOVER_MEMBER_NOT_IN_GROUP)

            # update field group_clients first
            logger.info("New group client: {}".format(group_clients))
            group.group_clients = json.dumps(group_clients)
            group.updated_by = leave_member_by.id
            group.update()

            owner_workspace_domain = get_owner_workspace_domain()

            # wait for service to leave group, and return base response if no exception occured
            if (group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain):
                await self.service.leave_group_not_owner(
                    leave_member,
                    leave_member_by,
                    group,
                )
            else:
                await self.service.leave_group_owner(
                    leave_member,
                    leave_member_by,
                    group,
                )

            return group_messages.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.LEAVE_GROUP_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def workspace_leave_group(self, request, context):
        try:
            leave_member = request.leave_member
            leave_member_by = request.leave_member_by
            owner_group = request.owner_group

            # wait for service to call workspace leave group, and return base response if no exception occured
            await self.service.workspace_leave_group(
                leave_member,
                leave_member_by,
                owner_group
            )
            return group_messages.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.ADD_MEMBER_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def workspace_notify_deactive_member(self, request, context):
        try:
            await self.service.workspace_notify_deactive_member(
                request.deactive_account_id,
                request.client_ids
            )
            return group_messages.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.LEAVE_GROUP_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)
Example #16
0
    async def call_to_group_not_owner(self, request, group, from_client_id):
        client_id = request.client_id
        call_type = request.call_type
        from_client_name = ""
        from_client_avatar = ""
        owner_workspace_domain = get_owner_workspace_domain()

        logger.info("call_to_group_not_owner, group_id={}".format(str(group.id)))

        # request call to owner server, response ọbject push notification
        lst_client = GroupService().get_clients_in_group_owner(group.owner_group_id)

        for client in lst_client:
            if client.User and client.User.id == from_client_id:
                from_client_name = client.User.display_name
                if client.User.avatar:
                    from_client_avatar = client.User.avatar
                else:
                    from_client_avatar = ""

        other_client_in_this_workspace = []
        for client in lst_client:
            if client.User and client.User.id != from_client_id:
                client_with_group = {
                    "client_id": client.User.id,
                    "group_id": client.GroupClientKey.group_id
                }
                other_client_in_this_workspace.append(client_with_group)

        request = video_call_pb2.WorkspaceVideoCallRequest(
            from_client_id=from_client_id,
            from_client_name=from_client_name,
            from_client_avatar=from_client_avatar,
            from_client_workspace_domain=owner_workspace_domain,
            client_id=client_id,
            group_id=group.owner_group_id,
            call_type=call_type
        )
        obj_res = ClientVideoCall(group.owner_workspace_domain).workspace_video_call(request)
        if obj_res:
            # push for other user in this server
            for client in other_client_in_this_workspace:
                push_payload = {
                    'notify_type': 'request_call',
                    'call_type': call_type,
                    'group_id': str(client["group_id"]),
                    'group_name': group.group_name if group.group_name else '',
                    'group_type': group.group_type if group.group_type else '',
                    'group_rtc_token': obj_res.group_rtc_token,
                    'group_rtc_url': obj_res.group_rtc_url,
                    'group_rtc_id': str(obj_res.group_rtc_id),
                    'from_client_id': from_client_id,
                    'from_client_name': from_client_name,
                    'from_client_avatar': from_client_avatar,
                    'client_id': client_id,
                    'stun_server': obj_res.stun_server,
                    'turn_server': obj_res.turn_server
                }
                logger.info(push_payload)
                await NotifyPushService().push_voip_client(client["client_id"], push_payload)
            return obj_res
        else:
            raise
Example #17
0
 def __init__(self, *kwargs):
     self.service = VideoCallService()
     self.service_group = GroupService()
Example #18
0
class VideoCallController(BaseController):
    def __init__(self, *kwargs):
        self.service = VideoCallService()
        self.service_group = GroupService()

    @request_logged
    @auth_required
    async def video_call(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            from_client_id = introspect_token['sub']
            group_id = request.group_id

            owner_workspace_domain = get_owner_workspace_domain()

            group = GroupService().get_group_info(group_id)
            if group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain:
                return await self.call_to_group_not_owner(request, group, from_client_id)
            else:
                return await self.call_to_group_owner(request, group, from_client_id)
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_REQUEST_CALL_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def workspace_video_call(self, request, context):
        try:
            logger.info("workspace_video_call")

            from_client_id = request.from_client_id
            from_client_name = request.from_client_name
            if request.from_client_avatar:
                from_client_avatar = request.from_client_avatar
            else:
                from_client_avatar = ""
            group_id = request.group_id
            client_id = request.client_id

            server_info = ServerInfoService().get_server_info()
            webrtc_token = secrets.token_hex(10)

            group_obj = GroupService().get_group_info(group_id)
            group_obj.group_rtc_token = webrtc_token
            group_obj.update()
            # register webrtc
            self.service_group.register_webrtc_token(webrtc_token)
            #  create room
            self.service_group.create_rtc_group(group_id, webrtc_token)
            logger.info('janus webrtc token={}'.format(webrtc_token))
            client_ws_url = get_system_config()['janus_webrtc'].get('client_ws_url')

            # send push notification to all member of group
            lst_client_in_groups = self.service_group.get_clients_in_group(group_id)
            # list token for each device type

            owner_workspace_domain = get_owner_workspace_domain()

            for client in lst_client_in_groups:
                if client.GroupClientKey.client_workspace_domain != request.from_client_workspace_domain:
                    push_payload = {
                        'notify_type': 'request_call',
                        'call_type': request.call_type,
                        'group_id': str(request.group_id),
                        'group_name': group_obj.group_name if group_obj.group_name else '',
                        'group_type': group_obj.group_type if group_obj.group_type else '',
                        'group_rtc_token': webrtc_token,
                        'group_rtc_url': client_ws_url,
                        'group_rtc_id': str(group_id),
                        'from_client_id': from_client_id,
                        'from_client_name': from_client_name,
                        'from_client_avatar': from_client_avatar,
                        'client_id': client_id,
                        'stun_server': server_info.stun_server,
                        'turn_server': server_info.turn_server
                    }
                    logger.info(push_payload)
                    if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                        await NotifyPushService().push_voip_client(client.User.id, push_payload)
                    else:
                        new_push_payload = deepcopy(push_payload)
                        new_push_payload['group_id'] = str(client.GroupClientKey.client_workspace_group_id)
                        logger.info(new_push_payload)
                        ClientPush(client.GroupClientKey.client_workspace_domain).push_voip(client.User.id,
                                                                                            json.dumps(new_push_payload))

            stun_server_obj = json.loads(server_info.stun_server)
            stun_server = video_call_pb2.StunServer(
                server=stun_server_obj["server"],
                port=stun_server_obj["port"]
            )
            turn_server_obj = json.loads(server_info.turn_server)
            turn_server = video_call_pb2.TurnServer(
                server=turn_server_obj["server"],
                port=turn_server_obj["port"],
                type=turn_server_obj["type"],
                user=turn_server_obj["user"],
                pwd=turn_server_obj["pwd"]
            )
            return video_call_pb2.ServerResponse(
                group_rtc_url=client_ws_url,
                group_rtc_id=group_id,
                group_rtc_token=webrtc_token,
                stun_server=stun_server,
                turn_server=turn_server,
            )
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_REQUEST_CALL_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)


    async def call_to_group_owner(self, request, group_obj, from_client_id):
        from_client_name = ""
        from_client_avatar = ""
        owner_workspace_domain = get_owner_workspace_domain()
        group_id = request.group_id
        logger.info("call_to_group_owner, group_id= {}".format(str(group_id)))

        client_id = request.client_id

        server_info = ServerInfoService().get_server_info()
        webrtc_token = secrets.token_hex(10)

        group_obj.group_rtc_token = webrtc_token
        group_obj.update()
        # register webrtc
        self.service_group.register_webrtc_token(webrtc_token)
        #  create room
        self.service_group.create_rtc_group(group_id, webrtc_token)
        logger.info('janus webrtc token={}'.format(webrtc_token))

        client_ws_url = get_system_config()['janus_webrtc'].get('client_ws_url')

        # send push notification to all member of group
        lst_client_in_groups = self.service_group.get_clients_in_group(group_id)
        # list token for each device type
        for client in lst_client_in_groups:
            if client.User and client.User.id == from_client_id:
                from_client_name = client.User.display_name
                if client.User.avatar:
                    from_client_avatar = client.User.avatar
                else:
                    from_client_avatar = ""

        for client in lst_client_in_groups:
            if client.User is None or client.User.id != from_client_id:
                push_payload = {
                    'notify_type': 'request_call',
                    'call_type': request.call_type,
                    'group_id': str(client.GroupClientKey.group_id),
                    'group_name': group_obj.group_name if group_obj.group_name else '',
                    'group_type': group_obj.group_type if group_obj.group_type else '',
                    'group_rtc_token': webrtc_token,
                    'group_rtc_url':  client_ws_url,
                    'group_rtc_id': str(group_id),
                    'from_client_id': from_client_id,
                    'from_client_name': from_client_name,
                    'from_client_avatar': from_client_avatar,
                    'client_id': client_id,
                    'stun_server': server_info.stun_server,
                    'turn_server': server_info.turn_server
                }
                logger.info(push_payload)

                if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                    await NotifyPushService().push_voip_client(client.User.id, push_payload)
                else:
                    logger.info("Push voip from {} to client {} in {}".format(owner_workspace_domain, client.GroupClientKey.client_workspace_domain, client.GroupClientKey.client_id))
                    new_push_payload = deepcopy(push_payload)
                    new_push_payload['group_id'] = str(client.GroupClientKey.client_workspace_group_id)
                    logger.info(new_push_payload)
                    ClientPush(client.GroupClientKey.client_workspace_domain).push_voip(client.GroupClientKey.client_id,
                                                                                        json.dumps(new_push_payload))

        stun_server_obj = json.loads(server_info.stun_server)
        stun_server = video_call_pb2.StunServer(
            server=stun_server_obj["server"],
            port=stun_server_obj["port"]
        )
        turn_server_obj = json.loads(server_info.turn_server)
        turn_server = video_call_pb2.TurnServer(
            server=turn_server_obj["server"],
            port=turn_server_obj["port"],
            type=turn_server_obj["type"],
            user=turn_server_obj["user"],
            pwd=turn_server_obj["pwd"]
        )
        return video_call_pb2.ServerResponse(
            group_rtc_url=client_ws_url,
            group_rtc_id=group_id,
            group_rtc_token=webrtc_token,
            stun_server=stun_server,
            turn_server=turn_server
        )

    async def call_to_group_not_owner(self, request, group, from_client_id):
        client_id = request.client_id
        call_type = request.call_type
        from_client_name = ""
        from_client_avatar = ""
        owner_workspace_domain = get_owner_workspace_domain()

        logger.info("call_to_group_not_owner, group_id={}".format(str(group.id)))

        # request call to owner server, response ọbject push notification
        lst_client = GroupService().get_clients_in_group_owner(group.owner_group_id)

        for client in lst_client:
            if client.User and client.User.id == from_client_id:
                from_client_name = client.User.display_name
                if client.User.avatar:
                    from_client_avatar = client.User.avatar
                else:
                    from_client_avatar = ""

        other_client_in_this_workspace = []
        for client in lst_client:
            if client.User and client.User.id != from_client_id:
                client_with_group = {
                    "client_id": client.User.id,
                    "group_id": client.GroupClientKey.group_id
                }
                other_client_in_this_workspace.append(client_with_group)

        request = video_call_pb2.WorkspaceVideoCallRequest(
            from_client_id=from_client_id,
            from_client_name=from_client_name,
            from_client_avatar=from_client_avatar,
            from_client_workspace_domain=owner_workspace_domain,
            client_id=client_id,
            group_id=group.owner_group_id,
            call_type=call_type
        )
        obj_res = ClientVideoCall(group.owner_workspace_domain).workspace_video_call(request)
        if obj_res:
            # push for other user in this server
            for client in other_client_in_this_workspace:
                push_payload = {
                    'notify_type': 'request_call',
                    'call_type': call_type,
                    'group_id': str(client["group_id"]),
                    'group_name': group.group_name if group.group_name else '',
                    'group_type': group.group_type if group.group_type else '',
                    'group_rtc_token': obj_res.group_rtc_token,
                    'group_rtc_url': obj_res.group_rtc_url,
                    'group_rtc_id': str(obj_res.group_rtc_id),
                    'from_client_id': from_client_id,
                    'from_client_name': from_client_name,
                    'from_client_avatar': from_client_avatar,
                    'client_id': client_id,
                    'stun_server': obj_res.stun_server,
                    'turn_server': obj_res.turn_server
                }
                logger.info(push_payload)
                await NotifyPushService().push_voip_client(client["client_id"], push_payload)
            return obj_res
        else:
            raise

    @request_logged
    @auth_required
    async def update_call(self, request, context):
        try:
            header_data = dict(context.invocation_metadata())
            introspect_token = KeyCloakUtils.introspect_token(header_data['access_token'])
            from_client_id = introspect_token['sub']
            group_id = request.group_id

            owner_workspace_domain = get_owner_workspace_domain()

            group = GroupService().get_group_info(group_id)
            if group.owner_workspace_domain and group.owner_workspace_domain != owner_workspace_domain:
                return await self.update_call_to_group_not_owner(request, group, from_client_id)
            else:
                return await self.update_call_to_group_owner(request, from_client_id)
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_UPDATE_CALL_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    @request_logged
    async def workspace_update_call(self, request, context):
        try:
            logger.info("workspace_update_call")

            from_client_id = request.from_client_id
            from_client_name = request.from_client_name
            from_client_avatar = request.from_client_avatar
            group_id = request.group_id
            client_id = request.client_id
            update_type = request.update_type

            # send push notification to all member of group
            lst_client_in_groups = self.service_group.get_clients_in_group(group_id)
            # list token for each device type
            owner_workspace_domain = get_owner_workspace_domain()

            for client in lst_client_in_groups:
                if client.GroupClientKey.client_workspace_domain != request.from_client_workspace_domain:
                    push_payload = {
                        'notify_type': update_type,
                        'group_id': str(client.GroupClientKey.group_id),
                        'from_client_id': from_client_id,
                        'from_client_name': from_client_name,
                        'from_client_avatar': from_client_avatar,
                        'client_id': client_id
                    }
                    if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                        # ret_val = NotifyInAppService().notify_client_update_call(update_type, client.GroupClientKey.client_id, from_client_id,
                        #                                                          client.GroupClientKey.group_id)
                        # if not ret_val:
                        new_push_payload = deepcopy(push_payload)
                        logger.info(new_push_payload)
                        await NotifyPushService().push_voip_client(client.GroupClientKey.client_id, new_push_payload)
                    else:
                        new_push_payload = deepcopy(push_payload)
                        new_push_payload["group_id"] = str(client.GroupClientKey.client_workspace_group_id)
                        logger.info(new_push_payload)
                        ClientPush(client.GroupClientKey.client_workspace_domain).push_voip(client.GroupClientKey.client_id,
                                                                                            json.dumps(new_push_payload))
                        #continue
            return video_call_pb2.BaseResponse()
        except Exception as e:
            logger.error(e)
            if not e.args or e.args[0] not in Message.msg_dict:
                errors = [Message.get_error_object(Message.CLIENT_UPDATE_CALL_FAILED)]
            else:
                errors = [Message.get_error_object(e.args[0])]
            context.set_details(json.dumps(
                errors, default=lambda x: x.__dict__))
            context.set_code(grpc.StatusCode.INTERNAL)

    async def update_call_to_group_owner(self, request, from_client_id):
        logger.info("update_call_to_group_owner")

        from_client_name = ""
        from_client_avatar = ""
        owner_workspace_domain = get_owner_workspace_domain()

        group_id = request.group_id
        client_id = request.client_id
        update_type = request.update_type

        # send push notification to all member of group
        lst_client_in_groups = self.service_group.get_clients_in_group(group_id)

        for client in lst_client_in_groups:
            if client.User and client.User.id == from_client_id:
                from_client_name = client.User.display_name
                from_client_avatar = client.User.avatar

        for client in lst_client_in_groups:
            if client.User is None or client.User.id != from_client_id:
                push_payload = {
                    'notify_type': update_type,
                    'group_id': str(client.GroupClientKey.group_id),
                    'from_client_id': from_client_id,
                    'from_client_name': from_client_name,
                    'from_client_avatar': from_client_avatar,
                    'client_id': client_id
                }
                if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                    # logger.info("update_call_to_group_owner, owner member ->client_id {}".format(client.GroupClientKey.client_id))
                    # ret_val = NotifyInAppService().notify_client_update_call(update_type, client.GroupClientKey.client_id, from_client_id,
                    #                                                          client.GroupClientKey.group_id)
                    # logger.info("notify inapp {}".format(ret_val))
                    # if not ret_val:
                    #     logger.info("notify push notification")
                    new_push_payload = deepcopy(push_payload)
                    new_push_payload["group_id"] = str(client.GroupClientKey.group_id)
                    logger.info(new_push_payload)
                    await NotifyPushService().push_voip_client(client.GroupClientKey.client_id, new_push_payload)
                else:
                    new_push_payload = deepcopy(push_payload)
                    new_push_payload["group_id"] = str(client.GroupClientKey.client_workspace_group_id)
                    logger.info(new_push_payload)
                    ClientPush(client.GroupClientKey.client_workspace_domain).push_voip(client.GroupClientKey.client_id,
                                                                                        json.dumps(new_push_payload))
                    #continue

        return video_call_pb2.BaseResponse()

    async def update_call_to_group_not_owner(self, request, group, from_client_id):
        logger.info("update_call_to_group_not_owner")

        client_id = request.client_id
        update_type = request.update_type
        from_client_username = ""
        from_client_avatar = ""
        owner_workspace_domain = get_owner_workspace_domain()

        # update call to owner server, response ọbject push notification
        lst_client = GroupService().get_clients_in_group_owner(group.owner_group_id)
        for client in lst_client:
            if client.User.id == from_client_id:
                from_client_username = client.User.display_name
                from_client_avatar = client.User.avatar
            else:
                # ret_val = NotifyInAppService().notify_client_update_call(update_type, client.GroupClientKey.client_id, from_client_id, client.GroupClientKey.group_id)
                # if not ret_val:
                push_payload = {
                    'notify_type': update_type,
                    'group_id': str(client.GroupClientKey.group_id),
                    'from_client_id': from_client_id,
                    'from_client_name': from_client_username,
                    'from_client_avatar': from_client_avatar,
                    'client_id': client_id
                }
                await NotifyPushService().push_voip_client(client.GroupClientKey.client_id, push_payload)

        request = video_call_pb2.WorkspaceUpdateCallRequest(
            from_client_id=from_client_id,
            from_client_name=from_client_username,
            from_client_avatar=from_client_avatar,
            from_client_workspace_domain=owner_workspace_domain,
            client_id=client_id,
            group_id=group.owner_group_id,
            update_type=update_type
        )
        obj_res = ClientVideoCall(group.owner_workspace_domain).workspace_update_call(request)
        return video_call_pb2.BaseResponse()