From 6d499032fa1794edc6c62f44048ba250176b5c59 Mon Sep 17 00:00:00 2001 From: "Xinwei Xiong(cubxxw-openim)" <3293172751nss@gmail.com> Date: Thu, 29 Jun 2023 22:35:31 +0800 Subject: [PATCH] v3 - main to cut out --- .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md | 37 + .github/ISSUE_TEMPLATE/deployment-issues.md | 36 + .github/ISSUE_TEMPLATE/update-.md | 38 + .github/workflows/codeql-analysis.yml | 71 + .gitignore | 22 + .gitmodules | 4 + LICENSE | 201 + README.md | 159 + cmd/Open-IM-SDK-Core | 1 + cmd/open_im_api/Makefile | 25 + cmd/open_im_api/main.go | 177 + cmd/open_im_cms_api/Makefile | 25 + cmd/open_im_cms_api/main.go | 17 + cmd/open_im_demo/Makefile | 25 + cmd/open_im_demo/main.go | 42 + cmd/open_im_msg_gateway/Makefile | 24 + cmd/open_im_msg_gateway/main.go | 23 + cmd/open_im_msg_transfer/Makefile | 25 + cmd/open_im_msg_transfer/main.go | 19 + cmd/open_im_push/Makefile | 25 + cmd/open_im_push/main.go | 22 + cmd/open_im_timer_task/Makefile | 25 + cmd/open_im_timer_task/main.go | 63 + cmd/rpc/open_im_admin_cms/Makefile | 23 + cmd/rpc/open_im_admin_cms/main.go | 15 + cmd/rpc/open_im_auth/Makefile | 24 + cmd/rpc/open_im_auth/main.go | 16 + cmd/rpc/open_im_friend/Makefile | 25 + cmd/rpc/open_im_friend/main.go | 16 + cmd/rpc/open_im_group/Makefile | 25 + cmd/rpc/open_im_group/main.go | 15 + cmd/rpc/open_im_message_cms/Makefile | 23 + cmd/rpc/open_im_message_cms/main.go | 15 + cmd/rpc/open_im_msg/Makefile | 23 + cmd/rpc/open_im_msg/main.go | 15 + cmd/rpc/open_im_office/Makefile | 23 + cmd/rpc/open_im_office/main.go | 15 + cmd/rpc/open_im_organization/Makefile | 25 + cmd/rpc/open_im_organization/main.go | 15 + cmd/rpc/open_im_statistics/Makefile | 23 + cmd/rpc/open_im_statistics/main.go | 15 + cmd/rpc/open_im_user/Makefile | 25 + cmd/rpc/open_im_user/main.go | 15 + cmd/test/main.go | 69 + config/config.yaml | 609 ++ deploy.Dockerfile | 39 + deploy/.dockerignore | 6 + deploy/Makefile | 158 + deploy/config.example.yaml | 183 + deploy/dockerfiles/Dockerfile.api | 16 + deploy/dockerfiles/Dockerfile.demo | 16 + deploy/dockerfiles/Dockerfile.msg_gateway | 16 + deploy/dockerfiles/Dockerfile.msg_transfer | 16 + deploy/dockerfiles/Dockerfile.push | 16 + deploy/dockerfiles/Dockerfile.rpc_auth | 16 + deploy/dockerfiles/Dockerfile.rpc_friend | 16 + deploy/dockerfiles/Dockerfile.rpc_group | 16 + deploy/dockerfiles/Dockerfile.rpc_msg | 16 + deploy/dockerfiles/Dockerfile.rpc_user | 16 + deploy/dockerfiles/Dockerfile.timer_task | 16 + deploy/env.yaml | 101 + deploy/openim.yaml | 223 + deploy/readme.md | 30 + docker-compose.yaml | 116 + docs/Architecture.jpg | Bin 0 -> 212410 bytes docs/Open-IM-Servers-on-System.png | Bin 0 -> 21614 bytes docs/Open-IM-Servers-on-docker.png | Bin 0 -> 10172 bytes docs/Open-IM.png | Bin 0 -> 17614 bytes docs/Wechat.jpg | Bin 0 -> 212904 bytes docs/open-im-logo.png | Bin 0 -> 245627 bytes docs/open-im-server.png | Bin 0 -> 109213 bytes go.mod | 69 + go.sum | 1138 ++++ internal/api/auth/auth.go | 91 + internal/api/chat/del_msg.go | 43 + internal/api/chat/get_max_min_seq.go | 61 + internal/api/chat/pull_msg.go | 68 + internal/api/chat/send_msg.go | 99 + internal/api/conversation/conversation.go | 218 + internal/api/friend/friend.go | 456 ++ internal/api/group/group.go | 698 +++ internal/api/manage/management_chat.go | 296 + internal/api/manage/management_user.go | 180 + internal/api/office/tag.go | 280 + internal/api/office/work_moments.go | 371 ++ internal/api/organization/organization.go | 439 ++ internal/api/third/ali_oss_credential.go | 95 + internal/api/third/minio_init.go | 67 + .../api/third/minio_storage_credential.go | 138 + .../third/tencent_cloud_storage_credential.go | 72 + internal/api/user/user.go | 129 + internal/cms_api/admin/admin.go | 42 + internal/cms_api/group/group.go | 450 ++ internal/cms_api/message_cms/message.go | 109 + internal/cms_api/middleware/cors.go | 23 + internal/cms_api/middleware/jwt_auth.go | 24 + internal/cms_api/organization/organization.go | 49 + internal/cms_api/router.go | 95 + internal/cms_api/statistics/statistics.go | 224 + internal/cms_api/user/user.go | 307 + internal/demo/register/login.go | 70 + internal/demo/register/reset_password.go | 56 + internal/demo/register/send_code.go | 130 + internal/demo/register/set_password.go | 89 + internal/demo/register/verify.go | 80 + internal/msg_gateway/gate/init.go | 35 + internal/msg_gateway/gate/logic.go | 297 + .../msg_gateway/gate/open_im_media/room.go | 58 + internal/msg_gateway/gate/rpc_server.go | 149 + internal/msg_gateway/gate/validate.go | 253 + internal/msg_gateway/gate/ws_server.go | 285 + internal/msg_transfer/logic/db.go | 23 + .../msg_transfer/logic/history_msg_handler.go | 142 + internal/msg_transfer/logic/init.go | 25 + .../logic/persistent_msg_handler.go | 78 + internal/push/content_struct/content.go | 85 + internal/push/getui/push.go | 222 + internal/push/jpush/common/JGPlatform.go | 13 + internal/push/jpush/push.go | 74 + internal/push/jpush/requestBody/audience.go | 53 + internal/push/jpush/requestBody/message.go | 27 + .../push/jpush/requestBody/notification.go | 36 + internal/push/jpush/requestBody/options.go | 9 + internal/push/jpush/requestBody/platform.go | 83 + internal/push/jpush/requestBody/pushObj.go | 28 + internal/push/logic/init.go | 39 + internal/push/logic/push_handler.go | 52 + internal/push/logic/push_rpc_server.go | 57 + internal/push/logic/push_to_client.go | 167 + internal/push/logic/tpns.go | 34 + internal/push/push_interface.go | 5 + .../sdk/tpns-server-sdk-go/go/auth/auth.go | 62 + .../tpns-server-sdk-go/go/client/client.go | 18 + .../go/common/http_helper.go | 62 + .../go/common/json_helper.go | 8 + .../push/sdk/tpns-server-sdk-go/go/def.go | 256 + .../push/sdk/tpns-server-sdk-go/go/req/req.go | 403 ++ internal/rpc/admin_cms/admin_cms.go | 87 + internal/rpc/auth/auth.go | 104 + internal/rpc/auth/callback.go | 1 + internal/rpc/friend/callback.go | 1 + internal/rpc/friend/firend.go | 519 ++ internal/rpc/group/callback.go | 13 + internal/rpc/group/group.go | 1046 ++++ internal/rpc/message_cms/message_cms.go | 167 + internal/rpc/msg/callback.go | 159 + internal/rpc/msg/conversation_notification.go | 76 + internal/rpc/msg/del_msg.go | 23 + internal/rpc/msg/friend_notification.go | 165 + internal/rpc/msg/group_notification.go | 508 ++ internal/rpc/msg/pull_message.go | 74 + internal/rpc/msg/rpcChat.go | 67 + internal/rpc/msg/send_msg.go | 593 ++ internal/rpc/msg/tag_send_msg.go | 45 + internal/rpc/office/office.go | 445 ++ internal/rpc/organization/organization.go | 349 ++ internal/rpc/statistics/statistics.go | 378 ++ internal/rpc/user/callback.go | 1 + internal/rpc/user/user.go | 590 ++ internal/timed_task/init.go | 26 + internal/timed_task/timed_task.go | 26 + internal/utils/callback.go | 1 + internal/utils/cors_middleware_test.go | 68 + internal/utils/get_server_ip_test.go | 13 + internal/utils/id.go | 28 + internal/utils/id_test.go | 15 + internal/utils/image_test.go | 28 + internal/utils/jwt_token_test.go | 89 + internal/utils/md5_test.go | 16 + .../utils/platform_number_id_to_name_test.go | 46 + internal/utils/utils.go | 49 + pkg/base_info/auth_api_struct.go | 39 + pkg/base_info/conversation_api_struct.go | 117 + pkg/base_info/cos_api_struct.go | 20 + pkg/base_info/friend_api_struct.go | 136 + pkg/base_info/group_api_struct.go | 222 + pkg/base_info/manage_api_struct.go | 44 + pkg/base_info/minio_api_struct.go | 25 + pkg/base_info/msg.go | 12 + pkg/base_info/office_struct.go | 88 + pkg/base_info/organization_api_struct.go | 110 + pkg/base_info/oss_api_struct.go | 22 + pkg/base_info/public_struct.go | 139 + pkg/base_info/user_api_struct.go | 34 + pkg/base_info/work_moments_struct.go | 97 + pkg/call_back_struct/common.go | 24 + pkg/call_back_struct/group.go | 9 + pkg/call_back_struct/message.go | 47 + pkg/cms_api_struct/admin.go | 10 + pkg/cms_api_struct/common.go | 11 + pkg/cms_api_struct/group.go | 144 + pkg/cms_api_struct/message_cms.go | 50 + pkg/cms_api_struct/organization.go | 25 + pkg/cms_api_struct/statistics.go | 89 + pkg/cms_api_struct/user.go | 110 + pkg/common/config/config.go | 434 ++ pkg/common/constant/constant.go | 235 + pkg/common/constant/error.go | 100 + .../constant/platform_number_id_to_name.go | 66 + pkg/common/db/model.go | 119 + pkg/common/db/model_struct.go | 272 + pkg/common/db/mongoModel.go | 681 +++ pkg/common/db/mysql.go | 162 + .../mysql_model/im_mysql_model/demo_model.go | 41 + .../im_mysql_model/friend_model.go | 91 + .../im_mysql_model/friend_request_model.go | 112 + .../im_mysql_model/group_member_model.go | 316 ++ .../mysql_model/im_mysql_model/group_model.go | 225 + .../im_mysql_model/group_request_model.go | 209 + .../mysql_model/im_mysql_model/message_cms.go | 68 + .../im_mysql_model/organization_model.go | 182 + .../im_mysql_model/statistics_model.go | 153 + .../im_mysql_model/user_black_list_model.go | 58 + .../mysql_model/im_mysql_model/user_model.go | 398 ++ .../im_mysql_msg_model/chat_log_model.go | 51 + .../im_mysql_msg_model/hash_code.go | 36 + pkg/common/db/redisModel.go | 157 + pkg/common/db/redisModel_test.go | 27 + pkg/common/http/http_client.go | 66 + pkg/common/http/http_resp.go | 43 + pkg/common/kafka/consumer.go | 36 + pkg/common/kafka/consumer_group.go | 53 + pkg/common/kafka/producer.go | 49 + pkg/common/log/es_hk.go | 107 + pkg/common/log/file_line_hk.go | 71 + pkg/common/log/logrus.go | 199 + pkg/common/log/time_format.go | 57 + .../multi_terminal_login.go | 73 + pkg/common/token_verify/jwt_token.go | 231 + pkg/common/utils/utils.go | 161 + pkg/grpc-etcdv3/getcdv3/pool.go | 254 + pkg/grpc-etcdv3/getcdv3/register.go | 118 + pkg/grpc-etcdv3/getcdv3/resolver.go | 262 + pkg/proto/admin_cms/admin_cms.pb.go | 317 ++ pkg/proto/admin_cms/admin_cms.proto | 18 + pkg/proto/auth/auth.pb.go | 414 ++ pkg/proto/auth/auth.proto | 36 + pkg/proto/auto_proto.sh | 13 + pkg/proto/base/base.proto | 5 + pkg/proto/chat/chat.pb.go | 650 +++ pkg/proto/chat/chat.proto | 82 + pkg/proto/friend/friend.pb.go | 1990 +++++++ pkg/proto/friend/friend.proto | 169 + pkg/proto/group/group.pb.go | 4481 +++++++++++++++ pkg/proto/group/group.proto | 423 ++ pkg/proto/message_cms/message_cms.pb.go | 1083 ++++ pkg/proto/message_cms/message_cms.proto | 71 + pkg/proto/office/office.pb.go | 2851 ++++++++++ pkg/proto/office/office.proto | 263 + pkg/proto/organization/organization.pb.go | 1780 ++++++ pkg/proto/organization/organization.proto | 172 + pkg/proto/proto_dir.cfg | 15 + pkg/proto/push/push.pb.go | 216 + pkg/proto/push/push.proto | 38 + pkg/proto/relay/relay.pb.go | 602 ++ pkg/proto/relay/relay.proto | 61 + pkg/proto/rtc/rtc.pb.go | 2990 ++++++++++ pkg/proto/rtc/rtc.proto | 219 + pkg/proto/sdk_ws/ws.pb.go | 5002 +++++++++++++++++ pkg/proto/sdk_ws/ws.proto | 571 ++ pkg/proto/statistics/statistics.pb.go | 1498 +++++ pkg/proto/statistics/statistics.proto | 93 + pkg/proto/user/user.pb.go | 3505 ++++++++++++ pkg/proto/user/user.proto | 316 ++ pkg/statistics/statistics.go | 32 + pkg/utils/cors_middleware.go | 24 + pkg/utils/file.go | 39 + pkg/utils/get_server_ip.go | 26 + pkg/utils/image.go | 56 + pkg/utils/map.go | 129 + pkg/utils/md5.go | 13 + pkg/utils/strings.go | 96 + pkg/utils/time_format.go | 85 + pkg/utils/utils.go | 95 + script/build_all_service.sh | 36 + script/build_images.sh | 11 + script/check_all.sh | 66 + script/demo_svr_start.sh | 47 + script/docker_check_service.sh | 11 + script/docker_start_all.sh | 34 + script/env_check.sh | 43 + script/function.sh | 15 + script/msg_gateway_start.sh | 50 + script/msg_transfer_start.sh | 36 + script/mysql_database_init.sh | 38 + script/path_info.cfg | 84 + script/push_start.sh | 45 + script/sdk_svr_start.sh | 48 + script/start_all.sh | 29 + script/start_rpc_service.sh | 69 + script/stop_all.sh | 19 + script/style_info.cfg | 9 + script/timer_start.sh | 35 + 293 files changed, 57778 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/deployment-issues.md create mode 100644 .github/ISSUE_TEMPLATE/update-.md create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 README.md create mode 160000 cmd/Open-IM-SDK-Core create mode 100644 cmd/open_im_api/Makefile create mode 100644 cmd/open_im_api/main.go create mode 100644 cmd/open_im_cms_api/Makefile create mode 100644 cmd/open_im_cms_api/main.go create mode 100644 cmd/open_im_demo/Makefile create mode 100644 cmd/open_im_demo/main.go create mode 100644 cmd/open_im_msg_gateway/Makefile create mode 100644 cmd/open_im_msg_gateway/main.go create mode 100644 cmd/open_im_msg_transfer/Makefile create mode 100644 cmd/open_im_msg_transfer/main.go create mode 100644 cmd/open_im_push/Makefile create mode 100644 cmd/open_im_push/main.go create mode 100644 cmd/open_im_timer_task/Makefile create mode 100644 cmd/open_im_timer_task/main.go create mode 100644 cmd/rpc/open_im_admin_cms/Makefile create mode 100644 cmd/rpc/open_im_admin_cms/main.go create mode 100644 cmd/rpc/open_im_auth/Makefile create mode 100644 cmd/rpc/open_im_auth/main.go create mode 100644 cmd/rpc/open_im_friend/Makefile create mode 100644 cmd/rpc/open_im_friend/main.go create mode 100644 cmd/rpc/open_im_group/Makefile create mode 100644 cmd/rpc/open_im_group/main.go create mode 100644 cmd/rpc/open_im_message_cms/Makefile create mode 100644 cmd/rpc/open_im_message_cms/main.go create mode 100644 cmd/rpc/open_im_msg/Makefile create mode 100644 cmd/rpc/open_im_msg/main.go create mode 100644 cmd/rpc/open_im_office/Makefile create mode 100644 cmd/rpc/open_im_office/main.go create mode 100644 cmd/rpc/open_im_organization/Makefile create mode 100644 cmd/rpc/open_im_organization/main.go create mode 100644 cmd/rpc/open_im_statistics/Makefile create mode 100644 cmd/rpc/open_im_statistics/main.go create mode 100644 cmd/rpc/open_im_user/Makefile create mode 100644 cmd/rpc/open_im_user/main.go create mode 100644 cmd/test/main.go create mode 100644 config/config.yaml create mode 100644 deploy.Dockerfile create mode 100644 deploy/.dockerignore create mode 100644 deploy/Makefile create mode 100644 deploy/config.example.yaml create mode 100644 deploy/dockerfiles/Dockerfile.api create mode 100644 deploy/dockerfiles/Dockerfile.demo create mode 100644 deploy/dockerfiles/Dockerfile.msg_gateway create mode 100644 deploy/dockerfiles/Dockerfile.msg_transfer create mode 100644 deploy/dockerfiles/Dockerfile.push create mode 100644 deploy/dockerfiles/Dockerfile.rpc_auth create mode 100644 deploy/dockerfiles/Dockerfile.rpc_friend create mode 100644 deploy/dockerfiles/Dockerfile.rpc_group create mode 100644 deploy/dockerfiles/Dockerfile.rpc_msg create mode 100644 deploy/dockerfiles/Dockerfile.rpc_user create mode 100644 deploy/dockerfiles/Dockerfile.timer_task create mode 100644 deploy/env.yaml create mode 100644 deploy/openim.yaml create mode 100644 deploy/readme.md create mode 100644 docker-compose.yaml create mode 100644 docs/Architecture.jpg create mode 100644 docs/Open-IM-Servers-on-System.png create mode 100644 docs/Open-IM-Servers-on-docker.png create mode 100644 docs/Open-IM.png create mode 100644 docs/Wechat.jpg create mode 100644 docs/open-im-logo.png create mode 100644 docs/open-im-server.png create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/api/auth/auth.go create mode 100644 internal/api/chat/del_msg.go create mode 100644 internal/api/chat/get_max_min_seq.go create mode 100644 internal/api/chat/pull_msg.go create mode 100644 internal/api/chat/send_msg.go create mode 100644 internal/api/conversation/conversation.go create mode 100644 internal/api/friend/friend.go create mode 100644 internal/api/group/group.go create mode 100644 internal/api/manage/management_chat.go create mode 100644 internal/api/manage/management_user.go create mode 100644 internal/api/office/tag.go create mode 100644 internal/api/office/work_moments.go create mode 100644 internal/api/organization/organization.go create mode 100644 internal/api/third/ali_oss_credential.go create mode 100644 internal/api/third/minio_init.go create mode 100644 internal/api/third/minio_storage_credential.go create mode 100644 internal/api/third/tencent_cloud_storage_credential.go create mode 100644 internal/api/user/user.go create mode 100644 internal/cms_api/admin/admin.go create mode 100644 internal/cms_api/group/group.go create mode 100644 internal/cms_api/message_cms/message.go create mode 100644 internal/cms_api/middleware/cors.go create mode 100644 internal/cms_api/middleware/jwt_auth.go create mode 100644 internal/cms_api/organization/organization.go create mode 100644 internal/cms_api/router.go create mode 100644 internal/cms_api/statistics/statistics.go create mode 100644 internal/cms_api/user/user.go create mode 100644 internal/demo/register/login.go create mode 100644 internal/demo/register/reset_password.go create mode 100644 internal/demo/register/send_code.go create mode 100644 internal/demo/register/set_password.go create mode 100644 internal/demo/register/verify.go create mode 100644 internal/msg_gateway/gate/init.go create mode 100644 internal/msg_gateway/gate/logic.go create mode 100644 internal/msg_gateway/gate/open_im_media/room.go create mode 100644 internal/msg_gateway/gate/rpc_server.go create mode 100644 internal/msg_gateway/gate/validate.go create mode 100644 internal/msg_gateway/gate/ws_server.go create mode 100644 internal/msg_transfer/logic/db.go create mode 100644 internal/msg_transfer/logic/history_msg_handler.go create mode 100644 internal/msg_transfer/logic/init.go create mode 100644 internal/msg_transfer/logic/persistent_msg_handler.go create mode 100644 internal/push/content_struct/content.go create mode 100644 internal/push/getui/push.go create mode 100644 internal/push/jpush/common/JGPlatform.go create mode 100644 internal/push/jpush/push.go create mode 100644 internal/push/jpush/requestBody/audience.go create mode 100644 internal/push/jpush/requestBody/message.go create mode 100644 internal/push/jpush/requestBody/notification.go create mode 100644 internal/push/jpush/requestBody/options.go create mode 100644 internal/push/jpush/requestBody/platform.go create mode 100644 internal/push/jpush/requestBody/pushObj.go create mode 100644 internal/push/logic/init.go create mode 100644 internal/push/logic/push_handler.go create mode 100644 internal/push/logic/push_rpc_server.go create mode 100644 internal/push/logic/push_to_client.go create mode 100644 internal/push/logic/tpns.go create mode 100644 internal/push/push_interface.go create mode 100644 internal/push/sdk/tpns-server-sdk-go/go/auth/auth.go create mode 100644 internal/push/sdk/tpns-server-sdk-go/go/client/client.go create mode 100644 internal/push/sdk/tpns-server-sdk-go/go/common/http_helper.go create mode 100644 internal/push/sdk/tpns-server-sdk-go/go/common/json_helper.go create mode 100644 internal/push/sdk/tpns-server-sdk-go/go/def.go create mode 100644 internal/push/sdk/tpns-server-sdk-go/go/req/req.go create mode 100644 internal/rpc/admin_cms/admin_cms.go create mode 100644 internal/rpc/auth/auth.go create mode 100644 internal/rpc/auth/callback.go create mode 100644 internal/rpc/friend/callback.go create mode 100644 internal/rpc/friend/firend.go create mode 100644 internal/rpc/group/callback.go create mode 100644 internal/rpc/group/group.go create mode 100644 internal/rpc/message_cms/message_cms.go create mode 100644 internal/rpc/msg/callback.go create mode 100644 internal/rpc/msg/conversation_notification.go create mode 100644 internal/rpc/msg/del_msg.go create mode 100644 internal/rpc/msg/friend_notification.go create mode 100644 internal/rpc/msg/group_notification.go create mode 100644 internal/rpc/msg/pull_message.go create mode 100644 internal/rpc/msg/rpcChat.go create mode 100644 internal/rpc/msg/send_msg.go create mode 100644 internal/rpc/msg/tag_send_msg.go create mode 100644 internal/rpc/office/office.go create mode 100644 internal/rpc/organization/organization.go create mode 100644 internal/rpc/statistics/statistics.go create mode 100644 internal/rpc/user/callback.go create mode 100644 internal/rpc/user/user.go create mode 100644 internal/timed_task/init.go create mode 100644 internal/timed_task/timed_task.go create mode 100644 internal/utils/callback.go create mode 100644 internal/utils/cors_middleware_test.go create mode 100644 internal/utils/get_server_ip_test.go create mode 100644 internal/utils/id.go create mode 100644 internal/utils/id_test.go create mode 100644 internal/utils/image_test.go create mode 100644 internal/utils/jwt_token_test.go create mode 100644 internal/utils/md5_test.go create mode 100644 internal/utils/platform_number_id_to_name_test.go create mode 100644 internal/utils/utils.go create mode 100644 pkg/base_info/auth_api_struct.go create mode 100644 pkg/base_info/conversation_api_struct.go create mode 100644 pkg/base_info/cos_api_struct.go create mode 100644 pkg/base_info/friend_api_struct.go create mode 100644 pkg/base_info/group_api_struct.go create mode 100644 pkg/base_info/manage_api_struct.go create mode 100644 pkg/base_info/minio_api_struct.go create mode 100644 pkg/base_info/msg.go create mode 100644 pkg/base_info/office_struct.go create mode 100644 pkg/base_info/organization_api_struct.go create mode 100644 pkg/base_info/oss_api_struct.go create mode 100644 pkg/base_info/public_struct.go create mode 100644 pkg/base_info/user_api_struct.go create mode 100644 pkg/base_info/work_moments_struct.go create mode 100644 pkg/call_back_struct/common.go create mode 100644 pkg/call_back_struct/group.go create mode 100644 pkg/call_back_struct/message.go create mode 100644 pkg/cms_api_struct/admin.go create mode 100644 pkg/cms_api_struct/common.go create mode 100644 pkg/cms_api_struct/group.go create mode 100644 pkg/cms_api_struct/message_cms.go create mode 100644 pkg/cms_api_struct/organization.go create mode 100644 pkg/cms_api_struct/statistics.go create mode 100644 pkg/cms_api_struct/user.go create mode 100644 pkg/common/config/config.go create mode 100644 pkg/common/constant/constant.go create mode 100644 pkg/common/constant/error.go create mode 100644 pkg/common/constant/platform_number_id_to_name.go create mode 100644 pkg/common/db/model.go create mode 100644 pkg/common/db/model_struct.go create mode 100644 pkg/common/db/mongoModel.go create mode 100644 pkg/common/db/mysql.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/demo_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/friend_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/friend_request_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/group_member_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/group_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/group_request_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/message_cms.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/organization_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/statistics_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/user_black_list_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_model/user_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_msg_model/chat_log_model.go create mode 100644 pkg/common/db/mysql_model/im_mysql_msg_model/hash_code.go create mode 100644 pkg/common/db/redisModel.go create mode 100644 pkg/common/db/redisModel_test.go create mode 100644 pkg/common/http/http_client.go create mode 100644 pkg/common/http/http_resp.go create mode 100644 pkg/common/kafka/consumer.go create mode 100644 pkg/common/kafka/consumer_group.go create mode 100644 pkg/common/kafka/producer.go create mode 100644 pkg/common/log/es_hk.go create mode 100644 pkg/common/log/file_line_hk.go create mode 100644 pkg/common/log/logrus.go create mode 100644 pkg/common/log/time_format.go create mode 100644 pkg/common/multi_terminal_login/multi_terminal_login.go create mode 100644 pkg/common/token_verify/jwt_token.go create mode 100644 pkg/common/utils/utils.go create mode 100644 pkg/grpc-etcdv3/getcdv3/pool.go create mode 100644 pkg/grpc-etcdv3/getcdv3/register.go create mode 100644 pkg/grpc-etcdv3/getcdv3/resolver.go create mode 100644 pkg/proto/admin_cms/admin_cms.pb.go create mode 100644 pkg/proto/admin_cms/admin_cms.proto create mode 100644 pkg/proto/auth/auth.pb.go create mode 100644 pkg/proto/auth/auth.proto create mode 100644 pkg/proto/auto_proto.sh create mode 100644 pkg/proto/base/base.proto create mode 100644 pkg/proto/chat/chat.pb.go create mode 100644 pkg/proto/chat/chat.proto create mode 100644 pkg/proto/friend/friend.pb.go create mode 100644 pkg/proto/friend/friend.proto create mode 100644 pkg/proto/group/group.pb.go create mode 100644 pkg/proto/group/group.proto create mode 100644 pkg/proto/message_cms/message_cms.pb.go create mode 100644 pkg/proto/message_cms/message_cms.proto create mode 100644 pkg/proto/office/office.pb.go create mode 100644 pkg/proto/office/office.proto create mode 100644 pkg/proto/organization/organization.pb.go create mode 100644 pkg/proto/organization/organization.proto create mode 100644 pkg/proto/proto_dir.cfg create mode 100644 pkg/proto/push/push.pb.go create mode 100644 pkg/proto/push/push.proto create mode 100644 pkg/proto/relay/relay.pb.go create mode 100644 pkg/proto/relay/relay.proto create mode 100644 pkg/proto/rtc/rtc.pb.go create mode 100644 pkg/proto/rtc/rtc.proto create mode 100644 pkg/proto/sdk_ws/ws.pb.go create mode 100644 pkg/proto/sdk_ws/ws.proto create mode 100644 pkg/proto/statistics/statistics.pb.go create mode 100644 pkg/proto/statistics/statistics.proto create mode 100644 pkg/proto/user/user.pb.go create mode 100644 pkg/proto/user/user.proto create mode 100644 pkg/statistics/statistics.go create mode 100644 pkg/utils/cors_middleware.go create mode 100644 pkg/utils/file.go create mode 100644 pkg/utils/get_server_ip.go create mode 100644 pkg/utils/image.go create mode 100644 pkg/utils/map.go create mode 100644 pkg/utils/md5.go create mode 100644 pkg/utils/strings.go create mode 100644 pkg/utils/time_format.go create mode 100644 pkg/utils/utils.go create mode 100644 script/build_all_service.sh create mode 100644 script/build_images.sh create mode 100644 script/check_all.sh create mode 100644 script/demo_svr_start.sh create mode 100644 script/docker_check_service.sh create mode 100644 script/docker_start_all.sh create mode 100644 script/env_check.sh create mode 100644 script/function.sh create mode 100644 script/msg_gateway_start.sh create mode 100644 script/msg_transfer_start.sh create mode 100644 script/mysql_database_init.sh create mode 100644 script/path_info.cfg create mode 100644 script/push_start.sh create mode 100644 script/sdk_svr_start.sh create mode 100644 script/start_all.sh create mode 100644 script/start_rpc_service.sh create mode 100644 script/stop_all.sh create mode 100644 script/style_info.cfg create mode 100644 script/timer_start.sh diff --git a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..e5d8ed6fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md @@ -0,0 +1,37 @@ +--- +name: "\U0001F41E Bug" +about: File a bug/issue +title: "[BUG] " +labels: '' +assignees: '' + +--- + +<!-- +Note: Please search to see if an issue already exists for the bug you encountered. +--> + +### Environment: +<!-- linux? windows? or Mac? +Example: +- OS: Ubuntu 20.04 --> + +### Physical Memory Capacity: +<!-- 8G or above is better --> + +### Docker Image: +<!-- Did you pull the docker image before execute docker images --> + +### Code Version: +<!-- Did you pull code from github? Make sure the code is up to date--> + +### Component installation: +<!-- Has etcd, mysql, mongodb, redis or Kafka been installed on the server before Open-IM-Server deployment--> + + +### Log File: +<!-- view log file(logs/openIM.log) content. --> + + +### screenshot: +<!----> diff --git a/.github/ISSUE_TEMPLATE/deployment-issues.md b/.github/ISSUE_TEMPLATE/deployment-issues.md new file mode 100644 index 000000000..57d7cbcb7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/deployment-issues.md @@ -0,0 +1,36 @@ +--- +name: Deployment issues +about: Deployment issues +title: '' +labels: '' +assignees: '' + +--- + +If you are deploying OpenIM for the first time + + + +``` +git clone https://github.com/OpenIMSDK/Open-IM-Server.git --recursive +``` + +screenshot here + +``` +cd Open-IM-Server/script ; chmod +x *.sh ; ./env_check.sh +``` + +screenshot here + +``` +cd .. ; docker-compose up -d +``` + +screenshot here + +``` +cd script ; ./docker_check_service.sh +``` + +screenshot here diff --git a/.github/ISSUE_TEMPLATE/update-.md b/.github/ISSUE_TEMPLATE/update-.md new file mode 100644 index 000000000..ba8da7270 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/update-.md @@ -0,0 +1,38 @@ +--- +name: 'update ' +about: update docker image +title: update docker image +labels: '' +assignees: '' + +--- + +``` +cd Open-IM-Server ; docker-compose down +``` + +screenshot here + +``` +git pull +``` + +screenshot here + +``` +docker-compose pull +``` + +screenshot here + +``` +chmod +x script/*.sh ; docker-compose up -d +``` + +screenshot here + +``` +cd script ; ./docker_check_service.sh +``` + +screenshot here diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..f106438e3 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '23 2 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3390267f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +bin +logs +.devcontainer +components +logs +out-test +.github +.idea + + +deploy/open_im_demo +deploy/open_im_api +deploy/open_im_msg_gateway +deploy/open_im_msg_transfer +deploy/open_im_push +deploy/open_im_timer_task +deploy/open_im_rpc_user +deploy/open_im_rpc_friend +deploy/open_im_rpc_group +deploy/open_im_rpc_msg +deploy/open_im_rpc_auth +deploy/Open-IM-SDK-Core diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..be3279250 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ + +[submodule "cmd/Open-IM-SDK-Core"] + path = cmd/Open-IM-SDK-Core + url = https://github.com/OpenIMSDK/Open-IM-SDK-Core.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 000000000..4964bacb5 --- /dev/null +++ b/README.md @@ -0,0 +1,159 @@ +# Open-IM-Server + +![avatar](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/open-im-logo.png) + +[![LICENSE](https://img.shields.io/badge/license-Apache--2.0-green)](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/LICENSE) [![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/) + +## Open-IM-Server: Open source Instant Messaging Server + +Instant messaging server. Backend in pure Golang, wire transport protocol is JSON over websocket. + +Everything is a message in Open-IM-Server, so you can extend custom messages easily, there is no need to modify the server code. + +Using microservice architectures, Open-IM-Server can be deployed using clusters. + +By deployment of the Open-IM-Server on the customer's server, developers can integrate instant messaging and real-time network capabilities into their own applications free of charge and quickly, and ensure the security and privacy of business data. + +## Features + +- Everything in Free +- Scalable architecture +- Easy integration +- Good scalability +- High performance +- Lightweight +- Supports multiple protocols + +## Community + +- Join the Telegram-OpenIM group: https://t.me/joinchat/zSJLPaHBNLZmODI1 +- 中文官网访问这里:[Open-IM中文开发文档](https://doc.rentsoft.cn/) + +## Quick start + +### Installing Open-IM-Server + +> Open-IM relies on five open source high-performance components: ETCD, MySQL, MongoDB, Redis, and Kafka. Privatization deployment Before Open-IM-Server, please make sure that the above five components have been installed. If your server does not have the above components, you must first install Missing components. If you have the above components, it is recommended to use them directly. If not, it is recommended to use Docker-compose, no To install dependencies, one-click deployment, faster and more convenient. + +#### Source code deployment + +1. Install [Go environment](https://golang.org/doc/install). Make sure Go version is at least 1.15. + +2. Clone the Open-IM project to your server. + + ``` + git clone https://github.com/OpenIMSDK/Open-IM-Server.git --recursive + ``` + +3. Build and start Service. + + 1. Shell authorization + + ``` + #cd Open-IM-server/script + + chmod +x *.sh + ``` + + 2. Execute the build shell + + ``` + ./build_all_service.sh + ``` + + 3. Start service + + ``` + ./start_all.sh + ``` + + 4. Check service + + ``` + ./check_all.sh + ``` + + ![OpenIMServersonSystempng](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/Open-IM-Servers-on-System.png) + +#### Docker deployment + +All images are available at https://hub.docker.com/r/lyt1123/open_im_server + +1. [Install Docker](https://docs.docker.com/install/) 1.13 or above. + +2. [Install Docker Compose](https://docs.docker.com/compose/install/) 1.22 or above. + +3. Clone the Open-IM project to your server. + + ``` + git clone https://github.com/OpenIMSDK/Open-IM-Server.git --recursive + ``` + +4. Start docker-compose with one click(Docker automatically pulls all images) + + ``` + cd Open-IM-Server + docker-compose up -d + ``` + +5. Check service + + ``` + ./docker_check_service.sh + ./check_all.sh + ``` + + ![OpenIMServersondockerpng](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/Open-IM-Servers-on-docker.png) + +### CONFIGURATION INSTRUCTIONS + +> Open-IM configuration is divided into basic component configuration and business internal service configuration. Developers need to fill in the address of each component as the address of their server component when using the product, and ensure that the internal service port of the business is not occupied + +#### Basic Component Configuration Instructions + +- ETCD + - Etcd is used for the discovery and registration of rpc services, etcd Schema is the prefix of the registered name, it is recommended to modify it to your company name, etcd address (ip+port) supports clustered deployment, you can fill in multiple ETCD addresses separated by commas, and also only one etcd address. +- MySQL + - mysql is used for full storage of messages and user relationships. Cluster deployment is not supported for the time being. Modify addresses and users, passwords, and database names. +- Mongo + - Mongo is used for offline storage of messages. The default storage is 7 days. Cluster deployment is temporarily not supported. Just modify the address and database name. +- Redis + - Redis is currently mainly used for message serial number storage and user token information storage. Cluster deployment is temporarily not supported. Just modify the corresponding redis address and password. +- Kafka + - Kafka is used as a message transfer storage queue to support cluster deployment, just modify the corresponding address + +#### Internal Service Configuration Instructions + +- credential&&push + - The Open-IM needs to use the three-party offline push function. Currently, Tencent's three-party push is used. It supports IOS, Android and OSX push. This information is some registration information pushed by Tencent. Developers need to go to Tencent Cloud Mobile Push to register the corresponding information. If you do not fill in the corresponding information, you cannot use the offline message push function +- api&&rpcport&&longconnsvr&&rpcregistername + - The api port is the http interface, longconnsvr is the websocket listening port, and rpcport is the internal service startup port. Both support cluster deployment. Make sure that these ports are not used. If you want to open multiple services for a single service, fill in multiple ports separated by commas. rpcregistername is the service name registered by each service to the registry etcd, no need to modify +- log&&modulename + - The log configuration includes the storage path of the log file, and the log is sent to elasticsearch for log viewing. Currently, the log is not supported to be sent to elasticsearch. The configuration does not need to be modified for the time being. The modulename is used to split the log according to the name of the service module. The default configuration is fine. +- multiloginpolicy&&tokenpolicy + - Open-IM supports multi-terminal login. Currently, there are three multi-terminal login policies. The PC terminal and the mobile terminal are online at the same time by default. When multiple policies are configured to be true, the first policy with true is used by default, and the token policy is the generated token policy. , The developer can customize the expiration time of the token + +### SCRIPT DESCRIPTION + +> Open-IM script provides service compilation, start, and stop scripts. There are four Open-IM script start modules, one is the http+rpc service start module, the second is the websocket service start module, then the msg_transfer module, and the last is the push module + +- path_info.cfg&&style_info.cfg&&functions.sh + - Contains the path information of each module, including the path where the source code is located, the name of the service startup, the shell print font style, and some functions for processing shell strings +- build_all_service.sh + - Compile the module, compile all the source code of Open-IM into a binary file and put it into the bin directory +- start_rpc_api_service.sh&&msg_gateway_start.sh&&msg_transfer_start.sh&&push_start.sh + - Independent script startup module, followed by api and rpc modules, message gateway module, message transfer module, and push module +- start_all.sh&&stop_all.sh + - Total script, start all services and close all services + +## Authentication Clow Chart + +![avatar](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/open-im-server.png) + +## Architecture + +![avatar](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/docs/Architecture.jpg) + +## License + +Open-IM-Server is under the Apache 2.0 license. See the [LICENSE](https://github.com/OpenIMSDK/Open-IM-Server/blob/main/LICENSE) file for details diff --git a/cmd/Open-IM-SDK-Core b/cmd/Open-IM-SDK-Core new file mode 160000 index 000000000..3ecd23203 --- /dev/null +++ b/cmd/Open-IM-SDK-Core @@ -0,0 +1 @@ +Subproject commit 3ecd23203cd6bd746b1fcb0c70755bd2cbf5361c diff --git a/cmd/open_im_api/Makefile b/cmd/open_im_api/Makefile new file mode 100644 index 000000000..1f96bca5a --- /dev/null +++ b/cmd/open_im_api/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_api +BIN_DIR=../../bin/ + + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + diff --git a/cmd/open_im_api/main.go b/cmd/open_im_api/main.go new file mode 100644 index 000000000..a2f8522ef --- /dev/null +++ b/cmd/open_im_api/main.go @@ -0,0 +1,177 @@ +package main + +import ( + apiAuth "Open_IM/internal/api/auth" + apiChat "Open_IM/internal/api/chat" + "Open_IM/internal/api/conversation" + "Open_IM/internal/api/friend" + "Open_IM/internal/api/group" + "Open_IM/internal/api/manage" + "Open_IM/internal/api/office" + "Open_IM/internal/api/organization" + apiThird "Open_IM/internal/api/third" + "Open_IM/internal/api/user" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "flag" + "fmt" + "io" + "os" + "strconv" + + "github.com/gin-gonic/gin" + //"syscall" + "Open_IM/pkg/common/constant" +) + +func main() { + log.NewPrivateLog(constant.LogFileName) + gin.SetMode(gin.ReleaseMode) + f, _ := os.Create("../logs/api.log") + gin.DefaultWriter = io.MultiWriter(f) + + r := gin.Default() + r.Use(utils.CorsHandler()) + + log.Info("load config: ", config.Config) + // user routing group, which handles user registration and login services + userRouterGroup := r.Group("/user") + { + userRouterGroup.POST("/update_user_info", user.UpdateUserInfo) //1 + userRouterGroup.POST("/get_users_info", user.GetUsersInfo) //1 + userRouterGroup.POST("/get_self_user_info", user.GetSelfUserInfo) //1 + } + //friend routing group + friendRouterGroup := r.Group("/friend") + { + // friendRouterGroup.POST("/get_friends_info", friend.GetFriendsInfo) + friendRouterGroup.POST("/add_friend", friend.AddFriend) //1 + friendRouterGroup.POST("/delete_friend", friend.DeleteFriend) //1 + friendRouterGroup.POST("/get_friend_apply_list", friend.GetFriendApplyList) //1 + friendRouterGroup.POST("/get_self_friend_apply_list", friend.GetSelfFriendApplyList) //1 + friendRouterGroup.POST("/get_friend_list", friend.GetFriendList) //1 + friendRouterGroup.POST("/add_friend_response", friend.AddFriendResponse) //1 + friendRouterGroup.POST("/set_friend_remark", friend.SetFriendRemark) //1 + + friendRouterGroup.POST("/add_black", friend.AddBlack) //1 + friendRouterGroup.POST("/get_black_list", friend.GetBlacklist) //1 + friendRouterGroup.POST("/remove_black", friend.RemoveBlack) //1 + + friendRouterGroup.POST("/import_friend", friend.ImportFriend) //1 + friendRouterGroup.POST("/is_friend", friend.IsFriend) //1 + } + //group related routing group + groupRouterGroup := r.Group("/group") + { + groupRouterGroup.POST("/create_group", group.CreateGroup) //1 + groupRouterGroup.POST("/set_group_info", group.SetGroupInfo) //1 + groupRouterGroup.POST("join_group", group.JoinGroup) //1 + groupRouterGroup.POST("/quit_group", group.QuitGroup) //1 + groupRouterGroup.POST("/group_application_response", group.ApplicationGroupResponse) //1 + groupRouterGroup.POST("/transfer_group", group.TransferGroupOwner) //1 + groupRouterGroup.POST("/get_recv_group_applicationList", group.GetRecvGroupApplicationList) //1 + groupRouterGroup.POST("/get_user_req_group_applicationList", group.GetUserReqGroupApplicationList) + groupRouterGroup.POST("/get_groups_info", group.GetGroupsInfo) //1 + groupRouterGroup.POST("/kick_group", group.KickGroupMember) //1 + groupRouterGroup.POST("/get_group_member_list", group.GetGroupMemberList) //no use + groupRouterGroup.POST("/get_group_all_member_list", group.GetGroupAllMemberList) //1 + groupRouterGroup.POST("/get_group_members_info", group.GetGroupMembersInfo) //1 + groupRouterGroup.POST("/invite_user_to_group", group.InviteUserToGroup) //1 + groupRouterGroup.POST("/get_joined_group_list", group.GetJoinedGroupList) //1 + groupRouterGroup.POST("/dismiss_group", group.DismissGroup) // + groupRouterGroup.POST("/mute_group_member", group.MuteGroupMember) + groupRouterGroup.POST("/cancel_mute_group_member", group.CancelMuteGroupMember) //MuteGroup + groupRouterGroup.POST("/mute_group", group.MuteGroup) + groupRouterGroup.POST("/cancel_mute_group", group.CancelMuteGroup) + } + //certificate + authRouterGroup := r.Group("/auth") + { + authRouterGroup.POST("/user_register", apiAuth.UserRegister) //1 + authRouterGroup.POST("/user_token", apiAuth.UserToken) //1 + } + //Third service + thirdGroup := r.Group("/third") + { + thirdGroup.POST("/tencent_cloud_storage_credential", apiThird.TencentCloudStorageCredential) + thirdGroup.POST("/ali_oss_credential", apiThird.AliOSSCredential) + thirdGroup.POST("/minio_storage_credential", apiThird.MinioStorageCredential) + thirdGroup.POST("/minio_upload", apiThird.MinioUploadFile) + } + //Message + chatGroup := r.Group("/msg") + { + chatGroup.POST("/newest_seq", apiChat.GetSeq) + chatGroup.POST("/send_msg", apiChat.SendMsg) + chatGroup.POST("/pull_msg_by_seq", apiChat.PullMsgBySeqList) + chatGroup.POST("/del_msg", apiChat.DelMsg) + } + //Manager + managementGroup := r.Group("/manager") + { + managementGroup.POST("/delete_user", manage.DeleteUser) //1 + managementGroup.POST("/send_msg", manage.ManagementSendMsg) + managementGroup.POST("/get_all_users_uid", manage.GetAllUsersUid) //1 + managementGroup.POST("/account_check", manage.AccountCheck) //1 + managementGroup.POST("/get_users_online_status", manage.GetUsersOnlineStatus) //1 + } + //Conversation + conversationGroup := r.Group("/conversation") + { //1 + conversationGroup.POST("/get_all_conversations", conversation.GetAllConversations) + conversationGroup.POST("/get_conversation", conversation.GetConversation) + conversationGroup.POST("/get_conversations", conversation.GetConversations) + conversationGroup.POST("/set_conversation", conversation.SetConversation) + conversationGroup.POST("/batch_set_conversation", conversation.BatchSetConversations) + conversationGroup.POST("/set_recv_msg_opt", conversation.SetRecvMsgOpt) + } + // office + officeGroup := r.Group("/office") + { + officeGroup.POST("/get_user_tags", office.GetUserTags) + officeGroup.POST("/get_user_tag_by_id", office.GetUserTagByID) + officeGroup.POST("/create_tag", office.CreateTag) + officeGroup.POST("/delete_tag", office.DeleteTag) + officeGroup.POST("/set_tag", office.SetTag) + officeGroup.POST("/send_msg_to_tag", office.SendMsg2Tag) + officeGroup.POST("/get_send_tag_log", office.GetTagSendLogs) + + officeGroup.POST("/create_one_work_moment", office.CreateOneWorkMoment) + officeGroup.POST("/delete_one_work_moment", office.DeleteOneWorkMoment) + officeGroup.POST("/like_one_work_moment", office.LikeOneWorkMoment) + officeGroup.POST("/comment_one_work_moment", office.CommentOneWorkMoment) + officeGroup.POST("/get_user_work_moments", office.GetUserWorkMoments) + officeGroup.POST("/get_user_friend_work_moments", office.GetUserFriendWorkMoments) + officeGroup.POST("/get_user_work_moments_comments_msg", office.GetUserWorkMomentsCommentsMsg) + officeGroup.POST("/clear_user_work_moments_comments_msg", office.ClearUserWorkMomentsCommentsMsg) + officeGroup.POST("/set_user_work_moments_level", office.SetUserWorkMomentsLevel) + } + + organizationGroup := r.Group("/organization") + { + organizationGroup.POST("/create_department", organization.CreateDepartment) + organizationGroup.POST("/update_department", organization.UpdateDepartment) + organizationGroup.POST("/get_sub_department", organization.GetSubDepartment) + organizationGroup.POST("/delete_department", organization.DeleteDepartment) + + organizationGroup.POST("/create_organization_user", organization.CreateOrganizationUser) + organizationGroup.POST("/update_organization_user", organization.UpdateOrganizationUser) + organizationGroup.POST("/create_department_member", organization.CreateDepartmentMember) + + organizationGroup.POST("/get_user_in_department", organization.GetUserInDepartment) + organizationGroup.POST("/update_user_In_department", organization.UpdateUserInDepartment) + organizationGroup.POST("/delete_organization_user", organization.DeleteOrganizationUser) + organizationGroup.POST("/get_department_member", organization.GetDepartmentMember) + organizationGroup.POST("/delete_user_in_department", organization.DeleteUserInDepartment) + } + + go apiThird.MinioInit() + ginPort := flag.Int("port", 10000, "get ginServerPort from cmd,default 10000 as port") + flag.Parse() + fmt.Println("start api server, port: ", *ginPort) + err := r.Run(":" + strconv.Itoa(*ginPort)) + if err != nil { + log.Error("", "run failed ", *ginPort, err.Error()) + } +} diff --git a/cmd/open_im_cms_api/Makefile b/cmd/open_im_cms_api/Makefile new file mode 100644 index 000000000..31304542d --- /dev/null +++ b/cmd/open_im_cms_api/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_cms_api +BIN_DIR=../../bin/ + + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + diff --git a/cmd/open_im_cms_api/main.go b/cmd/open_im_cms_api/main.go new file mode 100644 index 000000000..262020fea --- /dev/null +++ b/cmd/open_im_cms_api/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "Open_IM/internal/cms_api" + "Open_IM/pkg/utils" + "fmt" + + "github.com/gin-gonic/gin" +) + +func main() { + gin.SetMode(gin.ReleaseMode) + router := cms_api.NewGinRouter() + router.Use(utils.CorsHandler()) + fmt.Println("start cms api server, port: ", 8000) + router.Run(":" + "8000") +} diff --git a/cmd/open_im_demo/Makefile b/cmd/open_im_demo/Makefile new file mode 100644 index 000000000..45829acd8 --- /dev/null +++ b/cmd/open_im_demo/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_demo +BIN_DIR=../../bin/ + + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + diff --git a/cmd/open_im_demo/main.go b/cmd/open_im_demo/main.go new file mode 100644 index 000000000..af7809547 --- /dev/null +++ b/cmd/open_im_demo/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "Open_IM/internal/demo/register" + "Open_IM/pkg/utils" + "flag" + "fmt" + "io" + "os" + "strconv" + + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "github.com/gin-gonic/gin" +) + +func main() { + log.NewPrivateLog(constant.LogFileName) + gin.SetMode(gin.ReleaseMode) + f, _ := os.Create("../logs/api.log") + gin.DefaultWriter = io.MultiWriter(f) + + r := gin.Default() + r.Use(utils.CorsHandler()) + + authRouterGroup := r.Group("/auth") + { + authRouterGroup.POST("/code", register.SendVerificationCode) + authRouterGroup.POST("/verify", register.Verify) + authRouterGroup.POST("/password", register.SetPassword) + authRouterGroup.POST("/login", register.Login) + authRouterGroup.POST("/reset_password", register.ResetPassword) + } + + ginPort := flag.Int("port", 42233, "get ginServerPort from cmd,default 42233 as port") + flag.Parse() + fmt.Println("start demo api server, port: ", *ginPort) + err := r.Run(":" + strconv.Itoa(*ginPort)) + if err != nil { + log.Error("", "run failed ", *ginPort, err.Error()) + } +} diff --git a/cmd/open_im_msg_gateway/Makefile b/cmd/open_im_msg_gateway/Makefile new file mode 100644 index 000000000..566d8d9c2 --- /dev/null +++ b/cmd/open_im_msg_gateway/Makefile @@ -0,0 +1,24 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_msg_gateway +BIN_DIR=../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + diff --git a/cmd/open_im_msg_gateway/main.go b/cmd/open_im_msg_gateway/main.go new file mode 100644 index 000000000..283f831b8 --- /dev/null +++ b/cmd/open_im_msg_gateway/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "Open_IM/internal/msg_gateway/gate" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "flag" + "fmt" + "sync" +) + +func main() { + log.NewPrivateLog(constant.LogFileName) + rpcPort := flag.Int("rpc_port", 10400, "rpc listening port") + wsPort := flag.Int("ws_port", 17778, "ws listening port") + flag.Parse() + var wg sync.WaitGroup + wg.Add(1) + fmt.Println("start rpc/msg_gateway server, port: ", *rpcPort, *wsPort) + gate.Init(*rpcPort, *wsPort) + gate.Run() + wg.Wait() +} diff --git a/cmd/open_im_msg_transfer/Makefile b/cmd/open_im_msg_transfer/Makefile new file mode 100644 index 000000000..6a67b9bee --- /dev/null +++ b/cmd/open_im_msg_transfer/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_msg_transfer +BIN_DIR=../../bin/ + + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + diff --git a/cmd/open_im_msg_transfer/main.go b/cmd/open_im_msg_transfer/main.go new file mode 100644 index 000000000..9dfabecda --- /dev/null +++ b/cmd/open_im_msg_transfer/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "Open_IM/internal/msg_transfer/logic" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "fmt" + "sync" +) + +func main() { + var wg sync.WaitGroup + wg.Add(1) + log.NewPrivateLog(constant.LogFileName) + logic.Init() + fmt.Println("start msg_transfer server") + logic.Run() + wg.Wait() +} diff --git a/cmd/open_im_push/Makefile b/cmd/open_im_push/Makefile new file mode 100644 index 000000000..df7b9e88a --- /dev/null +++ b/cmd/open_im_push/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_push +BIN_DIR=../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + + diff --git a/cmd/open_im_push/main.go b/cmd/open_im_push/main.go new file mode 100644 index 000000000..95e8521dd --- /dev/null +++ b/cmd/open_im_push/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "Open_IM/internal/push/logic" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "flag" + "fmt" + "sync" +) + +func main() { + rpcPort := flag.Int("port", 10700, "rpc listening port") + flag.Parse() + var wg sync.WaitGroup + wg.Add(1) + log.NewPrivateLog(constant.LogFileName) + fmt.Println("start push rpc server, port: ", *rpcPort) + logic.Init(*rpcPort) + logic.Run() + wg.Wait() +} diff --git a/cmd/open_im_timer_task/Makefile b/cmd/open_im_timer_task/Makefile new file mode 100644 index 000000000..6c6d713d8 --- /dev/null +++ b/cmd/open_im_timer_task/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_timer_task +BIN_DIR=../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + + diff --git a/cmd/open_im_timer_task/main.go b/cmd/open_im_timer_task/main.go new file mode 100644 index 000000000..20d9a4d1c --- /dev/null +++ b/cmd/open_im_timer_task/main.go @@ -0,0 +1,63 @@ +package main + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" +) + +func main() { + log.NewPrivateLog(constant.LogFileName) + //for { + // fmt.Println("start delete mongodb expired record") + // timeUnixBegin := time.Now().Unix() + // count, _ := db.DB.MgoUserCount() + // fmt.Println("mongodb record count: ", count) + // for i := 0; i < count; i++ { + // time.Sleep(1 * time.Millisecond) + // uid, _ := db.DB.MgoSkipUID(i) + // fmt.Println("operate uid: ", uid) + // err := db.DB.DelUserChat(uid) + // if err != nil { + // fmt.Println("operate uid failed: ", uid, err.Error()) + // } + // } + // + // timeUnixEnd := time.Now().Unix() + // costTime := timeUnixEnd - timeUnixBegin + // if costTime > int64(config.Config.Mongo.DBRetainChatRecords*24*3600) { + // continue + // } else { + // sleepTime := 0 + // if int64(config.Config.Mongo.DBRetainChatRecords*24*3600)-costTime > 24*3600 { + // sleepTime = 24 * 3600 + // } else { + // sleepTime = config.Config.Mongo.DBRetainChatRecords*24*3600 - int(costTime) + // } + // fmt.Println("sleep: ", sleepTime) + // time.Sleep(time.Duration(sleepTime) * time.Second) + // } + //} + //for { + // uidList, err := im_mysql_model.SelectAllUserID() + // if err != nil { + // //log.NewError("999999", err.Error()) + // } else { + // for _, v := range uidList { + // minSeq, err := commonDB.DB.GetMinSeqFromMongo(v) + // if err != nil { + // //log.NewError("999999", "get user minSeq err", err.Error(), v) + // continue + // } else { + // err := commonDB.DB.SetUserMinSeq(v, minSeq) + // if err != nil { + // //log.NewError("999999", "set user minSeq err", err.Error(), v) + // } + // } + // time.Sleep(time.Duration(100) * time.Millisecond) + // } + // + // } + // + //} + +} diff --git a/cmd/rpc/open_im_admin_cms/Makefile b/cmd/rpc/open_im_admin_cms/Makefile new file mode 100644 index 000000000..f6efc1c08 --- /dev/null +++ b/cmd/rpc/open_im_admin_cms/Makefile @@ -0,0 +1,23 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_admin_cms +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi diff --git a/cmd/rpc/open_im_admin_cms/main.go b/cmd/rpc/open_im_admin_cms/main.go new file mode 100644 index 000000000..c69135645 --- /dev/null +++ b/cmd/rpc/open_im_admin_cms/main.go @@ -0,0 +1,15 @@ +package main + +import ( + rpcMessageCMS "Open_IM/internal/rpc/admin_cms" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 11000, "rpc listening port") + flag.Parse() + fmt.Println("start cms rpc server, port: ", *rpcPort) + rpcServer := rpcMessageCMS.NewAdminCMSServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_auth/Makefile b/cmd/rpc/open_im_auth/Makefile new file mode 100644 index 000000000..da280c3b5 --- /dev/null +++ b/cmd/rpc/open_im_auth/Makefile @@ -0,0 +1,24 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_auth +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + diff --git a/cmd/rpc/open_im_auth/main.go b/cmd/rpc/open_im_auth/main.go new file mode 100644 index 000000000..53b0f9de5 --- /dev/null +++ b/cmd/rpc/open_im_auth/main.go @@ -0,0 +1,16 @@ +package main + +import ( + rpcAuth "Open_IM/internal/rpc/auth" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 10600, "RpcToken default listen port 10800") + flag.Parse() + fmt.Println("start auth rpc server, port: ", *rpcPort) + rpcServer := rpcAuth.NewRpcAuthServer(*rpcPort) + rpcServer.Run() + +} diff --git a/cmd/rpc/open_im_friend/Makefile b/cmd/rpc/open_im_friend/Makefile new file mode 100644 index 000000000..c47cbcf1d --- /dev/null +++ b/cmd/rpc/open_im_friend/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_friend +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + + diff --git a/cmd/rpc/open_im_friend/main.go b/cmd/rpc/open_im_friend/main.go new file mode 100644 index 000000000..85d05e39c --- /dev/null +++ b/cmd/rpc/open_im_friend/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "Open_IM/internal/rpc/friend" + "flag" + "fmt" +) + +func main() { + + rpcPort := flag.Int("port", 10200, "get RpcFriendPort from cmd,default 12000 as port") + flag.Parse() + fmt.Println("start friend rpc server, port: ", *rpcPort) + rpcServer := friend.NewFriendServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_group/Makefile b/cmd/rpc/open_im_group/Makefile new file mode 100644 index 000000000..e7d1cb29d --- /dev/null +++ b/cmd/rpc/open_im_group/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_group +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + + diff --git a/cmd/rpc/open_im_group/main.go b/cmd/rpc/open_im_group/main.go new file mode 100644 index 000000000..7afc7ec57 --- /dev/null +++ b/cmd/rpc/open_im_group/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "Open_IM/internal/rpc/group" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 10500, "get RpcGroupPort from cmd,default 16000 as port") + flag.Parse() + fmt.Println("start group rpc server, port: ", *rpcPort) + rpcServer := group.NewGroupServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_message_cms/Makefile b/cmd/rpc/open_im_message_cms/Makefile new file mode 100644 index 000000000..4ac4cba3a --- /dev/null +++ b/cmd/rpc/open_im_message_cms/Makefile @@ -0,0 +1,23 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_message_cms +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi diff --git a/cmd/rpc/open_im_message_cms/main.go b/cmd/rpc/open_im_message_cms/main.go new file mode 100644 index 000000000..16151a2ed --- /dev/null +++ b/cmd/rpc/open_im_message_cms/main.go @@ -0,0 +1,15 @@ +package main + +import ( + rpcMessageCMS "Open_IM/internal/rpc/message_cms" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 10900, "rpc listening port") + flag.Parse() + fmt.Println("start msg cms rpc server, port: ", *rpcPort) + rpcServer := rpcMessageCMS.NewMessageCMSServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_msg/Makefile b/cmd/rpc/open_im_msg/Makefile new file mode 100644 index 000000000..7214d3fe1 --- /dev/null +++ b/cmd/rpc/open_im_msg/Makefile @@ -0,0 +1,23 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_msg +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi diff --git a/cmd/rpc/open_im_msg/main.go b/cmd/rpc/open_im_msg/main.go new file mode 100644 index 000000000..95908f48a --- /dev/null +++ b/cmd/rpc/open_im_msg/main.go @@ -0,0 +1,15 @@ +package main + +import ( + rpcChat "Open_IM/internal/rpc/msg" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 10300, "rpc listening port") + flag.Parse() + fmt.Println("start msg rpc server, port: ", *rpcPort) + rpcServer := rpcChat.NewRpcChatServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_office/Makefile b/cmd/rpc/open_im_office/Makefile new file mode 100644 index 000000000..b86230c64 --- /dev/null +++ b/cmd/rpc/open_im_office/Makefile @@ -0,0 +1,23 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_office +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi diff --git a/cmd/rpc/open_im_office/main.go b/cmd/rpc/open_im_office/main.go new file mode 100644 index 000000000..c9a05c791 --- /dev/null +++ b/cmd/rpc/open_im_office/main.go @@ -0,0 +1,15 @@ +package main + +import ( + rpc "Open_IM/internal/rpc/office" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 11100, "rpc listening port") + flag.Parse() + fmt.Println("start office rpc server, port: ", *rpcPort) + rpcServer := rpc.NewOfficeServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_organization/Makefile b/cmd/rpc/open_im_organization/Makefile new file mode 100644 index 000000000..77d658db9 --- /dev/null +++ b/cmd/rpc/open_im_organization/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_organization +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + + diff --git a/cmd/rpc/open_im_organization/main.go b/cmd/rpc/open_im_organization/main.go new file mode 100644 index 000000000..906ac510f --- /dev/null +++ b/cmd/rpc/open_im_organization/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "Open_IM/internal/rpc/organization" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 11200, "get RpcOrganizationPort from cmd,default 11200 as port") + flag.Parse() + fmt.Println("start organization rpc server, port: ", *rpcPort) + rpcServer := organization.NewServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_statistics/Makefile b/cmd/rpc/open_im_statistics/Makefile new file mode 100644 index 000000000..37dbb3efe --- /dev/null +++ b/cmd/rpc/open_im_statistics/Makefile @@ -0,0 +1,23 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_statistics +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi diff --git a/cmd/rpc/open_im_statistics/main.go b/cmd/rpc/open_im_statistics/main.go new file mode 100644 index 000000000..b87440abf --- /dev/null +++ b/cmd/rpc/open_im_statistics/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "Open_IM/internal/rpc/statistics" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 10800, "rpc listening port") + flag.Parse() + fmt.Println("start statistics rpc server, port: ", *rpcPort) + rpcServer := statistics.NewStatisticsServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/rpc/open_im_user/Makefile b/cmd/rpc/open_im_user/Makefile new file mode 100644 index 000000000..c379db284 --- /dev/null +++ b/cmd/rpc/open_im_user/Makefile @@ -0,0 +1,25 @@ +.PHONY: all build run gotool install clean help + +BINARY_NAME=open_im_user +BIN_DIR=../../../bin/ + +all: gotool build + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" + +run: + @go run ./ + +gotool: + go fmt ./ + go vet ./ + +install: + make build + mv ${BINARY_NAME} ${BIN_DIR} + +clean: + @if [ -f ${BINARY_NAME} ] ; then rm ${BINARY_NAME} ; fi + + diff --git a/cmd/rpc/open_im_user/main.go b/cmd/rpc/open_im_user/main.go new file mode 100644 index 000000000..d8644d028 --- /dev/null +++ b/cmd/rpc/open_im_user/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "Open_IM/internal/rpc/user" + "flag" + "fmt" +) + +func main() { + rpcPort := flag.Int("port", 10100, "rpc listening port") + flag.Parse() + fmt.Println("start user rpc server, port: ", *rpcPort) + rpcServer := user.NewUserServer(*rpcPort) + rpcServer.Run() +} diff --git a/cmd/test/main.go b/cmd/test/main.go new file mode 100644 index 000000000..87d5165f7 --- /dev/null +++ b/cmd/test/main.go @@ -0,0 +1,69 @@ +package main + +import ( + "Open_IM/pkg/utils" + "context" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "time" +) + +type MongoMsg struct { + UID string + Msg []string +} + + +func main() { + //"mongodb://%s:%s@%s/%s/?maxPoolSize=%d" + uri := "mongodb://user:pass@sample.host:27017/?maxPoolSize=20&w=majority" + DBAddress := "127.0.0.1:37017" + DBDatabase := "new-test-db" + Collection := "new-test-collection" + DBMaxPoolSize := 100 + uri = fmt.Sprintf("mongodb://%s/%s/?maxPoolSize=%d", + DBAddress,DBDatabase, + DBMaxPoolSize) + + mongoClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)) + if err != nil { + panic(err) + } + filter := bson.M{"uid":"my_uid"} + ctx, _ := context.WithTimeout(context.Background(), 30*time.Second) + for i:=0; i < 2; i++{ + + if err = mongoClient.Database(DBDatabase).Collection(Collection).FindOneAndUpdate(ctx, filter, + bson.M{"$push": bson.M{"msg": utils.Int32ToString(int32(i))}}).Err(); err != nil{ + fmt.Println("FindOneAndUpdate failed ", i, ) + var mmsg MongoMsg + mmsg.UID = "my_uid" + mmsg.Msg = append(mmsg.Msg, utils.Int32ToString(int32(i))) + _, err := mongoClient.Database(DBDatabase).Collection(Collection).InsertOne(ctx, &mmsg) + if err != nil { + fmt.Println("insertone failed ", err.Error(), i) + } else{ + fmt.Println("insertone ok ", i) + } + + }else { + fmt.Println("FindOneAndUpdate ok ", i) + } + + } + + var mmsg MongoMsg + + if err = mongoClient.Database(DBDatabase).Collection(Collection).FindOne(ctx, filter).Decode(&mmsg); err != nil { + fmt.Println("findone failed ", err.Error()) + }else{ + fmt.Println("findone ok ", mmsg.UID) + for i, v:=range mmsg.Msg{ + fmt.Println("find value: ", i, v) + } + } + + +} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 000000000..d61292bdc --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,609 @@ +# The class cannot be named by Pascal or camel case. +# If it is not used, the corresponding structure will not be set, +# and it will not be read naturally. +serverversion: 2.0.0 +#---------------Infrastructure configuration---------------------# +etcd: + etcdSchema: openIM #默认即可 + etcdAddr: [ 127.0.0.1:2379 ] #单机部署时,默认即可 + +mysql: + dbMysqlAddress: [ 127.0.0.1:13306 ] #mysql地址 目前仅支持单机,默认即可 + dbMysqlUserName: root #mysql用户名,建议修改 + dbMysqlPassword: openIM # mysql密码,建议修改 + dbMysqlDatabaseName: openIM_v2 #默认即可 + dbTableName: eMsg #默认即可 + dbMsgTableNum: 1 + dbMaxOpenConns: 20 + dbMaxIdleConns: 10 + dbMaxLifeTime: 120 + +mongo: + dbUri: ""#当dbUri值不为空则直接使用该值 + dbAddress: [ 127.0.0.1:37017 ] #mongo地址 目前仅支持单机,默认即可 + dbDirect: false + dbTimeout: 10 + dbDatabase: openIM #mongo db 默认即可 + dbSource: admin + dbUserName: #mongo用户名,建议先不设置 + dbPassword: #mongo密码,建议先不设置 + dbMaxPoolSize: 20 + dbRetainChatRecords: 3650 #mongo保存离线消息时间(天),根据需求修改 + +redis: + dbAddress: 127.0.0.1:16379 #redis地址 目前仅支持单机,默认即可 + dbMaxIdle: 128 + dbMaxActive: 0 + dbIdleTimeout: 120 + dbPassWord: openIM #redis密码 建议修改 + +kafka: + ws2mschat: + addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可 + topic: "ws2ms_chat" + ms2pschat: + addr: [ 127.0.0.1:9092 ] #kafka配置,默认即可 + topic: "ms2ps_chat" + consumergroupid: + msgToMongo: mongo + msgToMySql: mysql + msgToPush: push + + + +#---------------Internal service configuration---------------------# + +# The service ip default is empty, +# automatically obtain the machine's valid network card ip as the service ip, +# otherwise the configuration ip is preferred +#如果是单机模式,用0.0.0.0或者不填,默认即可 +serverip: 0.0.0.0 + +# endpoints 内部组件间访问的端点host名称,访问时,可以内部直接访问 host:port 来访问 +endpoints: + api: openim_api + cmsapi: openim_cms_api + push: openim_push + msg_gateway: openim_msg_gateway + rpc_auth: openim_rpc_auth + rpc_friend: openim_rpc_friend + rpc_group: openim_rpc_group + rpc_msg: openim_rpc_msg + rpc_user: openim_rpc_user + rpc_statistic: openim_rpc_statistic + rpc_admin_cms: openim_rpc_admin_cms + rpc_message_cms: openim_rpc_admin_cms + rpc_office: openim_rpc_office + +api: + openImApiPort: [ 10000 ] #api服务端口,默认即可,需要开放此端口或做nginx转发 +cmsapi: + openImCmsApiPort: [ 8000 ] #管理后台api服务端口,默认即可,需要开放此端口或做nginx转发 +sdk: + openImSdkWsPort: [ 30000 ] #jssdk服务端口,默认即可,项目中使用jssdk才需开放此端口或做nginx转发 +#对象存储服务,以下配置二选一,目前支持两种,腾讯云和minio,二者配置好其中一种即可(如果使用minio参考https://doc.rentsoft.cn/#/qa/minio搭建minio服务器) +credential: #腾讯cos,发送图片、视频、文件时需要,请自行申请后替换,必须修改 + tencent: + appID: 1302656840 + region: ap-chengdu + bucket: echat-1302656840 + secretID: AKIDGNYVChzIQinu7QEgtNp0hnNgqcV8vZTC + secretKey: kz15vW83qM6dBUWIq681eBZA0c0vlIbe + minio: #MinIO 发送图片、视频、文件时需要,请自行申请后替换,必须修改。 客户端初始化InitSDK,中 object_storage参数为minio + bucket: openim + location: us-east-1 + endpoint: http://127.0.0.1:9000 + endpointInner: http://127.0.0.1:9000 #minio内网地址 + endpointInnerEnable: true #是否启用minio内网地址 启用可以让桶初始化,IM server连接minio走内网地址访问 + accessKeyID: user12345 + secretAccessKey: key12345 + ali: # ali oss + regionID: "oss-cn-beijing" + accessKeyID: "" + accessKeySecret: "" + stsEndpoint: "sts.cn-beijing.aliyun.com" + ossEndpoint: "oss-cn-beijing.aliyuncs.com" + bucket: "bucket1" + finalHost: "http://bucket1.oss-cn-beijing.aliyuncs.com" + stsDurationSeconds: 3600 + OssRoleArn: "acs:ram::xxx:role/xxx" + + + +rpcport: #rpc服务端口 默认即可 + openImUserPort: [ 10100 ] + openImFriendPort: [ 10200 ] + openImOfflineMessagePort: [ 10300 ] + openImOnlineRelayPort: [ 10400 ] + openImGroupPort: [ 10500 ] + openImAuthPort: [ 10600 ] + openImPushPort: [ 10700 ] + openImStatisticsPort: [ 10800 ] + openImMessageCmsPort: [ 10900 ] + openImAdminCmsPort: [ 11000 ] + openImOfficePort: [ 11100 ] + openImOrganizationPort: [ 11200 ] + c2c: + callbackBeforeSendMsg: + switch: false + timeoutStrategy: 1 #1:send + callbackAfterSendMsg: + switch: false + state: + stateChange: + switch: false + +rpcregistername: #rpc注册服务名,默认即可 + openImUserName: User + openImFriendName: Friend + openImOfflineMessageName: OfflineMessage + openImPushName: Push + openImOnlineMessageRelayName: OnlineMessageRelay + openImGroupName: Group + openImAuthName: Auth + OpenImStatisticsName: Statistics + OpenImMessageCMSName: MessageCMS + openImAdminCMSName: AdminCMS + openImOfficeName: Office + openImOrganizationName: Organization + +log: + storageLocation: ../logs/ + rotationTime: 24 + remainRotationCount: 3 #日志数量 + #日志级别 6表示全都打印,测试阶段建议设置为6 + remainLogLevel: 6 + elasticSearchSwitch: false + elasticSearchAddr: [ 127.0.0.1:9201 ] + elasticSearchUser: "" + elasticSearchPassword: "" + +modulename: #日志文件按模块命名,默认即可 + longConnSvrName: msg_gateway + msgTransferName: msg_transfer + pushName: push + +longconnsvr: + openImWsPort: [ 17778 ] # ws服务端口,默认即可,要开放此端口或做nginx转发 + websocketMaxConnNum: 10000 + websocketMaxMsgLen: 4096 + websocketTimeOut: 10 + +## 推送只能开启一个 enable代表开启 +push: + tpns: #腾讯推送,暂未测试 暂不要使用 + ios: + accessID: 1600018281 + secretKey: 3cd68a77a95b89e5089a1aca523f318f + android: + accessID: 111 + secretKey: 111 + enable: false + jpns: #极光推送 在极光后台申请后,修改以下四项,必须修改 + appKey: cf47465a368f24c659608e7e + masterSecret: 02204efe3f3832947a236ee5 + pushUrl: "https://api.jpush.cn/v3/push" + pushIntent: "intent:#Intent;component=io.openim.app.enterprisechat/io.openim.app.enterprisechat.MainActivity;end" + enable: true + getui: #个推推送,暂未测试 暂不要使用 + pushUrl: "https://restapi.getui.com/v2/$appId" + masterSecret: "" + appKey: "" + intent: "" + enable: false + + + +manager: + #app管理员userID和对应的secret 建议修改。 用于管理后台登录,也可以用户管理后台对应的api + appManagerUid: [ "openIM123456","openIM654321", "openIM333", "openIMAdmin"] + secrets: [ "openIM1","openIM2", "openIM333", "openIMAdmin"] + +secret: tuoyun +# 多端互踢策略 +# 1:多平台登录:Android、iOS、Windows、Mac 每种平台只能一个在线,web端可以多个同时在线 +multiloginpolicy: 1 + +#token config +tokenpolicy: + accessSecret: "open_im_server" #token生成相关,默认即可 + # Token effective time day as a unit + accessExpire: 3650 #token过期时间(天) 默认即可 +messageverify: + friendVerify: false + +# c2c: +# callbackBeforeSendMsg: +# switch: false +# timeoutStrategy: 1 #1:send +# callbackAfterSendMsg: +# switch: false +# state: +# stateChange: +# switch: false +#ios系统推送声音以及标记计数 +iospush: + pushSound: "xxx" + badgeCount: true + +callback: + # callback url 需要自行更换callback url + callbackUrl : "http://127.0.0.1:8080/callback" + # 开启关闭操作前后回调的配置 + callbackbeforeSendSingleMsg: + enable: false # 回调是否启用 + callbackTimeOut: 2 # 回调超时时间 + callbackFailedContinue: true # 回调超时是否继续执行代码 + callbackAfterSendSingleMsg: + enable: false + callbackTimeOut: 2 + callbackBeforeSendGroupMsg: + enable: false + callbackTimeOut: 2 + callbackFailedContinue: true + callbackAfterSendGroupMsg: + enable: false + callbackTimeOut: 2 + callbackWordFilter: + enable: false + callbackTimeOut: 2 + callbackFailedContinue: true + + +notification: + groupCreated: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: true + title: "create group title" # xx create the group + desc: "create group desc" + ext: "create group ext" + defaultTips: + tips: "create the group" # xx create the group + + groupInfoSet: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupInfoSet title" + desc: "groupInfoSet desc" + ext: "groupInfoSet ext" + defaultTips: + tips: "modified the group profile" # group info changed by xx + + joinGroupApplication: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: false + title: "joinGroupApplication title" + desc: "joinGroupApplication desc" + ext: "joinGroupApplication ext" + defaultTips: + tips: "apply to join the group" # group info changed by xx + + memberQuit: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "memberQuit title" + desc: "memberQuit desc" + ext: "memberQuit ext" + defaultTips: + tips: "quit group chat" # group info changed by xx + + groupApplicationAccepted: + conversation: + reliabilityLevel: 2 + unreadCount: true + offlinePush: + switch: false + title: "groupApplicationAccepted title" + desc: "groupApplicationAccepted desc" + ext: "groupApplicationAccepted ext" + defaultTips: + tips: "was allowed to join the group" # group info changed by xx + + groupApplicationRejected: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: false + title: " title" + desc: " desc" + ext: " ext" + defaultTips: + tips: "was rejected into the group" # group info changed by xx + + groupOwnerTransferred: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupOwnerTransferred title" + desc: "groupOwnerTransferred desc" + ext: "groupOwnerTransferred ext" + defaultTips: + tips: "become a new group owner" # group info changed by xx + + memberKicked: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "memberKicked title" + desc: "memberKicked desc" + ext: "memberKicked ext" + defaultTips: + tips: "was kicked out of the group" # group info changed by xx + + memberInvited: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "memberInvited title" + desc: "memberInvited desc" + ext: "memberInvited ext" + defaultTips: + tips: "was invited into the group" # group info changed by xx + + memberEnter: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "memberEnter title" + desc: "memberEnter desc" + ext: "memberEnter ext" + defaultTips: + tips: "entered the group" # group info changed by xx + + groupDismissed: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupDismissed title" + desc: "groupDismissed desc" + ext: "groupDismissed ext" + defaultTips: + tips: "group dismissed" + + + groupMuted: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupMuted title" + desc: "groupMuted desc" + ext: "groupMuted ext" + defaultTips: + tips: "group Muted" + + groupCancelMuted: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupCancelMuted title" + desc: "groupCancelMuted desc" + ext: "groupCancelMuted ext" + defaultTips: + tips: "group Cancel Muted" + + + groupMemberMuted: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupMemberMuted title" + desc: "groupMemberMuted desc" + ext: "groupMemberMuted ext" + defaultTips: + tips: "group Member Muted" + + groupMemberCancelMuted: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: false + title: "groupMemberCancelMuted title" + desc: "groupMemberCancelMuted desc" + ext: "groupMemberCancelMuted ext" + defaultTips: + tips: "group Member Cancel Muted" + #############################friend################################# + + friendApplicationAdded: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "Somebody applies to add you as a friend" + desc: "Somebody applies to add you as a friend" + ext: "Somebody applies to add you as a friend" + defaultTips: + tips: "I applies to add you as a friend" # + + friendApplicationApproved: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "Someone applies to add your friend application" + desc: "Someone applies to add your friend application" + ext: "Someone applies to add your friend application" + defaultTips: + tips: "I applies to add your friend application" # + + + friendApplicationRejected: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "Someone rejected your friend application" + desc: "Someone rejected your friend application" + ext: "Someone rejected your friend application" + defaultTips: + tips: "I rejected your friend application" # + + + + + + friendAdded: + conversation: + reliabilityLevel: 3 + unreadCount: true + offlinePush: + switch: true + title: "We have become friends" + desc: "We have become friends" + ext: "We have become friends" + defaultTips: + tips: "We have become friends" # + + + + friendDeleted: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "deleted a friend" + desc: "deleted a friend" + ext: "deleted a friend" + defaultTips: + tips: "deleted a friend" # + + + friendRemarkSet: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "Your friend's profile has been changed" + desc: "Your friend's profile has been changed" + ext: "Your friend's profile has been changed" + defaultTips: + tips: "Your friend's profile has been changed" # + + + + blackAdded: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "blocked a user" + desc: "blocked a user" + ext: "blocked a user" + defaultTips: + tips: "blocked a user" # + + + blackDeleted: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "Remove a blocked user" + desc: "Remove a blocked user" + ext: "Remove a blocked user" + defaultTips: + tips: "Remove a blocked user" + + #####################user######################### + userInfoUpdated: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "Remove a blocked user" + desc: "Remove a blocked user" + ext: "Remove a blocked user" + defaultTips: + tips: "remove a blocked user" + + #####################conversation######################### + conversationOptUpdate: + conversation: + reliabilityLevel: 2 + unreadCount: false + offlinePush: + switch: true + title: "conversation opt update" + desc: "conversation opt update" + ext: "conversation opt update" + defaultTips: + tips: "conversation opt update" + + conversationSetPrivate: + conversation: + reliabilityLevel: 2 + unreadCount: true + offlinePush: + switch: true + title: "burn after reading" + desc: "burn after reading" + ext: "burn after reading" + defaultTips: + openTips: "burn after reading was opened" + closeTips: "burn after reading was closed" + + + +#---------------demo configuration---------------------# +#The following configuration items are applied to openIM Demo configuration +#是否启动demo,如果自身没有账号体系,设置为true +demoswitch: true +demo: + #demo对外服务端口,默认即可,需要开放此端口或做nginx转发 + openImDemoPort: [ 42233 ] + alismsverify: #阿里云短信配置,在阿里云申请成功后修改以下四项,必须修改 + accessKeyId: LTAI5tJPkn4HuuePdiLdGqe7 + accessKeySecret: 4n9OJ7ZCVN1U6KeHDAtOyNeVZcjOuV + signName: 托云信息技术 + verificationCodeTemplateCode: SMS_226810164 + superCode: 666666 #超级验证码,建议修改掉,收不到短信验证码时可以用此替代 + # second + codeTTL: 300 + mail: #仅支持qq邮箱,具体操作参考 https://service.mail.qq.com/cgi-bin/help?subtype=1&id=28&no=1001256 必须修改 + title: "openIM" + senderMail: "765567899@qq.com" + senderAuthorizationCode: "gxyausfoevlzbfag" + smtpAddr: "smtp.qq.com" + smtpPort: 25 #需开放此端口 出口方向 + +rtc: + port: 11300 + address: 127.0.0.1 \ No newline at end of file diff --git a/deploy.Dockerfile b/deploy.Dockerfile new file mode 100644 index 000000000..1738bda80 --- /dev/null +++ b/deploy.Dockerfile @@ -0,0 +1,39 @@ +FROM golang as build + +# go mod Installation source, container environment variable addition will override the default variable value +ENV GO111MODULE=on +ENV GOPROXY=https://goproxy.cn,direct + +# Set up the working directory +WORKDIR /Open-IM-Server +# add all files to the container +COPY . . + +WORKDIR /Open-IM-Server/script +RUN chmod +x *.sh + +RUN /bin/sh -c ./build_all_service.sh + +#Blank image Multi-Stage Build +FROM ubuntu + +RUN rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install apt-transport-https && apt-get install procps\ +&&apt-get install net-tools +#Non-interactive operation +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get install -y vim curl tzdata gawk +#Time zone adjusted to East eighth District +RUN ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && dpkg-reconfigure -f noninteractive tzdata + + +#set directory to map logs,config file,script file. +VOLUME ["/Open-IM-Server/logs","/Open-IM-Server/config","/Open-IM-Server/script","/Open-IM-Server/db/sdk"] + +#Copy scripts files and binary files to the blank image +COPY --from=build /Open-IM-Server/script /Open-IM-Server/script +COPY --from=build /Open-IM-Server/bin /Open-IM-Server/bin + +WORKDIR /Open-IM-Server/script + +CMD ["./docker_start_all.sh"] diff --git a/deploy/.dockerignore b/deploy/.dockerignore new file mode 100644 index 000000000..019893ce7 --- /dev/null +++ b/deploy/.dockerignore @@ -0,0 +1,6 @@ +# 先设为忽略所有内容 +**/** + + +# 然后逐个排除 +!open_im_* \ No newline at end of file diff --git a/deploy/Makefile b/deploy/Makefile new file mode 100644 index 000000000..8250a06a4 --- /dev/null +++ b/deploy/Makefile @@ -0,0 +1,158 @@ + +GREEN_PREFIX="\033[32m" +COLOR_SUFFIX="\033[0m" +SKY_BLUE_PREFIX="\033[36m" + + +# 编译所有需要的组件源码 +win-build-all: + go env -w GOOS=linux + + make build-api && make build-msg-gateway && make build-msg-transfer && make build-push && make build-timer-task + make build-rpc-user && make build-rpc-friend && make build-rpc-group && make build-rpc-msg && make build-rpc-auth + make build-demo + + go env -w GOOS=windows + +# 编译 open_im_api +build-api: + echo -e ${GREEN_PREFIX} "open_im_api building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_api ../cmd/open_im_api/main.go + echo -e ${GREEN_PREFIX} "open_im_api build ok" ${COLOR_SUFFIX} + +# 编译 open_im_msg_gateway +build-msg-gateway: + echo -e ${GREEN_PREFIX} "open_im_msg_gateway building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_msg_gateway ../cmd/open_im_msg_gateway/main.go + echo -e ${GREEN_PREFIX} "open_im_msg_gateway build ok" ${COLOR_SUFFIX} + +# 编译 open_im_msg_transfer +build-msg-transfer: + echo -e ${GREEN_PREFIX} "open_im_msg_transfer building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_msg_transfer ../cmd/open_im_msg_transfer/main.go + echo -e ${GREEN_PREFIX} "open_im_msg_transfer build ok" ${COLOR_SUFFIX} + +# 编译 open_im_push +build-push: + echo -e ${GREEN_PREFIX} "open_im_push building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_push ../cmd/open_im_push/main.go + echo -e ${GREEN_PREFIX} "open_im_push build ok" ${COLOR_SUFFIX} + +# 编译 open_im_timer_task +build-timer-task: + echo -e ${GREEN_PREFIX} "open_im_timer_task building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_timer_task ../cmd/open_im_timer_task/main.go + echo -e ${GREEN_PREFIX} "open_im_timer_task build ok" ${COLOR_SUFFIX} + +# 编译 build-rpc-user +build-rpc-user: + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_user building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_rpc_user ../cmd/rpc/open_im_user/main.go + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_user build ok" ${COLOR_SUFFIX} + +# 编译 build-rpc-friend +build-rpc-friend: + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_friend building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_rpc_friend ../cmd/rpc/open_im_friend/main.go + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_friend build ok" ${COLOR_SUFFIX} + +# 编译 build-rpc-group +build-rpc-group: + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_group building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_rpc_group ../cmd/rpc/open_im_group/main.go + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_group build ok" ${COLOR_SUFFIX} + +# 编译 build-rpc-auth +build-rpc-auth: + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_auth building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_rpc_auth ../cmd/rpc/open_im_auth/main.go + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_auth build ok" ${COLOR_SUFFIX} + +# 编译 build-rpc-msg +build-rpc-msg: + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_msg building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_rpc_msg ../cmd/rpc/open_im_msg/main.go + echo -e ${SKY_BLUE_PREFIX} "open_im_rpc_msg build ok" ${COLOR_SUFFIX} + +# 编译 open_im_demo +build-demo: + echo -e ${SKY_BLUE_PREFIX} "open_im_demo building..." ${COLOR_SUFFIX} + go build -ldflags="-w -s" -o open_im_demo ../cmd/open_im_demo/main.go + echo -e ${SKY_BLUE_PREFIX} "open_im_demo build ok" ${COLOR_SUFFIX} + +# 打包所有组件为镜像 +image-all: + make image-api && make image-msg-gateway && make image-msg-transfer & make image-push && make image-timer-task + make image-rpc-user && make image-rpc-friend && make image-rpc-group && make image-rpc-msg && make image-rpc-auth + make image-demo + +# 打包 open_im_api +image-api: + echo -e ${GREEN_PREFIX} "IMAGE:openim/api building..." ${COLOR_SUFFIX} + docker build -t openim/api:latest -f ./dockerfiles/Dockerfile.api . + echo -e ${GREEN_PREFIX} "IMAGE:openim/api build ok" ${COLOR_SUFFIX} + +# 打包 open_im_msg_gateway +image-msg-gateway: + echo -e ${GREEN_PREFIX} "IMAGE:openim/msg_gateway building..." ${COLOR_SUFFIX} + docker build -t openim/msg_gateway:latest -f ./dockerfiles/Dockerfile.msg_gateway . + echo -e ${GREEN_PREFIX} "IMAGE:openim/msg_gateway build ok" ${COLOR_SUFFIX} + +# 打包 open_im_msg_transfer +image-msg-transfer: + echo -e ${GREEN_PREFIX} "IMAGE:openim/msg_transfer building..." ${COLOR_SUFFIX} + docker build -t openim/msg_transfer:latest -f ./dockerfiles/Dockerfile.msg_transfer . + echo -e ${GREEN_PREFIX} "IMAGE:openim/msg_transfer build ok" ${COLOR_SUFFIX} + +# 打包 open_im_push +image-push: + echo -e ${GREEN_PREFIX} "IMAGE:openim/push building..." ${COLOR_SUFFIX} + docker build -t openim/push:latest -f ./dockerfiles/Dockerfile.push . + echo -e ${GREEN_PREFIX} "IMAGE:openim/push build ok" ${COLOR_SUFFIX} + +# 打包 open_im_timer_task +image-timer-task: + echo -e ${GREEN_PREFIX} "IMAGE:openim/timer_task building..." ${COLOR_SUFFIX} + docker build -t openim/timer_task:latest -f ./dockerfiles/Dockerfile.timer_task . + echo -e ${GREEN_PREFIX} "IMAGE:openim/timer_task build ok" ${COLOR_SUFFIX} + +# 打包 build-rpc-user +image-rpc-user: + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_user building..." ${COLOR_SUFFIX} + docker build -t openim/rpc_user:latest -f ./dockerfiles/Dockerfile.rpc_user . + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_user build ok" ${COLOR_SUFFIX} + +# 打包 build-rpc-friend +image-rpc-friend: + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_friend building..." ${COLOR_SUFFIX} + docker build -t openim/rpc_friend:latest -f ./dockerfiles/Dockerfile.rpc_friend . + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_friend build ok" ${COLOR_SUFFIX} + +# 打包 build-rpc-group +image-rpc-group: + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_group building..." ${COLOR_SUFFIX} + docker build -t openim/rpc_group:latest -f ./dockerfiles/Dockerfile.rpc_group . + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_group build ok" ${COLOR_SUFFIX} + +# 打包 build-rpc-auth +image-rpc-auth: + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_auth building..." ${COLOR_SUFFIX} + docker build -t openim/rpc_auth:latest -f ./dockerfiles/Dockerfile.rpc_auth . + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_auth build ok" ${COLOR_SUFFIX} + +# 打包 build-rpc-msg +image-rpc-msg: + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_msg building..." ${COLOR_SUFFIX} + docker build -t openim/rpc_msg:latest -f ./dockerfiles/Dockerfile.rpc_msg . + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/rpc_msg build ok" ${COLOR_SUFFIX} + +# 打包 open_im_demo +image-demo: + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/demo building..." ${COLOR_SUFFIX} + docker build -t openim/demo:latest -f ./dockerfiles/Dockerfile.demo . + echo -e ${SKY_BLUE_PREFIX} "IMAGE:openim/demo build ok" ${COLOR_SUFFIX} + +.PHONY: win-build-all build-api build-msg-gateway build-msg-transfer build-push + build-timer-task build-rpc-user build-rpc-friend build-rpc-group build-rpc-msg build-demo + image-all image-api image-msg-gateway image-msg-transfer image-push + image-timer-task image-rpc-user image-rpc-friend image-rpc-group image-rpc-msg image-demo diff --git a/deploy/config.example.yaml b/deploy/config.example.yaml new file mode 100644 index 000000000..08d8858e4 --- /dev/null +++ b/deploy/config.example.yaml @@ -0,0 +1,183 @@ +# The class cannot be named by Pascal or camel case. +# If it is not used, the corresponding structure will not be set, +# and it will not be read naturally. +serverversion: 1.0.3 +#---------------Infrastructure configuration---------------------# +etcd: + etcdSchema: openIM + etcdAddr: [ openim_etcd:2379 ] + +mysql: + dbMysqlAddress: [ openim_mysql:3306 ] # openim_mysql 是对应的mysql服务的host + dbMysqlUserName: openIM + dbMysqlPassword: openIM + dbMysqlDatabaseName: openIM + dbTableName: eMsg + dbMsgTableNum: 1 + dbMaxOpenConns: 20 + dbMaxIdleConns: 10 + dbMaxLifeTime: 120 + +mongo: + dbUri: ""#当dbUri值不为空则直接使用该值 + dbAddress: [ openim_mongo:27017 ] + dbDirect: false + dbTimeout: 10 + dbDatabase: openIM + dbSource: admin + dbUserName: + dbPassword: + dbMaxPoolSize: 20 + dbRetainChatRecords: 7 + +redis: + dbAddress: openim_redis:6379 + dbMaxIdle: 128 + dbMaxActive: 0 + dbIdleTimeout: 120 + dbPassWord: openIM + +kafka: + ws2mschat: + addr: [ openim_kafka:9092 ] + topic: "ws2ms_chat" + ms2pschat: + addr: [ openim_kafka:9092 ] + topic: "ms2ps_chat" + consumergroupid: + msgToMongo: mongo + msgToMySql: mysql + msgToPush: push + + + +#---------------Internal service configuration---------------------# + +# The service ip default is empty, +# automatically obtain the machine's valid network card ip as the service ip, +# otherwise the configuration ip is preferred +serverip: 0.0.0.0 + +# endpoints 内部组件间访问的端点host名称,访问时,可以内部直接访问 host:port 来访问 +# 新增的这一段配置节,主要是位了注册到etcd时,可以使用同一network下的容器名(host)来访问不同的容器,拆分到不同容器后原来全部使用serverip的形式不能用了 +endpoints: + api: openim_api + push: openim_push + msg_gateway: openim_msg_gateway + rpc_auth: openim_rpc_auth + rpc_friend: openim_rpc_friend + rpc_group: openim_rpc_group + rpc_msg: openim_rpc_msg + rpc_user: openim_rpc_user + +api: + openImApiPort: [ 10000 ] +sdk: + openImSdkWsPort: [ 30000 ] +cmsapi: + openImCmsApiPort: [ 8000 ] + +credential: + tencent: + appID: 1302656840 + region: ap-chengdu + bucket: echat-1302656840 + secretID: AKIDGNYVChzIQinu7QEgtNp0hnNgqcV8vZTC + secretKey: kz15vW83qM6dBUWIq681eBZA0c0vlIbe + + +rpcport: + openImUserPort: [ 10100 ] + openImFriendPort: [ 10200 ] + openImOfflineMessagePort: [ 10300] + openImOnlineRelayPort: [ 10400 ] + openImGroupPort: [ 10500 ] + openImAuthPort: [ 10600 ] + openImPushPort: [ 10700 ] + openImStatisticsPort: [ 10800 ] + openImMessageCmsPort: [ 10900 ] + openImAdminCmsPort: [ 11000 ] + +rpcregistername: + openImUserName: User + openImFriendName: Friend + openImOfflineMessageName: OfflineMessage + openImPushName: Push + openImOnlineMessageRelayName: OnlineMessageRelay + openImGroupName: Group + openImAuthName: Auth + +log: + storageLocation: ../logs/ + rotationTime: 24 + remainRotationCount: 5 + remainLogLevel: 6 + elasticSearchSwitch: false + elasticSearchAddr: [ 127.0.0.1:9201 ] + elasticSearchUser: "" + elasticSearchPassword: "" + +modulename: + longConnSvrName: msg_gateway + msgTransferName: msg_transfer + pushName: push + +longconnsvr: + openImWsPort: [ 17778 ] + websocketMaxConnNum: 10000 + websocketMaxMsgLen: 4096 + websocketTimeOut: 10 + +push: + tpns: + ios: + accessID: 1600018281 + secretKey: 3cd68a77a95b89e5089a1aca523f318f + android: + accessID: 111 + secretKey: 111 + jpns: + appKey: cf47465a368f24c659608e7e + masterSecret: 02204efe3f3832947a236ee5 + pushUrl: "https://api.jpush.cn/v3/push" + pushIntent: "intent:#Intent;component=io.openim.app.enterprisechat/io.openim.app.enterprisechat.MainActivity;end" +manager: + appManagerUid: ["openIM123456","openIM654321"] + secrets: ["openIM1","openIM2"] + +secret: tuoyun + +multiloginpolicy: 1 + +#token config +tokenpolicy: + accessSecret: "open_im_server" + # Token effective time day as a unit + accessExpire: 7 + +messagecallback: + callbackSwitch: false + callbackUrl: "http://www.xxx.com/msg/judge" + #TimeOut use second as unit + callbackTimeOut: 10 + + +#---------------demo configuration---------------------# +#The following configuration items are applied to openIM Demo configuration +demoswitch: true +demo: + openImDemoPort: [ 42233 ] + alismsverify: + accessKeyId: LTAI5tJPkn4HuuePdiLdGqe71 + accessKeySecret: 4n9OJ7ZCVN1U6KeHDAtOyNeVZcjOuV1 + signName: OpenIM Corporation + verificationCodeTemplateCode: SMS_2268101641 + superCode: 666666 + mail: + title: "openIM" + senderMail: "1765567899@qq.com" + senderAuthorizationCode: "1gxyausfoevlzbfag" + smtpAddr: "smtp.qq.com" + smtpPort: 25 + + diff --git a/deploy/dockerfiles/Dockerfile.api b/deploy/dockerfiles/Dockerfile.api new file mode 100644 index 000000000..9c70d735d --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.api @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_api $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.demo b/deploy/dockerfiles/Dockerfile.demo new file mode 100644 index 000000000..ac77ad8d3 --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.demo @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_demo $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.msg_gateway b/deploy/dockerfiles/Dockerfile.msg_gateway new file mode 100644 index 000000000..ffd012bc4 --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.msg_gateway @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_msg_gateway $WORKDIR/main + +# 创建用于挂载的几个目录,重命名可执行文件为 main,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.msg_transfer b/deploy/dockerfiles/Dockerfile.msg_transfer new file mode 100644 index 000000000..a82c4da8b --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.msg_transfer @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_msg_transfer $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.push b/deploy/dockerfiles/Dockerfile.push new file mode 100644 index 000000000..b929dd82c --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.push @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_push $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.rpc_auth b/deploy/dockerfiles/Dockerfile.rpc_auth new file mode 100644 index 000000000..a8e50fdb1 --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.rpc_auth @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_rpc_auth $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.rpc_friend b/deploy/dockerfiles/Dockerfile.rpc_friend new file mode 100644 index 000000000..cfa2fe18c --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.rpc_friend @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_rpc_friend $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.rpc_group b/deploy/dockerfiles/Dockerfile.rpc_group new file mode 100644 index 000000000..d56a0fefe --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.rpc_group @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_rpc_group $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.rpc_msg b/deploy/dockerfiles/Dockerfile.rpc_msg new file mode 100644 index 000000000..01b5de02f --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.rpc_msg @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_rpc_msg $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.rpc_user b/deploy/dockerfiles/Dockerfile.rpc_user new file mode 100644 index 000000000..5be6298bd --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.rpc_user @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_rpc_user $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/dockerfiles/Dockerfile.timer_task b/deploy/dockerfiles/Dockerfile.timer_task new file mode 100644 index 000000000..0c2222cfb --- /dev/null +++ b/deploy/dockerfiles/Dockerfile.timer_task @@ -0,0 +1,16 @@ +FROM alpine:3.13 + +# 设置固定的项目路径 +ENV WORKDIR /app +ENV CONFIG_NAME $WORKDIR/config/config.yaml + +# 将可执行文件复制到目标目录 +ADD ./open_im_timer_task $WORKDIR/main + +# 创建用于挂载的几个目录,添加可执行权限 +RUN mkdir $WORKDIR/logs $WORKDIR/config $WORKDIR/db && \ + chmod +x $WORKDIR/main + + +WORKDIR $WORKDIR +CMD ./main \ No newline at end of file diff --git a/deploy/env.yaml b/deploy/env.yaml new file mode 100644 index 000000000..423807e4f --- /dev/null +++ b/deploy/env.yaml @@ -0,0 +1,101 @@ +version: "3.7" +networks: + openim: + external: true + +services: + mysql: + networks: + - openim + image: mysql:5.7 + # ports: + # #- 13306:3306 + # - 23306:33060 + container_name: openim_mysql + volumes: + - ./components/mysql/data:/var/lib/mysql + - /etc/localtime:/etc/localtime + environment: + MYSQL_ROOT_PASSWORD: openIM + restart: always + + mongodb: + networks: + - openim + image: mongo:4.4.5-bionic + # ports: + # - 37017:27017 + container_name: openim_mongo + volumes: + - ./components/mongodb/data/db:/data/db + - ./components/mongodb/data/logs:/data/logs + - ./components/mongodb/data/conf:/etc/mongo + environment: + TZ: Asia/Shanghai + # - MONGO_INITDB_ROOT_USERNAME=openIM + # - MONGO_INITDB_ROOT_PASSWORD=openIM + restart: always + + redis: + networks: + - openim + image: redis:6.2.4-alpine + # ports: + # - 16379:6379 + container_name: openim_redis + volumes: + - ./components/redis/data:/data + #redis config file + #- ./components/redis/config/redis.conf:/usr/local/redis/config/redis.conf + environment: + TZ: Asia/Shanghai + restart: always + sysctls: + net.core.somaxconn: 1024 + command: redis-server --requirepass openIM --appendonly yes + + + zookeeper: + networks: + - openim + image: wurstmeister/zookeeper + # ports: + # - 2181:2181 + container_name: openim_zookeeper + volumes: + - /etc/localtime:/etc/localtime + environment: + TZ: Asia/Shanghai + restart: always + + kafka: + networks: + - openim + image: wurstmeister/kafka + container_name: openim_kafka + restart: always + environment: + TZ: Asia/Shanghai + KAFKA_BROKER_ID: 0 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 + KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092 + depends_on: + - zookeeper + + etcd: + networks: + - openim + image: quay.io/coreos/etcd + # ports: + # - 2379:2379 + # - 2380:2380 + container_name: openim_etcd + volumes: + - /etc/timezone:/etc/timezone + - /etc/localtime:/etc/localtime + environment: + ETCDCTL_API: 3 + restart: always + command: /usr/local/bin/etcd --name etcd0 --data-dir /etcd-data --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://0.0.0.0:2380 --initial-cluster etcd0=http://0.0.0.0:2380 --initial-cluster-token tkn --initial-cluster-state new + diff --git a/deploy/openim.yaml b/deploy/openim.yaml new file mode 100644 index 000000000..350729399 --- /dev/null +++ b/deploy/openim.yaml @@ -0,0 +1,223 @@ +version: "3.7" +networks: + openim: + external: true + +services: + api: + networks: + - openim + image: openim/api + container_name: openim_api + ports: + - 10000:10000 # API,必须开 + volumes: + - ./logs:/app/logs + # Dockerfile 里定义了配置文件的路径环境变量,CONFIG_NAME,默认指向了 /app/config/config.yaml + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" + + msg_gateway: + networks: + - openim + image: openim/msg_gateway + container_name: openim_msg_gateway + ports: + - 17778:17778 # 消息,必须开 + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" + + msg_transfer: + networks: + - openim + image: openim/msg_transfer + container_name: openim_msg_transfer + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" + + push: + networks: + - openim + image: openim/push + container_name: openim_push + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" + + timer_task: + networks: + - openim + image: openim/timer_task + container_name: openim_timer_task + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" + + rpc_user: + networks: + - openim + image: openim/rpc_user + container_name: openim_rpc_user + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" + + rpc_friend: + networks: + - openim + image: openim/rpc_friend + container_name: openim_rpc_friend + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + + rpc_group: + networks: + - openim + image: openim/rpc_group + container_name: openim_rpc_group + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + + rpc_auth: + networks: + - openim + image: openim/rpc_auth + container_name: openim_rpc_auth + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + + rpc_msg: + networks: + - openim + image: openim/rpc_msg + container_name: openim_rpc_msg + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always + # depends_on: + # - kafka + # # - mysql + # # - mongodb + # - redis + # - etcd + + demo: + networks: + - openim + image: openim/demo + container_name: openim_demo + ports: + - 42233:42233 + volumes: + - ./logs:/app/logs + - ./config/config.yaml:/app/config/config.yaml + - ./db/sdk:/app/db/sdk + restart: always \ No newline at end of file diff --git a/deploy/readme.md b/deploy/readme.md new file mode 100644 index 000000000..61fbd9700 --- /dev/null +++ b/deploy/readme.md @@ -0,0 +1,30 @@ + +### 以docker-compose 形式单独部署 +```sh +# 查看 ./Makefile ,先编译各个需要的源码到 ../bin +# win-* 表示在win平台编译位linux二进制,其实就是处理了 go env -w GOOS=linux +make win-build-all + +# 得到各个二进制程序之后,打包为镜像 +# 目前没有处理 Open-IM-SDK-Core ,需要的话可以自己单独处理这个模块 +make image-all + +# docker-compose.yaml 分成了两部分,一部分是openIM的镜像容器 openim.yaml,一部分是依赖的环境 env.yaml +# 两部分使用一个外部的网络来联通,所以首先创建用到的 network +docker network create openim --attachable=true -d bridge + +# 处理openim组件需要的挂载目录,主要是处理config目录 +mkdir ./config +cp ./config.example.yaml ./config/config.yaml # 修改 ./config/config.yaml 内容,比如各个依赖组件的 host + +# 然后拉起env.yaml +docker-compose -f ./env.yaml up -d + +# 等env 容器全部拉起成功之后,拉起openim.yaml +docker-compose -f ./openim.yaml up -d + +# 查看容器运行,推荐使用下 portainer ,web查看容器情况,查看日志等等 +docker container ps -a | grep openim + +# 正常应该是查看api,demo等的容器日志,看到gin打印的路由日志才算是成功 +``` \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..c67203773 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,116 @@ +version: "3" +#fixme Clone openIM Server project before using docker-compose,project address:https://github.com/OpenIMSDK/Open-IM-Server.git + +services: + mysql: + image: mysql:5.7 + ports: + - 13306:3306 + - 23306:33060 + container_name: mysql + volumes: + - ./components/mysql/data:/var/lib/mysql + - /etc/localtime:/etc/localtime + environment: + MYSQL_ROOT_PASSWORD: openIM + restart: always + + mongodb: + image: mongo:4.0 + ports: + - 37017:27017 + container_name: mongo + volumes: + - ./components/mongodb/data/db:/data/db + - ./components/mongodb/data/logs:/data/logs + - ./components/mongodb/data/conf:/etc/mongo + environment: + - TZ=Asia/Shanghai + # cache + - wiredTigerCacheSizeGB=1 +# environment: +# - MONGO_INITDB_ROOT_USERNAME=openIM +# - MONGO_INITDB_ROOT_PASSWORD=openIM + + + #TZ: Asia/Shanghai + restart: always + + redis: + image: redis + ports: + - 16379:6379 + container_name: redis + volumes: + - ./components/redis/data:/data + #redis config file + #- ./components/redis/config/redis.conf:/usr/local/redis/config/redis.conf + environment: + TZ: Asia/Shanghai + restart: always + sysctls: + net.core.somaxconn: 1024 + command: redis-server --requirepass openIM --appendonly yes + + + zookeeper: + image: wurstmeister/zookeeper + ports: + - 2181:2181 + container_name: zookeeper + volumes: + - /etc/localtime:/etc/localtime + environment: + TZ: Asia/Shanghai + restart: always + + + kafka: + image: wurstmeister/kafka + container_name: kafka + restart: always + environment: + TZ: Asia/Shanghai + KAFKA_BROKER_ID: 0 + KAFKA_ZOOKEEPER_CONNECT: 127.0.0.1:2181 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092 + KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092 + network_mode: "host" + depends_on: + - zookeeper + + etcd: + image: quay.io/coreos/etcd + ports: + - 2379:2379 + - 2380:2380 + container_name: etcd + volumes: + - /etc/timezone:/etc/timezone + - /etc/localtime:/etc/localtime + environment: + ETCDCTL_API: 3 + restart: always + command: /usr/local/bin/etcd --name etcd0 --data-dir /etcd-data --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://0.0.0.0:2380 --initial-cluster etcd0=http://0.0.0.0:2380 --initial-cluster-token tkn --initial-cluster-state new + + open_im_server: + image: openim/open_im_server:v2.0.5 + container_name: open_im_server + volumes: + - ./logs:/Open-IM-Server/logs + - ./config/config.yaml:/Open-IM-Server/config/config.yaml + - ./db/sdk:/Open-IM-Server/db/sdk + - ./script:/Open-IM-Server/script + restart: always + depends_on: + - kafka + - mysql + - mongodb + - redis + - etcd + network_mode: "host" + logging: + driver: json-file + options: + max-size: "1g" + max-file: "2" diff --git a/docs/Architecture.jpg b/docs/Architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..138a72472b2c599624085a7c5e19d96dea39bf84 GIT binary patch literal 212410 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±ZK9h-=<qve-qXmH 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ξmXy` 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 literal 0 HcmV?d00001 diff --git a/docs/Open-IM-Servers-on-System.png b/docs/Open-IM-Servers-on-System.png new file mode 100644 index 0000000000000000000000000000000000000000..3c8a1020214a2cfcb9e5cc6c5beb339b7e2be67d GIT binary patch literal 21614 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 Z7iVs2wPSi}fqg{rG*ony3lwkr{y(Ud)0qGO literal 0 HcmV?d00001 diff --git a/docs/Open-IM-Servers-on-docker.png b/docs/Open-IM-Servers-on-docker.png new file mode 100644 index 0000000000000000000000000000000000000000..c66f7fb095e862e64eaab2a9dbc1ac1c3c73977b GIT binary patch literal 10172 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 literal 0 HcmV?d00001 diff --git a/docs/Open-IM.png b/docs/Open-IM.png new file mode 100644 index 0000000000000000000000000000000000000000..b617065505626ea5df9467ca5e945f851258aee6 GIT binary patch literal 17614 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 YUw`QzX|_9nXOJ*>y85}Sb4q9e07i?OPXGV_ literal 0 HcmV?d00001 diff --git a/docs/Wechat.jpg b/docs/Wechat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d3caf1a444fd9e312f77228d2f6c0651b287f212 GIT binary patch literal 212904 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⪼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 F{{Uj##+?8F literal 0 HcmV?d00001 diff --git a/docs/open-im-logo.png b/docs/open-im-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb6a6700d4c29fdc7448a7e4fe8cdbd6cc56b20 GIT binary patch literal 245627 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%0A#bI{D)nby7N&zmeI#Vf0k)BGnZ!YgN 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%0Dn+<R$yQz$S<=Z0q4qY?9Zt9$3|!98DGC6~k)PX( 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�s3m|_Q9@OzCp`D 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 M_4cLhIeGE_0j;yd_W%F@ literal 0 HcmV?d00001 diff --git a/docs/open-im-server.png b/docs/open-im-server.png new file mode 100644 index 0000000000000000000000000000000000000000..35df36f395c894870d9a89dbdcc1fc1ccfdd1b1a GIT binary patch literal 109213 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 TpKY2Ufqx1zs*qAC(>MPQj_s*} literal 0 HcmV?d00001 diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..f005f9ce0 --- /dev/null +++ b/go.mod @@ -0,0 +1,69 @@ +module Open_IM + +go 1.15 + +require ( + github.com/Shopify/sarama v1.19.0 + github.com/Shopify/toxiproxy v2.1.4+incompatible // indirect + github.com/alibabacloud-go/darabonba-openapi v0.1.11 + github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.8 + github.com/alibabacloud-go/sts-20150401 v1.1.0 + github.com/alibabacloud-go/tea v1.1.17 + github.com/antonfisher/nested-logrus-formatter v1.3.0 + github.com/bwmarrin/snowflake v0.3.0 + github.com/coreos/etcd v3.3.27+incompatible // indirect + github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/eapache/go-resiliency v1.2.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/fatih/structs v1.1.0 + github.com/frankban/quicktest v1.14.0 // indirect + github.com/garyburd/redigo v1.6.2 + github.com/gin-gonic/gin v1.7.0 + github.com/go-playground/validator/v10 v10.4.1 + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/gogo/protobuf v1.3.2 + github.com/golang-jwt/jwt/v4 v4.1.0 + github.com/golang/protobuf v1.5.2 + github.com/golang/snappy v0.0.4 // indirect + github.com/gorilla/websocket v1.4.2 + github.com/jinzhu/copier v0.3.4 + github.com/jinzhu/gorm v1.9.16 + github.com/jinzhu/now v1.1.3 // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/lestrrat-go/strftime v1.0.4 // indirect + github.com/lib/pq v1.2.0 // indirect + //github.com/livekit/protocol v0.11.14-0.20220223195254-d8c251e13231 // indirect + //github.com/livekit/server-sdk-go v0.9.1 + github.com/mattn/go-sqlite3 v1.14.6 // indirect + github.com/minio/minio-go/v7 v7.0.22 + github.com/mitchellh/mapstructure v1.4.2 + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 + github.com/olivere/elastic/v7 v7.0.23 + github.com/pierrec/lz4 v2.6.1+incompatible // indirect + github.com/pkg/errors v0.9.1 + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 + github.com/sirupsen/logrus v1.8.1 + github.com/spf13/viper v1.9.0 + github.com/stretchr/testify v1.7.0 + github.com/tencentyun/qcloud-cos-sts-sdk v0.0.0-20210325043845-84a0811633ca + github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect + //go.etcd.io/etcd v3.3.27+incompatible + go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 + go.mongodb.org/mongo-driver v1.8.3 + golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd + google.golang.org/grpc v1.42.0 + google.golang.org/grpc/examples v0.0.0-20220311002955-722367c4a737 // indirect + google.golang.org/protobuf v1.27.1 + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b + sigs.k8s.io/yaml v1.2.0 // indirect +) + +replace google.golang.org/grpc => google.golang.org/grpc v1.29.0 diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..cec54f0ff --- /dev/null +++ b/go.sum @@ -0,0 +1,1138 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alibabacloud-go/darabonba-openapi v0.1.7/go.mod h1:6FV1Bt1AItYIlC2rVopPTumrRNtkfPBmrPVAZ8v2bLk= +github.com/alibabacloud-go/darabonba-openapi v0.1.11 h1:w59gtSA0s87p0U5NNG/N/PIHsRP3rtj7qCP9hx9+GL8= +github.com/alibabacloud-go/darabonba-openapi v0.1.11/go.mod h1:MPJMxv7HYrFm5m9uOZWkDYsAWyZztEgnBRfk9Fg0eIU= +github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.8 h1:KXMiCg99Jx7B6V+DlRFbWwL9UCGippE5z1wGzhyimiA= +github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.8/go.mod h1:8aL6tSyQIWJygF7W/Vqxdf/QDbN2S+u57k36bEA8hD8= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.8/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.0.9 h1:Z0DP4LFzkM/rW2nxOMiiLoQVZSeE3jVc5jrZ9Fd/UX0= +github.com/alibabacloud-go/openapi-util v0.0.9/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/sts-20150401 v1.1.0 h1:1yVyKz02ES6aKo3xVjmoPLBH1OAmmSqPkhKRdjEkmYs= +github.com/alibabacloud-go/sts-20150401 v1.1.0/go.mod h1:QW4O/c7Hp4krHYt+6xwnoG8EyZW3V9GYkl6EgIBmxJc= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.15/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.17 h1:05R5DnaJXe9sCNIe8KUgWHC/z6w/VZIwczgUwzRnul8= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.3.9 h1:TtbzxS+BXrisA7wzbAMRtlU8A2eWLg0ufm7m/Tl6fc4= +github.com/alibabacloud-go/tea-utils v1.3.9/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antonfisher/nested-logrus-formatter v1.3.0 h1:8zixYquU1Odk+vzAaAQPAdRh1ZjmUXNQ1T+dUBvlhVo= +github.com/antonfisher/nested-logrus-formatter v1.3.0/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.38.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bep/debounce v1.2.0 h1:wXds8Kq8qRfwAOpAxHrJDbCXgC5aHSzgQb/0gKsHQqo= +github.com/bep/debounce v1.2.0/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/coreos/etcd v0.5.0-alpha.5 h1:0Qi6Jzjk2CDuuGlIeecpu+em2nrjhOgz2wsIwCmQHmc= +github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA= +github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= +github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM= +github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= +github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.0.0-rc1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.1.0 h1:nAbevmWlS2Ic4m4+/An5NXkaGqlqpbBgdcuThZxnZyI= +github.com/go-logr/logr v1.1.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.0.0 h1:y5pcs7gk8uL+w55/cmuTqhhg5Vjsn8NhlZgr8atE60c= +github.com/go-logr/stdr v1.0.0/go.mod h1:ALK2+RP34e8Kg4N/jgsMDWyZb/T282UsFmhyUqyzpmc= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCxgt8= +github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= +github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI= +github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= +github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= +github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jxskiss/base62 v0.0.0-20191017122030-4f11678b909b h1:XUr8tvMEILhphQPp3TFcIudb5KTOzFeD0pJyDn5+5QI= +github.com/jxskiss/base62 v0.0.0-20191017122030-4f11678b909b/go.mod h1:a5Mn24iYVJRUQSkFupGByqykzD+k+wFI8J91zGHuPf8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= +github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.4 h1:T1Rb9EPkAhgxKqbcMIPguPq8glqXTA1koF8n9BHElA8= +github.com/lestrrat-go/strftime v1.0.4/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lithammer/shortuuid/v3 v3.0.6 h1:pr15YQyvhiSX/qPxncFtqk+v4xLEpOZObbsY/mKrcvA= +github.com/lithammer/shortuuid/v3 v3.0.6/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts= +github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8= +github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts= +github.com/livekit/protocol v0.11.13 h1:5iWXKTeFMfERpE/0ocoLUOQtPV1BKwas151nZm0YVt0= +github.com/livekit/protocol v0.11.13/go.mod h1:YoHW9YbWbPnuVsgwBB4hAINKT+V68jmfh9zXBSSn6Wg= +github.com/livekit/protocol v0.11.14-0.20220223195254-d8c251e13231 h1:2bSLRW/t4sosQkqoxI9b6PN296FBw4Xiy9cT9tZPi3w= +github.com/livekit/protocol v0.11.14-0.20220223195254-d8c251e13231/go.mod h1:3pHsWUtQmWaH8mG0cXrQWpbf3Vo+kj0U+In77CEXu90= +github.com/livekit/server-sdk-go v0.9.1 h1:AhshcG4o1Domyo0rfB5lYKnczOZT5nOQQPIkG9jFfE0= +github.com/livekit/server-sdk-go v0.9.1/go.mod h1:I31XJ1SmfUW7DFX3sltpVf9GwvuTO0jr05zscP1nrwA= +github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0/go.mod h1:fcEyUyXZXoV4Abw8DX0t7wyL8mCDxXyU4iAFZfT3IHw= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= +github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= +github.com/minio/minio-go/v7 v7.0.22 h1:iXhsiRyYh1ozm/+jN2qGgEIahYjEkvcpuu6NcdpSxcA= +github.com/minio/minio-go/v7 v7.0.22/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2DAn1ou4+Do= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olivere/elastic/v7 v7.0.23 h1:b7tjMogDMhf2CisGI+L02LXLVa0ZyE82Z15XfW1e8t8= +github.com/olivere/elastic/v7 v7.0.23/go.mod h1:OuWmD2DiuYhddWegBKPWQuelVKBLrW0fa/VUYgxuGTY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E= +github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ= +github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus= +github.com/pion/dtls/v2 v2.1.3 h1:3UF7udADqous+M2R5Uo2q/YaP4EzUoWKdfX2oscCUio= +github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus= +github.com/pion/ice/v2 v2.2.1 h1:R3MeuJZpU1ty3diPqpD5OxaxcZ15eprAc+EtUiSoFxg= +github.com/pion/ice/v2 v2.2.1/go.mod h1:Op8jlPtjeiycsXh93Cs4jK82C9j/kh7vef6ztIOvtIQ= +github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U= +github.com/pion/interceptor v0.1.8 h1:5K27KMw8enTB1jVDFrjadK8sZjI5JbPJ91OVfiih5fE= +github.com/pion/interceptor v0.1.8/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw= +github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0= +github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U= +github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo= +github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= +github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA= +github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= +github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= +github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA= +github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= +github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8= +github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk= +github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ= +github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A= +github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= +github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= +github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= +github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= +github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY= +github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g= +github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw= +github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw= +github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o= +github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= +github.com/pion/webrtc/v3 v3.1.25-0.20220225075517-37e16a3b15a3 h1:TzOKzLajJt/Le720iy7bFry5HBBLWB3v6n9jEO4WJDs= +github.com/pion/webrtc/v3 v3.1.25-0.20220225075517-37e16a3b15a3/go.mod h1:mO/yv7fBN3Lp7YNlnYcTj1jtpvNvssJG+7eh6itZ4xM= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.4.2/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk= +github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tencentyun/qcloud-cos-sts-sdk v0.0.0-20210325043845-84a0811633ca h1:G/aIr3WiUesWHL2YGYgEqjM5tCAJ43Ml+0C18wDkWWs= +github.com/tencentyun/qcloud-cos-sts-sdk v0.0.0-20210325043845-84a0811633ca/go.mod h1:b18KQa4IxHbxeseW1GcZox53d7J0z39VNONTxvvlkXw= +github.com/thoas/go-funk v0.9.0 h1:Yzu8aTjTb1sqHZzSZLBt4qaZrFfjNizhA7IfnefjEzo= +github.com/thoas/go-funk v0.9.0/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/twitchtv/twirp v8.1.0+incompatible h1:KGXanpa9LXdVE/V5P/tA27rkKFmXRGCtSNT7zdeeVOY= +github.com/twitchtv/twirp v8.1.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 h1:jWtjCJX1qxhHISBMLRztWwR+EXkI7MJAF2HjHAE/x/I= +go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698/go.mod h1:YoUyTScD3Vcv2RBm3eGVOq7i1ULiz3OuXoQFWOirmAM= +go.etcd.io/etcd v0.5.0-alpha.5 h1:VOolFSo3XgsmnYDLozjvZ6JL6AAwIDu1Yx1y+4EYLDo= +go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0= +go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4= +go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/grpc v1.29.0 h1:2pJjwYOdkZ9HlN4sWRYBg9ttH5bCOlsueaM+b/oYjwo= +google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/examples v0.0.0-20220311002955-722367c4a737 h1:rLsBNkV6Gc/K6J87wfvo/BSg/TQGd28++7sS+hs8qDw= +google.golang.org/grpc/examples v0.0.0-20220311002955-722367c4a737/go.mod h1:wKDg0brwMZpaizQ1i7IzYcJjH1TmbJudYdnQC9+J+LE= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c= +gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/internal/api/auth/auth.go b/internal/api/auth/auth.go new file mode 100644 index 000000000..fed744d4f --- /dev/null +++ b/internal/api/auth/auth.go @@ -0,0 +1,91 @@ +package apiAuth + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + rpc "Open_IM/pkg/proto/auth" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func UserRegister(c *gin.Context) { + params := api.UserRegisterReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + if params.Secret != config.Config.Secret { + log.NewError(params.OperationID, "params.Secret != config.Config.Secret", params.Secret, config.Config.Secret) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 401, "errMsg": "not authorized"}) + return + } + req := &rpc.UserRegisterReq{UserInfo: &open_im_sdk.UserInfo{}} + utils.CopyStructFields(req.UserInfo, ¶ms) + //copier.Copy(req.UserInfo, ¶ms) + req.OperationID = params.OperationID + log.NewInfo(req.OperationID, "UserRegister args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImAuthName) + client := rpc.NewAuthClient(etcdConn) + reply, err := client.UserRegister(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "call rpc err ", err) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "internal service err"}) + return + } + if reply.CommonResp.ErrCode != 0 { + log.NewError(req.OperationID, "UserRegister failed ", err) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": reply.CommonResp.ErrMsg}) + return + + } + + pbDataToken := &rpc.UserTokenReq{Platform: params.Platform, FromUserID: params.UserID, OperationID: params.OperationID} + replyToken, err := client.UserToken(context.Background(), pbDataToken) + if err != nil { + log.NewError(req.OperationID, "UserToken failed ", err.Error(), pbDataToken) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + resp := api.UserRegisterResp{CommResp: api.CommResp{ErrCode: replyToken.CommonResp.ErrCode, ErrMsg: replyToken.CommonResp.ErrMsg}, + UserToken: api.UserTokenInfo{UserID: req.UserInfo.UserID, Token: replyToken.Token, ExpiredTime: replyToken.ExpiredTime}} + log.NewInfo(req.OperationID, "UserRegister return ", resp) + c.JSON(http.StatusOK, resp) + +} + +func UserToken(c *gin.Context) { + params := api.UserTokenReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + if params.Secret != config.Config.Secret { + log.NewError(params.OperationID, "params.Secret != config.Config.Secret", params.Secret, config.Config.Secret) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 401, "errMsg": "not authorized"}) + return + } + req := &rpc.UserTokenReq{Platform: params.Platform, FromUserID: params.UserID, OperationID: params.OperationID} + log.NewInfo(req.OperationID, "UserToken args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImAuthName) + client := rpc.NewAuthClient(etcdConn) + reply, err := client.UserToken(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "UserToken failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + resp := api.UserTokenResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}, + UserToken: api.UserTokenInfo{UserID: req.FromUserID, Token: reply.Token, ExpiredTime: reply.ExpiredTime}} + log.NewInfo(req.OperationID, "UserRegister return ", resp) + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/chat/del_msg.go b/internal/api/chat/del_msg.go new file mode 100644 index 000000000..81b705953 --- /dev/null +++ b/internal/api/chat/del_msg.go @@ -0,0 +1,43 @@ +package apiChat + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbChat "Open_IM/pkg/proto/chat" + pbCommon "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func DelMsg(c *gin.Context) { + var ( + req api.DelMsgReq + resp api.DelMsgResp + reqPb pbCommon.DelMsgListReq + ) + if err := c.BindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, &req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req) + grpcConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + msgClient := pbChat.NewChatClient(grpcConn) + respPb, err := msgClient.DelMsgList(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelMsgList failed", err.Error(), reqPb) + c.JSON(http.StatusOK, gin.H{"errCode": constant.ErrServer.ErrCode, "errMsg": constant.ErrServer.ErrMsg + err.Error()}) + return + } + resp.ErrCode = respPb.ErrCode + resp.ErrMsg = respPb.ErrMsg + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/chat/get_max_min_seq.go b/internal/api/chat/get_max_min_seq.go new file mode 100644 index 000000000..95a4b1340 --- /dev/null +++ b/internal/api/chat/get_max_min_seq.go @@ -0,0 +1,61 @@ +package apiChat + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbMsg "Open_IM/pkg/proto/chat" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +type paramsUserNewestSeq struct { + ReqIdentifier int `json:"reqIdentifier" binding:"required"` + SendID string `json:"sendID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + MsgIncr int `json:"msgIncr" binding:"required"` +} + +func GetSeq(c *gin.Context) { + params := paramsUserNewestSeq{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + token := c.Request.Header.Get("token") + if ok, err := token_verify.VerifyToken(token, params.SendID); !ok { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "token validate err" + err.Error()}) + return + } + pbData := pbMsg.GetMaxAndMinSeqReq{} + pbData.UserID = params.SendID + pbData.OperationID = params.OperationID + grpcConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + + if grpcConn == nil { + log.ErrorByKv("get grpcConn err", pbData.OperationID, "args", params) + } + msgClient := pbMsg.NewChatClient(grpcConn) + reply, err := msgClient.GetMaxAndMinSeq(context.Background(), &pbData) + if err != nil { + log.NewError(params.OperationID, "UserGetSeq rpc failed, ", params, err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 401, "errMsg": "UserGetSeq rpc failed, " + err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "errCode": reply.ErrCode, + "errMsg": reply.ErrMsg, + "msgIncr": params.MsgIncr, + "reqIdentifier": params.ReqIdentifier, + "data": gin.H{ + "maxSeq": reply.MaxSeq, + "minSeq": reply.MinSeq, + }, + }) + +} diff --git a/internal/api/chat/pull_msg.go b/internal/api/chat/pull_msg.go new file mode 100644 index 000000000..515e9b743 --- /dev/null +++ b/internal/api/chat/pull_msg.go @@ -0,0 +1,68 @@ +package apiChat + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + "Open_IM/pkg/proto/chat" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +type paramsUserPullMsg struct { + ReqIdentifier *int `json:"reqIdentifier" binding:"required"` + SendID string `json:"sendID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + Data struct { + SeqBegin *int64 `json:"seqBegin" binding:"required"` + SeqEnd *int64 `json:"seqEnd" binding:"required"` + } +} + +type paramsUserPullMsgBySeqList struct { + ReqIdentifier int `json:"reqIdentifier" binding:"required"` + SendID string `json:"sendID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + SeqList []uint32 `json:"seqList"` +} + +func PullMsgBySeqList(c *gin.Context) { + params := paramsUserPullMsgBySeqList{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + token := c.Request.Header.Get("token") + if ok, err := token_verify.VerifyToken(token, params.SendID); !ok { + if err != nil { + log.NewError(params.OperationID, utils.GetSelfFuncName(), err.Error(), token, params.SendID) + } + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "token validate err"}) + return + } + pbData := open_im_sdk.PullMessageBySeqListReq{} + pbData.UserID = params.SendID + pbData.OperationID = params.OperationID + pbData.SeqList = params.SeqList + + grpcConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + msgClient := pbChat.NewChatClient(grpcConn) + reply, err := msgClient.PullMessageBySeqList(context.Background(), &pbData) + if err != nil { + log.ErrorByKv("PullMessageBySeqList error", pbData.OperationID, "err", err.Error()) + return + } + log.InfoByKv("rpc call success to PullMessageBySeqList", pbData.OperationID, "ReplyArgs", reply.String(), len(reply.List)) + c.JSON(http.StatusOK, gin.H{ + "errCode": reply.ErrCode, + "errMsg": reply.ErrMsg, + "reqIdentifier": params.ReqIdentifier, + "data": reply.List, + }) +} diff --git a/internal/api/chat/send_msg.go b/internal/api/chat/send_msg.go new file mode 100644 index 000000000..a28dcd1ce --- /dev/null +++ b/internal/api/chat/send_msg.go @@ -0,0 +1,99 @@ +package apiChat + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + pbChat "Open_IM/pkg/proto/chat" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "context" + + "Open_IM/pkg/grpc-etcdv3/getcdv3" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +type paramsUserSendMsg struct { + SenderPlatformID int32 `json:"senderPlatformID" binding:"required"` + SendID string `json:"sendID" binding:"required"` + SenderNickName string `json:"senderNickName"` + SenderFaceURL string `json:"senderFaceUrl"` + OperationID string `json:"operationID" binding:"required"` + Data struct { + SessionType int32 `json:"sessionType" binding:"required"` + MsgFrom int32 `json:"msgFrom" binding:"required"` + ContentType int32 `json:"contentType" binding:"required"` + RecvID string `json:"recvID" ` + GroupID string `json:"groupID" ` + ForceList []string `json:"forceList"` + Content []byte `json:"content" binding:"required"` + Options map[string]bool `json:"options" ` + ClientMsgID string `json:"clientMsgID" binding:"required"` + CreateTime int64 `json:"createTime" binding:"required"` + OffLineInfo *open_im_sdk.OfflinePushInfo `json:"offlineInfo" ` + } +} + +func newUserSendMsgReq(token string, params *paramsUserSendMsg) *pbChat.SendMsgReq { + pbData := pbChat.SendMsgReq{ + Token: token, + OperationID: params.OperationID, + MsgData: &open_im_sdk.MsgData{ + SendID: params.SendID, + RecvID: params.Data.RecvID, + GroupID: params.Data.GroupID, + ClientMsgID: params.Data.ClientMsgID, + SenderPlatformID: params.SenderPlatformID, + SenderNickname: params.SenderNickName, + SenderFaceURL: params.SenderFaceURL, + SessionType: params.Data.SessionType, + MsgFrom: params.Data.MsgFrom, + ContentType: params.Data.ContentType, + Content: params.Data.Content, + CreateTime: params.Data.CreateTime, + Options: params.Data.Options, + OfflinePushInfo: params.Data.OffLineInfo, + }, + } + return &pbData +} + +func SendMsg(c *gin.Context) { + params := paramsUserSendMsg{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + log.ErrorByKv("json unmarshal err", "", "err", err.Error(), "data", c.PostForm("data")) + return + } + + token := c.Request.Header.Get("token") + + log.InfoByKv("api call success to sendMsgReq", params.OperationID, "Parameters", params) + + pbData := newUserSendMsgReq(token, ¶ms) + log.Info("", "", "api SendMsg call start..., [data: %s]", pbData.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + client := pbChat.NewChatClient(etcdConn) + + log.Info("", "", "api SendMsg call, api call rpc...") + + reply, err := client.SendMsg(context.Background(), pbData) + if err != nil { + log.NewError(params.OperationID, "SendMsg rpc failed, ", params, err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 401, "errMsg": "SendMsg rpc failed, " + err.Error()}) + return + } + log.Info("", "", "api SendMsg call end..., [data: %s] [reply: %s]", pbData.String(), reply.String()) + + c.JSON(http.StatusOK, gin.H{ + "errCode": reply.ErrCode, + "errMsg": reply.ErrMsg, + "data": gin.H{ + "clientMsgID": reply.ClientMsgID, + "serverMsgID": reply.ServerMsgID, + "sendTime": reply.SendTime, + }, + }) + +} diff --git a/internal/api/conversation/conversation.go b/internal/api/conversation/conversation.go new file mode 100644 index 000000000..3d580864f --- /dev/null +++ b/internal/api/conversation/conversation.go @@ -0,0 +1,218 @@ +package conversation + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbUser "Open_IM/pkg/proto/user" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func SetConversation(c *gin.Context) { + var ( + req api.SetConversationReq + resp api.SetConversationResp + reqPb pbUser.SetConversationReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + reqPb.Conversation = &pbUser.Conversation{} + err := utils.CopyStructFields(&reqPb, req) + err = utils.CopyStructFields(reqPb.Conversation, req.Conversation) + if err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", reqPb.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pbUser.NewUserClient(etcdConn) + respPb, err := client.SetConversation(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation rpc failed, ", reqPb.String(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": "GetAllConversationMsgOpt rpc failed, " + err.Error()}) + return + } + resp.ErrMsg = respPb.CommonResp.ErrMsg + resp.ErrCode = respPb.CommonResp.ErrCode + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func BatchSetConversations(c *gin.Context) { + var ( + req api.BatchSetConversationsReq + resp api.BatchSetConversationsResp + reqPb pbUser.BatchSetConversationsReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", reqPb.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pbUser.NewUserClient(etcdConn) + respPb, err := client.BatchSetConversations(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation rpc failed, ", reqPb.String(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": "GetAllConversationMsgOpt rpc failed, " + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.Data, respPb); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.ErrMsg = respPb.CommonResp.ErrMsg + resp.ErrCode = respPb.CommonResp.ErrCode + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetAllConversations(c *gin.Context) { + var ( + req api.GetAllConversationsReq + resp api.GetAllConversationsResp + reqPb pbUser.GetAllConversationsReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", reqPb.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pbUser.NewUserClient(etcdConn) + respPb, err := client.GetAllConversations(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation rpc failed, ", reqPb.String(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": "GetAllConversationMsgOpt rpc failed, " + err.Error()}) + return + } + resp.ErrMsg = respPb.CommonResp.ErrMsg + resp.ErrCode = respPb.CommonResp.ErrCode + if err := utils.CopyStructFields(&resp.Conversations, respPb.Conversations); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed, ", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetConversation(c *gin.Context) { + var ( + req api.GetConversationReq + resp api.GetConversationResp + reqPb pbUser.GetConversationReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", reqPb.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pbUser.NewUserClient(etcdConn) + respPb, err := client.GetConversation(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetConversation rpc failed, ", reqPb.String(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": "GetAllConversationMsgOpt rpc failed, " + err.Error()}) + return + } + resp.ErrMsg = respPb.CommonResp.ErrMsg + resp.ErrCode = respPb.CommonResp.ErrCode + if err := utils.CopyStructFields(&resp.Conversation, respPb.Conversation); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetConversations(c *gin.Context) { + var ( + req api.GetConversationsReq + resp api.GetConversationsResp + reqPb pbUser.GetConversationsReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", reqPb.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pbUser.NewUserClient(etcdConn) + respPb, err := client.GetConversations(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation rpc failed, ", reqPb.String(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": "GetAllConversationMsgOpt rpc failed, " + err.Error()}) + return + } + resp.ErrMsg = respPb.CommonResp.ErrMsg + resp.ErrCode = respPb.CommonResp.ErrCode + if err := utils.CopyStructFields(&resp.Conversations, respPb.Conversations); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func SetRecvMsgOpt(c *gin.Context) { + var ( + req api.SetRecvMsgOptReq + resp api.SetRecvMsgOptResp + reqPb pbUser.SetRecvMsgOptReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", reqPb.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pbUser.NewUserClient(etcdConn) + respPb, err := client.SetRecvMsgOpt(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetRecvMsgOpt rpc failed, ", reqPb.String(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": "GetAllConversationMsgOpt rpc failed, " + err.Error()}) + return + } + resp.ErrMsg = respPb.CommonResp.ErrMsg + resp.ErrCode = respPb.CommonResp.ErrCode + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +//Deprecated +func SetReceiveMessageOpt(c *gin.Context) { + +} + +//Deprecated +func GetReceiveMessageOpt(c *gin.Context) { + +} + +//Deprecated +func GetAllConversationMessageOpt(c *gin.Context) { + +} diff --git a/internal/api/friend/friend.go b/internal/api/friend/friend.go new file mode 100644 index 000000000..054878c0c --- /dev/null +++ b/internal/api/friend/friend.go @@ -0,0 +1,456 @@ +package friend + +import ( + jsonData "Open_IM/internal/utils" + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + rpc "Open_IM/pkg/proto/friend" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func AddBlack(c *gin.Context) { + params := api.AddBlacklistReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.AddBlacklistReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "AddBlacklist args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.AddBlacklist(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "AddBlacklist failed ", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call add blacklist rpc server failed"}) + return + } + resp := api.AddBlacklistResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.CommID.OperationID, "AddBlacklist api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func ImportFriend(c *gin.Context) { + params := api.ImportFriendReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.ImportFriendReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "ImportFriend args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.ImportFriend(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "ImportFriend failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "ImportFriend failed "}) + return + } + resp := api.ImportFriendResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + if resp.ErrCode == 0 { + for _, v := range RpcResp.UserIDResultList { + resp.UserIDResultList = append(resp.UserIDResultList, api.UserIDResult{UserID: v.UserID, Result: v.Result}) + } + } + if len(resp.UserIDResultList) == 0 { + resp.UserIDResultList = []api.UserIDResult{} + } + log.NewInfo(req.OperationID, "ImportFriend api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func AddFriend(c *gin.Context) { + params := api.AddFriendReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.AddFriendReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms.ParamsCommFriend) + req.ReqMsg = params.ReqMsg + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "AddFriend args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.AddFriend(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "AddFriend failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call AddFriend rpc server failed"}) + return + } + + resp := api.AddFriendResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.CommID.OperationID, "AddFriend api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func AddFriendResponse(c *gin.Context) { + params := api.AddFriendResponseReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.AddFriendResponseReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms.ParamsCommFriend) + req.HandleMsg = params.HandleMsg + req.HandleResult = params.Flag + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + utils.CopyStructFields(req, ¶ms) + log.NewInfo(req.CommID.OperationID, "AddFriendResponse args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.AddFriendResponse(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "AddFriendResponse failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call add_friend_response rpc server failed"}) + return + } + + resp := api.AddFriendResponseResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.CommID.OperationID, "AddFriendResponse api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func DeleteFriend(c *gin.Context) { + params := api.DeleteFriendReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.DeleteFriendReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms.ParamsCommFriend) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "DeleteFriend args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.DeleteFriend(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "DeleteFriend failed ", err, req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call delete_friend rpc server failed"}) + return + } + + resp := api.DeleteFriendResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.CommID.OperationID, "DeleteFriend api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetBlacklist(c *gin.Context) { + params := api.GetBlackListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetBlacklistReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "GetBlacklist args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.GetBlacklist(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "GetBlacklist failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call get blacklist rpc server failed"}) + return + } + + resp := api.GetBlackListResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + for _, v := range RpcResp.BlackUserInfoList { + black := open_im_sdk.PublicUserInfo{} + utils.CopyStructFields(&black, v) + resp.BlackUserInfoList = append(resp.BlackUserInfoList, &black) + } + resp.Data = jsonData.JsonDataList(resp.BlackUserInfoList) + log.NewInfo(req.CommID.OperationID, "GetBlacklist api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func SetFriendRemark(c *gin.Context) { + params := api.SetFriendRemarkReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.SetFriendRemarkReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms.ParamsCommFriend) + req.Remark = params.Remark + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "SetFriendComment args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.SetFriendRemark(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "SetFriendComment failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call set friend comment rpc server failed"}) + return + } + resp := api.SetFriendRemarkResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + + log.NewInfo(req.CommID.OperationID, "SetFriendComment api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func RemoveBlack(c *gin.Context) { + params := api.RemoveBlackListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.RemoveBlacklistReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms.ParamsCommFriend) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + + log.NewInfo(req.CommID.OperationID, "RemoveBlacklist args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.RemoveBlacklist(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "RemoveBlacklist failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call remove blacklist rpc server failed"}) + return + } + resp := api.RemoveBlackListResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.CommID.OperationID, "RemoveBlacklist api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func IsFriend(c *gin.Context) { + params := api.IsFriendReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.IsFriendReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms.ParamsCommFriend) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "IsFriend args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.IsFriend(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "IsFriend failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call add friend rpc server failed"}) + return + } + resp := api.IsFriendResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + resp.Response.Friend = RpcResp.Response + + log.NewInfo(req.CommID.OperationID, "IsFriend api return ", resp) + c.JSON(http.StatusOK, resp) +} + +// +//func GetFriendsInfo(c *gin.Context) { +// params := api.GetFriendsInfoReq{} +// if err := c.BindJSON(¶ms); err != nil { +// log.NewError("0", "BindJSON failed ", err.Error()) +// c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) +// return +// } +// req := &rpc.GetFriendsInfoReq{} +// utils.CopyStructFields(req.CommID, params) +// var ok bool +// ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token")) +// if !ok { +// log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) +// c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) +// return +// } +// log.NewInfo(req.CommID.OperationID, "GetFriendsInfo args ", req.String()) +// +// etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) +// client := rpc.NewFriendClient(etcdConn) +// RpcResp, err := client.GetFriendsInfo(context.Background(), req) +// if err != nil { +// log.NewError(req.CommID.OperationID, "GetFriendsInfo failed ", err.Error(), req.String()) +// c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call search friend rpc server failed"}) +// return +// } +// +// resp := api.GetFriendsInfoResp{CommResp:api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} +// utils.CopyStructFields(&resp, RpcResp) +// c.JSON(http.StatusOK, resp) +// log.NewInfo(req.CommID.OperationID, "GetFriendsInfo api return ", resp) +//} + +func GetFriendList(c *gin.Context) { + params := api.GetFriendListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetFriendListReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "GetFriendList args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.GetFriendList(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "GetFriendList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call get friend list rpc server failed"}) + return + } + + resp := api.GetFriendListResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, FriendInfoList: RpcResp.FriendInfoList} + resp.Data = jsonData.JsonDataList(resp.FriendInfoList) + log.NewInfo(req.CommID.OperationID, "GetFriendList api return ", resp) + c.JSON(http.StatusOK, resp) + //c.JSON(http.StatusOK, resp) +} + +func GetFriendApplyList(c *gin.Context) { + params := api.GetFriendApplyListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetFriendApplyListReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "GetFriendApplyList args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + + RpcResp, err := client.GetFriendApplyList(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "GetFriendApplyList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call get friend apply list rpc server failed"}) + return + } + + resp := api.GetFriendApplyListResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, FriendRequestList: RpcResp.FriendRequestList} + resp.Data = jsonData.JsonDataList(resp.FriendRequestList) + log.NewInfo(req.CommID.OperationID, "GetFriendApplyList api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetSelfFriendApplyList(c *gin.Context) { + params := api.GetSelfApplyListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetSelfApplyListReq{CommID: &rpc.CommID{}} + utils.CopyStructFields(req.CommID, ¶ms) + var ok bool + ok, req.CommID.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.CommID.OperationID) + if !ok { + log.NewError(req.CommID.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.CommID.OperationID, "GetSelfApplyList args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + RpcResp, err := client.GetSelfApplyList(context.Background(), req) + if err != nil { + log.NewError(req.CommID.OperationID, "GetSelfApplyList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call get self apply list rpc server failed"}) + return + } + resp := api.GetSelfApplyListResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, FriendRequestList: RpcResp.FriendRequestList} + resp.Data = jsonData.JsonDataList(resp.FriendRequestList) + log.NewInfo(req.CommID.OperationID, "GetSelfApplyList api return ", resp) + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/group/group.go b/internal/api/group/group.go new file mode 100644 index 000000000..35365cc10 --- /dev/null +++ b/internal/api/group/group.go @@ -0,0 +1,698 @@ +package group + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + rpc "Open_IM/pkg/proto/group" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + + "github.com/gin-gonic/gin" + + "net/http" + "strings" + + jsonData "Open_IM/internal/utils" +) + +func KickGroupMember(c *gin.Context) { + params := api.KickGroupMemberReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.KickGroupMemberReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + + log.NewInfo(req.OperationID, "KickGroupMember args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.KickGroupMember(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + var memberListResp api.KickGroupMemberResp + memberListResp.ErrMsg = RpcResp.ErrMsg + memberListResp.ErrCode = RpcResp.ErrCode + for _, v := range RpcResp.Id2ResultList { + memberListResp.UserIDResultList = append(memberListResp.UserIDResultList, &api.UserIDResult{UserID: v.UserID, Result: v.Result}) + } + if len(memberListResp.UserIDResultList) == 0 { + memberListResp.UserIDResultList = []*api.UserIDResult{} + } + + log.NewInfo(req.OperationID, "KickGroupMember api return ", memberListResp) + c.JSON(http.StatusOK, memberListResp) +} + +func GetGroupMembersInfo(c *gin.Context) { + params := api.GetGroupMembersInfoReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetGroupMembersInfoReq{} + utils.CopyStructFields(req, params) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + //c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + api.SetErrCodeMsg(c, http.StatusInternalServerError) + return + } + log.NewInfo(req.OperationID, "GetGroupMembersInfo args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + + RpcResp, err := client.GetGroupMembersInfo(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + memberListResp := api.GetGroupMembersInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, MemberList: RpcResp.MemberList} + memberListResp.Data = jsonData.JsonDataList(RpcResp.MemberList) + log.NewInfo(req.OperationID, "GetGroupMembersInfo api return ", memberListResp) + c.JSON(http.StatusOK, memberListResp) +} + +func GetGroupMemberList(c *gin.Context) { + params := api.GetGroupMemberListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetGroupMemberListReq{} + utils.CopyStructFields(req, params) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "GetGroupMemberList args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + + RpcResp, err := client.GetGroupMemberList(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberList failed, ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + memberListResp := api.GetGroupMemberListResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, MemberList: RpcResp.MemberList, NextSeq: RpcResp.NextSeq} + memberListResp.Data = jsonData.JsonDataList(memberListResp.MemberList) + + log.NewInfo(req.OperationID, "GetGroupMemberList api return ", memberListResp) + c.JSON(http.StatusOK, memberListResp) +} + +func GetGroupAllMemberList(c *gin.Context) { + params := api.GetGroupAllMemberReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetGroupAllMemberReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "GetGroupAllMember args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.GetGroupAllMember(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupAllMember failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + memberListResp := api.GetGroupAllMemberResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, MemberList: RpcResp.MemberList} + memberListResp.Data = jsonData.JsonDataList(memberListResp.MemberList) + log.NewInfo(req.OperationID, "GetGroupAllMember api return ", memberListResp) + c.JSON(http.StatusOK, memberListResp) +} + +func GetJoinedGroupList(c *gin.Context) { + params := api.GetJoinedGroupListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetJoinedGroupListReq{} + utils.CopyStructFields(req, params) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "GetJoinedGroupList args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.GetJoinedGroupList(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetJoinedGroupList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + GroupListResp := api.GetJoinedGroupListResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, GroupInfoList: RpcResp.GroupList} + GroupListResp.Data = jsonData.JsonDataList(GroupListResp.GroupInfoList) + log.NewInfo(req.OperationID, "GetJoinedGroupList api return ", GroupListResp) + c.JSON(http.StatusOK, GroupListResp) +} + +func InviteUserToGroup(c *gin.Context) { + params := api.InviteUserToGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.InviteUserToGroupReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "InviteUserToGroup args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.InviteUserToGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "InviteUserToGroup failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.InviteUserToGroupResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + for _, v := range RpcResp.Id2ResultList { + resp.UserIDResultList = append(resp.UserIDResultList, &api.UserIDResult{UserID: v.UserID, Result: v.Result}) + } + + if len(resp.UserIDResultList) == 0 { + resp.UserIDResultList = *new([]*api.UserIDResult) + } + + log.NewInfo(req.OperationID, "InviteUserToGroup api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func CreateGroup(c *gin.Context) { + params := api.CreateGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + // + req := &rpc.CreateGroupReq{GroupInfo: &open_im_sdk.GroupInfo{}} + utils.CopyStructFields(req.GroupInfo, ¶ms) + + for _, v := range params.MemberList { + req.InitMemberList = append(req.InitMemberList, &rpc.GroupAddMemberInfo{UserID: v.UserID, RoleLevel: v.RoleLevel}) + } + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + req.OwnerUserID = params.OwnerUserID + req.OperationID = params.OperationID + log.NewInfo(req.OperationID, "CreateGroup args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.CreateGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "CreateGroup failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + + resp := api.CreateGroupResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + if RpcResp.ErrCode == 0 { + utils.CopyStructFields(&resp.GroupInfo, RpcResp.GroupInfo) + resp.Data = jsonData.JsonDataOne(&resp.GroupInfo) + } + log.NewInfo(req.OperationID, "CreateGroup api return ", resp) + c.JSON(http.StatusOK, resp) +} + +// 群主或管理员收到的 +func GetRecvGroupApplicationList(c *gin.Context) { + params := api.GetGroupApplicationListReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetGroupApplicationListReq{} + utils.CopyStructFields(req, params) + //var ok bool + //ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token")) + //if !ok { + // log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + // c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + // return + //} + log.NewInfo(req.OperationID, "GetGroupApplicationList args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.GetGroupApplicationList(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupApplicationList failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.GetGroupApplicationListResp{CommResp: api.CommResp{ErrCode: reply.ErrCode, ErrMsg: reply.ErrMsg}, GroupRequestList: reply.GroupRequestList} + resp.Data = jsonData.JsonDataList(resp.GroupRequestList) + log.NewInfo(req.OperationID, "GetGroupApplicationList api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetUserReqGroupApplicationList(c *gin.Context) { + var params api.GetUserReqGroupApplicationListReq + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", utils.GetSelfFuncName(), err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetUserReqApplicationListReq{} + utils.CopyStructFields(req, params) + //ok, req.OpUserID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token")) + //if !ok { + // log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + // c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + // return + //} + log.NewInfo(req.OperationID, "GetGroupsInfo args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.GetUserReqApplicationList(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupsInfo failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + log.NewInfo(req.OperationID, RpcResp) + resp := api.GetGroupApplicationListResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}, GroupRequestList: RpcResp.GroupRequestList} + log.NewInfo(req.OperationID, "GetGroupApplicationList api return ", resp) + resp.Data = jsonData.JsonDataList(resp.GroupRequestList) + c.JSON(http.StatusOK, resp) +} + +func GetGroupsInfo(c *gin.Context) { + params := api.GetGroupInfoReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetGroupsInfoReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "GetGroupsInfo args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.GetGroupsInfo(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetGroupsInfo failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + + resp := api.GetGroupInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, GroupInfoList: RpcResp.GroupInfoList} + resp.Data = jsonData.JsonDataList(resp.GroupInfoList) + log.NewInfo(req.OperationID, "GetGroupsInfo api return ", resp) + c.JSON(http.StatusOK, resp) +} + +//process application +func ApplicationGroupResponse(c *gin.Context) { + params := api.ApplicationGroupResponseReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GroupApplicationResponseReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "ApplicationGroupResponse args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.GroupApplicationResponse(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GroupApplicationResponse failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.ApplicationGroupResponseResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, "ApplicationGroupResponse api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func JoinGroup(c *gin.Context) { + params := api.JoinGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.JoinGroupReq{} + utils.CopyStructFields(req, params) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "JoinGroup args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + + RpcResp, err := client.JoinGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "JoinGroup failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + resp := api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg} + log.NewInfo(req.OperationID, "JoinGroup api return", RpcResp.String()) + c.JSON(http.StatusOK, resp) +} + +func QuitGroup(c *gin.Context) { + params := api.QuitGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.QuitGroupReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "QuitGroup args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.QuitGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "call quit group rpc server failed,err=%s", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + resp := api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg} + log.NewInfo(req.OperationID, "QuitGroup api return", RpcResp.String()) + c.JSON(http.StatusOK, resp) +} + +func SetGroupInfo(c *gin.Context) { + params := api.SetGroupInfoReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.SetGroupInfoReq{GroupInfo: &open_im_sdk.GroupInfo{}} + utils.CopyStructFields(req.GroupInfo, ¶ms) + req.OperationID = params.OperationID + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "SetGroupInfo args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + RpcResp, err := client.SetGroupInfo(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "SetGroupInfo failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + resp := api.SetGroupInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + c.JSON(http.StatusOK, resp) + log.NewInfo(req.OperationID, "SetGroupInfo api return ", resp) +} + +func TransferGroupOwner(c *gin.Context) { + params := api.TransferGroupOwnerReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.TransferGroupOwnerReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "TransferGroupOwner args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.TransferGroupOwner(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "TransferGroupOwner failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.TransferGroupOwnerResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, "TransferGroupOwner api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func DismissGroup(c *gin.Context) { + params := api.DismissGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.DismissGroupReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.DismissGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), " failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.DismissGroupResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func MuteGroupMember(c *gin.Context) { + params := api.MuteGroupMemberReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.MuteGroupMemberReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.MuteGroupMember(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), " failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.MuteGroupMemberResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func CancelMuteGroupMember(c *gin.Context) { + params := api.CancelMuteGroupMemberReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.CancelMuteGroupMemberReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.CancelMuteGroupMember(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), " failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.CancelMuteGroupMemberResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func MuteGroup(c *gin.Context) { + params := api.MuteGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.MuteGroupReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.MuteGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), " failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.MuteGroupResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func CancelMuteGroup(c *gin.Context) { + params := api.CancelMuteGroupReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.CancelMuteGroupReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := rpc.NewGroupClient(etcdConn) + reply, err := client.CancelMuteGroup(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), " failed ", req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()}) + return + } + + resp := api.CancelMuteGroupResp{CommResp: api.CommResp{ErrCode: reply.CommonResp.ErrCode, ErrMsg: reply.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " api return ", resp) + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/manage/management_chat.go b/internal/api/manage/management_chat.go new file mode 100644 index 000000000..e1c1bc0ff --- /dev/null +++ b/internal/api/manage/management_chat.go @@ -0,0 +1,296 @@ +/* +** description(""). +** copyright('open-im,www.open-im.io'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/9/15 15:23). + */ +package manage + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbChat "Open_IM/pkg/proto/chat" + "Open_IM/pkg/proto/sdk_ws" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" + "github.com/golang/protobuf/proto" + "github.com/mitchellh/mapstructure" + "net/http" + "strings" +) + +var validate *validator.Validate + +func newUserSendMsgReq(params *ManagementSendMsgReq) *pbChat.SendMsgReq { + var newContent string + var err error + switch params.ContentType { + case constant.Text: + newContent = params.Content["text"].(string) + case constant.Picture: + fallthrough + case constant.Custom: + fallthrough + case constant.Voice: + fallthrough + case constant.File: + newContent = utils.StructToJsonString(params.Content) + case constant.Revoke: + newContent = params.Content["revokeMsgClientID"].(string) + + default: + } + var options map[string]bool + if params.IsOnlineOnly { + options = make(map[string]bool, 5) + utils.SetSwitchFromOptions(options, constant.IsOfflinePush, false) + utils.SetSwitchFromOptions(options, constant.IsHistory, false) + utils.SetSwitchFromOptions(options, constant.IsPersistent, false) + utils.SetSwitchFromOptions(options, constant.IsSenderSync, false) + } + pbData := pbChat.SendMsgReq{ + OperationID: params.OperationID, + MsgData: &open_im_sdk.MsgData{ + SendID: params.SendID, + RecvID: params.RecvID, + GroupID: params.GroupID, + ClientMsgID: utils.GetMsgID(params.SendID), + SenderPlatformID: params.SenderPlatformID, + SenderNickname: params.SenderNickname, + SenderFaceURL: params.SenderFaceURL, + SessionType: params.SessionType, + MsgFrom: constant.SysMsgType, + ContentType: params.ContentType, + Content: []byte(newContent), + // ForceList: params.ForceList, + CreateTime: utils.GetCurrentTimestampByMill(), + Options: options, + OfflinePushInfo: params.OfflinePushInfo, + }, + } + if params.ContentType == constant.OANotification { + var tips open_im_sdk.TipsComm + tips.JsonDetail = utils.StructToJsonString(params.Content) + pbData.MsgData.Content, err = proto.Marshal(&tips) + if err != nil { + log.Error(params.OperationID, "Marshal failed ", err.Error(), tips.String()) + } + } + return &pbData +} +func init() { + validate = validator.New() +} + +func ManagementSendMsg(c *gin.Context) { + var data interface{} + params := ManagementSendMsgReq{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + log.ErrorByKv("json unmarshal err", c.PostForm("operationID"), "err", err.Error(), "content", c.PostForm("content")) + return + } + switch params.ContentType { + case constant.Text: + data = TextElem{} + case constant.Picture: + data = PictureElem{} + case constant.Voice: + data = SoundElem{} + case constant.Video: + data = VideoElem{} + case constant.File: + data = FileElem{} + //case constant.AtText: + // data = AtElem{} + //case constant.Merger: + // data = + //case constant.Card: + //case constant.Location: + case constant.Custom: + data = CustomElem{} + case constant.Revoke: + data = RevokeElem{} + case constant.OANotification: + data = OANotificationElem{} + params.SessionType = constant.NotificationChatType + //case constant.HasReadReceipt: + //case constant.Typing: + //case constant.Quote: + default: + c.JSON(http.StatusBadRequest, gin.H{"errCode": 404, "errMsg": "contentType err"}) + log.ErrorByKv("contentType err", c.PostForm("operationID"), "content", c.PostForm("content")) + return + } + if err := mapstructure.WeakDecode(params.Content, &data); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 401, "errMsg": err.Error()}) + log.ErrorByKv("content to Data struct err", "", "err", err.Error()) + return + } else if err := validate.Struct(data); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 403, "errMsg": err.Error()}) + log.ErrorByKv("data args validate err", "", "err", err.Error()) + return + } + log.NewInfo("", data, params) + token := c.Request.Header.Get("token") + claims, err := token_verify.ParseToken(token, params.OperationID) + if err != nil { + log.NewError(params.OperationID, "parse token failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "parse token failed", "sendTime": 0, "MsgID": ""}) + return + } + if !utils.IsContain(claims.UID, config.Config.Manager.AppManagerUid) { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "not authorized", "sendTime": 0, "MsgID": ""}) + return + + } + switch params.SessionType { + case constant.SingleChatType: + if len(params.RecvID) == 0 { + log.NewError(params.OperationID, "recvID is a null string") + c.JSON(http.StatusBadRequest, gin.H{"errCode": 405, "errMsg": "recvID is a null string", "sendTime": 0, "MsgID": ""}) + return + } + case constant.GroupChatType: + if len(params.GroupID) == 0 { + log.NewError(params.OperationID, "groupID is a null string") + c.JSON(http.StatusBadRequest, gin.H{"errCode": 405, "errMsg": "groupID is a null string", "sendTime": 0, "MsgID": ""}) + return + } + + } + log.InfoByKv("Ws call success to ManagementSendMsgReq", params.OperationID, "Parameters", params) + + pbData := newUserSendMsgReq(¶ms) + log.Info("", "", "api ManagementSendMsg call start..., [data: %s]", pbData.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + client := pbChat.NewChatClient(etcdConn) + + log.Info("", "", "api ManagementSendMsg call, api call rpc...") + + RpcResp, err := client.SendMsg(context.Background(), pbData) + if err != nil { + log.NewError(params.OperationID, "call delete UserSendMsg rpc server failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call UserSendMsg rpc server failed"}) + return + } + log.Info("", "", "api ManagementSendMsg call end..., [data: %s] [reply: %s]", pbData.String(), RpcResp.String()) + resp := api.ManagementSendMsgResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, ResultList: server_api_params.UserSendMsgResp{ServerMsgID: RpcResp.ServerMsgID, ClientMsgID: RpcResp.ClientMsgID, SendTime: RpcResp.SendTime}} + log.Info(params.OperationID, "ManagementSendMsg return", resp) + c.JSON(http.StatusOK, resp) + +} + +// +//type MergeElem struct { +// Title string `json:"title"` +// AbstractList []string `json:"abstractList"` +// MultiMessage []*MsgStruct `json:"multiMessage"` +//} +// +//type QuoteElem struct { +// Text string `json:"text"` +// QuoteMessage *MsgStruct `json:"quoteMessage"` +//} +type ManagementSendMsgReq struct { + OperationID string `json:"operationID" binding:"required"` + SendID string `json:"sendID" binding:"required"` + RecvID string `json:"recvID" ` + GroupID string `json:"groupID" ` + SenderNickname string `json:"senderNickname" ` + SenderFaceURL string `json:"senderFaceURL" ` + SenderPlatformID int32 `json:"senderPlatformID"` + ForceList []string `json:"forceList" ` + Content map[string]interface{} `json:"content" binding:"required"` + ContentType int32 `json:"contentType" binding:"required"` + SessionType int32 `json:"sessionType" binding:"required"` + IsOnlineOnly bool `json:"isOnlineOnly"` + OfflinePushInfo *open_im_sdk.OfflinePushInfo `json:"offlinePushInfo"` +} + +type PictureBaseInfo struct { + UUID string `mapstructure:"uuid"` + Type string `mapstructure:"type" ` + Size int64 `mapstructure:"size" ` + Width int32 `mapstructure:"width" ` + Height int32 `mapstructure:"height"` + Url string `mapstructure:"url" ` +} + +type PictureElem struct { + SourcePath string `mapstructure:"sourcePath"` + SourcePicture PictureBaseInfo `mapstructure:"sourcePicture"` + BigPicture PictureBaseInfo `mapstructure:"bigPicture" ` + SnapshotPicture PictureBaseInfo `mapstructure:"snapshotPicture"` +} +type SoundElem struct { + UUID string `mapstructure:"uuid"` + SoundPath string `mapstructure:"soundPath"` + SourceURL string `mapstructure:"sourceUrl"` + DataSize int64 `mapstructure:"dataSize"` + Duration int64 `mapstructure:"duration"` +} +type VideoElem struct { + VideoPath string `mapstructure:"videoPath"` + VideoUUID string `mapstructure:"videoUUID"` + VideoURL string `mapstructure:"videoUrl"` + VideoType string `mapstructure:"videoType"` + VideoSize int64 `mapstructure:"videoSize"` + Duration int64 `mapstructure:"duration"` + SnapshotPath string `mapstructure:"snapshotPath"` + SnapshotUUID string `mapstructure:"snapshotUUID"` + SnapshotSize int64 `mapstructure:"snapshotSize"` + SnapshotURL string `mapstructure:"snapshotUrl"` + SnapshotWidth int32 `mapstructure:"snapshotWidth"` + SnapshotHeight int32 `mapstructure:"snapshotHeight"` +} +type FileElem struct { + FilePath string `mapstructure:"filePath"` + UUID string `mapstructure:"uuid"` + SourceURL string `mapstructure:"sourceUrl"` + FileName string `mapstructure:"fileName"` + FileSize int64 `mapstructure:"fileSize"` +} +type AtElem struct { + Text string `mapstructure:"text"` + AtUserList []string `mapstructure:"atUserList"` + IsAtSelf bool `mapstructure:"isAtSelf"` +} +type LocationElem struct { + Description string `mapstructure:"description"` + Longitude float64 `mapstructure:"longitude"` + Latitude float64 `mapstructure:"latitude"` +} +type CustomElem struct { + Data string `mapstructure:"data" validate:"required"` + Description string `mapstructure:"description"` + Extension string `mapstructure:"extension"` +} +type TextElem struct { + Text string `mapstructure:"text" validate:"required"` +} + +type RevokeElem struct { + RevokeMsgClientID string `mapstructure:"revokeMsgClientID" validate:"required"` +} +type OANotificationElem struct { + NotificationName string `mapstructure:"notificationName" validate:"required"` + NotificationFaceURL string `mapstructure:"notificationFaceURL" validate:"required"` + NotificationType int32 `mapstructure:"notificationType" validate:"required"` + Text string `mapstructure:"text" validate:"required"` + Url string `mapstructure:"url"` + MixType int32 `mapstructure:"mixType"` + PictureElem PictureElem `mapstructure:"pictureElem"` + SoundElem SoundElem `mapstructure:"soundElem"` + VideoElem VideoElem `mapstructure:"videoElem"` + FileElem FileElem `mapstructure:"fileElem"` + Ex string `mapstructure:"ex"` +} diff --git a/internal/api/manage/management_user.go b/internal/api/manage/management_user.go new file mode 100644 index 000000000..5bcc19be0 --- /dev/null +++ b/internal/api/manage/management_user.go @@ -0,0 +1,180 @@ +/* +** description(""). +** copyright('open-im,www.open-im.io'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/9/15 10:28). + */ +package manage + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbRelay "Open_IM/pkg/proto/relay" + rpc "Open_IM/pkg/proto/user" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func DeleteUser(c *gin.Context) { + params := api.DeleteUsersReq{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.DeleteUsersReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "DeleteUser args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := rpc.NewUserClient(etcdConn) + + RpcResp, err := client.DeleteUsers(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "call delete users rpc server failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call delete users rpc server failed"}) + return + } + resp := api.DeleteUsersResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}, FailedUserIDList: RpcResp.FailedUserIDList} + if len(RpcResp.FailedUserIDList) == 0 { + resp.FailedUserIDList = []string{} + } + log.NewInfo(req.OperationID, "DeleteUser api return", resp) + c.JSON(http.StatusOK, resp) +} +func GetAllUsersUid(c *gin.Context) { + params := api.GetAllUsersUidReq{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetAllUserIDReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "GetAllUsersUid args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := rpc.NewUserClient(etcdConn) + RpcResp, err := client.GetAllUserID(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "call GetAllUsersUid users rpc server failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call GetAllUsersUid users rpc server failed"}) + return + } + resp := api.GetAllUsersUidResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}, UserIDList: RpcResp.UserIDList} + if len(RpcResp.UserIDList) == 0 { + resp.UserIDList = []string{} + } + log.NewInfo(req.OperationID, "GetAllUsersUid api return", resp) + c.JSON(http.StatusOK, resp) + +} +func AccountCheck(c *gin.Context) { + params := api.AccountCheckReq{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.AccountCheckReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "AccountCheck args ", req.String()) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := rpc.NewUserClient(etcdConn) + + RpcResp, err := client.AccountCheck(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "call AccountCheck users rpc server failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call AccountCheck users rpc server failed"}) + return + } + resp := api.AccountCheckResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}, ResultList: RpcResp.ResultList} + if len(RpcResp.ResultList) == 0 { + resp.ResultList = []*rpc.AccountCheckResp_SingleUserStatus{} + } + log.NewInfo(req.OperationID, "AccountCheck api return", resp) + c.JSON(http.StatusOK, resp) +} +func GetUsersOnlineStatus(c *gin.Context) { + params := api.GetUsersOnlineStatusReq{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &pbRelay.GetUsersOnlineStatusReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "GetUsersOnlineStatus args ", req.String()) + var wsResult []*pbRelay.GetUsersOnlineStatusResp_SuccessResult + var respResult []*pbRelay.GetUsersOnlineStatusResp_SuccessResult + flag := false + grpcCons := getcdv3.GetConn4Unique(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOnlineMessageRelayName) + for _, v := range grpcCons { + client := pbRelay.NewOnlineMessageRelayServiceClient(v) + reply, err := client.GetUsersOnlineStatus(context.Background(), req) + if err != nil { + log.NewError(params.OperationID, "GetUsersOnlineStatus rpc err", req.String(), err.Error()) + continue + } else { + if reply.ErrCode == 0 { + wsResult = append(wsResult, reply.SuccessResult...) + } + } + } + log.NewInfo(params.OperationID, "call GetUsersOnlineStatus rpc server is success", wsResult) + //Online data merge of each node + for _, v1 := range params.UserIDList { + flag = false + temp := new(pbRelay.GetUsersOnlineStatusResp_SuccessResult) + for _, v2 := range wsResult { + if v2.UserID == v1 { + flag = true + temp.UserID = v1 + temp.Status = constant.OnlineStatus + temp.DetailPlatformStatus = append(temp.DetailPlatformStatus, v2.DetailPlatformStatus...) + } + + } + if !flag { + temp.UserID = v1 + temp.Status = constant.OfflineStatus + } + respResult = append(respResult, temp) + } + resp := api.GetUsersOnlineStatusResp{CommResp: api.CommResp{ErrCode: 0, ErrMsg: ""}, SuccessResult: respResult} + if len(respResult) == 0 { + resp.SuccessResult = []*pbRelay.GetUsersOnlineStatusResp_SuccessResult{} + } + log.NewInfo(req.OperationID, "GetUsersOnlineStatus api return", resp) + c.JSON(http.StatusOK, resp) + +} diff --git a/internal/api/office/tag.go b/internal/api/office/tag.go new file mode 100644 index 000000000..2471ddd87 --- /dev/null +++ b/internal/api/office/tag.go @@ -0,0 +1,280 @@ +package office + +import ( + apistruct "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbOffice "Open_IM/pkg/proto/office" + pbCommon "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func GetUserTags(c *gin.Context) { + var ( + req apistruct.GetUserTagsReq + resp apistruct.GetUserTagsResp + reqPb pbOffice.GetUserTagsReq + respPb *pbOffice.GetUserTagsResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + reqPb.OperationID = req.OperationID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.GetUserTags(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserTags rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + if respPb.Tags != nil { + resp.Data.Tags = respPb.Tags + } else { + resp.Data.Tags = []*pbOffice.Tag{} + } + c.JSON(http.StatusOK, resp) +} + +func CreateTag(c *gin.Context) { + var ( + req apistruct.CreateTagReq + resp apistruct.CreateTagResp + reqPb pbOffice.CreateTagReq + respPb *pbOffice.CreateTagResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.CreateTag(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateTag rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + c.JSON(http.StatusOK, resp) +} + +func DeleteTag(c *gin.Context) { + var ( + req apistruct.DeleteTagReq + resp apistruct.DeleteTagResp + reqPb pbOffice.DeleteTagReq + respPb *pbOffice.DeleteTagResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.DeleteTag(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateTag rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + c.JSON(http.StatusOK, resp) +} + +func SetTag(c *gin.Context) { + var ( + req apistruct.SetTagReq + resp apistruct.SetTagResp + reqPb pbOffice.SetTagReq + respPb *pbOffice.SetTagResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.SetTag(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateTag rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + c.JSON(http.StatusOK, resp) +} + +func SendMsg2Tag(c *gin.Context) { + var ( + req apistruct.SendMsg2TagReq + resp apistruct.SendMsg2TagResp + reqPb pbOffice.SendMsg2TagReq + respPb *pbOffice.SendMsg2TagResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.SendID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.SendMsg2Tag(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateTag rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + c.JSON(http.StatusOK, resp) +} + +func GetTagSendLogs(c *gin.Context) { + var ( + req apistruct.GetTagSendLogsReq + resp apistruct.GetTagSendLogsResp + reqPb pbOffice.GetTagSendLogsReq + respPb *pbOffice.GetTagSendLogsResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + reqPb.OperationID = req.OperationID + reqPb.Pagination = &pbCommon.RequestPagination{ + PageNumber: req.PageNumber, + ShowNumber: req.ShowNumber, + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.GetTagSendLogs(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateTag rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + if respPb.TagSendLogs != nil { + resp.Data.Logs = respPb.TagSendLogs + } else { + resp.Data.Logs = []*pbOffice.TagSendLog{} + } + resp.Data.ShowNumber = respPb.Pagination.ShowNumber + resp.Data.CurrentPage = respPb.Pagination.CurrentPage + c.JSON(http.StatusOK, resp) +} + +func GetUserTagByID(c *gin.Context) { + var ( + req apistruct.GetUserTagByIDReq + resp apistruct.GetUserTagByIDResp + reqPb pbOffice.GetUserTagByIDReq + respPb *pbOffice.GetUserTagByIDResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + reqPb.OperationID = req.OperationID + reqPb.TagID = req.TagID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.GetUserTagByID(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTagByID failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateTag rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp.CommResp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.Data.Tag = respPb.Tag + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/office/work_moments.go b/internal/api/office/work_moments.go new file mode 100644 index 000000000..ac7619dda --- /dev/null +++ b/internal/api/office/work_moments.go @@ -0,0 +1,371 @@ +package office + +import ( + apiStruct "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbOffice "Open_IM/pkg/proto/office" + pbCommon "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func CreateOneWorkMoment(c *gin.Context) { + var ( + req apiStruct.CreateOneWorkMomentReq + resp apiStruct.CreateOneWorkMomentResp + reqPb pbOffice.CreateOneWorkMomentReq + respPb *pbOffice.CreateOneWorkMomentResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.CreateOneWorkMoment(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CreateOneWorkMoment rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CreateOneWorkMoment rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func DeleteOneWorkMoment(c *gin.Context) { + var ( + req apiStruct.DeleteOneWorkMomentReq + resp apiStruct.DeleteOneWorkMomentResp + reqPb pbOffice.DeleteOneWorkMomentReq + respPb *pbOffice.DeleteOneWorkMomentResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.DeleteOneWorkMoment(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "DeleteOneWorkMoment rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "DeleteOneWorkMoment rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func LikeOneWorkMoment(c *gin.Context) { + var ( + req apiStruct.LikeOneWorkMomentReq + resp apiStruct.LikeOneWorkMomentResp + reqPb pbOffice.LikeOneWorkMomentReq + respPb *pbOffice.LikeOneWorkMomentResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.LikeOneWorkMoment(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "LikeOneWorkMoment rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "LikeOneWorkMoment rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func CommentOneWorkMoment(c *gin.Context) { + var ( + req apiStruct.CommentOneWorkMomentReq + resp apiStruct.CommentOneWorkMomentResp + reqPb pbOffice.CommentOneWorkMomentReq + respPb *pbOffice.CommentOneWorkMomentResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.CommentOneWorkMoment(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CommentOneWorkMoment rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "CommentOneWorkMoment rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetUserWorkMoments(c *gin.Context) { + var ( + req apiStruct.GetUserWorkMomentsReq + resp apiStruct.GetUserWorkMomentsResp + reqPb pbOffice.GetUserWorkMomentsReq + respPb *pbOffice.GetUserWorkMomentsResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.OperationID = req.OperationID + reqPb.Pagination = &pbCommon.RequestPagination{ + PageNumber: req.PageNumber, + ShowNumber: req.ShowNumber, + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.GetUserWorkMoments(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserWorkMoments rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserWorkMoments rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.Data.WorkMoments = respPb.WorkMoments + resp.Data.ShowNumber = respPb.Pagination.ShowNumber + resp.Data.CurrentPage = respPb.Pagination.CurrentPage + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetUserFriendWorkMoments(c *gin.Context) { + var ( + req apiStruct.GetUserFriendWorkMomentsReq + resp apiStruct.GetUserFriendWorkMomentsResp + reqPb pbOffice.GetUserFriendWorkMomentsReq + respPb *pbOffice.GetUserFriendWorkMomentsResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.OperationID = req.OperationID + reqPb.Pagination = &pbCommon.RequestPagination{ + PageNumber: req.PageNumber, + ShowNumber: req.ShowNumber, + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.GetUserFriendWorkMoments(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserFriendWorkMoments rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserFriendWorkMoments rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.Data.WorkMoments = respPb.WorkMoments + resp.Data.ShowNumber = respPb.Pagination.ShowNumber + resp.Data.CurrentPage = respPb.Pagination.CurrentPage + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetUserWorkMomentsCommentsMsg(c *gin.Context) { + var ( + req apiStruct.GetUserWorkMomentsCommentsMsgReq + resp apiStruct.GetUserWorkMomentsCommentsMsgResp + reqPb pbOffice.GetUserWorkMomentsCommentsMsgReq + respPb *pbOffice.GetUserWorkMomentsCommentsMsgResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.OperationID = req.OperationID + reqPb.Pagination = &pbCommon.RequestPagination{ + PageNumber: req.PageNumber, + ShowNumber: req.ShowNumber, + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.GetUserWorkMomentsCommentsMsg(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserWorkMomentsCommentsMsg rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserWorkMomentsCommentsMsg rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.Data.CurrentPage = respPb.Pagination.CurrentPage + resp.Data.ShowNumber = respPb.Pagination.ShowNumber + resp.Data.CommentMsgs = respPb.CommentsMsgs + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func SetUserWorkMomentsLevel(c *gin.Context) { + var ( + req apiStruct.SetUserWorkMomentsLevelReq + resp apiStruct.SetUserWorkMomentsLevelResp + reqPb pbOffice.SetUserWorkMomentsLevelReq + respPb *pbOffice.SetUserWorkMomentsLevelResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + if err := utils.CopyStructFields(&reqPb, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + reqPb.UserID = userID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.SetUserWorkMomentsLevel(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetUserWorkMomentsLevel rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "SetUserWorkMomentsLevel rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} + +func ClearUserWorkMomentsCommentsMsg(c *gin.Context) { + var ( + req apiStruct.ClearUserWorkMomentsCommentsMsgReq + resp apiStruct.ClearUserWorkMomentsCommentsMsgResp + reqPb pbOffice.ClearUserWorkMomentsCommentsMsgReq + respPb *pbOffice.ClearUserWorkMomentsCommentsMsgResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "bind json failed " + err.Error()}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req) + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + reqPb.UserID = userID + reqPb.OperationID = req.OperationID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfficeName) + client := pbOffice.NewOfficeServiceClient(etcdConn) + respPb, err := client.ClearUserWorkMomentsCommentsMsg(context.Background(), &reqPb) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "ClearUserWorkMomentsCommentsMsg rpc failed", err.Error()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "ClearUserWorkMomentsCommentsMsg rpc server failed" + err.Error()}) + return + } + if err := utils.CopyStructFields(&resp, respPb.CommonResp); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/organization/organization.go b/internal/api/organization/organization.go new file mode 100644 index 000000000..250e9eef0 --- /dev/null +++ b/internal/api/organization/organization.go @@ -0,0 +1,439 @@ +package organization + +import ( + jsonData "Open_IM/internal/utils" + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + rpc "Open_IM/pkg/proto/organization" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func CreateDepartment(c *gin.Context) { + params := api.CreateDepartmentReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.CreateDepartmentReq{DepartmentInfo: &open_im_sdk.Department{}} + utils.CopyStructFields(req, ¶ms) + utils.CopyStructFields(req.DepartmentInfo, ¶ms) + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + " " + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.CreateDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc CreateDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.CreateDepartmentResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, Department: RpcResp.DepartmentInfo} + apiResp.Data = jsonData.JsonDataOne(RpcResp.DepartmentInfo) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func UpdateDepartment(c *gin.Context) { + params := api.UpdateDepartmentReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.UpdateDepartmentReq{DepartmentInfo: &open_im_sdk.Department{}} + utils.CopyStructFields(req, ¶ms) + utils.CopyStructFields(req.DepartmentInfo, ¶ms) + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.UpdateDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc UpdateDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.UpdateDepartmentResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func GetSubDepartment(c *gin.Context) { + params := api.GetSubDepartmentReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.GetSubDepartmentReq{} + utils.CopyStructFields(req, ¶ms) + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.GetSubDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc GetDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.GetSubDepartmentResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, DepartmentList: RpcResp.DepartmentList} + apiResp.Data = jsonData.JsonDataList(RpcResp.DepartmentList) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func DeleteDepartment(c *gin.Context) { + params := api.DeleteDepartmentReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.DeleteDepartmentReq{} + utils.CopyStructFields(req, ¶ms) + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.DeleteDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc DeleteDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.DeleteDepartmentResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func CreateOrganizationUser(c *gin.Context) { + params := api.CreateOrganizationUserReq{OrganizationUser: &open_im_sdk.OrganizationUser{}} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.CreateOrganizationUserReq{OrganizationUser: &open_im_sdk.OrganizationUser{}} + utils.CopyStructFields(req, ¶ms) + utils.CopyStructFields(req.OrganizationUser, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.CreateOrganizationUser(context.Background(), req) + if err != nil { + errMsg := "rpc CreateOrganizationUser failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.CreateOrganizationUserResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func UpdateOrganizationUser(c *gin.Context) { + params := api.UpdateOrganizationUserReq{OrganizationUser: &open_im_sdk.OrganizationUser{}} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.UpdateOrganizationUserReq{OrganizationUser: &open_im_sdk.OrganizationUser{}} + utils.CopyStructFields(req, ¶ms) + utils.CopyStructFields(req.OrganizationUser, ¶ms) + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.UpdateOrganizationUser(context.Background(), req) + if err != nil { + errMsg := "rpc UpdateOrganizationUser failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.UpdateOrganizationUserResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func CreateDepartmentMember(c *gin.Context) { + params := api.CreateDepartmentMemberReq{UserInDepartment: &open_im_sdk.UserInDepartment{}} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.CreateDepartmentMemberReq{UserInDepartment: &open_im_sdk.UserInDepartment{}} + utils.CopyStructFields(req, ¶ms) + utils.CopyStructFields(req.UserInDepartment, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.CreateDepartmentMember(context.Background(), req) + if err != nil { + errMsg := "rpc CreateDepartmentMember failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.CreateDepartmentMemberResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func GetUserInDepartment(c *gin.Context) { + params := api.GetUserInDepartmentReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.GetUserInDepartmentReq{} + utils.CopyStructFields(req, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.GetUserInDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc GetUserInDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.GetUserInDepartmentResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, UserInDepartment: RpcResp.UserInDepartment} + apiResp.Data = jsonData.JsonDataOne(RpcResp.UserInDepartment) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func UpdateUserInDepartment(c *gin.Context) { + params := api.UpdateUserInDepartmentReq{DepartmentMember: &open_im_sdk.DepartmentMember{}} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.UpdateUserInDepartmentReq{DepartmentMember: &open_im_sdk.DepartmentMember{}} + utils.CopyStructFields(req, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.UpdateUserInDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc UpdateUserInDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.UpdateUserInDepartmentResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func DeleteOrganizationUser(c *gin.Context) { + params := api.DeleteOrganizationUserReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.DeleteOrganizationUserReq{} + utils.CopyStructFields(req, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.DeleteOrganizationUser(context.Background(), req) + if err != nil { + errMsg := "rpc DeleteOrganizationUser failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.DeleteOrganizationUserResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func GetDepartmentMember(c *gin.Context) { + params := api.GetDepartmentMemberReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + + req := &rpc.GetDepartmentMemberReq{} + utils.CopyStructFields(req, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.GetDepartmentMember(context.Background(), req) + if err != nil { + errMsg := "rpc GetDepartmentMember failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.GetDepartmentMemberResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}, UserInDepartmentList: RpcResp.UserInDepartmentList} + apiResp.Data = jsonData.JsonDataList(RpcResp.UserInDepartmentList) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} + +func DeleteUserInDepartment(c *gin.Context) { + params := api.DeleteUserInDepartmentReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.DeleteUserInDepartmentReq{} + utils.CopyStructFields(req, ¶ms) + + err, opUserID := token_verify.ParseTokenGetUserID(c.Request.Header.Get("token"), req.OperationID) + req.OpUserID = opUserID + if err != nil { + errMsg := "ParseTokenGetUserID failed " + err.Error() + c.Request.Header.Get("token") + log.NewError(req.OperationID, errMsg, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api args ", req.String(), "params", params) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOrganizationName) + client := rpc.NewOrganizationClient(etcdConn) + RpcResp, err := client.DeleteUserInDepartment(context.Background(), req) + if err != nil { + errMsg := "rpc DeleteUserInDepartment failed " + err.Error() + req.String() + log.NewError(req.OperationID, errMsg) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg}) + return + } + + apiResp := api.GetDepartmentMemberResp{CommResp: api.CommResp{ErrCode: RpcResp.ErrCode, ErrMsg: RpcResp.ErrMsg}} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "api return ", apiResp) + c.JSON(http.StatusOK, apiResp) +} diff --git a/internal/api/third/ali_oss_credential.go b/internal/api/third/ali_oss_credential.go new file mode 100644 index 000000000..6f5bc7c04 --- /dev/null +++ b/internal/api/third/ali_oss_credential.go @@ -0,0 +1,95 @@ +package apiThird + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "fmt" + openapi "github.com/alibabacloud-go/darabonba-openapi/client" + sts20150401 "github.com/alibabacloud-go/sts-20150401/client" + "github.com/alibabacloud-go/tea/tea" + "github.com/fatih/structs" + + //"github.com/fatih/structs" + "github.com/gin-gonic/gin" + "net/http" + "time" +) + +var stsClient *sts20150401.Client + +/** + * 使用AK&SK初始化账号Client + * @param accessKeyId + * @param accessKeySecret + * @return Client + * @throws Exception + */ +func getStsClient() *sts20150401.Client { + if stsClient != nil { + return stsClient + } + conf := &openapi.Config{ + // 您的AccessKey ID + AccessKeyId: tea.String(config.Config.Credential.Ali.AccessKeyID), + // 您的AccessKey Secret + AccessKeySecret: tea.String(config.Config.Credential.Ali.AccessKeySecret), + // Endpoint + Endpoint: tea.String(config.Config.Credential.Ali.StsEndpoint), + } + result, err := sts20150401.NewClient(conf) + if err != nil { + log.NewError("", "alists client初始化失败 ", err) + } + stsClient = result + return stsClient +} + +func AliOSSCredential(c *gin.Context) { + req := api.OSSCredentialReq{} + if err := c.BindJSON(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "AliOSSCredential args ", userID) + + stsResp, err := getStsClient().AssumeRole(&sts20150401.AssumeRoleRequest{ + DurationSeconds: tea.Int64(config.Config.Credential.Ali.StsDurationSeconds), + Policy: nil, + RoleArn: tea.String(config.Config.Credential.Ali.OssRoleArn), + RoleSessionName: tea.String(fmt.Sprintf("%s-%d", userID, time.Now().Unix())), + }) + + resp := api.OSSCredentialResp{} + if err != nil { + resp.ErrCode = constant.ErrTencentCredential.ErrCode + resp.ErrMsg = err.Error() + } else { + resp = api.OSSCredentialResp{ + CommResp: api.CommResp{}, + OssData: api.OSSCredentialRespData{ + Endpoint: config.Config.Credential.Ali.OssEndpoint, + AccessKeyId: *stsResp.Body.Credentials.AccessKeyId, + AccessKeySecret: *stsResp.Body.Credentials.AccessKeySecret, + Token: *stsResp.Body.Credentials.SecurityToken, + Bucket: config.Config.Credential.Ali.Bucket, + FinalHost: config.Config.Credential.Ali.FinalHost, + }, + Data: nil, + } + } + + resp.Data = structs.Map(&resp.OssData) + log.NewInfo(req.OperationID, "AliOSSCredential return ", resp) + + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/third/minio_init.go b/internal/api/third/minio_init.go new file mode 100644 index 000000000..b3d66b934 --- /dev/null +++ b/internal/api/third/minio_init.go @@ -0,0 +1,67 @@ +package apiThird + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "context" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + url2 "net/url" +) + +var ( + minioClient *minio.Client +) + +func MinioInit() { + operationID := utils.OperationIDGenerator() + log.NewInfo(operationID, utils.GetSelfFuncName(), "minio config: ", config.Config.Credential.Minio) + var initUrl string + if config.Config.Credential.Minio.EndpointInnerEnable { + initUrl = config.Config.Credential.Minio.EndpointInner + } else { + initUrl = config.Config.Credential.Minio.Endpoint + } + log.NewInfo(operationID, utils.GetSelfFuncName(), "use initUrl: ", initUrl) + minioUrl, err := url2.Parse(initUrl) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "parse failed, please check config/config.yaml", err.Error()) + return + } + log.NewInfo(operationID, utils.GetSelfFuncName(), "Parse ok ", config.Config.Credential.Minio) + minioClient, err = minio.New(minioUrl.Host, &minio.Options{ + Creds: credentials.NewStaticV4(config.Config.Credential.Minio.AccessKeyID, config.Config.Credential.Minio.SecretAccessKey, ""), + Secure: false, + }) + log.NewInfo(operationID, utils.GetSelfFuncName(), "new ok ", config.Config.Credential.Minio) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "init minio client failed", err.Error()) + return + } + opt := minio.MakeBucketOptions{ + Region: config.Config.Credential.Minio.Location, + ObjectLocking: false, + } + err = minioClient.MakeBucket(context.Background(), config.Config.Credential.Minio.Bucket, opt) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "MakeBucket failed ", err.Error()) + exists, err := minioClient.BucketExists(context.Background(), config.Config.Credential.Minio.Bucket) + if err == nil && exists { + log.NewWarn(operationID, utils.GetSelfFuncName(), "We already own ", config.Config.Credential.Minio.Bucket) + } else { + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), err.Error()) + } + log.NewError(operationID, utils.GetSelfFuncName(), "create bucket failed and bucket not exists") + return + } + } + // 自动化桶public的代码 + //err = minioClient.SetBucketPolicy(context.Background(), config.Config.Credential.Minio.Bucket, policy.BucketPolicyReadWrite) + //if err != nil { + // log.NewError("", utils.GetSelfFuncName(), "SetBucketPolicy failed please set in web", err.Error()) + // return + //} + log.NewInfo(operationID, utils.GetSelfFuncName(), "minio create and set policy success") +} diff --git a/internal/api/third/minio_storage_credential.go b/internal/api/third/minio_storage_credential.go new file mode 100644 index 000000000..f9f4c078d --- /dev/null +++ b/internal/api/third/minio_storage_credential.go @@ -0,0 +1,138 @@ +package apiThird + +import ( + apiStruct "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + _ "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "github.com/minio/minio-go/v7" + _ "github.com/minio/minio-go/v7" + cr "github.com/minio/minio-go/v7/pkg/credentials" + "net/http" +) + +func MinioUploadFile(c *gin.Context) { + var ( + req apiStruct.MinioUploadFileReq + resp apiStruct.MinioUploadFileResp + ) + defer func() { + if r := recover(); r != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), r) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "missing file or snapShot args"}) + return + } + }() + if err := c.Bind(&req); err != nil { + log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + ok, _ := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError("", utils.GetSelfFuncName(), "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req) + switch req.FileType { + // videoType upload snapShot + case constant.VideoType: + snapShotFile, err := c.FormFile("snapShot") + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "missing snapshot arg: " + err.Error()}) + return + } + snapShotFileObj, err := snapShotFile.Open() + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "Open file error", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + snapShotNewName, snapShotNewType := utils.GetNewFileNameAndContentType(snapShotFile.Filename, constant.ImageType) + log.Debug(req.OperationID, utils.GetSelfFuncName(), snapShotNewName, snapShotNewType) + _, err = minioClient.PutObject(context.Background(), config.Config.Credential.Minio.Bucket, snapShotNewName, snapShotFileObj, snapShotFile.Size, minio.PutObjectOptions{ContentType: snapShotNewType}) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "PutObject snapShotFile error", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + resp.SnapshotURL = config.Config.Credential.Minio.Endpoint + "/" + config.Config.Credential.Minio.Bucket + "/" + snapShotNewName + resp.SnapshotNewName = snapShotNewName + } + file, err := c.FormFile("file") + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "missing file arg: " + err.Error()}) + return + } + fileObj, err := file.Open() + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "Open file error", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "invalid file path" + err.Error()}) + return + } + newName, newType := utils.GetNewFileNameAndContentType(file.Filename, req.FileType) + log.Debug(req.OperationID, utils.GetSelfFuncName(), newName, newType) + _, err = minioClient.PutObject(context.Background(), config.Config.Credential.Minio.Bucket, newName, fileObj, file.Size, minio.PutObjectOptions{ContentType: newType}) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "open file error") + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "invalid file path" + err.Error()}) + return + } + resp.NewName = newName + resp.URL = config.Config.Credential.Minio.Endpoint + "/" + config.Config.Credential.Minio.Bucket + "/" + newName + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp) + c.JSON(http.StatusOK, gin.H{"errCode": 0, "errMsg": "", "data": resp}) + return +} + +func MinioStorageCredential(c *gin.Context) { + var ( + req apiStruct.MinioStorageCredentialReq + resp apiStruct.MiniostorageCredentialResp + ) + if err := c.BindJSON(&req); err != nil { + log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + ok, _ := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError("", utils.GetSelfFuncName(), "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + var stsOpts cr.STSAssumeRoleOptions + stsOpts.AccessKey = config.Config.Credential.Minio.AccessKeyID + stsOpts.SecretKey = config.Config.Credential.Minio.SecretAccessKey + stsOpts.DurationSeconds = constant.MinioDurationTimes + var endpoint string + if config.Config.Credential.Minio.EndpointInnerEnable { + endpoint = config.Config.Credential.Minio.EndpointInner + } else { + endpoint = config.Config.Credential.Minio.Endpoint + } + li, err := cr.NewSTSAssumeRole(endpoint, stsOpts) + if err != nil { + log.NewError("", utils.GetSelfFuncName(), "NewSTSAssumeRole failed", err.Error(), stsOpts, config.Config.Credential.Minio.Endpoint) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + v, err := li.Get() + if err != nil { + log.NewError("0", utils.GetSelfFuncName(), "li.Get error", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + resp.SessionToken = v.SessionToken + resp.SecretAccessKey = v.SecretAccessKey + resp.AccessKeyID = v.AccessKeyID + resp.BucketName = config.Config.Credential.Minio.Bucket + resp.StsEndpointURL = config.Config.Credential.Minio.Endpoint + c.JSON(http.StatusOK, gin.H{"errCode": 0, "errMsg": "", "data": resp}) +} diff --git a/internal/api/third/tencent_cloud_storage_credential.go b/internal/api/third/tencent_cloud_storage_credential.go new file mode 100644 index 000000000..ed293791e --- /dev/null +++ b/internal/api/third/tencent_cloud_storage_credential.go @@ -0,0 +1,72 @@ +package apiThird + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "github.com/fatih/structs" + + //"github.com/fatih/structs" + "github.com/gin-gonic/gin" + sts "github.com/tencentyun/qcloud-cos-sts-sdk/go" + "net/http" + "time" +) + +func TencentCloudStorageCredential(c *gin.Context) { + req := api.TencentCloudStorageCredentialReq{} + if err := c.BindJSON(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(req.OperationID, "TencentCloudStorageCredential args ", userID) + + cli := sts.NewClient( + config.Config.Credential.Tencent.SecretID, + config.Config.Credential.Tencent.SecretKey, + nil, + ) + + opt := &sts.CredentialOptions{ + DurationSeconds: int64(time.Hour.Seconds()), + Region: config.Config.Credential.Tencent.Region, + Policy: &sts.CredentialPolicy{ + Statement: []sts.CredentialPolicyStatement{ + { + Action: []string{ + "name/cos:PostObject", + "name/cos:PutObject", + }, + Effect: "allow", + Resource: []string{ + "qcs::cos:" + config.Config.Credential.Tencent.Region + ":uid/" + config.Config.Credential.Tencent.AppID + ":" + config.Config.Credential.Tencent.Bucket + "/*", + }, + }, + }, + }, + } + res, err := cli.GetCredential(opt) + resp := api.TencentCloudStorageCredentialResp{} + if err != nil { + resp.ErrCode = constant.ErrTencentCredential.ErrCode + resp.ErrMsg = err.Error() + } else { + resp.CosData.Bucket = config.Config.Credential.Tencent.Bucket + resp.CosData.Region = config.Config.Credential.Tencent.Region + resp.CosData.CredentialResult = res + } + + resp.Data = structs.Map(&resp.CosData) + log.NewInfo(req.OperationID, "TencentCloudStorageCredential return ", resp) + + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/user/user.go b/internal/api/user/user.go new file mode 100644 index 000000000..1756a9f8d --- /dev/null +++ b/internal/api/user/user.go @@ -0,0 +1,129 @@ +package user + +import ( + jsonData "Open_IM/internal/utils" + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + rpc "Open_IM/pkg/proto/user" + "Open_IM/pkg/utils" + "context" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func GetUsersInfo(c *gin.Context) { + params := api.GetUsersInfoReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": http.StatusBadRequest, "errMsg": err.Error()}) + return + } + req := &rpc.GetUserInfoReq{} + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "GetUserInfo args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := rpc.NewUserClient(etcdConn) + RpcResp, err := client.GetUserInfo(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetUserInfo failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + var publicUserInfoList []*open_im_sdk.PublicUserInfo + for _, v := range RpcResp.UserInfoList { + publicUserInfoList = append(publicUserInfoList, + &open_im_sdk.PublicUserInfo{UserID: v.UserID, Nickname: v.Nickname, FaceURL: v.FaceURL, Gender: v.Gender, Ex: v.Ex}) + } + + resp := api.GetUsersInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}, UserInfoList: publicUserInfoList} + resp.Data = jsonData.JsonDataList(resp.UserInfoList) + log.NewInfo(req.OperationID, "GetUserInfo api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func UpdateUserInfo(c *gin.Context) { + params := api.UpdateSelfUserInfoReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()}) + return + } + req := &rpc.UpdateUserInfoReq{UserInfo: &open_im_sdk.UserInfo{}} + utils.CopyStructFields(req.UserInfo, ¶ms) + + req.OperationID = params.OperationID + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + log.NewInfo(params.OperationID, "UpdateUserInfo args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := rpc.NewUserClient(etcdConn) + RpcResp, err := client.UpdateUserInfo(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "UpdateUserInfo failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + resp := api.UpdateUserInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, "UpdateUserInfo api return ", resp) + c.JSON(http.StatusOK, resp) +} + +func GetSelfUserInfo(c *gin.Context) { + params := api.GetSelfUserInfoReq{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": http.StatusBadRequest, "errMsg": err.Error()}) + return + } + req := &rpc.GetUserInfoReq{} + + utils.CopyStructFields(req, ¶ms) + var ok bool + ok, req.OpUserID = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID) + if !ok { + log.NewError(req.OperationID, "GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "GetUserIDFromToken failed"}) + return + } + req.UserIDList = append(req.UserIDList, req.OpUserID) + log.NewInfo(params.OperationID, "GetUserInfo args ", req.String()) + + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := rpc.NewUserClient(etcdConn) + RpcResp, err := client.GetUserInfo(context.Background(), req) + if err != nil { + log.NewError(req.OperationID, "GetUserInfo failed ", err.Error(), req.String()) + c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "call rpc server failed"}) + return + } + if len(RpcResp.UserInfoList) == 1 { + resp := api.GetSelfUserInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}, UserInfo: RpcResp.UserInfoList[0]} + resp.Data = jsonData.JsonDataOne(resp.UserInfo) + log.NewInfo(req.OperationID, "GetUserInfo api return ", resp) + c.JSON(http.StatusOK, resp) + } else { + resp := api.GetSelfUserInfoResp{CommResp: api.CommResp{ErrCode: RpcResp.CommonResp.ErrCode, ErrMsg: RpcResp.CommonResp.ErrMsg}} + log.NewInfo(req.OperationID, "GetUserInfo api return ", resp) + c.JSON(http.StatusOK, resp) + } + +} diff --git a/internal/cms_api/admin/admin.go b/internal/cms_api/admin/admin.go new file mode 100644 index 000000000..02b2390c5 --- /dev/null +++ b/internal/cms_api/admin/admin.go @@ -0,0 +1,42 @@ +package admin + +import ( + "Open_IM/pkg/cms_api_struct" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + openIMHttp "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbAdmin "Open_IM/pkg/proto/admin_cms" + "Open_IM/pkg/utils" + "context" + "strings" + + "github.com/gin-gonic/gin" +) + +// register +func AdminLogin(c *gin.Context) { + var ( + req cms_api_struct.AdminLoginRequest + resp cms_api_struct.AdminLoginResponse + reqPb pbAdmin.AdminLoginReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewInfo("0", utils.GetSelfFuncName(), err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.Secret = req.Secret + reqPb.AdminID = req.AdminName + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImAdminCMSName) + client := pbAdmin.NewAdminCMSClient(etcdConn) + respPb, err := client.AdminLogin(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "rpc failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + resp.Token = respPb.Token + openIMHttp.RespHttp200(c, constant.OK, resp) +} diff --git a/internal/cms_api/group/group.go b/internal/cms_api/group/group.go new file mode 100644 index 000000000..740fd5821 --- /dev/null +++ b/internal/cms_api/group/group.go @@ -0,0 +1,450 @@ +package group + +import ( + "Open_IM/pkg/cms_api_struct" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + openIMHttp "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + commonPb "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "strings" + + pbGroup "Open_IM/pkg/proto/group" + + "github.com/gin-gonic/gin" +) + +func GetGroupById(c *gin.Context) { + var ( + req cms_api_struct.GetGroupByIdRequest + resp cms_api_struct.GetGroupByIdResponse + reqPb pbGroup.GetGroupByIdReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + respPb, err := client.GetGroupById(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetGroupById failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + resp.GroupName = respPb.CMSGroup.GroupInfo.GroupName + resp.GroupID = respPb.CMSGroup.GroupInfo.GroupID + resp.CreateTime = (utils.UnixSecondToTime(int64(respPb.CMSGroup.GroupInfo.CreateTime))).String() + resp.ProfilePhoto = respPb.CMSGroup.GroupInfo.FaceURL + resp.GroupMasterName = respPb.CMSGroup.GroupMasterName + resp.GroupMasterId = respPb.CMSGroup.GroupMasterId + resp.IsBanChat = constant.GroupIsBanChat(respPb.CMSGroup.GroupInfo.Status) + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetGroups(c *gin.Context) { + var ( + req cms_api_struct.GetGroupsRequest + resp cms_api_struct.GetGroupsResponse + reqPb pbGroup.GetGroupsReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.Pagination = &commonPb.RequestPagination{} + utils.CopyStructFields(&reqPb.Pagination, req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + respPb, err := client.GetGroups(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetUserInfo failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + for _, v := range respPb.CMSGroups { + resp.Groups = append(resp.Groups, cms_api_struct.GroupResponse{ + GroupName: v.GroupInfo.GroupName, + GroupID: v.GroupInfo.GroupID, + GroupMasterName: v.GroupMasterName, + GroupMasterId: v.GroupMasterId, + CreateTime: (utils.UnixSecondToTime(int64(v.GroupInfo.CreateTime))).String(), + IsBanChat: constant.GroupIsBanChat(v.GroupInfo.Status), + IsBanPrivateChat: false, + ProfilePhoto: v.GroupInfo.FaceURL, + }) + } + resp.GroupNums = int(respPb.GroupNum) + resp.CurrentPage = int(respPb.Pagination.PageNumber) + resp.ShowNumber = int(respPb.Pagination.ShowNumber) + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetGroupByName(c *gin.Context) { + var ( + req cms_api_struct.GetGroupRequest + resp cms_api_struct.GetGroupResponse + reqPb pbGroup.GetGroupReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupName = req.GroupName + reqPb.Pagination = &commonPb.RequestPagination{} + utils.CopyStructFields(&reqPb.Pagination, req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + respPb, err := client.GetGroup(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetGroup failed", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrServer, nil) + return + } + for _, v := range respPb.CMSGroups { + resp.Groups = append(resp.Groups, cms_api_struct.GroupResponse{ + GroupName: v.GroupInfo.GroupName, + GroupID: v.GroupInfo.GroupID, + GroupMasterName: v.GroupMasterName, + GroupMasterId: v.GroupMasterId, + CreateTime: (utils.UnixSecondToTime(int64(v.GroupInfo.CreateTime))).String(), + IsBanChat: constant.GroupIsBanChat(v.GroupInfo.Status), + IsBanPrivateChat: false, + ProfilePhoto: v.GroupInfo.FaceURL, + }) + } + resp.CurrentPage = int(respPb.Pagination.PageNumber) + resp.ShowNumber = int(respPb.Pagination.ShowNumber) + resp.GroupNums = int(respPb.GroupNums) + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func CreateGroup(c *gin.Context) { + var ( + req cms_api_struct.CreateGroupRequest + _ cms_api_struct.CreateGroupResponse + reqPb pbGroup.CreateGroupReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupInfo = &commonPb.GroupInfo{} + reqPb.GroupInfo.GroupName = req.GroupName + reqPb.GroupInfo.CreatorUserID = req.GroupMasterId + reqPb.OwnerUserID = req.GroupMasterId + reqPb.OpUserID = req.GroupMasterId + for _, v := range req.GroupMembers { + reqPb.InitMemberList = append(reqPb.InitMemberList, &pbGroup.GroupAddMemberInfo{ + UserID: v, + RoleLevel: 1, + }) + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.CreateGroup(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "CreateGroup failed", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrServer, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func BanGroupChat(c *gin.Context) { + var ( + req cms_api_struct.BanGroupChatRequest + reqPb pbGroup.OperateGroupStatusReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + reqPb.Status = constant.GroupBanChat + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.OperateGroupStatus(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BanGroupChat failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) + +} + +func BanPrivateChat(c *gin.Context) { + var ( + req cms_api_struct.BanPrivateChatRequest + reqPb pbGroup.OperateGroupStatusReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + reqPb.Status = constant.GroupBanPrivateChat + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.OperateGroupStatus(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "OperateGroupStatus failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func OpenGroupChat(c *gin.Context) { + var ( + req cms_api_struct.BanPrivateChatRequest + reqPb pbGroup.OperateGroupStatusReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + reqPb.Status = constant.GroupOk + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.OperateGroupStatus(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "OperateGroupStatus failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func OpenPrivateChat(c *gin.Context) { + var ( + req cms_api_struct.BanPrivateChatRequest + reqPb pbGroup.OperateGroupStatusReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "OpenPrivateChat failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + reqPb.Status = constant.GroupOk + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.OperateGroupStatus(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "OperateGroupStatus failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func GetGroupMembers(c *gin.Context) { + var ( + req cms_api_struct.GetGroupMembersRequest + reqPb pbGroup.GetGroupMembersCMSReq + resp cms_api_struct.GetGroupMembersResponse + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.Pagination = &commonPb.RequestPagination{ + PageNumber: int32(req.PageNumber), + ShowNumber: int32(req.ShowNumber), + } + reqPb.GroupId = req.GroupId + reqPb.UserName = req.UserName + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + respPb, err := client.GetGroupMembersCMS(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetGroupMembersCMS failed:", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + resp.ResponsePagination = cms_api_struct.ResponsePagination{ + CurrentPage: int(respPb.Pagination.CurrentPage), + ShowNumber: int(respPb.Pagination.ShowNumber), + } + resp.MemberNums = int(respPb.MemberNums) + for _, groupMembers := range respPb.Members { + resp.GroupMembers = append(resp.GroupMembers, cms_api_struct.GroupMemberResponse{ + MemberPosition: int(groupMembers.RoleLevel), + MemberNickName: groupMembers.Nickname, + MemberId: groupMembers.UserID, + JoinTime: utils.UnixSecondToTime(int64(groupMembers.JoinTime)).String(), + }) + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func AddGroupMembers(c *gin.Context) { + var ( + req cms_api_struct.RemoveGroupMembersRequest + resp cms_api_struct.RemoveGroupMembersResponse + reqPb pbGroup.AddGroupMembersCMSReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationId, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.UserIds = req.Members + reqPb.GroupId = req.GroupId + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + respPb, err := client.AddGroupMembersCMS(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationId, utils.GetSelfFuncName(), "AddGroupMembersCMS failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + resp.Success = respPb.Success + resp.Failed = respPb.Failed + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func RemoveGroupMembers(c *gin.Context) { + var ( + req cms_api_struct.RemoveGroupMembersRequest + resp cms_api_struct.RemoveGroupMembersResponse + reqPb pbGroup.RemoveGroupMembersCMSReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.UserIds = req.Members + reqPb.GroupId = req.GroupId + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + respPb, err := client.RemoveGroupMembersCMS(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "RemoveGroupMembersCMS failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + resp.Success = respPb.Success + resp.Failed = respPb.Failed + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func DeleteGroup(c *gin.Context) { + var ( + req cms_api_struct.DeleteGroupRequest + _ cms_api_struct.DeleteGroupResponse + reqPb pbGroup.DeleteGroupReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.DeleteGroup(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "DeleteGroup failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func SetGroupMaster(c *gin.Context) { + var ( + req cms_api_struct.SetGroupMasterRequest + _ cms_api_struct.SetGroupMasterResponse + reqPb pbGroup.OperateUserRoleReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + reqPb.UserId = req.UserId + reqPb.RoleLevel = constant.GroupOwner + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.OperateUserRole(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "DeleteGroup failed", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrServer, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func SetGroupOrdinaryUsers(c *gin.Context) { + var ( + req cms_api_struct.SetGroupMemberRequest + _ cms_api_struct.AdminLoginResponse + reqPb pbGroup.OperateUserRoleReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.GroupId = req.GroupId + reqPb.UserId = req.UserId + reqPb.RoleLevel = constant.GroupOrdinaryUsers + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.OperateUserRole(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "DeleteGroup failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func AlterGroupInfo(c *gin.Context) { + var ( + req cms_api_struct.AlterGroupInfoRequest + _ cms_api_struct.SetGroupMasterResponse + reqPb pbGroup.SetGroupInfoReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.OpUserID = c.MustGet("userID").(string) + reqPb.GroupInfo = &commonPb.GroupInfo{ + GroupID: req.GroupID, + GroupName: req.GroupName, + Introduction: req.Introduction, + Notification: req.Notification, + FaceURL: req.ProfilePhoto, + GroupType: int32(req.GroupType), + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + _, err := client.SetGroupInfo(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "DeleteGroup failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} diff --git a/internal/cms_api/message_cms/message.go b/internal/cms_api/message_cms/message.go new file mode 100644 index 000000000..c5ced390e --- /dev/null +++ b/internal/cms_api/message_cms/message.go @@ -0,0 +1,109 @@ +package messageCMS + +import ( + "Open_IM/pkg/cms_api_struct" + "Open_IM/pkg/common/config" + openIMHttp "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbMessage "Open_IM/pkg/proto/message_cms" + pbCommon "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "strings" + + "Open_IM/pkg/common/constant" + + "github.com/gin-gonic/gin" +) + +func BroadcastMessage(c *gin.Context) { + var ( + reqPb pbMessage.BoradcastMessageReq + ) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMessageCMSName) + client := pbMessage.NewMessageCMSClient(etcdConn) + _, err := client.BoradcastMessage(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetChatLogs rpc failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func MassSendMassage(c *gin.Context) { + var ( + reqPb pbMessage.MassSendMessageReq + ) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMessageCMSName) + client := pbMessage.NewMessageCMSClient(etcdConn) + _, err := client.MassSendMessage(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetChatLogs rpc failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func WithdrawMessage(c *gin.Context) { + var ( + reqPb pbMessage.WithdrawMessageReq + ) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMessageCMSName) + client := pbMessage.NewMessageCMSClient(etcdConn) + _, err := client.WithdrawMessage(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetChatLogs rpc failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func GetChatLogs(c *gin.Context) { + var ( + req cms_api_struct.GetChatLogsRequest + resp cms_api_struct.GetChatLogsResponse + reqPb pbMessage.GetChatLogsReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, resp) + return + } + reqPb.Pagination = &pbCommon.RequestPagination{ + PageNumber: int32(req.PageNumber), + ShowNumber: int32(req.ShowNumber), + } + utils.CopyStructFields(&reqPb, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMessageCMSName) + client := pbMessage.NewMessageCMSClient(etcdConn) + respPb, err := client.GetChatLogs(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetChatLogs rpc failed", err.Error()) + openIMHttp.RespHttp200(c, err, resp) + return + } + //utils.CopyStructFields(&resp, &respPb) + for _, chatLog := range respPb.ChatLogs { + resp.ChatLogs = append(resp.ChatLogs, cms_api_struct.ChatLog{ + SessionType: int(chatLog.SessionType), + ContentType: int(chatLog.ContentType), + SenderNickName: chatLog.SenderNickName, + SenderId: chatLog.SenderId, + SearchContent: chatLog.SearchContent, + WholeContent: chatLog.WholeContent, + ReceiverNickName: chatLog.ReciverNickName, + ReceiverID: chatLog.ReciverId, + GroupName: chatLog.GroupName, + GroupId: chatLog.GroupId, + Date: chatLog.Date, + }) + } + resp.ShowNumber = int(respPb.Pagination.ShowNumber) + resp.CurrentPage = int(respPb.Pagination.CurrentPage) + resp.ChatLogsNum = int(respPb.ChatLogsNum) + openIMHttp.RespHttp200(c, constant.OK, resp) +} diff --git a/internal/cms_api/middleware/cors.go b/internal/cms_api/middleware/cors.go new file mode 100644 index 000000000..139a001af --- /dev/null +++ b/internal/cms_api/middleware/cors.go @@ -0,0 +1,23 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "net/http" +) + +func CorsHandler() gin.HandlerFunc { + return func(context *gin.Context) { + context.Writer.Header().Set("Access-Control-Allow-Origin", "*") + context.Header("Access-Control-Allow-Methods", "*") + context.Header("Access-Control-Allow-Headers", "*") + context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析 + context.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒 + context.Header("Access-Control-Allow-Credentials", "false") // 跨域请求是否需要带cookie信息 默认设置为true + context.Header("content-type", "application/json") // 设置返回格式是json + //Release all option pre-requests + if context.Request.Method == http.MethodOptions { + context.JSON(http.StatusOK, "Options Request!") + } + context.Next() + } +} diff --git a/internal/cms_api/middleware/jwt_auth.go b/internal/cms_api/middleware/jwt_auth.go new file mode 100644 index 000000000..a6f1af993 --- /dev/null +++ b/internal/cms_api/middleware/jwt_auth.go @@ -0,0 +1,24 @@ +package middleware + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/utils" + "github.com/gin-gonic/gin" +) + +func JWTAuth() gin.HandlerFunc { + return func(c *gin.Context) { + ok, userID := token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), "") + log.NewInfo("0", utils.GetSelfFuncName(), "userID: ", userID) + c.Set("userID", userID) + if !ok { + log.NewError("","GetUserIDFromToken false ", c.Request.Header.Get("token")) + c.Abort() + http.RespHttp200(c, constant.ErrParseToken, nil) + return + } + } +} diff --git a/internal/cms_api/organization/organization.go b/internal/cms_api/organization/organization.go new file mode 100644 index 000000000..f775283ca --- /dev/null +++ b/internal/cms_api/organization/organization.go @@ -0,0 +1,49 @@ +package organization + +import ( + "github.com/gin-gonic/gin" +) + +func GetStaffs(c *gin.Context) { + +} + +func GetOrganizations(c *gin.Context) { + +} + +func GetSquads(c *gin.Context) { + +} + +func AlterStaff(c *gin.Context) { + +} + +func AddOrganization(c *gin.Context) { + +} + +func InquireOrganization(g *gin.Context) { + +} + +func AlterOrganization(c *gin.Context) { + +} + +func DeleteOrganization(g *gin.Context) { + +} + +func GetOrganizationSquads(c *gin.Context) { + +} + +func AlterStaffsInfo(c *gin.Context) { + +} + +func AddChildOrganization(c *gin.Context) { + +} diff --git a/internal/cms_api/router.go b/internal/cms_api/router.go new file mode 100644 index 000000000..941cc5bf5 --- /dev/null +++ b/internal/cms_api/router.go @@ -0,0 +1,95 @@ +package cms_api + +import ( + "Open_IM/internal/cms_api/admin" + "Open_IM/internal/cms_api/group" + messageCMS "Open_IM/internal/cms_api/message_cms" + "Open_IM/internal/cms_api/middleware" + "Open_IM/internal/cms_api/organization" + "Open_IM/internal/cms_api/statistics" + "Open_IM/internal/cms_api/user" + + "github.com/gin-gonic/gin" +) + +func NewGinRouter() *gin.Engine { + gin.SetMode(gin.ReleaseMode) + baseRouter := gin.Default() + router := baseRouter.Group("/api") + router.Use(middleware.CorsHandler()) + adminRouterGroup := router.Group("/admin") + { + adminRouterGroup.POST("/login", admin.AdminLogin) + } + r2 := router.Group("") + r2.Use(middleware.JWTAuth()) + statisticsRouterGroup := r2.Group("/statistics") + { + statisticsRouterGroup.GET("/get_messages_statistics", statistics.GetMessagesStatistics) + statisticsRouterGroup.GET("/get_user_statistics", statistics.GetUserStatistics) + statisticsRouterGroup.GET("/get_group_statistics", statistics.GetGroupStatistics) + statisticsRouterGroup.GET("/get_active_user", statistics.GetActiveUser) + statisticsRouterGroup.GET("/get_active_group", statistics.GetActiveGroup) + } + organizationRouterGroup := r2.Group("/organization") + { + organizationRouterGroup.GET("/get_staffs", organization.GetStaffs) + organizationRouterGroup.GET("/get_organizations", organization.GetOrganizations) + organizationRouterGroup.GET("/get_squad", organization.GetSquads) + organizationRouterGroup.POST("/add_organization", organization.AddOrganization) + organizationRouterGroup.POST("/alter_staff", organization.AlterStaff) + organizationRouterGroup.GET("/inquire_organization", organization.InquireOrganization) + organizationRouterGroup.POST("/alter_organization", organization.AlterOrganization) + organizationRouterGroup.POST("/delete_organization", organization.DeleteOrganization) + organizationRouterGroup.POST("/get_organization_squad", organization.GetOrganizationSquads) + organizationRouterGroup.PATCH("/alter_corps_info", organization.AlterStaffsInfo) + organizationRouterGroup.POST("/add_child_org", organization.AddChildOrganization) + } + groupRouterGroup := r2.Group("/group") + { + groupRouterGroup.GET("/get_group_by_id", group.GetGroupById) + groupRouterGroup.GET("/get_groups", group.GetGroups) + groupRouterGroup.GET("/get_group_by_name", group.GetGroupByName) + groupRouterGroup.GET("/get_group_members", group.GetGroupMembers) + groupRouterGroup.POST("/create_group", group.CreateGroup) + groupRouterGroup.POST("/add_members", group.AddGroupMembers) + groupRouterGroup.POST("/remove_members", group.RemoveGroupMembers) + groupRouterGroup.POST("/ban_group_private_chat", group.BanPrivateChat) + groupRouterGroup.POST("/open_group_private_chat", group.OpenPrivateChat) + groupRouterGroup.POST("/ban_group_chat", group.BanGroupChat) + groupRouterGroup.POST("/open_group_chat", group.OpenGroupChat) + groupRouterGroup.POST("/delete_group", group.DeleteGroup) + groupRouterGroup.POST("/get_members_in_group", group.GetGroupMembers) + groupRouterGroup.POST("/set_group_master", group.SetGroupMaster) + groupRouterGroup.POST("/set_group_ordinary_user", group.SetGroupOrdinaryUsers) + groupRouterGroup.POST("/alter_group_info", group.AlterGroupInfo) + } + userRouterGroup := r2.Group("/user") + { + userRouterGroup.POST("/resign", user.ResignUser) + userRouterGroup.GET("/get_user", user.GetUserById) + userRouterGroup.POST("/alter_user", user.AlterUser) + userRouterGroup.GET("/get_users", user.GetUsers) + userRouterGroup.POST("/add_user", user.AddUser) + userRouterGroup.POST("/unblock_user", user.UnblockUser) + userRouterGroup.POST("/block_user", user.BlockUser) + userRouterGroup.GET("/get_block_users", user.GetBlockUsers) + userRouterGroup.GET("/get_block_user", user.GetBlockUserById) + userRouterGroup.POST("/delete_user", user.DeleteUser) + userRouterGroup.GET("/get_users_by_name", user.GetUsersByName) + } + friendRouterGroup := r2.Group("/friend") + { + friendRouterGroup.POST("/get_friends_by_id") + friendRouterGroup.POST("/set_friend") + friendRouterGroup.POST("/remove_friend") + } + messageCMSRouterGroup := r2.Group("/message") + { + messageCMSRouterGroup.GET("/get_chat_logs", messageCMS.GetChatLogs) + messageCMSRouterGroup.POST("/broadcast_message", messageCMS.BroadcastMessage) + messageCMSRouterGroup.POST("/mass_send_message", messageCMS.MassSendMassage) + messageCMSRouterGroup.POST("/withdraw_message", messageCMS.WithdrawMessage) + } + return baseRouter +} diff --git a/internal/cms_api/statistics/statistics.go b/internal/cms_api/statistics/statistics.go new file mode 100644 index 000000000..c8a9488ca --- /dev/null +++ b/internal/cms_api/statistics/statistics.go @@ -0,0 +1,224 @@ +package statistics + +import ( + "Open_IM/pkg/cms_api_struct" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + openIMHttp "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pb "Open_IM/pkg/proto/statistics" + "Open_IM/pkg/utils" + "context" + "strings" + + "github.com/gin-gonic/gin" +) + +func GetMessagesStatistics(c *gin.Context) { + var ( + req cms_api_struct.GetMessageStatisticsRequest + resp cms_api_struct.GetMessageStatisticsResponse + reqPb pb.GetMessageStatisticsReq + ) + reqPb.StatisticsReq = &pb.StatisticsReq{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb.StatisticsReq, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImStatisticsName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetMessageStatistics(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetMessageStatistics failed", err.Error()) + openIMHttp.RespHttp200(c, err, resp) + return + } + // utils.CopyStructFields(&resp, respPb) + resp.GroupMessageNum = int(respPb.GroupMessageNum) + resp.PrivateMessageNum = int(respPb.PrivateMessageNum) + for _, v := range respPb.PrivateMessageNumList { + resp.PrivateMessageNumList = append(resp.PrivateMessageNumList, struct { + Date string "json:\"date\"" + MessageNum int "json:\"message_num\"" + }{ + Date: v.Date, + MessageNum: int(v.Num), + }) + } + for _, v := range respPb.GroupMessageNumList { + resp.GroupMessageNumList = append(resp.GroupMessageNumList, struct { + Date string "json:\"date\"" + MessageNum int "json:\"message_num\"" + }{ + Date: v.Date, + MessageNum: int(v.Num), + }) + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetUserStatistics(c *gin.Context) { + var ( + req cms_api_struct.GetUserStatisticsRequest + resp cms_api_struct.GetUserStatisticsResponse + reqPb pb.GetUserStatisticsReq + ) + reqPb.StatisticsReq = &pb.StatisticsReq{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb.StatisticsReq, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImStatisticsName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetUserStatistics(context.Background(), &reqPb) + if err != nil { + log.NewError("0", utils.GetSelfFuncName(), "GetUserStatistics failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + // utils.CopyStructFields(&resp, respPb) + resp.ActiveUserNum = int(respPb.ActiveUserNum) + resp.IncreaseUserNum = int(respPb.IncreaseUserNum) + resp.TotalUserNum = int(respPb.TotalUserNum) + for _, v := range respPb.ActiveUserNumList { + resp.ActiveUserNumList = append(resp.ActiveUserNumList, struct { + Date string "json:\"date\"" + ActiveUserNum int "json:\"active_user_num\"" + }{ + Date: v.Date, + ActiveUserNum: int(v.Num), + }) + } + for _, v := range respPb.IncreaseUserNumList { + resp.IncreaseUserNumList = append(resp.IncreaseUserNumList, struct { + Date string "json:\"date\"" + IncreaseUserNum int "json:\"increase_user_num\"" + }{ + Date: v.Date, + IncreaseUserNum: int(v.Num), + }) + } + for _, v := range respPb.TotalUserNumList { + resp.TotalUserNumList = append(resp.TotalUserNumList, struct { + Date string "json:\"date\"" + TotalUserNum int "json:\"total_user_num\"" + }{ + Date: v.Date, + TotalUserNum: int(v.Num), + }) + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetGroupStatistics(c *gin.Context) { + var ( + req cms_api_struct.GetGroupStatisticsRequest + resp cms_api_struct.GetGroupStatisticsResponse + reqPb pb.GetGroupStatisticsReq + ) + reqPb.StatisticsReq = &pb.StatisticsReq{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb.StatisticsReq, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImStatisticsName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetGroupStatistics(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetGroupStatistics failed", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + // utils.CopyStructFields(&resp, respPb) + resp.IncreaseGroupNum = int(respPb.GetIncreaseGroupNum()) + resp.TotalGroupNum = int(respPb.GetTotalGroupNum()) + for _, v := range respPb.IncreaseGroupNumList { + resp.IncreaseGroupNumList = append(resp.IncreaseGroupNumList, + struct { + Date string "json:\"date\"" + IncreaseGroupNum int "json:\"increase_group_num\"" + }{ + Date: v.Date, + IncreaseGroupNum: int(v.Num), + }) + } + for _, v := range respPb.TotalGroupNumList { + resp.TotalGroupNumList = append(resp.TotalGroupNumList, + struct { + Date string "json:\"date\"" + TotalGroupNum int "json:\"total_group_num\"" + }{ + Date: v.Date, + TotalGroupNum: int(v.Num), + }) + + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetActiveUser(c *gin.Context) { + var ( + req cms_api_struct.GetActiveUserRequest + resp cms_api_struct.GetActiveUserResponse + reqPb pb.GetActiveUserReq + ) + reqPb.StatisticsReq = &pb.StatisticsReq{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb.StatisticsReq, req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImStatisticsName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetActiveUser(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetActiveUser failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + utils.CopyStructFields(&resp.ActiveUserList, respPb.Users) + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetActiveGroup(c *gin.Context) { + var ( + req cms_api_struct.GetActiveGroupRequest + resp cms_api_struct.GetActiveGroupResponse + reqPb pb.GetActiveGroupReq + ) + reqPb.StatisticsReq = &pb.StatisticsReq{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb.StatisticsReq, req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImStatisticsName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetActiveGroup(context.Background(), &reqPb) + if err != nil { + log.NewError("0", utils.GetSelfFuncName(), "GetActiveGroup failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + for _, group := range respPb.Groups { + resp.ActiveGroupList = append(resp.ActiveGroupList, struct { + GroupName string "json:\"group_name\"" + GroupId string "json:\"group_id\"" + MessageNum int "json:\"message_num\"" + }{ + GroupName: group.GroupName, + GroupId: group.GroupId, + MessageNum: int(group.MessageNum), + }) + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} diff --git a/internal/cms_api/user/user.go b/internal/cms_api/user/user.go new file mode 100644 index 000000000..a0e5dc188 --- /dev/null +++ b/internal/cms_api/user/user.go @@ -0,0 +1,307 @@ +package user + +import ( + "Open_IM/pkg/cms_api_struct" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + openIMHttp "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + commonPb "Open_IM/pkg/proto/sdk_ws" + pb "Open_IM/pkg/proto/user" + "Open_IM/pkg/utils" + "context" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" +) + +func GetUserById(c *gin.Context) { + var ( + req cms_api_struct.GetUserRequest + resp cms_api_struct.GetUserResponse + reqPb pb.GetUserByIdReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetUserById(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + if respPb.User.UserId == "" { + openIMHttp.RespHttp200(c, constant.OK, nil) + return + } + utils.CopyStructFields(&resp, respPb.User) + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetUsersByName(c *gin.Context) { + var ( + req cms_api_struct.GetUsersByNameRequest + resp cms_api_struct.GetUsersByNameResponse + reqPb pb.GetUsersByNameReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.UserName = req.UserName + reqPb.Pagination = &commonPb.RequestPagination{ + PageNumber: int32(req.PageNumber), + ShowNumber: int32(req.ShowNumber), + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetUsersByName(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "rpc", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + utils.CopyStructFields(&resp.Users, respPb.Users) + resp.ShowNumber = int(respPb.Pagination.ShowNumber) + resp.CurrentPage = int(respPb.Pagination.CurrentPage) + resp.UserNums = respPb.UserNums + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetUsers(c *gin.Context) { + var ( + req cms_api_struct.GetUsersRequest + resp cms_api_struct.GetUsersResponse + reqPb pb.GetUsersReq + ) + reqPb.Pagination = &commonPb.RequestPagination{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb.Pagination, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetUsers(context.Background(), &reqPb) + if err != nil { + openIMHttp.RespHttp200(c, err, resp) + return + } + utils.CopyStructFields(&resp.Users, respPb.User) + resp.ShowNumber = int(respPb.Pagination.ShowNumber) + resp.CurrentPage = int(respPb.Pagination.CurrentPage) + resp.UserNums = respPb.UserNums + openIMHttp.RespHttp200(c, constant.OK, resp) + +} + +func ResignUser(c *gin.Context) { + var ( + req cms_api_struct.ResignUserRequest + resp cms_api_struct.ResignUserResponse + reqPb pb.ResignUserReq + ) + if err := c.ShouldBind(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": http.StatusBadRequest, "errMsg": err.Error()}) + return + } + utils.CopyStructFields(&reqPb, &req) + fmt.Println(reqPb.UserId) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + _, err := client.ResignUser(context.Background(), &reqPb) + if err != nil { + openIMHttp.RespHttp200(c, err, resp) + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func AlterUser(c *gin.Context) { + var ( + req cms_api_struct.AlterUserRequest + resp cms_api_struct.AlterUserResponse + reqPb pb.AlterUserReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, resp) + return + } + utils.CopyStructFields(&reqPb, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + _, err := client.AlterUser(context.Background(), &reqPb) + if err != nil { + log.NewError("0", "microserver failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func AddUser(c *gin.Context) { + var ( + req cms_api_struct.AddUserRequest + reqPb pb.AddUserReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + utils.CopyStructFields(&reqPb, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + _, err := client.AddUser(context.Background(), &reqPb) + if err != nil { + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} + +func BlockUser(c *gin.Context) { + var ( + req cms_api_struct.BlockUserRequest + resp cms_api_struct.BlockUserResponse + reqPb pb.BlockUserReq + ) + if err := c.BindJSON(&req); err != nil { + fmt.Println(err) + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, resp) + return + } + utils.CopyStructFields(&reqPb, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + fmt.Println(reqPb) + _, err := client.BlockUser(context.Background(), &reqPb) + if err != nil { + openIMHttp.RespHttp200(c, err, resp) + return + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func UnblockUser(c *gin.Context) { + var ( + req cms_api_struct.UnblockUserRequest + resp cms_api_struct.UnBlockUserResponse + reqPb pb.UnBlockUserReq + ) + if err := c.ShouldBind(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, resp) + return + } + utils.CopyStructFields(&reqPb, &req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + _, err := client.UnBlockUser(context.Background(), &reqPb) + if err != nil { + openIMHttp.RespHttp200(c, err, resp) + return + } + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetBlockUsers(c *gin.Context) { + var ( + req cms_api_struct.GetBlockUsersRequest + resp cms_api_struct.GetBlockUsersResponse + reqPb pb.GetBlockUsersReq + respPb *pb.GetBlockUsersResp + ) + reqPb.Pagination = &commonPb.RequestPagination{} + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "ShouldBindQuery failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, resp) + return + } + utils.CopyStructFields(&reqPb.Pagination, &req) + log.NewInfo(reqPb.OperationID, utils.GetSelfFuncName(), "blockUsers", reqPb.Pagination, req) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetBlockUsers(context.Background(), &reqPb) + if err != nil { + log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "GetBlockUsers rpc", err.Error()) + openIMHttp.RespHttp200(c, err, resp) + return + } + for _, v := range respPb.BlockUsers { + resp.BlockUsers = append(resp.BlockUsers, cms_api_struct.BlockUser{ + UserResponse: cms_api_struct.UserResponse{ + UserId: v.User.UserId, + ProfilePhoto: v.User.ProfilePhoto, + Nickname: v.User.Nickname, + IsBlock: v.User.IsBlock, + CreateTime: v.User.CreateTime, + }, + BeginDisableTime: v.BeginDisableTime, + EndDisableTime: v.EndDisableTime, + }) + } + resp.ShowNumber = int(respPb.Pagination.ShowNumber) + resp.CurrentPage = int(respPb.Pagination.CurrentPage) + resp.UserNums = respPb.UserNums + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func GetBlockUserById(c *gin.Context) { + var ( + req cms_api_struct.GetBlockUserRequest + resp cms_api_struct.GetBlockUserResponse + reqPb pb.GetBlockUserByIdReq + ) + if err := c.ShouldBindQuery(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.UserId = req.UserId + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + respPb, err := client.GetBlockUserById(context.Background(), &reqPb) + if err != nil { + log.NewError("0", "GetBlockUserById rpc failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + resp.EndDisableTime = respPb.BlockUser.EndDisableTime + resp.BeginDisableTime = respPb.BlockUser.BeginDisableTime + utils.CopyStructFields(&resp, respPb.BlockUser.User) + openIMHttp.RespHttp200(c, constant.OK, resp) +} + +func DeleteUser(c *gin.Context) { + var ( + req cms_api_struct.DeleteUserRequest + reqPb pb.DeleteUserReq + ) + if err := c.BindJSON(&req); err != nil { + log.NewError("0", "BindJSON failed ", err.Error()) + openIMHttp.RespHttp200(c, constant.ErrArgs, nil) + return + } + reqPb.UserId = req.UserId + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImUserName) + client := pb.NewUserClient(etcdConn) + _, err := client.DeleteUser(context.Background(), &reqPb) + if err != nil { + log.NewError("0", "DeleteUser rpc failed ", err.Error()) + openIMHttp.RespHttp200(c, err, nil) + return + } + openIMHttp.RespHttp200(c, constant.OK, nil) +} diff --git a/internal/demo/register/login.go b/internal/demo/register/login.go new file mode 100644 index 000000000..e6de926dc --- /dev/null +++ b/internal/demo/register/login.go @@ -0,0 +1,70 @@ +package register + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + http2 "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "encoding/json" + "fmt" + "github.com/gin-gonic/gin" + "net/http" +) + +type ParamsLogin struct { + Email string `json:"email"` + PhoneNumber string `json:"phoneNumber"` + Password string `json:"password"` + Platform int32 `json:"platform"` + OperationID string `json:"operationID" binding:"required"` +} + +func Login(c *gin.Context) { + params := ParamsLogin{} + if err := c.BindJSON(¶ms); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": constant.FormattingError, "errMsg": err.Error()}) + return + } + var account string + if params.Email != "" { + account = params.Email + } else { + account = params.PhoneNumber + } + + r, err := im_mysql_model.GetRegister(account) + if err != nil { + log.NewError(params.OperationID, "user have not register", params.Password, account, err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.NotRegistered, "errMsg": "Mobile phone number is not registered"}) + return + } + if r.Password != params.Password { + log.NewError(params.OperationID, "password err", params.Password, account, r.Password, r.Account) + c.JSON(http.StatusOK, gin.H{"errCode": constant.PasswordErr, "errMsg": "password err"}) + return + } + url := fmt.Sprintf("http://%s:10000/auth/user_token", utils.ServerIP) + openIMGetUserToken := api.UserTokenReq{} + openIMGetUserToken.OperationID = params.OperationID + openIMGetUserToken.Platform = params.Platform + openIMGetUserToken.Secret = config.Config.Secret + openIMGetUserToken.UserID = account + openIMGetUserTokenResp := api.UserTokenResp{} + bMsg, err := http2.Post(url, openIMGetUserToken, 2) + if err != nil { + log.NewError(params.OperationID, "request openIM get user token error", account, "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.GetIMTokenErr, "errMsg": err.Error()}) + return + } + err = json.Unmarshal(bMsg, &openIMGetUserTokenResp) + if err != nil || openIMGetUserTokenResp.ErrCode != 0 { + log.NewError(params.OperationID, "request get user token", account, "err", "") + c.JSON(http.StatusOK, gin.H{"errCode": constant.GetIMTokenErr, "errMsg": ""}) + return + } + c.JSON(http.StatusOK, gin.H{"errCode": constant.NoError, "errMsg": "", "data": openIMGetUserTokenResp.UserToken}) + +} diff --git a/internal/demo/register/reset_password.go b/internal/demo/register/reset_password.go new file mode 100644 index 000000000..b668f4f62 --- /dev/null +++ b/internal/demo/register/reset_password.go @@ -0,0 +1,56 @@ +package register + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "github.com/gin-gonic/gin" + "net/http" +) + +type resetPasswordRequest struct { + VerificationCode string `json:"verificationCode" binding:"required"` + Email string `json:"email"` + PhoneNumber string `json:"phoneNumber"` + NewPassword string `json:"newPassword" binding:"required"` + OperationID string `json:"operationID"` +} + +func ResetPassword(c *gin.Context) { + var ( + req resetPasswordRequest + ) + if err := c.BindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"errCode": constant.FormattingError, "errMsg": err.Error()}) + return + } + var account string + if req.Email != "" { + account = req.Email + } else { + account = req.PhoneNumber + } + if req.VerificationCode != config.Config.Demo.SuperCode { + accountKey := account + "_" + constant.VerificationCodeForResetSuffix + v, err := db.DB.GetAccountCode(accountKey) + if err != nil || v != req.VerificationCode { + log.NewError(req.OperationID, "password Verification code error", account, req.VerificationCode, v) + c.JSON(http.StatusOK, gin.H{"errCode": constant.CodeInvalidOrExpired, "errMsg": "Verification code error!"}) + return + } + } + user, err := im_mysql_model.GetRegister(account) + if err != nil || user.Account == "" { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "get register error", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.NotRegistered, "errMsg": "user not register!"}) + return + } + if err := im_mysql_model.ResetPassword(account, req.NewPassword); err != nil { + c.JSON(http.StatusOK, gin.H{"errCode": constant.ResetPasswordFailed, "errMsg": "reset password failed: "+err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"errCode": constant.NoError, "errMsg": "reset password success"}) +} diff --git a/internal/demo/register/send_code.go b/internal/demo/register/send_code.go new file mode 100644 index 000000000..37e355b46 --- /dev/null +++ b/internal/demo/register/send_code.go @@ -0,0 +1,130 @@ +package register + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "fmt" + openapi "github.com/alibabacloud-go/darabonba-openapi/client" + dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v2/client" + "github.com/alibabacloud-go/tea/tea" + "github.com/gin-gonic/gin" + "gopkg.in/gomail.v2" + "math/rand" + "net/http" + "time" +) + +type paramsVerificationCode struct { + Email string `json:"email"` + PhoneNumber string `json:"phoneNumber"` + OperationID string `json:"operationID" binding:"required"` + UsedFor int `json:"usedFor"` +} + +func SendVerificationCode(c *gin.Context) { + params := paramsVerificationCode{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("", "BindJSON failed", "err:", err.Error(), "phoneNumber", params.PhoneNumber, "email", params.Email) + c.JSON(http.StatusBadRequest, gin.H{"errCode": constant.FormattingError, "errMsg": err.Error()}) + return + } + var account string + if params.Email != "" { + account = params.Email + } else { + account = params.PhoneNumber + } + var accountKey string + if params.UsedFor == 0 { + params.UsedFor = constant.VerificationCodeForRegister + } + switch params.UsedFor { + case constant.VerificationCodeForRegister: + _, err := im_mysql_model.GetRegister(account) + if err == nil { + log.NewError(params.OperationID, "The phone number has been registered", params) + c.JSON(http.StatusOK, gin.H{"errCode": constant.HasRegistered, "errMsg": "The phone number has been registered"}) + return + } + ok, err := db.DB.JudgeAccountEXISTS(account) + if ok || err != nil { + log.NewError(params.OperationID, "The phone number has been registered", params) + c.JSON(http.StatusOK, gin.H{"errCode": constant.RepeatSendCode, "errMsg": "The phone number has been registered"}) + return + } + accountKey = account + "_" + constant.VerificationCodeForRegisterSuffix + + case constant.VerificationCodeForReset: + accountKey = account + "_" + constant.VerificationCodeForResetSuffix + } + rand.Seed(time.Now().UnixNano()) + code := 100000 + rand.Intn(900000) + log.NewInfo(params.OperationID, params.UsedFor,"begin store redis", accountKey, code) + err := db.DB.SetAccountCode(accountKey, code, config.Config.Demo.CodeTTL) + if err != nil { + log.NewError(params.OperationID, "set redis error", accountKey, "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.SmsSendCodeErr, "errMsg": "Enter the superCode directly in the verification code box, SuperCode can be configured in config.xml"}) + return + } + log.NewDebug("", config.Config.Demo) + if params.Email != "" { + m := gomail.NewMessage() + m.SetHeader(`From`, config.Config.Demo.Mail.SenderMail) + m.SetHeader(`To`, []string{account}...) + m.SetHeader(`Subject`, config.Config.Demo.Mail.Title) + m.SetBody(`text/html`, fmt.Sprintf("%d", code)) + if err := gomail.NewDialer(config.Config.Demo.Mail.SmtpAddr, config.Config.Demo.Mail.SmtpPort, config.Config.Demo.Mail.SenderMail, config.Config.Demo.Mail.SenderAuthorizationCode).DialAndSend(m); err != nil { + log.ErrorByKv("send mail error", account, "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.MailSendCodeErr, "errMsg": ""}) + return + } + } else { + client, err := CreateClient(tea.String(config.Config.Demo.AliSMSVerify.AccessKeyID), tea.String(config.Config.Demo.AliSMSVerify.AccessKeySecret)) + if err != nil { + log.NewError(params.OperationID, "create sendSms client err", "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.SmsSendCodeErr, "errMsg": "Enter the superCode directly in the verification code box, SuperCode can be configured in config.xml"}) + return + } + + sendSmsRequest := &dysmsapi20170525.SendSmsRequest{ + PhoneNumbers: tea.String(account), + SignName: tea.String(config.Config.Demo.AliSMSVerify.SignName), + TemplateCode: tea.String(config.Config.Demo.AliSMSVerify.VerificationCodeTemplateCode), + TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%d\"}", code)), + } + + response, err := client.SendSms(sendSmsRequest) + if err != nil { + log.NewError(params.OperationID, "sendSms error", account, "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.SmsSendCodeErr, "errMsg": "Enter the superCode directly in the verification code box, SuperCode can be configured in config.xml"}) + return + } + if *response.Body.Code != "OK" { + log.NewError(params.OperationID, "alibabacloud sendSms error", account, "err", response.Body.Code, response.Body.Message) + c.JSON(http.StatusOK, gin.H{"errCode": constant.SmsSendCodeErr, "errMsg": "Enter the superCode directly in the verification code box, SuperCode can be configured in config.xml"}) + return + } + } + + data := make(map[string]interface{}) + data["account"] = account + c.JSON(http.StatusOK, gin.H{"errCode": constant.NoError, "errMsg": "Verification code has been set!", "data": data}) +} + +func CreateClient(accessKeyId *string, accessKeySecret *string) (result *dysmsapi20170525.Client, err error) { + c := &openapi.Config{ + // 您的AccessKey ID + AccessKeyId: accessKeyId, + // 您的AccessKey Secret + AccessKeySecret: accessKeySecret, + } + + // 访问的域名 + c.Endpoint = tea.String("dysmsapi.aliyuncs.com") + result = &dysmsapi20170525.Client{} + result, err = dysmsapi20170525.NewClient(c) + return result, err +} diff --git a/internal/demo/register/set_password.go b/internal/demo/register/set_password.go new file mode 100644 index 000000000..804e8eb11 --- /dev/null +++ b/internal/demo/register/set_password.go @@ -0,0 +1,89 @@ +package register + +import ( + api "Open_IM/pkg/base_info" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + http2 "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "encoding/json" + "fmt" + "github.com/gin-gonic/gin" + "net/http" +) + +type ParamsSetPassword struct { + Email string `json:"email"` + Name string `json:"name"` + PhoneNumber string `json:"phoneNumber"` + Password string `json:"password"` + VerificationCode string `json:"verificationCode"` + Platform int32 `json:"platform" binding:"required,min=1,max=7"` + Ex string `json:"ex"` + OperationID string `json:"operationID" binding:"required"` +} + +func SetPassword(c *gin.Context) { + params := ParamsSetPassword{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError(params.OperationID, utils.GetSelfFuncName(), "bind json failed", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": constant.FormattingError, "errMsg": err.Error()}) + return + } + var account string + if params.Email != "" { + account = params.Email + } else { + account = params.PhoneNumber + } + if params.Name == "" { + params.Name = account + } + if params.VerificationCode != config.Config.Demo.SuperCode { + accountKey := account + "_" + constant.VerificationCodeForRegisterSuffix + v, err := db.DB.GetAccountCode(accountKey) + if err != nil || v != params.VerificationCode { + log.NewError(params.OperationID, "password Verification code error", account, params.VerificationCode) + data := make(map[string]interface{}) + data["PhoneNumber"] = account + c.JSON(http.StatusOK, gin.H{"errCode": constant.CodeInvalidOrExpired, "errMsg": "Verification code error!", "data": data}) + return + } + } + url := fmt.Sprintf("http://%s:10000/auth/user_register", utils.ServerIP) + openIMRegisterReq := api.UserRegisterReq{} + openIMRegisterReq.OperationID = params.OperationID + openIMRegisterReq.Platform = params.Platform + openIMRegisterReq.UserID = account + openIMRegisterReq.Nickname = params.Name + openIMRegisterReq.Secret = config.Config.Secret + openIMRegisterResp := api.UserRegisterResp{} + bMsg, err := http2.Post(url, openIMRegisterReq, 2) + if err != nil { + log.NewError(params.OperationID, "request openIM register error", account, "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.RegisterFailed, "errMsg": err.Error()}) + return + } + err = json.Unmarshal(bMsg, &openIMRegisterResp) + if err != nil || openIMRegisterResp.ErrCode != 0 { + log.NewError(params.OperationID, "request openIM register error", account, "err", "resp: ", openIMRegisterResp.ErrCode) + if err != nil { + log.NewError(params.OperationID, utils.GetSelfFuncName(), err.Error()) + } + c.JSON(http.StatusOK, gin.H{"errCode": constant.RegisterFailed, "errMsg": "register failed: " + openIMRegisterResp.ErrMsg}) + return + } + log.Info(params.OperationID, "begin store mysql", account, params.Password) + err = im_mysql_model.SetPassword(account, params.Password, params.Ex) + if err != nil { + log.NewError(params.OperationID, "set phone number password error", account, "err", err.Error()) + c.JSON(http.StatusOK, gin.H{"errCode": constant.RegisterFailed, "errMsg": err.Error()}) + return + } + log.Info(params.OperationID, "end setPassword", account, params.Password) + c.JSON(http.StatusOK, gin.H{"errCode": constant.NoError, "errMsg": "", "data": openIMRegisterResp.UserToken}) + return +} diff --git a/internal/demo/register/verify.go b/internal/demo/register/verify.go new file mode 100644 index 000000000..01fafbb92 --- /dev/null +++ b/internal/demo/register/verify.go @@ -0,0 +1,80 @@ +package register + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + + "github.com/gin-gonic/gin" + "net/http" +) + +type paramsCertification struct { + Email string `json:"email"` + PhoneNumber string `json:"phoneNumber"` + VerificationCode string `json:"verificationCode"` + OperationID string `json:"operationID" binding:"required"` + UsedFor int `json:"usedFor"` +} + +func Verify(c *gin.Context) { + params := paramsCertification{} + if err := c.BindJSON(¶ms); err != nil { + log.NewError("", "request params json parsing failed", "", "err", err.Error()) + c.JSON(http.StatusBadRequest, gin.H{"errCode": constant.FormattingError, "errMsg": err.Error()}) + return + } + log.NewInfo("recv req: ", params) + + var account string + if params.Email != "" { + account = params.Email + } else { + account = params.PhoneNumber + } + + if params.VerificationCode == config.Config.Demo.SuperCode { + log.InfoByKv("Super Code Verified successfully", account) + data := make(map[string]interface{}) + data["account"] = account + data["verificationCode"] = params.VerificationCode + c.JSON(http.StatusOK, gin.H{"errCode": constant.NoError, "errMsg": "Verified successfully!", "data": data}) + return + } + log.NewInfo("0", " params.VerificationCode != config.Config.Demo.SuperCode", params.VerificationCode, config.Config.Demo) + log.NewInfo(params.OperationID, "begin get form redis", account) + if params.UsedFor == 0 { + params.UsedFor = constant.VerificationCodeForRegister + } + var accountKey string + switch params.UsedFor { + case constant.VerificationCodeForRegister: + accountKey = account + "_" + constant.VerificationCodeForRegisterSuffix + case constant.VerificationCodeForReset: + accountKey = account + "_" + constant.VerificationCodeForResetSuffix + } + + code, err := db.DB.GetAccountCode(accountKey) + log.NewInfo(params.OperationID, "redis phone number and verificating Code", accountKey, code, params) + if err != nil { + log.NewError(params.OperationID, "Verification code expired", accountKey, "err", err.Error()) + data := make(map[string]interface{}) + data["account"] = account + c.JSON(http.StatusOK, gin.H{"errCode": constant.CodeInvalidOrExpired, "errMsg": "Verification code expired!", "data": data}) + return + } + if params.VerificationCode == code { + log.Info(params.OperationID, "Verified successfully", account) + data := make(map[string]interface{}) + data["account"] = account + data["verificationCode"] = params.VerificationCode + c.JSON(http.StatusOK, gin.H{"errCode": constant.NoError, "errMsg": "Verified successfully!", "data": data}) + return + } else { + log.Info(params.OperationID, "Verification code error", account, params.VerificationCode) + data := make(map[string]interface{}) + data["account"] = account + c.JSON(http.StatusOK, gin.H{"errCode": constant.CodeInvalidOrExpired, "errMsg": "Verification code error!", "data": data}) + } +} diff --git a/internal/msg_gateway/gate/init.go b/internal/msg_gateway/gate/init.go new file mode 100644 index 000000000..8f2f2e35b --- /dev/null +++ b/internal/msg_gateway/gate/init.go @@ -0,0 +1,35 @@ +package gate + +import ( + "Open_IM/pkg/common/config" + + "Open_IM/pkg/statistics" + "fmt" + "github.com/go-playground/validator/v10" + "sync" +) + +var ( + rwLock *sync.RWMutex + validate *validator.Validate + ws WServer + rpcSvr RPCServer + sendMsgCount uint64 + userCount uint64 +) + +func Init(rpcPort, wsPort int) { + //log initialization + + rwLock = new(sync.RWMutex) + validate = validator.New() + statistics.NewStatistics(&sendMsgCount, config.Config.ModuleName.LongConnSvrName, fmt.Sprintf("%d second recv to msg_gateway sendMsgCount", sendMsgCount), 300) + statistics.NewStatistics(&userCount, config.Config.ModuleName.LongConnSvrName, fmt.Sprintf("%d second add user conn", userCount), 300) + ws.onInit(wsPort) + rpcSvr.onInit(rpcPort) +} + +func Run() { + go ws.run() + go rpcSvr.run() +} diff --git a/internal/msg_gateway/gate/logic.go b/internal/msg_gateway/gate/logic.go new file mode 100644 index 000000000..567b4e8c1 --- /dev/null +++ b/internal/msg_gateway/gate/logic.go @@ -0,0 +1,297 @@ +package gate + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbChat "Open_IM/pkg/proto/chat" + pbRtc "Open_IM/pkg/proto/rtc" + sdk_ws "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "bytes" + "context" + "encoding/gob" + "github.com/golang/protobuf/proto" + "github.com/gorilla/websocket" + "google.golang.org/grpc" + "runtime" + "strconv" + "strings" +) + +func (ws *WServer) msgParse(conn *UserConn, binaryMsg []byte) { + //ws online debug data + //{"ReqIdentifier":1001,"Token":"123","SendID":"c4ca4238a0b923820dcc509a6f75849b","Time":"123","OperationID":"123","MsgIncr":0} + //{"ReqIdentifier":1002,"Token":"123","SendID":"c4ca4238a0b923820dcc509a6f75849b","Time":"123","OperationID":"123","MsgIncr":0,"SeqBegin":1,"SeqEnd":6} + //{"ReqIdentifier":1003,"Token":"123","SendID":"c4ca4238a0b923820dcc509a6f75849b", + //"RecvID":"a87ff679a2f3e71d9181a67b7542122c","ClientMsgID":"2343","Time":"147878787","OperationID": + //"123","MsgIncr":0,"SubMsgType":101,"MsgType":100,"MsgFrom":1,"Content":"sdfsdf"} + b := bytes.NewBuffer(binaryMsg) + m := Req{} + dec := gob.NewDecoder(b) + err := dec.Decode(&m) + if err != nil { + log.NewError("", "ws Decode err", err.Error()) + ws.sendErrMsg(conn, 200, err.Error(), constant.WSDataError, "", "") + err = conn.Close() + if err != nil { + log.NewError("", "ws close err", err.Error()) + } + return + } + if err := validate.Struct(m); err != nil { + log.NewError("", "ws args validate err", err.Error()) + ws.sendErrMsg(conn, 201, err.Error(), m.ReqIdentifier, m.MsgIncr, m.OperationID) + return + } + //if !utils.VerifyToken(m.Token, m.SendID) { + // ws.sendErrMsg(conn, 202, "token validate err", m.ReqIdentifier, m.MsgIncr,m.OperationID) + // return + //} + log.NewInfo(m.OperationID, "Basic Info Authentication Success", m) + + switch m.ReqIdentifier { + case constant.WSGetNewestSeq: + ws.getSeqReq(conn, &m) + case constant.WSSendMsg: + ws.sendMsgReq(conn, &m) + case constant.WSSendSignalMsg: + ws.sendSignalMsgReq(conn, &m) + case constant.WSPullMsgBySeqList: + ws.pullMsgBySeqListReq(conn, &m) + default: + } + log.NewInfo("", "goroutine num is ", runtime.NumGoroutine()) +} +func (ws *WServer) getSeqReq(conn *UserConn, m *Req) { + log.NewInfo(m.OperationID, "Ws call success to getNewSeq", m.MsgIncr, m.SendID, m.ReqIdentifier, m.Data) + rpcReq := pbChat.GetMaxAndMinSeqReq{} + nReply := new(pbChat.GetMaxAndMinSeqResp) + rpcReq.UserID = m.SendID + rpcReq.OperationID = m.OperationID + grpcConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + if grpcConn == nil { + log.ErrorByKv("get grpcConn err", rpcReq.OperationID, "args", m) + } + msgClient := pbChat.NewChatClient(grpcConn) + rpcReply, err := msgClient.GetMaxAndMinSeq(context.Background(), &rpcReq) + if err != nil { + log.Error(rpcReq.OperationID, "rpc call failed to getSeqReq", err, rpcReq.String()) + nReply.ErrCode = 500 + nReply.ErrMsg = err.Error() + ws.getSeqResp(conn, m, nReply) + } else { + log.InfoByKv("rpc call success to getSeqReq", rpcReq.OperationID, "replyData", rpcReply.String()) + ws.getSeqResp(conn, m, rpcReply) + } +} +func (ws *WServer) getSeqResp(conn *UserConn, m *Req, pb *pbChat.GetMaxAndMinSeqResp) { + var mReplyData sdk_ws.GetMaxAndMinSeqResp + mReplyData.MaxSeq = pb.GetMaxSeq() + mReplyData.MinSeq = pb.GetMinSeq() + b, _ := proto.Marshal(&mReplyData) + mReply := Resp{ + ReqIdentifier: m.ReqIdentifier, + MsgIncr: m.MsgIncr, + ErrCode: pb.GetErrCode(), + ErrMsg: pb.GetErrMsg(), + OperationID: m.OperationID, + Data: b, + } + ws.sendMsg(conn, mReply) +} + +func (ws *WServer) pullMsgBySeqListReq(conn *UserConn, m *Req) { + log.NewInfo(m.OperationID, "Ws call success to pullMsgBySeqListReq start", m.SendID, m.ReqIdentifier, m.MsgIncr, m.Data) + nReply := new(sdk_ws.PullMessageBySeqListResp) + isPass, errCode, errMsg, data := ws.argsValidate(m, constant.WSPullMsgBySeqList) + if isPass { + rpcReq := sdk_ws.PullMessageBySeqListReq{} + rpcReq.SeqList = data.(sdk_ws.PullMessageBySeqListReq).SeqList + rpcReq.UserID = m.SendID + rpcReq.OperationID = m.OperationID + log.NewInfo(m.OperationID, "Ws call success to pullMsgBySeqListReq middle", m.SendID, m.ReqIdentifier, m.MsgIncr, data.(sdk_ws.PullMessageBySeqListReq).SeqList) + grpcConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + msgClient := pbChat.NewChatClient(grpcConn) + reply, err := msgClient.PullMessageBySeqList(context.Background(), &rpcReq) + if err != nil { + log.NewError(rpcReq.OperationID, "pullMsgBySeqListReq err", err.Error()) + nReply.ErrCode = 200 + nReply.ErrMsg = err.Error() + ws.pullMsgBySeqListResp(conn, m, nReply) + } else { + log.NewInfo(rpcReq.OperationID, "rpc call success to pullMsgBySeqListReq", reply.String(), len(reply.List)) + ws.pullMsgBySeqListResp(conn, m, reply) + } + } else { + nReply.ErrCode = errCode + nReply.ErrMsg = errMsg + ws.pullMsgBySeqListResp(conn, m, nReply) + } +} +func (ws *WServer) pullMsgBySeqListResp(conn *UserConn, m *Req, pb *sdk_ws.PullMessageBySeqListResp) { + log.NewInfo(m.OperationID, "pullMsgBySeqListResp come here ", pb.String()) + c, _ := proto.Marshal(pb) + mReply := Resp{ + ReqIdentifier: m.ReqIdentifier, + MsgIncr: m.MsgIncr, + ErrCode: pb.GetErrCode(), + ErrMsg: pb.GetErrMsg(), + OperationID: m.OperationID, + Data: c, + } + log.NewInfo(m.OperationID, "pullMsgBySeqListResp all data is ", mReply.ReqIdentifier, mReply.MsgIncr, mReply.ErrCode, mReply.ErrMsg, + len(mReply.Data)) + + ws.sendMsg(conn, mReply) + +} +func (ws *WServer) sendMsgReq(conn *UserConn, m *Req) { + sendMsgCount++ + log.NewInfo(m.OperationID, "Ws call success to sendMsgReq start", m.MsgIncr, m.ReqIdentifier, m.SendID, m.Data) + nReply := new(pbChat.SendMsgResp) + isPass, errCode, errMsg, pData := ws.argsValidate(m, constant.WSSendMsg) + if isPass { + data := pData.(sdk_ws.MsgData) + pbData := pbChat.SendMsgReq{ + Token: m.Token, + OperationID: m.OperationID, + MsgData: &data, + } + log.NewInfo(m.OperationID, "Ws call success to sendMsgReq middle", m.ReqIdentifier, m.SendID, m.MsgIncr, data) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + client := pbChat.NewChatClient(etcdConn) + reply, err := client.SendMsg(context.Background(), &pbData) + if err != nil { + log.NewError(pbData.OperationID, "UserSendMsg err", err.Error()) + nReply.ErrCode = 200 + nReply.ErrMsg = err.Error() + ws.sendMsgResp(conn, m, nReply) + } else { + log.NewInfo(pbData.OperationID, "rpc call success to sendMsgReq", reply.String()) + ws.sendMsgResp(conn, m, reply) + } + + } else { + nReply.ErrCode = errCode + nReply.ErrMsg = errMsg + ws.sendMsgResp(conn, m, nReply) + } + +} +func (ws *WServer) sendMsgResp(conn *UserConn, m *Req, pb *pbChat.SendMsgResp) { + // := make(map[string]interface{}) + + var mReplyData sdk_ws.UserSendMsgResp + mReplyData.ClientMsgID = pb.GetClientMsgID() + mReplyData.ServerMsgID = pb.GetServerMsgID() + mReplyData.SendTime = pb.GetSendTime() + b, _ := proto.Marshal(&mReplyData) + mReply := Resp{ + ReqIdentifier: m.ReqIdentifier, + MsgIncr: m.MsgIncr, + ErrCode: pb.GetErrCode(), + ErrMsg: pb.GetErrMsg(), + OperationID: m.OperationID, + Data: b, + } + ws.sendMsg(conn, mReply) +} + +func (ws *WServer) sendSignalMsgReq(conn *UserConn, m *Req) { + log.NewInfo(m.OperationID, "Ws call success to sendSignalMsgReq start", m.MsgIncr, m.ReqIdentifier, m.SendID, m.Data) + nReply := new(pbChat.SendMsgResp) + isPass, errCode, errMsg, pData := ws.argsValidate(m, constant.WSSendSignalMsg) + if isPass { + signalResp := pbRtc.SignalResp{} + //isPass2, errCode2, errMsg2, signalResp, msgData := ws.signalMessageAssemble(pData.(*sdk_ws.SignalReq), m.OperationID) + connGrpc, err := grpc.Dial(config.Config.Rtc.Address+":"+strconv.Itoa(config.Config.Rtc.Port), grpc.WithInsecure()) + if err != nil { + log.NewError(m.OperationID, utils.GetSelfFuncName(), "grpc.Dial failed", err.Error()) + ws.sendSignalMsgResp(conn, 204, "create grpc failed"+err.Error(), m, nil) + return + } + rtcClient := pbRtc.NewRtcServiceClient(connGrpc) + req := &pbRtc.SignalMessageAssembleReq{ + SignalReq: pData.(*pbRtc.SignalReq), + OperationID: m.OperationID, + } + respPb, err := rtcClient.SignalMessageAssemble(context.Background(), req) + if err != nil { + log.NewError(m.OperationID, utils.GetSelfFuncName(), "SignalMessageAssemble", err.Error(), config.Config.Rtc.Address+":"+strconv.Itoa(config.Config.Rtc.Port)) + ws.sendSignalMsgResp(conn, 204, "grpc SignalMessageAssemble failed: "+err.Error(), m, &signalResp) + return + } + signalResp.Payload = respPb.SignalResp.Payload + msgData := sdk_ws.MsgData{} + utils.CopyStructFields(&msgData, respPb.MsgData) + log.NewInfo(m.OperationID, utils.GetSelfFuncName(), respPb.String()) + if respPb.IsPass { + pbData := pbChat.SendMsgReq{ + Token: m.Token, + OperationID: m.OperationID, + MsgData: &msgData, + } + log.NewInfo(m.OperationID, utils.GetSelfFuncName(), "pbData: ", pbData) + log.NewInfo(m.OperationID, "Ws call success to sendSignalMsgReq middle", m.ReqIdentifier, m.SendID, m.MsgIncr, msgData) + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + client := pbChat.NewChatClient(etcdConn) + reply, err := client.SendMsg(context.Background(), &pbData) + if err != nil { + log.NewError(pbData.OperationID, utils.GetSelfFuncName(), "rpc sendMsg err", err.Error()) + nReply.ErrCode = 200 + nReply.ErrMsg = err.Error() + ws.sendSignalMsgResp(conn, 200, err.Error(), m, &signalResp) + } else { + log.NewInfo(pbData.OperationID, "rpc call success to sendMsgReq", reply.String()) + ws.sendSignalMsgResp(conn, 0, "", m, &signalResp) + } + } else { + log.NewError(m.OperationID, utils.GetSelfFuncName(), respPb.IsPass, respPb.CommonResp.ErrCode, respPb.CommonResp.ErrMsg) + ws.sendSignalMsgResp(conn, respPb.CommonResp.ErrCode, respPb.CommonResp.ErrMsg, m, &signalResp) + } + } else { + ws.sendSignalMsgResp(conn, errCode, errMsg, m, nil) + } + +} +func (ws *WServer) sendSignalMsgResp(conn *UserConn, errCode int32, errMsg string, m *Req, pb *pbRtc.SignalResp) { + // := make(map[string]interface{}) + log.Debug(m.OperationID, "SignalMsgResp is", pb.String()) + b, _ := proto.Marshal(pb) + mReply := Resp{ + ReqIdentifier: m.ReqIdentifier, + MsgIncr: m.MsgIncr, + ErrCode: errCode, + ErrMsg: errMsg, + OperationID: m.OperationID, + Data: b, + } + ws.sendMsg(conn, mReply) +} +func (ws *WServer) sendMsg(conn *UserConn, mReply interface{}) { + var b bytes.Buffer + enc := gob.NewEncoder(&b) + err := enc.Encode(mReply) + if err != nil { + uid, platform := ws.getUserUid(conn) + log.NewError(mReply.(Resp).OperationID, mReply.(Resp).ReqIdentifier, mReply.(Resp).ErrCode, mReply.(Resp).ErrMsg, "Encode Msg error", conn.RemoteAddr().String(), uid, platform, err.Error()) + return + } + err = ws.writeMsg(conn, websocket.BinaryMessage, b.Bytes()) + if err != nil { + uid, platform := ws.getUserUid(conn) + log.NewError(mReply.(Resp).OperationID, mReply.(Resp).ReqIdentifier, mReply.(Resp).ErrCode, mReply.(Resp).ErrMsg, "WS WriteMsg error", conn.RemoteAddr().String(), uid, platform, err.Error()) + } +} +func (ws *WServer) sendErrMsg(conn *UserConn, errCode int32, errMsg string, reqIdentifier int32, msgIncr string, operationID string) { + mReply := Resp{ + ReqIdentifier: reqIdentifier, + MsgIncr: msgIncr, + ErrCode: errCode, + ErrMsg: errMsg, + OperationID: operationID, + } + ws.sendMsg(conn, mReply) +} diff --git a/internal/msg_gateway/gate/open_im_media/room.go b/internal/msg_gateway/gate/open_im_media/room.go new file mode 100644 index 000000000..83796da29 --- /dev/null +++ b/internal/msg_gateway/gate/open_im_media/room.go @@ -0,0 +1,58 @@ +package open_im_media + +const ( + // Address gRPC服务地址 + Address = "127.0.0.1:11300" +) + +//var roomClient *lksdk.RoomServiceClient + +type Media struct { +} + +func NewMedia() *Media { + return &Media{} +} + +//func (m *Media) GetJoinToken(room, identity string, operationID string, data *open_im_sdk.ParticipantMetaData) (string, string, error) { +// var newData pbRtc.ParticipantMetaData +// copier.Copy(&newData, data) +// conn, err := grpc.Dial(Address, grpc.WithInsecure()) +// if err != nil { +// return "", "", err +// } +// defer conn.Close() +// c := pbRtc.NewRtcServiceClient(conn) +// req := &pbRtc.GetJoinTokenReq{Room: room, OperationID: operationID, Identity: identity, MetaData: &newData} +// resp, err := c.GetJoinToken(context.Background(), req) +// if err != nil { +// return "", "", err +// } +// if resp.CommonResp.ErrCode != 0 { +// return "", "", errors.New(resp.CommonResp.ErrMsg) +// } +// return resp.Jwt, resp.LiveURL, nil +// //at := auth.NewAccessToken(m.ApiKey, m.ApiSecret) +// //grant := &auth.VideoGrant{ +// // RoomJoin: true, +// // Room: room, +// //} +// //at.AddGrant(grant). +// // SetIdentity(identity). +// // SetValidFor(time.Hour) +// // +// //return at.ToJWT() +//} + +func init() { + //roomClient = lksdk.NewRoomServiceClient(MediaAddress, ApiKey, ApiSecret) +} + +func (m *Media) CreateRoom(roomName string) (error, error) { + return nil, nil + //return roomClient.CreateRoom(context.Background(), &livekit.CreateRoomRequest{ + // Name: roomName, + // EmptyTimeout: 60 * 3, + //}) + +} diff --git a/internal/msg_gateway/gate/rpc_server.go b/internal/msg_gateway/gate/rpc_server.go new file mode 100644 index 000000000..a088303cb --- /dev/null +++ b/internal/msg_gateway/gate/rpc_server.go @@ -0,0 +1,149 @@ +package gate + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbRelay "Open_IM/pkg/proto/relay" + "Open_IM/pkg/utils" + "bytes" + "context" + "encoding/gob" + "fmt" + "github.com/golang/protobuf/proto" + "net" + "strings" + + "github.com/gorilla/websocket" + "google.golang.org/grpc" +) + +type RPCServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func (r *RPCServer) onInit(rpcPort int) { + r.rpcPort = rpcPort + r.rpcRegisterName = config.Config.RpcRegisterName.OpenImOnlineMessageRelayName + r.etcdSchema = config.Config.Etcd.EtcdSchema + r.etcdAddr = config.Config.Etcd.EtcdAddr +} +func (r *RPCServer) run() { + ip := utils.ServerIP + registerAddress := ip + ":" + utils.IntToString(r.rpcPort) + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.ErrorByArgs(fmt.Sprintf("fail to listening consumer, err:%v\n", err)) + return + } + defer listener.Close() + srv := grpc.NewServer() + defer srv.GracefulStop() + pbRelay.RegisterOnlineMessageRelayServiceServer(srv, r) + err = getcdv3.RegisterEtcd4Unique(r.etcdSchema, strings.Join(r.etcdAddr, ","), ip, r.rpcPort, r.rpcRegisterName, 10) + if err != nil { + log.ErrorByKv("register push message rpc to etcd err", "", "err", err.Error()) + } + err = srv.Serve(listener) + if err != nil { + log.ErrorByKv("push message rpc listening err", "", "err", err.Error()) + return + } +} +func (r *RPCServer) OnlinePushMsg(_ context.Context, in *pbRelay.OnlinePushMsgReq) (*pbRelay.OnlinePushMsgResp, error) { + log.InfoByKv("PushMsgToUser is arriving", in.OperationID, "args", in.String()) + var resp []*pbRelay.SingleMsgToUser + msgBytes, _ := proto.Marshal(in.MsgData) + mReply := Resp{ + ReqIdentifier: constant.WSPushMsg, + OperationID: in.OperationID, + Data: msgBytes, + } + var replyBytes bytes.Buffer + enc := gob.NewEncoder(&replyBytes) + err := enc.Encode(mReply) + if err != nil { + log.NewError(in.OperationID, "data encode err", err.Error()) + } + var tag bool + recvID := in.PushToUserID + platformList := genPlatformArray() + for _, v := range platformList { + if conn := ws.getUserConn(recvID, v); conn != nil { + tag = true + resultCode := sendMsgToUser(conn, replyBytes.Bytes(), in, v, recvID) + temp := &pbRelay.SingleMsgToUser{ + ResultCode: resultCode, + RecvID: recvID, + RecvPlatFormID: constant.PlatformNameToID(v), + } + resp = append(resp, temp) + } else { + temp := &pbRelay.SingleMsgToUser{ + ResultCode: -1, + RecvID: recvID, + RecvPlatFormID: constant.PlatformNameToID(v), + } + resp = append(resp, temp) + } + } + if !tag { + log.NewError(in.OperationID, "push err ,no matched ws conn not in map", in.String()) + } + return &pbRelay.OnlinePushMsgResp{ + Resp: resp, + }, nil +} +func (r *RPCServer) GetUsersOnlineStatus(_ context.Context, req *pbRelay.GetUsersOnlineStatusReq) (*pbRelay.GetUsersOnlineStatusResp, error) { + log.NewInfo(req.OperationID, "rpc GetUsersOnlineStatus arrived server", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + log.NewError(req.OperationID, "no permission GetUsersOnlineStatus ", req.OpUserID) + return &pbRelay.GetUsersOnlineStatusResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + var resp pbRelay.GetUsersOnlineStatusResp + for _, userID := range req.UserIDList { + platformList := genPlatformArray() + temp := new(pbRelay.GetUsersOnlineStatusResp_SuccessResult) + temp.UserID = userID + for _, platform := range platformList { + if conn := ws.getUserConn(userID, platform); conn != nil { + ps := new(pbRelay.GetUsersOnlineStatusResp_SuccessDetail) + ps.Platform = platform + ps.Status = constant.OnlineStatus + temp.Status = constant.OnlineStatus + temp.DetailPlatformStatus = append(temp.DetailPlatformStatus, ps) + + } + } + if temp.Status == constant.OnlineStatus { + resp.SuccessResult = append(resp.SuccessResult, temp) + } + } + log.NewInfo(req.OperationID, "GetUsersOnlineStatus rpc return ", resp.String()) + return &resp, nil +} +func sendMsgToUser(conn *UserConn, bMsg []byte, in *pbRelay.OnlinePushMsgReq, RecvPlatForm, RecvID string) (ResultCode int64) { + err := ws.writeMsg(conn, websocket.BinaryMessage, bMsg) + if err != nil { + log.ErrorByKv("PushMsgToUser is failed By Ws", "", "Addr", conn.RemoteAddr().String(), + "error", err, "senderPlatform", constant.PlatformIDToName(in.MsgData.SenderPlatformID), "recvPlatform", RecvPlatForm, "args", in.String(), "recvID", RecvID) + ResultCode = -2 + return ResultCode + } else { + log.InfoByKv("PushMsgToUser is success By Ws", in.OperationID, "args", in.String(), "recvPlatForm", RecvPlatForm, "recvID", RecvID) + ResultCode = 0 + return ResultCode + } + +} +func genPlatformArray() (array []string) { + for i := 1; i <= constant.LinuxPlatformID; i++ { + array = append(array, constant.PlatformIDToName(int32(i))) + } + return array +} diff --git a/internal/msg_gateway/gate/validate.go b/internal/msg_gateway/gate/validate.go new file mode 100644 index 000000000..329f93655 --- /dev/null +++ b/internal/msg_gateway/gate/validate.go @@ -0,0 +1,253 @@ +/* +** description(""). +** copyright('Open_IM,www.Open_IM.io'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/5/21 15:29). + */ +package gate + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + pbRtc "Open_IM/pkg/proto/rtc" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "github.com/golang/protobuf/proto" +) + +type Req struct { + ReqIdentifier int32 `json:"reqIdentifier" validate:"required"` + Token string `json:"token" ` + SendID string `json:"sendID" validate:"required"` + OperationID string `json:"operationID" validate:"required"` + MsgIncr string `json:"msgIncr" validate:"required"` + Data []byte `json:"data"` +} +type Resp struct { + ReqIdentifier int32 `json:"reqIdentifier"` + MsgIncr string `json:"msgIncr"` + OperationID string `json:"operationID"` + ErrCode int32 `json:"errCode"` + ErrMsg string `json:"errMsg"` + Data []byte `json:"data"` +} + +type SeqData struct { + SeqBegin int64 `mapstructure:"seqBegin" validate:"required"` + SeqEnd int64 `mapstructure:"seqEnd" validate:"required"` +} +type MsgData struct { + PlatformID int32 `mapstructure:"platformID" validate:"required"` + SessionType int32 `mapstructure:"sessionType" validate:"required"` + MsgFrom int32 `mapstructure:"msgFrom" validate:"required"` + ContentType int32 `mapstructure:"contentType" validate:"required"` + RecvID string `mapstructure:"recvID" validate:"required"` + ForceList []string `mapstructure:"forceList"` + Content string `mapstructure:"content" validate:"required"` + Options map[string]interface{} `mapstructure:"options" validate:"required"` + ClientMsgID string `mapstructure:"clientMsgID" validate:"required"` + OfflineInfo map[string]interface{} `mapstructure:"offlineInfo" validate:"required"` + Ext map[string]interface{} `mapstructure:"ext"` +} +type MaxSeqResp struct { + MaxSeq int64 `json:"maxSeq"` +} +type PullMessageResp struct { +} +type SeqListData struct { + SeqList []int64 `mapstructure:"seqList" validate:"required"` +} + +func (ws *WServer) argsValidate(m *Req, r int32) (isPass bool, errCode int32, errMsg string, returnData interface{}) { + switch r { + case constant.WSSendMsg: + data := open_im_sdk.MsgData{} + if err := proto.Unmarshal(m.Data, &data); err != nil { + log.ErrorByKv("Decode Data struct err", "", "err", err.Error(), "reqIdentifier", r) + return false, 203, err.Error(), nil + } + if err := validate.Struct(data); err != nil { + log.ErrorByKv("data args validate err", "", "err", err.Error(), "reqIdentifier", r) + return false, 204, err.Error(), nil + + } + return true, 0, "", data + case constant.WSSendSignalMsg: + data := pbRtc.SignalReq{} + if err := proto.Unmarshal(m.Data, &data); err != nil { + log.ErrorByKv("Decode Data struct err", "", "err", err.Error(), "reqIdentifier", r) + return false, 203, err.Error(), nil + } + if err := validate.Struct(data); err != nil { + log.ErrorByKv("data args validate err", "", "err", err.Error(), "reqIdentifier", r) + return false, 204, err.Error(), nil + + } + return true, 0, "", &data + case constant.WSPullMsgBySeqList: + data := open_im_sdk.PullMessageBySeqListReq{} + if err := proto.Unmarshal(m.Data, &data); err != nil { + log.ErrorByKv("Decode Data struct err", "", "err", err.Error(), "reqIdentifier", r) + return false, 203, err.Error(), nil + } + if err := validate.Struct(data); err != nil { + log.ErrorByKv("data args validate err", "", "err", err.Error(), "reqIdentifier", r) + return false, 204, err.Error(), nil + + } + return true, 0, "", data + + default: + } + + return false, 204, "args err", nil + + //b := bytes.NewBuffer(m.Data) + //dec := gob.NewDecoder(b) + //err := dec.Decode(&data) + //if err != nil { + // log.ErrorByKv("Decode Data struct err", "", "err", err.Error(), "reqIdentifier", r) + // return false, 203, err.Error(), nil + //} + //if err := mapstructure.WeakDecode(m.Data, &data); err != nil { + // log.ErrorByKv("map to Data struct err", "", "err", err.Error(), "reqIdentifier", r) + // return false, 203, err.Error(), nil + //} else + +} + +//func (ws *WServer) signalMessageAssemble(s *open_im_sdk.SignalReq, operationID string) (isPass bool, errCode int32, errMsg string, r *open_im_sdk.SignalResp, msgData *open_im_sdk.MsgData) { +// var msg open_im_sdk.MsgData +// var resp open_im_sdk.SignalResp +// media := open_im_media.NewMedia() +// msg.MsgFrom = constant.UserMsgType +// msg.ContentType = constant.SignalingNotification +// reqData, e := proto.Marshal(s) +// if e != nil { +// return false, 201, e.Error(), nil, nil +// } +// msg.Content = reqData +// msg.CreateTime = utils.GetCurrentTimestampByMill() +// options := make(map[string]bool, 6) +// utils.SetSwitchFromOptions(options, constant.IsHistory, false) +// utils.SetSwitchFromOptions(options, constant.IsPersistent, false) +// utils.SetSwitchFromOptions(options, constant.IsSenderSync, true) +// utils.SetSwitchFromOptions(options, constant.IsConversationUpdate, false) +// utils.SetSwitchFromOptions(options, constant.IsSenderConversationUpdate, false) +// utils.SetSwitchFromOptions(options, constant.IsUnreadCount, false) +// utils.SetSwitchFromOptions(options, constant.IsOfflinePush, true) +// msg.Options = options +// switch payload := s.Payload.(type) { +// case *open_im_sdk.SignalReq_Invite: +// token, liveURL, err2 := media.GetJoinToken(payload.Invite.Invitation.RoomID, payload.Invite.Invitation.InviterUserID, operationID, payload.Invite.Participant) +// if err2 != nil { +// return false, 202, err2.Error(), nil, nil +// } +// invite := open_im_sdk.SignalResp_Invite{&open_im_sdk.SignalInviteReply{ +// Token: token, +// RoomID: payload.Invite.Invitation.RoomID, +// LiveURL: liveURL, +// }} +// resp.Payload = &invite +// msg.SenderPlatformID = payload.Invite.Invitation.PlatformID +// msg.SessionType = payload.Invite.Invitation.SessionType +// msg.OfflinePushInfo = payload.Invite.OfflinePushInfo +// msg.SendID = payload.Invite.Invitation.InviterUserID +// if len(payload.Invite.Invitation.InviteeUserIDList) > 0 { +// msg.RecvID = payload.Invite.Invitation.InviteeUserIDList[0] +// } else { +// return false, 203, errors.New("InviteeUserIDList is null").Error(), nil, nil +// } +// msg.ClientMsgID = utils.GetMsgID(payload.Invite.Invitation.InviterUserID) +// return true, 0, "", &resp, &msg +// case *open_im_sdk.SignalReq_InviteInGroup: +// token, liveURL, err2 := media.GetJoinToken(payload.InviteInGroup.Invitation.RoomID, payload.InviteInGroup.Invitation.InviterUserID, operationID, payload.InviteInGroup.Participant) +// if err2 != nil { +// return false, 204, err2.Error(), nil, nil +// } +// inviteGroup := open_im_sdk.SignalResp_InviteInGroup{&open_im_sdk.SignalInviteInGroupReply{ +// RoomID: payload.InviteInGroup.Invitation.RoomID, +// Token: token, +// LiveURL: liveURL, +// }} +// resp.Payload = &inviteGroup +// msg.SenderPlatformID = payload.InviteInGroup.Invitation.PlatformID +// msg.SessionType = payload.InviteInGroup.Invitation.SessionType +// msg.OfflinePushInfo = payload.InviteInGroup.OfflinePushInfo +// msg.SendID = payload.InviteInGroup.Invitation.InviterUserID +// if len(payload.InviteInGroup.Invitation.InviteeUserIDList) > 0 { +// msg.GroupID = payload.InviteInGroup.Invitation.GroupID +// } else { +// return false, 205, errors.New("InviteeUserIDList is null").Error(), nil, nil +// } +// msg.ClientMsgID = utils.GetMsgID(payload.InviteInGroup.Invitation.InviterUserID) +// +// return true, 0, "", &resp, &msg +// case *open_im_sdk.SignalReq_Cancel: +// cancel := open_im_sdk.SignalResp_Cancel{&open_im_sdk.SignalCancelReply{}} +// resp.Payload = &cancel +// msg.OfflinePushInfo = payload.Cancel.OfflinePushInfo +// msg.SendID = payload.Cancel.Invitation.InviterUserID +// msg.SenderPlatformID = payload.Cancel.Invitation.PlatformID +// msg.SessionType = payload.Cancel.Invitation.SessionType +// if len(payload.Cancel.Invitation.InviteeUserIDList) > 0 { +// switch payload.Cancel.Invitation.SessionType { +// case constant.SingleChatType: +// msg.RecvID = payload.Cancel.Invitation.InviteeUserIDList[0] +// case constant.GroupChatType: +// msg.GroupID = payload.Cancel.Invitation.GroupID +// } +// } else { +// return false, 206, errors.New("InviteeUserIDList is null").Error(), nil, nil +// } +// msg.ClientMsgID = utils.GetMsgID(payload.Cancel.OpUserID) +// return true, 0, "", &resp, &msg +// case *open_im_sdk.SignalReq_Accept: +// token, liveURL, err2 := media.GetJoinToken(payload.Accept.Invitation.RoomID, payload.Accept.OpUserID, operationID, payload.Accept.Participant) +// if err2 != nil { +// return false, 207, err2.Error(), nil, nil +// } +// accept := open_im_sdk.SignalResp_Accept{&open_im_sdk.SignalAcceptReply{ +// Token: token, +// LiveURL: liveURL, +// RoomID: payload.Accept.Invitation.RoomID, +// }} +// resp.Payload = &accept +// msg.OfflinePushInfo = payload.Accept.OfflinePushInfo +// msg.SendID = payload.Accept.OpUserID +// msg.SenderPlatformID = payload.Accept.Invitation.PlatformID +// msg.SessionType = payload.Accept.Invitation.SessionType +// if len(payload.Accept.Invitation.InviteeUserIDList) > 0 { +// switch payload.Accept.Invitation.SessionType { +// case constant.SingleChatType: +// msg.RecvID = payload.Accept.Invitation.InviterUserID +// case constant.GroupChatType: +// msg.GroupID = payload.Accept.Invitation.GroupID +// } +// } else { +// return false, 208, errors.New("InviteeUserIDList is null").Error(), nil, nil +// } +// msg.ClientMsgID = utils.GetMsgID(payload.Accept.OpUserID) +// return true, 0, "", &resp, &msg +// case *open_im_sdk.SignalReq_HungUp: +// case *open_im_sdk.SignalReq_Reject: +// reject := open_im_sdk.SignalResp_Reject{&open_im_sdk.SignalRejectReply{}} +// resp.Payload = &reject +// msg.OfflinePushInfo = payload.Reject.OfflinePushInfo +// msg.SendID = payload.Reject.OpUserID +// msg.SenderPlatformID = payload.Reject.Invitation.PlatformID +// msg.SessionType = payload.Reject.Invitation.SessionType +// if len(payload.Reject.Invitation.InviteeUserIDList) > 0 { +// switch payload.Reject.Invitation.SessionType { +// case constant.SingleChatType: +// msg.RecvID = payload.Reject.Invitation.InviterUserID +// case constant.GroupChatType: +// msg.GroupID = payload.Reject.Invitation.GroupID +// } +// } else { +// return false, 209, errors.New("InviteeUserIDList is null").Error(), nil, nil +// } +// msg.ClientMsgID = utils.GetMsgID(payload.Reject.OpUserID) +// return true, 0, "", &resp, &msg +// } +// return false, 210, errors.New("InviteeUserIDList is null").Error(), nil, nil +//} diff --git a/internal/msg_gateway/gate/ws_server.go b/internal/msg_gateway/gate/ws_server.go new file mode 100644 index 000000000..7c602a5fc --- /dev/null +++ b/internal/msg_gateway/gate/ws_server.go @@ -0,0 +1,285 @@ +package gate + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/utils" + "bytes" + "encoding/gob" + "github.com/garyburd/redigo/redis" + "net/http" + "sync" + "time" + + "github.com/gorilla/websocket" +) + +type UserConn struct { + *websocket.Conn + w *sync.Mutex +} +type WServer struct { + wsAddr string + wsMaxConnNum int + wsUpGrader *websocket.Upgrader + wsConnToUser map[*UserConn]map[string]string + wsUserToConn map[string]map[string]*UserConn +} + +func (ws *WServer) onInit(wsPort int) { + ws.wsAddr = ":" + utils.IntToString(wsPort) + ws.wsMaxConnNum = config.Config.LongConnSvr.WebsocketMaxConnNum + ws.wsConnToUser = make(map[*UserConn]map[string]string) + ws.wsUserToConn = make(map[string]map[string]*UserConn) + ws.wsUpGrader = &websocket.Upgrader{ + HandshakeTimeout: time.Duration(config.Config.LongConnSvr.WebsocketTimeOut) * time.Second, + ReadBufferSize: config.Config.LongConnSvr.WebsocketMaxMsgLen, + CheckOrigin: func(r *http.Request) bool { return true }, + } +} + +func (ws *WServer) run() { + http.HandleFunc("/", ws.wsHandler) //Get request from client to handle by wsHandler + err := http.ListenAndServe(ws.wsAddr, nil) //Start listening + if err != nil { + log.ErrorByKv("Ws listening err", "", "err", err.Error()) + } +} + +func (ws *WServer) wsHandler(w http.ResponseWriter, r *http.Request) { + if ws.headerCheck(w, r) { + query := r.URL.Query() + conn, err := ws.wsUpGrader.Upgrade(w, r, nil) //Conn is obtained through the upgraded escalator + if err != nil { + log.ErrorByKv("upgrade http conn err", "", "err", err) + return + } else { + //Connection mapping relationship, + //userID+" "+platformID->conn + + //Initialize a lock for each user + newConn := &UserConn{conn, new(sync.Mutex)} + ws.addUserConn(query["sendID"][0], int32(utils.StringToInt64(query["platformID"][0])), newConn, query["token"][0]) + go ws.readMsg(newConn) + } + } +} + +func (ws *WServer) readMsg(conn *UserConn) { + for { + messageType, msg, err := conn.ReadMessage() + if messageType == websocket.PingMessage { + log.NewInfo("", "this is a pingMessage") + } + if err != nil { + uid, platform := ws.getUserUid(conn) + log.ErrorByKv("WS ReadMsg error", "", "userIP", conn.RemoteAddr().String(), "userUid", uid, "platform", platform, "error", err.Error()) + ws.delUserConn(conn) + return + } else { + //log.ErrorByKv("test", "", "msgType", msgType, "userIP", conn.RemoteAddr().String(), "userUid", ws.getUserUid(conn)) + } + ws.msgParse(conn, msg) + //ws.writeMsg(conn, 1, chat) + } + +} +func (ws *WServer) writeMsg(conn *UserConn, a int, msg []byte) error { + conn.w.Lock() + defer conn.w.Unlock() + return conn.WriteMessage(a, msg) + +} +func (ws *WServer) MultiTerminalLoginChecker(uid string, platformID int32, newConn *UserConn, token string, operationID string) { + switch config.Config.MultiLoginPolicy { + case constant.AllLoginButSameTermKick: + if oldConnMap, ok := ws.wsUserToConn[uid]; ok { // user->map[platform->conn] + if oldConn, ok := oldConnMap[constant.PlatformIDToName(platformID)]; ok { + log.NewDebug(operationID, uid, platformID, "kick old conn") + ws.sendKickMsg(oldConn, newConn) + m, err := db.DB.GetTokenMapByUidPid(uid, constant.PlatformIDToName(platformID)) + if err != nil && err != redis.ErrNil { + log.NewError(operationID, "get token from redis err", err.Error()) + return + } + if m == nil { + log.NewError(operationID, "get token from redis err", "m is nil") + return + } + for k, _ := range m { + if k != token { + m[k] = constant.KickedToken + } + } + log.NewDebug(operationID, "get map is ", m) + err = db.DB.SetTokenMapByUidPid(uid, platformID, m) + if err != nil { + log.NewError(operationID, "SetTokenMapByUidPid err", err.Error()) + return + } + err = oldConn.Close() + delete(oldConnMap, constant.PlatformIDToName(platformID)) + ws.wsUserToConn[uid] = oldConnMap + if len(oldConnMap) == 0 { + delete(ws.wsUserToConn, uid) + } + delete(ws.wsConnToUser, oldConn) + if err != nil { + log.NewError(operationID, "conn close err", err.Error(), uid, platformID) + } + + } else { + log.NewWarn(operationID, "abnormal uid-conn ", uid, platformID, oldConnMap[constant.PlatformIDToName(platformID)]) + } + + } else { + log.NewDebug(operationID, "no other conn", ws.wsUserToConn, uid, platformID) + } + + case constant.SingleTerminalLogin: + case constant.WebAndOther: + } +} +func (ws *WServer) sendKickMsg(oldConn, newConn *UserConn) { + mReply := Resp{ + ReqIdentifier: constant.WSKickOnlineMsg, + ErrCode: constant.ErrTokenInvalid.ErrCode, + ErrMsg: constant.ErrTokenInvalid.ErrMsg, + } + var b bytes.Buffer + enc := gob.NewEncoder(&b) + err := enc.Encode(mReply) + if err != nil { + log.NewError(mReply.OperationID, mReply.ReqIdentifier, mReply.ErrCode, mReply.ErrMsg, "Encode Msg error", oldConn.RemoteAddr().String(), newConn.RemoteAddr().String(), err.Error()) + return + } + err = ws.writeMsg(oldConn, websocket.BinaryMessage, b.Bytes()) + if err != nil { + log.NewError(mReply.OperationID, mReply.ReqIdentifier, mReply.ErrCode, mReply.ErrMsg, "WS WriteMsg error", oldConn.RemoteAddr().String(), newConn.RemoteAddr().String(), err.Error()) + } +} +func (ws *WServer) addUserConn(uid string, platformID int32, conn *UserConn, token string) { + rwLock.Lock() + defer rwLock.Unlock() + operationID := utils.OperationIDGenerator() + ws.MultiTerminalLoginChecker(uid, platformID, conn, token, operationID) + if oldConnMap, ok := ws.wsUserToConn[uid]; ok { + oldConnMap[constant.PlatformIDToName(platformID)] = conn + ws.wsUserToConn[uid] = oldConnMap + log.Debug(operationID, "user not first come in, add conn ", uid, platformID, conn, oldConnMap) + } else { + i := make(map[string]*UserConn) + i[constant.PlatformIDToName(platformID)] = conn + ws.wsUserToConn[uid] = i + log.Debug(operationID, "user first come in, new user, conn", uid, platformID, conn, ws.wsUserToConn[uid]) + } + if oldStringMap, ok := ws.wsConnToUser[conn]; ok { + oldStringMap[constant.PlatformIDToName(platformID)] = uid + ws.wsConnToUser[conn] = oldStringMap + } else { + i := make(map[string]string) + i[constant.PlatformIDToName(platformID)] = uid + ws.wsConnToUser[conn] = i + } + count := 0 + for _, v := range ws.wsUserToConn { + count = count + len(v) + } + log.Debug(operationID, "WS Add operation", "", "wsUser added", ws.wsUserToConn, "connection_uid", uid, "connection_platform", constant.PlatformIDToName(platformID), "online_user_num", len(ws.wsUserToConn), "online_conn_num", count) + userCount = uint64(len(ws.wsUserToConn)) + +} + +func (ws *WServer) delUserConn(conn *UserConn) { + rwLock.Lock() + defer rwLock.Unlock() + var platform, uid string + if oldStringMap, ok := ws.wsConnToUser[conn]; ok { + for k, v := range oldStringMap { + platform = k + uid = v + } + if oldConnMap, ok := ws.wsUserToConn[uid]; ok { + delete(oldConnMap, platform) + ws.wsUserToConn[uid] = oldConnMap + if len(oldConnMap) == 0 { + delete(ws.wsUserToConn, uid) + } + count := 0 + for _, v := range ws.wsUserToConn { + count = count + len(v) + } + log.WarnByKv("WS delete operation", "", "wsUser deleted", ws.wsUserToConn, "disconnection_uid", uid, "disconnection_platform", platform, "online_user_num", len(ws.wsUserToConn), "online_conn_num", count) + } else { + log.WarnByKv("WS delete operation", "", "wsUser deleted", ws.wsUserToConn, "disconnection_uid", uid, "disconnection_platform", platform, "online_user_num", len(ws.wsUserToConn)) + } + userCount = uint64(len(ws.wsUserToConn)) + delete(ws.wsConnToUser, conn) + + } + err := conn.Close() + if err != nil { + log.ErrorByKv("close err", "", "uid", uid, "platform", platform) + + } + +} + +func (ws *WServer) getUserConn(uid string, platform string) *UserConn { + rwLock.RLock() + defer rwLock.RUnlock() + if connMap, ok := ws.wsUserToConn[uid]; ok { + if conn, flag := connMap[platform]; flag { + return conn + } + } + return nil +} +func (ws *WServer) getSingleUserAllConn(uid string) map[string]*UserConn { + rwLock.RLock() + defer rwLock.RUnlock() + if connMap, ok := ws.wsUserToConn[uid]; ok { + return connMap + } + return nil +} +func (ws *WServer) getUserUid(conn *UserConn) (uid, platform string) { + rwLock.RLock() + defer rwLock.RUnlock() + + if stringMap, ok := ws.wsConnToUser[conn]; ok { + for k, v := range stringMap { + platform = k + uid = v + } + return uid, platform + } + return "", "" +} +func (ws *WServer) headerCheck(w http.ResponseWriter, r *http.Request) bool { + status := http.StatusUnauthorized + query := r.URL.Query() + if len(query["token"]) != 0 && len(query["sendID"]) != 0 && len(query["platformID"]) != 0 { + if ok, err, msg := token_verify.WsVerifyToken(query["token"][0], query["sendID"][0], query["platformID"][0]); !ok { + e := err.(*constant.ErrInfo) + log.ErrorByKv("Token verify failed", "", "query", query, msg) + w.Header().Set("Sec-Websocket-Version", "13") + http.Error(w, e.ErrMsg, int(e.ErrCode)) + return false + } else { + log.InfoByKv("Connection Authentication Success", "", "token", query["token"][0], "userID", query["sendID"][0]) + return true + } + } else { + log.ErrorByKv("Args err", "", "query", query) + w.Header().Set("Sec-Websocket-Version", "13") + http.Error(w, http.StatusText(status), status) + return false + } +} +func genMapKey(uid string, platformID int32) string { + return uid + " " + constant.PlatformIDToName(platformID) +} diff --git a/internal/msg_transfer/logic/db.go b/internal/msg_transfer/logic/db.go new file mode 100644 index 000000000..806b782c0 --- /dev/null +++ b/internal/msg_transfer/logic/db.go @@ -0,0 +1,23 @@ +package logic + +import ( + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + pbMsg "Open_IM/pkg/proto/chat" + "Open_IM/pkg/utils" +) + +func saveUserChat(uid string, msg *pbMsg.MsgDataToMQ) error { + time := utils.GetCurrentTimestampByMill() + seq, err := db.DB.IncrUserSeq(uid) + if err != nil { + log.NewError(msg.OperationID, "data insert to redis err", err.Error(), msg.String()) + return err + } + msg.MsgData.Seq = uint32(seq) + pbSaveData := pbMsg.MsgDataToDB{} + pbSaveData.MsgData = msg.MsgData + log.NewInfo(msg.OperationID, "IncrUserSeq cost time", utils.GetCurrentTimestampByMill()-time) + return db.DB.SaveUserChatMongo2(uid, pbSaveData.MsgData.SendTime, &pbSaveData) +// return db.DB.SaveUserChatMongo2(uid, pbSaveData.MsgData.SendTime, &pbSaveData) +} diff --git a/internal/msg_transfer/logic/history_msg_handler.go b/internal/msg_transfer/logic/history_msg_handler.go new file mode 100644 index 000000000..0b9f5c1c3 --- /dev/null +++ b/internal/msg_transfer/logic/history_msg_handler.go @@ -0,0 +1,142 @@ +package logic + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + kfk "Open_IM/pkg/common/kafka" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbMsg "Open_IM/pkg/proto/chat" + pbPush "Open_IM/pkg/proto/push" + "Open_IM/pkg/statistics" + "Open_IM/pkg/utils" + "context" + "github.com/Shopify/sarama" + "github.com/golang/protobuf/proto" + "strings" +) + +type fcb func(msg []byte, msgKey string) + +type HistoryConsumerHandler struct { + msgHandle map[string]fcb + historyConsumerGroup *kfk.MConsumerGroup + singleMsgCount uint64 + groupMsgCount uint64 +} + +func (mc *HistoryConsumerHandler) Init() { + statistics.NewStatistics(&mc.singleMsgCount, config.Config.ModuleName.MsgTransferName, "singleMsgCount insert to mongo ", 300) + statistics.NewStatistics(&mc.groupMsgCount, config.Config.ModuleName.MsgTransferName, "groupMsgCount insert to mongo ", 300) + + mc.msgHandle = make(map[string]fcb) + mc.msgHandle[config.Config.Kafka.Ws2mschat.Topic] = mc.handleChatWs2Mongo + mc.historyConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic}, + config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) + +} + +func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) { + time := utils.GetCurrentTimestampByNano() + msgFromMQ := pbMsg.MsgDataToMQ{} + err := proto.Unmarshal(msg, &msgFromMQ) + if err != nil { + log.Error("msg_transfer Unmarshal msg err", "", "msg", string(msg), "err", err.Error()) + return + } + operationID := msgFromMQ.OperationID + log.NewInfo(operationID, "msg come mongo!!!", "", "msg", string(msg)) + //Control whether to store offline messages (mongo) + isHistory := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsHistory) + //Control whether to store history messages (mysql) + isPersist := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsPersistent) + isSenderSync := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsSenderSync) + switch msgFromMQ.MsgData.SessionType { + case constant.SingleChatType: + log.NewDebug(msgFromMQ.OperationID, "msg_transfer msg type = SingleChatType", isHistory, isPersist) + if isHistory { + err := saveUserChat(msgKey, &msgFromMQ) + if err != nil { + log.NewError(operationID, "single data insert to mongo err", err.Error(), msgFromMQ.String()) + return + } + mc.singleMsgCount++ + log.NewDebug(msgFromMQ.OperationID, "sendMessageToPush cost time ", utils.GetCurrentTimestampByNano()-time) + } + if !isSenderSync && msgKey == msgFromMQ.MsgData.SendID { + } else { + go sendMessageToPush(&msgFromMQ, msgKey) + } + log.NewDebug(operationID, "saveUserChat cost time ", utils.GetCurrentTimestampByNano()-time) + case constant.GroupChatType: + log.NewDebug(msgFromMQ.OperationID, "msg_transfer msg type = GroupChatType", isHistory, isPersist) + if isHistory { + err := saveUserChat(msgFromMQ.MsgData.RecvID, &msgFromMQ) + if err != nil { + log.NewError(operationID, "group data insert to mongo err", msgFromMQ.String(), msgFromMQ.MsgData.RecvID, err.Error()) + return + } + mc.groupMsgCount++ + } + go sendMessageToPush(&msgFromMQ, msgFromMQ.MsgData.RecvID) + case constant.NotificationChatType: + log.NewDebug(msgFromMQ.OperationID, "msg_transfer msg type = NotificationChatType", isHistory, isPersist) + if isHistory { + err := saveUserChat(msgKey, &msgFromMQ) + if err != nil { + log.NewError(operationID, "single data insert to mongo err", err.Error(), msgFromMQ.String()) + return + } + mc.singleMsgCount++ + log.NewDebug(msgFromMQ.OperationID, "sendMessageToPush cost time ", utils.GetCurrentTimestampByNano()-time) + } + if !isSenderSync && msgKey == msgFromMQ.MsgData.SendID { + } else { + go sendMessageToPush(&msgFromMQ, msgKey) + } + log.NewDebug(operationID, "saveUserChat cost time ", utils.GetCurrentTimestampByNano()-time) + default: + log.NewError(msgFromMQ.OperationID, "SessionType error", msgFromMQ.String()) + return + } + log.NewDebug(msgFromMQ.OperationID, "msg_transfer handle topic data to database success...", msgFromMQ.String()) +} + +func (HistoryConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil } +func (HistoryConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } +func (mc *HistoryConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, + claim sarama.ConsumerGroupClaim) error { + for msg := range claim.Messages() { + log.InfoByKv("kafka get info to mongo", "", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value)) + mc.msgHandle[msg.Topic](msg.Value, string(msg.Key)) + sess.MarkMessage(msg, "") + } + return nil +} +func sendMessageToPush(message *pbMsg.MsgDataToMQ, pushToUserID string) { + log.Info(message.OperationID, "msg_transfer send message to push", "message", message.String()) + rpcPushMsg := pbPush.PushMsgReq{OperationID: message.OperationID, MsgData: message.MsgData, PushToUserID: pushToUserID} + mqPushMsg := pbMsg.PushMsgDataToMQ{OperationID: message.OperationID, MsgData: message.MsgData, PushToUserID: pushToUserID} + grpcConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImPushName) + if grpcConn == nil { + log.Error(rpcPushMsg.OperationID, "rpc dial failed", "push data", rpcPushMsg.String()) + pid, offset, err := producer.SendMessage(&mqPushMsg) + if err != nil { + log.Error(mqPushMsg.OperationID, "kafka send failed", "send data", message.String(), "pid", pid, "offset", offset, "err", err.Error()) + } + return + } + msgClient := pbPush.NewPushMsgServiceClient(grpcConn) + _, err := msgClient.PushMsg(context.Background(), &rpcPushMsg) + if err != nil { + log.Error(rpcPushMsg.OperationID, "rpc send failed", rpcPushMsg.OperationID, "push data", rpcPushMsg.String(), "err", err.Error()) + pid, offset, err := producer.SendMessage(&mqPushMsg) + if err != nil { + log.Error("kafka send failed", mqPushMsg.OperationID, "send data", mqPushMsg.String(), "pid", pid, "offset", offset, "err", err.Error()) + } + } else { + log.Info("rpc send success", rpcPushMsg.OperationID, "push data", rpcPushMsg.String()) + + } +} diff --git a/internal/msg_transfer/logic/init.go b/internal/msg_transfer/logic/init.go new file mode 100644 index 000000000..20326bbfc --- /dev/null +++ b/internal/msg_transfer/logic/init.go @@ -0,0 +1,25 @@ +package logic + +import ( + "Open_IM/pkg/common/config" + + "Open_IM/pkg/common/kafka" +) + +var ( + persistentCH PersistentConsumerHandler + historyCH HistoryConsumerHandler + producer *kafka.Producer +) + +func Init() { + + persistentCH.Init() + historyCH.Init() + producer = kafka.NewKafkaProducer(config.Config.Kafka.Ms2pschat.Addr, config.Config.Kafka.Ms2pschat.Topic) +} +func Run() { + //register mysqlConsumerHandler to + go persistentCH.persistentConsumerGroup.RegisterHandleAndConsumer(&persistentCH) + go historyCH.historyConsumerGroup.RegisterHandleAndConsumer(&historyCH) +} diff --git a/internal/msg_transfer/logic/persistent_msg_handler.go b/internal/msg_transfer/logic/persistent_msg_handler.go new file mode 100644 index 000000000..5400d54d6 --- /dev/null +++ b/internal/msg_transfer/logic/persistent_msg_handler.go @@ -0,0 +1,78 @@ +/* +** description(""). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/5/11 15:37). + */ +package logic + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db/mysql_model/im_mysql_msg_model" + kfk "Open_IM/pkg/common/kafka" + "Open_IM/pkg/common/log" + pbMsg "Open_IM/pkg/proto/chat" + "Open_IM/pkg/utils" + "github.com/Shopify/sarama" + "github.com/golang/protobuf/proto" +) + +type PersistentConsumerHandler struct { + msgHandle map[string]fcb + persistentConsumerGroup *kfk.MConsumerGroup +} + +func (pc *PersistentConsumerHandler) Init() { + pc.msgHandle = make(map[string]fcb) + pc.msgHandle[config.Config.Kafka.Ws2mschat.Topic] = pc.handleChatWs2Mysql + pc.persistentConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic}, + config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMySql) + +} + +func (pc *PersistentConsumerHandler) handleChatWs2Mysql(msg []byte, msgKey string) { + log.NewInfo("msg come here mysql!!!", "", "msg", string(msg)) + var tag bool + msgFromMQ := pbMsg.MsgDataToMQ{} + err := proto.Unmarshal(msg, &msgFromMQ) + if err != nil { + log.NewError(msgFromMQ.OperationID, "msg_transfer Unmarshal msg err", "msg", string(msg), "err", err.Error()) + return + } + //Control whether to store history messages (mysql) + isPersist := utils.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsPersistent) + //Only process receiver data + if isPersist { + switch msgFromMQ.MsgData.SessionType { + case constant.SingleChatType, constant.NotificationChatType: + if msgKey == msgFromMQ.MsgData.RecvID { + tag = true + } + case constant.GroupChatType: + if msgKey == msgFromMQ.MsgData.SendID || utils.IsContain(msgFromMQ.MsgData.SendID, config.Config.Manager.AppManagerUid) { + tag = true + } + } + if tag { + log.NewInfo(msgFromMQ.OperationID, "msg_transfer msg persisting", string(msg)) + if err = im_mysql_msg_model.InsertMessageToChatLog(msgFromMQ); err != nil { + log.NewError(msgFromMQ.OperationID, "Message insert failed", "err", err.Error(), "msg", msgFromMQ.String()) + return + } + } + + } +} +func (PersistentConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil } +func (PersistentConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } +func (pc *PersistentConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, + claim sarama.ConsumerGroupClaim) error { + for msg := range claim.Messages() { + log.InfoByKv("kafka get info to mysql", "", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value)) + pc.msgHandle[msg.Topic](msg.Value, string(msg.Key)) + sess.MarkMessage(msg, "") + } + return nil +} diff --git a/internal/push/content_struct/content.go b/internal/push/content_struct/content.go new file mode 100644 index 000000000..c27b3f92a --- /dev/null +++ b/internal/push/content_struct/content.go @@ -0,0 +1,85 @@ +/* +** description(""). +** copyright('open-im,www.open-im.io'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/5/27 11:24). + */ +package content_struct + +import ( + "encoding/json" +) + +type Content struct { + IsDisplay int32 `json:"isDisplay"` + ID string `json:"id"` + Text string `json:"text"` +} + +func NewContentStructString(isDisplay int32, ID string, text string) string { + c := Content{IsDisplay: isDisplay, ID: ID, Text: text} + return c.contentToString() +} + +func (c *Content) contentToString() string { + data, _ := json.Marshal(c) + dataString := string(data) + return dataString +} + +type groupMemberFullInfo struct { + GroupId string `json:"groupID"` + UserId string `json:"userId"` + Role int `json:"role"` + JoinTime uint64 `json:"joinTime"` + NickName string `json:"nickName"` + FaceUrl string `json:"faceUrl"` +} + +type AgreeOrRejectGroupMember struct { + GroupId string `json:"groupID"` + UserId string `json:"userId"` + Role int `json:"role"` + JoinTime uint64 `json:"joinTime"` + NickName string `json:"nickName"` + FaceUrl string `json:"faceUrl"` + Reason string `json:"reason"` +} +type AtTextContent struct { + Text string `json:"text"` + AtUserList []string `json:"atUserList"` + IsAtSelf bool `json:"isAtSelf"` +} + +type CreateGroupSysMsg struct { + uIdCreator string `creatorUid` + initMemberList []groupMemberFullInfo `json: initMemberList` + CreateTime uint64 `json:"CreateTime"` + Text string `json:"text"` +} + +type NotificationContent struct { + IsDisplay int32 `json:"isDisplay"` + DefaultTips string `json:"defaultTips"` + Detail string `json:"detail"` +} + +func (c *NotificationContent) ContentToString() string { + data, _ := json.Marshal(c) + dataString := string(data) + return dataString +} + +type KickGroupMemberApiReq struct { + GroupID string `json:"groupID"` + UidList []string `json:"uidList"` + Reason string `json:"reason"` + OperationID string `json:"operationID"` +} + +func NewCreateGroupSysMsgString(create *CreateGroupSysMsg, text string) string { + create.Text = text + jstring, _ := json.Marshal(create) + + return string(jstring) +} diff --git a/internal/push/getui/push.go b/internal/push/getui/push.go new file mode 100644 index 000000000..b91b51fc2 --- /dev/null +++ b/internal/push/getui/push.go @@ -0,0 +1,222 @@ +package getui + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "bytes" + "crypto/sha256" + "errors" + + //"crypto/sha512" + "encoding/hex" + "encoding/json" + "io/ioutil" + "net/http" + "strconv" + "time" +) + +var ( + GetuiClient *Getui + + TokenExpireError = errors.New("token expire") +) + +const ( + PushURL = "/push/single/alias" + AuthURL = "/auth" +) + +func init() { + GetuiClient = newGetuiClient() +} + +type Getui struct{} + +type GetuiCommonResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` +} + +type AuthReq struct { + Sign string `json:"sign"` + Timestamp string `json:"timestamp"` + Appkey string `json:"appkey"` +} + +type AuthResp struct { + ExpireTime string `json:"expire_time"` + Token string `json:"token"` +} + +type PushReq struct { + RequestID string `json:"request_id"` + Audience struct { + Alias []string `json:"alias"` + } `json:"audience"` + PushMessage struct { + Notification Notification `json:"notification,omitempty"` + Transmission string `json:"transmission,omitempty"` + } `json:"push_message"` + PushChannel struct { + Ios Ios `json:"ios"` + Android Android `json:"android"` + } `json:"push_channel"` +} + +type Ios struct { + Aps struct { + Sound string `json:"sound"` + Alert Alert `json:"alert"` + } `json:"aps"` +} + +type Alert struct { + Title string `json:"title"` + Body string `json:"body"` +} + +type Android struct { + Ups struct { + Notification Notification `json:"notification"` + } `json:"ups"` +} + +type Notification struct { + Title string `json:"title"` + Body string `json:"body"` + ClickType string `json:"click_type"` +} + +type PushResp struct { +} + +func newGetuiClient() *Getui { + return &Getui{} +} + +func (g *Getui) Push(userIDList []string, alert, detailContent, operationID string) (resp string, err error) { + token, err := db.DB.GetGetuiToken() + log.NewDebug(operationID, utils.GetSelfFuncName(), "token:", token) + if err != nil { + log.NewError(operationID, utils.OperationIDGenerator(), "GetGetuiToken failed", err.Error()) + } + if token == "" || err != nil { + token, err = g.getTokenAndSave2Redis(operationID) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "getTokenAndSave2Redis failed", err.Error()) + return "", utils.Wrap(err, "") + } + } + pushReq := PushReq{ + RequestID: utils.OperationIDGenerator(), + Audience: struct { + Alias []string `json:"alias"` + }{Alias: []string{userIDList[0]}}, + } + pushReq.PushMessage.Notification = Notification{ + Title: alert, + Body: alert, + ClickType: "startapp", + } + pushReq.PushChannel.Ios.Aps.Sound = "default" + pushReq.PushChannel.Ios.Aps.Alert = Alert{ + Title: alert, + Body: alert, + } + pushReq.PushChannel.Android.Ups.Notification = Notification{ + Title: alert, + Body: alert, + ClickType: "startapp", + } + pushResp := PushResp{} + err = g.request(PushURL, pushReq, token, &pushResp, operationID) + switch err { + case TokenExpireError: + token, err = g.getTokenAndSave2Redis(operationID) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "getTokenAndSave2Redis failed, ", err.Error()) + } else { + log.NewInfo(operationID, utils.GetSelfFuncName(), "getTokenAndSave2Redis: ", token) + } + } + if err != nil { + return "", utils.Wrap(err, "push failed") + } + respBytes, err := json.Marshal(pushResp) + return string(respBytes), utils.Wrap(err, "") +} + +func (g *Getui) Auth(operationID string, timeStamp int64) (token string, expireTime int64, err error) { + log.NewInfo(operationID, utils.GetSelfFuncName(), config.Config.Push.Getui.AppKey, timeStamp, config.Config.Push.Getui.MasterSecret) + h := sha256.New() + h.Write([]byte(config.Config.Push.Getui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.Getui.MasterSecret)) + sum := h.Sum(nil) + sign := hex.EncodeToString(sum) + log.NewInfo(operationID, utils.GetSelfFuncName(), "sha256 result", sign) + reqAuth := AuthReq{ + Sign: sign, + Timestamp: strconv.Itoa(int(timeStamp)), + Appkey: config.Config.Push.Getui.AppKey, + } + respAuth := AuthResp{} + err = g.request(AuthURL, reqAuth, "", &respAuth, operationID) + if err != nil { + return "", 0, err + } + log.NewInfo(operationID, utils.GetSelfFuncName(), "result: ", respAuth) + expire, err := strconv.Atoi(respAuth.ExpireTime) + return respAuth.Token, int64(expire), err +} + +func (g *Getui) request(url string, content interface{}, token string, returnStruct interface{}, operationID string) error { + con, err := json.Marshal(content) + if err != nil { + return err + } + client := &http.Client{} + log.Debug(operationID, utils.GetSelfFuncName(), "json:", string(con)) + req, err := http.NewRequest("POST", config.Config.Push.Getui.PushUrl+url, bytes.NewBuffer(con)) + if err != nil { + return err + } + if token != "" { + req.Header.Set("token", token) + } + req.Header.Set("content-type", "application/json") + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + result, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + log.NewInfo(operationID, "getui", utils.GetSelfFuncName(), "resp, ", string(result)) + commonResp := GetuiCommonResp{} + commonResp.Data = returnStruct + if err := json.Unmarshal(result, &commonResp); err != nil { + return err + } + if commonResp.Code == 10001 { + return TokenExpireError + } + return nil +} + +func (g *Getui) getTokenAndSave2Redis(operationID string) (token string, err error) { + token, expireTime, err := g.Auth(operationID, time.Now().UnixNano()/1e6) + if err != nil { + return "", utils.Wrap(err, "Auth failed") + } + log.NewDebug(operationID, "getui", utils.GetSelfFuncName(), token, expireTime, err) + err = db.DB.SetGetuiToken(token, 60*60*23) + if err != nil { + return "", utils.Wrap(err, "Auth failed") + } + return token, nil +} diff --git a/internal/push/jpush/common/JGPlatform.go b/internal/push/jpush/common/JGPlatform.go new file mode 100644 index 000000000..e2e858cf4 --- /dev/null +++ b/internal/push/jpush/common/JGPlatform.go @@ -0,0 +1,13 @@ +package common + +import ( + "encoding/base64" + "fmt" +) + +func GetAuthorization(Appkey string, MasterSecret string) string { + str := fmt.Sprintf("%s:%s", Appkey, MasterSecret) + buf := []byte(str) + Authorization := fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString(buf)) + return Authorization +} diff --git a/internal/push/jpush/push.go b/internal/push/jpush/push.go new file mode 100644 index 000000000..aaaee306d --- /dev/null +++ b/internal/push/jpush/push.go @@ -0,0 +1,74 @@ +package push + +import ( + "Open_IM/internal/push/jpush/common" + "Open_IM/internal/push/jpush/requestBody" + "Open_IM/pkg/common/config" + "bytes" + "encoding/json" + "io/ioutil" + "net/http" +) + +var ( + JPushClient *JPush +) + +func init() { + JPushClient = newGetuiClient() +} + +type JPush struct{} + +func newGetuiClient() *JPush { + return &JPush{} +} + +func (j *JPush) Auth(apiKey, secretKey string, timeStamp int64) (token string, err error) { + return token, nil +} + +func (j *JPush) SetAlias(cid, alias string) (resp string, err error) { + return resp, nil +} + +func (j *JPush) Push(accounts []string, alert, detailContent, operationID string) (string, error) { + var pf requestBody.Platform + pf.SetAll() + var au requestBody.Audience + au.SetAlias(accounts) + var no requestBody.Notification + no.SetAlert(alert) + var me requestBody.Message + me.SetMsgContent(detailContent) + var o requestBody.Options + o.SetApnsProduction(false) + var po requestBody.PushObj + po.SetPlatform(&pf) + po.SetAudience(&au) + po.SetNotification(&no) + po.SetMessage(&me) + po.SetOptions(&o) + + con, err := json.Marshal(po) + if err != nil { + return "", err + } + client := &http.Client{} + req, err := http.NewRequest("POST", config.Config.Push.Jpns.PushUrl, bytes.NewBuffer(con)) + if err != nil { + return "", err + } + req.Header.Set("Authorization", common.GetAuthorization(config.Config.Push.Jpns.AppKey, config.Config.Push.Jpns.MasterSecret)) + + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + result, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(result), nil +} diff --git a/internal/push/jpush/requestBody/audience.go b/internal/push/jpush/requestBody/audience.go new file mode 100644 index 000000000..dc20a83df --- /dev/null +++ b/internal/push/jpush/requestBody/audience.go @@ -0,0 +1,53 @@ +package requestBody + +const ( + TAG = "tag" + TAG_AND = "tag_and" + TAG_NOT = "tag_not" + ALIAS = "alias" + REGISTRATION_ID = "registration_id" + SEGMENT = "segment" + ABTEST = "abtest" +) + +type Audience struct { + Object interface{} + audience map[string][]string +} + +func (a *Audience) set(key string, v []string) { + if a.audience == nil { + a.audience = make(map[string][]string) + a.Object = a.audience + } + + //v, ok = this.audience[key] + //if ok { + // return + //} + a.audience[key] = v +} + +func (a *Audience) SetTag(tags []string) { + a.set(TAG, tags) +} + +func (a *Audience) SetTagAnd(tags []string) { + a.set(TAG_AND, tags) +} + +func (a *Audience) SetTagNot(tags []string) { + a.set(TAG_NOT, tags) +} + +func (a *Audience) SetAlias(alias []string) { + a.set(ALIAS, alias) +} + +func (a *Audience) SetRegistrationId(ids []string) { + a.set(REGISTRATION_ID, ids) +} + +func (a *Audience) SetAll() { + a.Object = "all" +} diff --git a/internal/push/jpush/requestBody/message.go b/internal/push/jpush/requestBody/message.go new file mode 100644 index 000000000..6e6fe1eb9 --- /dev/null +++ b/internal/push/jpush/requestBody/message.go @@ -0,0 +1,27 @@ +package requestBody + +type Message struct { + MsgContent string `json:"msg_content"` + Title string `json:"title,omitempty"` + ContentType string `json:"content_type,omitempty"` + Extras map[string]interface{} `json:"extras,omitempty"` +} + +func (m *Message) SetMsgContent(c string) { + m.MsgContent = c +} + +func (m *Message) SetTitle(t string) { + m.Title = t +} + +func (m *Message) SetContentType(c string) { + m.ContentType = c +} + +func (m *Message) SetExtras(key string, value interface{}) { + if m.Extras == nil { + m.Extras = make(map[string]interface{}) + } + m.Extras[key] = value +} diff --git a/internal/push/jpush/requestBody/notification.go b/internal/push/jpush/requestBody/notification.go new file mode 100644 index 000000000..9ff49a439 --- /dev/null +++ b/internal/push/jpush/requestBody/notification.go @@ -0,0 +1,36 @@ +package requestBody + +import ( + "Open_IM/pkg/common/config" +) + +type Notification struct { + Alert string `json:"alert,omitempty"` + Android Android `json:"android,omitempty"` + IOS Ios `json:"ios,omitempty"` +} + +type Android struct { + Alert string `json:"alert,omitempty"` + Intent struct { + URL string `json:"url,omitempty"` + } `json:"intent,omitempty"` +} +type Ios struct { + Alert string `json:"alert,omitempty"` + Sound string `json:"sound,omitempty"` + Badge string `json:"badge,omitempty"` +} + +func (n *Notification) SetAlert(alert string) { + n.Alert = alert + n.Android.Alert = alert + n.SetAndroidIntent() + n.IOS.Alert = alert + n.IOS.Sound = "default" + n.IOS.Badge = "+1" + +} +func (n *Notification) SetAndroidIntent() { + n.Android.Intent.URL = config.Config.Push.Jpns.PushIntent +} diff --git a/internal/push/jpush/requestBody/options.go b/internal/push/jpush/requestBody/options.go new file mode 100644 index 000000000..f82ebd035 --- /dev/null +++ b/internal/push/jpush/requestBody/options.go @@ -0,0 +1,9 @@ +package requestBody + +type Options struct { + ApnsProduction bool `json:"apns_production"` +} + +func (o *Options) SetApnsProduction(c bool) { + o.ApnsProduction = c +} diff --git a/internal/push/jpush/requestBody/platform.go b/internal/push/jpush/requestBody/platform.go new file mode 100644 index 000000000..0f9d243cf --- /dev/null +++ b/internal/push/jpush/requestBody/platform.go @@ -0,0 +1,83 @@ +package requestBody + +import ( + "Open_IM/pkg/common/constant" + "errors" +) + +const ( + ANDROID = "android" + IOS = "ios" + QUICKAPP = "quickapp" + WINDOWSPHONE = "winphone" + ALL = "all" +) + +type Platform struct { + Os interface{} + osArry []string +} + +func (p *Platform) Set(os string) error { + if p.Os == nil { + p.osArry = make([]string, 0, 4) + } else { + switch p.Os.(type) { + case string: + return errors.New("platform is all") + default: + } + } + + for _, value := range p.osArry { + if os == value { + return nil + } + } + + switch os { + case IOS: + fallthrough + case ANDROID: + fallthrough + case QUICKAPP: + fallthrough + case WINDOWSPHONE: + p.osArry = append(p.osArry, os) + p.Os = p.osArry + default: + return errors.New("unknow platform") + } + + return nil +} +func (p *Platform) SetPlatform(platform string) error { + switch platform { + case constant.AndroidPlatformStr: + return p.SetAndroid() + case constant.IOSPlatformStr: + return p.SetIOS() + default: + return errors.New("platform err") + } + +} +func (p *Platform) SetIOS() error { + return p.Set(IOS) +} + +func (p *Platform) SetAndroid() error { + return p.Set(ANDROID) +} + +func (p *Platform) SetQuickApp() error { + return p.Set(QUICKAPP) +} + +func (p *Platform) SetWindowsPhone() error { + return p.Set(WINDOWSPHONE) +} + +func (p *Platform) SetAll() { + p.Os = ALL +} diff --git a/internal/push/jpush/requestBody/pushObj.go b/internal/push/jpush/requestBody/pushObj.go new file mode 100644 index 000000000..974161407 --- /dev/null +++ b/internal/push/jpush/requestBody/pushObj.go @@ -0,0 +1,28 @@ +package requestBody + +type PushObj struct { + Platform interface{} `json:"platform"` + Audience interface{} `json:"audience"` + Notification interface{} `json:"notification,omitempty"` + Message interface{} `json:"message,omitempty"` + Options interface{} `json:"options,omitempty"` +} + +func (p *PushObj) SetPlatform(pf *Platform) { + p.Platform = pf.Os +} + +func (p *PushObj) SetAudience(ad *Audience) { + p.Audience = ad.Object +} + +func (p *PushObj) SetNotification(no *Notification) { + p.Notification = no +} + +func (p *PushObj) SetMessage(m *Message) { + p.Message = m +} +func (p *PushObj) SetOptions(o *Options) { + p.Options = o +} diff --git a/internal/push/logic/init.go b/internal/push/logic/init.go new file mode 100644 index 000000000..d2d127091 --- /dev/null +++ b/internal/push/logic/init.go @@ -0,0 +1,39 @@ +/* +** description(""). +** copyright('open-im,www.open-im.io'). +** author("fg,Gordon@open-im.io"). +** time(2021/3/22 15:33). + */ +package logic + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/kafka" + "Open_IM/pkg/statistics" + "fmt" +) + +var ( + rpcServer RPCServer + pushCh PushConsumerHandler + pushTerminal []int32 + producer *kafka.Producer + count uint64 +) + +func Init(rpcPort int) { + + rpcServer.Init(rpcPort) + pushCh.Init() + pushTerminal = []int32{constant.IOSPlatformID, constant.AndroidPlatformID} +} +func init() { + producer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.Ws2mschat.Topic) + statistics.NewStatistics(&count, config.Config.ModuleName.PushName, fmt.Sprintf("%d second push to msg_gateway count", 300), 300) +} + +func Run() { + go rpcServer.run() + go pushCh.pushConsumerGroup.RegisterHandleAndConsumer(&pushCh) +} diff --git a/internal/push/logic/push_handler.go b/internal/push/logic/push_handler.go new file mode 100644 index 000000000..294c48f15 --- /dev/null +++ b/internal/push/logic/push_handler.go @@ -0,0 +1,52 @@ +/* +** description(""). +** copyright('Open_IM,www.Open_IM.io'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/5/13 10:33). + */ +package logic + +import ( + "Open_IM/pkg/common/config" + kfk "Open_IM/pkg/common/kafka" + "Open_IM/pkg/common/log" + pbChat "Open_IM/pkg/proto/chat" + pbPush "Open_IM/pkg/proto/push" + "github.com/Shopify/sarama" + "github.com/golang/protobuf/proto" +) + +type fcb func(msg []byte) + +type PushConsumerHandler struct { + msgHandle map[string]fcb + pushConsumerGroup *kfk.MConsumerGroup +} + +func (ms *PushConsumerHandler) Init() { + ms.msgHandle = make(map[string]fcb) + ms.msgHandle[config.Config.Kafka.Ms2pschat.Topic] = ms.handleMs2PsChat + ms.pushConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0, + OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ms2pschat.Topic}, config.Config.Kafka.Ms2pschat.Addr, + config.Config.Kafka.ConsumerGroupID.MsgToPush) +} +func (ms *PushConsumerHandler) handleMs2PsChat(msg []byte) { + log.InfoByKv("msg come from kafka And push!!!", "", "msg", string(msg)) + msgFromMQ := pbChat.PushMsgDataToMQ{} + if err := proto.Unmarshal(msg, &msgFromMQ); err != nil { + log.ErrorByKv("push Unmarshal msg err", "", "msg", string(msg), "err", err.Error()) + return + } + //Call push module to send message to the user + MsgToUser((*pbPush.PushMsgReq)(&msgFromMQ)) +} +func (PushConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil } +func (PushConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } +func (ms *PushConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, + claim sarama.ConsumerGroupClaim) error { + for msg := range claim.Messages() { + log.InfoByKv("kafka get info to mysql", "", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value)) + ms.msgHandle[msg.Topic](msg.Value) + } + return nil +} diff --git a/internal/push/logic/push_rpc_server.go b/internal/push/logic/push_rpc_server.go new file mode 100644 index 000000000..b622ba721 --- /dev/null +++ b/internal/push/logic/push_rpc_server.go @@ -0,0 +1,57 @@ +package logic + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + "Open_IM/pkg/proto/push" + "Open_IM/pkg/utils" + "context" + "google.golang.org/grpc" + "net" + "strings" +) + +type RPCServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func (r *RPCServer) Init(rpcPort int) { + r.rpcPort = rpcPort + r.rpcRegisterName = config.Config.RpcRegisterName.OpenImPushName + r.etcdSchema = config.Config.Etcd.EtcdSchema + r.etcdAddr = config.Config.Etcd.EtcdAddr +} +func (r *RPCServer) run() { + ip := utils.ServerIP + registerAddress := ip + ":" + utils.IntToString(r.rpcPort) + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.ErrorByKv("push module rpc listening port err", "", "err", err.Error()) + return + } + defer listener.Close() + srv := grpc.NewServer() + defer srv.GracefulStop() + pbPush.RegisterPushMsgServiceServer(srv, r) + err = getcdv3.RegisterEtcd(r.etcdSchema, strings.Join(r.etcdAddr, ","), ip, r.rpcPort, r.rpcRegisterName, 10) + if err != nil { + log.ErrorByKv("register push module rpc to etcd err", "", "err", err.Error()) + } + err = srv.Serve(listener) + if err != nil { + log.ErrorByKv("push module rpc start err", "", "err", err.Error()) + return + } +} +func (r *RPCServer) PushMsg(_ context.Context, pbData *pbPush.PushMsgReq) (*pbPush.PushMsgResp, error) { + //Call push module to send message to the user + MsgToUser(pbData) + return &pbPush.PushMsgResp{ + ResultCode: 0, + }, nil + +} diff --git a/internal/push/logic/push_to_client.go b/internal/push/logic/push_to_client.go new file mode 100644 index 000000000..607d36db0 --- /dev/null +++ b/internal/push/logic/push_to_client.go @@ -0,0 +1,167 @@ +/* +** description(""). +** copyright('open-im,www.open-im.io'). +** author("fg,Gordon@open-im.io"). +** time(2021/3/5 14:31). + */ +package logic + +import ( + pusher "Open_IM/internal/push" + "Open_IM/internal/push/getui" + jpush "Open_IM/internal/push/jpush" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbPush "Open_IM/pkg/proto/push" + pbRelay "Open_IM/pkg/proto/relay" + "Open_IM/pkg/utils" + "context" + "encoding/json" + "strings" +) + +type OpenIMContent struct { + SessionType int `json:"sessionType"` + From string `json:"from"` + To string `json:"to"` + Seq uint32 `json:"seq"` +} +type AtContent struct { + Text string `json:"text"` + AtUserList []string `json:"atUserList"` + IsAtSelf bool `json:"isAtSelf"` +} + +func MsgToUser(pushMsg *pbPush.PushMsgReq) { + var wsResult []*pbRelay.SingleMsgToUser + isOfflinePush := utils.GetSwitchFromOptions(pushMsg.MsgData.Options, constant.IsOfflinePush) + log.Debug("Get msg from msg_transfer And push msg", pushMsg.OperationID, "PushData", pushMsg.String()) + grpcCons := getcdv3.GetConn4Unique(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOnlineMessageRelayName) + //Online push message + log.Debug("test", pushMsg.OperationID, "len grpc", len(grpcCons), "data", pushMsg.String()) + for _, v := range grpcCons { + msgClient := pbRelay.NewOnlineMessageRelayServiceClient(v) + reply, err := msgClient.OnlinePushMsg(context.Background(), &pbRelay.OnlinePushMsgReq{OperationID: pushMsg.OperationID, MsgData: pushMsg.MsgData, PushToUserID: pushMsg.PushToUserID}) + if err != nil { + log.InfoByKv("push data to client rpc err", pushMsg.OperationID, "err", err) + continue + } + if reply != nil && reply.Resp != nil { + wsResult = append(wsResult, reply.Resp...) + } + } + log.InfoByKv("push_result", pushMsg.OperationID, "result", wsResult, "sendData", pushMsg.MsgData) + count++ + if isOfflinePush && pushMsg.PushToUserID != pushMsg.MsgData.SendID { + for _, v := range wsResult { + if v.ResultCode == 0 { + continue + } + if utils.IsContainInt32(v.RecvPlatFormID, pushTerminal) { + //Use offline push messaging + var UIDList []string + UIDList = append(UIDList, v.RecvID) + customContent := OpenIMContent{ + SessionType: int(pushMsg.MsgData.SessionType), + From: pushMsg.MsgData.SendID, + To: pushMsg.MsgData.RecvID, + Seq: pushMsg.MsgData.Seq, + } + bCustomContent, _ := json.Marshal(customContent) + jsonCustomContent := string(bCustomContent) + var content string + if pushMsg.MsgData.OfflinePushInfo != nil { + content = pushMsg.MsgData.OfflinePushInfo.Title + + } else { + switch pushMsg.MsgData.ContentType { + case constant.Text: + content = constant.ContentType2PushContent[constant.Text] + case constant.Picture: + content = constant.ContentType2PushContent[constant.Picture] + case constant.Voice: + content = constant.ContentType2PushContent[constant.Voice] + case constant.Video: + content = constant.ContentType2PushContent[constant.Video] + case constant.File: + content = constant.ContentType2PushContent[constant.File] + case constant.AtText: + a := AtContent{} + _ = utils.JsonStringToStruct(string(pushMsg.MsgData.Content), &a) + if utils.IsContain(v.RecvID, a.AtUserList) { + content = constant.ContentType2PushContent[constant.AtText] + constant.ContentType2PushContent[constant.Common] + } else { + content = constant.ContentType2PushContent[constant.GroupMsg] + } + default: + content = constant.ContentType2PushContent[constant.Common] + } + } + var offlinePusher pusher.OfflinePusher + if config.Config.Push.Getui.Enable { + log.NewInfo(pushMsg.OperationID, utils.GetSelfFuncName(), config.Config.Push.Getui) + offlinePusher = getui.GetuiClient + } + if config.Config.Push.Jpns.Enable { + offlinePusher = jpush.JPushClient + } + if offlinePusher == nil { + offlinePusher = jpush.JPushClient + } + pushResult, err := offlinePusher.Push(UIDList, content, jsonCustomContent, pushMsg.OperationID) + if err != nil { + log.NewError(pushMsg.OperationID, "offline push error", pushMsg.String(), err.Error()) + } else { + log.NewDebug(pushMsg.OperationID, "offline push return result is ", pushResult, pushMsg.MsgData) + } + break + } + + } + + } +} + +//func SendMsgByWS(m *pbChat.WSToMsgSvrChatMsg) { +// m.MsgID = rpcChat.GetMsgID(m.SendID) +// m.ClientMsgID = m.MsgID +// switch m.SessionType { +// case constant.SingleChatType: +// sendMsgToKafka(m, m.SendID, "msgKey--sendID") +// sendMsgToKafka(m, m.RecvID, "msgKey--recvID") +// case constant.GroupChatType: +// etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) +// client := pbGroup.NewGroupClient(etcdConn) +// req := &pbGroup.Req{ +// GroupID: m.RecvID, +// Token: config.Config.Secret, +// OperationID: m.OperationID, +// } +// reply, err := client.(context.Background(), req) +// if err != nil { +// log.Error(m.Token, m.OperationID, "rpc getGroupInfo failed, err = %s", err.Error()) +// return +// } +// if reply.ErrorCode != 0 { +// log.Error(m.Token, m.OperationID, "rpc getGroupInfo failed, err = %s", reply.ErrorMsg) +// return +// } +// groupID := m.RecvID +// for i, v := range reply.MemberList { +// m.RecvID = v.UserId + " " + groupID +// sendMsgToKafka(m, utils.IntToString(i), "msgKey--recvID+\" \"+groupID") +// } +// default: +// +// } +//} +// +//func sendMsgToKafka(m *pbChat.WSToMsgSvrChatMsg, key string, flag string) { +// pid, offset, err := producer.SendMessage(m, key) +// if err != nil { +// log.ErrorByKv("kafka send failed", m.OperationID, "send data", m.String(), "pid", pid, "offset", offset, "err", err.Error(), flag, key) +// } +// +//} diff --git a/internal/push/logic/tpns.go b/internal/push/logic/tpns.go new file mode 100644 index 000000000..3d737f4a7 --- /dev/null +++ b/internal/push/logic/tpns.go @@ -0,0 +1,34 @@ +package logic + +import ( + tpns "Open_IM/internal/push/sdk/tpns-server-sdk-go/go" + "Open_IM/internal/push/sdk/tpns-server-sdk-go/go/auth" + "Open_IM/internal/push/sdk/tpns-server-sdk-go/go/common" + "Open_IM/internal/push/sdk/tpns-server-sdk-go/go/req" + "Open_IM/pkg/common/config" +) + +var badgeType = -2 +var iosAcceptId = auth.Auther{AccessID: config.Config.Push.Tpns.Ios.AccessID, SecretKey: config.Config.Push.Tpns.Ios.SecretKey} + +func IOSAccountListPush(accounts []string, title, content, jsonCustomContent string) { + var iosMessage = tpns.Message{ + Title: title, + Content: content, + IOS: &tpns.IOSParams{ + Aps: &tpns.Aps{ + BadgeType: &badgeType, + Sound: "default", + Category: "INVITE_CATEGORY", + }, + CustomContent: jsonCustomContent, + //CustomContent: `"{"key\":\"value\"}"`, + }, + } + pushReq, reqBody, err := req.NewListAccountPush(accounts, iosMessage) + if err != nil { + return + } + iosAcceptId.Auth(pushReq, auth.UseSignAuthored, iosAcceptId, reqBody) + common.PushAndGetResult(pushReq) +} diff --git a/internal/push/push_interface.go b/internal/push/push_interface.go new file mode 100644 index 000000000..59b4764b4 --- /dev/null +++ b/internal/push/push_interface.go @@ -0,0 +1,5 @@ +package push + +type OfflinePusher interface { + Push(userIDList []string, alert, detailContent, operationID string) (resp string, err error) +} diff --git a/internal/push/sdk/tpns-server-sdk-go/go/auth/auth.go b/internal/push/sdk/tpns-server-sdk-go/go/auth/auth.go new file mode 100644 index 000000000..5b8a486b0 --- /dev/null +++ b/internal/push/sdk/tpns-server-sdk-go/go/auth/auth.go @@ -0,0 +1,62 @@ +package auth + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + b64 "encoding/base64" + "encoding/hex" + "fmt" + "net/http" + "strconv" + "time" +) + +type Auther struct { + AccessID string + SecretKey string +} + +var UseSignAuthored = true + +func (a *Auther) Auth(req *http.Request, useSignAuthored bool, auth Auther, reqBody string) { + + if useSignAuthored { + now := time.Now() + timeStamp := now.Unix() + req.Header.Add("AccessId", auth.AccessID) + req.Header.Add("TimeStamp", strconv.Itoa(int(timeStamp))) + sign := GenSign(uint64(timeStamp), auth.AccessID, auth.SecretKey, reqBody) + req.Header.Add("Sign", sign) + } else { + author := makeAuthHeader(a.AccessID, a.SecretKey) + //log.Printf("author string:%v", author) + req.Header.Add("Authorization", author) + } + //req.Header.Add("Content-Type", "application/json") +} + +func makeAuthHeader(appID, secretKey string) string { + base64Str := base64.StdEncoding.EncodeToString( + []byte( + fmt.Sprintf("%s:%s", appID, secretKey), + ), + ) + return fmt.Sprintf("Basic %s", base64Str) +} + +func GenSign(timeStamp uint64, accessId string, secretKey, requestBody string) string { + signBody := strconv.Itoa(int(timeStamp)) + accessId + requestBody + // Create a new HMAC by defining the hash type and the key (as byte array) + h := hmac.New(sha256.New, []byte(secretKey)) + // Write Data to it + h.Write([]byte(signBody)) + + // Get result and encode as hexadecimal string + sha := hex.EncodeToString(h.Sum(nil)) + //fmt.Println() + //fmt.Println("timeStamp: " + strconv.Itoa(int(timeStamp)) + " accessID:" + accessId + " body:" + requestBody) + sEnc := b64.StdEncoding.EncodeToString([]byte(sha)) + //fmt.Println("final Result " + sEnc) + return sEnc +} diff --git a/internal/push/sdk/tpns-server-sdk-go/go/client/client.go b/internal/push/sdk/tpns-server-sdk-go/go/client/client.go new file mode 100644 index 000000000..848724402 --- /dev/null +++ b/internal/push/sdk/tpns-server-sdk-go/go/client/client.go @@ -0,0 +1,18 @@ +package client + +import ( + "net/http" + "time" +) + +func New() *http.Client { + return &http.Client{ + Transport: &http.Transport{ + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 30 * time.Second, + DisableCompression: false, + DisableKeepAlives: false, + }, + } +} diff --git a/internal/push/sdk/tpns-server-sdk-go/go/common/http_helper.go b/internal/push/sdk/tpns-server-sdk-go/go/common/http_helper.go new file mode 100644 index 000000000..6c010c4f4 --- /dev/null +++ b/internal/push/sdk/tpns-server-sdk-go/go/common/http_helper.go @@ -0,0 +1,62 @@ +package common + +import ( + tpns "Open_IM/internal/push/sdk/tpns-server-sdk-go/go" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +func PushAndGetResult(pushReq *http.Request) { + c := &http.Client{} + rsp, err := c.Do(pushReq) + fmt.Println() + if err != nil { + //fmt.Printf("http err:%v", err) + return + } + defer rsp.Body.Close() + body, err := ioutil.ReadAll(rsp.Body) + //fmt.Printf("http ReadAll err:%v, body:%v ", err, string(body)) + if err != nil { + return + } + r := &tpns.CommonRsp{} + json.Unmarshal(body, r) + //fmt.Printf("push result: %+v", r) +} + +func UploadFile(req *http.Request) (int, error) { + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return 0, err + } + + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return 0, err + } + + if resp.StatusCode != http.StatusOK { + return 0, fmt.Errorf("response error, status: %s, body: %s", resp.Status, string(body)) + } + + type uploadResponse struct { + RetCode int `json:"retCode"` + ErrMsg string `json:"errMsg"` + UploadId int `json:"uploadId"` + } + + var ur uploadResponse + if err := json.Unmarshal(body, &ur); err != nil { + return 0, err + } + + if ur.RetCode != 0 { + return 0, fmt.Errorf("response with %d:%s", ur.RetCode, ur.ErrMsg) + } + return ur.UploadId, nil +} diff --git a/internal/push/sdk/tpns-server-sdk-go/go/common/json_helper.go b/internal/push/sdk/tpns-server-sdk-go/go/common/json_helper.go new file mode 100644 index 000000000..368cfd843 --- /dev/null +++ b/internal/push/sdk/tpns-server-sdk-go/go/common/json_helper.go @@ -0,0 +1,8 @@ +package common + +import "encoding/json" + +func ToJson(v interface{}) string { + bs, _ := json.Marshal(v) + return string(bs) +} diff --git a/internal/push/sdk/tpns-server-sdk-go/go/def.go b/internal/push/sdk/tpns-server-sdk-go/go/def.go new file mode 100644 index 000000000..3e5d383e4 --- /dev/null +++ b/internal/push/sdk/tpns-server-sdk-go/go/def.go @@ -0,0 +1,256 @@ +package tpns + +type CommonRspEnv string + +const ( + // EnvProd + EnvProd CommonRspEnv = "product" + // EnvDev + EnvDev CommonRspEnv = "dev" +) + +type CommonRsp struct { + // TODO: doc this + Seq int64 `json:"seq"` + + PushID string `json:"push_id"` + + RetCode int `json:"ret_code"` + + Environment CommonRspEnv `json:"environment"` + + ErrMsg string `json:"err_msg,omitempty"` + + Result map[string]string `json:"result,omitempty"` +} + +type AudienceType string + +const ( + AdAll AudienceType = "all" + + AdTag AudienceType = "tag" + + AdToken AudienceType = "token" + + AdTokenList AudienceType = "token_list" + + AdAccount AudienceType = "account" + + AdAccountList AudienceType = "account_list" + + AdPackageAccount AudienceType = "package_account_push" + + AdPackageToken AudienceType = "package_token_push" +) + +// MessageType push API message_type +type MessageType string + +const ( + MsgTypeNotify MessageType = "notify" + + MsgTypeMessage MessageType = "message" +) + +type Request struct { + AudienceType AudienceType `json:"audience_type"` + + Message Message `json:"message"` + + MessageType MessageType `json:"message_type"` + + Tag []TagRule `json:"tag_rules,omitempty"` + + TokenList []string `json:"token_list,omitempty"` + + AccountList []string `json:"account_list,omitempty"` + + Environment CommonRspEnv `json:"environment,omitempty"` + + UploadId int `json:"upload_id,omitempty"` + + ExpireTime int `json:"expire_time,omitempty"` + + SendTime string `json:"send_time,omitempty"` + + MultiPkg bool `json:"multi_pkg,omitempty"` + + PlanId string `json:"plan_id,omitempty"` + + AccountPushType int `json:"account_push_type,omitempty"` + + PushSpeed int `json:"push_speed,omitempty"` + + CollapseId int `json:"collapse_id"` + + TPNSOnlinePushType int `json:"tpns_online_push_type"` + + ChannelRules []*ChannelDistributeRule `json:"channel_rules,omitempty"` + + LoopParam *PushLoopParam `json:"loop_param,omitempty"` + ForceCollapse bool `json:"force_collapse"` +} + +type TagListOperation string + +type ChannelDistributeRule struct { + ChannelName string `json:"channel"` + Disable bool `json:"disable"` +} + +type PushLoopParam struct { + StartDate string `json:"startDate"` + + EndDate string `json:"endDate"` + + LoopType PushLoopType `json:"loopType"` + + LoopDayIndexs []uint32 `json:"loopDayIndexs"` + + DayTimes []string `json:"dayTimes"` +} + +type PushLoopType int32 + +const ( + TagListOpAnd TagListOperation = "AND" + + TagListOpOr TagListOperation = "OR" +) + +type TagType string + +const ( + XGAutoProvince TagType = "xg_auto_province" + XGAutoActive TagType = "xg_auto_active" + XGUserDefine TagType = "xg_user_define" + XGAutoVersion TagType = "xg_auto_version" + XGAutoSdkversion TagType = "xg_auto_sdkversion" + XGAutoDevicebrand TagType = "xg_auto_devicebrand" + XGAutoDeviceversion TagType = "xg_auto_deviceversion" + XGAutoCountry TagType = "xg_auto_country" +) + +type TagRule struct { + TagItems []TagItem `json:"tag_items"` + + IsNot bool `json:"is_not"` + + Operator TagListOperation `json:"operator"` +} + +type TagItem struct { + // 标签 + Tags []string `json:"tags"` + IsNot bool `json:"is_not"` + TagsOperator TagListOperation `json:"tags_operator"` + ItemsOperator TagListOperation `json:"items_operator"` + TagType TagType `json:"tag_type"` +} + +type Message struct { + Title string `json:"title,omitempty"` + Content string `json:"content,omitempty"` + + AcceptTime []AcceptTimeItem `json:"accept_time,omitempty"` + + Android *AndroidParams `json:"android,omitempty"` + + IOS *IOSParams `json:"ios,omitempty"` + + ThreadId string `json:"thread_id,omitempty"` + + ThreadSumtext string `json:"thread_sumtext,omitempty"` + + XGMediaResources string `json:"xg_media_resources,omitempty"` + + XGMediaAudioResources string `json:"xg_media_audio_resources,omitempty"` +} + +type AcceptTimeItem struct { + Start HourAndMin `json:"start,omitempty"` + End HourAndMin `json:"end,omitempty"` +} + +type HourAndMin struct { + Hour string `json:"hour,omitempty"` + Min string `json:"min,omitempty"` +} + +type AndroidParams struct { + BuilderId *int `json:"builder_id,omitempty"` + + Ring *int `json:"ring,omitempty"` + + RingRaw string `json:"ring_raw,omitempty"` + + Vibrate *int `json:"vibrate,omitempty"` + + Lights *int `json:"lights,omitempty"` + + Clearable *int `json:"clearable,omitempty"` + + IconType *int `json:"icon_type"` + + IconRes string `json:"icon_res,omitempty"` + + StyleId *int `json:"style_id,omitempty"` + + SmallIcon string `json:"small_icon,omitempty"` + + Action *Action `json:"action,omitempty"` + + CustomContent string `json:"custom_content,omitempty"` + + ShowType *int `json:"show_type,omitempty"` + + NChId string `json:"n_ch_id,omitempty"` + + NChName string `json:"n_ch_name,omitempty"` + + HwChId string `json:"hw_ch_id,omitempty"` + + XmChId string `json:"xm_ch_id,omitempty"` + + OppoChId string `json:"oppo_ch_id,omitempty"` + + VivoChId string `json:"vivo_ch_id,omitempty"` + + BadgeType *int `json:"badge_type,omitempty"` + + IconColor *int `json:"icon_color,omitempty"` +} + +type Action struct { + ActionType *int `json:"action_type,omitempty"` + Activity string `json:"activity"` + AtyAttr AtyAttr `json:"aty_attr,omitempty"` + Intent string `json:"intent"` + Browser Browser `json:"browser,omitempty"` +} + +type Browser struct { + Url string `json:"url,omitempty"` + Confirm *int `json:"confirm,omitempty"` +} + +type AtyAttr struct { + AttrIf *int `json:"if,omitempty"` + Pf *int `json:"pf,omitempty"` +} + +type IOSParams struct { + Aps *Aps `json:"aps,omitempty"` + + CustomContent string `json:"custom_content,omitempty"` +} + +type Aps struct { + Alert map[string]string `json:"alert,omitempty"` + BadgeType *int `json:"badge_type,omitempty"` + Category string `json:"category,omitempty"` + ContentAvailableInt *int `json:"content-available,omitempty"` + MutableContent *int `json:"mutable-content,omitempty"` + Sound string `json:"sound,omitempty"` +} diff --git a/internal/push/sdk/tpns-server-sdk-go/go/req/req.go b/internal/push/sdk/tpns-server-sdk-go/go/req/req.go new file mode 100644 index 000000000..7afc07004 --- /dev/null +++ b/internal/push/sdk/tpns-server-sdk-go/go/req/req.go @@ -0,0 +1,403 @@ +package req + +import ( + tpns "Open_IM/internal/push/sdk/tpns-server-sdk-go/go" + "bytes" + "encoding/json" + "io" + "mime/multipart" + "net/http" + "os" + "path/filepath" +) + +var PushURL = "https://api.tpns.tencent.com/v3/push/app" + +//var PushURL = "https://test.api.tpns.tencent.com/v3/push/app" + +func URL(url string) { + PushURL = url +} + +type ReqOpt func(*tpns.Request) + +func NewPush(req *tpns.Request, opts ...ReqOpt) (*http.Request, string, error) { + return NewPushReq(req, opts...) +} + +func NewUploadFileRequest(host string, file string) (*http.Request, error) { + fp, err := os.Open(file) + if err != nil { + return nil, err + } + + defer fp.Close() + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile("file", filepath.Base(fp.Name())) + if err != nil { + return nil, err + } + + io.Copy(part, fp) + writer.Close() + url := host + "/v3/push/package/upload" + req, err := http.NewRequest("POST", url, body) + if err != nil { + return nil, err + } + req.Header.Add("Content-Type", writer.FormDataContentType()) + + return req, nil +} + +func NewSingleAccountPush( + message tpns.Message, + account string, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdAccountList, + AccountList: []string{account}, + Message: message, + } + return NewPushReq(req, opts...) +} + +func NewListAccountPush( + accounts []string, message tpns.Message, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdAccountList, + AccountList: accounts, + Message: message, + Environment: tpns.EnvDev, + } + return NewPushReq(req, opts...) +} + +func NewTokenPush( + tokens []string, message tpns.Message, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdTokenList, + TokenList: tokens, + Message: message, + Environment: tpns.EnvProd, + } + //fmt.Printf("reqBody :%v", common.ToJson(req)) + //fmt.Println() + return NewPushReq(req, opts...) +} + +func NewTagsPush( + tagList []tpns.TagRule, message tpns.Message, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdTag, + Tag: tagList, + Message: message, + } + //fmt.Printf("reqBody :%v", common.ToJson(req)) + //fmt.Println() + return NewPushReq(req, opts...) +} + +func NewAllPush( + message tpns.Message, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdAll, + Message: message, + } + return NewPushReq(req, opts...) +} + +func NewAccountPackagePush( + message tpns.Message, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdPackageAccount, + Message: message, + } + return NewPushReq(req, opts...) +} + +func NewTokenPackagePush( + message tpns.Message, + opts ...ReqOpt, +) (*http.Request, string, error) { + req := &tpns.Request{ + MessageType: tpns.MsgTypeNotify, + AudienceType: tpns.AdPackageToken, + Message: message, + } + return NewPushReq(req, opts...) +} + +func NewPushReq(req *tpns.Request, opts ...ReqOpt) (request *http.Request, reqBody string, err error) { + for _, opt := range opts { + opt(req) + } + bodyBytes, err := json.Marshal(req) + if err != nil { + return nil, "", err + } + reqBody = string(bodyBytes) + //fmt.Printf("NewPushReq req:%v", reqBody) + request, err = http.NewRequest("POST", PushURL, bytes.NewReader(bodyBytes)) + if err != nil { + return nil, "", err + } + request.Header.Add("Content-Type", "application/json") + return +} + +func EnvProd() ReqOpt { + return func(r *tpns.Request) { + r.Environment = tpns.EnvProd + } +} + +func EnvDev() ReqOpt { + return func(r *tpns.Request) { + r.Environment = tpns.EnvDev + } +} + +func Title(t string) ReqOpt { + return func(r *tpns.Request) { + r.Message.Title = t + if r.Message.IOS != nil { + if r.Message.IOS.Aps != nil { + r.Message.IOS.Aps.Alert["title"] = t + } else { + r.Message.IOS.Aps = &tpns.Aps{ + Alert: map[string]string{"title": t}, + } + } + } else { + r.Message.IOS = &tpns.IOSParams{ + Aps: &tpns.Aps{ + Alert: map[string]string{"title": t}, + }, + } + } + } +} + +func Content(c string) ReqOpt { + return func(r *tpns.Request) { + r.Message.Content = c + if r.Message.IOS != nil { + if r.Message.IOS.Aps != nil { + r.Message.IOS.Aps.Alert["body"] = c + } else { + r.Message.IOS.Aps = &tpns.Aps{ + Alert: map[string]string{"body": c}, + } + } + } else { + r.Message.IOS = &tpns.IOSParams{ + Aps: &tpns.Aps{ + Alert: map[string]string{"body": c}, + }, + } + } + } +} + +func Ring(ring *int) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.Ring = ring + } +} + +func RingRaw(rr string) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.RingRaw = rr + } +} + +func Vibrate(v *int) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.Vibrate = v + } +} + +func Lights(l *int) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.Lights = l + } +} + +func Clearable(c *int) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.Clearable = c + } +} + +func IconType(it *int) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.IconType = it + } +} + +func IconRes(ir string) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.IconRes = ir + } +} + +func AndroidCustomContent(ct string) ReqOpt { + return func(r *tpns.Request) { + r.Message.Android.CustomContent = ct + } +} + +func Aps(aps *tpns.Aps) ReqOpt { + return func(r *tpns.Request) { + r.Message.IOS.Aps = aps + } +} + +func AudienceType(at tpns.AudienceType) ReqOpt { + return func(r *tpns.Request) { + r.AudienceType = at + } +} + +func Message(m tpns.Message) ReqOpt { + return func(r *tpns.Request) { + r.Message = m + } +} + +func TokenList(tl []string) ReqOpt { + return func(r *tpns.Request) { + r.TokenList = tl + } +} + +func TokenListAdd(t string) ReqOpt { + return func(r *tpns.Request) { + if r.TokenList != nil { + r.TokenList = append(r.TokenList, t) + } else { + r.TokenList = []string{t} + } + } +} + +func AccountList(al []string) ReqOpt { + return func(r *tpns.Request) { + r.AccountList = al + } +} + +//ChannelDistributeRules +func AddChannelRules(ChannelRules []*tpns.ChannelDistributeRule) ReqOpt { + return func(r *tpns.Request) { + r.ChannelRules = ChannelRules + } +} + +//ChannelDistributeRules +func AddLoopParam(loopParam *tpns.PushLoopParam) ReqOpt { + return func(r *tpns.Request) { + r.LoopParam = loopParam + } +} + +func AccountListAdd(a string) ReqOpt { + return func(r *tpns.Request) { + if r.AccountList != nil { + r.AccountList = append(r.AccountList, a) + } else { + r.AccountList = []string{a} + } + } +} + +func MessageType(t tpns.MessageType) ReqOpt { + return func(r *tpns.Request) { + r.MessageType = t + } +} + +func AddMultiPkg(multipPkg bool) ReqOpt { + return func(r *tpns.Request) { + r.MultiPkg = multipPkg + } +} + +func AddForceCollapse(forceCollapse bool) ReqOpt { + return func(r *tpns.Request) { + r.ForceCollapse = forceCollapse + } +} + +func AddTPNSOnlinePushType(onlinePushType int) ReqOpt { + return func(r *tpns.Request) { + r.TPNSOnlinePushType = onlinePushType + } +} + +func AddCollapseId(collapseId int) ReqOpt { + return func(r *tpns.Request) { + r.CollapseId = collapseId + } +} + +func AddPushSpeed(pushSpeed int) ReqOpt { + return func(r *tpns.Request) { + r.PushSpeed = pushSpeed + } +} + +func AddAccountPushType(accountPushType int) ReqOpt { + return func(r *tpns.Request) { + r.AccountPushType = accountPushType + } +} + +func AddPlanId(planId string) ReqOpt { + return func(r *tpns.Request) { + r.PlanId = planId + } +} + +func AddSendTime(sendTime string) ReqOpt { + return func(r *tpns.Request) { + r.SendTime = sendTime + } +} + +func AddExpireTime(expireTime int) ReqOpt { + return func(r *tpns.Request) { + r.ExpireTime = expireTime + } +} + +func AddUploadId(UploadId int) ReqOpt { + return func(r *tpns.Request) { + r.UploadId = UploadId + } +} + +func AddEnvironment(Environment tpns.CommonRspEnv) ReqOpt { + return func(r *tpns.Request) { + r.Environment = Environment + } +} diff --git a/internal/rpc/admin_cms/admin_cms.go b/internal/rpc/admin_cms/admin_cms.go new file mode 100644 index 000000000..156748bbc --- /dev/null +++ b/internal/rpc/admin_cms/admin_cms.go @@ -0,0 +1,87 @@ +package admin_cms + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + openIMHttp "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbAdminCMS "Open_IM/pkg/proto/admin_cms" + "Open_IM/pkg/utils" + "context" + "google.golang.org/grpc" + "net" + "strconv" + "strings" +) + +type adminCMSServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewAdminCMSServer(port int) *adminCMSServer { + log.NewPrivateLog(constant.LogFileName) + return &adminCMSServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImAdminCMSName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *adminCMSServer) Run() { + log.NewInfo("0", "AdminCMS rpc start ") + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("0", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("0", "listen network success, ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + pbAdminCMS.RegisterAdminCMSServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error()) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error()) + return + } + log.NewInfo("0", "message cms rpc success") +} + +func (s *adminCMSServer) AdminLogin(_ context.Context, req *pbAdminCMS.AdminLoginReq) (*pbAdminCMS.AdminLoginResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbAdminCMS.AdminLoginResp{} + for i, adminID := range config.Config.Manager.AppManagerUid { + if adminID == req.AdminID && config.Config.Manager.Secrets[i] == req.Secret { + token, expTime, err := token_verify.CreateToken(adminID, constant.SingleChatType) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "generate token success", "token: ", token, "expTime:", expTime) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "generate token failed", "adminID: ", adminID, err.Error()) + return resp, openIMHttp.WrapError(constant.ErrTokenUnknown) + } + resp.Token = token + break + } + } + + if resp.Token == "" { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "failed") + return resp, openIMHttp.WrapError(constant.ErrTokenMalformed) + } + return resp, nil +} diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go new file mode 100644 index 000000000..1aa0ec50b --- /dev/null +++ b/internal/rpc/auth/auth.go @@ -0,0 +1,104 @@ +package auth + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbAuth "Open_IM/pkg/proto/auth" + "Open_IM/pkg/utils" + "context" + "net" + "strconv" + "strings" + + "Open_IM/pkg/common/config" + + "google.golang.org/grpc" +) + +func (rpc *rpcAuth) UserRegister(_ context.Context, req *pbAuth.UserRegisterReq) (*pbAuth.UserRegisterResp, error) { + log.NewInfo(req.OperationID, "UserRegister args ", req.String()) + var user db.User + utils.CopyStructFields(&user, req.UserInfo) + if req.UserInfo.Birth != 0 { + user.Birth = utils.UnixSecondToTime(int64(req.UserInfo.Birth)) + } + err := imdb.UserRegister(user) + if err != nil { + log.NewError(req.OperationID, "UserRegister failed ", err.Error(), user) + return &pbAuth.UserRegisterResp{CommonResp: &pbAuth.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + log.NewInfo(req.OperationID, "rpc UserRegister return") + return &pbAuth.UserRegisterResp{CommonResp: &pbAuth.CommonResp{}}, nil +} + +func (rpc *rpcAuth) UserToken(_ context.Context, req *pbAuth.UserTokenReq) (*pbAuth.UserTokenResp, error) { + log.NewInfo(req.OperationID, "UserToken args ", req.String()) + + _, err := imdb.GetUserByUserID(req.FromUserID) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), req.FromUserID) + return &pbAuth.UserTokenResp{CommonResp: &pbAuth.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + tokens, expTime, err := token_verify.CreateToken(req.FromUserID, req.Platform) + if err != nil { + log.NewError(req.OperationID, "CreateToken failed ", err.Error(), req.FromUserID, req.Platform) + return &pbAuth.UserTokenResp{CommonResp: &pbAuth.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + log.NewInfo(req.OperationID, "rpc UserToken return ", tokens, expTime) + return &pbAuth.UserTokenResp{CommonResp: &pbAuth.CommonResp{}, Token: tokens, ExpiredTime: expTime}, nil +} + +type rpcAuth struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewRpcAuthServer(port int) *rpcAuth { + log.NewPrivateLog(constant.LogFileName) + return &rpcAuth{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImAuthName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (rpc *rpcAuth) Run() { + log.NewInfo("0", "rpc auth start...") + + address := utils.ServerIP + ":" + strconv.Itoa(rpc.rpcPort) + listener, err := net.Listen("tcp", address) + if err != nil { + log.NewError("0", "listen network failed ", err.Error(), address) + return + } + log.NewInfo("0", "listen network success, ", address, listener) + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + + //service registers with etcd + pbAuth.RegisterAuthServer(srv, rpc) + err = getcdv3.RegisterEtcd(rpc.etcdSchema, strings.Join(rpc.etcdAddr, ","), utils.ServerIP, rpc.rpcPort, rpc.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error(), + rpc.etcdSchema, strings.Join(rpc.etcdAddr, ","), utils.ServerIP, rpc.rpcPort, rpc.rpcRegisterName) + return + } + log.NewInfo("0", "RegisterAuthServer ok ", rpc.etcdSchema, strings.Join(rpc.etcdAddr, ","), utils.ServerIP, rpc.rpcPort, rpc.rpcRegisterName) + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error()) + return + } + log.NewInfo("0", "rpc auth ok") +} diff --git a/internal/rpc/auth/callback.go b/internal/rpc/auth/callback.go new file mode 100644 index 000000000..8832b06d1 --- /dev/null +++ b/internal/rpc/auth/callback.go @@ -0,0 +1 @@ +package auth diff --git a/internal/rpc/friend/callback.go b/internal/rpc/friend/callback.go new file mode 100644 index 000000000..cf8ea69c8 --- /dev/null +++ b/internal/rpc/friend/callback.go @@ -0,0 +1 @@ +package friend diff --git a/internal/rpc/friend/firend.go b/internal/rpc/friend/firend.go new file mode 100644 index 000000000..b570b8106 --- /dev/null +++ b/internal/rpc/friend/firend.go @@ -0,0 +1,519 @@ +package friend + +import ( + chat "Open_IM/internal/rpc/msg" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + cp "Open_IM/pkg/common/utils" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbFriend "Open_IM/pkg/proto/friend" + sdkws "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "google.golang.org/grpc" + "net" + "strconv" + "strings" + "time" +) + +type friendServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewFriendServer(port int) *friendServer { + log.NewPrivateLog(constant.LogFileName) + return &friendServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImFriendName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *friendServer) Run() { + log.NewInfo("0", "friendServer run...") + + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("0", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("0", "listen ok ", registerAddress) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //User friend related services register to etcd + pbFriend.RegisterFriendServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error(), s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error(), listener) + return + } +} + +func (s *friendServer) AddBlacklist(ctx context.Context, req *pbFriend.AddBlacklistReq) (*pbFriend.AddBlacklistResp, error) { + log.NewInfo(req.CommID.OperationID, "AddBlacklist args ", req.String()) + ok := token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) + if !ok { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.AddBlacklistResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + black := db.Black{OwnerUserID: req.CommID.FromUserID, BlockUserID: req.CommID.ToUserID, OperatorUserID: req.CommID.OpUserID} + + err := imdb.InsertInToUserBlackList(black) + if err != nil { + log.NewError(req.CommID.OperationID, "InsertInToUserBlackList failed ", err.Error()) + return &pbFriend.AddBlacklistResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + log.NewInfo(req.CommID.OperationID, "AddBlacklist rpc ok ", req.CommID.FromUserID, req.CommID.ToUserID) + chat.BlackAddedNotification(req) + return &pbFriend.AddBlacklistResp{CommonResp: &pbFriend.CommonResp{}}, nil +} + +func (s *friendServer) AddFriend(ctx context.Context, req *pbFriend.AddFriendReq) (*pbFriend.AddFriendResp, error) { + log.NewInfo(req.CommID.OperationID, "AddFriend args ", req.String()) + ok := token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) + if !ok { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.AddFriendResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + //Cannot add non-existent users + if _, err := imdb.GetUserByUserID(req.CommID.ToUserID); err != nil { + log.NewError(req.CommID.OperationID, "GetUserByUserID failed ", err.Error(), req.CommID.ToUserID) + return &pbFriend.AddFriendResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + //Establish a latest relationship in the friend request table + friendRequest := db.FriendRequest{ + HandleResult: 0, ReqMsg: req.ReqMsg, CreateTime: time.Now()} + utils.CopyStructFields(&friendRequest, req.CommID) + // {openIM001 openIM002 0 test add friend 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC }] + log.NewDebug(req.CommID.OperationID, "UpdateFriendApplication args ", friendRequest) + //err := imdb.InsertFriendApplication(&friendRequest) + err := imdb.InsertFriendApplication(&friendRequest, + map[string]interface{}{"handle_result": 0, "req_msg": friendRequest.ReqMsg, "create_time": friendRequest.CreateTime, + "handler_user_id": "", "handle_msg": "", "handle_time": utils.UnixSecondToTime(0), "ex": ""}) + if err != nil { + log.NewError(req.CommID.OperationID, "UpdateFriendApplication failed ", err.Error(), friendRequest) + return &pbFriend.AddFriendResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + chat.FriendApplicationNotification(req) + return &pbFriend.AddFriendResp{CommonResp: &pbFriend.CommonResp{}}, nil +} + +func (s *friendServer) ImportFriend(ctx context.Context, req *pbFriend.ImportFriendReq) (*pbFriend.ImportFriendResp, error) { + log.NewInfo(req.OperationID, "ImportFriend args ", req.String()) + resp := pbFriend.ImportFriendResp{CommonResp: &pbFriend.CommonResp{}} + var c pbFriend.CommonResp + + if !utils.IsContain(req.OpUserID, config.Config.Manager.AppManagerUid) { + log.NewError(req.OperationID, "not authorized", req.OpUserID, config.Config.Manager.AppManagerUid) + c.ErrCode = constant.ErrAccess.ErrCode + c.ErrMsg = constant.ErrAccess.ErrMsg + for _, v := range req.FriendUserIDList { + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: -1}) + } + resp.CommonResp = &c + return &resp, nil + } + if _, err := imdb.GetUserByUserID(req.FromUserID); err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), req.FromUserID) + c.ErrCode = constant.ErrDB.ErrCode + c.ErrMsg = "this user not exists,cant not add friend" + for _, v := range req.FriendUserIDList { + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: -1}) + } + resp.CommonResp = &c + return &resp, nil + } + + for _, v := range req.FriendUserIDList { + log.NewDebug(req.OperationID, "FriendUserIDList ", v) + if _, fErr := imdb.GetUserByUserID(v); fErr != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", fErr.Error(), v) + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: -1}) + } else { + if _, err := imdb.GetFriendRelationshipFromFriend(req.FromUserID, v); err != nil { + //Establish two single friendship + toInsertFollow := db.Friend{OwnerUserID: req.FromUserID, FriendUserID: v} + err1 := imdb.InsertToFriend(&toInsertFollow) + if err1 != nil { + log.NewError(req.OperationID, "InsertToFriend failed ", err1.Error(), toInsertFollow) + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: -1}) + continue + } + toInsertFollow = db.Friend{OwnerUserID: v, FriendUserID: req.FromUserID} + err2 := imdb.InsertToFriend(&toInsertFollow) + if err2 != nil { + log.NewError(req.OperationID, "InsertToFriend failed ", err2.Error(), toInsertFollow) + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: -1}) + continue + } + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: 0}) + log.NewDebug(req.OperationID, "UserIDResultList ", resp.UserIDResultList) + chat.FriendAddedNotification(req.OperationID, req.OpUserID, req.FromUserID, v) + } else { + log.NewWarn(req.OperationID, "GetFriendRelationshipFromFriend ok", req.FromUserID, v) + resp.UserIDResultList = append(resp.UserIDResultList, &pbFriend.UserIDResult{UserID: v, Result: 0}) + } + } + } + resp.CommonResp.ErrCode = 0 + log.NewInfo(req.OperationID, "ImportFriend rpc ok ", resp.String()) + return &resp, nil +} + +//process Friend application +func (s *friendServer) AddFriendResponse(ctx context.Context, req *pbFriend.AddFriendResponseReq) (*pbFriend.AddFriendResponseResp, error) { + log.NewInfo(req.CommID.OperationID, "AddFriendResponse args ", req.String()) + + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.AddFriendResponseResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + + //Check there application before agreeing or refuse to a friend's application + //req.CommID.FromUserID process req.CommID.ToUserID + friendRequest, err := imdb.GetFriendApplicationByBothUserID(req.CommID.ToUserID, req.CommID.FromUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "GetFriendApplicationByBothUserID failed ", err.Error(), req.CommID.ToUserID, req.CommID.FromUserID) + return &pbFriend.AddFriendResponseResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + friendRequest.HandleResult = req.HandleResult + friendRequest.HandleTime = time.Now() + //friendRequest.HandleTime.Unix() + friendRequest.HandleMsg = req.HandleMsg + friendRequest.HandlerUserID = req.CommID.OpUserID + err = imdb.UpdateFriendApplication(friendRequest) + if err != nil { + log.NewError(req.CommID.OperationID, "UpdateFriendApplication failed ", err.Error(), friendRequest) + return &pbFriend.AddFriendResponseResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + //Change the status of the friend request form + if req.HandleResult == constant.FriendFlag { + //Establish friendship after find friend relationship not exists + _, err := imdb.GetFriendRelationshipFromFriend(req.CommID.FromUserID, req.CommID.ToUserID) + if err == nil { + log.NewWarn(req.CommID.OperationID, "GetFriendRelationshipFromFriend exist", req.CommID.FromUserID, req.CommID.ToUserID) + } else { + //Establish two single friendship + toInsertFollow := db.Friend{OwnerUserID: req.CommID.FromUserID, FriendUserID: req.CommID.ToUserID, OperatorUserID: req.CommID.OpUserID} + err = imdb.InsertToFriend(&toInsertFollow) + if err != nil { + log.NewError(req.CommID.OperationID, "InsertToFriend failed ", err.Error(), toInsertFollow) + return &pbFriend.AddFriendResponseResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + } + + _, err = imdb.GetFriendRelationshipFromFriend(req.CommID.ToUserID, req.CommID.FromUserID) + if err == nil { + log.NewWarn(req.CommID.OperationID, "GetFriendRelationshipFromFriend exist", req.CommID.ToUserID, req.CommID.FromUserID) + } else { + toInsertFollow := db.Friend{OwnerUserID: req.CommID.ToUserID, FriendUserID: req.CommID.FromUserID, OperatorUserID: req.CommID.OpUserID} + err = imdb.InsertToFriend(&toInsertFollow) + if err != nil { + log.NewError(req.CommID.OperationID, "InsertToFriend failed ", err.Error(), toInsertFollow) + return &pbFriend.AddFriendResponseResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.FriendAddedNotification(req.CommID.OperationID, req.CommID.OpUserID, req.CommID.FromUserID, req.CommID.ToUserID) + } + } + if req.HandleResult == constant.FriendResponseAgree { + chat.FriendApplicationApprovedNotification(req) + } else if req.HandleResult == constant.FriendResponseRefuse { + chat.FriendApplicationRejectedNotification(req) + } else { + log.Error(req.CommID.OperationID, "HandleResult failed ", req.HandleResult) + } + log.NewInfo(req.CommID.OperationID, "rpc AddFriendResponse ok") + return &pbFriend.AddFriendResponseResp{CommonResp: &pbFriend.CommonResp{}}, nil +} + +func (s *friendServer) DeleteFriend(ctx context.Context, req *pbFriend.DeleteFriendReq) (*pbFriend.DeleteFriendResp, error) { + log.NewInfo(req.CommID.OperationID, "DeleteFriend args ", req.String()) + //Parse token, to find current user information + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.DeleteFriendResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + err := imdb.DeleteSingleFriendInfo(req.CommID.FromUserID, req.CommID.ToUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "DeleteSingleFriendInfo failed", err.Error(), req.CommID.FromUserID, req.CommID.ToUserID) + return &pbFriend.DeleteFriendResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + log.NewInfo(req.CommID.OperationID, "DeleteFriend rpc ok") + chat.FriendDeletedNotification(req) + return &pbFriend.DeleteFriendResp{CommonResp: &pbFriend.CommonResp{}}, nil +} + +func (s *friendServer) GetBlacklist(ctx context.Context, req *pbFriend.GetBlacklistReq) (*pbFriend.GetBlacklistResp, error) { + log.NewInfo(req.CommID.OperationID, "GetBlacklist args ", req.String()) + + //Parse token, to find current user information + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.GetBlacklistResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + blackListInfo, err := imdb.GetBlackListByUserID(req.CommID.FromUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "GetBlackListByUID failed ", err.Error(), req.CommID.FromUserID) + return &pbFriend.GetBlacklistResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, nil + } + + var ( + userInfoList []*sdkws.PublicUserInfo + ) + for _, blackUser := range blackListInfo { + var blackUserInfo sdkws.PublicUserInfo + //Find black user information + us, err := imdb.GetUserByUserID(blackUser.BlockUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "GetUserByUserID failed ", err.Error(), blackUser.BlockUserID) + continue + } + utils.CopyStructFields(&blackUserInfo, us) + userInfoList = append(userInfoList, &blackUserInfo) + } + log.NewInfo(req.CommID.OperationID, "rpc GetBlacklist ok ", pbFriend.GetBlacklistResp{BlackUserInfoList: userInfoList}) + return &pbFriend.GetBlacklistResp{BlackUserInfoList: userInfoList}, nil +} + +func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbFriend.SetFriendRemarkReq) (*pbFriend.SetFriendRemarkResp, error) { + log.NewInfo(req.CommID.OperationID, "SetFriendComment args ", req.String()) + //Parse token, to find current user information + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.SetFriendRemarkResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + + err := imdb.UpdateFriendComment(req.CommID.FromUserID, req.CommID.ToUserID, req.Remark) + if err != nil { + log.NewError(req.CommID.OperationID, "UpdateFriendComment failed ", req.CommID.FromUserID, req.CommID.ToUserID, req.Remark) + return &pbFriend.SetFriendRemarkResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + log.NewInfo(req.CommID.OperationID, "rpc SetFriendComment ok") + chat.FriendRemarkSetNotification(req.CommID.OperationID, req.CommID.OpUserID, req.CommID.FromUserID, req.CommID.ToUserID) + return &pbFriend.SetFriendRemarkResp{CommonResp: &pbFriend.CommonResp{}}, nil +} + +func (s *friendServer) RemoveBlacklist(ctx context.Context, req *pbFriend.RemoveBlacklistReq) (*pbFriend.RemoveBlacklistResp, error) { + log.NewInfo(req.CommID.OperationID, "RemoveBlacklist args ", req.String()) + //Parse token, to find current user information + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.RemoveBlacklistResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + err := imdb.RemoveBlackList(req.CommID.FromUserID, req.CommID.ToUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "RemoveBlackList failed", err.Error(), req.CommID.FromUserID, req.CommID.ToUserID) + return &pbFriend.RemoveBlacklistResp{CommonResp: &pbFriend.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + + } + log.NewInfo(req.CommID.OperationID, "rpc RemoveBlacklist ok ") + chat.BlackDeletedNotification(req) + return &pbFriend.RemoveBlacklistResp{CommonResp: &pbFriend.CommonResp{}}, nil +} + +func (s *friendServer) IsInBlackList(ctx context.Context, req *pbFriend.IsInBlackListReq) (*pbFriend.IsInBlackListResp, error) { + log.NewInfo("IsInBlackList args ", req.String()) + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.IsInBlackListResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + var isInBlacklist = false + err := imdb.CheckBlack(req.CommID.FromUserID, req.CommID.ToUserID) + if err == nil { + isInBlacklist = true + } + log.NewInfo(req.CommID.OperationID, "IsInBlackList rpc ok ", pbFriend.IsInBlackListResp{Response: isInBlacklist}) + return &pbFriend.IsInBlackListResp{Response: isInBlacklist}, nil +} + +func (s *friendServer) IsFriend(ctx context.Context, req *pbFriend.IsFriendReq) (*pbFriend.IsFriendResp, error) { + log.NewInfo(req.CommID.OperationID, req.String()) + var isFriend bool + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.IsFriendResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + _, err := imdb.GetFriendRelationshipFromFriend(req.CommID.FromUserID, req.CommID.ToUserID) + if err == nil { + isFriend = true + } else { + isFriend = false + } + log.NewInfo(req.CommID.OperationID, pbFriend.IsFriendResp{Response: isFriend}) + return &pbFriend.IsFriendResp{Response: isFriend}, nil +} + +func (s *friendServer) GetFriendList(ctx context.Context, req *pbFriend.GetFriendListReq) (*pbFriend.GetFriendListResp, error) { + log.NewInfo("GetFriendList args ", req.String()) + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.GetFriendListResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + friends, err := imdb.GetFriendListByUserID(req.CommID.FromUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "FindUserInfoFromFriend failed ", err.Error(), req.CommID.FromUserID) + return &pbFriend.GetFriendListResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, nil + } + var userInfoList []*sdkws.FriendInfo + for _, friendUser := range friends { + friendUserInfo := sdkws.FriendInfo{FriendUser: &sdkws.UserInfo{}} + cp.FriendDBCopyOpenIM(&friendUserInfo, &friendUser) + log.NewDebug(req.CommID.OperationID, "friends : ", friendUser, "openim friends: ", friendUserInfo) + userInfoList = append(userInfoList, &friendUserInfo) + } + log.NewInfo(req.CommID.OperationID, "rpc GetFriendList ok", pbFriend.GetFriendListResp{FriendInfoList: userInfoList}) + return &pbFriend.GetFriendListResp{FriendInfoList: userInfoList}, nil +} + +//received +func (s *friendServer) GetFriendApplyList(ctx context.Context, req *pbFriend.GetFriendApplyListReq) (*pbFriend.GetFriendApplyListResp, error) { + log.NewInfo(req.CommID.OperationID, "GetFriendApplyList args ", req.String()) + //Parse token, to find current user information + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.GetFriendApplyListResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + // Find the current user friend applications received + ApplyUsersInfo, err := imdb.GetReceivedFriendsApplicationListByUserID(req.CommID.FromUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "GetReceivedFriendsApplicationListByUserID ", err.Error(), req.CommID.FromUserID) + return &pbFriend.GetFriendApplyListResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, nil + } + + var appleUserList []*sdkws.FriendRequest + for _, applyUserInfo := range ApplyUsersInfo { + var userInfo sdkws.FriendRequest + cp.FriendRequestDBCopyOpenIM(&userInfo, &applyUserInfo) + // utils.CopyStructFields(&userInfo, applyUserInfo) + // u, err := imdb.GetUserByUserID(userInfo.FromUserID) + // if err != nil { + // log.Error(req.CommID.OperationID, "GetUserByUserID", userInfo.FromUserID) + // continue + // } + // userInfo.FromNickname = u.Nickname + // userInfo.FromFaceURL = u.FaceURL + // userInfo.FromGender = u.Gender + // + // u, err = imdb.GetUserByUserID(userInfo.ToUserID) + // if err != nil { + // log.Error(req.CommID.OperationID, "GetUserByUserID", userInfo.ToUserID) + // continue + // } + // userInfo.ToNickname = u.Nickname + // userInfo.ToFaceURL = u.FaceURL + // userInfo.ToGender = u.Gender + appleUserList = append(appleUserList, &userInfo) + } + + log.NewInfo(req.CommID.OperationID, "rpc GetFriendApplyList ok", pbFriend.GetFriendApplyListResp{FriendRequestList: appleUserList}) + return &pbFriend.GetFriendApplyListResp{FriendRequestList: appleUserList}, nil +} + +func (s *friendServer) GetSelfApplyList(ctx context.Context, req *pbFriend.GetSelfApplyListReq) (*pbFriend.GetSelfApplyListResp, error) { + log.NewInfo(req.CommID.OperationID, "GetSelfApplyList args ", req.String()) + + //Parse token, to find current user information + if !token_verify.CheckAccess(req.CommID.OpUserID, req.CommID.FromUserID) { + log.NewError(req.CommID.OperationID, "CheckAccess false ", req.CommID.OpUserID, req.CommID.FromUserID) + return &pbFriend.GetSelfApplyListResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + // Find the self add other userinfo + usersInfo, err := imdb.GetSendFriendApplicationListByUserID(req.CommID.FromUserID) + if err != nil { + log.NewError(req.CommID.OperationID, "GetSendFriendApplicationListByUserID failed ", err.Error(), req.CommID.FromUserID) + return &pbFriend.GetSelfApplyListResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, nil + } + var selfApplyOtherUserList []*sdkws.FriendRequest + for _, selfApplyOtherUserInfo := range usersInfo { + var userInfo sdkws.FriendRequest // pbFriend.ApplyUserInfo + cp.FriendRequestDBCopyOpenIM(&userInfo, &selfApplyOtherUserInfo) + //u, err := imdb.GetUserByUserID(userInfo.FromUserID) + //if err != nil { + // log.Error(req.CommID.OperationID, "GetUserByUserID", userInfo.FromUserID) + // continue + //} + //userInfo.FromNickname = u.Nickname + //userInfo.FromFaceURL = u.FaceURL + //userInfo.FromGender = u.Gender + // + //u, err = imdb.GetUserByUserID(userInfo.ToUserID) + //if err != nil { + // log.Error(req.CommID.OperationID, "GetUserByUserID", userInfo.ToUserID) + // continue + //} + //userInfo.ToNickname = u.Nickname + //userInfo.ToFaceURL = u.FaceURL + //userInfo.ToGender = u.Gender + + selfApplyOtherUserList = append(selfApplyOtherUserList, &userInfo) + } + log.NewInfo(req.CommID.OperationID, "rpc GetSelfApplyList ok", pbFriend.GetSelfApplyListResp{FriendRequestList: selfApplyOtherUserList}) + return &pbFriend.GetSelfApplyListResp{FriendRequestList: selfApplyOtherUserList}, nil +} + +//// +//func (s *friendServer) GetFriendsInfo(ctx context.Context, req *pbFriend.GetFriendsInfoReq) (*pbFriend.GetFriendInfoResp, error) { +// return nil, nil +//// log.NewInfo(req.CommID.OperationID, "GetFriendsInfo args ", req.String()) +//// var ( +//// isInBlackList int32 +//// // isFriend int32 +//// comment string +//// ) +//// +//// friendShip, err := imdb.FindFriendRelationshipFromFriend(req.CommID.FromUserID, req.CommID.ToUserID) +//// if err != nil { +//// log.NewError(req.CommID.OperationID, "FindFriendRelationshipFromFriend failed ", err.Error()) +//// return &pbFriend.GetFriendInfoResp{ErrCode: constant.ErrSearchUserInfo.ErrCode, ErrMsg: constant.ErrSearchUserInfo.ErrMsg}, nil +//// // isFriend = constant.FriendFlag +//// } +//// comment = friendShip.Remark +//// +//// friendUserInfo, err := imdb.FindUserByUID(req.CommID.ToUserID) +//// if err != nil { +//// log.NewError(req.CommID.OperationID, "FindUserByUID failed ", err.Error()) +//// return &pbFriend.GetFriendInfoResp{ErrCode: constant.ErrSearchUserInfo.ErrCode, ErrMsg: constant.ErrSearchUserInfo.ErrMsg}, nil +//// } +//// +//// err = imdb.FindRelationshipFromBlackList(req.CommID.FromUserID, req.CommID.ToUserID) +//// if err == nil { +//// isInBlackList = constant.BlackListFlag +//// } +//// +//// resp := pbFriend.GetFriendInfoResp{ErrCode: 0, ErrMsg: "",} +//// +//// utils.CopyStructFields(resp.FriendInfoList, friendUserInfo) +//// resp.Data.IsBlack = isInBlackList +//// resp.Data.OwnerUserID = req.CommID.FromUserID +//// resp.Data.Remark = comment +//// resp.Data.CreateTime = friendUserInfo.CreateTime +//// +//// log.NewInfo(req.CommID.OperationID, "GetFriendsInfo ok ", resp) +//// return &resp, nil +//// +//} diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go new file mode 100644 index 000000000..1e9e612a6 --- /dev/null +++ b/internal/rpc/group/callback.go @@ -0,0 +1,13 @@ +package group + +import ( + pbGroup "Open_IM/pkg/proto/group" +) + +func callbackBeforeCreateGroup(req *pbGroup.CreateGroupReq) (bool, error) { + return true, nil +} + +func callbackAfterCreateGroup(req *pbGroup.CreateGroupReq) { + +} diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go new file mode 100644 index 000000000..e22ab18bf --- /dev/null +++ b/internal/rpc/group/group.go @@ -0,0 +1,1046 @@ +package group + +import ( + chat "Open_IM/internal/rpc/msg" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + cp "Open_IM/pkg/common/utils" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbGroup "Open_IM/pkg/proto/group" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "net" + "strconv" + "strings" + "time" + + "google.golang.org/grpc" +) + +type groupServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewGroupServer(port int) *groupServer { + log.NewPrivateLog(constant.LogFileName) + return &groupServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImGroupName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *groupServer) Run() { + log.NewInfo("", "group rpc start ") + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("", "listen network success, ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + pbGroup.RegisterGroupServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("", "RegisterEtcd failed ", err.Error()) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("", "Serve failed ", err.Error()) + return + } + log.NewInfo("", "group rpc success") +} + +func (s *groupServer) CreateGroup(ctx context.Context, req *pbGroup.CreateGroupReq) (*pbGroup.CreateGroupResp, error) { + log.NewInfo(req.OperationID, "CreateGroup, args ", req.String()) + if !token_verify.CheckAccess(req.OpUserID, req.OwnerUserID) { + log.NewError(req.OperationID, "CheckAccess false ", req.OpUserID, req.OwnerUserID) + return &pbGroup.CreateGroupResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + canCreate, err := callbackBeforeCreateGroup(req) + if err != nil || !canCreate { + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "callbackBeforeCreateGroup failed") + } + } + //Time stamp + MD5 to generate group chat id + groupId := utils.Md5(strconv.FormatInt(time.Now().UnixNano(), 10)) + //to group + groupInfo := db.Group{} + utils.CopyStructFields(&groupInfo, req.GroupInfo) + groupInfo.CreatorUserID = req.OpUserID + groupInfo.GroupID = groupId + err = imdb.InsertIntoGroup(groupInfo) + if err != nil { + log.NewError(req.OperationID, "InsertIntoGroup failed, ", err.Error(), groupInfo) + return &pbGroup.CreateGroupResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, http.WrapError(constant.ErrDB) + } + + us, err := imdb.GetUserByUserID(req.OwnerUserID) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), req.OwnerUserID) + return &pbGroup.CreateGroupResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, http.WrapError(constant.ErrDB) + } + + //to group member + groupMember := db.GroupMember{GroupID: groupId, RoleLevel: constant.GroupOwner, OperatorUserID: req.OpUserID} + utils.CopyStructFields(&groupMember, us) + err = imdb.InsertIntoGroupMember(groupMember) + if err != nil { + log.NewError(req.OperationID, "InsertIntoGroupMember failed ", err.Error(), groupMember) + return &pbGroup.CreateGroupResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, http.WrapError(constant.ErrDB) + } + + err = db.DB.AddGroupMember(groupId, req.OwnerUserID) + if err != nil { + log.NewError(req.OperationID, "AddGroupMember failed ", err.Error(), groupId, req.OwnerUserID) + } + var okUserIDList []string + //to group member + for _, user := range req.InitMemberList { + us, err := imdb.GetUserByUserID(user.UserID) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), user.UserID) + continue + } + if user.RoleLevel == constant.GroupOwner { + log.NewError(req.OperationID, "only one owner, failed ", user) + continue + } + groupMember.RoleLevel = user.RoleLevel + utils.CopyStructFields(&groupMember, us) + err = imdb.InsertIntoGroupMember(groupMember) + if err != nil { + log.NewError(req.OperationID, "InsertIntoGroupMember failed ", err.Error(), groupMember) + continue + } + + okUserIDList = append(okUserIDList, user.UserID) + err = db.DB.AddGroupMember(groupId, user.UserID) + if err != nil { + log.NewError(req.OperationID, "add mongo group member failed, db.DB.AddGroupMember failed ", err.Error()) + } + } + + resp := &pbGroup.CreateGroupResp{GroupInfo: &open_im_sdk.GroupInfo{}} + group, err := imdb.GetGroupInfoByGroupID(groupId) + if err != nil { + log.NewError(req.OperationID, "GetGroupInfoByGroupID failed ", err.Error(), groupId) + resp.ErrCode = constant.ErrDB.ErrCode + resp.ErrMsg = constant.ErrDB.ErrMsg + return resp, nil + } + utils.CopyStructFields(resp.GroupInfo, group) + resp.GroupInfo.MemberCount, err = imdb.GetGroupMemberNumByGroupID(groupId) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberNumByGroupID failed ", err.Error(), groupId) + resp.ErrCode = constant.ErrDB.ErrCode + resp.ErrMsg = constant.ErrDB.ErrMsg + return resp, nil + } + resp.GroupInfo.OwnerUserID = req.OwnerUserID + + log.NewInfo(req.OperationID, "rpc CreateGroup return ", resp.String()) + chat.GroupCreatedNotification(req.OperationID, req.OpUserID, groupId, okUserIDList) + return resp, nil +} + +func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbGroup.GetJoinedGroupListReq) (*pbGroup.GetJoinedGroupListResp, error) { + log.NewInfo(req.OperationID, "GetJoinedGroupList, args ", req.String()) + if !token_verify.CheckAccess(req.OpUserID, req.FromUserID) { + log.NewError(req.OperationID, "CheckAccess false ", req.OpUserID, req.FromUserID) + return &pbGroup.GetJoinedGroupListResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + //group list + joinedGroupList, err := imdb.GetJoinedGroupIDListByUserID(req.FromUserID) + if err != nil { + log.NewError(req.OperationID, "GetJoinedGroupIDListByUserID failed ", err.Error(), req.FromUserID) + return &pbGroup.GetJoinedGroupListResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, nil + } + + var resp pbGroup.GetJoinedGroupListResp + for _, v := range joinedGroupList { + var groupNode open_im_sdk.GroupInfo + num, err := imdb.GetGroupMemberNumByGroupID(v) + owner, err2 := imdb.GetGroupOwnerInfoByGroupID(v) + group, err := imdb.GetGroupInfoByGroupID(v) + if num > 0 && owner != nil && err2 == nil && group != nil && err == nil { + utils.CopyStructFields(&groupNode, group) + groupNode.CreateTime = uint32(group.CreateTime.Unix()) + groupNode.MemberCount = uint32(num) + groupNode.OwnerUserID = owner.UserID + resp.GroupList = append(resp.GroupList, &groupNode) + } else { + log.NewError(req.OperationID, "check nil ", num, owner, err, group) + continue + } + log.NewDebug(req.OperationID, "joinedGroup ", groupNode) + } + log.NewInfo(req.OperationID, "GetJoinedGroupList rpc return ", resp.String()) + return &resp, nil +} + +func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbGroup.InviteUserToGroupReq) (*pbGroup.InviteUserToGroupResp, error) { + log.NewInfo(req.OperationID, "InviteUserToGroup args ", req.String()) + + if !imdb.IsExistGroupMember(req.GroupID, req.OpUserID) && !token_verify.IsManagerUserID(req.OpUserID) { + log.NewError(req.OperationID, "no permission InviteUserToGroup ", req.GroupID, req.OpUserID) + return &pbGroup.InviteUserToGroupResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + _, err := imdb.GetGroupInfoByGroupID(req.GroupID) + if err != nil { + log.NewError(req.OperationID, "GetGroupInfoByGroupID failed ", req.GroupID, err) + return &pbGroup.InviteUserToGroupResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + // + //from User: invite: applicant + //to user: invite: invited + var resp pbGroup.InviteUserToGroupResp + var okUserIDList []string + for _, v := range req.InvitedUserIDList { + var resultNode pbGroup.Id2Result + resultNode.UserID = v + resultNode.Result = 0 + toUserInfo, err := imdb.GetUserByUserID(v) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), v) + resultNode.Result = -1 + resp.Id2ResultList = append(resp.Id2ResultList, &resultNode) + continue + } + + if imdb.IsExistGroupMember(req.GroupID, v) { + log.NewError(req.OperationID, "IsExistGroupMember ", req.GroupID, v) + resultNode.Result = -1 + resp.Id2ResultList = append(resp.Id2ResultList, &resultNode) + continue + } + var toInsertInfo db.GroupMember + utils.CopyStructFields(&toInsertInfo, toUserInfo) + toInsertInfo.GroupID = req.GroupID + toInsertInfo.RoleLevel = constant.GroupOrdinaryUsers + toInsertInfo.OperatorUserID = req.OpUserID + err = imdb.InsertIntoGroupMember(toInsertInfo) + if err != nil { + log.NewError(req.OperationID, "InsertIntoGroupMember failed ", req.GroupID, toUserInfo.UserID, toUserInfo.Nickname, toUserInfo.FaceURL) + resultNode.Result = -1 + resp.Id2ResultList = append(resp.Id2ResultList, &resultNode) + continue + } + okUserIDList = append(okUserIDList, v) + err = db.DB.AddGroupMember(req.GroupID, toUserInfo.UserID) + if err != nil { + log.NewError(req.OperationID, "AddGroupMember failed ", err.Error(), req.GroupID, toUserInfo.UserID) + } + resp.Id2ResultList = append(resp.Id2ResultList, &resultNode) + } + + chat.MemberInvitedNotification(req.OperationID, req.GroupID, req.OpUserID, req.Reason, okUserIDList) + resp.ErrCode = 0 + log.NewInfo(req.OperationID, "InviteUserToGroup rpc return ", resp.String()) + return &resp, nil +} + +func (s *groupServer) GetGroupAllMember(ctx context.Context, req *pbGroup.GetGroupAllMemberReq) (*pbGroup.GetGroupAllMemberResp, error) { + log.NewInfo(req.OperationID, "GetGroupAllMember, args ", req.String()) + var resp pbGroup.GetGroupAllMemberResp + memberList, err := imdb.GetGroupMemberListByGroupID(req.GroupID) + if err != nil { + resp.ErrCode = constant.ErrDB.ErrCode + resp.ErrMsg = constant.ErrDB.ErrMsg + log.NewError(req.OperationID, "GetGroupMemberListByGroupID failed,", err.Error(), req.GroupID) + return &resp, nil + } + + for _, v := range memberList { + log.Debug(req.OperationID, v) + var node open_im_sdk.GroupMemberFullInfo + cp.GroupMemberDBCopyOpenIM(&node, &v) + log.Debug(req.OperationID, "db value:", v.MuteEndTime, "seconds: ", v.MuteEndTime.Unix()) + log.Debug(req.OperationID, "cp value: ", node) + resp.MemberList = append(resp.MemberList, &node) + } + log.NewInfo(req.OperationID, "GetGroupAllMember rpc return ", resp.String()) + return &resp, nil +} + +func (s *groupServer) GetGroupMemberList(ctx context.Context, req *pbGroup.GetGroupMemberListReq) (*pbGroup.GetGroupMemberListResp, error) { + log.NewInfo(req.OperationID, "GetGroupMemberList args ", req.String()) + var resp pbGroup.GetGroupMemberListResp + memberList, err := imdb.GetGroupMemberByGroupID(req.GroupID, req.Filter, req.NextSeq, 30) + if err != nil { + resp.ErrCode = constant.ErrDB.ErrCode + resp.ErrMsg = constant.ErrDB.ErrMsg + log.NewError(req.OperationID, "GetGroupMemberByGroupId failed,", req.GroupID, req.Filter, req.NextSeq, 30) + return &resp, nil + } + + for _, v := range memberList { + var node open_im_sdk.GroupMemberFullInfo + utils.CopyStructFields(&node, &v) + resp.MemberList = append(resp.MemberList, &node) + } + //db operate get db sorted by join time + if int32(len(memberList)) < 30 { + resp.NextSeq = 0 + } else { + resp.NextSeq = req.NextSeq + int32(len(memberList)) + } + + resp.ErrCode = 0 + log.NewInfo(req.OperationID, "GetGroupMemberList rpc return ", resp.String()) + return &resp, nil +} + +func (s *groupServer) KickGroupMember(ctx context.Context, req *pbGroup.KickGroupMemberReq) (*pbGroup.KickGroupMemberResp, error) { + log.NewInfo(req.OperationID, "KickGroupMember args ", req.String()) + ownerList, err := imdb.GetOwnerManagerByGroupID(req.GroupID) + if err != nil { + log.NewError(req.OperationID, "GetOwnerManagerByGroupId failed ", err.Error(), req.GroupID) + return &pbGroup.KickGroupMemberResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}, nil + } + //op is group owner? + var flag = 0 + for _, v := range ownerList { + if v.UserID == req.OpUserID { + flag = 1 + log.NewDebug(req.OperationID, "is group owner ", req.OpUserID, req.GroupID) + break + } + } + + //op is app manager + if flag != 1 { + if token_verify.IsManagerUserID(req.OpUserID) { + flag = 1 + log.NewDebug(req.OperationID, "is app manager ", req.OpUserID) + } + } + + if flag != 1 { + log.NewError(req.OperationID, "failed, no access kick ", req.OpUserID) + return &pbGroup.KickGroupMemberResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + if len(req.KickedUserIDList) == 0 { + log.NewError(req.OperationID, "failed, kick list 0") + return &pbGroup.KickGroupMemberResp{ErrCode: constant.ErrArgs.ErrCode, ErrMsg: constant.ErrArgs.ErrMsg}, nil + } + + groupOwnerUserID := "" + for _, v := range ownerList { + if v.RoleLevel == constant.GroupOwner { + groupOwnerUserID = v.UserID + } + } + + var okUserIDList []string + //remove + var resp pbGroup.KickGroupMemberResp + for _, v := range req.KickedUserIDList { + //owner can‘t kicked + if v == groupOwnerUserID { + log.NewError(req.OperationID, "failed, can't kick owner ", v) + resp.Id2ResultList = append(resp.Id2ResultList, &pbGroup.Id2Result{UserID: v, Result: -1}) + continue + } + err := imdb.RemoveGroupMember(req.GroupID, v) + if err != nil { + log.NewError(req.OperationID, "RemoveGroupMember failed ", err.Error(), req.GroupID, v) + resp.Id2ResultList = append(resp.Id2ResultList, &pbGroup.Id2Result{UserID: v, Result: -1}) + } else { + log.NewDebug(req.OperationID, "kicked ", v) + resp.Id2ResultList = append(resp.Id2ResultList, &pbGroup.Id2Result{UserID: v, Result: 0}) + okUserIDList = append(okUserIDList, v) + } + + err = db.DB.DelGroupMember(req.GroupID, v) + if err != nil { + log.NewError(req.OperationID, "DelGroupMember failed ", err.Error(), req.GroupID, v) + } + } + chat.MemberKickedNotification(req, okUserIDList) + log.NewInfo(req.OperationID, "GetGroupMemberList rpc return ", resp.String()) + return &resp, nil +} + +func (s *groupServer) GetGroupMembersInfo(ctx context.Context, req *pbGroup.GetGroupMembersInfoReq) (*pbGroup.GetGroupMembersInfoResp, error) { + log.NewInfo(req.OperationID, "GetGroupMembersInfo args ", req.String()) + + var resp pbGroup.GetGroupMembersInfoResp + + for _, v := range req.MemberList { + var memberNode open_im_sdk.GroupMemberFullInfo + memberInfo, err := imdb.GetMemberInfoByID(req.GroupID, v) + memberNode.UserID = v + if err != nil { + log.NewError(req.OperationID, "GetMemberInfoById failed ", err.Error(), req.GroupID, v) + continue + } else { + utils.CopyStructFields(&memberNode, memberInfo) + memberNode.JoinTime = int32(memberInfo.JoinTime.Unix()) + resp.MemberList = append(resp.MemberList, &memberNode) + } + } + resp.ErrCode = 0 + log.NewInfo(req.OperationID, "GetGroupMembersInfo rpc return ", resp.String()) + return &resp, nil +} + +func (s *groupServer) GetGroupApplicationList(_ context.Context, req *pbGroup.GetGroupApplicationListReq) (*pbGroup.GetGroupApplicationListResp, error) { + log.NewInfo(req.OperationID, "GetGroupMembersInfo args ", req.String()) + reply, err := imdb.GetGroupApplicationList(req.FromUserID) + if err != nil { + log.NewError(req.OperationID, "GetGroupApplicationList failed ", err.Error(), req.FromUserID) + return &pbGroup.GetGroupApplicationListResp{ErrCode: 701, ErrMsg: "GetGroupApplicationList failed"}, nil + } + + log.NewDebug(req.OperationID, "GetGroupApplicationList reply ", reply) + resp := pbGroup.GetGroupApplicationListResp{} + for _, v := range reply { + node := open_im_sdk.GroupRequest{UserInfo: &open_im_sdk.PublicUserInfo{}, GroupInfo: &open_im_sdk.GroupInfo{}} + group, err := imdb.GetGroupInfoByGroupID(v.GroupID) + if err != nil { + log.Error(req.OperationID, "GetGroupInfoByGroupID failed ", err.Error(), v.GroupID) + continue + } + user, err := imdb.GetUserByUserID(v.UserID) + if err != nil { + log.Error(req.OperationID, "GetUserByUserID failed ", err.Error(), v.UserID) + continue + } + + cp.GroupRequestDBCopyOpenIM(&node, &v) + cp.UserDBCopyOpenIMPublicUser(node.UserInfo, user) + cp.GroupDBCopyOpenIM(node.GroupInfo, group) + log.NewDebug(req.OperationID, "node ", node, "v ", v) + resp.GroupRequestList = append(resp.GroupRequestList, &node) + } + log.NewInfo(req.OperationID, "GetGroupMembersInfo rpc return ", resp) + return &resp, nil +} + +func (s *groupServer) GetGroupsInfo(ctx context.Context, req *pbGroup.GetGroupsInfoReq) (*pbGroup.GetGroupsInfoResp, error) { + log.NewInfo(req.OperationID, "GetGroupsInfo args ", req.String()) + groupsInfoList := make([]*open_im_sdk.GroupInfo, 0) + for _, groupID := range req.GroupIDList { + groupInfoFromMysql, err := imdb.GetGroupInfoByGroupID(groupID) + if err != nil { + log.NewError(req.OperationID, "GetGroupInfoByGroupID failed ", err.Error(), groupID) + continue + } + var groupInfo open_im_sdk.GroupInfo + cp.GroupDBCopyOpenIM(&groupInfo, groupInfoFromMysql) + groupsInfoList = append(groupsInfoList, &groupInfo) + } + + resp := pbGroup.GetGroupsInfoResp{GroupInfoList: groupsInfoList} + log.NewInfo(req.OperationID, "GetGroupsInfo rpc return ", resp) + return &resp, nil +} + +func (s *groupServer) GroupApplicationResponse(_ context.Context, req *pbGroup.GroupApplicationResponseReq) (*pbGroup.GroupApplicationResponseResp, error) { + log.NewInfo(req.OperationID, "GroupApplicationResponse args ", req.String()) + + groupRequest := db.GroupRequest{} + utils.CopyStructFields(&groupRequest, req) + groupRequest.UserID = req.FromUserID + groupRequest.HandleUserID = req.OpUserID + groupRequest.HandledTime = time.Now() + if !token_verify.IsManagerUserID(req.OpUserID) && !imdb.IsGroupOwnerAdmin(req.GroupID, req.OpUserID) { + log.NewError(req.OperationID, "IsManagerUserID IsGroupOwnerAdmin false ", req.GroupID, req.OpUserID) + return &pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + err := imdb.UpdateGroupRequest(groupRequest) + if err != nil { + //{openIM002 7836e478bc43ce1d3b8889cac983f59b 1 ok 0001-01-01 00:00:00 +0000 UTC openIM001 0001-01-01 00:00:00 +0000 UTC } + log.NewError(req.OperationID, "GroupApplicationResponse failed ", err.Error(), groupRequest) + return &pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + if req.HandleResult == constant.GroupResponseAgree { + user, err := imdb.GetUserByUserID(req.FromUserID) + if err != nil { + log.NewError(req.OperationID, "GroupApplicationResponse failed ", err.Error(), req.FromUserID) + return &pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + member := db.GroupMember{} + member.GroupID = req.GroupID + member.UserID = req.FromUserID + member.RoleLevel = constant.GroupOrdinaryUsers + member.OperatorUserID = req.OpUserID + member.FaceURL = user.FaceURL + member.Nickname = user.Nickname + + err = imdb.InsertIntoGroupMember(member) + if err != nil { + log.NewError(req.OperationID, "GroupApplicationResponse failed ", err.Error(), member) + return &pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupApplicationAcceptedNotification(req) + chat.MemberEnterNotification(req) + } else if req.HandleResult == constant.GroupResponseRefuse { + chat.GroupApplicationRejectedNotification(req) + } else { + log.Error(req.OperationID, "HandleResult failed ", req.HandleResult) + return &pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrArgs.ErrCode, ErrMsg: constant.ErrArgs.ErrMsg}}, nil + } + + log.NewInfo(req.OperationID, "rpc GroupApplicationResponse return ", pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{}}) + return &pbGroup.GroupApplicationResponseResp{CommonResp: &pbGroup.CommonResp{}}, nil +} + +func (s *groupServer) JoinGroup(ctx context.Context, req *pbGroup.JoinGroupReq) (*pbGroup.JoinGroupResp, error) { + log.NewInfo(req.OperationID, "JoinGroup args ", req.String()) + _, err := imdb.GetUserByUserID(req.OpUserID) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), req.OpUserID) + return &pbGroup.JoinGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + var groupRequest db.GroupRequest + groupRequest.UserID = req.OpUserID + groupRequest.ReqMsg = req.ReqMessage + groupRequest.GroupID = req.GroupID + + err = imdb.InsertIntoGroupRequest(groupRequest) + if err != nil { + log.NewError(req.OperationID, "UpdateGroupRequest ", err.Error(), groupRequest) + return &pbGroup.JoinGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + _, err = imdb.GetGroupMemberListByGroupIDAndRoleLevel(req.GroupID, constant.GroupOwner) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberListByGroupIDAndRoleLevel failed ", err.Error(), req.GroupID, constant.GroupOwner) + return &pbGroup.JoinGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil + } + + chat.JoinGroupApplicationNotification(req) + + log.NewInfo(req.OperationID, "ReceiveJoinApplicationNotification rpc return ") + return &pbGroup.JoinGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} + +func (s *groupServer) QuitGroup(ctx context.Context, req *pbGroup.QuitGroupReq) (*pbGroup.QuitGroupResp, error) { + log.NewError(req.OperationID, "QuitGroup args ", req.String()) + _, err := imdb.GetGroupMemberInfoByGroupIDAndUserID(req.GroupID, req.OpUserID) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberInfoByGroupIDAndUserID failed ", err.Error(), req.GroupID, req.OpUserID) + return &pbGroup.QuitGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + err = imdb.DeleteGroupMemberByGroupIDAndUserID(req.GroupID, req.OpUserID) + if err != nil { + log.NewError(req.OperationID, "DeleteGroupMemberByGroupIdAndUserId failed ", err.Error(), req.GroupID, req.OpUserID) + return &pbGroup.QuitGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + + err = db.DB.DelGroupMember(req.GroupID, req.OpUserID) + if err != nil { + log.NewError(req.OperationID, "DelGroupMember failed ", req.GroupID, req.OpUserID) + // return &pbGroup.CommonResp{ErrorCode: constant.ErrQuitGroup.ErrCode, ErrorMsg: constant.ErrQuitGroup.ErrMsg}, nil + } + + chat.MemberQuitNotification(req) + log.NewInfo(req.OperationID, "rpc QuitGroup return ", pbGroup.QuitGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}) + return &pbGroup.QuitGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} + +func hasAccess(req *pbGroup.SetGroupInfoReq) bool { + if utils.IsContain(req.OpUserID, config.Config.Manager.AppManagerUid) { + return true + } + groupUserInfo, err := imdb.GetGroupMemberInfoByGroupIDAndUserID(req.GroupInfo.GroupID, req.OpUserID) + if err != nil { + log.NewError(req.OperationID, "GetGroupMemberInfoByGroupIDAndUserID failed, ", err.Error(), req.GroupInfo.GroupID, req.OpUserID) + return false + + } + if groupUserInfo.RoleLevel == constant.GroupOwner || groupUserInfo.RoleLevel == constant.GroupAdmin { + return true + } + return false +} + +func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbGroup.SetGroupInfoReq) (*pbGroup.SetGroupInfoResp, error) { + log.NewInfo(req.OperationID, "SetGroupInfo args ", req.String()) + if !hasAccess(req) { + log.NewError(req.OperationID, "no access ", req) + return &pbGroup.SetGroupInfoResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + + group, err := imdb.GetGroupInfoByGroupID(req.GroupInfo.GroupID) + if err != nil { + log.NewError(req.OperationID, "GetGroupInfoByGroupID failed ", err.Error(), req.GroupInfo.GroupID) + return &pbGroup.SetGroupInfoResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, http.WrapError(constant.ErrDB) + } + + ////bitwise operators: 0001:groupName; 0010:Notification 0100:Introduction; 1000:FaceUrl; 10000:owner + var changedType int32 + if group.GroupName != req.GroupInfo.GroupName && req.GroupInfo.GroupName != "" { + changedType = 1 + } + if group.Notification != req.GroupInfo.Notification && req.GroupInfo.Notification != "" { + changedType = changedType | (1 << 1) + } + if group.Introduction != req.GroupInfo.Introduction && req.GroupInfo.Introduction != "" { + changedType = changedType | (1 << 2) + } + if group.FaceURL != req.GroupInfo.FaceURL && req.GroupInfo.FaceURL != "" { + changedType = changedType | (1 << 3) + } + //only administrators can set group information + var groupInfo db.Group + utils.CopyStructFields(&groupInfo, req.GroupInfo) + err = imdb.SetGroupInfo(groupInfo) + if err != nil { + log.NewError(req.OperationID, "SetGroupInfo failed ", err.Error(), groupInfo) + return &pbGroup.SetGroupInfoResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, http.WrapError(constant.ErrDB) + } + log.NewInfo(req.OperationID, "SetGroupInfo rpc return ", pbGroup.SetGroupInfoResp{CommonResp: &pbGroup.CommonResp{}}) + if changedType != 0 { + chat.GroupInfoSetNotification(req.OperationID, req.OpUserID, req.GroupInfo.GroupID) + } + return &pbGroup.SetGroupInfoResp{CommonResp: &pbGroup.CommonResp{}}, nil +} + +func (s *groupServer) TransferGroupOwner(_ context.Context, req *pbGroup.TransferGroupOwnerReq) (*pbGroup.TransferGroupOwnerResp, error) { + log.NewInfo(req.OperationID, "TransferGroupOwner ", req.String()) + + if req.OldOwnerUserID == req.NewOwnerUserID { + log.NewError(req.OperationID, "same owner ", req.OldOwnerUserID, req.NewOwnerUserID) + return &pbGroup.TransferGroupOwnerResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrArgs.ErrCode, ErrMsg: constant.ErrArgs.ErrMsg}}, nil + } + groupMemberInfo := db.GroupMember{GroupID: req.GroupID, UserID: req.OldOwnerUserID, RoleLevel: constant.GroupOrdinaryUsers} + err := imdb.UpdateGroupMemberInfo(groupMemberInfo) + if err != nil { + log.NewError(req.OperationID, "UpdateGroupMemberInfo failed ", groupMemberInfo) + return &pbGroup.TransferGroupOwnerResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + groupMemberInfo = db.GroupMember{GroupID: req.GroupID, UserID: req.NewOwnerUserID, RoleLevel: constant.GroupOwner} + err = imdb.UpdateGroupMemberInfo(groupMemberInfo) + if err != nil { + log.NewError(req.OperationID, "UpdateGroupMemberInfo failed ", groupMemberInfo) + return &pbGroup.TransferGroupOwnerResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupOwnerTransferredNotification(req) + + return &pbGroup.TransferGroupOwnerResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil + +} + +func (s *groupServer) GetGroupById(_ context.Context, req *pbGroup.GetGroupByIdReq) (*pbGroup.GetGroupByIdResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbGroup.GetGroupByIdResp{CMSGroup: &pbGroup.CMSGroup{ + GroupInfo: &open_im_sdk.GroupInfo{}, + }} + group, err := imdb.GetGroupById(req.GroupId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupById error", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + resp.CMSGroup.GroupInfo = &open_im_sdk.GroupInfo{ + GroupID: group.GroupID, + GroupName: group.GroupName, + FaceURL: group.FaceURL, + OwnerUserID: group.CreatorUserID, + MemberCount: 0, + Status: group.Status, + CreatorUserID: group.CreatorUserID, + GroupType: group.GroupType, + CreateTime: uint32(group.CreateTime.Unix()), + } + groupMember, err := imdb.GetGroupMaster(group.GroupID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMaster", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + resp.CMSGroup.GroupMasterName = groupMember.Nickname + resp.CMSGroup.GroupMasterId = groupMember.UserID + resp.CMSGroup.GroupInfo.CreatorUserID = group.CreatorUserID + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *groupServer) GetGroup(_ context.Context, req *pbGroup.GetGroupReq) (*pbGroup.GetGroupResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbGroup.GetGroupResp{ + CMSGroups: []*pbGroup.CMSGroup{}, + } + groups, err := imdb.GetGroupsByName(req.GroupName, req.Pagination.PageNumber, req.Pagination.ShowNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupsByName error", req.String()) + return resp, http.WrapError(constant.ErrDB) + } + nums, err := imdb.GetGroupsCountNum(db.Group{GroupName: req.GroupName}) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupsCountNum error", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + resp.GroupNums = nums + resp.Pagination = &open_im_sdk.RequestPagination{ + PageNumber: req.Pagination.PageNumber, + ShowNumber: req.Pagination.ShowNumber, + } + for _, v := range groups { + groupMember, err := imdb.GetGroupMaster(v.GroupID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMaster error", err.Error()) + continue + } + resp.CMSGroups = append(resp.CMSGroups, &pbGroup.CMSGroup{ + GroupInfo: &open_im_sdk.GroupInfo{ + GroupID: v.GroupID, + GroupName: v.GroupName, + FaceURL: v.FaceURL, + OwnerUserID: v.CreatorUserID, + Status: v.Status, + CreatorUserID: v.CreatorUserID, + CreateTime: uint32(v.CreateTime.Unix()), + }, + GroupMasterName: groupMember.Nickname, + GroupMasterId: groupMember.UserID, + }) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *groupServer) GetGroups(_ context.Context, req *pbGroup.GetGroupsReq) (*pbGroup.GetGroupsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "GetGroups ", req.String()) + resp := &pbGroup.GetGroupsResp{ + CMSGroups: []*pbGroup.CMSGroup{}, + Pagination: &open_im_sdk.RequestPagination{}, + } + groups, err := imdb.GetGroups(int(req.Pagination.PageNumber), int(req.Pagination.ShowNumber)) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroups error", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + groupsCountNum, err := imdb.GetGroupsCountNum(db.Group{}) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "groupsCountNum ", groupsCountNum) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupsCountNum", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + resp.GroupNum = int32(groupsCountNum) + resp.Pagination.PageNumber = req.Pagination.PageNumber + resp.Pagination.ShowNumber = req.Pagination.ShowNumber + for _, v := range groups { + groupMember, err := imdb.GetGroupMaster(v.GroupID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error()) + } + resp.CMSGroups = append(resp.CMSGroups, &pbGroup.CMSGroup{ + GroupInfo: &open_im_sdk.GroupInfo{ + GroupID: v.GroupID, + GroupName: v.GroupName, + FaceURL: v.FaceURL, + OwnerUserID: v.CreatorUserID, + Status: v.Status, + CreatorUserID: v.CreatorUserID, + CreateTime: uint32(v.CreateTime.Unix()), + }, + GroupMasterId: groupMember.UserID, + GroupMasterName: groupMember.Nickname, + }) + } + + return resp, nil +} + +func (s *groupServer) OperateGroupStatus(_ context.Context, req *pbGroup.OperateGroupStatusReq) (*pbGroup.OperateGroupStatusResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbGroup.OperateGroupStatusResp{} + if err := imdb.OperateGroupStatus(req.GroupId, req.Status); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "OperateGroupStatus", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + return resp, nil +} + +func (s *groupServer) DeleteGroup(_ context.Context, req *pbGroup.DeleteGroupReq) (*pbGroup.DeleteGroupResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbGroup.DeleteGroupResp{} + if err := imdb.DeleteGroup(req.GroupId); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "DeleteGroup error", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + return resp, nil +} + +func (s *groupServer) OperateUserRole(_ context.Context, req *pbGroup.OperateUserRoleReq) (*pbGroup.OperateUserRoleResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "args:", req.String()) + resp := &pbGroup.OperateUserRoleResp{} + oldOwnerUserID, err := imdb.GetGroupMaster(req.GroupId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMaster failed", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + var reqPb pbGroup.TransferGroupOwnerReq + reqPb.OperationID = req.OperationID + reqPb.NewOwnerUserID = req.UserId + reqPb.GroupID = req.GroupId + reqPb.OpUserID = "cms admin" + reqPb.OldOwnerUserID = oldOwnerUserID.UserID + reply, err := client.TransferGroupOwner(context.Background(), &reqPb) + if reply.CommonResp.ErrCode != 0 || err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "TransferGroupOwner rpc failed") + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error()) + } + } + return resp, nil +} + +func (s *groupServer) GetGroupMembersCMS(_ context.Context, req *pbGroup.GetGroupMembersCMSReq) (*pbGroup.GetGroupMembersCMSResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "args:", req.String()) + resp := &pbGroup.GetGroupMembersCMSResp{} + groupMembers, err := imdb.GetGroupMembersByGroupIdCMS(req.GroupId, req.UserName, req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMembersByGroupIdCMS Error", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + groupMembersCount, err := imdb.GetGroupMembersCount(req.GroupId, req.UserName) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMembersCMS Error", err.Error()) + return resp, http.WrapError(constant.ErrDB) + } + log.NewInfo(req.OperationID, groupMembersCount) + resp.MemberNums = groupMembersCount + for _, groupMember := range groupMembers { + resp.Members = append(resp.Members, &open_im_sdk.GroupMemberFullInfo{ + GroupID: req.GroupId, + UserID: groupMember.UserID, + RoleLevel: groupMember.RoleLevel, + JoinTime: int32(groupMember.JoinTime.Unix()), + Nickname: groupMember.Nickname, + FaceURL: groupMember.FaceURL, + JoinSource: groupMember.JoinSource, + }) + } + resp.Pagination = &open_im_sdk.ResponsePagination{ + CurrentPage: req.Pagination.PageNumber, + ShowNumber: req.Pagination.ShowNumber, + } + return resp, nil +} + +func (s *groupServer) RemoveGroupMembersCMS(_ context.Context, req *pbGroup.RemoveGroupMembersCMSReq) (*pbGroup.RemoveGroupMembersCMSResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "args:", req.String()) + resp := &pbGroup.RemoveGroupMembersCMSResp{} + for _, userId := range req.UserIds { + err := imdb.RemoveGroupMember(req.GroupId, userId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error()) + resp.Failed = append(resp.Failed, userId) + } else { + resp.Success = append(resp.Success, userId) + } + } + reqKick := &pbGroup.KickGroupMemberReq{ + GroupID: req.GroupId, + KickedUserIDList: resp.Success, + Reason: "admin kick", + OperationID: req.OperationID, + OpUserID: req.OpUserId, + } + chat.MemberKickedNotification(reqKick, resp.Success) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "success: ", resp.Success) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "failed: ", resp.Failed) + return resp, nil +} + +func (s *groupServer) AddGroupMembersCMS(_ context.Context, req *pbGroup.AddGroupMembersCMSReq) (*pbGroup.AddGroupMembersCMSResp, error) { + log.NewInfo(req.OperationId, utils.GetSelfFuncName(), "args:", req.String()) + resp := &pbGroup.AddGroupMembersCMSResp{} + for _, userId := range req.UserIds { + if isExist := imdb.IsExistGroupMember(req.GroupId, userId); isExist { + log.NewError(req.OperationId, utils.GetSelfFuncName(), "user is exist in group", userId, req.GroupId) + resp.Failed = append(resp.Failed, userId) + continue + } + user, err := imdb.GetUserByUserID(userId) + if err != nil { + log.NewError(req.OperationId, utils.GetSelfFuncName(), "GetUserByUserID", err.Error()) + resp.Failed = append(resp.Failed, userId) + continue + } + groupMember := db.GroupMember{ + GroupID: req.GroupId, + UserID: userId, + Nickname: user.Nickname, + FaceURL: "", + RoleLevel: 1, + JoinTime: time.Time{}, + JoinSource: constant.JoinByAdmin, + OperatorUserID: "CmsAdmin", + Ex: "", + } + if err := imdb.InsertIntoGroupMember(groupMember); err != nil { + log.NewError(req.OperationId, utils.GetSelfFuncName(), "InsertIntoGroupMember failed", req.String()) + resp.Failed = append(resp.Failed, userId) + } else { + resp.Success = append(resp.Success, userId) + } + } + chat.MemberInvitedNotification(req.OperationId, req.GroupId, req.OpUserId, "admin add you to group", resp.Success) + return resp, nil +} + +func (s *groupServer) GetUserReqApplicationList(_ context.Context, req *pbGroup.GetUserReqApplicationListReq) (*pbGroup.GetUserReqApplicationListResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbGroup.GetUserReqApplicationListResp{} + groupRequests, err := imdb.GetUserReqGroupByUserID(req.UserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserReqGroupByUserID failed ", err.Error()) + resp.CommonResp = &pbGroup.CommonResp{ + ErrCode: constant.ErrDB.ErrCode, + ErrMsg: constant.ErrDB.ErrMsg, + } + return resp, nil + } + for _, groupReq := range groupRequests { + node := open_im_sdk.GroupRequest{UserInfo: &open_im_sdk.PublicUserInfo{}, GroupInfo: &open_im_sdk.GroupInfo{}} + group, err := imdb.GetGroupInfoByGroupID(groupReq.GroupID) + if err != nil { + log.Error(req.OperationID, "GetGroupInfoByGroupID failed ", err.Error(), groupReq.GroupID) + continue + } + user, err := imdb.GetUserByUserID(groupReq.UserID) + if err != nil { + log.Error(req.OperationID, "GetUserByUserID failed ", err.Error(), groupReq.UserID) + continue + } + cp.GroupRequestDBCopyOpenIM(&node, &groupReq) + cp.UserDBCopyOpenIMPublicUser(node.UserInfo, user) + cp.GroupDBCopyOpenIM(node.GroupInfo, group) + resp.GroupRequestList = append(resp.GroupRequestList, &node) + } + resp.CommonResp = &pbGroup.CommonResp{ + ErrCode: 0, + ErrMsg: "", + } + return resp, nil +} + +func (s *groupServer) DismissGroup(ctx context.Context, req *pbGroup.DismissGroupReq) (*pbGroup.DismissGroupResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) && !imdb.IsGroupOwnerAdmin(req.GroupID, req.OpUserID) { + log.NewError(req.OperationID, "verify failed ", req.OpUserID, req.GroupID) + return &pbGroup.DismissGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + + err := imdb.OperateGroupStatus(req.GroupID, constant.GroupStatusDismissed) + if err != nil { + log.NewError(req.OperationID, "OperateGroupStatus failed ", req.GroupID, constant.GroupStatusDismissed) + return &pbGroup.DismissGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupDismissedNotification(req) + + err = imdb.DeleteGroupMemberByGroupID(req.GroupID) + if err != nil { + log.NewError(req.OperationID, "DeleteGroupMemberByGroupID failed ", req.GroupID) + return &pbGroup.DismissGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return ", pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}) + return &pbGroup.DismissGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} + +// rpc MuteGroupMember(MuteGroupMemberReq) returns(MuteGroupMemberResp); +// rpc CancelMuteGroupMember(CancelMuteGroupMemberReq) returns(CancelMuteGroupMemberResp); +// rpc MuteGroup(MuteGroupReq) returns(MuteGroupResp); +// rpc CancelMuteGroup(CancelMuteGroupReq) returns(CancelMuteGroupResp); + +func (s *groupServer) MuteGroupMember(ctx context.Context, req *pbGroup.MuteGroupMemberReq) (*pbGroup.MuteGroupMemberResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc args ", req.String()) + if !imdb.IsGroupOwnerAdmin(req.GroupID, req.OpUserID) && !token_verify.IsManagerUserID(req.OpUserID) { + log.Error(req.OperationID, "verify failed ", req.GroupID, req.UserID) + return &pbGroup.MuteGroupMemberResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + groupMemberInfo := db.GroupMember{GroupID: req.GroupID, UserID: req.UserID} + + groupMemberInfo.MuteEndTime = time.Unix(int64(time.Now().Second())+int64(req.MutedSeconds), time.Now().UnixNano()) + err := imdb.UpdateGroupMemberInfo(groupMemberInfo) + if err != nil { + log.Error(req.OperationID, "UpdateGroupMemberInfo failed ", err.Error(), groupMemberInfo) + return &pbGroup.MuteGroupMemberResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupMemberMutedNotification(req.OperationID, req.OpUserID, req.GroupID, req.UserID, req.MutedSeconds) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return ", pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}) + return &pbGroup.MuteGroupMemberResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} + +func (s *groupServer) CancelMuteGroupMember(ctx context.Context, req *pbGroup.CancelMuteGroupMemberReq) (*pbGroup.CancelMuteGroupMemberResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc args ", req.String()) + if !imdb.IsGroupOwnerAdmin(req.GroupID, req.OpUserID) && !token_verify.IsManagerUserID(req.OpUserID) { + log.Error(req.OperationID, "verify failed ", req.OpUserID, req.GroupID) + return &pbGroup.CancelMuteGroupMemberResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + groupMemberInfo := db.GroupMember{GroupID: req.GroupID, UserID: req.UserID} + groupMemberInfo.MuteEndTime = time.Unix(0, 0) + err := imdb.UpdateGroupMemberInfo(groupMemberInfo) + if err != nil { + log.Error(req.OperationID, "UpdateGroupMemberInfo failed ", err.Error(), groupMemberInfo) + return &pbGroup.CancelMuteGroupMemberResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupMemberCancelMutedNotification(req.OperationID, req.OpUserID, req.GroupID, req.UserID) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return ", pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}) + return &pbGroup.CancelMuteGroupMemberResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} + +func (s *groupServer) MuteGroup(ctx context.Context, req *pbGroup.MuteGroupReq) (*pbGroup.MuteGroupResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc args ", req.String()) + if !imdb.IsGroupOwnerAdmin(req.GroupID, req.OpUserID) && !token_verify.IsManagerUserID(req.OpUserID) { + log.Error(req.OperationID, "verify failed ", req.GroupID, req.GroupID) + return &pbGroup.MuteGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + err := imdb.OperateGroupStatus(req.GroupID, constant.GroupStatusMuted) + if err != nil { + log.Error(req.OperationID, "OperateGroupStatus failed ", err.Error(), req.GroupID, constant.GroupStatusMuted) + return &pbGroup.MuteGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupMutedNotification(req.OperationID, req.OpUserID, req.GroupID) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return ", pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}) + return &pbGroup.MuteGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} + +func (s *groupServer) CancelMuteGroup(ctx context.Context, req *pbGroup.CancelMuteGroupReq) (*pbGroup.CancelMuteGroupResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc args ", req.String()) + if !imdb.IsGroupOwnerAdmin(req.GroupID, req.OpUserID) && !token_verify.IsManagerUserID(req.OpUserID) { + log.Error(req.OperationID, "verify failed ", req.OpUserID, req.GroupID) + return &pbGroup.CancelMuteGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + + err := imdb.UpdateGroupInfoDefaultZero(req.GroupID, map[string]interface{}{"status": constant.GroupOk}) + if err != nil { + log.Error(req.OperationID, "UpdateGroupInfoDefaultZero failed ", err.Error(), req.GroupID) + return &pbGroup.CancelMuteGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + chat.GroupCancelMutedNotification(req.OperationID, req.OpUserID, req.GroupID) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return ", pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}) + return &pbGroup.CancelMuteGroupResp{CommonResp: &pbGroup.CommonResp{ErrCode: 0, ErrMsg: ""}}, nil +} diff --git a/internal/rpc/message_cms/message_cms.go b/internal/rpc/message_cms/message_cms.go new file mode 100644 index 000000000..7f27e007a --- /dev/null +++ b/internal/rpc/message_cms/message_cms.go @@ -0,0 +1,167 @@ +package messageCMS + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + errors "Open_IM/pkg/common/http" + "context" + + "Open_IM/pkg/common/log" + + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbMessageCMS "Open_IM/pkg/proto/message_cms" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + + "Open_IM/pkg/utils" + + "net" + "strconv" + "strings" + + "google.golang.org/grpc" +) + +type messageCMSServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewMessageCMSServer(port int) *messageCMSServer { + log.NewPrivateLog(constant.LogFileName) + return &messageCMSServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImMessageCMSName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *messageCMSServer) Run() { + log.NewInfo("0", "messageCMS rpc start ") + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("0", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("0", "listen network success, ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + pbMessageCMS.RegisterMessageCMSServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error()) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error()) + return + } + log.NewInfo("0", "message cms rpc success") +} + +func (s *messageCMSServer) BoradcastMessage(_ context.Context, req *pbMessageCMS.BoradcastMessageReq) (*pbMessageCMS.BoradcastMessageResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "BoradcastMessage", req.String()) + resp := &pbMessageCMS.BoradcastMessageResp{} + return resp, errors.WrapError(constant.ErrDB) +} + +func (s *messageCMSServer) GetChatLogs(_ context.Context, req *pbMessageCMS.GetChatLogsReq) (*pbMessageCMS.GetChatLogsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "GetChatLogs", req.String()) + resp := &pbMessageCMS.GetChatLogsResp{} + time, err := utils.TimeStringToTime(req.Date) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "time string parse error", err.Error()) + } + chatLog := db.ChatLog{ + Content: req.Content, + SendTime: time, + ContentType: req.ContentType, + SessionType: req.SessionType, + } + switch chatLog.SessionType { + case constant.SingleChatType: + chatLog.SendID = req.UserId + case constant.GroupChatType: + chatLog.RecvID = req.GroupId + chatLog.SendID = req.UserId + } + nums, err := imdb.GetChatLogCount(chatLog) + resp.ChatLogsNum = int32(nums) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetChatLogCount", err.Error()) + } + chatLogs, err := imdb.GetChatLog(chatLog, req.Pagination.PageNumber, req.Pagination.ShowNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetChatLog", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + for _, chatLog := range chatLogs { + pbChatLog := &pbMessageCMS.ChatLogs{ + SessionType: chatLog.SessionType, + ContentType: chatLog.ContentType, + SearchContent: req.Content, + WholeContent: chatLog.Content, + Date: chatLog.CreateTime.String(), + SenderNickName: chatLog.SenderNickname, + SenderId: chatLog.SendID, + } + if chatLog.SenderNickname == "" { + sendUser, err := imdb.GetUserByUserID(chatLog.SendID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserByUserID failed", err.Error()) + continue + } + pbChatLog.SenderNickName = sendUser.Nickname + } + switch chatLog.SessionType { + case constant.SingleChatType: + recvUser, err := imdb.GetUserByUserID(chatLog.RecvID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserByUserID failed", err.Error()) + continue + } + pbChatLog.ReciverId = recvUser.UserID + pbChatLog.ReciverNickName = recvUser.Nickname + + case constant.GroupChatType: + group, err := imdb.GetGroupById(chatLog.RecvID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupById failed") + continue + } + pbChatLog.GroupId = group.GroupID + pbChatLog.GroupName = group.GroupName + } + resp.ChatLogs = append(resp.ChatLogs, pbChatLog) + } + resp.Pagination = &open_im_sdk.ResponsePagination{ + CurrentPage: req.Pagination.PageNumber, + ShowNumber: req.Pagination.ShowNumber, + } + + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp output: ", resp.String()) + return resp, nil +} + +func (s *messageCMSServer) MassSendMessage(_ context.Context, req *pbMessageCMS.MassSendMessageReq) (*pbMessageCMS.MassSendMessageResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "MassSendMessage", req.String()) + resp := &pbMessageCMS.MassSendMessageResp{} + return resp, nil +} + +func (s *messageCMSServer) WithdrawMessage(_ context.Context, req *pbMessageCMS.WithdrawMessageReq) (*pbMessageCMS.WithdrawMessageResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "WithdrawMessage", req.String()) + resp := &pbMessageCMS.WithdrawMessageResp{} + return resp, nil +} diff --git a/internal/rpc/msg/callback.go b/internal/rpc/msg/callback.go new file mode 100644 index 000000000..bb8ccd700 --- /dev/null +++ b/internal/rpc/msg/callback.go @@ -0,0 +1,159 @@ +package msg + +import ( + cbApi "Open_IM/pkg/call_back_struct" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/http" + "Open_IM/pkg/common/log" + pbChat "Open_IM/pkg/proto/chat" + "Open_IM/pkg/utils" +) + +func copyCallbackCommonReqStruct(msg *pbChat.SendMsgReq) cbApi.CommonCallbackReq { + return cbApi.CommonCallbackReq{ + SendID: msg.MsgData.SendID, + ServerMsgID: msg.MsgData.ServerMsgID, + ClientMsgID: msg.MsgData.ClientMsgID, + OperationID: msg.OperationID, + SenderPlatformID: msg.MsgData.SenderPlatformID, + SenderNickname: msg.MsgData.SenderNickname, + SessionType: msg.MsgData.SessionType, + MsgFrom: msg.MsgData.MsgFrom, + ContentType: msg.MsgData.ContentType, + Status: msg.MsgData.Status, + CreateTime: msg.MsgData.CreateTime, + Content: string(msg.MsgData.Content), + } +} + +func callbackBeforeSendSingleMsg(msg *pbChat.SendMsgReq) (canSend bool, err error) { + if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable { + return true, nil + } + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg) + commonCallbackReq := copyCallbackCommonReqStruct(msg) + commonCallbackReq.CallbackCommand = constant.CallbackBeforeSendSingleMsgCommand + req := cbApi.CallbackBeforeSendSingleMsgReq{ + CommonCallbackReq: commonCallbackReq, + RecvID: msg.MsgData.RecvID, + } + resp := &cbApi.CallbackBeforeSendSingleMsgResp{ + CommonCallbackResp: cbApi.CommonCallbackResp{}, + } + //utils.CopyStructFields(req, msg.MsgData) + defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp) + if err := http.PostReturn(config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg.CallbackTimeOut); err != nil { + if !config.Config.Callback.CallbackBeforeSendSingleMsg.CallbackFailedContinue { + return false, err + } else { + return true, err + } + } else { + if resp.ActionCode == constant.ActionForbidden && resp.ErrCode == constant.CallbackHandleSuccess { + return false, nil + } + } + return true, err +} + +func callbackAfterSendSingleMsg(msg *pbChat.SendMsgReq) error { + if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable { + return nil + } + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg) + commonCallbackReq := copyCallbackCommonReqStruct(msg) + commonCallbackReq.CallbackCommand = constant.CallbackAfterSendSingleMsgCommand + req := cbApi.CallbackAfterSendSingleMsgReq{ + CommonCallbackReq: commonCallbackReq, + RecvID: msg.MsgData.RecvID, + } + resp := &cbApi.CallbackAfterSendSingleMsgResp{CommonCallbackResp: cbApi.CommonCallbackResp{}} + //utils.CopyStructFields(req, msg.MsgData) + defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp) + if err := http.PostReturn(config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackAfterSendSingleMsg.CallbackTimeOut); err != nil { + return err + } + return nil +} + +func callbackBeforeSendGroupMsg(msg *pbChat.SendMsgReq) (canSend bool, err error) { + if !config.Config.Callback.CallbackBeforeSendGroupMsg.Enable { + return true, nil + } + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg) + commonCallbackReq := copyCallbackCommonReqStruct(msg) + commonCallbackReq.CallbackCommand = constant.CallbackBeforeSendGroupMsgCommand + req := cbApi.CallbackAfterSendGroupMsgReq{ + CommonCallbackReq: commonCallbackReq, + GroupID: msg.MsgData.GroupID, + } + resp := &cbApi.CallbackBeforeSendGroupMsgResp{CommonCallbackResp: cbApi.CommonCallbackResp{}} + //utils.CopyStructFields(req, msg.MsgData) + defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp) + if err := http.PostReturn(config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg.CallbackTimeOut); err != nil { + if !config.Config.Callback.CallbackBeforeSendGroupMsg.CallbackFailedContinue { + return false, err + } else { + return true, err + } + } else { + if resp.ActionCode == constant.ActionForbidden && resp.ErrCode == constant.CallbackHandleSuccess { + return false, nil + } + } + return true, err +} + +func callbackAfterSendGroupMsg(msg *pbChat.SendMsgReq) error { + if !config.Config.Callback.CallbackAfterSendGroupMsg.Enable { + return nil + } + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg) + commonCallbackReq := copyCallbackCommonReqStruct(msg) + commonCallbackReq.CallbackCommand = constant.CallbackAfterSendGroupMsgCommand + req := cbApi.CallbackAfterSendGroupMsgReq{ + CommonCallbackReq: commonCallbackReq, + GroupID: msg.MsgData.GroupID, + } + resp := &cbApi.CallbackAfterSendGroupMsgResp{CommonCallbackResp: cbApi.CommonCallbackResp{}} + + //utils.CopyStructFields(req, msg.MsgData) + defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp) + if err := http.PostReturn(config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackAfterSendGroupMsg.CallbackTimeOut); err != nil { + return err + } + return nil +} + +func callbackWordFilter(msg *pbChat.SendMsgReq) (canSend bool, err error) { + if !config.Config.Callback.CallbackWordFilter.Enable || msg.MsgData.ContentType != constant.Text { + return true, nil + } + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), msg) + commonCallbackReq := copyCallbackCommonReqStruct(msg) + commonCallbackReq.CallbackCommand = constant.CallbackWordFilterCommand + req := cbApi.CallbackWordFilterReq{ + CommonCallbackReq: commonCallbackReq, + } + resp := &cbApi.CallbackWordFilterResp{CommonCallbackResp: cbApi.CommonCallbackResp{}} + //utils.CopyStructFields(&req., msg.MsgData) + defer log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), req, *resp) + if err := http.PostReturn(config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackWordFilter.CallbackTimeOut); err != nil { + if !config.Config.Callback.CallbackWordFilter.CallbackFailedContinue { + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), "callback failed and config disable, stop this operation") + return false, err + } else { + return true, err + } + } else { + if resp.ActionCode == constant.ActionForbidden && resp.ErrCode == constant.CallbackHandleSuccess { + return false, nil + } + if resp.ErrCode == constant.CallbackHandleSuccess { + msg.MsgData.Content = []byte(resp.Content) + } + log.NewDebug(msg.OperationID, utils.GetSelfFuncName(), string(msg.MsgData.Content)) + } + return true, err +} diff --git a/internal/rpc/msg/conversation_notification.go b/internal/rpc/msg/conversation_notification.go new file mode 100644 index 000000000..5c39ea06a --- /dev/null +++ b/internal/rpc/msg/conversation_notification.go @@ -0,0 +1,76 @@ +package msg + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" +) + +func SetConversationNotification(operationID, sendID, recvID string, contentType int, m proto.Message, tips open_im_sdk.TipsComm) { + log.NewInfo(operationID, "args: ", sendID, recvID, contentType, m.String(), tips.String()) + var err error + tips.Detail, err = proto.Marshal(m) + if err != nil { + log.NewError(operationID, "Marshal failed ", err.Error(), m.String()) + return + } + marshaler := jsonpb.Marshaler{ + OrigName: true, + EnumsAsInts: false, + EmitDefaults: false, + } + tips.JsonDetail, _ = marshaler.MarshalToString(m) + var n NotificationMsg + n.SendID = sendID + n.RecvID = recvID + n.ContentType = int32(contentType) + n.SessionType = constant.SingleChatType + n.MsgFrom = constant.SysMsgType + n.OperationID = operationID + n.Content, err = proto.Marshal(&tips) + if err != nil { + log.Error(operationID, utils.GetSelfFuncName(), "Marshal failed ", err.Error(), tips.String()) + return + } + Notification(&n) +} + +// SetPrivate调用 +func ConversationSetPrivateNotification(operationID, sendID, recvID string, isPrivateChat bool) { + log.NewInfo(operationID, utils.GetSelfFuncName()) + conversationSetPrivateTips := &open_im_sdk.ConversationSetPrivateTips{ + RecvID: recvID, + SendID: sendID, + IsPrivate: isPrivateChat, + } + var tips open_im_sdk.TipsComm + var tipsMsg string + //var senderName string + //senderName, err := im_mysql_model.GetUserNameByUserID(sendID) + //if err != nil { + // log.NewError(operationID, utils.GetSelfFuncName(), err.Error()) + // senderName = sendID + //} + if isPrivateChat == true { + tipsMsg = config.Config.Notification.ConversationSetPrivate.DefaultTips.OpenTips + } else { + tipsMsg = config.Config.Notification.ConversationSetPrivate.DefaultTips.CloseTips + } + tips.DefaultTips = tipsMsg + SetConversationNotification(operationID, sendID, recvID, constant.ConversationPrivateChatNotification, conversationSetPrivateTips, tips) +} + +// 会话改变 +func ConversationChangeNotification(operationID, userID string) { + log.NewInfo(operationID, utils.GetSelfFuncName()) + ConversationChangedTips := &open_im_sdk.ConversationUpdateTips{ + UserID: userID, + } + var tips open_im_sdk.TipsComm + tips.DefaultTips = config.Config.Notification.ConversationOptUpdate.DefaultTips.Tips + SetConversationNotification(operationID, userID, userID, constant.ConversationOptChangeNotification, ConversationChangedTips, tips) +} diff --git a/internal/rpc/msg/del_msg.go b/internal/rpc/msg/del_msg.go new file mode 100644 index 000000000..daacb8533 --- /dev/null +++ b/internal/rpc/msg/del_msg.go @@ -0,0 +1,23 @@ +package msg + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + commonPb "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" +) + +func (rpc *rpcChat) DelMsgList(_ context.Context, req *commonPb.DelMsgListReq) (*commonPb.DelMsgListResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &commonPb.DelMsgListResp{} + if err := db.DB.DelMsgLogic(req.UserID, req.SeqList, req.OperationID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelMsg failed", err.Error()) + resp.ErrMsg = constant.ErrDB.ErrMsg + resp.ErrCode = constant.ErrDB.ErrCode + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} diff --git a/internal/rpc/msg/friend_notification.go b/internal/rpc/msg/friend_notification.go new file mode 100644 index 000000000..91d926bf9 --- /dev/null +++ b/internal/rpc/msg/friend_notification.go @@ -0,0 +1,165 @@ +package msg + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + utils2 "Open_IM/pkg/common/utils" + pbFriend "Open_IM/pkg/proto/friend" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" +) + +func getFromToUserNickname(fromUserID, toUserID string) (string, string, error) { + from, err := imdb.GetUserByUserID(fromUserID) + if err != nil { + return "", "", utils.Wrap(err, "") + } + to, err := imdb.GetUserByUserID(toUserID) + if err != nil { + return "", "", utils.Wrap(err, "") + } + return from.Nickname, to.Nickname, nil +} + +func friendNotification(commID *pbFriend.CommID, contentType int32, m proto.Message) { + log.Info(commID.OperationID, utils.GetSelfFuncName(), "args: ", commID, contentType) + var err error + var tips open_im_sdk.TipsComm + tips.Detail, err = proto.Marshal(m) + if err != nil { + log.Error(commID.OperationID, "Marshal failed ", err.Error(), m.String()) + return + } + + marshaler := jsonpb.Marshaler{ + OrigName: true, + EnumsAsInts: false, + EmitDefaults: false, + } + + tips.JsonDetail, _ = marshaler.MarshalToString(m) + + fromUserNickname, toUserNickname, err := getFromToUserNickname(commID.FromUserID, commID.ToUserID) + if err != nil { + log.Error(commID.OperationID, "getFromToUserNickname failed ", err.Error(), commID.FromUserID, commID.ToUserID) + return + } + cn := config.Config.Notification + switch contentType { + case constant.FriendApplicationNotification: + tips.DefaultTips = fromUserNickname + cn.FriendApplication.DefaultTips.Tips + case constant.FriendApplicationApprovedNotification: + tips.DefaultTips = fromUserNickname + cn.FriendApplicationApproved.DefaultTips.Tips + case constant.FriendApplicationRejectedNotification: + tips.DefaultTips = fromUserNickname + cn.FriendApplicationRejected.DefaultTips.Tips + case constant.FriendAddedNotification: + tips.DefaultTips = cn.FriendAdded.DefaultTips.Tips + case constant.FriendDeletedNotification: + tips.DefaultTips = cn.FriendDeleted.DefaultTips.Tips + toUserNickname + case constant.FriendRemarkSetNotification: + tips.DefaultTips = fromUserNickname + cn.FriendRemarkSet.DefaultTips.Tips + case constant.BlackAddedNotification: + tips.DefaultTips = cn.BlackAdded.DefaultTips.Tips + case constant.BlackDeletedNotification: + tips.DefaultTips = cn.BlackDeleted.DefaultTips.Tips + toUserNickname + case constant.UserInfoUpdatedNotification: + tips.DefaultTips = cn.UserInfoUpdated.DefaultTips.Tips + default: + log.Error(commID.OperationID, "contentType failed ", contentType) + return + } + + var n NotificationMsg + n.SendID = commID.FromUserID + n.RecvID = commID.ToUserID + n.ContentType = contentType + n.SessionType = constant.SingleChatType + n.MsgFrom = constant.SysMsgType + n.OperationID = commID.OperationID + n.Content, err = proto.Marshal(&tips) + if err != nil { + log.Error(commID.OperationID, "Marshal failed ", err.Error(), tips.String()) + return + } + Notification(&n) +} + +func FriendApplicationNotification(req *pbFriend.AddFriendReq) { + FriendApplicationTips := open_im_sdk.FriendApplicationTips{FromToUserID: &open_im_sdk.FromToUserID{}} + FriendApplicationTips.FromToUserID.FromUserID = req.CommID.FromUserID + FriendApplicationTips.FromToUserID.ToUserID = req.CommID.ToUserID + friendNotification(req.CommID, constant.FriendApplicationNotification, &FriendApplicationTips) +} + +func FriendApplicationApprovedNotification(req *pbFriend.AddFriendResponseReq) { + FriendApplicationApprovedTips := open_im_sdk.FriendApplicationApprovedTips{FromToUserID: &open_im_sdk.FromToUserID{}} + FriendApplicationApprovedTips.FromToUserID.FromUserID = req.CommID.FromUserID + FriendApplicationApprovedTips.FromToUserID.ToUserID = req.CommID.ToUserID + FriendApplicationApprovedTips.HandleMsg = req.HandleMsg + friendNotification(req.CommID, constant.FriendApplicationApprovedNotification, &FriendApplicationApprovedTips) +} + +func FriendApplicationRejectedNotification(req *pbFriend.AddFriendResponseReq) { + FriendApplicationApprovedTips := open_im_sdk.FriendApplicationApprovedTips{FromToUserID: &open_im_sdk.FromToUserID{}} + FriendApplicationApprovedTips.FromToUserID.FromUserID = req.CommID.FromUserID + FriendApplicationApprovedTips.FromToUserID.ToUserID = req.CommID.ToUserID + FriendApplicationApprovedTips.HandleMsg = req.HandleMsg + friendNotification(req.CommID, constant.FriendApplicationRejectedNotification, &FriendApplicationApprovedTips) +} + +func FriendAddedNotification(operationID, opUserID, fromUserID, toUserID string) { + friendAddedTips := open_im_sdk.FriendAddedTips{Friend: &open_im_sdk.FriendInfo{}, OpUser: &open_im_sdk.PublicUserInfo{}} + user, err := imdb.GetUserByUserID(opUserID) + if err != nil { + log.NewError(operationID, "GetUserByUserID failed ", err.Error(), opUserID) + return + } + utils2.UserDBCopyOpenIMPublicUser(friendAddedTips.OpUser, user) + friend, err := imdb.GetFriendRelationshipFromFriend(fromUserID, toUserID) + if err != nil { + log.NewError(operationID, "GetFriendRelationshipFromFriend failed ", err.Error(), fromUserID, toUserID) + return + } + utils2.FriendDBCopyOpenIM(friendAddedTips.Friend, friend) + commID := pbFriend.CommID{FromUserID: fromUserID, ToUserID: toUserID, OpUserID: opUserID, OperationID: operationID} + friendNotification(&commID, constant.FriendAddedNotification, &friendAddedTips) +} + +func FriendDeletedNotification(req *pbFriend.DeleteFriendReq) { + friendDeletedTips := open_im_sdk.FriendDeletedTips{FromToUserID: &open_im_sdk.FromToUserID{}} + friendDeletedTips.FromToUserID.FromUserID = req.CommID.FromUserID + friendDeletedTips.FromToUserID.ToUserID = req.CommID.ToUserID + friendNotification(req.CommID, constant.FriendDeletedNotification, &friendDeletedTips) +} + +func FriendRemarkSetNotification(operationID, opUserID, fromUserID, toUserID string) { + friendInfoChangedTips := open_im_sdk.FriendInfoChangedTips{FromToUserID: &open_im_sdk.FromToUserID{}} + friendInfoChangedTips.FromToUserID.FromUserID = fromUserID + friendInfoChangedTips.FromToUserID.ToUserID = toUserID + commID := pbFriend.CommID{FromUserID: fromUserID, ToUserID: toUserID, OpUserID: opUserID, OperationID: operationID} + friendNotification(&commID, constant.FriendRemarkSetNotification, &friendInfoChangedTips) +} + +func BlackAddedNotification(req *pbFriend.AddBlacklistReq) { + blackAddedTips := open_im_sdk.BlackAddedTips{FromToUserID: &open_im_sdk.FromToUserID{}} + blackAddedTips.FromToUserID.FromUserID = req.CommID.FromUserID + blackAddedTips.FromToUserID.ToUserID = req.CommID.ToUserID + friendNotification(req.CommID, constant.BlackAddedNotification, &blackAddedTips) +} + +func BlackDeletedNotification(req *pbFriend.RemoveBlacklistReq) { + blackDeletedTips := open_im_sdk.BlackDeletedTips{FromToUserID: &open_im_sdk.FromToUserID{}} + blackDeletedTips.FromToUserID.FromUserID = req.CommID.FromUserID + blackDeletedTips.FromToUserID.ToUserID = req.CommID.ToUserID + friendNotification(req.CommID, constant.BlackDeletedNotification, &blackDeletedTips) +} + +func UserInfoUpdatedNotification(operationID, userID string, needNotifiedUserID string) { + selfInfoUpdatedTips := open_im_sdk.UserInfoUpdatedTips{UserID: userID} + commID := pbFriend.CommID{FromUserID: userID, ToUserID: needNotifiedUserID, OpUserID: userID, OperationID: operationID} + friendNotification(&commID, constant.UserInfoUpdatedNotification, &selfInfoUpdatedTips) +} diff --git a/internal/rpc/msg/group_notification.go b/internal/rpc/msg/group_notification.go new file mode 100644 index 000000000..56052573b --- /dev/null +++ b/internal/rpc/msg/group_notification.go @@ -0,0 +1,508 @@ +package msg + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + utils2 "Open_IM/pkg/common/utils" + pbGroup "Open_IM/pkg/proto/group" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" +) + +//message GroupCreatedTips{ +// GroupInfo Group = 1; +// GroupMemberFullInfo Creator = 2; +// repeated GroupMemberFullInfo MemberList = 3; +// uint64 OperationTime = 4; +//} creator->group + +func setOpUserInfo(opUserID, groupID string, groupMemberInfo *open_im_sdk.GroupMemberFullInfo) error { + if token_verify.IsManagerUserID(opUserID) { + u, err := imdb.GetUserByUserID(opUserID) + if err != nil { + return utils.Wrap(err, "GetUserByUserID failed") + } + utils.CopyStructFields(groupMemberInfo, u) + groupMemberInfo.GroupID = groupID + } else { + u, err := imdb.GetGroupMemberInfoByGroupIDAndUserID(groupID, opUserID) + if err == nil { + if err = utils2.GroupMemberDBCopyOpenIM(groupMemberInfo, u); err != nil { + return utils.Wrap(err, "") + } + } + + user, err := imdb.GetUserByUserID(opUserID) + if err != nil { + return utils.Wrap(err, "") + } + groupMemberInfo.GroupID = groupID + groupMemberInfo.UserID = user.UserID + groupMemberInfo.Nickname = user.Nickname + groupMemberInfo.AppMangerLevel = user.AppMangerLevel + groupMemberInfo.FaceURL = user.FaceURL + } + return nil +} + +func setGroupInfo(groupID string, groupInfo *open_im_sdk.GroupInfo) error { + group, err := imdb.GetGroupInfoByGroupID(groupID) + if err != nil { + return utils.Wrap(err, "GetGroupInfoByGroupID failed") + } + err = utils2.GroupDBCopyOpenIM(groupInfo, group) + if err != nil { + return utils.Wrap(err, "GetGroupMemberNumByGroupID failed") + } + return nil +} + +func setGroupMemberInfo(groupID, userID string, groupMemberInfo *open_im_sdk.GroupMemberFullInfo) error { + groupMember, err := imdb.GetGroupMemberInfoByGroupIDAndUserID(groupID, userID) + if err == nil { + return utils.Wrap(utils2.GroupMemberDBCopyOpenIM(groupMemberInfo, groupMember), "") + } + + user, err := imdb.GetUserByUserID(userID) + if err != nil { + return utils.Wrap(err, "") + } + groupMemberInfo.GroupID = groupID + groupMemberInfo.UserID = user.UserID + groupMemberInfo.Nickname = user.Nickname + groupMemberInfo.AppMangerLevel = user.AppMangerLevel + groupMemberInfo.FaceURL = user.FaceURL + return nil +} + +func setGroupOwnerInfo(groupID string, groupMemberInfo *open_im_sdk.GroupMemberFullInfo) error { + groupMember, err := imdb.GetGroupOwnerInfoByGroupID(groupID) + if err != nil { + return utils.Wrap(err, "") + } + if err = utils2.GroupMemberDBCopyOpenIM(groupMemberInfo, groupMember); err != nil { + return utils.Wrap(err, "") + } + return nil +} + +func setPublicUserInfo(userID string, publicUserInfo *open_im_sdk.PublicUserInfo) error { + user, err := imdb.GetUserByUserID(userID) + if err != nil { + return utils.Wrap(err, "") + } + utils2.UserDBCopyOpenIMPublicUser(publicUserInfo, user) + return nil +} + +func groupNotification(contentType int32, m proto.Message, sendID, groupID, recvUserID, operationID string) { + log.Info(operationID, utils.GetSelfFuncName(), "args: ", contentType) + + var err error + var tips open_im_sdk.TipsComm + tips.Detail, err = proto.Marshal(m) + if err != nil { + log.Error(operationID, "Marshal failed ", err.Error(), m.String()) + return + } + marshaler := jsonpb.Marshaler{ + OrigName: true, + EnumsAsInts: false, + EmitDefaults: false, + } + + tips.JsonDetail, _ = marshaler.MarshalToString(m) + + from, err := imdb.GetUserByUserID(sendID) + if err != nil { + log.Error(operationID, "GetUserByUserID failed ", err.Error(), sendID) + } + nickname := "" + if from != nil { + nickname = from.Nickname + } + + to, err := imdb.GetUserByUserID(recvUserID) + if err != nil { + log.Error(operationID, "GetUserByUserID failed ", err.Error(), recvUserID) + } + toNickname := "" + if to != nil { + toNickname = to.Nickname + } + + cn := config.Config.Notification + switch contentType { + case constant.GroupCreatedNotification: + tips.DefaultTips = nickname + " " + cn.GroupCreated.DefaultTips.Tips + case constant.GroupInfoSetNotification: + tips.DefaultTips = nickname + " " + cn.GroupInfoSet.DefaultTips.Tips + case constant.JoinGroupApplicationNotification: + tips.DefaultTips = nickname + " " + cn.JoinGroupApplication.DefaultTips.Tips + case constant.MemberQuitNotification: + tips.DefaultTips = nickname + " " + cn.MemberQuit.DefaultTips.Tips + case constant.GroupApplicationAcceptedNotification: // + tips.DefaultTips = toNickname + " " + cn.GroupApplicationAccepted.DefaultTips.Tips + case constant.GroupApplicationRejectedNotification: // + tips.DefaultTips = toNickname + " " + cn.GroupApplicationRejected.DefaultTips.Tips + case constant.GroupOwnerTransferredNotification: // + tips.DefaultTips = toNickname + " " + cn.GroupOwnerTransferred.DefaultTips.Tips + case constant.MemberKickedNotification: // + tips.DefaultTips = toNickname + " " + cn.MemberKicked.DefaultTips.Tips + case constant.MemberInvitedNotification: // + tips.DefaultTips = toNickname + " " + cn.MemberInvited.DefaultTips.Tips + case constant.MemberEnterNotification: + tips.DefaultTips = toNickname + " " + cn.MemberEnter.DefaultTips.Tips + case constant.GroupDismissedNotification: + tips.DefaultTips = toNickname + "" + cn.GroupDismissed.DefaultTips.Tips + case constant.GroupMutedNotification: + tips.DefaultTips = toNickname + "" + cn.GroupMuted.DefaultTips.Tips + case constant.GroupCancelMutedNotification: + tips.DefaultTips = toNickname + "" + cn.GroupCancelMuted.DefaultTips.Tips + case constant.GroupMemberMutedNotification: + tips.DefaultTips = toNickname + "" + cn.GroupMemberMuted.DefaultTips.Tips + case constant.GroupMemberCancelMutedNotification: + tips.DefaultTips = toNickname + "" + cn.GroupMemberCancelMuted.DefaultTips.Tips + default: + log.Error(operationID, "contentType failed ", contentType) + return + } + + var n NotificationMsg + n.SendID = sendID + if groupID != "" { + n.RecvID = groupID + n.SessionType = constant.GroupChatType + } else { + n.RecvID = recvUserID + n.SessionType = constant.SingleChatType + } + n.ContentType = contentType + n.OperationID = operationID + n.Content, err = proto.Marshal(&tips) + if err != nil { + log.Error(operationID, "Marshal failed ", err.Error(), tips.String()) + return + } + Notification(&n) +} + +//创建群后调用 +func GroupCreatedNotification(operationID, opUserID, groupID string, initMemberList []string) { + GroupCreatedTips := open_im_sdk.GroupCreatedTips{Group: &open_im_sdk.GroupInfo{}, + OpUser: &open_im_sdk.GroupMemberFullInfo{}, GroupOwnerUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setOpUserInfo(opUserID, groupID, GroupCreatedTips.OpUser); err != nil { + log.NewError(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID, GroupCreatedTips.OpUser) + return + } + err := setGroupInfo(groupID, GroupCreatedTips.Group) + if err != nil { + log.Error(operationID, "setGroupInfo failed ", groupID, GroupCreatedTips.Group) + return + } + imdb.GetGroupOwnerInfoByGroupID(groupID) + if err := setGroupOwnerInfo(groupID, GroupCreatedTips.GroupOwnerUser); err != nil { + log.Error(operationID, "setGroupOwnerInfo failed", err.Error(), groupID) + return + } + for _, v := range initMemberList { + var groupMemberInfo open_im_sdk.GroupMemberFullInfo + if err := setGroupMemberInfo(groupID, v, &groupMemberInfo); err != nil { + log.Error(operationID, "setGroupMemberInfo failed ", err.Error(), groupID, v) + continue + } + GroupCreatedTips.MemberList = append(GroupCreatedTips.MemberList, &groupMemberInfo) + } + groupNotification(constant.GroupCreatedNotification, &GroupCreatedTips, opUserID, groupID, "", operationID) +} + +//群信息改变后掉用 +func GroupInfoSetNotification(operationID, opUserID, groupID string) { + GroupInfoChangedTips := open_im_sdk.GroupInfoSetTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(groupID, GroupInfoChangedTips.Group); err != nil { + log.Error(operationID, "setGroupInfo failed ", err.Error(), groupID) + return + } + if err := setOpUserInfo(opUserID, groupID, GroupInfoChangedTips.OpUser); err != nil { + log.Error(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID) + return + } + groupNotification(constant.GroupInfoSetNotification, &GroupInfoChangedTips, opUserID, groupID, "", operationID) +} + +func GroupMutedNotification(operationID, opUserID, groupID string) { + tips := open_im_sdk.GroupMutedTips{Group: &open_im_sdk.GroupInfo{}, + OpUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(groupID, tips.Group); err != nil { + log.Error(operationID, "setGroupInfo failed ", err.Error(), groupID) + return + } + if err := setOpUserInfo(opUserID, groupID, tips.OpUser); err != nil { + log.Error(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID) + return + } + groupNotification(constant.GroupMutedNotification, &tips, opUserID, groupID, "", operationID) +} + +func GroupCancelMutedNotification(operationID, opUserID, groupID string) { + tips := open_im_sdk.GroupCancelMutedTips{Group: &open_im_sdk.GroupInfo{}, + OpUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(groupID, tips.Group); err != nil { + log.Error(operationID, "setGroupInfo failed ", err.Error(), groupID) + return + } + if err := setOpUserInfo(opUserID, groupID, tips.OpUser); err != nil { + log.Error(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID) + return + } + groupNotification(constant.GroupCancelMutedNotification, &tips, opUserID, groupID, "", operationID) +} + +func GroupMemberMutedNotification(operationID, opUserID, groupID, groupMemberUserID string, mutedSeconds uint32) { + tips := open_im_sdk.GroupMemberMutedTips{Group: &open_im_sdk.GroupInfo{}, + OpUser: &open_im_sdk.GroupMemberFullInfo{}, MutedUser: &open_im_sdk.GroupMemberFullInfo{}} + tips.MutedSeconds = mutedSeconds + if err := setGroupInfo(groupID, tips.Group); err != nil { + log.Error(operationID, "setGroupInfo failed ", err.Error(), groupID) + return + } + if err := setOpUserInfo(opUserID, groupID, tips.OpUser); err != nil { + log.Error(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID) + return + } + if err := setGroupMemberInfo(groupID, groupMemberUserID, tips.MutedUser); err != nil { + log.Error(operationID, "setGroupMemberInfo failed ", err.Error(), groupID, groupMemberUserID) + return + } + groupNotification(constant.GroupMemberMutedNotification, &tips, opUserID, groupID, "", operationID) +} + +func GroupMemberCancelMutedNotification(operationID, opUserID, groupID, groupMemberUserID string) { + tips := open_im_sdk.GroupMemberCancelMutedTips{Group: &open_im_sdk.GroupInfo{}, + OpUser: &open_im_sdk.GroupMemberFullInfo{}, MutedUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(groupID, tips.Group); err != nil { + log.Error(operationID, "setGroupInfo failed ", err.Error(), groupID) + return + } + if err := setOpUserInfo(opUserID, groupID, tips.OpUser); err != nil { + log.Error(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID) + return + } + if err := setGroupMemberInfo(groupID, groupMemberUserID, tips.MutedUser); err != nil { + log.Error(operationID, "setGroupMemberInfo failed ", err.Error(), groupID, groupMemberUserID) + return + } + groupNotification(constant.GroupMemberCancelMutedNotification, &tips, opUserID, groupID, "", operationID) +} + +//message ReceiveJoinApplicationTips{ +// GroupInfo Group = 1; +// PublicUserInfo Applicant = 2; +// string Reason = 3; +//} apply->all managers GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` +// ReqMessage string `protobuf:"bytes,2,opt,name=ReqMessage" json:"ReqMessage,omitempty"` +// OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` +// OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` +//申请进群后调用 +func JoinGroupApplicationNotification(req *pbGroup.JoinGroupReq) { + JoinGroupApplicationTips := open_im_sdk.JoinGroupApplicationTips{Group: &open_im_sdk.GroupInfo{}, Applicant: &open_im_sdk.PublicUserInfo{}} + err := setGroupInfo(req.GroupID, JoinGroupApplicationTips.Group) + if err != nil { + log.Error(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID) + return + } + if err = setPublicUserInfo(req.OpUserID, JoinGroupApplicationTips.Applicant); err != nil { + log.Error(req.OperationID, "setPublicUserInfo failed ", err.Error(), req.OpUserID) + return + } + JoinGroupApplicationTips.ReqMsg = req.ReqMessage + + managerList, err := imdb.GetOwnerManagerByGroupID(req.GroupID) + if err != nil { + log.NewError(req.OperationID, "GetOwnerManagerByGroupId failed ", err.Error(), req.GroupID) + return + } + for _, v := range managerList { + groupNotification(constant.JoinGroupApplicationNotification, &JoinGroupApplicationTips, req.OpUserID, "", v.UserID, req.OperationID) + log.NewInfo(req.OperationID, "Notification ", v) + } +} + +func MemberQuitNotification(req *pbGroup.QuitGroupReq) { + MemberQuitTips := open_im_sdk.MemberQuitTips{Group: &open_im_sdk.GroupInfo{}, QuitUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(req.GroupID, MemberQuitTips.Group); err != nil { + log.Error(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID) + return + } + if err := setOpUserInfo(req.OpUserID, req.GroupID, MemberQuitTips.QuitUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed ", err.Error(), req.OpUserID, req.GroupID) + return + } + + groupNotification(constant.MemberQuitNotification, &MemberQuitTips, req.OpUserID, req.GroupID, "", req.OperationID) + // groupNotification(constant.MemberQuitNotification, &MemberQuitTips, req.OpUserID, "", req.OpUserID, req.OperationID) + +} + +//message ApplicationProcessedTips{ +// GroupInfo Group = 1; +// GroupMemberFullInfo OpUser = 2; +// int32 Result = 3; +// string Reason = 4; +//} +//处理进群请求后调用 +func GroupApplicationAcceptedNotification(req *pbGroup.GroupApplicationResponseReq) { + GroupApplicationAcceptedTips := open_im_sdk.GroupApplicationAcceptedTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}, HandleMsg: req.HandledMsg} + if err := setGroupInfo(req.GroupID, GroupApplicationAcceptedTips.Group); err != nil { + log.NewError(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID, GroupApplicationAcceptedTips.Group) + return + } + if err := setOpUserInfo(req.OpUserID, req.GroupID, GroupApplicationAcceptedTips.OpUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed", req.OpUserID, req.GroupID, GroupApplicationAcceptedTips.OpUser) + return + } + groupNotification(constant.GroupApplicationAcceptedNotification, &GroupApplicationAcceptedTips, req.OpUserID, "", req.FromUserID, req.OperationID) +} + +func GroupApplicationRejectedNotification(req *pbGroup.GroupApplicationResponseReq) { + GroupApplicationRejectedTips := open_im_sdk.GroupApplicationRejectedTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}, HandleMsg: req.HandledMsg} + if err := setGroupInfo(req.GroupID, GroupApplicationRejectedTips.Group); err != nil { + log.NewError(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID, GroupApplicationRejectedTips.Group) + return + } + if err := setOpUserInfo(req.OpUserID, req.GroupID, GroupApplicationRejectedTips.OpUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed", req.OpUserID, req.GroupID, GroupApplicationRejectedTips.OpUser) + return + } + groupNotification(constant.GroupApplicationRejectedNotification, &GroupApplicationRejectedTips, req.OpUserID, "", req.FromUserID, req.OperationID) +} + +func GroupOwnerTransferredNotification(req *pbGroup.TransferGroupOwnerReq) { + GroupOwnerTransferredTips := open_im_sdk.GroupOwnerTransferredTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}, NewGroupOwner: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(req.GroupID, GroupOwnerTransferredTips.Group); err != nil { + log.NewError(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID) + return + } + if err := setOpUserInfo(req.OpUserID, req.GroupID, GroupOwnerTransferredTips.OpUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed", req.OpUserID, req.GroupID) + return + } + if err := setGroupMemberInfo(req.GroupID, req.NewOwnerUserID, GroupOwnerTransferredTips.NewGroupOwner); err != nil { + log.Error(req.OperationID, "setGroupMemberInfo failed", req.GroupID, req.NewOwnerUserID) + return + } + groupNotification(constant.GroupOwnerTransferredNotification, &GroupOwnerTransferredTips, req.OpUserID, req.GroupID, "", req.OperationID) +} + +func GroupDismissedNotification(req *pbGroup.DismissGroupReq) { + tips := open_im_sdk.GroupDismissedTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(req.GroupID, tips.Group); err != nil { + log.NewError(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID) + return + } + if err := setOpUserInfo(req.OpUserID, req.GroupID, tips.OpUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed", req.OpUserID, req.GroupID) + return + } + groupNotification(constant.GroupDismissedNotification, &tips, req.OpUserID, req.GroupID, "", req.OperationID) +} + +//message MemberKickedTips{ +// GroupInfo Group = 1; +// GroupMemberFullInfo OpUser = 2; +// GroupMemberFullInfo KickedUser = 3; +// uint64 OperationTime = 4; +//} +//被踢后调用 +func MemberKickedNotification(req *pbGroup.KickGroupMemberReq, kickedUserIDList []string) { + MemberKickedTips := open_im_sdk.MemberKickedTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(req.GroupID, MemberKickedTips.Group); err != nil { + log.Error(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID) + return + } + if err := setOpUserInfo(req.OpUserID, req.GroupID, MemberKickedTips.OpUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed ", err.Error(), req.OpUserID) + return + } + for _, v := range kickedUserIDList { + var groupMemberInfo open_im_sdk.GroupMemberFullInfo + if err := setGroupMemberInfo(req.GroupID, v, &groupMemberInfo); err != nil { + log.Error(req.OperationID, "setGroupMemberInfo failed ", err.Error(), req.GroupID, v) + continue + } + MemberKickedTips.KickedUserList = append(MemberKickedTips.KickedUserList, &groupMemberInfo) + } + groupNotification(constant.MemberKickedNotification, &MemberKickedTips, req.OpUserID, req.GroupID, "", req.OperationID) + // + //for _, v := range kickedUserIDList { + // groupNotification(constant.MemberKickedNotification, &MemberKickedTips, req.OpUserID, "", v, req.OperationID) + //} +} + +//message MemberInvitedTips{ +// GroupInfo Group = 1; +// GroupMemberFullInfo OpUser = 2; +// GroupMemberFullInfo InvitedUser = 3; +// uint64 OperationTime = 4; +//} +//被邀请进群后调用 +func MemberInvitedNotification(operationID, groupID, opUserID, reason string, invitedUserIDList []string) { + MemberInvitedTips := open_im_sdk.MemberInvitedTips{Group: &open_im_sdk.GroupInfo{}, OpUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(groupID, MemberInvitedTips.Group); err != nil { + log.Error(operationID, "setGroupInfo failed ", err.Error(), groupID) + return + } + if err := setOpUserInfo(opUserID, groupID, MemberInvitedTips.OpUser); err != nil { + log.Error(operationID, "setOpUserInfo failed ", err.Error(), opUserID, groupID) + return + } + for _, v := range invitedUserIDList { + var groupMemberInfo open_im_sdk.GroupMemberFullInfo + if err := setGroupMemberInfo(groupID, v, &groupMemberInfo); err != nil { + log.Error(operationID, "setGroupMemberInfo failed ", err.Error(), groupID) + continue + } + MemberInvitedTips.InvitedUserList = append(MemberInvitedTips.InvitedUserList, &groupMemberInfo) + } + + groupNotification(constant.MemberInvitedNotification, &MemberInvitedTips, opUserID, groupID, "", operationID) +} + +//message GroupInfoChangedTips{ +// int32 ChangedType = 1; //bitwise operators: 1:groupName; 10:Notification 100:Introduction; 1000:FaceUrl +// GroupInfo Group = 2; +// GroupMemberFullInfo OpUser = 3; +//} + +//message MemberLeaveTips{ +// GroupInfo Group = 1; +// GroupMemberFullInfo LeaverUser = 2; +// uint64 OperationTime = 3; +//} + +//群成员退群后调用 + +//message MemberEnterTips{ +// GroupInfo Group = 1; +// GroupMemberFullInfo EntrantUser = 2; +// uint64 OperationTime = 3; +//} +//群成员主动申请进群,管理员同意后调用, +func MemberEnterNotification(req *pbGroup.GroupApplicationResponseReq) { + MemberEnterTips := open_im_sdk.MemberEnterTips{Group: &open_im_sdk.GroupInfo{}, EntrantUser: &open_im_sdk.GroupMemberFullInfo{}} + if err := setGroupInfo(req.GroupID, MemberEnterTips.Group); err != nil { + log.Error(req.OperationID, "setGroupInfo failed ", err.Error(), req.GroupID, MemberEnterTips.Group) + return + } + if err := setGroupMemberInfo(req.GroupID, req.FromUserID, MemberEnterTips.EntrantUser); err != nil { + log.Error(req.OperationID, "setOpUserInfo failed ", err.Error(), req.OpUserID, req.GroupID, MemberEnterTips.EntrantUser) + return + } + groupNotification(constant.MemberEnterNotification, &MemberEnterTips, req.OpUserID, req.GroupID, "", req.OperationID) + +} diff --git a/internal/rpc/msg/pull_message.go b/internal/rpc/msg/pull_message.go new file mode 100644 index 000000000..10a0978aa --- /dev/null +++ b/internal/rpc/msg/pull_message.go @@ -0,0 +1,74 @@ +package msg + +import ( + "context" + "github.com/garyburd/redigo/redis" + + commonDB "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + pbMsg "Open_IM/pkg/proto/chat" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" +) + +func (rpc *rpcChat) GetMaxAndMinSeq(_ context.Context, in *pbMsg.GetMaxAndMinSeqReq) (*pbMsg.GetMaxAndMinSeqResp, error) { + log.InfoByKv("rpc getMaxAndMinSeq is arriving", in.OperationID, in.String()) + //seq, err := model.GetBiggestSeqFromReceive(in.UserID) + maxSeq, err1 := commonDB.DB.GetUserMaxSeq(in.UserID) + minSeq, err2 := commonDB.DB.GetUserMinSeq(in.UserID) + resp := new(pbMsg.GetMaxAndMinSeqResp) + if err1 == nil { + resp.MaxSeq = uint32(maxSeq) + } else if err1 == redis.ErrNil { + resp.MaxSeq = 0 + } else { + log.NewError(in.OperationID, "getMaxSeq from redis error", in.String(), err1.Error()) + resp.ErrCode = 200 + resp.ErrMsg = "redis get err" + } + if err2 == nil { + resp.MinSeq = uint32(minSeq) + } else if err2 == redis.ErrNil { + resp.MinSeq = 0 + } else { + log.NewError(in.OperationID, "getMaxSeq from redis error", in.String(), err2.Error()) + resp.ErrCode = 201 + resp.ErrMsg = "redis get err" + } + return resp, nil +} +func (rpc *rpcChat) PullMessageBySeqList(_ context.Context, in *open_im_sdk.PullMessageBySeqListReq) (*open_im_sdk.PullMessageBySeqListResp, error) { + log.NewInfo(in.OperationID, "rpc PullMessageBySeqList is arriving", in.String()) + resp := new(open_im_sdk.PullMessageBySeqListResp) + //msgList, err := commonDB.DB.GetMsgBySeqList(in.UserID, in.SeqList, in.OperationID) + msgList, err := commonDB.DB.GetMsgBySeqListMongo2(in.UserID, in.SeqList, in.OperationID) + if err != nil { + log.ErrorByKv("PullMessageBySeqList data error", in.OperationID, in.String()) + resp.ErrCode = 201 + resp.ErrMsg = err.Error() + return resp, nil + } + //respSingleMsgFormat = singleMsgHandleByUser(SingleMsgFormat, in.UserID) + //respGroupMsgFormat = groupMsgHandleByUser(GroupMsgFormat) + resp.ErrCode = 0 + resp.ErrMsg = "" + resp.List = msgList + return resp, nil + +} + +type MsgFormats []*open_im_sdk.MsgData + +// Implement the sort.Interface interface to get the number of elements method +func (s MsgFormats) Len() int { + return len(s) +} + +//Implement the sort.Interface interface comparison element method +func (s MsgFormats) Less(i, j int) bool { + return s[i].SendTime < s[j].SendTime +} + +//Implement the sort.Interface interface exchange element method +func (s MsgFormats) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} diff --git a/internal/rpc/msg/rpcChat.go b/internal/rpc/msg/rpcChat.go new file mode 100644 index 000000000..82c4ad37b --- /dev/null +++ b/internal/rpc/msg/rpcChat.go @@ -0,0 +1,67 @@ +package msg + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/kafka" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbChat "Open_IM/pkg/proto/chat" + "Open_IM/pkg/utils" + "google.golang.org/grpc" + "net" + "strconv" + "strings" +) + +type rpcChat struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string + producer *kafka.Producer +} + +func NewRpcChatServer(port int) *rpcChat { + log.NewPrivateLog(constant.LogFileName) + rc := rpcChat{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImOfflineMessageName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } + rc.producer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.Ws2mschat.Topic) + return &rc +} + +func (rpc *rpcChat) Run() { + log.Info("", "", "rpc get_token init...") + + address := utils.ServerIP + ":" + strconv.Itoa(rpc.rpcPort) + listener, err := net.Listen("tcp", address) + if err != nil { + log.Error("", "", "listen network failed, err = %s, address = %s", err.Error(), address) + return + } + log.Info("", "", "listen network success, address = ", address) + + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + + //service registers with etcd + + pbChat.RegisterChatServer(srv, rpc) + err = getcdv3.RegisterEtcd(rpc.etcdSchema, strings.Join(rpc.etcdAddr, ","), utils.ServerIP, rpc.rpcPort, rpc.rpcRegisterName, 10) + if err != nil { + log.Error("", "", "register rpc get_token to etcd failed, err = %s", err.Error()) + return + } + + err = srv.Serve(listener) + if err != nil { + log.Info("", "", "rpc get_token fail, err = %s", err.Error()) + return + } + log.Info("", "", "rpc get_token init success") +} diff --git a/internal/rpc/msg/send_msg.go b/internal/rpc/msg/send_msg.go new file mode 100644 index 000000000..c84549f6c --- /dev/null +++ b/internal/rpc/msg/send_msg.go @@ -0,0 +1,593 @@ +package msg + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbChat "Open_IM/pkg/proto/chat" + rpc "Open_IM/pkg/proto/friend" + pbGroup "Open_IM/pkg/proto/group" + sdk_ws "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "github.com/garyburd/redigo/redis" + "github.com/golang/protobuf/proto" + "math/rand" + "strconv" + "strings" + "time" +) + +type MsgCallBackReq struct { + SendID string `json:"sendID"` + RecvID string `json:"recvID"` + Content string `json:"content"` + SendTime int64 `json:"sendTime"` + MsgFrom int32 `json:"msgFrom"` + ContentType int32 `json:"contentType"` + SessionType int32 `json:"sessionType"` + PlatformID int32 `json:"senderPlatformID"` + MsgID string `json:"msgID"` + IsOnlineOnly bool `json:"isOnlineOnly"` +} +type MsgCallBackResp struct { + ErrCode int32 `json:"errCode"` + ErrMsg string `json:"errMsg"` + ResponseErrCode int32 `json:"responseErrCode"` + ResponseResult struct { + ModifiedMsg string `json:"modifiedMsg"` + Ext string `json:"ext"` + } +} + +func userRelationshipVerification(data *pbChat.SendMsgReq) (bool, int32, string) { + if data.MsgData.SessionType == constant.GroupChatType { + return true, 0, "" + } + log.NewDebug(data.OperationID, config.Config.MessageVerify.FriendVerify) + req := &rpc.IsInBlackListReq{CommID: &rpc.CommID{}} + req.CommID.OperationID = data.OperationID + req.CommID.OpUserID = data.MsgData.RecvID + req.CommID.FromUserID = data.MsgData.RecvID + req.CommID.ToUserID = data.MsgData.SendID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := rpc.NewFriendClient(etcdConn) + reply, err := client.IsInBlackList(context.Background(), req) + if err != nil { + log.NewDebug(data.OperationID, "IsInBlackListReq rpc failed, ", req.String(), err.Error()) + } else if reply.Response == true { + log.NewDebug(data.OperationID, "IsInBlackListReq ", req.String()) + return false, 600, "in black list" + } + log.NewDebug(data.OperationID, config.Config.MessageVerify.FriendVerify) + if config.Config.MessageVerify.FriendVerify { + friendReq := &rpc.IsFriendReq{CommID: &rpc.CommID{}} + friendReq.CommID.OperationID = data.OperationID + friendReq.CommID.OpUserID = data.MsgData.RecvID + friendReq.CommID.FromUserID = data.MsgData.RecvID + friendReq.CommID.ToUserID = data.MsgData.SendID + friendReply, err := client.IsFriend(context.Background(), friendReq) + if err != nil { + log.NewDebug(data.OperationID, "IsFriendReq rpc failed, ", req.String(), err.Error()) + return true, 0, "" + } else if friendReply.Response == false { + log.NewDebug(data.OperationID, "not friend ", req.String()) + return friendReply.Response, 601, "not friend" + } + log.NewDebug(data.OperationID, config.Config.MessageVerify.FriendVerify, friendReply.Response) + return true, 0, "" + } else { + return true, 0, "" + } +} +func (rpc *rpcChat) encapsulateMsgData(msg *sdk_ws.MsgData) { + msg.ServerMsgID = GetMsgID(msg.SendID) + msg.SendTime = utils.GetCurrentTimestampByMill() + switch msg.ContentType { + case constant.Text: + fallthrough + case constant.Picture: + fallthrough + case constant.Voice: + fallthrough + case constant.Video: + fallthrough + case constant.File: + fallthrough + case constant.AtText: + fallthrough + case constant.Merger: + fallthrough + case constant.Card: + fallthrough + case constant.Location: + fallthrough + case constant.Custom: + fallthrough + case constant.Quote: + utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, true) + utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, true) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, true) + case constant.Revoke: + utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) + case constant.HasReadReceipt: + log.Info("", "this is a test start", msg, msg.Options) + utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) + log.Info("", "this is a test end", msg, msg.Options) + case constant.Typing: + utils.SetSwitchFromOptions(msg.Options, constant.IsHistory, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsPersistent, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderSync, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) + + } +} +func (rpc *rpcChat) SendMsg(_ context.Context, pb *pbChat.SendMsgReq) (*pbChat.SendMsgResp, error) { + replay := pbChat.SendMsgResp{} + log.NewDebug(pb.OperationID, "rpc sendMsg come here", pb.String()) + flag, errCode, errMsg := userRelationshipVerification(pb) + if !flag { + return returnMsg(&replay, pb, errCode, errMsg, "", 0) + } + //if !utils.VerifyToken(pb.Token, pb.SendID) { + // return returnMsg(&replay, pb, http.StatusUnauthorized, "token validate err,not authorized", "", 0) + rpc.encapsulateMsgData(pb.MsgData) + log.Info("", "this is a test MsgData ", pb.MsgData) + msgToMQ := pbChat.MsgDataToMQ{Token: pb.Token, OperationID: pb.OperationID, MsgData: pb.MsgData} + //options := utils.JsonStringToMap(pbData.Options) + isHistory := utils.GetSwitchFromOptions(pb.MsgData.Options, constant.IsHistory) + mReq := MsgCallBackReq{ + SendID: pb.MsgData.SendID, + RecvID: pb.MsgData.RecvID, + Content: string(pb.MsgData.Content), + SendTime: pb.MsgData.SendTime, + MsgFrom: pb.MsgData.MsgFrom, + ContentType: pb.MsgData.ContentType, + SessionType: pb.MsgData.SessionType, + PlatformID: pb.MsgData.SenderPlatformID, + MsgID: pb.MsgData.ClientMsgID, + } + if !isHistory { + mReq.IsOnlineOnly = true + } + + // callback + canSend, err := callbackWordFilter(pb) + if err != nil { + log.NewError(pb.OperationID, utils.GetSelfFuncName(), "callbackWordFilter failed", err.Error(), pb.MsgData) + } + if !canSend { + log.NewDebug(pb.OperationID, utils.GetSelfFuncName(), "callbackWordFilter result", canSend, "end rpc and return", pb.MsgData) + return returnMsg(&replay, pb, 201, "callbackWordFilter result stop rpc and return", "", 0) + } + switch pb.MsgData.SessionType { + case constant.SingleChatType: + // callback + canSend, err := callbackBeforeSendSingleMsg(pb) + if err != nil { + log.NewError(pb.OperationID, utils.GetSelfFuncName(), "callbackBeforeSendSingleMsg failed", err.Error()) + } + if !canSend { + log.NewDebug(pb.OperationID, utils.GetSelfFuncName(), "callbackBeforeSendSingleMsg result", canSend, "end rpc and return") + return returnMsg(&replay, pb, 201, "callbackBeforeSendSingleMsg result stop rpc and return", "", 0) + } + isSend := modifyMessageByUserMessageReceiveOpt(pb.MsgData.RecvID, pb.MsgData.SendID, constant.SingleChatType, pb) + if isSend { + msgToMQ.MsgData = pb.MsgData + log.NewInfo(msgToMQ.OperationID, msgToMQ) + err1 := rpc.sendMsgToKafka(&msgToMQ, msgToMQ.MsgData.RecvID) + if err1 != nil { + log.NewError(msgToMQ.OperationID, "kafka send msg err:RecvID", msgToMQ.MsgData.RecvID, msgToMQ.String()) + return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0) + } + } + if msgToMQ.MsgData.SendID != msgToMQ.MsgData.RecvID { //Filter messages sent to yourself + err2 := rpc.sendMsgToKafka(&msgToMQ, msgToMQ.MsgData.SendID) + if err2 != nil { + log.NewError(msgToMQ.OperationID, "kafka send msg err:SendID", msgToMQ.MsgData.SendID, msgToMQ.String()) + return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0) + } + } + // callback + if err := callbackAfterSendSingleMsg(pb); err != nil { + log.NewError(pb.OperationID, utils.GetSelfFuncName(), "callbackAfterSendSingleMsg failed", err.Error()) + } + return returnMsg(&replay, pb, 0, "", msgToMQ.MsgData.ServerMsgID, msgToMQ.MsgData.SendTime) + case constant.GroupChatType: + // callback + canSend, err := callbackBeforeSendGroupMsg(pb) + if err != nil { + log.NewError(pb.OperationID, utils.GetSelfFuncName(), "callbackBeforeSendGroupMsg failed", err.Error()) + } + if !canSend { + log.NewDebug(pb.OperationID, utils.GetSelfFuncName(), "callbackBeforeSendGroupMsg result", canSend, "end rpc and return") + return returnMsg(&replay, pb, 201, "callbackBeforeSendGroupMsg result stop rpc and return", "", 0) + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImGroupName) + client := pbGroup.NewGroupClient(etcdConn) + req := &pbGroup.GetGroupAllMemberReq{ + GroupID: pb.MsgData.GroupID, + OperationID: pb.OperationID, + } + reply, err := client.GetGroupAllMember(context.Background(), req) + if err != nil { + log.Error(pb.Token, pb.OperationID, "rpc send_msg getGroupInfo failed, err = %s", err.Error()) + return returnMsg(&replay, pb, 201, err.Error(), "", 0) + } + if reply.ErrCode != 0 { + log.Error(pb.Token, pb.OperationID, "rpc send_msg getGroupInfo failed, err = %s", reply.ErrMsg) + return returnMsg(&replay, pb, reply.ErrCode, reply.ErrMsg, "", 0) + } + var addUidList []string + switch pb.MsgData.ContentType { + case constant.MemberKickedNotification: + var tips sdk_ws.TipsComm + var memberKickedTips sdk_ws.MemberKickedTips + err := proto.Unmarshal(pb.MsgData.Content, &tips) + if err != nil { + log.Error(pb.OperationID, "Unmarshal err", err.Error()) + } + err = proto.Unmarshal(tips.Detail, &memberKickedTips) + if err != nil { + log.Error(pb.OperationID, "Unmarshal err", err.Error()) + } + log.Info(pb.OperationID, "data is ", memberKickedTips) + for _, v := range memberKickedTips.KickedUserList { + addUidList = append(addUidList, v.UserID) + } + case constant.MemberQuitNotification: + addUidList = append(addUidList, pb.MsgData.SendID) + default: + } + groupID := pb.MsgData.GroupID + for _, v := range reply.MemberList { + pb.MsgData.RecvID = v.UserID + isSend := modifyMessageByUserMessageReceiveOpt(v.UserID, groupID, constant.GroupChatType, pb) + if isSend { + msgToMQ.MsgData = pb.MsgData + err := rpc.sendMsgToKafka(&msgToMQ, v.UserID) + if err != nil { + log.NewError(msgToMQ.OperationID, "kafka send msg err:UserId", v.UserID, msgToMQ.String()) + return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0) + } + } + + } + log.Info(msgToMQ.OperationID, "addUidList", addUidList) + for _, v := range addUidList { + pb.MsgData.RecvID = v + isSend := modifyMessageByUserMessageReceiveOpt(v, groupID, constant.GroupChatType, pb) + log.Info(msgToMQ.OperationID, "isSend", isSend) + if isSend { + msgToMQ.MsgData = pb.MsgData + err := rpc.sendMsgToKafka(&msgToMQ, v) + if err != nil { + log.NewError(msgToMQ.OperationID, "kafka send msg err:UserId", v, msgToMQ.String()) + return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0) + } + } + } + // callback + if err := callbackAfterSendGroupMsg(pb); err != nil { + log.NewError(pb.OperationID, utils.GetSelfFuncName(), "callbackAfterSendGroupMsg failed", err.Error()) + } + return returnMsg(&replay, pb, 0, "", msgToMQ.MsgData.ServerMsgID, msgToMQ.MsgData.SendTime) + case constant.NotificationChatType: + msgToMQ.MsgData = pb.MsgData + log.NewInfo(msgToMQ.OperationID, msgToMQ) + err1 := rpc.sendMsgToKafka(&msgToMQ, msgToMQ.MsgData.RecvID) + if err1 != nil { + log.NewError(msgToMQ.OperationID, "kafka send msg err:RecvID", msgToMQ.MsgData.RecvID, msgToMQ.String()) + return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0) + } + + if msgToMQ.MsgData.SendID != msgToMQ.MsgData.RecvID { //Filter messages sent to yourself + err2 := rpc.sendMsgToKafka(&msgToMQ, msgToMQ.MsgData.SendID) + if err2 != nil { + log.NewError(msgToMQ.OperationID, "kafka send msg err:SendID", msgToMQ.MsgData.SendID, msgToMQ.String()) + return returnMsg(&replay, pb, 201, "kafka send msg err", "", 0) + } + } + return returnMsg(&replay, pb, 0, "", msgToMQ.MsgData.ServerMsgID, msgToMQ.MsgData.SendTime) + default: + return returnMsg(&replay, pb, 203, "unkonwn sessionType", "", 0) + } +} + +func (rpc *rpcChat) sendMsgToKafka(m *pbChat.MsgDataToMQ, key string) error { + pid, offset, err := rpc.producer.SendMessage(m, key) + if err != nil { + log.ErrorByKv("kafka send failed", m.OperationID, "send data", m.String(), "pid", pid, "offset", offset, "err", err.Error(), "key", key) + } + return err +} +func GetMsgID(sendID string) string { + t := time.Now().Format("2006-01-02 15:04:05") + return utils.Md5(t + "-" + sendID + "-" + strconv.Itoa(rand.Int())) +} + +func returnMsg(replay *pbChat.SendMsgResp, pb *pbChat.SendMsgReq, errCode int32, errMsg, serverMsgID string, sendTime int64) (*pbChat.SendMsgResp, error) { + replay.ErrCode = errCode + replay.ErrMsg = errMsg + replay.ServerMsgID = serverMsgID + replay.ClientMsgID = pb.MsgData.ClientMsgID + replay.SendTime = sendTime + return replay, nil +} + +func modifyMessageByUserMessageReceiveOpt(userID, sourceID string, sessionType int, pb *pbChat.SendMsgReq) bool { + conversationID := utils.GetConversationIDBySessionType(sourceID, sessionType) + opt, err := db.DB.GetSingleConversationRecvMsgOpt(userID, conversationID) + if err != nil && err != redis.ErrNil { + log.NewError(pb.OperationID, "GetSingleConversationMsgOpt from redis err", conversationID, pb.String(), err.Error()) + return true + } + switch opt { + case constant.ReceiveMessage: + return true + case constant.NotReceiveMessage: + return false + case constant.ReceiveNotNotifyMessage: + if pb.MsgData.Options == nil { + pb.MsgData.Options = make(map[string]bool, 10) + } + utils.SetSwitchFromOptions(pb.MsgData.Options, constant.IsOfflinePush, false) + return true + } + + return true +} + +type NotificationMsg struct { + SendID string + RecvID string + Content []byte // open_im_sdk.TipsComm + MsgFrom int32 + ContentType int32 + SessionType int32 + OperationID string +} + +func Notification(n *NotificationMsg) { + var req pbChat.SendMsgReq + var msg sdk_ws.MsgData + var offlineInfo sdk_ws.OfflinePushInfo + var title, desc, ex string + var pushSwitch, unReadCount bool + var reliabilityLevel int + req.OperationID = n.OperationID + msg.SendID = n.SendID + msg.RecvID = n.RecvID + msg.Content = n.Content + msg.MsgFrom = n.MsgFrom + msg.ContentType = n.ContentType + msg.SessionType = n.SessionType + msg.CreateTime = utils.GetCurrentTimestampByMill() + msg.ClientMsgID = utils.GetMsgID(n.SendID) + msg.Options = make(map[string]bool, 7) + switch n.SessionType { + case constant.GroupChatType: + msg.RecvID = "" + msg.GroupID = n.RecvID + } + offlineInfo.IOSBadgeCount = config.Config.IOSPush.BadgeCount + offlineInfo.IOSPushSound = config.Config.IOSPush.PushSound + switch msg.ContentType { + case constant.GroupCreatedNotification: + pushSwitch = config.Config.Notification.GroupCreated.OfflinePush.PushSwitch + title = config.Config.Notification.GroupCreated.OfflinePush.Title + desc = config.Config.Notification.GroupCreated.OfflinePush.Desc + ex = config.Config.Notification.GroupCreated.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupCreated.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupCreated.Conversation.UnreadCount + case constant.GroupInfoSetNotification: + pushSwitch = config.Config.Notification.GroupInfoSet.OfflinePush.PushSwitch + title = config.Config.Notification.GroupInfoSet.OfflinePush.Title + desc = config.Config.Notification.GroupInfoSet.OfflinePush.Desc + ex = config.Config.Notification.GroupInfoSet.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupInfoSet.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupInfoSet.Conversation.UnreadCount + case constant.JoinGroupApplicationNotification: + pushSwitch = config.Config.Notification.JoinGroupApplication.OfflinePush.PushSwitch + title = config.Config.Notification.JoinGroupApplication.OfflinePush.Title + desc = config.Config.Notification.JoinGroupApplication.OfflinePush.Desc + ex = config.Config.Notification.JoinGroupApplication.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.JoinGroupApplication.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.JoinGroupApplication.Conversation.UnreadCount + case constant.MemberQuitNotification: + pushSwitch = config.Config.Notification.MemberQuit.OfflinePush.PushSwitch + title = config.Config.Notification.MemberQuit.OfflinePush.Title + desc = config.Config.Notification.MemberQuit.OfflinePush.Desc + ex = config.Config.Notification.MemberQuit.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.MemberQuit.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.MemberQuit.Conversation.UnreadCount + case constant.GroupApplicationAcceptedNotification: + pushSwitch = config.Config.Notification.GroupApplicationAccepted.OfflinePush.PushSwitch + title = config.Config.Notification.GroupApplicationAccepted.OfflinePush.Title + desc = config.Config.Notification.GroupApplicationAccepted.OfflinePush.Desc + ex = config.Config.Notification.GroupApplicationAccepted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupApplicationAccepted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupApplicationAccepted.Conversation.UnreadCount + case constant.GroupApplicationRejectedNotification: + pushSwitch = config.Config.Notification.GroupApplicationRejected.OfflinePush.PushSwitch + title = config.Config.Notification.GroupApplicationRejected.OfflinePush.Title + desc = config.Config.Notification.GroupApplicationRejected.OfflinePush.Desc + ex = config.Config.Notification.GroupApplicationRejected.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupApplicationRejected.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupApplicationRejected.Conversation.UnreadCount + case constant.GroupOwnerTransferredNotification: + pushSwitch = config.Config.Notification.GroupOwnerTransferred.OfflinePush.PushSwitch + title = config.Config.Notification.GroupOwnerTransferred.OfflinePush.Title + desc = config.Config.Notification.GroupOwnerTransferred.OfflinePush.Desc + ex = config.Config.Notification.GroupOwnerTransferred.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupOwnerTransferred.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupOwnerTransferred.Conversation.UnreadCount + case constant.MemberKickedNotification: + pushSwitch = config.Config.Notification.MemberKicked.OfflinePush.PushSwitch + title = config.Config.Notification.MemberKicked.OfflinePush.Title + desc = config.Config.Notification.MemberKicked.OfflinePush.Desc + ex = config.Config.Notification.MemberKicked.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.MemberKicked.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.MemberKicked.Conversation.UnreadCount + case constant.MemberInvitedNotification: + pushSwitch = config.Config.Notification.MemberInvited.OfflinePush.PushSwitch + title = config.Config.Notification.MemberInvited.OfflinePush.Title + desc = config.Config.Notification.MemberInvited.OfflinePush.Desc + ex = config.Config.Notification.MemberInvited.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.MemberInvited.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.MemberInvited.Conversation.UnreadCount + case constant.MemberEnterNotification: + pushSwitch = config.Config.Notification.MemberEnter.OfflinePush.PushSwitch + title = config.Config.Notification.MemberEnter.OfflinePush.Title + desc = config.Config.Notification.MemberEnter.OfflinePush.Desc + ex = config.Config.Notification.MemberEnter.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.MemberEnter.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.MemberEnter.Conversation.UnreadCount + case constant.UserInfoUpdatedNotification: + pushSwitch = config.Config.Notification.UserInfoUpdated.OfflinePush.PushSwitch + title = config.Config.Notification.UserInfoUpdated.OfflinePush.Title + desc = config.Config.Notification.UserInfoUpdated.OfflinePush.Desc + ex = config.Config.Notification.UserInfoUpdated.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.UserInfoUpdated.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.UserInfoUpdated.Conversation.UnreadCount + case constant.FriendApplicationNotification: + pushSwitch = config.Config.Notification.FriendApplication.OfflinePush.PushSwitch + title = config.Config.Notification.FriendApplication.OfflinePush.Title + desc = config.Config.Notification.FriendApplication.OfflinePush.Desc + ex = config.Config.Notification.FriendApplication.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.FriendApplication.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.FriendApplication.Conversation.UnreadCount + case constant.FriendApplicationApprovedNotification: + pushSwitch = config.Config.Notification.FriendApplicationApproved.OfflinePush.PushSwitch + title = config.Config.Notification.FriendApplicationApproved.OfflinePush.Title + desc = config.Config.Notification.FriendApplicationApproved.OfflinePush.Desc + ex = config.Config.Notification.FriendApplicationApproved.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.FriendApplicationApproved.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.FriendApplicationApproved.Conversation.UnreadCount + case constant.FriendApplicationRejectedNotification: + pushSwitch = config.Config.Notification.FriendApplicationRejected.OfflinePush.PushSwitch + title = config.Config.Notification.FriendApplicationRejected.OfflinePush.Title + desc = config.Config.Notification.FriendApplicationRejected.OfflinePush.Desc + ex = config.Config.Notification.FriendApplicationRejected.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.FriendApplicationRejected.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.FriendApplicationRejected.Conversation.UnreadCount + case constant.FriendAddedNotification: + pushSwitch = config.Config.Notification.FriendAdded.OfflinePush.PushSwitch + title = config.Config.Notification.FriendAdded.OfflinePush.Title + desc = config.Config.Notification.FriendAdded.OfflinePush.Desc + ex = config.Config.Notification.FriendAdded.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.FriendAdded.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.FriendAdded.Conversation.UnreadCount + case constant.FriendDeletedNotification: + pushSwitch = config.Config.Notification.FriendDeleted.OfflinePush.PushSwitch + title = config.Config.Notification.FriendDeleted.OfflinePush.Title + desc = config.Config.Notification.FriendDeleted.OfflinePush.Desc + ex = config.Config.Notification.FriendDeleted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.FriendDeleted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.FriendDeleted.Conversation.UnreadCount + case constant.FriendRemarkSetNotification: + pushSwitch = config.Config.Notification.FriendRemarkSet.OfflinePush.PushSwitch + title = config.Config.Notification.FriendRemarkSet.OfflinePush.Title + desc = config.Config.Notification.FriendRemarkSet.OfflinePush.Desc + ex = config.Config.Notification.FriendRemarkSet.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.FriendRemarkSet.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.FriendRemarkSet.Conversation.UnreadCount + case constant.BlackAddedNotification: + pushSwitch = config.Config.Notification.BlackAdded.OfflinePush.PushSwitch + title = config.Config.Notification.BlackAdded.OfflinePush.Title + desc = config.Config.Notification.BlackAdded.OfflinePush.Desc + ex = config.Config.Notification.BlackAdded.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.BlackAdded.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.BlackAdded.Conversation.UnreadCount + case constant.BlackDeletedNotification: + pushSwitch = config.Config.Notification.BlackDeleted.OfflinePush.PushSwitch + title = config.Config.Notification.BlackDeleted.OfflinePush.Title + desc = config.Config.Notification.BlackDeleted.OfflinePush.Desc + ex = config.Config.Notification.BlackDeleted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.BlackDeleted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.BlackDeleted.Conversation.UnreadCount + case constant.ConversationOptChangeNotification: + pushSwitch = config.Config.Notification.ConversationOptUpdate.OfflinePush.PushSwitch + title = config.Config.Notification.ConversationOptUpdate.OfflinePush.Title + desc = config.Config.Notification.ConversationOptUpdate.OfflinePush.Desc + ex = config.Config.Notification.ConversationOptUpdate.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.ConversationOptUpdate.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.ConversationOptUpdate.Conversation.UnreadCount + + case constant.GroupDismissedNotification: + pushSwitch = config.Config.Notification.GroupDismissed.OfflinePush.PushSwitch + title = config.Config.Notification.GroupDismissed.OfflinePush.Title + desc = config.Config.Notification.GroupDismissed.OfflinePush.Desc + ex = config.Config.Notification.GroupDismissed.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupDismissed.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupDismissed.Conversation.UnreadCount + + case constant.GroupMutedNotification: + pushSwitch = config.Config.Notification.GroupMuted.OfflinePush.PushSwitch + title = config.Config.Notification.GroupMuted.OfflinePush.Title + desc = config.Config.Notification.GroupMuted.OfflinePush.Desc + ex = config.Config.Notification.GroupMuted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupMuted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupMuted.Conversation.UnreadCount + + case constant.GroupCancelMutedNotification: + pushSwitch = config.Config.Notification.GroupCancelMuted.OfflinePush.PushSwitch + title = config.Config.Notification.GroupCancelMuted.OfflinePush.Title + desc = config.Config.Notification.GroupCancelMuted.OfflinePush.Desc + ex = config.Config.Notification.GroupCancelMuted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupCancelMuted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupCancelMuted.Conversation.UnreadCount + + case constant.GroupMemberMutedNotification: + pushSwitch = config.Config.Notification.GroupMemberMuted.OfflinePush.PushSwitch + title = config.Config.Notification.GroupMemberMuted.OfflinePush.Title + desc = config.Config.Notification.GroupMemberMuted.OfflinePush.Desc + ex = config.Config.Notification.GroupMemberMuted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupMemberMuted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupMemberMuted.Conversation.UnreadCount + + case constant.GroupMemberCancelMutedNotification: + pushSwitch = config.Config.Notification.GroupMemberCancelMuted.OfflinePush.PushSwitch + title = config.Config.Notification.GroupMemberCancelMuted.OfflinePush.Title + desc = config.Config.Notification.GroupMemberCancelMuted.OfflinePush.Desc + ex = config.Config.Notification.GroupMemberCancelMuted.OfflinePush.Ext + reliabilityLevel = config.Config.Notification.GroupMemberCancelMuted.Conversation.ReliabilityLevel + unReadCount = config.Config.Notification.GroupMemberCancelMuted.Conversation.UnreadCount + } + switch reliabilityLevel { + case constant.UnreliableNotification: + utils.SetSwitchFromOptions(msg.Options, constant.IsHistory, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsPersistent, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) + case constant.ReliableNotificationNoMsg: + utils.SetSwitchFromOptions(msg.Options, constant.IsConversationUpdate, false) + utils.SetSwitchFromOptions(msg.Options, constant.IsSenderConversationUpdate, false) + case constant.ReliableNotificationMsg: + + } + utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, unReadCount) + utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, pushSwitch) + offlineInfo.Title = title + offlineInfo.Desc = desc + offlineInfo.Ex = ex + msg.OfflinePushInfo = &offlineInfo + req.MsgData = &msg + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + client := pbChat.NewChatClient(etcdConn) + reply, err := client.SendMsg(context.Background(), &req) + if err != nil { + log.NewError(req.OperationID, "SendMsg rpc failed, ", req.String(), err.Error()) + } else if reply.ErrCode != 0 { + log.NewError(req.OperationID, "SendMsg rpc failed, ", req.String(), reply.ErrCode, reply.ErrMsg) + } +} diff --git a/internal/rpc/msg/tag_send_msg.go b/internal/rpc/msg/tag_send_msg.go new file mode 100644 index 000000000..195640498 --- /dev/null +++ b/internal/rpc/msg/tag_send_msg.go @@ -0,0 +1,45 @@ +package msg + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbChat "Open_IM/pkg/proto/chat" + pbCommon "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "strings" +) + +func TagSendMessage(operationID string, user *db.User, recvID, content string, senderPlatformID int32) { + log.NewInfo(operationID, utils.GetSelfFuncName(), "args: ", user.UserID, recvID, content) + var req pbChat.SendMsgReq + var msgData pbCommon.MsgData + msgData.SendID = user.UserID + msgData.RecvID = recvID + msgData.ContentType = constant.Custom + msgData.SessionType = constant.SingleChatType + msgData.MsgFrom = constant.UserMsgType + msgData.Content = []byte(content) + msgData.SenderFaceURL = user.FaceURL + msgData.SenderNickname = user.Nickname + msgData.Options = map[string]bool{} + msgData.Options[constant.IsSenderConversationUpdate] = false + msgData.CreateTime = utils.GetCurrentTimestampByMill() + msgData.ClientMsgID = utils.GetMsgID(user.UserID) + msgData.SenderPlatformID = senderPlatformID + req.MsgData = &msgData + req.OperationID = operationID + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImOfflineMessageName) + client := pbChat.NewChatClient(etcdConn) + respPb, err := client.SendMsg(context.Background(), &req) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "send msg failed", err.Error()) + return + } + if respPb.ErrCode != 0 { + log.NewError(operationID, utils.GetSelfFuncName(), "send tag msg failed ", respPb) + } +} diff --git a/internal/rpc/office/office.go b/internal/rpc/office/office.go new file mode 100644 index 000000000..53e58f223 --- /dev/null +++ b/internal/rpc/office/office.go @@ -0,0 +1,445 @@ +package office + +import ( + "Open_IM/internal/rpc/msg" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbOffice "Open_IM/pkg/proto/office" + pbCommon "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "google.golang.org/grpc" + "net" + "strconv" + "strings" + "time" +) + +type officeServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewOfficeServer(port int) *officeServer { + log.NewPrivateLog(constant.LogFileName) + return &officeServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImOfficeName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *officeServer) Run() { + log.NewInfo("0", "officeServer rpc start ") + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("0", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("0", "listen network success, ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + pbOffice.RegisterOfficeServiceServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error()) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error()) + return + } + log.NewInfo("0", "message cms rpc success") +} + +func (s *officeServer) GetUserTags(_ context.Context, req *pbOffice.GetUserTagsReq) (resp *pbOffice.GetUserTagsResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req ", req.String()) + resp = &pbOffice.GetUserTagsResp{ + CommonResp: &pbOffice.CommonResp{}, + Tags: []*pbOffice.Tag{}, + } + tags, err := db.DB.GetUserTags(req.UserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + return resp, nil + } + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "tags: ", tags) + for _, v := range tags { + tag := &pbOffice.Tag{ + TagID: v.TagID, + TagName: v.TagName, + } + for _, userID := range v.UserList { + UserName, err := im_mysql_model.GetUserNameByUserID(userID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserNameByUserID failed", err.Error()) + continue + } + tag.UserList = append(tag.UserList, &pbOffice.TagUser{ + UserID: userID, + UserName: UserName, + }) + } + resp.Tags = append(resp.Tags, tag) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp ", resp.String()) + return resp, nil +} + +func (s *officeServer) CreateTag(_ context.Context, req *pbOffice.CreateTagReq) (resp *pbOffice.CreateTagResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "CreateTag req", req.String()) + userIDList := utils.RemoveRepeatedStringInList(req.UserIDList) + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "userIDList: ", userIDList) + resp = &pbOffice.CreateTagResp{CommonResp: &pbOffice.CommonResp{}} + if err := db.DB.CreateTag(req.UserID, req.TagName, userIDList); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserTags failed", err.Error()) + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp", resp.String()) + return resp, nil +} + +func (s *officeServer) DeleteTag(_ context.Context, req *pbOffice.DeleteTagReq) (resp *pbOffice.DeleteTagResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.DeleteTagResp{CommonResp: &pbOffice.CommonResp{}} + if err := db.DB.DeleteTag(req.UserID, req.TagID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "DeleteTag failed", err.Error()) + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) SetTag(_ context.Context, req *pbOffice.SetTagReq) (resp *pbOffice.SetTagResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.SetTagResp{CommonResp: &pbOffice.CommonResp{}} + IncreaseUserIDList := utils.RemoveRepeatedStringInList(req.IncreaseUserIDList) + reduceUserIDList := utils.RemoveRepeatedStringInList(req.ReduceUserIDList) + if err := db.DB.SetTag(req.UserID, req.TagID, req.NewName, IncreaseUserIDList, reduceUserIDList); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetTag failed", err.Error()) + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) SendMsg2Tag(_ context.Context, req *pbOffice.SendMsg2TagReq) (resp *pbOffice.SendMsg2TagResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.SendMsg2TagResp{CommonResp: &pbOffice.CommonResp{}} + var tagUserIDList []string + for _, tagID := range req.TagList { + userIDList, err := db.DB.GetUserIDListByTagID(req.SendID, tagID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserIDListByTagID failed", err.Error()) + continue + } + tagUserIDList = append(tagUserIDList, userIDList...) + } + var groupUserIDList []string + for _, groupID := range req.GroupList { + userIDList, err := im_mysql_model.GetGroupMemberIDListByGroupID(groupID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMemberIDListByGroupID failed", err.Error()) + continue + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), userIDList) + groupUserIDList = append(groupUserIDList, userIDList...) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), groupUserIDList, req.GroupList) + var userIDList []string + userIDList = append(userIDList, tagUserIDList...) + userIDList = append(userIDList, groupUserIDList...) + userIDList = append(userIDList, req.UserList...) + userIDList = utils.RemoveRepeatedStringInList(userIDList) + for i, userID := range userIDList { + if userID == req.SendID || userID == "" { + userIDList = append(userIDList[:i], userIDList[i+1:]...) + } + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "total userIDList result: ", userIDList) + us, err := imdb.GetUserByUserID(req.SendID) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), req.SendID) + } + for _, userID := range userIDList { + msg.TagSendMessage(req.OperationID, us, userID, req.Content, req.SenderPlatformID) + } + var tagSendLogs db.TagSendLog + for _, userID := range userIDList { + userName, err := im_mysql_model.GetUserNameByUserID(userID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserNameByUserID failed", err.Error()) + continue + } + tagSendLogs.UserList = append(tagSendLogs.UserList, db.TagUser{ + UserID: userID, + UserName: userName, + }) + } + tagSendLogs.SendID = req.SendID + tagSendLogs.Content = req.Content + tagSendLogs.SenderPlatformID = req.SenderPlatformID + tagSendLogs.SendTime = time.Now().Unix() + if err := db.DB.SaveTagSendLog(&tagSendLogs); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SaveTagSendLog failed", err.Error()) + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) GetTagSendLogs(_ context.Context, req *pbOffice.GetTagSendLogsReq) (resp *pbOffice.GetTagSendLogsResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.GetTagSendLogsResp{ + CommonResp: &pbOffice.CommonResp{}, + Pagination: &pbCommon.ResponsePagination{ + CurrentPage: req.Pagination.PageNumber, + ShowNumber: req.Pagination.ShowNumber, + }, + TagSendLogs: []*pbOffice.TagSendLog{}, + } + tagSendLogs, err := db.DB.GetTagSendLogs(req.UserID, req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetTagSendLogs", err.Error()) + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + return resp, nil + } + if err := utils.CopyStructFields(&resp.TagSendLogs, tagSendLogs); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) GetUserTagByID(_ context.Context, req *pbOffice.GetUserTagByIDReq) (resp *pbOffice.GetUserTagByIDResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.GetUserTagByIDResp{ + CommonResp: &pbOffice.CommonResp{}, + Tag: &pbOffice.Tag{}, + } + tag, err := db.DB.GetTagByID(req.UserID, req.TagID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetTagByID failed", err.Error()) + resp.CommonResp.ErrCode = constant.ErrDB.ErrCode + resp.CommonResp.ErrMsg = constant.ErrDB.ErrMsg + return resp, nil + } + for _, userID := range tag.UserList { + userName, err := im_mysql_model.GetUserNameByUserID(userID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserNameByUserID failed", err.Error()) + continue + } + resp.Tag.UserList = append(resp.Tag.UserList, &pbOffice.TagUser{ + UserID: userID, + UserName: userName, + }) + } + resp.Tag.TagID = tag.TagID + resp.Tag.TagName = tag.TagName + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) CreateOneWorkMoment(_ context.Context, req *pbOffice.CreateOneWorkMomentReq) (resp *pbOffice.CreateOneWorkMomentResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.CreateOneWorkMomentResp{} + workMoment := db.WorkMoment{} + if err := utils.CopyStructFields(&workMoment, req.WorkMoment); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + err = db.DB.CreateOneWorkMoment(&workMoment) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CreateOneWorkMoment", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) DeleteOneWorkMoment(_ context.Context, req *pbOffice.DeleteOneWorkMomentReq) (resp *pbOffice.DeleteOneWorkMomentResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.DeleteOneWorkMomentResp{} + err = db.DB.DeleteOneWorkMoment(req.WorkMomentID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "DeleteOneWorkMoment", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) LikeOneWorkMoment(_ context.Context, req *pbOffice.LikeOneWorkMomentReq) (resp *pbOffice.LikeOneWorkMomentResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.LikeOneWorkMomentResp{} + workMoment, err := db.DB.GetWorkMomentByID(req.WorkMomentID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetWorkMomentByID failed", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if workMoment.UserID != req.WorkMomentID { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "workMoment.UserID != req.WorkMomentID ", workMoment, req.WorkMomentID) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg} + return resp, nil + } + if err = db.DB.LikeOneWorkMoment(req.UserID, req.WorkMomentID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "LikeOneWorkMoment failed ", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) CommentOneWorkMoment(_ context.Context, req *pbOffice.CommentOneWorkMomentReq) (resp *pbOffice.CommentOneWorkMomentResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.CommentOneWorkMomentResp{} + commentUserName, err := imdb.GetUserNameByUserID(req.UserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserNameByUserID commentUserName failed", req.UserID, err.Error()) + } + var replyUserName string + if req.ReplyUserID != "" { + replyUserName, err = imdb.GetUserNameByUserID(req.ReplyUserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserNameByUserID get replyUserName failed", req.ReplyUserID, err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + } + comment := db.Comment{ + UserID: req.UserID, + UserName: commentUserName, + ReplyUserID: req.ReplyUserID, + ReplyUserName: replyUserName, + ContentID: "", + Content: req.Content, + CreateTime: int32(time.Now().Unix()), + } + if err = db.DB.CommentOneWorkMoment(comment, req.WorkMomentID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "CommentOneWorkMoment failed", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) GetUserWorkMoments(_ context.Context, req *pbOffice.GetUserWorkMomentsReq) (resp *pbOffice.GetUserWorkMomentsResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.GetUserWorkMomentsResp{} + workMoments, err := db.DB.GetUserWorkMoments(req.UserID, req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), err) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if err := utils.CopyStructFields(resp.WorkMoments, workMoments); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.Pagination = &pbCommon.ResponsePagination{CurrentPage: req.Pagination.PageNumber, ShowNumber: req.Pagination.ShowNumber} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) GetUserFriendWorkMoments(_ context.Context, req *pbOffice.GetUserFriendWorkMomentsReq) (resp *pbOffice.GetUserFriendWorkMomentsResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.GetUserFriendWorkMomentsResp{} + friendIDList, err := imdb.GetFriendIDListByUserID(req.UserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetFriendIDListByUserID", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "friendIDList: ", friendIDList) + workMoments, err := db.DB.GetUserFriendWorkMoments(friendIDList, req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserFriendWorkMoments", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if err := utils.CopyStructFields(resp.WorkMoments, workMoments); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", err.Error()) + } + resp.Pagination = &pbCommon.ResponsePagination{CurrentPage: req.Pagination.PageNumber, ShowNumber: req.Pagination.ShowNumber} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) GetUserWorkMomentsCommentsMsg(_ context.Context, req *pbOffice.GetUserWorkMomentsCommentsMsgReq) (resp *pbOffice.GetUserWorkMomentsCommentsMsgResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.GetUserWorkMomentsCommentsMsgResp{CommentsMsgs: []*pbOffice.CommentsMsg{}} + workMomentsCommentMsgs, err := db.DB.GetUserWorkMomentsCommentsMsg(req.UserID, req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserWorkMomentsCommentsMsg", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + for _, commentMsg := range workMomentsCommentMsgs { + comment := pbOffice.Comment{} + if err := utils.CopyStructFields(&comment, commentMsg); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), err.Error()) + } + resp.CommentsMsgs = append(resp.CommentsMsgs, &pbOffice.CommentsMsg{ + Comment: &comment, + WorkMomentID: commentMsg.WorkMomentID, + Content: commentMsg.Content, + }) + } + resp.Pagination = &pbCommon.ResponsePagination{CurrentPage: req.Pagination.PageNumber, ShowNumber: req.Pagination.ShowNumber} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) SetUserWorkMomentsLevel(_ context.Context, req *pbOffice.SetUserWorkMomentsLevelReq) (resp *pbOffice.SetUserWorkMomentsLevelResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.SetUserWorkMomentsLevelResp{} + if err := db.DB.SetUserWorkMomentsLevel(req.UserID, req.Level); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetUserWorkMomentsLevel failed", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} + +func (s *officeServer) ClearUserWorkMomentsCommentsMsg(_ context.Context, req *pbOffice.ClearUserWorkMomentsCommentsMsgReq) (resp *pbOffice.ClearUserWorkMomentsCommentsMsgResp, err error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp = &pbOffice.ClearUserWorkMomentsCommentsMsgResp{} + if err := db.DB.ClearUserWorkMomentsCommentsMsg(req.UserID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "ClearUserWorkMomentsCommentsMsg", err.Error()) + resp.CommonResp = &pbOffice.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + return resp, nil +} diff --git a/internal/rpc/organization/organization.go b/internal/rpc/organization/organization.go new file mode 100644 index 000000000..894fa643d --- /dev/null +++ b/internal/rpc/organization/organization.go @@ -0,0 +1,349 @@ +package organization + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + rpc "Open_IM/pkg/proto/organization" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "time" + + "context" + "google.golang.org/grpc" + "net" + "strconv" + "strings" +) + +type organizationServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewServer(port int) *organizationServer { + log.NewPrivateLog(constant.LogFileName) + return &organizationServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImOrganizationName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *organizationServer) Run() { + log.NewInfo("", "organization rpc start ") + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("", "listen network success, ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + rpc.RegisterOrganizationServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("", "RegisterEtcd failed ", err.Error()) + return + } + log.NewInfo("", "organization rpc RegisterEtcd success", ip, s.rpcPort, s.rpcRegisterName, 10) + err = srv.Serve(listener) + if err != nil { + log.NewError("", "Serve failed ", err.Error()) + return + } + log.NewInfo("", "organization rpc success") +} + +func (s *organizationServer) CreateDepartment(ctx context.Context, req *rpc.CreateDepartmentReq) (*rpc.CreateDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.CreateDepartmentResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + department := db.Department{} + utils.CopyStructFields(&department, req.DepartmentInfo) + if department.DepartmentID == "" { + department.DepartmentID = utils.Md5(strconv.FormatInt(time.Now().UnixNano(), 10)) + } + log.Debug(req.OperationID, "dst ", department, "src ", req.DepartmentInfo) + if err := imdb.CreateDepartment(&department); err != nil { + errMsg := req.OperationID + " " + "CreateDepartment failed " + err.Error() + log.Error(req.OperationID, errMsg) + return &rpc.CreateDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + err, createdDepartment := imdb.GetDepartment(department.DepartmentID) + if err != nil { + errMsg := req.OperationID + " " + "GetDepartment failed " + err.Error() + department.DepartmentID + log.Error(req.OperationID, errMsg) + return &rpc.CreateDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "GetDepartment ", department.DepartmentID, *createdDepartment) + resp := &rpc.CreateDepartmentResp{DepartmentInfo: &open_im_sdk.Department{}} + utils.CopyStructFields(resp.DepartmentInfo, createdDepartment) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) UpdateDepartment(ctx context.Context, req *rpc.UpdateDepartmentReq) (*rpc.UpdateDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.UpdateDepartmentResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + department := db.Department{} + utils.CopyStructFields(&department, req.DepartmentInfo) + + log.Debug(req.OperationID, "dst ", department, "src ", req.DepartmentInfo) + if err := imdb.UpdateDepartment(&department, nil); err != nil { + errMsg := req.OperationID + " " + "UpdateDepartment failed " + err.Error() + log.Error(req.OperationID, errMsg) + return &rpc.UpdateDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + + resp := &rpc.UpdateDepartmentResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) GetSubDepartment(ctx context.Context, req *rpc.GetSubDepartmentReq) (*rpc.GetSubDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + err, departmentList := imdb.GetSubDepartmentList(req.DepartmentID) + if err != nil { + errMsg := req.OperationID + " " + "GetDepartment failed " + err.Error() + log.Error(req.OperationID, errMsg) + return &rpc.GetSubDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "GetSubDepartmentList ", req.DepartmentID, departmentList) + resp := &rpc.GetSubDepartmentResp{} + for _, v := range departmentList { + v1 := open_im_sdk.Department{} + utils.CopyStructFields(&v1, v) + log.Debug(req.OperationID, "src ", v, "dst ", v1) + resp.DepartmentList = append(resp.DepartmentList, &v1) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) DeleteDepartment(ctx context.Context, req *rpc.DeleteDepartmentReq) (*rpc.DeleteDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.DeleteDepartmentResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + err := imdb.DeleteDepartment(req.DepartmentID) + if err != nil { + errMsg := req.OperationID + " " + "DeleteDepartment failed " + err.Error() + log.Error(req.OperationID, errMsg, req.DepartmentID) + return &rpc.DeleteDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "DeleteDepartment ", req.DepartmentID) + resp := &rpc.DeleteDepartmentResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", resp) + return resp, nil +} + +func (s *organizationServer) CreateOrganizationUser(ctx context.Context, req *rpc.CreateOrganizationUserReq) (*rpc.CreateOrganizationUserResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.CreateOrganizationUserResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + organizationUser := db.OrganizationUser{} + utils.CopyStructFields(&organizationUser, req.OrganizationUser) + organizationUser.Birth = utils.UnixSecondToTime(int64(req.OrganizationUser.Birth)) + log.Debug(req.OperationID, "src ", *req.OrganizationUser, "dst ", organizationUser) + err := imdb.CreateOrganizationUser(&organizationUser) + if err != nil { + errMsg := req.OperationID + " " + "CreateOrganizationUser failed " + err.Error() + log.Error(req.OperationID, errMsg, organizationUser) + return &rpc.CreateOrganizationUserResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "CreateOrganizationUser ", organizationUser) + resp := &rpc.CreateOrganizationUserResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) UpdateOrganizationUser(ctx context.Context, req *rpc.UpdateOrganizationUserReq) (*rpc.UpdateOrganizationUserResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.UpdateOrganizationUserResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + organizationUser := db.OrganizationUser{} + utils.CopyStructFields(&organizationUser, req.OrganizationUser) + log.Debug(req.OperationID, "src ", *req.OrganizationUser, "dst ", organizationUser) + err := imdb.UpdateOrganizationUser(&organizationUser, nil) + if err != nil { + errMsg := req.OperationID + " " + "CreateOrganizationUser failed " + err.Error() + log.Error(req.OperationID, errMsg, organizationUser) + return &rpc.UpdateOrganizationUserResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "UpdateOrganizationUser ", organizationUser) + resp := &rpc.UpdateOrganizationUserResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", resp) + return resp, nil +} + +func (s *organizationServer) CreateDepartmentMember(ctx context.Context, req *rpc.CreateDepartmentMemberReq) (*rpc.CreateDepartmentMemberResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.CreateDepartmentMemberResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + departmentMember := db.DepartmentMember{} + utils.CopyStructFields(&departmentMember, req.UserInDepartment) + log.Debug(req.OperationID, "src ", *req.UserInDepartment, "dst ", departmentMember) + err := imdb.CreateDepartmentMember(&departmentMember) + if err != nil { + errMsg := req.OperationID + " " + "CreateDepartmentMember failed " + err.Error() + log.Error(req.OperationID, errMsg, departmentMember) + return &rpc.CreateDepartmentMemberResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "UpdateOrganizationUser ", departmentMember) + resp := &rpc.CreateDepartmentMemberResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) GetUserInDepartmentByUserID(userID string) (*open_im_sdk.UserInDepartment, error) { + err, organizationUser := imdb.GetOrganizationUser(userID) + if err != nil { + return nil, utils.Wrap(err, "GetOrganizationUser failed") + } + err, departmentMemberList := imdb.GetUserInDepartment(userID) + if err != nil { + return nil, utils.Wrap(err, "GetUserInDepartment failed") + } + resp := &open_im_sdk.UserInDepartment{OrganizationUser: &open_im_sdk.OrganizationUser{}} + utils.CopyStructFields(resp.OrganizationUser, organizationUser) + for _, v := range departmentMemberList { + v1 := open_im_sdk.DepartmentMember{} + utils.CopyStructFields(&v1, v) + resp.DepartmentMemberList = append(resp.DepartmentMemberList, &v1) + } + return resp, nil +} + +func (s *organizationServer) GetUserInDepartment(ctx context.Context, req *rpc.GetUserInDepartmentReq) (*rpc.GetUserInDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + r, err := s.GetUserInDepartmentByUserID(req.UserID) + if err != nil { + errMsg := req.OperationID + " " + "GetUserInDepartmentByUserID failed " + err.Error() + log.Error(req.OperationID, errMsg, req.UserID) + return &rpc.GetUserInDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "GetUserInDepartmentByUserID success ", req.UserID, r) + resp := rpc.GetUserInDepartmentResp{UserInDepartment: &open_im_sdk.UserInDepartment{OrganizationUser: &open_im_sdk.OrganizationUser{}}} + resp.UserInDepartment.DepartmentMemberList = r.DepartmentMemberList + resp.UserInDepartment.OrganizationUser = r.OrganizationUser + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", resp) + return &resp, nil +} + +func (s *organizationServer) UpdateUserInDepartment(ctx context.Context, req *rpc.UpdateUserInDepartmentReq) (*rpc.UpdateUserInDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.UpdateUserInDepartmentResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + departmentMember := &db.DepartmentMember{} + utils.CopyStructFields(departmentMember, req.DepartmentMember) + log.Debug(req.OperationID, "dst ", departmentMember, "src ", req.DepartmentMember) + err := imdb.UpdateUserInDepartment(departmentMember, nil) + if err != nil { + errMsg := req.OperationID + " " + "UpdateUserInDepartment failed " + err.Error() + log.Error(req.OperationID, errMsg, *departmentMember) + return &rpc.UpdateUserInDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + resp := &rpc.UpdateUserInDepartmentResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) DeleteUserInDepartment(ctx context.Context, req *rpc.DeleteUserInDepartmentReq) (*rpc.DeleteUserInDepartmentResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.DeleteUserInDepartmentResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + + err := imdb.DeleteUserInDepartment(req.DepartmentID, req.UserID) + if err != nil { + errMsg := req.OperationID + " " + "DeleteUserInDepartment failed " + err.Error() + log.Error(req.OperationID, errMsg, req.DepartmentID, req.UserID) + return &rpc.DeleteUserInDepartmentResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "DeleteUserInDepartment success ", req.DepartmentID, req.UserID) + resp := &rpc.DeleteUserInDepartmentResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) DeleteOrganizationUser(ctx context.Context, req *rpc.DeleteOrganizationUserReq) (*rpc.DeleteOrganizationUserResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + errMsg := req.OperationID + "" + req.OpUserID + " is not app manager" + log.Error(req.OperationID, errMsg) + return &rpc.DeleteOrganizationUserResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, nil + } + err := imdb.DeleteOrganizationUser(req.UserID) + if err != nil { + errMsg := req.OperationID + " " + "DeleteOrganizationUser failed " + err.Error() + log.Error(req.OperationID, errMsg, req.UserID) + return &rpc.DeleteOrganizationUserResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + log.Debug(req.OperationID, "DeleteOrganizationUser success ", req.UserID) + resp := &rpc.DeleteOrganizationUserResp{} + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", *resp) + return resp, nil +} + +func (s *organizationServer) GetDepartmentMember(ctx context.Context, req *rpc.GetDepartmentMemberReq) (*rpc.GetDepartmentMemberResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String()) + err, departmentMemberUserIDList := imdb.GetDepartmentMemberUserIDList(req.DepartmentID) + if err != nil { + errMsg := req.OperationID + " " + "GetDepartmentMemberUserIDList failed " + err.Error() + log.Error(req.OperationID, errMsg, req.DepartmentID) + return &rpc.GetDepartmentMemberResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: errMsg}, nil + } + + resp := rpc.GetDepartmentMemberResp{} + for _, v := range departmentMemberUserIDList { + r, err := s.GetUserInDepartmentByUserID(v) + if err != nil { + log.Error(req.OperationID, "GetUserInDepartmentByUserID failed ", err.Error()) + continue + } + log.Debug(req.OperationID, "GetUserInDepartmentByUserID success ", *r) + resp.UserInDepartmentList = append(resp.UserInDepartmentList, r) + } + + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc return ", resp) + return &resp, nil +} diff --git a/internal/rpc/statistics/statistics.go b/internal/rpc/statistics/statistics.go new file mode 100644 index 000000000..cda164332 --- /dev/null +++ b/internal/rpc/statistics/statistics.go @@ -0,0 +1,378 @@ +package statistics + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "context" + "sync" + "time" + + //"Open_IM/pkg/common/constant" + //"Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/log" + + //cp "Open_IM/pkg/common/utils" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbStatistics "Open_IM/pkg/proto/statistics" + + //open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + //"context" + errors "Open_IM/pkg/common/http" + "net" + "strconv" + "strings" + + "google.golang.org/grpc" +) + +type statisticsServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewStatisticsServer(port int) *statisticsServer { + log.NewPrivateLog(constant.LogFileName) + return &statisticsServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImStatisticsName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *statisticsServer) Run() { + log.NewInfo("0", "Statistics rpc start ") + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("0", "Listen failed ", err.Error(), registerAddress) + return + } + log.NewInfo("0", "listen network success, ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + pbStatistics.RegisterUserServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error()) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error()) + return + } + log.NewInfo("0", "statistics rpc success") +} + +func (s *statisticsServer) GetActiveGroup(_ context.Context, req *pbStatistics.GetActiveGroupReq) (*pbStatistics.GetActiveGroupResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbStatistics.GetActiveGroupResp{} + fromTime, toTime, err := ParseTimeFromTo(req.StatisticsReq.From, req.StatisticsReq.To) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "ParseTimeFromTo failed", err.Error()) + return resp, errors.WrapError(constant.ErrArgs) + } + activeGroups, err := imdb.GetActiveGroups(fromTime, toTime, 12) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetActiveGroups failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + for _, activeGroup := range activeGroups { + resp.Groups = append(resp.Groups, + &pbStatistics.GroupResp{ + GroupName: activeGroup.Name, + GroupId: activeGroup.Id, + MessageNum: int32(activeGroup.MessageNum), + }) + } + return resp, nil +} + +func (s *statisticsServer) GetActiveUser(_ context.Context, req *pbStatistics.GetActiveUserReq) (*pbStatistics.GetActiveUserResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbStatistics.GetActiveUserResp{} + fromTime, toTime, err := ParseTimeFromTo(req.StatisticsReq.From, req.StatisticsReq.To) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "ParseTimeFromTo failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + activeUsers, err := imdb.GetActiveUsers(fromTime, toTime, 12) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetActiveUsers failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + for _, activeUser := range activeUsers { + resp.Users = append(resp.Users, + &pbStatistics.UserResp{ + UserId: activeUser.Id, + NickName: activeUser.Name, + MessageNum: int32(activeUser.MessageNum), + }, + ) + } + return resp, nil +} + +func ParseTimeFromTo(from, to string) (time.Time, time.Time, error) { + var fromTime time.Time + var toTime time.Time + fromTime, err := utils.TimeStringToTime(from) + if err != nil { + return fromTime, toTime, err + } + toTime, err = utils.TimeStringToTime(to) + if err != nil { + return fromTime, toTime, err + } + return fromTime, toTime, nil +} + +func isInOneMonth(from, to time.Time) bool { + return from.Month() == to.Month() && from.Year() == to.Year() +} + +func GetRangeDate(from, to time.Time) [][2]time.Time { + interval := to.Sub(from) + var times [][2]time.Time + switch { + // today + case interval == 0: + times = append(times, [2]time.Time{ + from, from.Add(time.Hour * 24), + }) + // days + case isInOneMonth(from, to): + for i := 0; ; i++ { + fromTime := from.Add(time.Hour * 24 * time.Duration(i)) + toTime := from.Add(time.Hour * 24 * time.Duration(i+1)) + if toTime.After(to.Add(time.Hour * 24)) { + break + } + times = append(times, [2]time.Time{ + fromTime, toTime, + }) + } + // month + case !isInOneMonth(from, to): + if to.Sub(from) < time.Hour*24*30 { + for i := 0; ; i++ { + fromTime := from.Add(time.Hour * 24 * time.Duration(i)) + toTime := from.Add(time.Hour * 24 * time.Duration(i+1)) + if toTime.After(to.Add(time.Hour * 24)) { + break + } + times = append(times, [2]time.Time{ + fromTime, toTime, + }) + } + } else { + for i := 0; ; i++ { + if i == 0 { + fromTime := from + toTime := getFirstDateOfNextNMonth(fromTime, 1) + times = append(times, [2]time.Time{ + fromTime, toTime, + }) + } else { + fromTime := getFirstDateOfNextNMonth(from, i) + toTime := getFirstDateOfNextNMonth(fromTime, 1) + if toTime.After(to) { + toTime = to + times = append(times, [2]time.Time{ + fromTime, toTime, + }) + break + } + times = append(times, [2]time.Time{ + fromTime, toTime, + }) + } + + } + } + } + return times +} + +func getFirstDateOfNextNMonth(currentTime time.Time, n int) time.Time { + lastOfMonth := time.Date(currentTime.Year(), currentTime.Month(), 1, 0, 0, 0, 0, currentTime.Location()).AddDate(0, n, 0) + return lastOfMonth +} + +func (s *statisticsServer) GetGroupStatistics(_ context.Context, req *pbStatistics.GetGroupStatisticsReq) (*pbStatistics.GetGroupStatisticsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbStatistics.GetGroupStatisticsResp{} + fromTime, toTime, err := ParseTimeFromTo(req.StatisticsReq.From, req.StatisticsReq.To) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupStatistics failed", err.Error()) + return resp, errors.WrapError(constant.ErrArgs) + } + increaseGroupNum, err := imdb.GetIncreaseGroupNum(fromTime, toTime.Add(time.Hour*24)) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseGroupNum failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + totalGroupNum, err := imdb.GetTotalGroupNum() + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.IncreaseGroupNum = increaseGroupNum + resp.TotalGroupNum = totalGroupNum + times := GetRangeDate(fromTime, toTime) + log.NewInfo(req.OperationID, "times:", times) + wg := &sync.WaitGroup{} + resp.IncreaseGroupNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + resp.TotalGroupNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + wg.Add(len(times)) + for i, v := range times { + go func(wg *sync.WaitGroup, index int, v [2]time.Time) { + defer wg.Done() + num, err := imdb.GetIncreaseGroupNum(v[0], v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseGroupNum", v, err.Error()) + } + resp.IncreaseGroupNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + num, err = imdb.GetGroupNum(v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseGroupNum", v, err.Error()) + } + resp.TotalGroupNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + }(wg, i, v) + } + wg.Wait() + return resp, nil +} + +func (s *statisticsServer) GetMessageStatistics(_ context.Context, req *pbStatistics.GetMessageStatisticsReq) (*pbStatistics.GetMessageStatisticsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbStatistics.GetMessageStatisticsResp{} + fromTime, toTime, err := ParseTimeFromTo(req.StatisticsReq.From, req.StatisticsReq.To) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "ParseTimeFromTo failed", err.Error()) + return resp, errors.WrapError(constant.ErrArgs) + } + privateMessageNum, err := imdb.GetPrivateMessageNum(fromTime, toTime.Add(time.Hour*24)) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetPrivateMessageNum failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + groupMessageNum, err := imdb.GetGroupMessageNum(fromTime, toTime.Add(time.Hour*24)) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetGroupMessageNum failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.PrivateMessageNum = privateMessageNum + resp.GroupMessageNum = groupMessageNum + times := GetRangeDate(fromTime, toTime) + resp.GroupMessageNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + resp.PrivateMessageNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + wg := &sync.WaitGroup{} + wg.Add(len(times)) + for i, v := range times { + go func(wg *sync.WaitGroup, index int, v [2]time.Time) { + defer wg.Done() + + num, err := imdb.GetPrivateMessageNum(v[0], v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseGroupNum", v, err.Error()) + } + resp.PrivateMessageNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + num, err = imdb.GetGroupMessageNum(v[0], v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseGroupNum", v, err.Error()) + } + resp.GroupMessageNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + }(wg, i, v) + } + wg.Wait() + return resp, nil +} + +func (s *statisticsServer) GetUserStatistics(_ context.Context, req *pbStatistics.GetUserStatisticsReq) (*pbStatistics.GetUserStatisticsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbStatistics.GetUserStatisticsResp{} + fromTime, toTime, err := ParseTimeFromTo(req.StatisticsReq.From, req.StatisticsReq.To) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "ParseTimeFromTo failed", err.Error()) + return resp, errors.WrapError(constant.ErrArgs) + } + activeUserNum, err := imdb.GetActiveUserNum(fromTime, toTime.Add(time.Hour*24)) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetActiveUserNum failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + increaseUserNum, err := imdb.GetIncreaseUserNum(fromTime, toTime.Add(time.Hour*24)) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseUserNum failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + totalUserNum, err := imdb.GetTotalUserNum() + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetTotalUserNum failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.ActiveUserNum = activeUserNum + resp.TotalUserNum = totalUserNum + resp.IncreaseUserNum = increaseUserNum + times := GetRangeDate(fromTime, toTime) + resp.TotalUserNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + resp.ActiveUserNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + resp.IncreaseUserNumList = make([]*pbStatistics.DateNumList, len(times), len(times)) + wg := &sync.WaitGroup{} + wg.Add(len(times)) + for i, v := range times { + go func(wg *sync.WaitGroup, index int, v [2]time.Time) { + defer wg.Done() + num, err := imdb.GetActiveUserNum(v[0], v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseGroupNum", v, err.Error()) + } + resp.ActiveUserNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + + num, err = imdb.GetTotalUserNumByDate(v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetTotalUserNumByDate", v, err.Error()) + } + resp.TotalUserNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + num, err = imdb.GetIncreaseUserNum(v[0], v[1]) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetIncreaseUserNum", v, err.Error()) + } + resp.IncreaseUserNumList[index] = &pbStatistics.DateNumList{ + Date: v[0].String(), + Num: num, + } + }(wg, i, v) + } + wg.Wait() + return resp, nil +} diff --git a/internal/rpc/user/callback.go b/internal/rpc/user/callback.go new file mode 100644 index 000000000..a00006b65 --- /dev/null +++ b/internal/rpc/user/callback.go @@ -0,0 +1 @@ +package user diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go new file mode 100644 index 000000000..1234b2be9 --- /dev/null +++ b/internal/rpc/user/user.go @@ -0,0 +1,590 @@ +package user + +import ( + chat "Open_IM/internal/rpc/msg" + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + errors "Open_IM/pkg/common/http" + + "Open_IM/pkg/common/log" + "Open_IM/pkg/common/token_verify" + "Open_IM/pkg/grpc-etcdv3/getcdv3" + pbFriend "Open_IM/pkg/proto/friend" + sdkws "Open_IM/pkg/proto/sdk_ws" + pbUser "Open_IM/pkg/proto/user" + "Open_IM/pkg/utils" + "context" + "fmt" + "net" + "strconv" + "strings" + + "google.golang.org/grpc" +) + +type userServer struct { + rpcPort int + rpcRegisterName string + etcdSchema string + etcdAddr []string +} + +func NewUserServer(port int) *userServer { + log.NewPrivateLog(constant.LogFileName) + return &userServer{ + rpcPort: port, + rpcRegisterName: config.Config.RpcRegisterName.OpenImUserName, + etcdSchema: config.Config.Etcd.EtcdSchema, + etcdAddr: config.Config.Etcd.EtcdAddr, + } +} + +func (s *userServer) Run() { + log.NewInfo("0", "", "rpc user start...") + + ip := utils.ServerIP + registerAddress := ip + ":" + strconv.Itoa(s.rpcPort) + //listener network + listener, err := net.Listen("tcp", registerAddress) + if err != nil { + log.NewError("0", "listen network failed ", err.Error(), registerAddress) + return + } + log.NewInfo("0", "listen network success, address ", registerAddress, listener) + defer listener.Close() + //grpc server + srv := grpc.NewServer() + defer srv.GracefulStop() + //Service registers with etcd + pbUser.RegisterUserServer(srv, s) + err = getcdv3.RegisterEtcd(s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName, 10) + if err != nil { + log.NewError("0", "RegisterEtcd failed ", err.Error(), s.etcdSchema, strings.Join(s.etcdAddr, ","), ip, s.rpcPort, s.rpcRegisterName) + return + } + err = srv.Serve(listener) + if err != nil { + log.NewError("0", "Serve failed ", err.Error()) + return + } + log.NewInfo("0", "rpc user success") +} + +func syncPeerUserConversation(conversation *pbUser.Conversation, operationID string) error { + peerUserConversation := db.Conversation{ + OwnerUserID: conversation.UserID, + ConversationID: "single_" + conversation.OwnerUserID, + ConversationType: constant.SingleChatType, + UserID: conversation.OwnerUserID, + GroupID: "", + RecvMsgOpt: 0, + UnreadCount: 0, + DraftTextTime: 0, + IsPinned: false, + IsPrivateChat: conversation.IsPrivateChat, + AttachedInfo: "", + Ex: "", + } + err := imdb.PeerUserSetConversation(peerUserConversation) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "SetConversation error", err.Error()) + return err + } + chat.ConversationSetPrivateNotification(operationID, conversation.OwnerUserID, conversation.UserID, conversation.IsPrivateChat) + return nil +} + +func (s *userServer) GetUserInfo(ctx context.Context, req *pbUser.GetUserInfoReq) (*pbUser.GetUserInfoResp, error) { + log.NewInfo(req.OperationID, "GetUserInfo args ", req.String()) + var userInfoList []*sdkws.UserInfo + if len(req.UserIDList) > 0 { + for _, userID := range req.UserIDList { + var userInfo sdkws.UserInfo + user, err := imdb.GetUserByUserID(userID) + if err != nil { + log.NewError(req.OperationID, "GetUserByUserID failed ", err.Error(), userID) + continue + } + utils.CopyStructFields(&userInfo, user) + userInfo.Birth = uint32(user.Birth.Unix()) + userInfoList = append(userInfoList, &userInfo) + } + } else { + return &pbUser.GetUserInfoResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrArgs.ErrCode, ErrMsg: constant.ErrArgs.ErrMsg}}, nil + } + log.NewInfo(req.OperationID, "GetUserInfo rpc return ", pbUser.GetUserInfoResp{CommonResp: &pbUser.CommonResp{}, UserInfoList: userInfoList}) + return &pbUser.GetUserInfoResp{CommonResp: &pbUser.CommonResp{}, UserInfoList: userInfoList}, nil +} + +func (s *userServer) BatchSetConversations(ctx context.Context, req *pbUser.BatchSetConversationsReq) (*pbUser.BatchSetConversationsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + if req.NotificationType == 0 { + req.NotificationType = constant.ConversationOptChangeNotification + } + resp := &pbUser.BatchSetConversationsResp{} + for _, v := range req.Conversations { + conversation := db.Conversation{} + if err := utils.CopyStructFields(&conversation, v); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), v.String(), "CopyStructFields failed", err.Error()) + } + if err := db.DB.SetSingleConversationRecvMsgOpt(req.OwnerUserID, v.ConversationID, v.RecvMsgOpt); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "cache failed, rpc return", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if err := imdb.SetConversation(conversation); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation error", err.Error()) + resp.Failed = append(resp.Failed, v.ConversationID) + continue + } + resp.Success = append(resp.Success, v.ConversationID) + // if is set private chat operation,then peer user need to sync and set tips\ + if v.ConversationType == constant.SingleChatType && req.NotificationType == constant.ConversationPrivateChatNotification { + if err := syncPeerUserConversation(v, req.OperationID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "syncPeerUserConversation", err.Error()) + } + } + } + chat.ConversationChangeNotification(req.OperationID, req.OwnerUserID) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return", resp.String()) + resp.CommonResp = &pbUser.CommonResp{} + return resp, nil +} + +func (s *userServer) GetAllConversations(ctx context.Context, req *pbUser.GetAllConversationsReq) (*pbUser.GetAllConversationsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbUser.GetAllConversationsResp{Conversations: []*pbUser.Conversation{}} + conversations, err := imdb.GetUserAllConversations(req.OwnerUserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetConversations error", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if err = utils.CopyStructFields(&resp.Conversations, conversations); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields error", err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return", resp.String()) + resp.CommonResp = &pbUser.CommonResp{} + return resp, nil +} + +func (s *userServer) GetConversation(ctx context.Context, req *pbUser.GetConversationReq) (*pbUser.GetConversationResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbUser.GetConversationResp{Conversation: &pbUser.Conversation{}} + conversation, err := imdb.GetConversation(req.OwnerUserID, req.ConversationID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetConversation error", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if err := utils.CopyStructFields(resp.Conversation, &conversation); err != nil { + log.Debug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields error", conversation, err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + resp.CommonResp = &pbUser.CommonResp{} + return resp, nil +} + +func (s *userServer) GetConversations(ctx context.Context, req *pbUser.GetConversationsReq) (*pbUser.GetConversationsResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbUser.GetConversationsResp{Conversations: []*pbUser.Conversation{}} + conversations, err := imdb.GetConversations(req.OwnerUserID, req.ConversationIDs) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetConversations error", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + if err := utils.CopyStructFields(&resp.Conversations, conversations); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", conversations, err.Error()) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + resp.CommonResp = &pbUser.CommonResp{} + return resp, nil +} + +func (s *userServer) SetConversation(ctx context.Context, req *pbUser.SetConversationReq) (*pbUser.SetConversationResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + if req.NotificationType == 0 { + req.NotificationType = constant.ConversationOptChangeNotification + } + resp := &pbUser.SetConversationResp{} + var conversation db.Conversation + if err := utils.CopyStructFields(&conversation, req.Conversation); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", *req.Conversation, err.Error()) + } + if err := db.DB.SetSingleConversationRecvMsgOpt(req.Conversation.OwnerUserID, req.Conversation.ConversationID, req.Conversation.RecvMsgOpt); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "cache failed, rpc return", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + err := imdb.SetConversation(conversation) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation error", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + // notification + if req.Conversation.ConversationType == constant.SingleChatType && req.NotificationType == constant.ConversationPrivateChatNotification { + //sync peer user conversation if conversation is singleChatType + if err := syncPeerUserConversation(req.Conversation, req.OperationID); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "syncPeerUserConversation", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + } else { + chat.ConversationChangeNotification(req.OperationID, req.Conversation.OwnerUserID) + } + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "rpc return", resp.String()) + resp.CommonResp = &pbUser.CommonResp{} + return resp, nil +} + +func (s *userServer) SetRecvMsgOpt(ctx context.Context, req *pbUser.SetRecvMsgOptReq) (*pbUser.SetRecvMsgOptResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbUser.SetRecvMsgOptResp{} + var conversation db.Conversation + if err := utils.CopyStructFields(&conversation, req); err != nil { + log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields failed", *req, err.Error()) + } + if err := db.DB.SetSingleConversationRecvMsgOpt(req.OwnerUserID, req.ConversationID, req.RecvMsgOpt); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "cache failed, rpc return", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + stringList := strings.Split(req.ConversationID, "_") + if len(stringList) > 1 { + switch stringList[0] { + case "single_": + conversation.UserID = stringList[1] + conversation.ConversationType = constant.SingleChatType + case "group": + conversation.GroupID = stringList[1] + conversation.ConversationType = constant.GroupChatType + } + } + err := imdb.SetRecvMsgOpt(conversation) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "SetConversation error", err.Error()) + resp.CommonResp = &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg} + return resp, nil + } + chat.ConversationChangeNotification(req.OperationID, req.OwnerUserID) + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp.String()) + resp.CommonResp = &pbUser.CommonResp{} + return resp, nil +} + +func (s *userServer) DeleteUsers(_ context.Context, req *pbUser.DeleteUsersReq) (*pbUser.DeleteUsersResp, error) { + log.NewInfo(req.OperationID, "DeleteUsers args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + log.NewError(req.OperationID, "IsManagerUserID false ", req.OpUserID) + return &pbUser.DeleteUsersResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}, FailedUserIDList: req.DeleteUserIDList}, nil + } + var common pbUser.CommonResp + resp := pbUser.DeleteUsersResp{CommonResp: &common} + for _, userID := range req.DeleteUserIDList { + i := imdb.DeleteUser(userID) + if i == 0 { + log.NewError(req.OperationID, "delete user error", userID) + common.ErrCode = 201 + common.ErrMsg = "some uid deleted failed" + resp.FailedUserIDList = append(resp.FailedUserIDList, userID) + } + } + log.NewInfo(req.OperationID, "DeleteUsers rpc return ", resp.String()) + return &resp, nil +} + +func (s *userServer) GetAllUserID(_ context.Context, req *pbUser.GetAllUserIDReq) (*pbUser.GetAllUserIDResp, error) { + log.NewInfo(req.OperationID, "GetAllUserID args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + log.NewError(req.OperationID, "IsManagerUserID false ", req.OpUserID) + return &pbUser.GetAllUserIDResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + uidList, err := imdb.SelectAllUserID() + if err != nil { + log.NewError(req.OperationID, "SelectAllUserID false ", err.Error()) + return &pbUser.GetAllUserIDResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } else { + log.NewInfo(req.OperationID, "GetAllUserID rpc return ", pbUser.GetAllUserIDResp{CommonResp: &pbUser.CommonResp{}, UserIDList: uidList}) + return &pbUser.GetAllUserIDResp{CommonResp: &pbUser.CommonResp{}, UserIDList: uidList}, nil + } +} + +func (s *userServer) AccountCheck(_ context.Context, req *pbUser.AccountCheckReq) (*pbUser.AccountCheckResp, error) { + log.NewInfo(req.OperationID, "AccountCheck args ", req.String()) + if !token_verify.IsManagerUserID(req.OpUserID) { + log.NewError(req.OperationID, "IsManagerUserID false ", req.OpUserID) + return &pbUser.AccountCheckResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + uidList, err := imdb.SelectSomeUserID(req.CheckUserIDList) + log.NewDebug(req.OperationID, "from db uid list is:", uidList) + if err != nil { + log.NewError(req.OperationID, "SelectSomeUserID failed ", err.Error(), req.CheckUserIDList) + return &pbUser.AccountCheckResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } else { + var r []*pbUser.AccountCheckResp_SingleUserStatus + for _, v := range req.CheckUserIDList { + temp := new(pbUser.AccountCheckResp_SingleUserStatus) + temp.UserID = v + if utils.IsContain(v, uidList) { + temp.AccountStatus = constant.Registered + } else { + temp.AccountStatus = constant.UnRegistered + } + r = append(r, temp) + } + resp := pbUser.AccountCheckResp{CommonResp: &pbUser.CommonResp{ErrCode: 0, ErrMsg: ""}, ResultList: r} + log.NewInfo(req.OperationID, "AccountCheck rpc return ", resp.String()) + return &resp, nil + } + +} + +func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbUser.UpdateUserInfoReq) (*pbUser.UpdateUserInfoResp, error) { + log.NewInfo(req.OperationID, "UpdateUserInfo args ", req.String()) + if !token_verify.CheckAccess(req.OpUserID, req.UserInfo.UserID) { + log.NewError(req.OperationID, "CheckAccess false ", req.OpUserID, req.UserInfo.UserID) + return &pbUser.UpdateUserInfoResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrAccess.ErrCode, ErrMsg: constant.ErrAccess.ErrMsg}}, nil + } + + var user db.User + utils.CopyStructFields(&user, req.UserInfo) + if req.UserInfo.Birth != 0 { + user.Birth = utils.UnixSecondToTime(int64(req.UserInfo.Birth)) + } + err := imdb.UpdateUserInfo(user) + if err != nil { + log.NewError(req.OperationID, "UpdateUserInfo failed ", err.Error(), user) + return &pbUser.UpdateUserInfoResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: constant.ErrDB.ErrMsg}}, nil + } + etcdConn := getcdv3.GetConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImFriendName) + client := pbFriend.NewFriendClient(etcdConn) + newReq := &pbFriend.GetFriendListReq{ + CommID: &pbFriend.CommID{OperationID: req.OperationID, FromUserID: req.UserInfo.UserID, OpUserID: req.OpUserID}, + } + + RpcResp, err := client.GetFriendList(context.Background(), newReq) + if err != nil { + log.NewError(req.OperationID, "GetFriendList failed ", err.Error(), newReq) + return &pbUser.UpdateUserInfoResp{CommonResp: &pbUser.CommonResp{}}, nil + } + for _, v := range RpcResp.FriendInfoList { + log.Info(req.OperationID, "UserInfoUpdatedNotification ", req.UserInfo.UserID, v.FriendUser.UserID) + chat.UserInfoUpdatedNotification(req.OperationID, req.UserInfo.UserID, v.FriendUser.UserID) + } + chat.UserInfoUpdatedNotification(req.OperationID, req.UserInfo.UserID, req.OpUserID) + log.Info(req.OperationID, "UserInfoUpdatedNotification ", req.UserInfo.UserID, req.OpUserID) + return &pbUser.UpdateUserInfoResp{CommonResp: &pbUser.CommonResp{}}, nil +} + +func (s *userServer) GetUsersByName(ctx context.Context, req *pbUser.GetUsersByNameReq) (*pbUser.GetUsersByNameResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req.String()) + resp := &pbUser.GetUsersByNameResp{} + users, err := imdb.GetUserByName(req.UserName, req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUserByName failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + for _, user := range users { + isBlock, err := imdb.UserIsBlock(user.UserID) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error()) + continue + } + resp.Users = append(resp.Users, &pbUser.User{ + ProfilePhoto: user.FaceURL, + Nickname: user.Nickname, + UserId: user.UserID, + CreateTime: user.CreateTime.String(), + IsBlock: isBlock, + }) + } + user := db.User{Nickname: req.UserName} + userNums, err := imdb.GetUsersCount(user) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.UserNums = userNums + resp.Pagination = &sdkws.ResponsePagination{ + CurrentPage: req.Pagination.PageNumber, + ShowNumber: req.Pagination.ShowNumber, + } + return resp, nil +} + +func (s *userServer) GetUserById(ctx context.Context, req *pbUser.GetUserByIdReq) (*pbUser.GetUserByIdResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req.String()) + resp := &pbUser.GetUserByIdResp{User: &pbUser.User{}} + user, err := imdb.GetUserByUserID(req.UserId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + return resp, errors.WrapError(constant.ErrDB) + } + isBlock, err := imdb.UserIsBlock(req.UserId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "req:", req.String()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.User = &pbUser.User{ + ProfilePhoto: user.FaceURL, + Nickname: user.Nickname, + UserId: user.UserID, + CreateTime: user.CreateTime.String(), + IsBlock: isBlock, + } + return resp, nil +} + +func (s *userServer) GetUsers(ctx context.Context, req *pbUser.GetUsersReq) (*pbUser.GetUsersResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String()) + resp := &pbUser.GetUsersResp{User: []*pbUser.User{}} + users, err := imdb.GetUsers(req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + return resp, errors.WrapError(constant.ErrDB) + } + for _, v := range users { + isBlock, err := imdb.UserIsBlock(v.UserID) + if err == nil { + user := &pbUser.User{ + ProfilePhoto: v.FaceURL, + UserId: v.UserID, + CreateTime: v.CreateTime.String(), + Nickname: v.Nickname, + IsBlock: isBlock, + } + resp.User = append(resp.User, user) + } + } + user := db.User{} + nums, err := imdb.GetUsersCount(user) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetUsersCount failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.UserNums = nums + resp.Pagination = &sdkws.ResponsePagination{ShowNumber: req.Pagination.ShowNumber, CurrentPage: req.Pagination.PageNumber} + return resp, nil +} + +func (s *userServer) ResignUser(ctx context.Context, req *pbUser.ResignUserReq) (*pbUser.ResignUserResp, error) { + log.NewInfo(req.OperationID, "ResignUser args ", req.String()) + return &pbUser.ResignUserResp{}, nil +} + +func (s *userServer) AlterUser(ctx context.Context, req *pbUser.AlterUserReq) (*pbUser.AlterUserResp, error) { + log.NewInfo(req.OperationID, "AlterUser args ", req.String()) + resp := &pbUser.AlterUserResp{} + user := db.User{ + PhoneNumber: strconv.FormatInt(req.PhoneNumber, 10), + Nickname: req.Nickname, + Email: req.Email, + UserID: req.UserId, + } + if err := imdb.UpdateUserInfo(user); err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "UpdateUserInfo", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + chat.UserInfoUpdatedNotification(req.OperationID, req.UserId, req.OpUserId) + return resp, nil +} + +func (s *userServer) AddUser(ctx context.Context, req *pbUser.AddUserReq) (*pbUser.AddUserResp, error) { + log.NewInfo(req.OperationID, "AddUser args ", req.String()) + resp := &pbUser.AddUserResp{} + err := imdb.AddUser(req.UserId, req.PhoneNumber, req.Name) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "AddUser", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + return resp, nil +} + +func (s *userServer) BlockUser(ctx context.Context, req *pbUser.BlockUserReq) (*pbUser.BlockUserResp, error) { + log.NewInfo(req.OperationID, "BlockUser args ", req.String()) + fmt.Println("BlockUser args ", req.String()) + resp := &pbUser.BlockUserResp{} + err := imdb.BlockUser(req.UserId, req.EndDisableTime) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "BlockUser", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + return resp, nil +} + +func (s *userServer) UnBlockUser(ctx context.Context, req *pbUser.UnBlockUserReq) (*pbUser.UnBlockUserResp, error) { + log.NewInfo(req.OperationID, "UnBlockUser args ", req.String()) + resp := &pbUser.UnBlockUserResp{} + err := imdb.UnBlockUser(req.UserId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "unBlockUser", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + return resp, nil +} + +func (s *userServer) GetBlockUsers(ctx context.Context, req *pbUser.GetBlockUsersReq) (*pbUser.GetBlockUsersResp, error) { + log.NewInfo(req.OperationID, "GetBlockUsers args ", req.String()) + resp := &pbUser.GetBlockUsersResp{} + blockUsers, err := imdb.GetBlockUsers(req.Pagination.ShowNumber, req.Pagination.PageNumber) + if err != nil { + log.Error(req.OperationID, utils.GetSelfFuncName(), "GetBlockUsers", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + for _, v := range blockUsers { + resp.BlockUsers = append(resp.BlockUsers, &pbUser.BlockUser{ + User: &pbUser.User{ + ProfilePhoto: v.User.FaceURL, + Nickname: v.User.Nickname, + UserId: v.User.UserID, + IsBlock: true, + }, + BeginDisableTime: (v.BeginDisableTime).String(), + EndDisableTime: (v.EndDisableTime).String(), + }) + } + resp.Pagination = &sdkws.ResponsePagination{} + resp.Pagination.ShowNumber = req.Pagination.ShowNumber + resp.Pagination.CurrentPage = req.Pagination.PageNumber + nums, err := imdb.GetBlockUsersNumCount() + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetBlockUsersNumCount failed", err.Error()) + return resp, errors.WrapError(constant.ErrDB) + } + resp.UserNums = nums + return resp, nil +} + +func (s *userServer) GetBlockUserById(_ context.Context, req *pbUser.GetBlockUserByIdReq) (*pbUser.GetBlockUserByIdResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "GetBlockUserById args ", req.String()) + resp := &pbUser.GetBlockUserByIdResp{} + user, err := imdb.GetBlockUserById(req.UserId) + if err != nil { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetBlockUserById", err) + return resp, errors.WrapError(constant.ErrDB) + } + resp.BlockUser = &pbUser.BlockUser{ + User: &pbUser.User{ + ProfilePhoto: user.User.FaceURL, + Nickname: user.User.Nickname, + UserId: user.User.UserID, + IsBlock: true, + }, + BeginDisableTime: (user.BeginDisableTime).String(), + EndDisableTime: (user.EndDisableTime).String(), + } + return resp, nil +} + +func (s *userServer) DeleteUser(_ context.Context, req *pbUser.DeleteUserReq) (*pbUser.DeleteUserResp, error) { + log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req.String()) + resp := &pbUser.DeleteUserResp{} + if row := imdb.DeleteUser(req.UserId); row == 0 { + log.NewError(req.OperationID, utils.GetSelfFuncName(), "delete failed", "delete rows:", row) + return resp, errors.WrapError(constant.ErrDB) + } + return resp, nil +} diff --git a/internal/timed_task/init.go b/internal/timed_task/init.go new file mode 100644 index 000000000..8ee5d9452 --- /dev/null +++ b/internal/timed_task/init.go @@ -0,0 +1,26 @@ +package timed_task + +type TimeTask struct { + delMgoChatChan chan bool +} + +var timeTask TimeTask + +func GetInstance() *TimeTask { + if timeTask.delMgoChatChan == nil { + timeTask.delMgoChatChan = make(chan bool) + go func() { + timeTask.delMgoChatChan <- true + }() + } + return &timeTask +} + +func (t *TimeTask) Run() { + for { + select { + case <-t.delMgoChatChan: + t.timedDeleteUserChat() + } + } +} diff --git a/internal/timed_task/timed_task.go b/internal/timed_task/timed_task.go new file mode 100644 index 000000000..5b0264123 --- /dev/null +++ b/internal/timed_task/timed_task.go @@ -0,0 +1,26 @@ +package timed_task + +import ( + "Open_IM/pkg/common/db" + "time" +) + +func (t *TimeTask) timedDeleteUserChat() { + now := time.Now() + next := now.Add(time.Hour * 24) + next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location()) + tm := time.NewTimer(next.Sub(now)) + + <-tm.C + + count, _ := db.DB.MgoUserCount() + for i := 0; i < count; i++ { + time.Sleep(10 * time.Millisecond) + uid, _ := db.DB.MgoSkipUID(i) + db.DB.DelUserChatMongo2(uid) + } + + go func() { + t.delMgoChatChan <- true + }() +} diff --git a/internal/utils/callback.go b/internal/utils/callback.go new file mode 100644 index 000000000..d4b585bf7 --- /dev/null +++ b/internal/utils/callback.go @@ -0,0 +1 @@ +package utils diff --git a/internal/utils/cors_middleware_test.go b/internal/utils/cors_middleware_test.go new file mode 100644 index 000000000..248cc1ca0 --- /dev/null +++ b/internal/utils/cors_middleware_test.go @@ -0,0 +1,68 @@ +package utils + +import ( + "Open_IM/pkg/utils" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" +) + +func init() { + gin.SetMode(gin.TestMode) +} + +func performRequest(r http.Handler, method, origin string) *httptest.ResponseRecorder { + return performRequestWithHeaders(r, method, origin, http.Header{}) +} + +func performRequestWithHeaders(r http.Handler, method, origin string, header http.Header) *httptest.ResponseRecorder { + req, _ := http.NewRequest(method, "/", nil) + // From go/net/http/request.go: + // For incoming requests, the Host header is promoted to the + // Request.Host field and removed from the Header map. + req.Host = header.Get("Host") + header.Del("Host") + if len(origin) > 0 { + header.Set("Origin", origin) + } + req.Header = header + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func newTestRouter() *gin.Engine { + router := gin.New() + router.Use(utils.CorsHandler()) + router.GET("/", func(c *gin.Context) { + c.String(http.StatusOK, "get") + }) + router.POST("/", func(c *gin.Context) { + c.String(http.StatusOK, "post") + }) + router.PATCH("/", func(c *gin.Context) { + c.String(http.StatusOK, "patch") + }) + + return router +} + +func Test_CorsHandler(t *testing.T) { + router := newTestRouter() + // no CORS request, origin == "" + w := performRequest(router, "GET", "") + assert.Equal(t, "get", w.Body.String()) + assert.Equal(t, w.Header().Get("Access-Control-Allow-Origin"), "*") + assert.Equal(t, w.Header().Get("Access-Control-Allow-Methods"), "*") + assert.Equal(t, w.Header().Get("Access-Control-Allow-Headers"), "*") + assert.Equal(t, w.Header().Get("Access-Control-Expose-Headers"), "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") + assert.Equal(t, w.Header().Get("Access-Control-Max-Age"), "172800") + assert.Equal(t, w.Header().Get("Access-Control-Allow-Credentials"), "false") + assert.Equal(t, w.Header().Get("content-type"), "application/json") + + w = performRequest(router, "OPTIONS", "") + assert.Equal(t, w.Body.String(), "\"Options Request!\"") +} diff --git a/internal/utils/get_server_ip_test.go b/internal/utils/get_server_ip_test.go new file mode 100644 index 000000000..de15537cb --- /dev/null +++ b/internal/utils/get_server_ip_test.go @@ -0,0 +1,13 @@ +package utils + +import ( + "Open_IM/pkg/utils" + "net" + "testing" +) + +func TestServerIP(t *testing.T) { + if net.ParseIP(utils.ServerIP) == nil { + t.Fail() + } +} diff --git a/internal/utils/id.go b/internal/utils/id.go new file mode 100644 index 000000000..509578df7 --- /dev/null +++ b/internal/utils/id.go @@ -0,0 +1,28 @@ +package utils + +import ( + "github.com/bwmarrin/snowflake" +) + +func init() { + var err error + idGenerator, err = snowflake.NewNode(getNodeNum()) + if err != nil { + panic(err) + } +} + +func getNodeNum() int64 { + return 1 +} + +var idGenerator *snowflake.Node + +func GenID() string { + return idGenerator.Generate().String() +} + +func GenIDs(count int) []string { + //impl + return []string{} +} diff --git a/internal/utils/id_test.go b/internal/utils/id_test.go new file mode 100644 index 000000000..3c0d5938e --- /dev/null +++ b/internal/utils/id_test.go @@ -0,0 +1,15 @@ +package utils + +import "testing" + +func TestGenID(t *testing.T) { + m := map[string]struct{}{} + for i := 0; i < 2000; i++ { + got := GenID() + if _, ok := m[got]; !ok { + m[got] = struct{}{} + } else { + t.Error("id generate error", got) + } + } +} diff --git a/internal/utils/image_test.go b/internal/utils/image_test.go new file mode 100644 index 000000000..ab328fbc4 --- /dev/null +++ b/internal/utils/image_test.go @@ -0,0 +1,28 @@ +package utils + +import ( + "Open_IM/pkg/utils" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + _, b, _, _ = runtime.Caller(0) + // Root folder of this project + Root = filepath.Join(filepath.Dir(b), "../..") +) + +func Test_GenSmallImage(t *testing.T) { + println(Root) + err := utils.GenSmallImage(Root+"/docs/open-im-logo.png", Root+"/out-test/open-im-logo-test.png") + assert.Nil(t, err) + + err = utils.GenSmallImage(Root+"/docs/open-im-logo.png", "out-test/open-im-logo-test.png") + assert.Nil(t, err) + + err = utils.GenSmallImage(Root+"/docs/Architecture.jpg", "out-test/Architecture-test.jpg") + assert.Nil(t, err) +} diff --git a/internal/utils/jwt_token_test.go b/internal/utils/jwt_token_test.go new file mode 100644 index 000000000..da53a2a36 --- /dev/null +++ b/internal/utils/jwt_token_test.go @@ -0,0 +1,89 @@ +package utils + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/token_verify" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_BuildClaims(t *testing.T) { + uid := "1" + platform := "PC" + ttl := int64(-1) + claim := token_verify.BuildClaims(uid, platform, ttl) + now := time.Now().Unix() + + assert.Equal(t, claim.UID, uid, "uid should equal") + assert.Equal(t, claim.Platform, platform, "platform should equal") + assert.Equal(t, claim.RegisteredClaims.ExpiresAt, int64(-1), "StandardClaims.ExpiresAt should be equal") + // time difference within 1s + assert.Equal(t, claim.RegisteredClaims.IssuedAt, now, "StandardClaims.IssuedAt should be equal") + assert.Equal(t, claim.RegisteredClaims.NotBefore, now, "StandardClaims.NotBefore should be equal") + + ttl = int64(60) + now = time.Now().Unix() + claim = token_verify.BuildClaims(uid, platform, ttl) + // time difference within 1s + assert.Equal(t, claim.RegisteredClaims.ExpiresAt, int64(60)+now, "StandardClaims.ExpiresAt should be equal") + assert.Equal(t, claim.RegisteredClaims.IssuedAt, now, "StandardClaims.IssuedAt should be equal") + assert.Equal(t, claim.RegisteredClaims.NotBefore, now, "StandardClaims.NotBefore should be equal") +} + +func Test_CreateToken(t *testing.T) { + uid := "1" + platform := int32(1) + now := time.Now().Unix() + + tokenString, expiresAt, err := token_verify.CreateToken(uid, platform) + + assert.NotEmpty(t, tokenString) + assert.Equal(t, expiresAt, 604800+now) + assert.Nil(t, err) +} + +func Test_VerifyToken(t *testing.T) { + uid := "1" + platform := int32(1) + tokenString, _, _ := token_verify.CreateToken(uid, platform) + result, _ := token_verify.VerifyToken(tokenString, uid) + assert.True(t, result) + result, _ = token_verify.VerifyToken(tokenString, "2") + assert.False(t, result) +} + +func Test_ParseRedisInterfaceToken(t *testing.T) { + uid := "1" + platform := int32(1) + tokenString, _, _ := token_verify.CreateToken(uid, platform) + + claims, err := token_verify.ParseRedisInterfaceToken([]uint8(tokenString)) + assert.Nil(t, err) + assert.Equal(t, claims.UID, uid) + + // timeout + config.Config.TokenPolicy.AccessExpire = -80 + tokenString, _, _ = token_verify.CreateToken(uid, platform) + claims, err = token_verify.ParseRedisInterfaceToken([]uint8(tokenString)) + assert.Equal(t, err, constant.ExpiredToken) + assert.Nil(t, claims) +} + +func Test_ParseToken(t *testing.T) { + uid := "1" + platform := int32(1) + tokenString, _, _ := token_verify.CreateToken(uid, platform) + claims, err := token_verify.ParseToken(tokenString, "") + if err == nil { + assert.Equal(t, claims.UID, uid) + } +} +func Test_GetClaimFromToken(t *testing.T) { + token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVSUQiOiJvcGVuSU0xMjM0NTYiLCJQbGF0Zm9ybSI6IiIsImV4cCI6MTYzODg0NjQ3NiwibmJmIjoxNjM4MjQxNjc2LCJpYXQiOjE2MzgyNDE2NzZ9.W8RZB7ec5ySFj-rGE2Aho2z32g3MprQMdCyPiQu_C2I" + c, err := token_verify.GetClaimFromToken(token) + assert.Nil(t, c) + assert.Nil(t, err) +} diff --git a/internal/utils/md5_test.go b/internal/utils/md5_test.go new file mode 100644 index 000000000..4db7bd854 --- /dev/null +++ b/internal/utils/md5_test.go @@ -0,0 +1,16 @@ +package utils + +import ( + "Open_IM/pkg/utils" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Md5(t *testing.T) { + result := utils.Md5("go") + assert.Equal(t, result, "34d1f91fb2e514b8576fab1a75a89a6b") + + result2 := utils.Md5("go") + assert.Equal(t, result, result2) +} diff --git a/internal/utils/platform_number_id_to_name_test.go b/internal/utils/platform_number_id_to_name_test.go new file mode 100644 index 000000000..8a956bfac --- /dev/null +++ b/internal/utils/platform_number_id_to_name_test.go @@ -0,0 +1,46 @@ +package utils + +import ( + "Open_IM/pkg/common/constant" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_PlatformIDToName(t *testing.T) { + assert.Equal(t, constant.PlatformIDToName(1), "IOS") + assert.Equal(t, constant.PlatformIDToName(2), "Android") + assert.Equal(t, constant.PlatformIDToName(3), "Windows") + assert.Equal(t, constant.PlatformIDToName(4), "OSX") + assert.Equal(t, constant.PlatformIDToName(5), "Web") + assert.Equal(t, constant.PlatformIDToName(6), "MiniWeb") + assert.Equal(t, constant.PlatformIDToName(7), "Linux") + + assert.Equal(t, constant.PlatformIDToName(0), "") +} + +func Test_PlatformNameToID(t *testing.T) { + assert.Equal(t, constant.PlatformNameToID("IOS"), int32(1)) + assert.Equal(t, constant.PlatformNameToID("Android"), int32(2)) + assert.Equal(t, constant.PlatformNameToID("Windows"), int32(3)) + assert.Equal(t, constant.PlatformNameToID("OSX"), int32(4)) + assert.Equal(t, constant.PlatformNameToID("Web"), int32(5)) + assert.Equal(t, constant.PlatformNameToID("MiniWeb"), int32(6)) + assert.Equal(t, constant.PlatformNameToID("Linux"), int32(7)) + + assert.Equal(t, constant.PlatformNameToID("UnknownDevice"), int32(0)) + assert.Equal(t, constant.PlatformNameToID(""), int32(0)) +} + +func Test_PlatformNameToClass(t *testing.T) { + assert.Equal(t, constant.PlatformNameToClass("IOS"), "Mobile") + assert.Equal(t, constant.PlatformNameToClass("Android"), "Mobile") + assert.Equal(t, constant.PlatformNameToClass("OSX"), "PC") + assert.Equal(t, constant.PlatformNameToClass("Windows"), "PC") + assert.Equal(t, constant.PlatformNameToClass("Web"), "PC") + assert.Equal(t, constant.PlatformNameToClass("MiniWeb"), "Mobile") + assert.Equal(t, constant.PlatformNameToClass("Linux"), "PC") + + assert.Equal(t, constant.PlatformNameToClass("UnknownDevice"), "") + assert.Equal(t, constant.PlatformNameToClass(""), "") +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go new file mode 100644 index 000000000..73ebbf127 --- /dev/null +++ b/internal/utils/utils.go @@ -0,0 +1,49 @@ +package utils + +import ( + "encoding/json" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "reflect" +) + +func JsonDataList(resp interface{}) []map[string]interface{} { + var list []proto.Message + if reflect.TypeOf(resp).Kind() == reflect.Slice { + s := reflect.ValueOf(resp) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + list = append(list, ele.Interface().(proto.Message)) + } + } + + result := make([]map[string]interface{}, 0) + for _, v := range list { + m := ProtoToMap(v, false) + result = append(result, m) + } + return result +} + +func JsonDataOne(pb proto.Message) map[string]interface{} { + return ProtoToMap(pb, false) +} + +func ProtoToMap(pb proto.Message, idFix bool) map[string]interface{} { + marshaler := jsonpb.Marshaler{ + OrigName: true, + EnumsAsInts: false, + EmitDefaults: false, + } + + s, _ := marshaler.MarshalToString(pb) + out := make(map[string]interface{}) + json.Unmarshal([]byte(s), &out) + if idFix { + if _, ok := out["id"]; ok { + out["_id"] = out["id"] + delete(out, "id") + } + } + return out +} diff --git a/pkg/base_info/auth_api_struct.go b/pkg/base_info/auth_api_struct.go new file mode 100644 index 000000000..13d6e140b --- /dev/null +++ b/pkg/base_info/auth_api_struct.go @@ -0,0 +1,39 @@ +package base_info + +//UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` +// Nickname string `protobuf:"bytes,2,opt,name=Nickname" json:"Nickname,omitempty"` +// FaceUrl string `protobuf:"bytes,3,opt,name=FaceUrl" json:"FaceUrl,omitempty"` +// Gender int32 `protobuf:"varint,4,opt,name=Gender" json:"Gender,omitempty"` +// PhoneNumber string `protobuf:"bytes,5,opt,name=PhoneNumber" json:"PhoneNumber,omitempty"` +// Birth string `protobuf:"bytes,6,opt,name=Birth" json:"Birth,omitempty"` +// Email string `protobuf:"bytes,7,opt,name=Email" json:"Email,omitempty"` +// Ex string `protobuf:"bytes,8,opt,name=Ex" json:"Ex,omitempty"` + +type UserRegisterReq struct { + Secret string `json:"secret" binding:"required,max=32"` + Platform int32 `json:"platform" binding:"required,min=1,max=7"` + ApiUserInfo + OperationID string `json:"operationID" binding:"required"` +} + +type UserTokenInfo struct { + UserID string `json:"userID"` + Token string `json:"token"` + ExpiredTime int64 `json:"expiredTime"` +} +type UserRegisterResp struct { + CommResp + UserToken UserTokenInfo `json:"data"` +} + +type UserTokenReq struct { + Secret string `json:"secret" binding:"required,max=32"` + Platform int32 `json:"platform" binding:"required,min=1,max=8"` + UserID string `json:"userID" binding:"required,min=1,max=64"` + OperationID string `json:"operationID" binding:"required"` +} + +type UserTokenResp struct { + CommResp + UserToken UserTokenInfo `json:"data"` +} diff --git a/pkg/base_info/conversation_api_struct.go b/pkg/base_info/conversation_api_struct.go new file mode 100644 index 000000000..10b46f547 --- /dev/null +++ b/pkg/base_info/conversation_api_struct.go @@ -0,0 +1,117 @@ +package base_info + +type OptResult struct { + ConversationID string `json:"conversationID"` + Result *int32 `json:"result"` +} +type GetAllConversationMessageOptReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetAllConversationMessageOptResp struct { + CommResp + ConversationOptResultList []*OptResult `json:"data"` +} +type GetReceiveMessageOptReq struct { + ConversationIDList []string `json:"conversationIDList" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetReceiveMessageOptResp struct { + CommResp + ConversationOptResultList []*OptResult `json:"data"` +} +type SetReceiveMessageOptReq struct { + FromUserID string `json:"fromUserID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + Opt *int32 `json:"opt" binding:"required"` + ConversationIDList []string `json:"conversationIDList" binding:"required"` +} +type SetReceiveMessageOptResp struct { + CommResp + ConversationOptResultList []*OptResult `json:"data"` +} + +type Conversation struct { + OwnerUserID string `json:"ownerUserID" binding:"required"` + ConversationID string `json:"conversationID" binding:"required"` + ConversationType int32 `json:"conversationType" binding:"required"` + UserID string `json:"userID"` + GroupID string `json:"groupID"` + RecvMsgOpt int32 `json:"recvMsgOpt" binding:"omitempty,oneof=0 1 2"` + UnreadCount int32 `json:"unreadCount" binding:"omitempty"` + DraftTextTime int64 `json:"draftTextTime"` + IsPinned bool `json:"isPinned" binding:"omitempty"` + IsPrivateChat bool `json:"isPrivateChat"` + AttachedInfo string `json:"attachedInfo"` + Ex string `json:"ex"` +} + +type SetConversationReq struct { + Conversation + NotificationType int32 `json:"notificationType"` + OperationID string `json:"operationID" binding:"required"` +} + +type SetConversationResp struct { + CommResp +} + +type BatchSetConversationsReq struct { + Conversations []Conversation `json:"conversations" binding:"required"` + NotificationType int32 `json:"notificationType"` + OwnerUserID string `json:"ownerUserID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type BatchSetConversationsResp struct { + CommResp + Data struct { + Success []string `json:"success"` + Failed []string `json:"failed"` + } `json:"data"` +} + +type GetConversationReq struct { + ConversationID string `json:"conversationID" binding:"required"` + OwnerUserID string `json:"ownerUserID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type GetConversationResp struct { + CommResp + Conversation Conversation `json:"data"` +} + +type GetAllConversationsReq struct { + OwnerUserID string `json:"ownerUserID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type GetAllConversationsResp struct { + CommResp + Conversations []Conversation `json:"data"` +} + +type GetConversationsReq struct { + ConversationIDs []string `json:"conversationIDs" binding:"required"` + OwnerUserID string `json:"ownerUserID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type GetConversationsResp struct { + CommResp + Conversations []Conversation `json:"data"` +} + +type SetRecvMsgOptReq struct { + OwnerUserID string `json:"ownerUserID" binding:"required"` + ConversationID string `json:"conversationID"` + RecvMsgOpt int32 `json:"recvMsgOpt" binding:"omitempty,oneof=0 1 2"` + OperationID string `json:"operationID" binding:"required"` + NotificationType int32 `json:"notificationType"` +} + +type SetRecvMsgOptResp struct { + CommResp +} diff --git a/pkg/base_info/cos_api_struct.go b/pkg/base_info/cos_api_struct.go new file mode 100644 index 000000000..e35931ad9 --- /dev/null +++ b/pkg/base_info/cos_api_struct.go @@ -0,0 +1,20 @@ +package base_info + +import sts "github.com/tencentyun/qcloud-cos-sts-sdk/go" + +type TencentCloudStorageCredentialReq struct { + OperationID string `json:"operationID"` +} + +type TencentCloudStorageCredentialRespData struct { + *sts.CredentialResult + Region string `json:"region"` + Bucket string `json:"bucket"` +} + +type TencentCloudStorageCredentialResp struct { + CommResp + CosData TencentCloudStorageCredentialRespData `json:"-"` + + Data map[string]interface{} `json:"data"` +} diff --git a/pkg/base_info/friend_api_struct.go b/pkg/base_info/friend_api_struct.go new file mode 100644 index 000000000..3c45c393e --- /dev/null +++ b/pkg/base_info/friend_api_struct.go @@ -0,0 +1,136 @@ +package base_info + +import open_im_sdk "Open_IM/pkg/proto/sdk_ws" + +type ParamsCommFriend struct { + OperationID string `json:"operationID" binding:"required"` + ToUserID string `json:"toUserID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} + +type AddBlacklistReq struct { + ParamsCommFriend +} +type AddBlacklistResp struct { + CommResp +} + +type ImportFriendReq struct { + FriendUserIDList []string `json:"friendUserIDList" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type UserIDResult struct { + UserID string `json:"userID"` + Result int32 `json:"result"` +} +type ImportFriendResp struct { + CommResp + UserIDResultList []UserIDResult `json:"data"` +} + +type AddFriendReq struct { + ParamsCommFriend + ReqMsg string `json:"reqMsg"` +} +type AddFriendResp struct { + CommResp +} + +type AddFriendResponseReq struct { + ParamsCommFriend + Flag int32 `json:"flag" binding:"required,oneof=-1 0 1"` + HandleMsg string `json:"handleMsg"` +} +type AddFriendResponseResp struct { + CommResp +} + +type DeleteFriendReq struct { + ParamsCommFriend +} +type DeleteFriendResp struct { + CommResp +} + +type GetBlackListReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetBlackListResp struct { + CommResp + BlackUserInfoList []*open_im_sdk.PublicUserInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +//type PublicUserInfo struct { +// UserID string `json:"userID"` +// Nickname string `json:"nickname"` +// FaceUrl string `json:"faceUrl"` +// Gender int32 `json:"gender"` +//} + +type SetFriendRemarkReq struct { + ParamsCommFriend + Remark string `json:"remark" binding:"required"` +} +type SetFriendRemarkResp struct { + CommResp +} + +type RemoveBlackListReq struct { + ParamsCommFriend +} +type RemoveBlackListResp struct { + CommResp +} + +type IsFriendReq struct { + ParamsCommFriend +} +type Response struct { + Friend bool `json:"isFriend"` +} +type IsFriendResp struct { + CommResp + Response Response `json:"data"` +} + +type GetFriendsInfoReq struct { + ParamsCommFriend +} +type GetFriendsInfoResp struct { + CommResp + FriendInfoList []*open_im_sdk.FriendInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type GetFriendListReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetFriendListResp struct { + CommResp + FriendInfoList []*open_im_sdk.FriendInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type GetFriendApplyListReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetFriendApplyListResp struct { + CommResp + FriendRequestList []*open_im_sdk.FriendRequest `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type GetSelfApplyListReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetSelfApplyListResp struct { + CommResp + FriendRequestList []*open_im_sdk.FriendRequest `json:"-"` + Data []map[string]interface{} `json:"data"` +} diff --git a/pkg/base_info/group_api_struct.go b/pkg/base_info/group_api_struct.go new file mode 100644 index 000000000..47b6a6c67 --- /dev/null +++ b/pkg/base_info/group_api_struct.go @@ -0,0 +1,222 @@ +package base_info + +import ( + open_im_sdk "Open_IM/pkg/proto/sdk_ws" +) + +type CommResp struct { + ErrCode int32 `json:"errCode"` + ErrMsg string `json:"errMsg"` +} + +type CommDataResp struct { + CommResp + Data []map[string]interface{} `json:"data"` +} + +type KickGroupMemberReq struct { + GroupID string `json:"groupID" binding:"required"` + KickedUserIDList []string `json:"kickedUserIDList" binding:"required"` + Reason string `json:"reason"` + OperationID string `json:"operationID" binding:"required"` +} +type KickGroupMemberResp struct { + CommResp + UserIDResultList []*UserIDResult `json:"data"` +} + +type GetGroupMembersInfoReq struct { + GroupID string `json:"groupID" binding:"required"` + MemberList []string `json:"memberList" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type GetGroupMembersInfoResp struct { + CommResp + MemberList []*open_im_sdk.GroupMemberFullInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type InviteUserToGroupReq struct { + GroupID string `json:"groupID" binding:"required"` + InvitedUserIDList []string `json:"invitedUserIDList" binding:"required"` + Reason string `json:"reason"` + OperationID string `json:"operationID" binding:"required"` +} +type InviteUserToGroupResp struct { + CommResp + UserIDResultList []*UserIDResult `json:"data"` +} + +type GetJoinedGroupListReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` +} +type GetJoinedGroupListResp struct { + CommResp + GroupInfoList []*open_im_sdk.GroupInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type GetGroupMemberListReq struct { + GroupID string `json:"groupID"` + Filter int32 `json:"filter"` + NextSeq int32 `json:"nextSeq"` + OperationID string `json:"operationID"` +} +type GetGroupMemberListResp struct { + CommResp + NextSeq int32 `json:"nextSeq"` + MemberList []*open_im_sdk.GroupMemberFullInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type GetGroupAllMemberReq struct { + GroupID string `json:"groupID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type GetGroupAllMemberResp struct { + CommResp + MemberList []*open_im_sdk.GroupMemberFullInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type CreateGroupReq struct { + MemberList []*GroupAddMemberInfo `json:"memberList" binding:"required"` + OwnerUserID string `json:"ownerUserID" binding:"required"` + GroupType int32 `json:"groupType"` + GroupName string `json:"groupName"` + Notification string `json:"notification"` + Introduction string `json:"introduction"` + FaceURL string `json:"faceURL"` + Ex string `json:"ex"` + OperationID string `json:"operationID" binding:"required"` +} +type CreateGroupResp struct { + CommResp + GroupInfo open_im_sdk.GroupInfo `json:"-"` + Data map[string]interface{} `json:"data"` +} + +type GetGroupApplicationListReq struct { + OperationID string `json:"operationID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` //作为管理员或群主收到的 进群申请 +} +type GetGroupApplicationListResp struct { + CommResp + GroupRequestList []*open_im_sdk.GroupRequest `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type GetUserReqGroupApplicationListReq struct { + OperationID string `json:"operationID" binding:"required"` + UserID string `json:"userID" binding:"required"` +} + +type GetUserRespGroupApplicationResp struct { + CommResp + GroupRequestList []*open_im_sdk.GroupRequest `json:"-"` +} + +type GetGroupInfoReq struct { + GroupIDList []string `json:"groupIDList" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type GetGroupInfoResp struct { + CommResp + GroupInfoList []*open_im_sdk.GroupInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type ApplicationGroupResponseReq struct { + OperationID string `json:"operationID" binding:"required"` + GroupID string `json:"groupID" binding:"required"` + FromUserID string `json:"fromUserID" binding:"required"` //application from FromUserID + HandledMsg string `json:"handledMsg"` + HandleResult int32 `json:"handleResult" binding:"required,oneof=-1 1"` +} +type ApplicationGroupResponseResp struct { + CommResp +} + +type JoinGroupReq struct { + GroupID string `json:"groupID" binding:"required"` + ReqMessage string `json:"reqMessage"` + OperationID string `json:"operationID" binding:"required"` +} +type JoinGroupResp struct { + CommResp +} + +type QuitGroupReq struct { + GroupID string `json:"groupID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type QuitGroupResp struct { + CommResp +} + +type SetGroupInfoReq struct { + GroupID string `json:"groupID" binding:"required"` + GroupName string `json:"groupName"` + Notification string `json:"notification"` + Introduction string `json:"introduction"` + FaceURL string `json:"faceURL"` + Ex string `json:"ex"` + OperationID string `json:"operationID" binding:"required"` +} +type SetGroupInfoResp struct { + CommResp +} + +type TransferGroupOwnerReq struct { + GroupID string `json:"groupID" binding:"required"` + OldOwnerUserID string `json:"oldOwnerUserID" binding:"required"` + NewOwnerUserID string `json:"newOwnerUserID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type TransferGroupOwnerResp struct { + CommResp +} + +type DismissGroupReq struct { + GroupID string `json:"groupID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type DismissGroupResp struct { + CommResp +} + +type MuteGroupMemberReq struct { + OperationID string `json:"operationID" binding:"required"` + GroupID string `json:"groupID" binding:"required"` + UserID string `json:"userID" binding:"required"` + MutedSeconds uint32 `json:"mutedSeconds" binding:"required"` +} +type MuteGroupMemberResp struct { + CommResp +} + +type CancelMuteGroupMemberReq struct { + OperationID string `json:"operationID" binding:"required"` + GroupID string `json:"groupID" binding:"required"` + UserID string `json:"userID" binding:"required"` +} +type CancelMuteGroupMemberResp struct { + CommResp +} + +type MuteGroupReq struct { + OperationID string `json:"operationID" binding:"required"` + GroupID string `json:"groupID" binding:"required"` +} +type MuteGroupResp struct { + CommResp +} + +type CancelMuteGroupReq struct { + OperationID string `json:"operationID" binding:"required"` + GroupID string `json:"groupID" binding:"required"` +} +type CancelMuteGroupResp struct { + CommResp +} diff --git a/pkg/base_info/manage_api_struct.go b/pkg/base_info/manage_api_struct.go new file mode 100644 index 000000000..4b2061b57 --- /dev/null +++ b/pkg/base_info/manage_api_struct.go @@ -0,0 +1,44 @@ +package base_info + +import ( + pbRelay "Open_IM/pkg/proto/relay" + "Open_IM/pkg/proto/sdk_ws" + pbUser "Open_IM/pkg/proto/user" +) + +type DeleteUsersReq struct { + OperationID string `json:"operationID" binding:"required"` + DeleteUserIDList []string `json:"deleteUserIDList" binding:"required"` +} +type DeleteUsersResp struct { + CommResp + FailedUserIDList []string `json:"data"` +} +type GetAllUsersUidReq struct { + OperationID string `json:"operationID" binding:"required"` +} +type GetAllUsersUidResp struct { + CommResp + UserIDList []string `json:"data"` +} +type GetUsersOnlineStatusReq struct { + OperationID string `json:"operationID" binding:"required"` + UserIDList []string `json:"userIDList" binding:"required,lte=200"` +} +type GetUsersOnlineStatusResp struct { + CommResp + SuccessResult []*pbRelay.GetUsersOnlineStatusResp_SuccessResult `json:"data"` +} +type AccountCheckReq struct { + OperationID string `json:"operationID" binding:"required"` + CheckUserIDList []string `json:"checkUserIDList" binding:"required,lte=100"` +} +type AccountCheckResp struct { + CommResp + ResultList []*pbUser.AccountCheckResp_SingleUserStatus `json:"data"` +} + +type ManagementSendMsgResp struct { + CommResp + ResultList server_api_params.UserSendMsgResp `json:"data"` +} diff --git a/pkg/base_info/minio_api_struct.go b/pkg/base_info/minio_api_struct.go new file mode 100644 index 000000000..6d3b0ecac --- /dev/null +++ b/pkg/base_info/minio_api_struct.go @@ -0,0 +1,25 @@ +package base_info + +type MinioStorageCredentialReq struct { + OperationID string `json:"operationID"` +} + +type MiniostorageCredentialResp struct { + SecretAccessKey string `json:"secretAccessKey"` + AccessKeyID string `json:"accessKeyID"` + SessionToken string `json:"sessionToken"` + BucketName string `json:"bucketName"` + StsEndpointURL string `json:"stsEndpointURL"` +} + +type MinioUploadFileReq struct { + OperationID string `form:"operationID" binding:"required"` + FileType int `form:"fileType" binding:"required"` +} + +type MinioUploadFileResp struct { + URL string `json:"URL"` + NewName string `json:"newName"` + SnapshotURL string `json:"snapshotURL,omitempty"` + SnapshotNewName string `json:"snapshotName,omitempty"` +} diff --git a/pkg/base_info/msg.go b/pkg/base_info/msg.go new file mode 100644 index 000000000..bc80cf304 --- /dev/null +++ b/pkg/base_info/msg.go @@ -0,0 +1,12 @@ +package base_info + +type DelMsgReq struct { + OpUserID string `json:"opUserID,omitempty"` + UserID string `json:"userID,omitempty"` + SeqList []uint32 `json:"seqList,omitempty"` + OperationID string `json:"operationID,omitempty"` +} + +type DelMsgResp struct { + CommResp +} diff --git a/pkg/base_info/office_struct.go b/pkg/base_info/office_struct.go new file mode 100644 index 000000000..e4dca230d --- /dev/null +++ b/pkg/base_info/office_struct.go @@ -0,0 +1,88 @@ +package base_info + +import ( + pbOffice "Open_IM/pkg/proto/office" +) + +type GetUserTagsReq struct { + OperationID string `json:"operationID" binding:"required"` +} + +type GetUserTagsResp struct { + CommResp + Data struct { + Tags []*pbOffice.Tag `json:"tags"` + } `json:"data"` +} + +type CreateTagReq struct { + TagName string `json:"tagName" binding:"required"` + UserIDList []string `json:"userIDList" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type CreateTagResp struct { + CommResp +} + +type DeleteTagReq struct { + TagID string `json:"tagID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type DeleteTagResp struct { + CommResp +} + +type SetTagReq struct { + TagID string `json:"tagID" binding:"required"` + NewName string `json:"newName"` + IncreaseUserIDList []string `json:"increaseUserIDList"` + ReduceUserIDList []string `json:"reduceUserIDList"` + OperationID string `json:"operationID" binding:"required"` +} + +type SetTagResp struct { + CommResp +} + +type SendMsg2TagReq struct { + TagList []string `json:"tagList"` + UserList []string `json:"userList"` + GroupList []string `json:"groupList"` + + SenderPlatformID int32 `json:"senderPlatformID" binding:"required"` + Content string `json:"content" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type SendMsg2TagResp struct { + CommResp +} + +type GetTagSendLogsReq struct { + PageNumber int32 `json:"pageNumber" binding:"required"` + ShowNumber int32 `json:"showNumber" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type GetTagSendLogsResp struct { + CommResp + Data struct { + Logs []*pbOffice.TagSendLog `json:"logs"` + CurrentPage int32 `json:"currentPage"` + ShowNumber int32 `json:"showNumber"` + } `json:"data"` +} + +type GetUserTagByIDReq struct { + TagID string `json:"tagID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} + +type GetUserTagByIDResp struct { + CommResp + Data struct { + Tag *pbOffice.Tag `json:"tag"` + } `json:"data"` +} diff --git a/pkg/base_info/organization_api_struct.go b/pkg/base_info/organization_api_struct.go new file mode 100644 index 000000000..c8c6babe8 --- /dev/null +++ b/pkg/base_info/organization_api_struct.go @@ -0,0 +1,110 @@ +package base_info + +import open_im_sdk "Open_IM/pkg/proto/sdk_ws" + +type CreateDepartmentReq struct { + *open_im_sdk.Department + OperationID string `json:"operationID" binding:"required"` +} +type CreateDepartmentResp struct { + CommResp + Department *open_im_sdk.Department `json:"-"` + Data map[string]interface{} `json:"data"` +} + +type UpdateDepartmentReq struct { + *open_im_sdk.Department + DepartmentID string `json:"departmentID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type UpdateDepartmentResp struct { + CommResp +} + +type GetSubDepartmentReq struct { + OperationID string `json:"operationID" binding:"required"` + DepartmentID string `json:"departmentID" binding:"required"` +} +type GetSubDepartmentResp struct { + CommResp + DepartmentList []*open_im_sdk.Department `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type DeleteDepartmentReq struct { + OperationID string `json:"operationID" binding:"required"` + DepartmentID string `json:"departmentID" binding:"required"` +} +type DeleteDepartmentResp struct { + CommResp +} + +type CreateOrganizationUserReq struct { + OperationID string `json:"operationID" binding:"required"` + OrganizationUser *open_im_sdk.OrganizationUser +} +type CreateOrganizationUserResp struct { + CommResp +} + +type UpdateOrganizationUserReq struct { + OperationID string `json:"operationID" binding:"required"` + OrganizationUser *open_im_sdk.OrganizationUser +} +type UpdateOrganizationUserResp struct { + CommResp +} + +type CreateDepartmentMemberReq struct { + OperationID string `json:"operationID" binding:"required"` + UserInDepartment *open_im_sdk.UserInDepartment +} + +type CreateDepartmentMemberResp struct { + CommResp +} + +type GetUserInDepartmentReq struct { + UserID string + OperationID string `json:"operationID" binding:"required"` +} +type GetUserInDepartmentResp struct { + CommResp + UserInDepartment *open_im_sdk.UserInDepartment `json:"-"` + Data map[string]interface{} `json:"data"` +} + +type UpdateUserInDepartmentReq struct { + OperationID string `json:"operationID" binding:"required"` + *open_im_sdk.DepartmentMember +} +type UpdateUserInDepartmentResp struct { + CommResp +} + +type DeleteOrganizationUserReq struct { + UserID string + OperationID string `json:"operationID" binding:"required"` +} +type DeleteOrganizationUserResp struct { + CommResp +} + +type GetDepartmentMemberReq struct { + DepartmentID string + OperationID string `json:"operationID" binding:"required"` +} +type GetDepartmentMemberResp struct { + CommResp + UserInDepartmentList []*open_im_sdk.UserInDepartment `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type DeleteUserInDepartmentReq struct { + DepartmentID string `json:"departmentID" binding:"required"` + UserID string `json:"userID" binding:"required"` + OperationID string `json:"operationID" binding:"required"` +} +type DeleteUserInDepartmentResp struct { + CommResp +} diff --git a/pkg/base_info/oss_api_struct.go b/pkg/base_info/oss_api_struct.go new file mode 100644 index 000000000..621d18820 --- /dev/null +++ b/pkg/base_info/oss_api_struct.go @@ -0,0 +1,22 @@ +package base_info + +type OSSCredentialReq struct { + OperationID string `json:"operationID"` + Filename string `json:"filename"` + FileType string `json:"file_type"` +} + +type OSSCredentialRespData struct { + Endpoint string `json:"endpoint"` + AccessKeyId string `json:"access_key_id"` + AccessKeySecret string `json:"access_key_secret"` + Token string `json:"token"` + Bucket string `json:"bucket"` + FinalHost string `json:"final_host"` +} + +type OSSCredentialResp struct { + CommResp + OssData OSSCredentialRespData `json:"-"` + Data map[string]interface{} `json:"data"` +} diff --git a/pkg/base_info/public_struct.go b/pkg/base_info/public_struct.go new file mode 100644 index 000000000..2950dbea8 --- /dev/null +++ b/pkg/base_info/public_struct.go @@ -0,0 +1,139 @@ +package base_info + +import ( + "github.com/gin-gonic/gin" + "net/http" +) + +type ApiUserInfo struct { + UserID string `json:"userID" binding:"required,min=1,max=64"` + Nickname string `json:"nickname" binding:"omitempty,min=1,max=64"` + FaceURL string `json:"faceURL" binding:"omitempty,max=1024"` + Gender int32 `json:"gender" binding:"omitempty,oneof=0 1 2"` + PhoneNumber string `json:"phoneNumber" binding:"omitempty,max=32"` + Birth uint32 `json:"birth" binding:"omitempty"` + Email string `json:"email" binding:"omitempty,max=64"` + Ex string `json:"ex" binding:"omitempty,max=1024"` +} + +//type Conversation struct { +// OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"` +// ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"` +// ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"` +// UserID string `gorm:"column:user_id;type:char(64)" json:"userID"` +// GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"` +// RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"` +// UnreadCount int32 `gorm:"column:unread_count" json:"unreadCount"` +// DraftTextTime int64 `gorm:"column:draft_text_time" json:"draftTextTime"` +// IsPinned bool `gorm:"column:is_pinned" json:"isPinned"` +// AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"` +// Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` +//} + +type GroupAddMemberInfo struct { + UserID string `json:"userID" binding:"required"` + RoleLevel int32 `json:"roleLevel" binding:"required"` +} + +func SetErrCodeMsg(c *gin.Context, status int) *CommResp { + resp := CommResp{ErrCode: int32(status), ErrMsg: http.StatusText(status)} + c.JSON(status, resp) + return &resp +} + +//GroupName string `json:"groupName"` +// Introduction string `json:"introduction"` +// Notification string `json:"notification"` +// FaceUrl string `json:"faceUrl"` +// OperationID string `json:"operationID" binding:"required"` +// GroupType int32 `json:"groupType"` +// Ex string `json:"ex"` + +//type GroupInfo struct { +// GroupID string `json:"groupID"` +// GroupName string `json:"groupName"` +// Notification string `json:"notification"` +// Introduction string `json:"introduction"` +// FaceUrl string `json:"faceUrl"` +// OwnerUserID string `json:"ownerUserID"` +// Ex string `json:"ex"` +// GroupType int32 `json:"groupType"` +//} + +//type GroupMemberFullInfo struct { +// GroupID string `json:"groupID"` +// UserID string `json:"userID"` +// RoleLevel int32 `json:"roleLevel"` +// JoinTime uint64 `json:"joinTime"` +// Nickname string `json:"nickname"` +// FaceUrl string `json:"faceUrl"` +// FriendRemark string `json:"friendRemark"` +// AppMangerLevel int32 `json:"appMangerLevel"` +// JoinSource int32 `json:"joinSource"` +// OperatorUserID string `json:"operatorUserID"` +// Ex string `json:"ex"` +//} +// +//type PublicUserInfo struct { +// UserID string `json:"userID"` +// Nickname string `json:"nickname"` +// FaceUrl string `json:"faceUrl"` +// Gender int32 `json:"gender"` +//} +// +//type UserInfo struct { +// UserID string `json:"userID"` +// Nickname string `json:"nickname"` +// FaceUrl string `json:"faceUrl"` +// Gender int32 `json:"gender"` +// Mobile string `json:"mobile"` +// Birth string `json:"birth"` +// Email string `json:"email"` +// Ex string `json:"ex"` +//} +// +//type FriendInfo struct { +// OwnerUserID string `json:"ownerUserID"` +// Remark string `json:"remark"` +// CreateTime int64 `json:"createTime"` +// FriendUser UserInfo `json:"friendUser"` +// AddSource int32 `json:"addSource"` +// OperatorUserID string `json:"operatorUserID"` +// Ex string `json:"ex"` +//} +// +//type BlackInfo struct { +// OwnerUserID string `json:"ownerUserID"` +// CreateTime int64 `json:"createTime"` +// BlackUser PublicUserInfo `json:"friendUser"` +// AddSource int32 `json:"addSource"` +// OperatorUserID string `json:"operatorUserID"` +// Ex string `json:"ex"` +//} +// +//type GroupRequest struct { +// UserID string `json:"userID"` +// GroupID string `json:"groupID"` +// HandleResult string `json:"handleResult"` +// ReqMsg string `json:"reqMsg"` +// HandleMsg string `json:"handleMsg"` +// ReqTime int64 `json:"reqTime"` +// HandleUserID string `json:"handleUserID"` +// HandleTime int64 `json:"handleTime"` +// Ex string `json:"ex"` +//} +// +//type FriendRequest struct { +// FromUserID string `json:"fromUserID"` +// ToUserID string `json:"toUserID"` +// HandleResult int32 `json:"handleResult"` +// ReqMessage string `json:"reqMessage"` +// CreateTime int64 `json:"createTime"` +// HandlerUserID string `json:"handlerUserID"` +// HandleMsg string `json:"handleMsg"` +// HandleTime int64 `json:"handleTime"` +// Ex string `json:"ex"` +//} +// +// +// diff --git a/pkg/base_info/user_api_struct.go b/pkg/base_info/user_api_struct.go new file mode 100644 index 000000000..10f20376c --- /dev/null +++ b/pkg/base_info/user_api_struct.go @@ -0,0 +1,34 @@ +package base_info + +import ( + open_im_sdk "Open_IM/pkg/proto/sdk_ws" +) + +type GetUsersInfoReq struct { + OperationID string `json:"operationID" binding:"required"` + UserIDList []string `json:"userIDList" binding:"required"` +} +type GetUsersInfoResp struct { + CommResp + UserInfoList []*open_im_sdk.PublicUserInfo `json:"-"` + Data []map[string]interface{} `json:"data"` +} + +type UpdateSelfUserInfoReq struct { + ApiUserInfo + OperationID string `json:"operationID" binding:"required"` +} + +type UpdateUserInfoResp struct { + CommResp +} + +type GetSelfUserInfoReq struct { + OperationID string `json:"operationID" binding:"required"` + UserID string `json:"userID" binding:"required"` +} +type GetSelfUserInfoResp struct { + CommResp + UserInfo *open_im_sdk.UserInfo `json:"-"` + Data map[string]interface{} `json:"data"` +} diff --git a/pkg/base_info/work_moments_struct.go b/pkg/base_info/work_moments_struct.go new file mode 100644 index 000000000..22d38df37 --- /dev/null +++ b/pkg/base_info/work_moments_struct.go @@ -0,0 +1,97 @@ +package base_info + +import "Open_IM/pkg/proto/office" + +type CreateOneWorkMomentReq struct { + office.CreateOneWorkMomentReq +} + +type CreateOneWorkMomentResp struct { + CommResp +} + +type DeleteOneWorkMomentReq struct { + office.DeleteOneWorkMomentReq +} + +type DeleteOneWorkMomentResp struct { + CommResp +} + +type LikeOneWorkMomentReq struct { + office.LikeOneWorkMomentReq +} + +type LikeOneWorkMomentResp struct { + CommResp +} + +type CommentOneWorkMomentReq struct { + office.CommentOneWorkMomentReq +} + +type CommentOneWorkMomentResp struct { + CommResp +} + +type WorkMomentsUserCommonReq struct { + PageNumber int32 `json:"pageNumber" binding:"required"` + ShowNumber int32 `json:"showNumber" binding:"required"` + OperationID string `json:"operationID" binding:"required"` + UserID string `json:"UserID" binding:"required"` +} + +type GetUserWorkMomentsReq struct { + WorkMomentsUserCommonReq +} + +type GetUserWorkMomentsResp struct { + CommResp + Data struct { + WorkMoments []*office.WorkMoment `json:"workMoments"` + CurrentPage int32 `json:"currentPage"` + ShowNumber int32 `json:"showNumber"` + } `json:"data"` +} + +type GetUserFriendWorkMomentsReq struct { + WorkMomentsUserCommonReq +} + +type GetUserFriendWorkMomentsResp struct { + CommResp + Data struct { + WorkMoments []*office.WorkMoment `json:"workMoments"` + CurrentPage int32 `json:"currentPage"` + ShowNumber int32 `json:"showNumber"` + } `json:"data"` +} + +type GetUserWorkMomentsCommentsMsgReq struct { + WorkMomentsUserCommonReq +} + +type GetUserWorkMomentsCommentsMsgResp struct { + CommResp + Data struct { + CommentMsgs []*office.CommentsMsg `json:"comments"` + CurrentPage int32 `json:"currentPage"` + ShowNumber int32 `json:"showNumber"` + } `json:"data"` +} + +type SetUserWorkMomentsLevelReq struct { + office.SetUserWorkMomentsLevelReq +} + +type SetUserWorkMomentsLevelResp struct { + CommResp +} + +type ClearUserWorkMomentsCommentsMsgReq struct { + office.ClearUserWorkMomentsCommentsMsgReq +} + +type ClearUserWorkMomentsCommentsMsgResp struct { + CommResp +} diff --git a/pkg/call_back_struct/common.go b/pkg/call_back_struct/common.go new file mode 100644 index 000000000..bc9ad5dac --- /dev/null +++ b/pkg/call_back_struct/common.go @@ -0,0 +1,24 @@ +package call_back_struct + +type CommonCallbackReq struct { + SendID string `json:"sendID"` + CallbackCommand string `json:"callbackCommand"` + ServerMsgID string `json:"serverMsgID"` + ClientMsgID string `json:"clientMsgID"` + OperationID string `json:"operationID"` + SenderPlatformID int32 `json:"senderPlatformID"` + SenderNickname string `json:"senderNickname"` + SessionType int32 `json:"sessionType"` + MsgFrom int32 `json:"msgFrom"` + ContentType int32 `json:"contentType"` + Status int32 `json:"status"` + CreateTime int64 `json:"createTime"` + Content string `json:"content"` +} + +type CommonCallbackResp struct { + ActionCode int `json:"actionCode"` + ErrCode int `json:"errCode"` + ErrMsg string `json:"errMsg"` + OperationID string `json:"operationID"` +} diff --git a/pkg/call_back_struct/group.go b/pkg/call_back_struct/group.go new file mode 100644 index 000000000..3681dddcc --- /dev/null +++ b/pkg/call_back_struct/group.go @@ -0,0 +1,9 @@ +package call_back_struct + +type CallbackBeforeCreateGroupReq struct { + CommonCallbackReq +} + +type CallbackAfterCreateGroupResp struct { + CommonCallbackResp +} \ No newline at end of file diff --git a/pkg/call_back_struct/message.go b/pkg/call_back_struct/message.go new file mode 100644 index 000000000..31c215ea2 --- /dev/null +++ b/pkg/call_back_struct/message.go @@ -0,0 +1,47 @@ +package call_back_struct + + +type CallbackBeforeSendSingleMsgReq struct { + CommonCallbackReq + RecvID string `json:"recvID"` +} + +type CallbackBeforeSendSingleMsgResp struct { + CommonCallbackResp +} + +type CallbackAfterSendSingleMsgReq struct { + CommonCallbackReq + RecvID string `json:"recvID"` +} + +type CallbackAfterSendSingleMsgResp struct { + CommonCallbackResp +} + +type CallbackBeforeSendGroupMsgReq struct { + CommonCallbackReq + GroupID string `json:"groupID"` +} + +type CallbackBeforeSendGroupMsgResp struct { + CommonCallbackResp +} + +type CallbackAfterSendGroupMsgReq struct { + CommonCallbackReq + GroupID string `json:"groupID"` +} + +type CallbackAfterSendGroupMsgResp struct { + CommonCallbackResp +} + +type CallbackWordFilterReq struct { + CommonCallbackReq +} + +type CallbackWordFilterResp struct { + CommonCallbackResp + Content string `json:"content"` +} diff --git a/pkg/cms_api_struct/admin.go b/pkg/cms_api_struct/admin.go new file mode 100644 index 000000000..54674662e --- /dev/null +++ b/pkg/cms_api_struct/admin.go @@ -0,0 +1,10 @@ +package cms_api_struct + +type AdminLoginRequest struct { + AdminName string `json:"admin_name" binding:"required"` + Secret string `json:"secret" binding:"required"` +} + +type AdminLoginResponse struct { + Token string `json:"token"` +} \ No newline at end of file diff --git a/pkg/cms_api_struct/common.go b/pkg/cms_api_struct/common.go new file mode 100644 index 000000000..7d160f543 --- /dev/null +++ b/pkg/cms_api_struct/common.go @@ -0,0 +1,11 @@ +package cms_api_struct + +type RequestPagination struct { + PageNumber int `form:"page_number" binding:"required"` + ShowNumber int `form:"show_number" binding:"required"` +} + +type ResponsePagination struct { + CurrentPage int `json:"current_number" binding:"required"` + ShowNumber int `json:"show_number" binding:"required"` +} \ No newline at end of file diff --git a/pkg/cms_api_struct/group.go b/pkg/cms_api_struct/group.go new file mode 100644 index 000000000..7d3333127 --- /dev/null +++ b/pkg/cms_api_struct/group.go @@ -0,0 +1,144 @@ +package cms_api_struct + +type GroupResponse struct { + GroupName string `json:"group_name"` + GroupID string `json:"group_id"` + GroupMasterName string `json:"group_master_name"` + GroupMasterId string `json:"group_master_id"` + CreateTime string `json:"create_time"` + IsBanChat bool `json:"is_ban_chat"` + IsBanPrivateChat bool `json:"is_ban_private_chat"` + ProfilePhoto string `json:"profile_photo"` +} + +type GetGroupByIdRequest struct { + GroupId string `form:"group_id" binding:"required"` +} + +type GetGroupByIdResponse struct { + GroupResponse +} + +type GetGroupRequest struct { + GroupName string `form:"group_name" binding:"required"` + RequestPagination +} + +type GetGroupResponse struct { + Groups []GroupResponse `json:"groups"` + GroupNums int `json:"group_nums"` + ResponsePagination +} + +type GetGroupsRequest struct { + RequestPagination +} + +type GetGroupsResponse struct { + Groups []GroupResponse `json:"groups"` + GroupNums int `json:"group_nums"` + ResponsePagination +} + +type CreateGroupRequest struct { + GroupName string `json:"group_name" binding:"required"` + GroupMasterId string `json:"group_master_id" binding:"required"` + GroupMembers []string `json:"group_members" binding:"required"` +} + +type CreateGroupResponse struct { +} + +type SetGroupMasterRequest struct { + GroupId string `json:"group_id" binding:"required"` + UserId string `json:"user_id" binding:"required"` +} + +type SetGroupMasterResponse struct { +} + +type SetGroupMemberRequest struct { + GroupId string `json:"group_id" binding:"required"` + UserId string `json:"user_id" binding:"required"` +} + +type SetGroupMemberRespones struct { +} + +type BanGroupChatRequest struct { + GroupId string `json:"group_id" binding:"required"` +} + +type BanGroupChatResponse struct { +} + +type BanPrivateChatRequest struct { + GroupId string `json:"group_id" binding:"required"` +} + +type BanPrivateChatResponse struct { +} + +type DeleteGroupRequest struct { + GroupId string `json:"group_id" binding:"required"` +} + +type DeleteGroupResponse struct { +} + +type GetGroupMembersRequest struct { + GroupId string `form:"group_id" binding:"required"` + UserName string `form:"user_name"` + RequestPagination +} + +type GroupMemberResponse struct { + MemberPosition int `json:"member_position"` + MemberNickName string `json:"member_nick_name"` + MemberId string `json:"member_id"` + JoinTime string `json:"join_time"` +} + +type GetGroupMembersResponse struct { + GroupMembers []GroupMemberResponse `json:"group_members"` + ResponsePagination + MemberNums int `json:"member_nums"` +} + +type GroupMemberRequest struct { + GroupId string `json:"group_id" binding:"required"` + Members []string `json:"members" binding:"required"` +} + +type GroupMemberOperateResponse struct { + Success []string `json:"success"` + Failed []string `json:"failed"` +} + +type AddGroupMembersRequest struct { + GroupMemberRequest +} + +type AddGroupMembersResponse struct { + GroupMemberOperateResponse +} + +type RemoveGroupMembersRequest struct { + GroupMemberRequest +} + +type RemoveGroupMembersResponse struct { + GroupMemberOperateResponse +} + +type AlterGroupInfoRequest struct { + GroupID string `json:"group_id"` + GroupName string `json:"group_name"` + Notification string `json:"notification"` + Introduction string `json:"introduction"` + ProfilePhoto string `json:"profile_photo"` + GroupType int `json:"group_type"` +} + +type AlterGroupInfoResponse struct { +} diff --git a/pkg/cms_api_struct/message_cms.go b/pkg/cms_api_struct/message_cms.go new file mode 100644 index 000000000..164c75011 --- /dev/null +++ b/pkg/cms_api_struct/message_cms.go @@ -0,0 +1,50 @@ +package cms_api_struct + +type BroadcastRequest struct { + Message string `json:"message"` +} + +type BroadcastResponse struct { +} + +type MassSendMassageRequest struct { + Message string `json:"message"` + Users []string `json:"users"` +} + +type MassSendMassageResponse struct { +} + +type GetChatLogsRequest struct { + SessionType int `form:"session_type"` + ContentType int `form:"content_type"` + Content string `form:"content"` + UserId string `form:"user_id"` + GroupId string `form:"group_id"` + Date string `form:"date"` + + RequestPagination +} + +type ChatLog struct { + SessionType int `json:"session_type"` + ContentType int `json:"content_type"` + SenderNickName string `json:"sender_nick_name"` + SenderId string `json:"sender_id"` + SearchContent string `json:"search_content"` + WholeContent string `json:"whole_content"` + + ReceiverNickName string `json:"receiver_nick_name,omitempty"` + ReceiverID string `json:"receiver_id,omitempty"` + + GroupName string `json:"group_name,omitempty"` + GroupId string `json:"group_id,omitempty"` + + Date string `json:"date"` +} + +type GetChatLogsResponse struct { + ChatLogs []ChatLog `json:"chat_logs"` + ChatLogsNum int `json:"log_nums"` + ResponsePagination +} diff --git a/pkg/cms_api_struct/organization.go b/pkg/cms_api_struct/organization.go new file mode 100644 index 000000000..825d41aa1 --- /dev/null +++ b/pkg/cms_api_struct/organization.go @@ -0,0 +1,25 @@ +package cms_api_struct + +type GetStaffsResponse struct { + StaffsList []struct { + ProfilePhoto string `json:"profile_photo"` + NickName string `json:"nick_name"` + StaffId int `json:"staff_id"` + Position string `json:"position"` + EntryTime string `json:"entry_time"` + } `json:"staffs_list"` +} + +type GetOrganizationsResponse struct { + OrganizationList []struct { + OrganizationId int `json:"organization_id"` + OrganizationName string `json:"organization_name"` + } `json:"organization_list"` +} + +type SquadResponse struct { + SquadList []struct { + SquadId int `json:"squad_id"` + SquadName string `json:"squad_name"` + } `json:"squad_list"` +} diff --git a/pkg/cms_api_struct/statistics.go b/pkg/cms_api_struct/statistics.go new file mode 100644 index 000000000..2ff1efffa --- /dev/null +++ b/pkg/cms_api_struct/statistics.go @@ -0,0 +1,89 @@ +package cms_api_struct + +type GetStatisticsRequest struct { + From string `form:"from" binding:"required"` + To string `form:"to" binding:"required"` +} + +type GetMessageStatisticsRequest struct { + GetStatisticsRequest +} + +type GetMessageStatisticsResponse struct { + PrivateMessageNum int `json:"private_message_num"` + GroupMessageNum int `json:"group_message_num"` + PrivateMessageNumList []struct { + Date string `json:"date"` + MessageNum int `json:"message_num"` + } `json:"private_message_num_list"` + GroupMessageNumList []struct { + Date string `json:"date"` + MessageNum int `json:"message_num"` + } `json:"group_message_num_list"` +} + +type GetUserStatisticsRequest struct { + GetStatisticsRequest +} + +type GetUserStatisticsResponse struct { + IncreaseUserNum int `json:"increase_user_num"` + ActiveUserNum int `json:"active_user_num"` + TotalUserNum int `json:"total_user_num"` + IncreaseUserNumList []struct { + Date string `json:"date"` + IncreaseUserNum int `json:"increase_user_num"` + } `json:"increase_user_num_list"` + ActiveUserNumList []struct { + Date string `json:"date"` + ActiveUserNum int `json:"active_user_num"` + } `json:"active_user_num_list"` + TotalUserNumList []struct { + Date string `json:"date"` + TotalUserNum int `json:"total_user_num"` + } `json:"total_user_num_list"` +} + +type GetGroupStatisticsRequest struct { + GetStatisticsRequest +} + +// 群聊统计 +type GetGroupStatisticsResponse struct { + IncreaseGroupNum int `json:"increase_group_num"` + TotalGroupNum int `json:"total_group_num"` + IncreaseGroupNumList []struct { + Date string `json:"date"` + IncreaseGroupNum int `json:"increase_group_num"` + } `json:"increase_group_num_list"` + TotalGroupNumList []struct { + Date string `json:"date"` + TotalGroupNum int `json:"total_group_num"` + } `json:"total_group_num_list"` +} + +type GetActiveUserRequest struct { + GetStatisticsRequest + // RequestPagination +} + +type GetActiveUserResponse struct { + ActiveUserList []struct { + NickName string `json:"nick_name"` + UserId string `json:"user_id"` + MessageNum int `json:"message_num"` + } `json:"active_user_list"` +} + +type GetActiveGroupRequest struct { + GetStatisticsRequest + // RequestPagination +} + +type GetActiveGroupResponse struct { + ActiveGroupList []struct { + GroupName string `json:"group_name"` + GroupId string `json:"group_id"` + MessageNum int `json:"message_num"` + } `json:"active_group_list"` +} diff --git a/pkg/cms_api_struct/user.go b/pkg/cms_api_struct/user.go new file mode 100644 index 000000000..2c0b004b0 --- /dev/null +++ b/pkg/cms_api_struct/user.go @@ -0,0 +1,110 @@ +package cms_api_struct + +type UserResponse struct { + ProfilePhoto string `json:"profile_photo"` + Nickname string `json:"nick_name"` + UserId string `json:"user_id"` + CreateTime string `json:"create_time,omitempty"` + IsBlock bool `json:"is_block"` +} + +type GetUserRequest struct { + UserId string `form:"user_id" binding:"required"` +} + +type GetUserResponse struct { + UserResponse +} + +type GetUsersRequest struct { + RequestPagination +} + +type GetUsersResponse struct { + Users []*UserResponse `json:"users"` + ResponsePagination + UserNums int32 `json:"user_nums"` +} + +type GetUsersByNameRequest struct { + UserName string `form:"user_name" binding:"required"` + RequestPagination +} + +type GetUsersByNameResponse struct { + Users []*UserResponse `json:"users"` + ResponsePagination + UserNums int32 `json:"user_nums"` +} + +type ResignUserRequest struct { + UserId string `json:"user_id"` +} + +type ResignUserResponse struct { +} + +type AlterUserRequest struct { + UserId string `json:"user_id" binding:"required"` + Nickname string `json:"nickname"` + PhoneNumber int `json:"phone_number" validate:"len=11"` + Email string `json:"email"` +} + +type AlterUserResponse struct { +} + +type AddUserRequest struct { + PhoneNumber string `json:"phone_number" binding:"required"` + UserId string `json:"user_id" binding:"required"` + Name string `json:"name" binding:"required"` +} + +type AddUserResponse struct { +} + +type BlockUser struct { + UserResponse + BeginDisableTime string `json:"begin_disable_time"` + EndDisableTime string `json:"end_disable_time"` +} + +type BlockUserRequest struct { + UserId string `json:"user_id" binding:"required"` + EndDisableTime string `json:"end_disable_time" binding:"required"` +} + +type BlockUserResponse struct { +} + +type UnblockUserRequest struct { + UserId string `json:"user_id" binding:"required"` +} + +type UnBlockUserResponse struct { +} + +type GetBlockUsersRequest struct { + RequestPagination +} + +type GetBlockUsersResponse struct { + BlockUsers []BlockUser `json:"block_users"` + ResponsePagination + UserNums int32 `json:"user_nums"` +} + +type GetBlockUserRequest struct { + UserId string `form:"user_id" binding:"required"` +} + +type GetBlockUserResponse struct { + BlockUser +} + +type DeleteUserRequest struct { + UserId string `json:"user_id" binding:"required"` +} + +type DeleteUserResponse struct { +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go new file mode 100644 index 000000000..9e1bd54b6 --- /dev/null +++ b/pkg/common/config/config.go @@ -0,0 +1,434 @@ +package config + +import ( + "io/ioutil" + "os" + "path/filepath" + "runtime" + + "github.com/spf13/viper" + "gopkg.in/yaml.v3" +) + +var ( + _, b, _, _ = runtime.Caller(0) + // Root folder of this project + Root = filepath.Join(filepath.Dir(b), "../../..") +) + +var Config config + +type callBackConfig struct { + Enable bool `yaml:"enable"` + CallbackTimeOut int `yaml:"callbackTimeOut"` + CallbackFailedContinue bool `yaml:"callbackFailedContinue"` +} + +type config struct { + ServerIP string `yaml:"serverip"` + ServerVersion string `yaml:"serverversion"` + Api struct { + GinPort []int `yaml:"openImApiPort"` + } + CmsApi struct { + GinPort []int `yaml:"openImCmsApiPort"` + } + Sdk struct { + WsPort []int `yaml:"openImSdkWsPort"` + } + Credential struct { + Tencent struct { + AppID string `yaml:"appID"` + Region string `yaml:"region"` + Bucket string `yaml:"bucket"` + SecretID string `yaml:"secretID"` + SecretKey string `yaml:"secretKey"` + } + Ali struct { + RegionID string `yaml:"regionID"` + AccessKeyID string `yaml:"accessKeyID"` + AccessKeySecret string `yaml:"accessKeySecret"` + StsEndpoint string `yaml:"stsEndpoint"` + OssEndpoint string `yaml:"ossEndpoint"` + Bucket string `yaml:"bucket"` + FinalHost string `yaml:"finalHost"` + StsDurationSeconds int64 `yaml:"stsDurationSeconds"` + OssRoleArn string `yaml:"OssRoleArn"` + } + Minio struct { + Bucket string `yaml:"bucket"` + Location string `yaml:"location"` + Endpoint string `yaml:"endpoint"` + AccessKeyID string `yaml:"accessKeyID"` + SecretAccessKey string `yaml:"secretAccessKey"` + EndpointInner string `yaml:"endpointInner"` + EndpointInnerEnable bool `yaml:"endpointInnerEnable"` + } `yaml:"minio"` + } + + Mysql struct { + DBAddress []string `yaml:"dbMysqlAddress"` + DBUserName string `yaml:"dbMysqlUserName"` + DBPassword string `yaml:"dbMysqlPassword"` + DBDatabaseName string `yaml:"dbMysqlDatabaseName"` + DBTableName string `yaml:"DBTableName"` + DBMsgTableNum int `yaml:"dbMsgTableNum"` + DBMaxOpenConns int `yaml:"dbMaxOpenConns"` + DBMaxIdleConns int `yaml:"dbMaxIdleConns"` + DBMaxLifeTime int `yaml:"dbMaxLifeTime"` + } + Mongo struct { + DBUri string `yaml:"dbUri"` // 当dbUri值不为空则直接使用该值 + DBAddress []string `yaml:"dbAddress"` + DBDirect bool `yaml:"dbDirect"` + DBTimeout int `yaml:"dbTimeout"` + DBDatabase string `yaml:"dbDatabase"` + DBSource string `yaml:"dbSource"` + DBUserName string `yaml:"dbUserName"` + DBPassword string `yaml:"dbPassword"` + DBMaxPoolSize int `yaml:"dbMaxPoolSize"` + DBRetainChatRecords int `yaml:"dbRetainChatRecords"` + } + Redis struct { + DBAddress string `yaml:"dbAddress"` + DBMaxIdle int `yaml:"dbMaxIdle"` + DBMaxActive int `yaml:"dbMaxActive"` + DBIdleTimeout int `yaml:"dbIdleTimeout"` + DBPassWord string `yaml:"dbPassWord"` + } + RpcPort struct { + OpenImUserPort []int `yaml:"openImUserPort"` + openImFriendPort []int `yaml:"openImFriendPort"` + RpcMessagePort []int `yaml:"rpcMessagePort"` + RpcPushMessagePort []int `yaml:"rpcPushMessagePort"` + OpenImGroupPort []int `yaml:"openImGroupPort"` + RpcModifyUserInfoPort []int `yaml:"rpcModifyUserInfoPort"` + RpcGetTokenPort []int `yaml:"rpcGetTokenPort"` + } + RpcRegisterName struct { + OpenImStatisticsName string `yaml:"OpenImStatisticsName"` + OpenImUserName string `yaml:"openImUserName"` + OpenImFriendName string `yaml:"openImFriendName"` + OpenImOfflineMessageName string `yaml:"openImOfflineMessageName"` + OpenImPushName string `yaml:"openImPushName"` + OpenImOnlineMessageRelayName string `yaml:"openImOnlineMessageRelayName"` + OpenImGroupName string `yaml:"openImGroupName"` + OpenImAuthName string `yaml:"openImAuthName"` + OpenImMessageCMSName string `yaml:"openImMessageCMSName"` + OpenImAdminCMSName string `yaml:"openImAdminCMSName"` + OpenImOfficeName string `yaml:"openImOfficeName"` + OpenImOrganizationName string `yaml:"openImOrganizationName"` + } + Etcd struct { + EtcdSchema string `yaml:"etcdSchema"` + EtcdAddr []string `yaml:"etcdAddr"` + } + Log struct { + StorageLocation string `yaml:"storageLocation"` + RotationTime int `yaml:"rotationTime"` + RemainRotationCount uint `yaml:"remainRotationCount"` + RemainLogLevel uint `yaml:"remainLogLevel"` + ElasticSearchSwitch bool `yaml:"elasticSearchSwitch"` + ElasticSearchAddr []string `yaml:"elasticSearchAddr"` + ElasticSearchUser string `yaml:"elasticSearchUser"` + ElasticSearchPassword string `yaml:"elasticSearchPassword"` + } + ModuleName struct { + LongConnSvrName string `yaml:"longConnSvrName"` + MsgTransferName string `yaml:"msgTransferName"` + PushName string `yaml:"pushName"` + } + LongConnSvr struct { + WebsocketPort []int `yaml:"openImWsPort"` + WebsocketMaxConnNum int `yaml:"websocketMaxConnNum"` + WebsocketMaxMsgLen int `yaml:"websocketMaxMsgLen"` + WebsocketTimeOut int `yaml:"websocketTimeOut"` + } + + Push struct { + Tpns struct { + Ios struct { + AccessID string `yaml:"accessID"` + SecretKey string `yaml:"secretKey"` + } + Android struct { + AccessID string `yaml:"accessID"` + SecretKey string `yaml:"secretKey"` + } + Enable bool `yaml:"enable"` + } + Jpns struct { + AppKey string `yaml:"appKey"` + MasterSecret string `yaml:"masterSecret"` + PushUrl string `yaml:"pushUrl"` + PushIntent string `yaml:"pushIntent"` + Enable bool `yaml:"enable"` + } + Getui struct { + PushUrl string `yaml:"pushUrl"` + AppKey string `yaml:"appKey"` + Enable bool `yaml:"enable"` + Intent string `yaml:"intent"` + MasterSecret string `yaml:"masterSecret"` + } + } + Manager struct { + AppManagerUid []string `yaml:"appManagerUid"` + Secrets []string `yaml:"secrets"` + } + Kafka struct { + Ws2mschat struct { + Addr []string `yaml:"addr"` + Topic string `yaml:"topic"` + } + Ms2pschat struct { + Addr []string `yaml:"addr"` + Topic string `yaml:"topic"` + } + ConsumerGroupID struct { + MsgToMongo string `yaml:"msgToMongo"` + MsgToMySql string `yaml:"msgToMySql"` + MsgToPush string `yaml:"msgToPush"` + } + } + Secret string `yaml:"secret"` + MultiLoginPolicy int `yaml:"multiloginpolicy"` + TokenPolicy struct { + AccessSecret string `yaml:"accessSecret"` + AccessExpire int64 `yaml:"accessExpire"` + } + MessageVerify struct { + FriendVerify bool `yaml:"friendVerify"` + } + IOSPush struct { + PushSound string `yaml:"pushSound"` + BadgeCount bool `yaml:"badgeCount"` + } + + Callback struct { + CallbackUrl string `yaml:"callbackUrl"` + CallbackBeforeSendSingleMsg callBackConfig `yaml:"callbackbeforeSendSingleMsg"` + CallbackAfterSendSingleMsg callBackConfig `yaml:"callbackAfterSendSingleMsg"` + CallbackBeforeSendGroupMsg callBackConfig `yaml:"callbackBeforeSendGroupMsg"` + CallbackAfterSendGroupMsg callBackConfig `yaml:"callbackAfterSendGroupMsg"` + CallbackWordFilter callBackConfig `yaml:"callbackWordFilter"` + } `yaml:"callback"` + Notification struct { + ///////////////////////group///////////////////////////// + GroupCreated struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupCreated"` + + GroupInfoSet struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupInfoSet"` + + JoinGroupApplication struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"joinGroupApplication"` + + MemberQuit struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"memberQuit"` + + GroupApplicationAccepted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupApplicationAccepted"` + + GroupApplicationRejected struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupApplicationRejected"` + + GroupOwnerTransferred struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupOwnerTransferred"` + + MemberKicked struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"memberKicked"` + + MemberInvited struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"memberInvited"` + + MemberEnter struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"memberEnter"` + + GroupDismissed struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupDismissed"` + + GroupMuted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupMuted"` + + GroupCancelMuted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupCancelMuted"` + + GroupMemberMuted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupMemberMuted"` + + GroupMemberCancelMuted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"groupMemberCancelMuted"` + + ////////////////////////user/////////////////////// + UserInfoUpdated struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"userInfoUpdated"` + + //////////////////////friend/////////////////////// + FriendApplication struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"friendApplicationAdded"` + FriendApplicationApproved struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"friendApplicationApproved"` + + FriendApplicationRejected struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"friendApplicationRejected"` + + FriendAdded struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"friendAdded"` + + FriendDeleted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"friendDeleted"` + FriendRemarkSet struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"friendRemarkSet"` + BlackAdded struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"blackAdded"` + BlackDeleted struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"blackDeleted"` + ConversationOptUpdate struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips PDefaultTips `yaml:"defaultTips"` + } `yaml:"conversationOptUpdate"` + ConversationSetPrivate struct { + Conversation PConversation `yaml:"conversation"` + OfflinePush POfflinePush `yaml:"offlinePush"` + DefaultTips struct { + OpenTips string `yaml:"openTips"` + CloseTips string `yaml:"closeTips"` + } `yaml:"defaultTips"` + } `yaml:"conversationSetPrivate"` + } + Demo struct { + Port []int `yaml:"openImDemoPort"` + AliSMSVerify struct { + AccessKeyID string `yaml:"accessKeyId"` + AccessKeySecret string `yaml:"accessKeySecret"` + SignName string `yaml:"signName"` + VerificationCodeTemplateCode string `yaml:"verificationCodeTemplateCode"` + } + SuperCode string `yaml:"superCode"` + CodeTTL int `yaml:"codeTTL"` + Mail struct { + Title string `yaml:"title"` + SenderMail string `yaml:"senderMail"` + SenderAuthorizationCode string `yaml:"senderAuthorizationCode"` + SmtpAddr string `yaml:"smtpAddr"` + SmtpPort int `yaml:"smtpPort"` + } + } + Rtc struct { + Port int `yaml:"port"` + Address string `yaml:"address"` + } `yaml:"rtc"` +} +type PConversation struct { + ReliabilityLevel int `yaml:"reliabilityLevel"` + UnreadCount bool `yaml:"unreadCount"` +} + +type POfflinePush struct { + PushSwitch bool `yaml:"switch"` + Title string `yaml:"title"` + Desc string `yaml:"desc"` + Ext string `yaml:"ext"` +} +type PDefaultTips struct { + Tips string `yaml:"tips"` +} + +func init() { + //path, _ := os.Getwd() + //bytes, err := ioutil.ReadFile(path + "/config/config.yaml") + // if we cd Open-IM-Server/src/utils and run go test + // it will panic cannot find config/config.yaml + + cfgName := os.Getenv("CONFIG_NAME") + if len(cfgName) == 0 { + cfgName = Root + "/config/config.yaml" + } + + viper.SetConfigFile(cfgName) + err := viper.ReadInConfig() + if err != nil { + panic(err.Error()) + } + bytes, err := ioutil.ReadFile(cfgName) + if err != nil { + panic(err.Error()) + } + if err = yaml.Unmarshal(bytes, &Config); err != nil { + panic(err.Error()) + } +} diff --git a/pkg/common/constant/constant.go b/pkg/common/constant/constant.go new file mode 100644 index 000000000..fdee4f2b7 --- /dev/null +++ b/pkg/common/constant/constant.go @@ -0,0 +1,235 @@ +package constant + +const ( + + //group admin + // OrdinaryMember = 0 + // GroupOwner = 1 + // Administrator = 2 + //group application + // Application = 0 + // AgreeApplication = 1 + + //friend related + BlackListFlag = 1 + ApplicationFriendFlag = 0 + FriendFlag = 1 + RefuseFriendFlag = -1 + + //Websocket Protocol + WSGetNewestSeq = 1001 + WSPullMsgBySeqList = 1002 + WSSendMsg = 1003 + WSSendSignalMsg = 1004 + WSPushMsg = 2001 + WSKickOnlineMsg = 2002 + WsLogoutMsg = 2003 + WSDataError = 3001 + + ///ContentType + //UserRelated + Text = 101 + Picture = 102 + Voice = 103 + Video = 104 + File = 105 + AtText = 106 + Merger = 107 + Card = 108 + Location = 109 + Custom = 110 + Revoke = 111 + HasReadReceipt = 112 + Typing = 113 + Quote = 114 + Common = 200 + GroupMsg = 201 + + //SysRelated + NotificationBegin = 1000 + + FriendApplicationApprovedNotification = 1201 //add_friend_response + FriendApplicationRejectedNotification = 1202 //add_friend_response + FriendApplicationNotification = 1203 //add_friend + FriendAddedNotification = 1204 + FriendDeletedNotification = 1205 //delete_friend + FriendRemarkSetNotification = 1206 //set_friend_remark? + BlackAddedNotification = 1207 //add_black + BlackDeletedNotification = 1208 //remove_black + + ConversationOptChangeNotification = 1300 // change conversation opt + + UserNotificationBegin = 1301 + UserInfoUpdatedNotification = 1303 //SetSelfInfoTip = 204 + UserNotificationEnd = 1399 + OANotification = 1400 + + GroupNotificationBegin = 1500 + + GroupCreatedNotification = 1501 + GroupInfoSetNotification = 1502 + JoinGroupApplicationNotification = 1503 + MemberQuitNotification = 1504 + GroupApplicationAcceptedNotification = 1505 + GroupApplicationRejectedNotification = 1506 + GroupOwnerTransferredNotification = 1507 + MemberKickedNotification = 1508 + MemberInvitedNotification = 1509 + MemberEnterNotification = 1510 + GroupDismissedNotification = 1511 + GroupMemberMutedNotification = 1512 + GroupMemberCancelMutedNotification = 1513 + GroupMutedNotification = 1514 + GroupCancelMutedNotification = 1515 + + SignalingNotificationBegin = 1600 + SignalingNotification = 1601 + SignalingNotificationEnd = 1699 + + ConversationPrivateChatNotification = 1701 + + NotificationEnd = 2000 + + //status + MsgNormal = 1 + MsgDeleted = 4 + + //MsgFrom + UserMsgType = 100 + SysMsgType = 200 + + //SessionType + SingleChatType = 1 + GroupChatType = 2 + + NotificationChatType = 4 + //token + NormalToken = 0 + InValidToken = 1 + KickedToken = 2 + ExpiredToken = 3 + + //MultiTerminalLogin + //Full-end login, but the same end is mutually exclusive + AllLoginButSameTermKick = 1 + //Only one of the endpoints can log in + SingleTerminalLogin = 2 + //The web side can be online at the same time, and the other side can only log in at one end + WebAndOther = 3 + //The PC side is mutually exclusive, and the mobile side is mutually exclusive, but the web side can be online at the same time + PcMobileAndWeb = 4 + + OnlineStatus = "online" + OfflineStatus = "offline" + Registered = "registered" + UnRegistered = "unregistered" + + //MsgReceiveOpt + ReceiveMessage = 0 + NotReceiveMessage = 1 + ReceiveNotNotifyMessage = 2 + + //OptionsKey + IsHistory = "history" + IsPersistent = "persistent" + IsOfflinePush = "offlinePush" + IsUnreadCount = "unreadCount" + IsConversationUpdate = "conversationUpdate" + IsSenderSync = "senderSync" + IsNotPrivate = "notPrivate" + IsSenderConversationUpdate = "senderConversationUpdate" + + //GroupStatus + GroupOk = 0 + GroupBanChat = 1 + GroupStatusDismissed = 2 + GroupStatusMuted = 3 + + GroupBaned = 3 + GroupBanPrivateChat = 4 + + //UserJoinGroupSource + JoinByAdmin = 1 + + //Minio + MinioDurationTimes = 3600 + + // verificationCode used for + VerificationCodeForRegister = 1 + VerificationCodeForReset = 2 + VerificationCodeForRegisterSuffix = "_forRegister" + VerificationCodeForResetSuffix = "_forReset" + + //callbackCommand + CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand" + CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand" + CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand" + CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand" + CallbackWordFilterCommand = "callbackWordFilterCommand" + //callback actionCode + ActionAllow = 0 + ActionForbidden = 1 + //callback callbackHandleCode + CallbackHandleSuccess = 0 + CallbackHandleFailed = 1 + + // minioUpload + OtherType = 1 + VideoType = 2 + ImageType = 3 +) + +var ContentType2PushContent = map[int64]string{ + Picture: "[图片]", + Voice: "[语音]", + Video: "[视频]", + File: "[文件]", + Text: "你收到了一条文本消息", + AtText: "[有人@你]", + GroupMsg: "你收到一条群聊消息", + Common: "你收到一条新消息", +} + +const ( + AppOrdinaryUsers = 1 + AppAdmin = 2 + + GroupOrdinaryUsers = 1 + GroupOwner = 2 + GroupAdmin = 3 + + GroupResponseAgree = 1 + GroupResponseRefuse = -1 + + FriendResponseAgree = 1 + FriendResponseRefuse = -1 + + Male = 1 + Female = 2 +) + +const ( + UnreliableNotification = 1 + ReliableNotificationNoMsg = 2 + ReliableNotificationMsg = 3 +) + +const FriendAcceptTip = "You have successfully become friends, so start chatting" + +func GroupIsBanChat(status int32) bool { + if status != GroupStatusMuted { + return false + } + return true +} + +func GroupIsBanPrivateChat(status int32) bool { + if status != GroupBanPrivateChat { + return false + } + return true +} + +const BigVersion = "v3" + +const LogFileName = "OpenIM.log" diff --git a/pkg/common/constant/error.go b/pkg/common/constant/error.go new file mode 100644 index 000000000..00a11fd49 --- /dev/null +++ b/pkg/common/constant/error.go @@ -0,0 +1,100 @@ +package constant + +import "errors" + +// key = errCode, string = errMsg +type ErrInfo struct { + ErrCode int32 + ErrMsg string +} + +var ( + OK = ErrInfo{0, ""} + ErrServer = ErrInfo{500, "server error"} + + // ErrMysql = ErrInfo{100, ""} + // ErrMongo = ErrInfo{110, ""} + // ErrRedis = ErrInfo{120, ""} + ErrParseToken = ErrInfo{700, ParseTokenMsg.Error()} + // ErrCreateToken = ErrInfo{201, "Create token failed"} + // ErrAppServerKey = ErrInfo{300, "key error"} + ErrTencentCredential = ErrInfo{400, ThirdPartyMsg.Error()} + + // ErrorUserRegister = ErrInfo{600, "User registration failed"} + // ErrAccountExists = ErrInfo{601, "The account is already registered and cannot be registered again"} + // ErrUserPassword = ErrInfo{602, "User password error"} + // ErrRefreshToken = ErrInfo{605, "Failed to refresh token"} + // ErrAddFriend = ErrInfo{606, "Failed to add friends"} + // ErrAgreeToAddFriend = ErrInfo{607, "Failed to agree application"} + // ErrAddFriendToBlack = ErrInfo{608, "Failed to add friends to the blacklist"} + // ErrGetBlackList = ErrInfo{609, "Failed to get blacklist"} + // ErrDeleteFriend = ErrInfo{610, "Failed to delete friend"} + // ErrGetFriendApplyList = ErrInfo{611, "Failed to get friend application list"} + // ErrGetFriendList = ErrInfo{612, "Failed to get friend list"} + // ErrRemoveBlackList = ErrInfo{613, "Failed to remove blacklist"} + // ErrSearchUserInfo = ErrInfo{614, "Can't find the user information"} + // ErrDelAppleDeviceToken = ErrInfo{615, ""} + // ErrModifyUserInfo = ErrInfo{616, "update user some attribute failed"} + // ErrSetFriendComment = ErrInfo{617, "set friend comment failed"} + // ErrSearchUserInfoFromTheGroup = ErrInfo{618, "There is no such group or the user not in the group"} + // ErrCreateGroup = ErrInfo{619, "create group chat failed"} + // ErrJoinGroupApplication = ErrInfo{620, "Failed to apply to join the group"} + // ErrQuitGroup = ErrInfo{621, "Failed to quit the group"} + // ErrSetGroupInfo = ErrInfo{622, "Failed to set group info"} + // ErrParam = ErrInfo{700, "param failed"} + ErrTokenExpired = ErrInfo{701, TokenExpiredMsg.Error()} + ErrTokenInvalid = ErrInfo{702, TokenInvalidMsg.Error()} + ErrTokenMalformed = ErrInfo{703, TokenMalformedMsg.Error()} + ErrTokenNotValidYet = ErrInfo{704, TokenNotValidYetMsg.Error()} + ErrTokenUnknown = ErrInfo{705, TokenUnknownMsg.Error()} + ErrTokenKicked = ErrInfo{706, TokenUserKickedMsg.Error()} + + ErrAccess = ErrInfo{ErrCode: 801, ErrMsg: AccessMsg.Error()} + ErrDB = ErrInfo{ErrCode: 802, ErrMsg: DBMsg.Error()} + ErrArgs = ErrInfo{ErrCode: 8003, ErrMsg: ArgsMsg.Error()} + ErrCallback = ErrInfo{ErrCode: 809, ErrMsg: CallBackMsg.Error()} +) + +var ( + ParseTokenMsg = errors.New("parse token failed") + TokenExpiredMsg = errors.New("token is timed out, please log in again") + TokenInvalidMsg = errors.New("token has been invalidated") + TokenNotValidYetMsg = errors.New("token not active yet") + TokenMalformedMsg = errors.New("that's not even a token") + TokenUnknownMsg = errors.New("couldn't handle this token") + TokenUserKickedMsg = errors.New("user has been kicked") + AccessMsg = errors.New("no permission") + DBMsg = errors.New("db failed") + ArgsMsg = errors.New("args failed") + CallBackMsg = errors.New("callback failed") + + ThirdPartyMsg = errors.New("third party error") +) + +const ( + NoError = 0 + FormattingError = 10001 + HasRegistered = 10002 + NotRegistered = 10003 + PasswordErr = 10004 + GetIMTokenErr = 10005 + RepeatSendCode = 10006 + MailSendCodeErr = 10007 + SmsSendCodeErr = 10008 + CodeInvalidOrExpired = 10009 + RegisterFailed = 10010 + ResetPasswordFailed = 10011 + DatabaseError = 10002 + ServerError = 10004 + HttpError = 10005 + IoError = 10006 + IntentionalError = 10007 +) + +func (e ErrInfo) Error() string { + return e.ErrMsg +} + +func (e *ErrInfo) Code() int32 { + return e.ErrCode +} diff --git a/pkg/common/constant/platform_number_id_to_name.go b/pkg/common/constant/platform_number_id_to_name.go new file mode 100644 index 000000000..c3a970b69 --- /dev/null +++ b/pkg/common/constant/platform_number_id_to_name.go @@ -0,0 +1,66 @@ +package constant + +// fixme 1<--->IOS 2<--->Android 3<--->Windows +//fixme 4<--->OSX 5<--->Web 6<--->MiniWeb 7<--->Linux + +const ( + //Platform ID + IOSPlatformID = 1 + AndroidPlatformID = 2 + WindowsPlatformID = 3 + OSXPlatformID = 4 + WebPlatformID = 5 + MiniWebPlatformID = 6 + LinuxPlatformID = 7 + + //Platform string match to Platform ID + IOSPlatformStr = "IOS" + AndroidPlatformStr = "Android" + WindowsPlatformStr = "Windows" + OSXPlatformStr = "OSX" + WebPlatformStr = "Web" + MiniWebPlatformStr = "MiniWeb" + LinuxPlatformStr = "Linux" + + //terminal types + TerminalPC = "PC" + TerminalMobile = "Mobile" +) + +var PlatformID2Name = map[int32]string{ + IOSPlatformID: IOSPlatformStr, + AndroidPlatformID: AndroidPlatformStr, + WindowsPlatformID: WindowsPlatformStr, + OSXPlatformID: OSXPlatformStr, + WebPlatformID: WebPlatformStr, + MiniWebPlatformID: MiniWebPlatformStr, + LinuxPlatformID: LinuxPlatformStr, +} +var PlatformName2ID = map[string]int32{ + IOSPlatformStr: IOSPlatformID, + AndroidPlatformStr: AndroidPlatformID, + WindowsPlatformStr: WindowsPlatformID, + OSXPlatformStr: OSXPlatformID, + WebPlatformStr: WebPlatformID, + MiniWebPlatformStr: MiniWebPlatformID, + LinuxPlatformStr: LinuxPlatformID, +} +var Platform2class = map[string]string{ + IOSPlatformStr: TerminalMobile, + AndroidPlatformStr: TerminalMobile, + MiniWebPlatformStr: WebPlatformStr, + WebPlatformStr: WebPlatformStr, + WindowsPlatformStr: TerminalPC, + OSXPlatformStr: TerminalPC, + LinuxPlatformStr: TerminalPC, +} + +func PlatformIDToName(num int32) string { + return PlatformID2Name[num] +} +func PlatformNameToID(name string) int32 { + return PlatformName2ID[name] +} +func PlatformNameToClass(name string) string { + return Platform2class[name] +} diff --git a/pkg/common/db/model.go b/pkg/common/db/model.go new file mode 100644 index 000000000..bd465d6ff --- /dev/null +++ b/pkg/common/db/model.go @@ -0,0 +1,119 @@ +package db + +import ( + "Open_IM/pkg/common/config" + //"Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "fmt" + "go.mongodb.org/mongo-driver/mongo/options" + + // "context" + // "fmt" + "github.com/garyburd/redigo/redis" + "gopkg.in/mgo.v2" + "time" + + "context" + //"go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + // "go.mongodb.org/mongo-driver/mongo/options" +) + +var DB DataBases + +type DataBases struct { + MysqlDB mysqlDB + mgoSession *mgo.Session + redisPool *redis.Pool + mongoClient *mongo.Client +} + +func key(dbAddress, dbName string) string { + return dbAddress + "_" + dbName +} + +func init() { + //log.NewPrivateLog(constant.LogFileName) + //var mgoSession *mgo.Session + var mongoClient *mongo.Client + var err1 error + //mysql init + initMysqlDB() + // mongo init + // "mongodb://sysop:moon@localhost/records" + uri := "mongodb://sample.host:27017/?maxPoolSize=20&w=majority" + if config.Config.Mongo.DBUri != "" { + // example: mongodb://$user:$password@mongo1.mongo:27017,mongo2.mongo:27017,mongo3.mongo:27017/$DBDatabase/?replicaSet=rs0&readPreference=secondary&authSource=admin&maxPoolSize=$DBMaxPoolSize + uri = config.Config.Mongo.DBUri + } else { + if config.Config.Mongo.DBPassword != "" && config.Config.Mongo.DBUserName != "" { + uri = fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%d", config.Config.Mongo.DBUserName, config.Config.Mongo.DBPassword, config.Config.Mongo.DBAddress[0], + config.Config.Mongo.DBDatabase, config.Config.Mongo.DBMaxPoolSize) + } else { + uri = fmt.Sprintf("mongodb://%s/%s/?maxPoolSize=%d", + config.Config.Mongo.DBAddress[0], config.Config.Mongo.DBDatabase, + config.Config.Mongo.DBMaxPoolSize) + } + } + mongoClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)) + if err != nil { + fmt.Println(" mongo.Connect failed, try ", utils.GetSelfFuncName(), err.Error(), uri) + time.Sleep(time.Duration(30) * time.Second) + mongoClient, err1 = mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)) + if err1 != nil { + fmt.Println(" mongo.Connect retry failed, panic", err.Error(), uri) + panic(err1.Error()) + } + } + fmt.Println("0", utils.GetSelfFuncName(), "mongo driver client init success: ", uri) + + DB.mongoClient = mongoClient + + //mgoDailInfo := &mgo.DialInfo{ + // Addrs: config.Config.Mongo.DBAddress, + // Direct: config.Config.Mongo.DBDirect, + // Timeout: time.Second * time.Duration(config.Config.Mongo.DBTimeout), + // Database: config.Config.Mongo.DBDatabase, + // Source: config.Config.Mongo.DBSource, + // Username: config.Config.Mongo.DBUserName, + // Password: config.Config.Mongo.DBPassword, + // PoolLimit: config.Config.Mongo.DBMaxPoolSize, + //} + //mgoSession, err = mgo.DialWithInfo(mgoDailInfo) + // + //if err != nil { + // + // mgoSession, err1 = mgo.DialWithInfo(mgoDailInfo) + // if err1 != nil { + // log.NewError(" mongo.Connect failed, panic", err.Error()) + // panic(err1.Error()) + // } + //} + + //DB.mgoSession = mgoSession + //DB.mgoSession.SetMode(mgo.Monotonic, true) + //c := DB.mgoSession.DB(config.Config.Mongo.DBDatabase).C(cChat) + //err = c.EnsureIndexKey("uid") + //if err != nil { + // panic(err.Error()) + //} + // + + // redis pool init + DB.redisPool = &redis.Pool{ + MaxIdle: config.Config.Redis.DBMaxIdle, + MaxActive: config.Config.Redis.DBMaxActive, + IdleTimeout: time.Duration(config.Config.Redis.DBIdleTimeout) * time.Second, + Dial: func() (redis.Conn, error) { + return redis.Dial( + "tcp", + config.Config.Redis.DBAddress, + redis.DialReadTimeout(time.Duration(1000)*time.Millisecond), + redis.DialWriteTimeout(time.Duration(1000)*time.Millisecond), + redis.DialConnectTimeout(time.Duration(1000)*time.Millisecond), + redis.DialDatabase(0), + redis.DialPassword(config.Config.Redis.DBPassWord), + ) + }, + } +} diff --git a/pkg/common/db/model_struct.go b/pkg/common/db/model_struct.go new file mode 100644 index 000000000..9591050e0 --- /dev/null +++ b/pkg/common/db/model_struct.go @@ -0,0 +1,272 @@ +package db + +import "time" + +type Register struct { + Account string `gorm:"column:account;primary_key;type:char(255)" json:"account"` + Password string `gorm:"column:password;type:varchar(255)" json:"password"` + Ex string `gorm:"column:ex;size:1024" json:"ex"` +} + +// +//message FriendInfo{ +//string OwnerUserID = 1; +//string Remark = 2; +//int64 CreateTime = 3; +//UserInfo FriendUser = 4; +//int32 AddSource = 5; +//string OperatorUserID = 6; +//string Ex = 7; +//} +//open_im_sdk.FriendInfo(FriendUser) != imdb.Friend(FriendUserID) +type Friend struct { + OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` + FriendUserID string `gorm:"column:friend_user_id;primary_key;size:64"` + Remark string `gorm:"column:remark;size:255"` + CreateTime time.Time `gorm:"column:create_time"` + AddSource int32 `gorm:"column:add_source"` + OperatorUserID string `gorm:"column:operator_user_id;size:64"` + Ex string `gorm:"column:ex;size:1024"` +} + +//message FriendRequest{ +//string FromUserID = 1; +//string ToUserID = 2; +//int32 HandleResult = 3; +//string ReqMsg = 4; +//int64 CreateTime = 5; +//string HandlerUserID = 6; +//string HandleMsg = 7; +//int64 HandleTime = 8; +//string Ex = 9; +//} +//open_im_sdk.FriendRequest(nickname, farce url ...) != imdb.FriendRequest +type FriendRequest struct { + FromUserID string `gorm:"column:from_user_id;primary_key;size:64"` + ToUserID string `gorm:"column:to_user_id;primary_key;size:64"` + HandleResult int32 `gorm:"column:handle_result"` + ReqMsg string `gorm:"column:req_msg;size:255"` + CreateTime time.Time `gorm:"column:create_time"` + HandlerUserID string `gorm:"column:handler_user_id;size:64"` + HandleMsg string `gorm:"column:handle_msg;size:255"` + HandleTime time.Time `gorm:"column:handle_time"` + Ex string `gorm:"column:ex;size:1024"` +} + +func (FriendRequest) TableName() string { + return "friend_requests" +} + +//message GroupInfo{ +// string GroupID = 1; +// string GroupName = 2; +// string Notification = 3; +// string Introduction = 4; +// string FaceUrl = 5; +// string OwnerUserID = 6; +// uint32 MemberCount = 8; +// int64 CreateTime = 7; +// string Ex = 9; +// int32 Status = 10; +// string CreatorUserID = 11; +// int32 GroupType = 12; +//} +// open_im_sdk.GroupInfo (OwnerUserID , MemberCount )> imdb.Group +type Group struct { + //`json:"operationID" binding:"required"` + //`protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` `json:"operationID" binding:"required"` + GroupID string `gorm:"column:group_id;primary_key;size:64" json:"groupID" binding:"required"` + GroupName string `gorm:"column:name;size:255" json:"groupName"` + Notification string `gorm:"column:notification;size:255" json:"notification"` + Introduction string `gorm:"column:introduction;size:255" json:"introduction"` + FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"` + CreateTime time.Time `gorm:"column:create_time"` + Ex string `gorm:"column:ex" json:"ex;size:1024" json:"ex"` + Status int32 `gorm:"column:status"` + CreatorUserID string `gorm:"column:creator_user_id;size:64"` + GroupType int32 `gorm:"column:group_type"` +} + +//message GroupMemberFullInfo { +//string GroupID = 1 ; +//string UserID = 2 ; +//int32 roleLevel = 3; +//int64 JoinTime = 4; +//string NickName = 5; +//string FaceUrl = 6; +//int32 JoinSource = 8; +//string OperatorUserID = 9; +//string Ex = 10; +//int32 AppMangerLevel = 7; //if >0 +//} open_im_sdk.GroupMemberFullInfo(AppMangerLevel) > imdb.GroupMember +type GroupMember struct { + GroupID string `gorm:"column:group_id;primary_key;size:64"` + UserID string `gorm:"column:user_id;primary_key;size:64"` + Nickname string `gorm:"column:nickname;size:255"` + FaceURL string `gorm:"column:user_group_face_url;size:255"` + RoleLevel int32 `gorm:"column:role_level"` + JoinTime time.Time `gorm:"column:join_time"` + JoinSource int32 `gorm:"column:join_source"` + OperatorUserID string `gorm:"column:operator_user_id;size:64"` + MuteEndTime time.Time `gorm:"column:mute_end_time"` + Ex string `gorm:"column:ex;size:1024"` +} + +//message GroupRequest{ +//string UserID = 1; +//string GroupID = 2; +//string HandleResult = 3; +//string ReqMsg = 4; +//string HandleMsg = 5; +//int64 ReqTime = 6; +//string HandleUserID = 7; +//int64 HandleTime = 8; +//string Ex = 9; +//}open_im_sdk.GroupRequest == imdb.GroupRequest +type GroupRequest struct { + UserID string `gorm:"column:user_id;primary_key;size:64"` + GroupID string `gorm:"column:group_id;primary_key;size:64"` + HandleResult int32 `gorm:"column:handle_result"` + ReqMsg string `gorm:"column:req_msg;size:1024"` + HandledMsg string `gorm:"column:handle_msg;size:1024"` + ReqTime time.Time `gorm:"column:req_time"` + HandleUserID string `gorm:"column:handle_user_id;size:64"` + HandledTime time.Time `gorm:"column:handle_time"` + Ex string `gorm:"column:ex;size:1024"` +} + +//string UserID = 1; +//string Nickname = 2; +//string FaceUrl = 3; +//int32 Gender = 4; +//string PhoneNumber = 5; +//string Birth = 6; +//string Email = 7; +//string Ex = 8; +//int64 CreateTime = 9; +//int32 AppMangerLevel = 10; +//open_im_sdk.User == imdb.User +type User struct { + UserID string `gorm:"column:user_id;primary_key;size:64"` + Nickname string `gorm:"column:name;size:255"` + FaceURL string `gorm:"column:face_url;size:255"` + Gender int32 `gorm:"column:gender"` + PhoneNumber string `gorm:"column:phone_number;size:32"` + Birth time.Time `gorm:"column:birth"` + Email string `gorm:"column:email;size:64"` + Ex string `gorm:"column:ex;size:1024"` + CreateTime time.Time `gorm:"column:create_time"` + AppMangerLevel int32 `gorm:"column:app_manger_level"` +} + +//message BlackInfo{ +//string OwnerUserID = 1; +//int64 CreateTime = 2; +//PublicUserInfo BlackUserInfo = 4; +//int32 AddSource = 5; +//string OperatorUserID = 6; +//string Ex = 7; +//} +// open_im_sdk.BlackInfo(BlackUserInfo) != imdb.Black (BlockUserID) +type Black struct { + OwnerUserID string `gorm:"column:owner_user_id;primary_key;size:64"` + BlockUserID string `gorm:"column:block_user_id;primary_key;size:64"` + CreateTime time.Time `gorm:"column:create_time"` + AddSource int32 `gorm:"column:add_source"` + OperatorUserID string `gorm:"column:operator_user_id;size:64"` + Ex string `gorm:"column:ex;size:1024"` +} + +type ChatLog struct { + ServerMsgID string `gorm:"column:server_msg_id;primary_key;type:char(64)" json:"serverMsgID"` + ClientMsgID string `gorm:"column:client_msg_id;type:char(64)" json:"clientMsgID"` + SendID string `gorm:"column:send_id;type:char(64)" json:"sendID"` + RecvID string `gorm:"column:recv_id;type:char(64)" json:"recvID"` + SenderPlatformID int32 `gorm:"column:sender_platform_id" json:"senderPlatformID"` + SenderNickname string `gorm:"column:sender_nick_name;type:varchar(255)" json:"senderNickname"` + SenderFaceURL string `gorm:"column:sender_face_url;type:varchar(255)" json:"senderFaceURL"` + SessionType int32 `gorm:"column:session_type" json:"sessionType"` + MsgFrom int32 `gorm:"column:msg_from" json:"msgFrom"` + ContentType int32 `gorm:"column:content_type" json:"contentType"` + Content string `gorm:"column:content;type:varchar(3000)" json:"content"` + Status int32 `gorm:"column:status" json:"status"` + SendTime time.Time `gorm:"column:send_time" json:"sendTime"` + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` + Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` +} + +func (ChatLog) TableName() string { + return "chat_logs" +} + +type BlackList struct { + UserId string `gorm:"column:uid"` + BeginDisableTime time.Time `gorm:"column:begin_disable_time"` + EndDisableTime time.Time `gorm:"column:end_disable_time"` +} +type Conversation struct { + OwnerUserID string `gorm:"column:owner_user_id;primary_key;type:char(128)" json:"OwnerUserID"` + ConversationID string `gorm:"column:conversation_id;primary_key;type:char(128)" json:"conversationID"` + ConversationType int32 `gorm:"column:conversation_type" json:"conversationType"` + UserID string `gorm:"column:user_id;type:char(64)" json:"userID"` + GroupID string `gorm:"column:group_id;type:char(128)" json:"groupID"` + RecvMsgOpt int32 `gorm:"column:recv_msg_opt" json:"recvMsgOpt"` + UnreadCount int32 `gorm:"column:unread_count" json:"unreadCount"` + DraftTextTime int64 `gorm:"column:draft_text_time" json:"draftTextTime"` + IsPinned bool `gorm:"column:is_pinned" json:"isPinned"` + IsPrivateChat bool `gorm:"column:is_private_chat" json:"isPrivateChat"` + AttachedInfo string `gorm:"column:attached_info;type:varchar(1024)" json:"attachedInfo"` + Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` +} + +func (Conversation) TableName() string { + return "conversations" +} + +type Department struct { + DepartmentID string `gorm:"column:department_id;primary_key;size:64" json:"departmentID"` + FaceURL string `gorm:"column:face_url;size:255" json:"faceURL"` + Name string `gorm:"column:name;size:256" json:"name" binding:"required"` + ParentID string `gorm:"column:parent_id;size:64" json:"parentID" binding:"required"` // "0" or Real parent id + Order int32 `gorm:"column:order" json:"order" ` // 1, 2, ... + DepartmentType int32 `gorm:"column:department_type" json:"departmentType"` //1, 2... + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` + Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` +} + +func (Department) TableName() string { + return "departments" +} + +type OrganizationUser struct { + UserID string `gorm:"column:user_id;primary_key;size:64"` + Nickname string `gorm:"column:nickname;size:256"` + EnglishName string `gorm:"column:english_name;size:256"` + FaceURL string `gorm:"column:face_url;size:256"` + Gender int32 `gorm:"column:gender"` //1 ,2 + Mobile string `gorm:"column:mobile;size:32"` + Telephone string `gorm:"column:telephone;size:32"` + Birth time.Time `gorm:"column:birth"` + Email string `gorm:"column:email;size:64"` + CreateTime time.Time `gorm:"column:create_time"` + Ex string `gorm:"column:ex;size:1024"` +} + +func (OrganizationUser) TableName() string { + return "organization_users" +} + +type DepartmentMember struct { + UserID string `gorm:"column:user_id;primary_key;size:64"` + DepartmentID string `gorm:"column:department_id;primary_key;size:64"` + Order int32 `gorm:"column:order" json:"order"` //1,2 + Position string `gorm:"column:position;size:256" json:"position"` + Leader int32 `gorm:"column:leader" json:"leader"` //-1, 1 + Status int32 `gorm:"column:status" json:"status"` //-1, 1 + CreateTime time.Time `gorm:"column:create_time"` + Ex string `gorm:"column:ex;type:varchar(1024)" json:"ex"` +} + +func (DepartmentMember) TableName() string { + return "department_members" +} diff --git a/pkg/common/db/mongoModel.go b/pkg/common/db/mongoModel.go new file mode 100644 index 000000000..6d7ff3f7c --- /dev/null +++ b/pkg/common/db/mongoModel.go @@ -0,0 +1,681 @@ +package db + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/log" + pbMsg "Open_IM/pkg/proto/chat" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "context" + "errors" + "fmt" + "github.com/gogo/protobuf/sortkeys" + "go.mongodb.org/mongo-driver/mongo/options" + "math/rand" + + //"github.com/garyburd/redigo/redis" + "github.com/golang/protobuf/proto" + "gopkg.in/mgo.v2/bson" + + "strconv" + "time" +) + +const cChat = "msg" +const cGroup = "group" +const cTag = "tag" +const cSendLog = "send_log" +const singleGocMsgNum = 5000 + +type MsgInfo struct { + SendTime int64 + Msg []byte +} + +type UserChat struct { + UID string + Msg []MsgInfo +} + +type GroupMember_x struct { + GroupID string + UIDList []string +} + +func (d *DataBases) GetMinSeqFromMongo(uid string) (MinSeq uint32, err error) { + return 1, nil + //var i, NB uint32 + //var seqUid string + //session := d.mgoSession.Clone() + //if session == nil { + // return MinSeq, errors.New("session == nil") + //} + //defer session.Close() + //c := session.DB(config.Config.Mongo.DBDatabase).C(cChat) + //MaxSeq, err := d.GetUserMaxSeq(uid) + //if err != nil && err != redis.ErrNil { + // return MinSeq, err + //} + //NB = uint32(MaxSeq / singleGocMsgNum) + //for i = 0; i <= NB; i++ { + // seqUid = indexGen(uid, i) + // n, err := c.Find(bson.M{"uid": seqUid}).Count() + // if err == nil && n != 0 { + // if i == 0 { + // MinSeq = 1 + // } else { + // MinSeq = uint32(i * singleGocMsgNum) + // } + // break + // } + //} + //return MinSeq, nil +} + +func (d *DataBases) GetMinSeqFromMongo2(uid string) (MinSeq uint32, err error) { + return 1, nil +} + +// deleteMsgByLogic +func (d *DataBases) DelMsgLogic(uid string, seqList []uint32, operationID string) error { + sortkeys.Uint32s(seqList) + seqMsgs, err := d.GetMsgBySeqListMongo2(uid, seqList, operationID) + if err != nil { + return utils.Wrap(err, "") + } + for _, seqMsg := range seqMsgs { + log.NewDebug(operationID, utils.GetSelfFuncName(), *seqMsg) + seqMsg.Status = constant.MsgDeleted + if err = d.ReplaceMsgBySeq(uid, seqMsg, operationID); err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "ReplaceMsgListBySeq error", err.Error()) + } + } + return nil +} + +func (d *DataBases) ReplaceMsgBySeq(uid string, msg *open_im_sdk.MsgData, operationID string) error { + log.NewInfo(operationID, utils.GetSelfFuncName(), uid, *msg) + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat) + uid = getSeqUid(uid, msg.Seq) + seqIndex := getMsgIndex(msg.Seq) + s := fmt.Sprintf("msg.%d.msg", seqIndex) + log.NewDebug(operationID, utils.GetSelfFuncName(), seqIndex, s) + bytes, err := proto.Marshal(msg) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "proto marshal", err.Error()) + return utils.Wrap(err, "") + } + updateResult, err := c.UpdateOne( + ctx, bson.M{"uid": uid}, + bson.M{"$set": bson.M{s: bytes}}) + log.NewInfo(operationID, utils.GetSelfFuncName(), updateResult) + if err != nil { + log.NewError(operationID, utils.GetSelfFuncName(), "UpdateOne", err.Error()) + return utils.Wrap(err, "") + } + return nil +} + +func (d *DataBases) GetMsgBySeqList(uid string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, err error) { + log.NewInfo(operationID, utils.GetSelfFuncName(), uid, seqList) + var hasSeqList []uint32 + singleCount := 0 + session := d.mgoSession.Clone() + if session == nil { + return nil, errors.New("session == nil") + } + defer session.Close() + c := session.DB(config.Config.Mongo.DBDatabase).C(cChat) + m := func(uid string, seqList []uint32) map[string][]uint32 { + t := make(map[string][]uint32) + for i := 0; i < len(seqList); i++ { + seqUid := getSeqUid(uid, seqList[i]) + if value, ok := t[seqUid]; !ok { + var temp []uint32 + t[seqUid] = append(temp, seqList[i]) + } else { + t[seqUid] = append(value, seqList[i]) + } + } + return t + }(uid, seqList) + sChat := UserChat{} + for seqUid, value := range m { + if err = c.Find(bson.M{"uid": seqUid}).One(&sChat); err != nil { + log.NewError(operationID, "not find seqUid", seqUid, value, uid, seqList, err.Error()) + continue + } + singleCount = 0 + for i := 0; i < len(sChat.Msg); i++ { + msg := new(open_im_sdk.MsgData) + if err = proto.Unmarshal(sChat.Msg[i].Msg, msg); err != nil { + log.NewError(operationID, "Unmarshal err", seqUid, value, uid, seqList, err.Error()) + return nil, err + } + if isContainInt32(msg.Seq, value) { + seqMsg = append(seqMsg, msg) + hasSeqList = append(hasSeqList, msg.Seq) + singleCount++ + if singleCount == len(value) { + break + } + } + } + } + if len(hasSeqList) != len(seqList) { + var diff []uint32 + diff = utils.Difference(hasSeqList, seqList) + exceptionMSg := genExceptionMessageBySeqList(diff) + seqMsg = append(seqMsg, exceptionMSg...) + + } + return seqMsg, nil +} + +func (d *DataBases) GetMsgBySeqListMongo2(uid string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, err error) { + var hasSeqList []uint32 + singleCount := 0 + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat) + + m := func(uid string, seqList []uint32) map[string][]uint32 { + t := make(map[string][]uint32) + for i := 0; i < len(seqList); i++ { + seqUid := getSeqUid(uid, seqList[i]) + if value, ok := t[seqUid]; !ok { + var temp []uint32 + t[seqUid] = append(temp, seqList[i]) + } else { + t[seqUid] = append(value, seqList[i]) + } + } + return t + }(uid, seqList) + sChat := UserChat{} + for seqUid, value := range m { + if err = c.FindOne(ctx, bson.M{"uid": seqUid}).Decode(&sChat); err != nil { + log.NewError(operationID, "not find seqUid", seqUid, value, uid, seqList, err.Error()) + continue + } + singleCount = 0 + for i := 0; i < len(sChat.Msg); i++ { + msg := new(open_im_sdk.MsgData) + if err = proto.Unmarshal(sChat.Msg[i].Msg, msg); err != nil { + log.NewError(operationID, "Unmarshal err", seqUid, value, uid, seqList, err.Error()) + return nil, err + } + if isContainInt32(msg.Seq, value) { + seqMsg = append(seqMsg, msg) + hasSeqList = append(hasSeqList, msg.Seq) + singleCount++ + if singleCount == len(value) { + break + } + } + } + } + if len(hasSeqList) != len(seqList) { + var diff []uint32 + diff = utils.Difference(hasSeqList, seqList) + exceptionMSg := genExceptionMessageBySeqList(diff) + seqMsg = append(seqMsg, exceptionMSg...) + + } + return seqMsg, nil +} + +func genExceptionMessageBySeqList(seqList []uint32) (exceptionMsg []*open_im_sdk.MsgData) { + for _, v := range seqList { + msg := new(open_im_sdk.MsgData) + msg.Seq = v + exceptionMsg = append(exceptionMsg, msg) + } + return exceptionMsg +} + +func (d *DataBases) SaveUserChatMongo2(uid string, sendTime int64, m *pbMsg.MsgDataToDB) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat) + newTime := getCurrentTimestampByMill() + operationID := "" + seqUid := getSeqUid(uid, m.MsgData.Seq) + filter := bson.M{"uid": seqUid} + var err error + sMsg := MsgInfo{} + sMsg.SendTime = sendTime + if sMsg.Msg, err = proto.Marshal(m.MsgData); err != nil { + return utils.Wrap(err, "") + } + err = c.FindOneAndUpdate(ctx, filter, bson.M{"$push": bson.M{"msg": sMsg}}).Err() + log.NewDebug(operationID, "get mgoSession cost time", getCurrentTimestampByMill()-newTime) + if err != nil { + sChat := UserChat{} + sChat.UID = seqUid + sChat.Msg = append(sChat.Msg, sMsg) + if _, err = c.InsertOne(ctx, &sChat); err != nil { + log.NewDebug(operationID, "InsertOne failed", filter) + return utils.Wrap(err, "") + } + } else { + log.NewDebug(operationID, "FindOneAndUpdate ok", filter) + } + + log.NewDebug(operationID, "find mgo uid cost time", getCurrentTimestampByMill()-newTime) + return nil +} + +func (d *DataBases) SaveUserChat(uid string, sendTime int64, m *pbMsg.MsgDataToDB) error { + var seqUid string + newTime := getCurrentTimestampByMill() + session := d.mgoSession.Clone() + if session == nil { + return errors.New("session == nil") + } + defer session.Close() + log.NewDebug("", "get mgoSession cost time", getCurrentTimestampByMill()-newTime) + c := session.DB(config.Config.Mongo.DBDatabase).C(cChat) + seqUid = getSeqUid(uid, m.MsgData.Seq) + n, err := c.Find(bson.M{"uid": seqUid}).Count() + if err != nil { + return err + } + log.NewDebug("", "find mgo uid cost time", getCurrentTimestampByMill()-newTime) + sMsg := MsgInfo{} + sMsg.SendTime = sendTime + if sMsg.Msg, err = proto.Marshal(m.MsgData); err != nil { + return err + } + if n == 0 { + sChat := UserChat{} + sChat.UID = seqUid + sChat.Msg = append(sChat.Msg, sMsg) + err = c.Insert(&sChat) + if err != nil { + return err + } + } else { + err = c.Update(bson.M{"uid": seqUid}, bson.M{"$push": bson.M{"msg": sMsg}}) + if err != nil { + return err + } + } + log.NewDebug("", "insert mgo data cost time", getCurrentTimestampByMill()-newTime) + return nil +} + +func (d *DataBases) DelUserChat(uid string) error { + return nil + //session := d.mgoSession.Clone() + //if session == nil { + // return errors.New("session == nil") + //} + //defer session.Close() + // + //c := session.DB(config.Config.Mongo.DBDatabase).C(cChat) + // + //delTime := time.Now().Unix() - int64(config.Config.Mongo.DBRetainChatRecords)*24*3600 + //if err := c.Update(bson.M{"uid": uid}, bson.M{"$pull": bson.M{"msg": bson.M{"sendtime": bson.M{"$lte": delTime}}}}); err != nil { + // return err + //} + // + //return nil +} + +func (d *DataBases) DelUserChatMongo2(uid string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat) + filter := bson.M{"uid": uid} + + delTime := time.Now().Unix() - int64(config.Config.Mongo.DBRetainChatRecords)*24*3600 + if _, err := c.UpdateOne(ctx, filter, bson.M{"$pull": bson.M{"msg": bson.M{"sendtime": bson.M{"$lte": delTime}}}}); err != nil { + return utils.Wrap(err, "") + } + return nil +} + +func (d *DataBases) MgoUserCount() (int, error) { + return 0, nil + //session := d.mgoSession.Clone() + //if session == nil { + // return 0, errors.New("session == nil") + //} + //defer session.Close() + // + //c := session.DB(config.Config.Mongo.DBDatabase).C(cChat) + // + //return c.Find(nil).Count() +} + +func (d *DataBases) MgoSkipUID(count int) (string, error) { + return "", nil + //session := d.mgoSession.Clone() + //if session == nil { + // return "", errors.New("session == nil") + //} + //defer session.Close() + // + //c := session.DB(config.Config.Mongo.DBDatabase).C(cChat) + // + //sChat := UserChat{} + //c.Find(nil).Skip(count).Limit(1).One(&sChat) + //return sChat.UID, nil +} + +func (d *DataBases) GetGroupMember(groupID string) []string { + return nil + //groupInfo := GroupMember_x{} + //groupInfo.GroupID = groupID + //groupInfo.UIDList = make([]string, 0) + // + //session := d.mgoSession.Clone() + //if session == nil { + // return groupInfo.UIDList + //} + //defer session.Close() + // + //c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup) + // + //if err := c.Find(bson.M{"groupid": groupInfo.GroupID}).One(&groupInfo); err != nil { + // return groupInfo.UIDList + //} + // + //return groupInfo.UIDList +} + +func (d *DataBases) AddGroupMember(groupID, uid string) error { + return nil + //session := d.mgoSession.Clone() + //if session == nil { + // return errors.New("session == nil") + //} + //defer session.Close() + // + //c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup) + // + //n, err := c.Find(bson.M{"groupid": groupID}).Count() + //if err != nil { + // return err + //} + // + //if n == 0 { + // groupInfo := GroupMember_x{} + // groupInfo.GroupID = groupID + // groupInfo.UIDList = append(groupInfo.UIDList, uid) + // err = c.Insert(&groupInfo) + // if err != nil { + // return err + // } + //} else { + // err = c.Update(bson.M{"groupid": groupID}, bson.M{"$addToSet": bson.M{"uidlist": uid}}) + // if err != nil { + // return err + // } + //} + // + //return nil +} + +func (d *DataBases) DelGroupMember(groupID, uid string) error { + return nil + //session := d.mgoSession.Clone() + //if session == nil { + // return errors.New("session == nil") + //} + //defer session.Close() + // + //c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup) + // + //if err := c.Update(bson.M{"groupid": groupID}, bson.M{"$pull": bson.M{"uidlist": uid}}); err != nil { + // return err + //} + // + //return nil +} + +type Tag struct { + UserID string `bson:"user_id"` + TagID string `bson:"tag_id"` + TagName string `bson:"tag_name"` + UserList []string `bson:"user_list"` +} + +func (d *DataBases) GetUserTags(userID string) ([]Tag, error) { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag) + var tags []Tag + cursor, err := c.Find(ctx, bson.M{"user_id": userID}) + if err != nil { + return tags, err + } + if err = cursor.All(ctx, &tags); err != nil { + return tags, err + } + return tags, nil +} + +func (d *DataBases) CreateTag(userID, tagName string, userList []string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag) + tagID := generateTagID(tagName, userID) + tag := Tag{ + UserID: userID, + TagID: tagID, + TagName: tagName, + UserList: userList, + } + _, err := c.InsertOne(ctx, tag) + return err +} + +func (d *DataBases) GetTagByID(userID, tagID string) (Tag, error) { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag) + var tag Tag + err := c.FindOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}).Decode(&tag) + return tag, err +} + +func (d *DataBases) DeleteTag(userID, tagID string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag) + _, err := c.DeleteOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}) + return err +} + +func (d *DataBases) SetTag(userID, tagID, newName string, increaseUserIDList []string, reduceUserIDList []string) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag) + var tag Tag + if err := c.FindOne(ctx, bson.M{"tag_id": tagID, "user_id": userID}).Decode(&tag); err != nil { + return err + } + if newName != "" { + _, err := c.UpdateOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}, bson.M{"$set": bson.M{"tag_name": newName}}) + if err != nil { + return err + } + } + tag.UserList = append(tag.UserList, increaseUserIDList...) + tag.UserList = utils.RemoveRepeatedStringInList(tag.UserList) + for _, v := range reduceUserIDList { + for i2, v2 := range tag.UserList { + if v == v2 { + tag.UserList[i2] = "" + } + } + } + var newUserList []string + for _, v := range tag.UserList { + if v != "" { + newUserList = append(newUserList, v) + } + } + _, err := c.UpdateOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}, bson.M{"$set": bson.M{"user_list": newUserList}}) + if err != nil { + return err + } + return nil +} + +func (d *DataBases) GetUserIDListByTagID(userID, tagID string) ([]string, error) { + var tag Tag + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cTag) + _ = c.FindOne(ctx, bson.M{"user_id": userID, "tag_id": tagID}).Decode(&tag) + return tag.UserList, nil +} + +type TagUser struct { + UserID string `bson:"user_id"` + UserName string `bson:"user_name"` +} + +type TagSendLog struct { + UserList []TagUser `bson:"tag_list"` + SendID string `bson:"send_id"` + SenderPlatformID int32 `bson:"sender_platform_id"` + Content string `bson:"content"` + SendTime int64 `bson:"send_time"` +} + +func (d *DataBases) SaveTagSendLog(tagSendLog *TagSendLog) error { + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSendLog) + _, err := c.InsertOne(ctx, tagSendLog) + return err +} + +func (d *DataBases) GetTagSendLogs(userID string, showNumber, pageNumber int32) ([]TagSendLog, error) { + var tagSendLogs []TagSendLog + ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second) + c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cSendLog) + findOpts := options.Find().SetLimit(int64(showNumber)).SetSkip(int64(showNumber) * (int64(pageNumber) - 1)).SetSort(bson.M{"send_time": -1}) + cursor, err := c.Find(ctx, bson.M{"send_id": userID}, findOpts) + if err != nil { + return tagSendLogs, err + } + err = cursor.All(ctx, &tagSendLogs) + if err != nil { + return tagSendLogs, err + } + return tagSendLogs, nil +} + +type WorkMoment struct { + WorkMomentID string `bson:"work_moment_id"` + UserID string `bson:"user_id"` + Content string `bson:"content"` + LikeUsers []*LikeUser `bson:"like_users"` + Comments []*Comment `bson:"comments"` + WhoCanSeeUserIDList []string `bson:"who_can_see_user_id_list"` + WhoCantSeeUserIDList []string `bson:"who_cant_see_user_id_list"` + IsPrivate bool + IsPublic bool + CreateTime int32 +} + +type LikeUser struct { + UserID string + UserName string +} + +type Comment struct { + UserID string + UserName string + ReplyUserID string + ReplyUserName string + ContentID string + Content string + CreateTime int32 +} + +func (d *DataBases) CreateOneWorkMoment(workMoment *WorkMoment) error { + return nil +} + +func (d *DataBases) DeleteOneWorkMoment(workMomentID string) error { + return nil +} + +func (d *DataBases) GetWorkMomentByID(workMomentID string) (*WorkMoment, error) { + return nil, nil +} + +func (d *DataBases) LikeOneWorkMoment(likeUserID, workMomentID string) error { + return nil +} + +func (d *DataBases) SetUserWorkMomentsLevel(userID string, level int32) error { + return nil +} + +func (d *DataBases) ClearUserWorkMomentsCommentsMsg(userID string) error { + return nil +} + +type CommentMsg struct { + WorkMomentID string `bson:"workMoment"` + CommentContent string `bson:"content"` + Comment +} + +func (d *DataBases) GetUserWorkMomentsCommentsMsg(userID string, showNumber, pageNumber int32) ([]CommentMsg, error) { + return nil, nil +} + +func (d *DataBases) CommentOneWorkMoment(comment Comment, workMomentID string) error { + return nil +} + +func (d *DataBases) GetUserWorkMoments(userID string, showNumber, pageNumber int32) ([]WorkMoment, error) { + return nil, nil +} + +func (d *DataBases) GetUserFriendWorkMoments(friendIDList []string, showNumber, pageNumber int32) ([]WorkMoment, error) { + return nil, nil +} + +func generateTagID(tagName, userID string) string { + return utils.Md5(tagName + userID + strconv.Itoa(rand.Int()) + time.Now().String()) +} + +func generateWorkMomentID(userID string) string { + return utils.Md5(userID + strconv.Itoa(rand.Int()) + time.Now().String()) +} + +func getCurrentTimestampByMill() int64 { + return time.Now().UnixNano() / 1e6 +} + +func getSeqUid(uid string, seq uint32) string { + seqSuffix := seq / singleGocMsgNum + return indexGen(uid, seqSuffix) +} + +func getMsgIndex(seq uint32) int { + seqSuffix := seq / singleGocMsgNum + var index uint32 + if seqSuffix == 0 { + index = (seq - seqSuffix*5000) - 1 + } else { + index = seq - seqSuffix*singleGocMsgNum + } + return int(index) +} + +func isContainInt32(target uint32, List []uint32) bool { + + for _, element := range List { + + if target == element { + return true + } + } + return false + +} +func indexGen(uid string, seqSuffix uint32) string { + return uid + ":" + strconv.FormatInt(int64(seqSuffix), 10) +} diff --git a/pkg/common/db/mysql.go b/pkg/common/db/mysql.go new file mode 100644 index 000000000..cfef4dfee --- /dev/null +++ b/pkg/common/db/mysql.go @@ -0,0 +1,162 @@ +package db + +import ( + "Open_IM/pkg/common/config" + + "fmt" + "sync" + "time" + + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/mysql" +) + +type mysqlDB struct { + sync.RWMutex + dbMap map[string]*gorm.DB +} + +func initMysqlDB() { + //When there is no open IM database, connect to the mysql built-in database to create openIM database + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", + config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], "mysql") + var db *gorm.DB + var err1 error + db, err := gorm.Open("mysql", dsn) + if err != nil { + fmt.Println("0", "Open failed ", err.Error(), dsn) + } + if err != nil { + time.Sleep(time.Duration(30) * time.Second) + db, err1 = gorm.Open("mysql", dsn) + if err1 != nil { + fmt.Println("0", "Open failed ", err1.Error(), dsn) + panic(err1.Error()) + } + } + + //Check the database and table during initialization + sql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8 COLLATE utf8_general_ci;", config.Config.Mysql.DBDatabaseName) + err = db.Exec(sql).Error + if err != nil { + fmt.Println("0", "Exec failed ", err.Error(), sql) + panic(err.Error()) + } + db.Close() + + dsn = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", + config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName) + db, err = gorm.Open("mysql", dsn) + if err != nil { + fmt.Println("0", "Open failed ", err.Error(), dsn) + panic(err.Error()) + } + + fmt.Println("open db ok ", dsn) + db.AutoMigrate(&Friend{}, + &FriendRequest{}, + &Group{}, + &GroupMember{}, + &GroupRequest{}, + &User{}, + &Black{}, &ChatLog{}, &Register{}, &Conversation{}) + db.Set("gorm:table_options", "CHARSET=utf8") + db.Set("gorm:table_options", "collation=utf8_unicode_ci") + + if !db.HasTable(&Friend{}) { + fmt.Println("CreateTable Friend") + db.CreateTable(&Friend{}) + } + + if !db.HasTable(&FriendRequest{}) { + fmt.Println("CreateTable FriendRequest") + db.CreateTable(&FriendRequest{}) + } + + if !db.HasTable(&Group{}) { + fmt.Println("CreateTable Group") + db.CreateTable(&Group{}) + } + + if !db.HasTable(&GroupMember{}) { + fmt.Println("CreateTable GroupMember") + db.CreateTable(&GroupMember{}) + } + if !db.HasTable(&GroupRequest{}) { + fmt.Println("CreateTable GroupRequest") + db.CreateTable(&GroupRequest{}) + } + if !db.HasTable(&User{}) { + fmt.Println("CreateTable User") + db.CreateTable(&User{}) + } + if !db.HasTable(&Black{}) { + fmt.Println("CreateTable Black") + db.CreateTable(&Black{}) + } + if !db.HasTable(&ChatLog{}) { + fmt.Println("CreateTable ChatLog") + db.CreateTable(&ChatLog{}) + } + if !db.HasTable(&Register{}) { + fmt.Println("CreateTable Register") + db.CreateTable(&Register{}) + } + if !db.HasTable(&Conversation{}) { + fmt.Println("CreateTable Conversation") + db.CreateTable(&Conversation{}) + } + + if !db.HasTable(&Department{}) { + fmt.Println("CreateTable Department") + db.CreateTable(&Department{}) + } + if !db.HasTable(&OrganizationUser{}) { + fmt.Println("CreateTable OrganizationUser") + db.CreateTable(&OrganizationUser{}) + } + if !db.HasTable(&DepartmentMember{}) { + fmt.Println("CreateTable DepartmentMember") + db.CreateTable(&DepartmentMember{}) + } + + return +} + +func (m *mysqlDB) DefaultGormDB() (*gorm.DB, error) { + return m.GormDB(config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName) +} + +func (m *mysqlDB) GormDB(dbAddress, dbName string) (*gorm.DB, error) { + m.Lock() + defer m.Unlock() + + k := key(dbAddress, dbName) + if _, ok := m.dbMap[k]; !ok { + if err := m.open(dbAddress, dbName); err != nil { + return nil, err + } + } + return m.dbMap[k], nil +} + +func (m *mysqlDB) open(dbAddress, dbName string) error { + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", + config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, dbAddress, dbName) + db, err := gorm.Open("mysql", dsn) + if err != nil { + return err + } + + db.SingularTable(true) + db.DB().SetMaxOpenConns(config.Config.Mysql.DBMaxOpenConns) + db.DB().SetMaxIdleConns(config.Config.Mysql.DBMaxIdleConns) + db.DB().SetConnMaxLifetime(time.Duration(config.Config.Mysql.DBMaxLifeTime) * time.Second) + + if m.dbMap == nil { + m.dbMap = make(map[string]*gorm.DB) + } + k := key(dbAddress, dbName) + m.dbMap[k] = db + return nil +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/demo_model.go b/pkg/common/db/mysql_model/im_mysql_model/demo_model.go new file mode 100644 index 000000000..eff3050be --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/demo_model.go @@ -0,0 +1,41 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + _ "github.com/jinzhu/gorm" +) + +func GetRegister(account string) (*db.Register, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var r db.Register + return &r, dbConn.Table("registers").Where("account = ?", + account).Take(&r).Error +} + +func SetPassword(account, password, ex string) error { + r := db.Register{ + Account: account, + Password: password, + Ex: ex, + } + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + return dbConn.Table("registers").Create(&r).Error +} + +func ResetPassword(account, password string) error { + r := db.Register{ + Password: password, + } + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + dbConn.LogMode(false) + if err != nil { + return err + } + return dbConn.Table("registers").Where("account = ?", account).Update(&r).Error +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/friend_model.go b/pkg/common/db/mysql_model/im_mysql_model/friend_model.go new file mode 100644 index 000000000..a7b14f198 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/friend_model.go @@ -0,0 +1,91 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + _ "github.com/jinzhu/gorm/dialects/mysql" + "time" +) + +func InsertToFriend(toInsertFollow *db.Friend) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + toInsertFollow.CreateTime = time.Now() + + err = dbConn.Table("friends").Create(toInsertFollow).Error + if err != nil { + return err + } + return nil +} + +func GetFriendRelationshipFromFriend(OwnerUserID, FriendUserID string) (*db.Friend, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var friend db.Friend + err = dbConn.Table("friends").Where("owner_user_id=? and friend_user_id=?", OwnerUserID, FriendUserID).Take(&friend).Error + if err != nil { + return nil, err + } + return &friend, err +} + +func GetFriendListByUserID(OwnerUserID string) ([]db.Friend, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var friends []db.Friend + var x db.Friend + x.OwnerUserID = OwnerUserID + err = dbConn.Table("friends").Where("owner_user_id=?", OwnerUserID).Find(&friends).Error + + if err != nil { + return nil, err + } + return friends, nil +} + +func GetFriendIDListByUserID(OwnerUserID string) ([]string, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var friendIDList []string + err = dbConn.Table("friends").Select("friend_user_id").Where("owner_user_id=?", OwnerUserID).Find(&friendIDList).Error + if err != nil { + return nil, err + } + return friendIDList, nil +} + +func UpdateFriendComment(OwnerUserID, FriendUserID, Remark string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Exec("update friends set remark=? where owner_user_id=? and friend_user_id=?", Remark, OwnerUserID, FriendUserID).Error + return err +} + +func DeleteSingleFriendInfo(OwnerUserID, FriendUserID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("friends").Where("owner_user_id=? and friend_user_id=?", OwnerUserID, FriendUserID).Delete(db.Friend{}).Error + return err +} + +//type Friend struct { +// OwnerUserID string `gorm:"column:owner_user_id;primaryKey;"` +// FriendUserID string `gorm:"column:friend_user_id;primaryKey;"` +// Remark string `gorm:"column:remark"` +// CreateTime time.Time `gorm:"column:create_time"` +// AddSource int32 `gorm:"column:add_source"` +// OperatorUserID string `gorm:"column:operator_user_id"` +// Ex string `gorm:"column:ex"` +//} diff --git a/pkg/common/db/mysql_model/im_mysql_model/friend_request_model.go b/pkg/common/db/mysql_model/im_mysql_model/friend_request_model.go new file mode 100644 index 000000000..171a6aedf --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/friend_request_model.go @@ -0,0 +1,112 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + "Open_IM/pkg/utils" + "time" +) + +//type FriendRequest struct { +// FromUserID string `gorm:"column:from_user_id;primaryKey;"` +// ToUserID string `gorm:"column:to_user_id;primaryKey;"` +// HandleResult int32 `gorm:"column:handle_result"` +// ReqMessage string `gorm:"column:req_message"` +// CreateTime time.Time `gorm:"column:create_time"` +// HandlerUserID string `gorm:"column:handler_user_id"` +// HandleMsg string `gorm:"column:handle_msg"` +// HandleTime time.Time `gorm:"column:handle_time"` +// Ex string `gorm:"column:ex"` +//} + +// who apply to add me +func GetReceivedFriendsApplicationListByUserID(ToUserID string) ([]db.FriendRequest, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var usersInfo []db.FriendRequest + err = dbConn.Table("friend_requests").Where("to_user_id=?", ToUserID).Find(&usersInfo).Error + if err != nil { + return nil, err + } + return usersInfo, nil +} + +//I apply to add somebody +func GetSendFriendApplicationListByUserID(FromUserID string) ([]db.FriendRequest, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var usersInfo []db.FriendRequest + err = dbConn.Table("friend_requests").Where("from_user_id=?", FromUserID).Find(&usersInfo).Error + if err != nil { + return nil, err + } + return usersInfo, nil +} + +//FromUserId apply to add ToUserID +func GetFriendApplicationByBothUserID(FromUserID, ToUserID string) (*db.FriendRequest, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var friendRequest db.FriendRequest + err = dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?", FromUserID, ToUserID).Take(&friendRequest).Error + if err != nil { + return nil, err + } + return &friendRequest, nil +} + +func UpdateFriendApplication(friendRequest *db.FriendRequest) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + friendRequest.CreateTime = time.Now() + + return dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?", + friendRequest.FromUserID, friendRequest.ToUserID).Update(&friendRequest).Error +} + +func InsertFriendApplication(friendRequest *db.FriendRequest, args map[string]interface{}) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + + if err = dbConn.Table("friend_requests").Create(friendRequest).Error; err == nil { + return nil + } + + //t := dbConn.Debug().Table("friend_requests").Where("from_user_id = ? and to_user_id = ?", friendRequest.FromUserID, friendRequest.ToUserID).Select("*").Updates(*friendRequest) + //if t.RowsAffected == 0 { + // return utils.Wrap(errors.New("RowsAffected == 0"), "no update") + //} + //return utils.Wrap(t.Error, "") + + friendRequest.CreateTime = time.Now() + args["create_time"] = friendRequest.CreateTime + u := dbConn.Model(friendRequest).Updates(args) + //u := dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?", + // friendRequest.FromUserID, friendRequest.ToUserID).Update(&friendRequest) + //u := dbConn.Table("friend_requests").Where("from_user_id=? and to_user_id=?", + // friendRequest.FromUserID, friendRequest.ToUserID).Update(&friendRequest) + if u.RowsAffected != 0 { + return nil + } + + if friendRequest.CreateTime.Unix() < 0 { + friendRequest.CreateTime = time.Now() + } + if friendRequest.HandleTime.Unix() < 0 { + friendRequest.HandleTime = utils.UnixSecondToTime(0) + } + err = dbConn.Table("friend_requests").Create(friendRequest).Error + if err != nil { + return err + } + return nil +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/group_member_model.go b/pkg/common/db/mysql_model/im_mysql_model/group_member_model.go new file mode 100644 index 000000000..289a157fc --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/group_member_model.go @@ -0,0 +1,316 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/utils" + "errors" + "fmt" + "time" +) + +//type GroupMember struct { +// GroupID string `gorm:"column:group_id;primaryKey;"` +// UserID string `gorm:"column:user_id;primaryKey;"` +// NickName string `gorm:"column:nickname"` +// FaceUrl string `gorm:"user_group_face_url"` +// RoleLevel int32 `gorm:"column:role_level"` +// JoinTime time.Time `gorm:"column:join_time"` +// JoinSource int32 `gorm:"column:join_source"` +// OperatorUserID string `gorm:"column:operator_user_id"` +// Ex string `gorm:"column:ex"` +//} + +func InsertIntoGroupMember(toInsertInfo db.GroupMember) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + toInsertInfo.JoinTime = time.Now() + if toInsertInfo.RoleLevel == 0 { + toInsertInfo.RoleLevel = constant.GroupOrdinaryUsers + } + toInsertInfo.MuteEndTime = time.Unix(int64(time.Now().Second()), 0) + err = dbConn.Table("group_members").Create(toInsertInfo).Error + if err != nil { + return err + } + return nil +} + +func GetGroupMemberListByUserID(userID string) ([]db.GroupMember, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupMemberList []db.GroupMember + err = dbConn.Table("group_members").Where("user_id=?", userID).Find(&groupMemberList).Error + //err = dbConn.Table("group_members").Where("user_id=?", userID).Take(&groupMemberList).Error + if err != nil { + return nil, err + } + return groupMemberList, nil +} + +func GetGroupMemberListByGroupID(groupID string) ([]db.GroupMember, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupMemberList []db.GroupMember + err = dbConn.Table("group_members").Where("group_id=?", groupID).Find(&groupMemberList).Error + + if err != nil { + return nil, err + } + return groupMemberList, nil +} + +func GetGroupMemberIDListByGroupID(groupID string) ([]string, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + dbConn.LogMode(false) + var groupMembers []db.GroupMember + err = dbConn.Table("group_members").Select("user_id").Where("group_id=?", groupID).Find(&groupMembers).Error + if err != nil { + return nil, err + } + var groupMemberIDList []string + for _, v := range groupMembers { + groupMemberIDList = append(groupMemberIDList, v.UserID) + } + return groupMemberIDList, nil +} + +func GetGroupMemberListByGroupIDAndRoleLevel(groupID string, roleLevel int32) ([]db.GroupMember, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupMemberList []db.GroupMember + err = dbConn.Table("group_members").Where("group_id=? and role_level=?", groupID, roleLevel).Find(&groupMemberList).Error + if err != nil { + return nil, err + } + return groupMemberList, nil +} + +func GetGroupMemberInfoByGroupIDAndUserID(groupID, userID string) (*db.GroupMember, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupMember db.GroupMember + err = dbConn.Table("group_members").Where("group_id=? and user_id=? ", groupID, userID).Limit(1).Take(&groupMember).Error + if err != nil { + return nil, err + } + return &groupMember, nil +} + +func DeleteGroupMemberByGroupIDAndUserID(groupID, userID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("group_members").Where("group_id=? and user_id=? ", groupID, userID).Delete(db.GroupMember{}).Error + if err != nil { + return err + } + return nil +} + +func DeleteGroupMemberByGroupID(groupID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("group_members").Where("group_id=? ", groupID).Delete(db.GroupMember{}).Error + if err != nil { + return err + } + return nil +} + +func UpdateGroupMemberInfo(groupMemberInfo db.GroupMember) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("group_members").Where("group_id=? and user_id=?", groupMemberInfo.GroupID, groupMemberInfo.UserID).Update(&groupMemberInfo).Error + if err != nil { + return err + } + return nil +} + +func GetOwnerManagerByGroupID(groupID string) ([]db.GroupMember, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupMemberList []db.GroupMember + err = dbConn.Table("group_members").Where("group_id=? and role_level>?", groupID, constant.GroupOrdinaryUsers).Find(&groupMemberList).Error + if err != nil { + return nil, err + } + return groupMemberList, nil +} + +func GetGroupMemberNumByGroupID(groupID string) (uint32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, utils.Wrap(err, "DefaultGormDB failed") + } + var number uint32 + err = dbConn.Table("group_members").Where("group_id=?", groupID).Count(&number).Error + if err != nil { + return 0, utils.Wrap(err, "") + } + return number, nil +} + +func GetGroupOwnerInfoByGroupID(groupID string) (*db.GroupMember, error) { + omList, err := GetOwnerManagerByGroupID(groupID) + if err != nil { + return nil, err + } + for _, v := range omList { + if v.RoleLevel == constant.GroupOwner { + return &v, nil + } + } + + return nil, utils.Wrap(errors.New("no owner"), "") +} + +func IsExistGroupMember(groupID, userID string) bool { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return false + } + var number int32 + err = dbConn.Table("group_members").Where("group_id = ? and user_id = ?", groupID, userID).Count(&number).Error + if err != nil { + return false + } + if number != 1 { + return false + } + return true +} + +func RemoveGroupMember(groupID string, UserID string) error { + return DeleteGroupMemberByGroupIDAndUserID(groupID, UserID) +} + +func GetMemberInfoByID(groupID string, userID string) (*db.GroupMember, error) { + return GetGroupMemberInfoByGroupIDAndUserID(groupID, userID) +} + +func GetGroupMemberByGroupID(groupID string, filter int32, begin int32, maxNumber int32) ([]db.GroupMember, error) { + var memberList []db.GroupMember + var err error + if filter >= 0 { + memberList, err = GetGroupMemberListByGroupIDAndRoleLevel(groupID, filter) //sorted by join time + } else { + memberList, err = GetGroupMemberListByGroupID(groupID) + } + + if err != nil { + return nil, err + } + if begin >= int32(len(memberList)) { + return nil, nil + } + + var end int32 + if begin+int32(maxNumber) < int32(len(memberList)) { + end = begin + maxNumber + } else { + end = int32(len(memberList)) + } + return memberList[begin:end], nil +} + +func GetJoinedGroupIDListByUserID(userID string) ([]string, error) { + memberList, err := GetGroupMemberListByUserID(userID) + if err != nil { + return nil, err + } + var groupIDList []string = make([]string, len(memberList)) + for _, v := range memberList { + groupIDList = append(groupIDList, v.GroupID) + } + return groupIDList, nil +} + +func IsGroupOwnerAdmin(groupID, UserID string) bool { + groupMemberList, err := GetOwnerManagerByGroupID(groupID) + if err != nil { + return false + } + for _, v := range groupMemberList { + if v.UserID == UserID && v.RoleLevel > constant.GroupOrdinaryUsers { + return true + } + } + return false +} + +func GetGroupMembersByGroupIdCMS(groupId string, userName string, showNumber, pageNumber int32) ([]db.GroupMember, error) { + var groupMembers []db.GroupMember + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return groupMembers, err + } + err = dbConn.Table("group_members").Where("group_id=?", groupId).Where(fmt.Sprintf(" nickname like '%%%s%%' ", userName)).Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&groupMembers).Error + if err != nil { + return nil, err + } + return groupMembers, nil +} + +func GetGroupMembersCount(groupId, userName string) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var count int32 + if err != nil { + return count, err + } + dbConn.LogMode(false) + if err := dbConn.Table("group_members").Where("group_id=?", groupId).Where(fmt.Sprintf(" nickname like '%%%s%%' ", userName)).Count(&count).Error; err != nil { + return count, err + } + return count, nil +} + +func UpdateGroupMemberInfoDefaultZero(groupMemberInfo db.GroupMember, args map[string]interface{}) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + return dbConn.Model(groupMemberInfo).Updates(args).Error +} + +// +//func SelectGroupList(groupID string) ([]string, error) { +// var groupUserID string +// var groupList []string +// dbConn, err := db.DB.MysqlDB.DefaultGormDB() +// if err != nil { +// return groupList, err +// } +// +// rows, err := dbConn.Model(&GroupMember{}).Where("group_id = ?", groupID).Select("user_id").Rows() +// if err != nil { +// return groupList, err +// } +// defer rows.Close() +// for rows.Next() { +// rows.Scan(&groupUserID) +// groupList = append(groupList, groupUserID) +// } +// return groupList, nil +//} diff --git a/pkg/common/db/mysql_model/im_mysql_model/group_model.go b/pkg/common/db/mysql_model/im_mysql_model/group_model.go new file mode 100644 index 000000000..9056bfb00 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/group_model.go @@ -0,0 +1,225 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/utils" + "errors" + "fmt" + "github.com/jinzhu/gorm" + "time" +) + +//type Group struct { +// GroupID string `gorm:"column:group_id;primaryKey;"` +// GroupName string `gorm:"column:name"` +// Introduction string `gorm:"column:introduction"` +// Notification string `gorm:"column:notification"` +// FaceUrl string `gorm:"column:face_url"` +// CreateTime time.Time `gorm:"column:create_time"` +// Status int32 `gorm:"column:status"` +// CreatorUserID string `gorm:"column:creator_user_id"` +// GroupType int32 `gorm:"column:group_type"` +// Ex string `gorm:"column:ex"` +//} + +func InsertIntoGroup(groupInfo db.Group) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + if groupInfo.GroupName == "" { + groupInfo.GroupName = "Group Chat" + } + groupInfo.CreateTime = time.Now() + err = dbConn.Table("groups").Create(groupInfo).Error + if err != nil { + return err + } + return nil +} + +func GetGroupInfoByGroupID(groupId string) (*db.Group, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, utils.Wrap(err, "") + } + var groupInfo db.Group + err = dbConn.Table("groups").Where("group_id=?", groupId).Take(&groupInfo).Error + if err != nil { + return nil, err + } + return &groupInfo, nil +} + +func SetGroupInfo(groupInfo db.Group) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("groups").Where("group_id=?", groupInfo.GroupID).Update(&groupInfo).Error + return err +} + +func GetGroupsByName(groupName string, pageNumber, showNumber int32) ([]db.Group, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var groups []db.Group + if err != nil { + return groups, err + } + + err = dbConn.Table("groups").Where(fmt.Sprintf(" name like '%%%s%%' ", groupName)).Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&groups).Error + return groups, err +} + +func GetGroups(pageNumber, showNumber int) ([]db.Group, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var groups []db.Group + if err != nil { + return groups, err + } + + if err = dbConn.Table("groups").Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&groups).Error; err != nil { + return groups, err + } + return groups, nil +} + +func OperateGroupStatus(groupId string, groupStatus int32) error { + group := db.Group{ + GroupID: groupId, + Status: groupStatus, + } + if err := SetGroupInfo(group); err != nil { + return err + } + return nil +} + +func DeleteGroup(groupId string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + + var group db.Group + var groupMembers []db.GroupMember + if err := dbConn.Table("groups").Where("group_id=?", groupId).Delete(&group).Error; err != nil { + return err + } + if err := dbConn.Table("group_members").Where("group_id=?", groupId).Delete(groupMembers).Error; err != nil { + return err + } + return nil +} + +func OperateGroupRole(userId, groupId string, roleLevel int32) (string, string, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return "", "", err + } + groupMember := db.GroupMember{ + UserID: userId, + GroupID: groupId, + } + updateInfo := db.GroupMember{ + RoleLevel: roleLevel, + } + groupMaster := db.GroupMember{} + switch roleLevel { + case constant.GroupOwner: + err = dbConn.Transaction(func(tx *gorm.DB) error { + result := dbConn.Table("group_members").Where("group_id = ? and role_level = ?", groupId, constant.GroupOwner).First(&groupMaster).Update(&db.GroupMember{ + RoleLevel: constant.GroupOrdinaryUsers, + }) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId)) + } + + result = dbConn.Table("group_members").First(&groupMember).Update(updateInfo) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId)) + } + return nil + }) + + case constant.GroupOrdinaryUsers: + err = dbConn.Transaction(func(tx *gorm.DB) error { + result := dbConn.Table("group_members").Where("group_id = ? and role_level = ?", groupId, constant.GroupOwner).First(&groupMaster) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId)) + } + if groupMaster.UserID == userId { + return errors.New(fmt.Sprintf("user %s is master of %s, cant set to ordinary user", userId, groupId)) + } else { + result = dbConn.Table("group_members").Find(&groupMember).Update(updateInfo) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return errors.New(fmt.Sprintf("user %s not exist in group %s or already operate", userId, groupId)) + } + } + return nil + }) + } + return "", "", nil +} + +func GetGroupsCountNum(group db.Group) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + + var count int32 + if err := dbConn.Table("groups").Where(fmt.Sprintf(" name like '%%%s%%' ", group.GroupName)).Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} + +func GetGroupById(groupId string) (db.Group, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + group := db.Group{ + GroupID: groupId, + } + if err != nil { + return group, err + } + + if err := dbConn.Table("groups").Find(&group).Error; err != nil { + return group, err + } + return group, nil +} + +func GetGroupMaster(groupId string) (db.GroupMember, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + groupMember := db.GroupMember{} + if err != nil { + return groupMember, err + } + + if err := dbConn.Table("group_members").Where("role_level=? and group_id=?", constant.GroupOwner, groupId).Find(&groupMember).Error; err != nil { + return groupMember, err + } + return groupMember, nil +} + +func UpdateGroupInfoDefaultZero(groupID string, args map[string]interface{}) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + return dbConn.Table("groups").Where("group_id = ? ", groupID).Update(args).Error +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/group_request_model.go b/pkg/common/db/mysql_model/im_mysql_model/group_request_model.go new file mode 100644 index 000000000..5e27cc3d2 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/group_request_model.go @@ -0,0 +1,209 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/utils" + "time" +) + +//type GroupRequest struct { +// UserID string `gorm:"column:user_id;primaryKey;"` +// GroupID string `gorm:"column:group_id;primaryKey;"` +// HandleResult int32 `gorm:"column:handle_result"` +// ReqMsg string `gorm:"column:req_msg"` +// HandledMsg string `gorm:"column:handled_msg"` +// ReqTime time.Time `gorm:"column:req_time"` +// HandleUserID string `gorm:"column:handle_user_id"` +// HandledTime time.Time `gorm:"column:handle_time"` +// Ex string `gorm:"column:ex"` +//} + +func UpdateGroupRequest(groupRequest db.GroupRequest) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + if groupRequest.HandledTime.Unix() < 0 { + groupRequest.HandledTime = utils.UnixSecondToTime(0) + } + return dbConn.Table("group_requests").Where("group_id=? and user_id=?", groupRequest.GroupID, groupRequest.UserID).Update(&groupRequest).Error +} + +func InsertIntoGroupRequest(toInsertInfo db.GroupRequest) error { + DelGroupRequestByGroupIDAndUserID(toInsertInfo.GroupID, toInsertInfo.UserID) + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + + if toInsertInfo.HandledTime.Unix() < 0 { + toInsertInfo.HandledTime = utils.UnixSecondToTime(0) + } + u := dbConn.Table("group_requests").Where("group_id=? and user_id=?", toInsertInfo.GroupID, toInsertInfo.UserID).Update(&toInsertInfo) + if u.RowsAffected != 0 { + return nil + } + + toInsertInfo.ReqTime = time.Now() + if toInsertInfo.HandledTime.Unix() < 0 { + toInsertInfo.HandledTime = utils.UnixSecondToTime(0) + } + + err = dbConn.Table("group_requests").Create(&toInsertInfo).Error + if err != nil { + return err + } + return nil +} + +func GetGroupRequestByGroupIDAndUserID(groupID, userID string) (*db.GroupRequest, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupRequest db.GroupRequest + err = dbConn.Table("group_requests").Where("user_id=? and group_id=?", userID, groupID).Take(&groupRequest).Error + if err != nil { + return nil, err + } + return &groupRequest, nil +} + +func DelGroupRequestByGroupIDAndUserID(groupID, userID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("group_requests").Where("group_id=? and user_id=?", groupID, userID).Delete(db.GroupRequest{}).Error + if err != nil { + return err + } + return nil +} + +func GetGroupRequestByGroupID(groupID string) ([]db.GroupRequest, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var groupRequestList []db.GroupRequest + err = dbConn.Table("group_requests").Where("group_id=?", groupID).Find(&groupRequestList).Error + if err != nil { + return nil, err + } + return groupRequestList, nil +} + +//received +func GetGroupApplicationList(userID string) ([]db.GroupRequest, error) { + var groupRequestList []db.GroupRequest + memberList, err := GetGroupMemberListByUserID(userID) + if err != nil { + return nil, err + } + for _, v := range memberList { + if v.RoleLevel > constant.GroupOrdinaryUsers { + list, err := GetGroupRequestByGroupID(v.GroupID) + if err != nil { + // fmt.Println("111 GetGroupRequestByGroupID failed ", err.Error()) + continue + } + // fmt.Println("222 GetGroupRequestByGroupID ok ", list) + groupRequestList = append(groupRequestList, list...) + // fmt.Println("333 GetGroupRequestByGroupID ok ", groupRequestList) + } + } + return groupRequestList, nil +} + +func GetUserReqGroupByUserID(userID string) ([]db.GroupRequest, error) { + var groupRequestList []db.GroupRequest + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + dbConn.LogMode(false) + err = dbConn.Table("group_requests").Where("user_id=?", userID).Find(&groupRequestList).Error + return groupRequestList, err +} + +// +//func GroupApplicationResponse(pb *group.GroupApplicationResponseReq) (*group.CommonResp, error) { +// +// ownerUser, err := FindGroupMemberInfoByGroupIdAndUserId(pb.GroupID, pb.OwnerID) +// if err != nil { +// log.ErrorByKv("FindGroupMemberInfoByGroupIdAndUserId failed", pb.OperationID, "groupId", pb.GroupID, "ownerID", pb.OwnerID) +// return nil, err +// } +// if ownerUser.AdministratorLevel <= 0 { +// return nil, errors.New("insufficient permissions") +// } +// +// dbConn, err := db.DB.MysqlDB.DefaultGormDB() +// if err != nil { +// return nil, err +// } +// var groupRequest GroupRequest +// err = dbConn.Raw("select * from `group_request` where handled_user = ? and group_id = ? and from_user_id = ? and to_user_id = ?", +// "", pb.GroupID, pb.FromUserID, pb.ToUserID).Scan(&groupRequest).Error +// if err != nil { +// log.ErrorByKv("find group_request info failed", pb.OperationID, "groupId", pb.GroupID, "fromUserId", pb.FromUserID, "toUserId", pb.OwnerID) +// return nil, err +// } +// +// if groupRequest.Flag != 0 { +// return nil, errors.New("application has already handle") +// } +// +// var saveFlag int +// if pb.HandleResult == 0 { +// saveFlag = -1 +// } else if pb.HandleResult == 1 { +// saveFlag = 1 +// } else { +// return nil, errors.New("parma HandleResult error") +// } +// err = dbConn.Exec("update `group_request` set flag = ?, handled_msg = ?, handled_user = ? where group_id = ? and from_user_id = ? and to_user_id = ?", +// saveFlag, pb.HandledMsg, pb.OwnerID, groupRequest.GroupID, groupRequest.FromUserID, groupRequest.ToUserID).Error +// if err != nil { +// log.ErrorByKv("update group request failed", pb.OperationID, "groupID", pb.GroupID, "flag", saveFlag, "ownerId", pb.OwnerID, "fromUserId", pb.FromUserID, "toUserID", pb.ToUserID) +// return nil, err +// } +// +// if saveFlag == 1 { +// if groupRequest.ToUserID == "0" { +// err = InsertIntoGroupMember(pb.GroupID, pb.FromUserID, groupRequest.FromUserNickname, groupRequest.FromUserFaceUrl, 0) +// if err != nil { +// log.ErrorByKv("InsertIntoGroupMember failed", pb.OperationID, "groupID", pb.GroupID, "fromUserId", pb.FromUserID) +// return nil, err +// } +// } else { +// err = InsertIntoGroupMember(pb.GroupID, pb.ToUserID, groupRequest.ToUserNickname, groupRequest.ToUserFaceUrl, 0) +// if err != nil { +// log.ErrorByKv("InsertIntoGroupMember failed", pb.OperationID, "groupID", pb.GroupID, "fromUserId", pb.FromUserID) +// return nil, err +// } +// } +// } +// +// return &group.GroupApplicationResponseResp{}, nil +//} + +//func FindGroupBeInvitedRequestInfoByUidAndGroupID(groupId, uid string) (*GroupRequest, error) { +// dbConn, err := db.DB.MysqlDB.DefaultGormDB() +// if err != nil { +// return nil, err +// } +// var beInvitedRequestUserInfo GroupRequest +// err = dbConn.Table("group_request").Where("to_user_id=? and group_id=?", uid, groupId).Find(&beInvitedRequestUserInfo).Error +// if err != nil { +// return nil, err +// } +// return &beInvitedRequestUserInfo, nil +// +//} + +//func InsertGroupRequest(groupId, fromUser, fromUserNickName, fromUserFaceUrl, toUser, requestMsg, handledMsg string, handleStatus int) error { +// return nil +//} diff --git a/pkg/common/db/mysql_model/im_mysql_model/message_cms.go b/pkg/common/db/mysql_model/im_mysql_model/message_cms.go new file mode 100644 index 000000000..29fb650cf --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/message_cms.go @@ -0,0 +1,68 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "fmt" +) + +func GetChatLog(chatLog db.ChatLog, pageNumber, showNumber int32) ([]db.ChatLog, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var chatLogs []db.ChatLog + if err != nil { + return chatLogs, err + } + dbConn.LogMode(false) + db := dbConn.Table("chat_logs"). + Where(fmt.Sprintf(" content like '%%%s%%'", chatLog.Content)). + Limit(showNumber).Offset(showNumber * (pageNumber - 1)) + if chatLog.SessionType != 0 { + db = db.Where("session_type = ?", chatLog.SessionType) + } + if chatLog.ContentType != 0 { + db = db.Where("content_type = ?", chatLog.ContentType) + } + if chatLog.SendID != "" { + db = db.Where("send_id = ?", chatLog.SendID) + } + if chatLog.RecvID != "" { + db = db.Where("recv_id = ?", chatLog.RecvID) + } + if chatLog.SendTime.Unix() > 0 { + db = db.Where("send_time > ? and send_time < ?", chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1)) + } + err = db.Find(&chatLogs).Error + return chatLogs, err +} + +func GetChatLogCount(chatLog db.ChatLog) (int64, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var chatLogs []db.ChatLog + var count int64 + if err != nil { + return count, err + } + dbConn.LogMode(false) + db := dbConn.Table("chat_logs"). + Where(fmt.Sprintf(" content like '%%%s%%'", chatLog.Content)) + if chatLog.SessionType != 0 { + db = db.Where("session_type = ?", chatLog.SessionType) + } + if chatLog.ContentType != 0 { + db = db.Where("content_type = ?", chatLog.ContentType) + } + if chatLog.SendID != "" { + db = db.Where("send_id = ?", chatLog.SendID) + } + if chatLog.RecvID != "" { + db = db.Where("recv_id = ?", chatLog.RecvID) + } + if chatLog.SendTime.Unix() > 0 { + log.NewDebug("", utils.GetSelfFuncName(), chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1)) + db = db.Where("send_time > ? and send_time < ?", chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1)) + } + + err = db.Find(&chatLogs).Count(&count).Error + return count, err +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/organization_model.go b/pkg/common/db/mysql_model/im_mysql_model/organization_model.go new file mode 100644 index 000000000..0b7f1621e --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/organization_model.go @@ -0,0 +1,182 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + "time" +) + +func CreateDepartment(department *db.Department) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + department.CreateTime = time.Now() + return dbConn.Table("departments").Create(department).Error +} + +func GetDepartment(departmentID string) (error, *db.Department) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err, nil + } + var department db.Department + err = dbConn.Table("departments").Where("department_id=?", departmentID).Find(&department).Error + return err, &department +} + +func UpdateDepartment(department *db.Department, args map[string]interface{}) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + if err = dbConn.Table("departments").Where("department_id=?", department.DepartmentID).Updates(department).Error; err != nil { + return err + } + if args != nil { + return dbConn.Table("departments").Where("department_id=?", department.DepartmentID).Updates(args).Error + } + return nil +} + +func GetSubDepartmentList(departmentID string) (error, []db.Department) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err, nil + } + var departmentList []db.Department + err = dbConn.Table("departments").Where("parent_id=?", departmentID).Find(&departmentList).Error + return err, departmentList +} + +func DeleteDepartment(departmentID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + if err = dbConn.Table("departments").Where("department_id=?", departmentID).Delete(db.Department{}).Error; err != nil { + return err + } + if err = dbConn.Table("department_members").Where("department_id=?", departmentID).Delete(db.DepartmentMember{}).Error; err != nil { + return err + } + return nil +} + +func CreateOrganizationUser(organizationUser *db.OrganizationUser) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + organizationUser.CreateTime = time.Now() + + return dbConn.Table("organization_users").Create(organizationUser).Error +} + +func GetOrganizationUser(userID string) (error, *db.OrganizationUser) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err, nil + } + organizationUser := db.OrganizationUser{} + err = dbConn.Table("organization_users").Where("user_id=?", userID).Take(&organizationUser).Error + return err, &organizationUser +} + +func UpdateOrganizationUser(organizationUser *db.OrganizationUser, args map[string]interface{}) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + if err = dbConn.Table("organization_users").Where("user_id=?", organizationUser.UserID).Updates(organizationUser).Error; err != nil { + return err + } + if args != nil { + return dbConn.Table("organization_users").Where("user_id=?", organizationUser.UserID).Updates(args).Error + } + return nil +} + +func CreateDepartmentMember(departmentMember *db.DepartmentMember) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + departmentMember.CreateTime = time.Now() + return dbConn.Table("department_members").Create(departmentMember).Error +} + +func GetUserInDepartment(userID string) (error, []db.DepartmentMember) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err, nil + } + var departmentMemberList []db.DepartmentMember + err = dbConn.Table("department_members").Where("user_id=?", userID).Take(&departmentMemberList).Error + return err, departmentMemberList +} + +func UpdateUserInDepartment(departmentMember *db.DepartmentMember, args map[string]interface{}) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + if err = dbConn.Table("department_members").Where("department_id=? ADN user_id=?", departmentMember.DepartmentID, departmentMember.UserID). + Updates(departmentMember).Error; err != nil { + return err + } + if args != nil { + return dbConn.Table("department_members").Where("department_id=? ADN user_id=?", departmentMember.DepartmentID, departmentMember.UserID). + Updates(args).Error + } + return nil +} + +func DeleteUserInDepartment(departmentID, userID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + return dbConn.Table("department_members").Where("department_id=? ADN user_id=?", departmentID, userID).Delete(db.DepartmentMember{}).Error +} + +func DeleteUserInAllDepartment(userID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + return dbConn.Table("department_members").Where("user_id=?", userID).Delete(db.DepartmentMember{}).Error +} + +func DeleteOrganizationUser(OrganizationUserID string) error { + if err := DeleteUserInAllDepartment(OrganizationUserID); err != nil { + return err + } + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + return dbConn.Table("organization_users").Where("user_id=?", OrganizationUserID).Delete(db.OrganizationUser{}).Error +} + +func GetDepartmentMemberUserIDList(departmentID string) (error, []string) { + //dbConn, err := db.DB.MysqlDB.DefaultGormDB() + //if err != nil { + // return err + //} + //return dbConn.Table("department_members").Where("user_id=?", userID).Delete(db.DepartmentMember{}).Error + + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err, nil + } + var departmentMemberList []db.DepartmentMember + err = dbConn.Table("department_members").Where("department_id=?", departmentID).Take(&departmentMemberList).Error + if err != nil { + return err, nil + } + var userIDList []string = make([]string, 0) + for _, v := range departmentMemberList { + userIDList = append(userIDList, v.UserID) + } + return err, userIDList +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/statistics_model.go b/pkg/common/db/mysql_model/im_mysql_model/statistics_model.go new file mode 100644 index 000000000..aa07c1688 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/statistics_model.go @@ -0,0 +1,153 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + "time" +) + +func GetActiveUserNum(from, to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("chat_logs").Select("count(distinct(send_id))").Where("create_time >= ? and create_time <= ?", from, to).Count(&num).Error + return num, err +} + +func GetIncreaseUserNum(from, to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("users").Where("create_time >= ? and create_time <= ?", from, to).Count(&num).Error + return num, err +} + +func GetTotalUserNum() (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("users").Count(&num).Error + return num, err +} + +func GetTotalUserNumByDate(to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("users").Where("create_time <= ?", to).Count(&num).Error + return num, err +} + +func GetPrivateMessageNum(from, to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("chat_logs").Where("create_time >= ? and create_time <= ? and session_type = ?", from, to, 1).Count(&num).Error + return num, err +} + +func GetGroupMessageNum(from, to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("chat_logs").Where("create_time >= ? and create_time <= ? and session_type = ?", from, to, 2).Count(&num).Error + return num, err +} + +func GetIncreaseGroupNum(from, to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("groups").Where("create_time >= ? and create_time <= ?", from, to).Count(&num).Error + return num, err +} + +func GetTotalGroupNum() (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("groups").Count(&num).Error + return num, err +} + +func GetGroupNum(to time.Time) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var num int32 + err = dbConn.Table("groups").Where("create_time <= ?", to).Count(&num).Error + return num, err +} + +type activeGroup struct { + Name string + Id string `gorm:"column:recv_id"` + MessageNum int `gorm:"column:message_num"` +} + +func GetActiveGroups(from, to time.Time, limit int) ([]*activeGroup, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var activeGroups []*activeGroup + if err != nil { + return activeGroups, err + } + dbConn.LogMode(false) + err = dbConn.Table("chat_logs").Select("recv_id, count(*) as message_num").Where("create_time >= ? and create_time <= ? and session_type = ?", from, to, 2).Group("recv_id").Limit(limit).Order("message_num DESC").Find(&activeGroups).Error + for _, activeGroup := range activeGroups { + group := db.Group{ + GroupID: activeGroup.Id, + } + dbConn.Table("groups").Where("group_id= ? ", group.GroupID).Find(&group) + activeGroup.Name = group.GroupName + } + return activeGroups, err +} + +type activeUser struct { + Name string + Id string `gorm:"column:send_id"` + MessageNum int `gorm:"column:message_num"` +} + +func GetActiveUsers(from, to time.Time, limit int) ([]*activeUser, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var activeUsers []*activeUser + if err != nil { + return activeUsers, err + } + dbConn.LogMode(false) + err = dbConn.Table("chat_logs").Select("send_id, count(*) as message_num").Where("create_time >= ? and create_time <= ? and session_type = ?", from, to, 1).Group("send_id").Limit(limit).Order("message_num DESC").Find(&activeUsers).Error + for _, activeUser := range activeUsers { + user := db.User{ + UserID: activeUser.Id, + } + dbConn.Table("users").Select("user_id, name").Find(&user) + activeUser.Name = user.Nickname + } + return activeUsers, err +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/user_black_list_model.go b/pkg/common/db/mysql_model/im_mysql_model/user_black_list_model.go new file mode 100644 index 000000000..7a60287a6 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/user_black_list_model.go @@ -0,0 +1,58 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/db" + "Open_IM/pkg/utils" + "time" +) + +func InsertInToUserBlackList(black db.Black) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + black.CreateTime = time.Now() + err = dbConn.Table("blacks").Create(black).Error + return err +} + +//type Black struct { +// OwnerUserID string `gorm:"column:owner_user_id;primaryKey;"` +// BlockUserID string `gorm:"column:block_user_id;primaryKey;"` +// CreateTime time.Time `gorm:"column:create_time"` +// AddSource int32 `gorm:"column:add_source"` +// OperatorUserID int32 `gorm:"column:operator_user_id"` +// Ex string `gorm:"column:ex"` +//} + +func CheckBlack(ownerUserID, blockUserID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + var black db.Black + err = dbConn.Table("blacks").Where("owner_user_id=? and block_user_id=?", ownerUserID, blockUserID).Find(&black).Error + return err +} + +func RemoveBlackList(ownerUserID, blockUserID string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + err = dbConn.Table("blacks").Where("owner_user_id=? and block_user_id=?", ownerUserID, blockUserID).Delete(db.Black{}).Error + return utils.Wrap(err, "RemoveBlackList failed") +} + +func GetBlackListByUserID(ownerUserID string) ([]db.Black, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var blackListUsersInfo []db.Black + err = dbConn.Table("blacks").Where("owner_user_id=?", ownerUserID).Find(&blackListUsersInfo).Error + if err != nil { + return nil, err + } + return blackListUsersInfo, nil +} diff --git a/pkg/common/db/mysql_model/im_mysql_model/user_model.go b/pkg/common/db/mysql_model/im_mysql_model/user_model.go new file mode 100644 index 000000000..003b7afa7 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_model/user_model.go @@ -0,0 +1,398 @@ +package im_mysql_model + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "fmt" + "time" + + _ "github.com/jinzhu/gorm/dialects/mysql" +) + +func init() { + //init managers + for k, v := range config.Config.Manager.AppManagerUid { + user, err := GetUserByUserID(v) + if err != nil { + fmt.Println("GetUserByUserID failed ", err.Error(), v, user) + } else { + continue + } + var appMgr db.User + appMgr.UserID = v + appMgr.Nickname = "AppManager" + utils.IntToString(k+1) + appMgr.AppMangerLevel = constant.AppAdmin + err = UserRegister(appMgr) + if err != nil { + fmt.Println("AppManager insert error", err.Error(), appMgr, "time: ", appMgr.Birth.Unix()) + } + + } +} + +func UserRegister(user db.User) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + user.CreateTime = time.Now() + if user.AppMangerLevel == 0 { + user.AppMangerLevel = constant.AppOrdinaryUsers + } + if user.Birth.Unix() < 0 { + user.Birth = utils.UnixSecondToTime(0) + } + err = dbConn.Table("users").Create(&user).Error + if err != nil { + return err + } + return nil +} + +func DeleteUser(userID string) (i int64) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0 + } + i = dbConn.Table("users").Where("user_id=?", userID).Delete(db.User{}).RowsAffected + return i +} + +func GetUserByUserID(userID string) (*db.User, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var user db.User + err = dbConn.Table("users").Where("user_id=?", userID).Take(&user).Error + if err != nil { + return nil, err + } + return &user, nil +} + +func GetUserNameByUserID(userID string) (string, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return "", err + } + var user db.User + err = dbConn.Table("users").Select("name").Where("user_id=?", userID).First(&user).Error + if err != nil { + return "", err + } + return user.Nickname, nil +} + +func UpdateUserInfo(user db.User) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + dbConn.LogMode(false) + err = dbConn.Table("users").Where("user_id=?", user.UserID).Update(&user).Error + return err +} + +func SelectAllUserID() ([]string, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return nil, err + } + var resultArr []string + err = dbConn.Table("users").Pluck("user_id", &resultArr).Error + if err != nil { + return nil, err + } + return resultArr, nil +} + +func SelectSomeUserID(userIDList []string) ([]string, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + dbConn.LogMode(false) + if err != nil { + return nil, err + } + var resultArr []string + err = dbConn.Table("users").Where("user_id IN (?) ", userIDList).Pluck("user_id", &resultArr).Error + + if err != nil { + return nil, err + } + return resultArr, nil +} + +func GetUsers(showNumber, pageNumber int32) ([]db.User, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var users []db.User + if err != nil { + return users, err + } + dbConn.LogMode(false) + err = dbConn.Table("users").Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&users).Error + if err != nil { + return users, err + } + return users, err +} + +func AddUser(userId, phoneNumber, name string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + user := db.User{ + PhoneNumber: phoneNumber, + Birth: time.Now(), + CreateTime: time.Now(), + UserID: userId, + Nickname: name, + } + result := dbConn.Table("users").Create(&user) + return result.Error +} + +func UserIsBlock(userId string) (bool, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return false, err + } + var user db.BlackList + rows := dbConn.Table("black_lists").Where("uid=?", userId).First(&user).RowsAffected + if rows >= 1 { + return true, nil + } + return false, nil +} + +func BlockUser(userId, endDisableTime string) error { + user, err := GetUserByUserID(userId) + if err != nil || user.UserID == "" { + return err + } + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + end, err := time.Parse("2006-01-02 15:04:05", endDisableTime) + if err != nil { + return err + } + if end.Before(time.Now()) { + return constant.ErrDB + } + var blockUser db.BlackList + dbConn.Table("black_lists").Where("uid=?", userId).First(&blockUser) + if blockUser.UserId != "" { + dbConn.Model(&blockUser).Where("uid=?", blockUser.UserId).Update("end_disable_time", end) + return nil + } + blockUser = db.BlackList{ + UserId: userId, + BeginDisableTime: time.Now(), + EndDisableTime: end, + } + result := dbConn.Create(&blockUser) + return result.Error +} + +func UnBlockUser(userId string) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + dbConn.LogMode(false) + result := dbConn.Where("uid=?", userId).Delete(&db.BlackList{}) + return result.Error +} + +type BlockUserInfo struct { + User db.User + BeginDisableTime time.Time + EndDisableTime time.Time +} + +func GetBlockUserById(userId string) (BlockUserInfo, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var blockUserInfo BlockUserInfo + blockUser := db.BlackList{ + UserId: userId, + } + if err != nil { + return blockUserInfo, err + } + if err = dbConn.Table("black_lists").Where("uid=?", userId).Find(&blockUser).Error; err != nil { + return blockUserInfo, err + } + user := db.User{ + UserID: blockUser.UserId, + } + if err := dbConn.Find(&user).Error; err != nil { + return blockUserInfo, err + } + blockUserInfo.User.UserID = user.UserID + blockUserInfo.User.FaceURL = user.UserID + blockUserInfo.User.Nickname = user.Nickname + blockUserInfo.BeginDisableTime = blockUser.BeginDisableTime + blockUserInfo.EndDisableTime = blockUser.EndDisableTime + return blockUserInfo, nil +} + +func GetBlockUsers(showNumber, pageNumber int32) ([]BlockUserInfo, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var blockUserInfos []BlockUserInfo + var blockUsers []db.BlackList + if err != nil { + return blockUserInfos, err + } + dbConn.LogMode(false) + if err = dbConn.Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&blockUsers).Error; err != nil { + return blockUserInfos, err + } + for _, blockUser := range blockUsers { + var user db.User + if err := dbConn.Table("users").Where("user_id=?", blockUser.UserId).First(&user).Error; err == nil { + blockUserInfos = append(blockUserInfos, BlockUserInfo{ + User: db.User{ + UserID: user.UserID, + Nickname: user.Nickname, + FaceURL: user.FaceURL, + }, + BeginDisableTime: blockUser.BeginDisableTime, + EndDisableTime: blockUser.EndDisableTime, + }) + } + } + return blockUserInfos, nil +} + +func GetUserByName(userName string, showNumber, pageNumber int32) ([]db.User, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + var users []db.User + if err != nil { + return users, err + } + dbConn.LogMode(false) + err = dbConn.Table("users").Where(fmt.Sprintf(" name like '%%%s%%' ", userName)).Limit(showNumber).Offset(showNumber * (pageNumber - 1)).Find(&users).Error + return users, err +} + +func GetUsersCount(user db.User) (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var count int32 + if err := dbConn.Table("users").Where(fmt.Sprintf(" name like '%%%s%%' ", user.Nickname)).Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} + +func GetBlockUsersNumCount() (int32, error) { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return 0, err + } + dbConn.LogMode(false) + var count int32 + if err := dbConn.Model(&db.BlackList{}).Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} + +func SetConversation(conversation db.Conversation) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + dbConn.LogMode(false) + newConversation := conversation + if dbConn.Model(&db.Conversation{}).Find(&newConversation).RowsAffected == 0 { + log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "not exist in db, create") + return dbConn.Model(&db.Conversation{}).Create(conversation).Error + // if exist, then update record + } else { + log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "exist in db, update") + //force update + return dbConn.Model(conversation).Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID). + Update(map[string]interface{}{"recv_msg_opt": conversation.RecvMsgOpt, "is_pinned": conversation.IsPinned, "is_private_chat": conversation.IsPrivateChat}).Error + } +} + +func PeerUserSetConversation(conversation db.Conversation) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + dbConn.LogMode(false) + newConversation := conversation + if dbConn.Model(&db.Conversation{}).Find(&newConversation).RowsAffected == 0 { + log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "not exist in db, create") + return dbConn.Model(&db.Conversation{}).Create(conversation).Error + // if exist, then update record + } + log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "exist in db, update") + //force update + return dbConn.Model(conversation).Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID). + Update(map[string]interface{}{"is_private_chat": conversation.IsPrivateChat}).Error + +} + +func SetRecvMsgOpt(conversation db.Conversation) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + dbConn.LogMode(false) + newConversation := conversation + if dbConn.Model(&db.Conversation{}).Find(&newConversation).RowsAffected == 0 { + log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "not exist in db, create") + return dbConn.Model(&db.Conversation{}).Create(conversation).Error + // if exist, then update record + } else { + log.NewDebug("", utils.GetSelfFuncName(), "conversation", conversation, "exist in db, update") + //force update + return dbConn.Model(conversation).Where("owner_user_id = ? and conversation_id = ?", conversation.OwnerUserID, conversation.ConversationID). + Update(map[string]interface{}{"recv_msg_opt": conversation.RecvMsgOpt}).Error + } +} + +func GetUserAllConversations(ownerUserID string) ([]db.Conversation, error) { + var conversations []db.Conversation + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return conversations, err + } + dbConn.LogMode(false) + err = dbConn.Model(&db.Conversation{}).Where("owner_user_id=?", ownerUserID).Find(&conversations).Error + return conversations, err +} + +func GetConversation(OwnerUserID, conversationID string) (db.Conversation, error) { + var conversation db.Conversation + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return conversation, err + } + err = dbConn.Model(&db.Conversation{ + OwnerUserID: OwnerUserID, + ConversationID: conversationID, + }).Find(&conversation).Error + return conversation, err +} + +func GetConversations(OwnerUserID string, conversationIDs []string) ([]db.Conversation, error) { + var conversations []db.Conversation + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return conversations, err + } + err = dbConn.Model(&db.Conversation{}).Where("conversation_id IN (?) and owner_user_id=?", conversationIDs, OwnerUserID).Find(&conversations).Error + return conversations, err +} diff --git a/pkg/common/db/mysql_model/im_mysql_msg_model/chat_log_model.go b/pkg/common/db/mysql_model/im_mysql_msg_model/chat_log_model.go new file mode 100644 index 000000000..99c099ac4 --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_msg_model/chat_log_model.go @@ -0,0 +1,51 @@ +/* +** description(""). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/3/4 11:18). + */ +package im_mysql_msg_model + +import ( + "Open_IM/pkg/common/constant" + "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + pbMsg "Open_IM/pkg/proto/chat" + "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/jinzhu/copier" +) + +func InsertMessageToChatLog(msg pbMsg.MsgDataToMQ) error { + dbConn, err := db.DB.MysqlDB.DefaultGormDB() + if err != nil { + return err + } + chatLog := new(db.ChatLog) + copier.Copy(chatLog, msg.MsgData) + switch msg.MsgData.SessionType { + case constant.GroupChatType: + chatLog.RecvID = msg.MsgData.GroupID + case constant.SingleChatType: + chatLog.RecvID = msg.MsgData.RecvID + } + if msg.MsgData.ContentType >= constant.NotificationBegin && msg.MsgData.ContentType <= constant.NotificationEnd { + var tips server_api_params.TipsComm + _ = proto.Unmarshal(msg.MsgData.Content, &tips) + marshaler := jsonpb.Marshaler{ + OrigName: true, + EnumsAsInts: false, + EmitDefaults: false, + } + chatLog.Content, _ = marshaler.MarshalToString(&tips) + + } else { + chatLog.Content = string(msg.MsgData.Content) + } + chatLog.CreateTime = utils.UnixMillSecondToTime(msg.MsgData.CreateTime) + chatLog.SendTime = utils.UnixMillSecondToTime(msg.MsgData.SendTime) + log.NewDebug("test", "this is ", chatLog) + return dbConn.Table("chat_logs").Create(chatLog).Error +} diff --git a/pkg/common/db/mysql_model/im_mysql_msg_model/hash_code.go b/pkg/common/db/mysql_model/im_mysql_msg_model/hash_code.go new file mode 100644 index 000000000..a631462ce --- /dev/null +++ b/pkg/common/db/mysql_model/im_mysql_msg_model/hash_code.go @@ -0,0 +1,36 @@ +package im_mysql_msg_model + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/db" + "hash/crc32" + "strconv" +) + +func getHashMsgDBAddr(userID string) string { + hCode := crc32.ChecksumIEEE([]byte(userID)) + return config.Config.Mysql.DBAddress[hCode%uint32(len(config.Config.Mysql.DBAddress))] +} + +func getHashMsgTableIndex(userID string) int { + hCode := crc32.ChecksumIEEE([]byte(userID)) + return int(hCode % uint32(config.Config.Mysql.DBMsgTableNum)) +} + +func QueryUserMsgID(userID string) ([]string, error) { + dbAddress, dbTableIndex := getHashMsgDBAddr(userID), getHashMsgTableIndex(userID) + dbTableName := "receive" + strconv.Itoa(dbTableIndex) + + dbConn, _ := db.DB.MysqlDB.GormDB(dbAddress, config.Config.Mysql.DBTableName) + + var msgID string + var msgIDList []string + rows, _ := dbConn.Raw("select msg_id from ? where user_id = ?", dbTableName, userID).Rows() + defer rows.Close() + for rows.Next() { + rows.Scan(&msgID) + msgIDList = append(msgIDList, msgID) + } + + return msgIDList, nil +} diff --git a/pkg/common/db/redisModel.go b/pkg/common/db/redisModel.go new file mode 100644 index 000000000..2faa9a6d8 --- /dev/null +++ b/pkg/common/db/redisModel.go @@ -0,0 +1,157 @@ +package db + +import ( + "Open_IM/pkg/common/constant" + log2 "Open_IM/pkg/common/log" + "github.com/garyburd/redigo/redis" +) + +const ( + AccountTempCode = "ACCOUNT_TEMP_CODE" + resetPwdTempCode = "RESET_PWD_TEMP_CODE" + userIncrSeq = "REDIS_USER_INCR_SEQ:" // user incr seq + appleDeviceToken = "DEVICE_TOKEN" + userMinSeq = "REDIS_USER_MIN_SEQ:" + uidPidToken = "UID_PID_TOKEN_STATUS:" + conversationReceiveMessageOpt = "CON_RECV_MSG_OPT:" + GetuiToken = "GETUI" +) + +func (d *DataBases) Exec(cmd string, key interface{}, args ...interface{}) (interface{}, error) { + con := d.redisPool.Get() + if err := con.Err(); err != nil { + log2.Error("", "", "redis cmd = %v, err = %v", cmd, err) + return nil, err + } + defer con.Close() + + params := make([]interface{}, 0) + params = append(params, key) + + if len(args) > 0 { + for _, v := range args { + params = append(params, v) + } + } + + return con.Do(cmd, params...) +} +func (d *DataBases) JudgeAccountEXISTS(account string) (bool, error) { + key := AccountTempCode + account + return redis.Bool(d.Exec("EXISTS", key)) +} +func (d *DataBases) SetAccountCode(account string, code, ttl int) (err error) { + key := AccountTempCode + account + _, err = d.Exec("SET", key, code, "ex", ttl) + return err +} +func (d *DataBases) GetAccountCode(account string) (string, error) { + key := AccountTempCode + account + return redis.String(d.Exec("GET", key)) +} + +//Perform seq auto-increment operation of user messages +func (d *DataBases) IncrUserSeq(uid string) (uint64, error) { + key := userIncrSeq + uid + return redis.Uint64(d.Exec("INCR", key)) +} + +//Get the largest Seq +func (d *DataBases) GetUserMaxSeq(uid string) (uint64, error) { + key := userIncrSeq + uid + return redis.Uint64(d.Exec("GET", key)) +} + +//Set the user's minimum seq +func (d *DataBases) SetUserMinSeq(uid string, minSeq uint32) (err error) { + key := userMinSeq + uid + _, err = d.Exec("SET", key, minSeq) + return err +} + +//Get the smallest Seq +func (d *DataBases) GetUserMinSeq(uid string) (uint64, error) { + key := userMinSeq + uid + return redis.Uint64(d.Exec("GET", key)) +} + +//Store Apple's device token to redis +func (d *DataBases) SetAppleDeviceToken(accountAddress, value string) (err error) { + key := appleDeviceToken + accountAddress + _, err = d.Exec("SET", key, value) + return err +} + +//Delete Apple device token +func (d *DataBases) DelAppleDeviceToken(accountAddress string) (err error) { + key := appleDeviceToken + accountAddress + _, err = d.Exec("DEL", key) + return err +} + +//Store userid and platform class to redis +func (d *DataBases) AddTokenFlag(userID string, platformID int32, token string, flag int) error { + key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID) + log2.NewDebug("", "add token key is ", key) + _, err1 := d.Exec("HSet", key, token, flag) + return err1 +} + +func (d *DataBases) GetTokenMapByUidPid(userID, platformID string) (map[string]int, error) { + key := uidPidToken + userID + ":" + platformID + log2.NewDebug("", "get token key is ", key) + return redis.IntMap(d.Exec("HGETALL", key)) +} +func (d *DataBases) SetTokenMapByUidPid(userID string, platformID int32, m map[string]int) error { + key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID) + _, err := d.Exec("hmset", key, redis.Args{}.Add().AddFlat(m)...) + return err +} +func (d *DataBases) DeleteTokenByUidPid(userID string, platformID int32, fields []string) error { + key := uidPidToken + userID + ":" + constant.PlatformIDToName(platformID) + _, err := d.Exec("HDEL", key, redis.Args{}.Add().AddFlat(fields)...) + return err +} + +func (d *DataBases) SetSingleConversationRecvMsgOpt(userID, conversationID string, opt int32) error { + key := conversationReceiveMessageOpt + userID + _, err := d.Exec("HSet", key, conversationID, opt) + return err +} + +func (d *DataBases) GetSingleConversationRecvMsgOpt(userID, conversationID string) (int, error) { + key := conversationReceiveMessageOpt + userID + return redis.Int(d.Exec("HGet", key, conversationID)) +} +func (d *DataBases) GetAllConversationMsgOpt(userID string) (map[string]int, error) { + key := conversationReceiveMessageOpt + userID + return redis.IntMap(d.Exec("HGETALL", key)) +} +func (d *DataBases) SetMultiConversationMsgOpt(userID string, m map[string]int) error { + key := conversationReceiveMessageOpt + userID + _, err := d.Exec("hmset", key, redis.Args{}.Add().AddFlat(m)...) + return err +} +func (d *DataBases) GetMultiConversationMsgOpt(userID string, conversationIDs []string) (m map[string]int, err error) { + m = make(map[string]int) + key := conversationReceiveMessageOpt + userID + i, err := redis.Ints(d.Exec("hmget", key, redis.Args{}.Add().AddFlat(conversationIDs)...)) + if err != nil { + return m, err + } + for k, v := range conversationIDs { + m[v] = i[k] + } + return m, nil + +} + +func (d *DataBases) SetGetuiToken(token string, expireTime int64) error { + _, err := d.Exec("SET", GetuiToken, token, "ex", expireTime) + return err +} + +func (d *DataBases) GetGetuiToken() (string, error) { + result, err := redis.String(d.Exec("GET", GetuiToken)) + return result, err +} diff --git a/pkg/common/db/redisModel_test.go b/pkg/common/db/redisModel_test.go new file mode 100644 index 000000000..1d9d254b7 --- /dev/null +++ b/pkg/common/db/redisModel_test.go @@ -0,0 +1,27 @@ +package db + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_SetTokenMapByUidPid(t *testing.T) { + m := make(map[string]int, 0) + m["test1"] = 1 + m["test2"] = 2 + m["2332"] = 4 + _ = DB.SetTokenMapByUidPid("1234", 2, m) + +} +func Test_GetTokenMapByUidPid(t *testing.T) { + m, err := DB.GetTokenMapByUidPid("1234", "Android") + assert.Nil(t, err) + fmt.Println(m) +} + +func TestDataBases_GetMultiConversationMsgOpt(t *testing.T) { + m, err := DB.GetMultiConversationMsgOpt("fg", []string{"user", "age", "color"}) + assert.Nil(t, err) + fmt.Println(m) +} diff --git a/pkg/common/http/http_client.go b/pkg/common/http/http_client.go new file mode 100644 index 000000000..e227da91e --- /dev/null +++ b/pkg/common/http/http_client.go @@ -0,0 +1,66 @@ +/* +** description(""). +** copyright('open-im,www.open-im.io'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/5/27 10:31). + */ +package http + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "time" +) + +func Get(url string) (response []byte, err error) { + client := http.Client{Timeout: 5 * time.Second} + resp, err := client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return body, nil +} + +//application/json; charset=utf-8 +func Post(url string, data interface{}, timeOutSecond int) (content []byte, err error) { + jsonStr, err := json.Marshal(data) + if err != nil { + return nil, err + } + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + if err != nil { + return nil, err + } + req.Close = true + req.Header.Add("content-type", "application/json; charset=utf-8") + + client := &http.Client{Timeout: time.Duration(timeOutSecond) * time.Second} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + result, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return result, nil +} + +func PostReturn(url string, input, output interface{}, timeOut int) error { + b, err := Post(url, input, timeOut) + if err != nil { + return err + } + if err = json.Unmarshal(b, output); err != nil { + return err + } + return nil +} diff --git a/pkg/common/http/http_resp.go b/pkg/common/http/http_resp.go new file mode 100644 index 000000000..cdbf04463 --- /dev/null +++ b/pkg/common/http/http_resp.go @@ -0,0 +1,43 @@ +package http + +import ( + "Open_IM/pkg/common/constant" + "fmt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + //"Open_IM/pkg/cms_api_struct" + "net/http" + + "github.com/gin-gonic/gin" +) + +type BaseResp struct { + Code int32 `json:"code"` + ErrMsg string `json:"err_msg"` + Data interface{} `json:"data"` +} + +func RespHttp200(ctx *gin.Context, err error, data interface{}) { + var resp BaseResp + switch e := err.(type) { + case constant.ErrInfo: + resp.Code = e.ErrCode + resp.ErrMsg = e.ErrMsg + default: + s, ok := status.FromError(err) + if !ok { + fmt.Println("need grpc format error") + return + } + resp.Code = int32(s.Code()) + resp.ErrMsg = s.Message() + } + resp.Data = data + ctx.JSON(http.StatusOK, resp) +} + +// warp error +func WrapError(err constant.ErrInfo) error { + return status.Error(codes.Code(err.ErrCode), err.ErrMsg) +} diff --git a/pkg/common/kafka/consumer.go b/pkg/common/kafka/consumer.go new file mode 100644 index 000000000..771145906 --- /dev/null +++ b/pkg/common/kafka/consumer.go @@ -0,0 +1,36 @@ +package kafka + +import ( + "github.com/Shopify/sarama" + "sync" +) + +type Consumer struct { + addr []string + WG sync.WaitGroup + Topic string + PartitionList []int32 + Consumer sarama.Consumer +} + +func NewKafkaConsumer(addr []string, topic string) *Consumer { + p := Consumer{} + p.Topic = topic + p.addr = addr + + consumer, err := sarama.NewConsumer(p.addr, nil) + if err != nil { + panic(err.Error()) + return nil + } + p.Consumer = consumer + + partitionList, err := consumer.Partitions(p.Topic) + if err != nil { + panic(err.Error()) + return nil + } + p.PartitionList = partitionList + + return &p +} diff --git a/pkg/common/kafka/consumer_group.go b/pkg/common/kafka/consumer_group.go new file mode 100644 index 000000000..3af714373 --- /dev/null +++ b/pkg/common/kafka/consumer_group.go @@ -0,0 +1,53 @@ +/* +** description(""). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/5/11 9:36). + */ +package kafka + +import ( + "context" + "github.com/Shopify/sarama" +) + +type MConsumerGroup struct { + sarama.ConsumerGroup + groupID string + topics []string +} + +type MConsumerGroupConfig struct { + KafkaVersion sarama.KafkaVersion + OffsetsInitial int64 + IsReturnErr bool +} + +func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addr []string, groupID string) *MConsumerGroup { + config := sarama.NewConfig() + config.Version = consumerConfig.KafkaVersion + config.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial + config.Consumer.Return.Errors = consumerConfig.IsReturnErr + client, err := sarama.NewClient(addr, config) + if err != nil { + panic(err.Error()) + } + consumerGroup, err := sarama.NewConsumerGroupFromClient(groupID, client) + if err != nil { + panic(err.Error()) + } + return &MConsumerGroup{ + consumerGroup, + groupID, + topics, + } +} +func (mc *MConsumerGroup) RegisterHandleAndConsumer(handler sarama.ConsumerGroupHandler) { + ctx := context.Background() + for { + err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) + if err != nil { + panic(err.Error()) + } + } +} diff --git a/pkg/common/kafka/producer.go b/pkg/common/kafka/producer.go new file mode 100644 index 000000000..98ad92209 --- /dev/null +++ b/pkg/common/kafka/producer.go @@ -0,0 +1,49 @@ +package kafka + +import ( + log2 "Open_IM/pkg/common/log" + "github.com/Shopify/sarama" + "github.com/golang/protobuf/proto" +) + +type Producer struct { + topic string + addr []string + config *sarama.Config + producer sarama.SyncProducer +} + +func NewKafkaProducer(addr []string, topic string) *Producer { + p := Producer{} + p.config = sarama.NewConfig() //Instantiate a sarama Config + p.config.Producer.Return.Successes = true //Whether to enable the successes channel to be notified after the message is sent successfully + p.config.Producer.RequiredAcks = sarama.WaitForAll //Set producer Message Reply level 0 1 all + p.config.Producer.Partitioner = sarama.NewHashPartitioner //Set the hash-key automatic hash partition. When sending a message, you must specify the key value of the message. If there is no key, the partition will be selected randomly + + p.addr = addr + p.topic = topic + + producer, err := sarama.NewSyncProducer(p.addr, p.config) //Initialize the client + if err != nil { + panic(err.Error()) + return nil + } + p.producer = producer + return &p +} + +func (p *Producer) SendMessage(m proto.Message, key ...string) (int32, int64, error) { + kMsg := &sarama.ProducerMessage{} + kMsg.Topic = p.topic + if len(key) == 1 { + kMsg.Key = sarama.StringEncoder(key[0]) + } + bMsg, err := proto.Marshal(m) + if err != nil { + log2.Error("", "", "proto marshal err = %s", err.Error()) + return -1, -1, err + } + kMsg.Value = sarama.ByteEncoder(bMsg) + + return p.producer.SendMessage(kMsg) +} diff --git a/pkg/common/log/es_hk.go b/pkg/common/log/es_hk.go new file mode 100644 index 000000000..19eafaed5 --- /dev/null +++ b/pkg/common/log/es_hk.go @@ -0,0 +1,107 @@ +/* +** description("Send logs to elasticsearch hook"). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/3/26 17:05). + */ +package log + +import ( + "Open_IM/pkg/common/config" + "context" + "fmt" + elasticV7 "github.com/olivere/elastic/v7" + "github.com/sirupsen/logrus" + "log" + "os" + "strings" + "time" +) + +//esHook CUSTOMIZED ES hook +type esHook struct { + moduleName string + client *elasticV7.Client +} + +//newEsHook Initialization +func newEsHook(moduleName string) *esHook { + //https://github.com/sohlich/elogrus + //client, err := elastic.NewClient(elastic.SetURL("http://localhost:9200")) + //if err != nil { + // log.Panic(err) + //} + //hook, err := elogrus.NewAsyncElasticHook(client, "localhost", logrus.DebugLevel, "mylog") + //if err != nil { + // log.Panic(err) + //} + es, err := elasticV7.NewClient( + elasticV7.SetURL(config.Config.Log.ElasticSearchAddr...), + elasticV7.SetBasicAuth(config.Config.Log.ElasticSearchUser, config.Config.Log.ElasticSearchPassword), + elasticV7.SetSniff(false), + elasticV7.SetHealthcheckInterval(60*time.Second), + elasticV7.SetErrorLog(log.New(os.Stderr, "ES:", log.LstdFlags)), + ) + + if err != nil { + log.Fatal("failed to create Elastic V7 Client: ", err) + } + + //info, code, err := es.Ping(logConfig.ElasticSearch.EsAddr[0]).Do(context.Background()) + //if err != nil { + // panic(err) + //} + //fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number) + // + //esversion, err := es.ElasticsearchVersion(logConfig.ElasticSearch.EsAddr[0]) + //if err != nil { + // panic(err) + //} + //fmt.Printf("Elasticsearch version %s\n", esversion) + return &esHook{client: es, moduleName: moduleName} +} + +//Fire log hook interface +func (hook *esHook) Fire(entry *logrus.Entry) error { + doc := newEsLog(entry) + go hook.sendEs(doc) + return nil +} + +func (hook *esHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +//sendEs +func (hook *esHook) sendEs(doc appLogDocModel) { + defer func() { + if r := recover(); r != nil { + fmt.Println("send entry to es failed: ", r) + } + }() + _, err := hook.client.Index().Index(hook.moduleName).Type(doc.indexName()).BodyJson(doc).Do(context.Background()) + if err != nil { + log.Println(err) + } + +} + +//appLogDocModel es model +type appLogDocModel map[string]interface{} + +func newEsLog(e *logrus.Entry) appLogDocModel { + ins := make(map[string]interface{}) + ins["level"] = strings.ToUpper(e.Level.String()) + ins["time"] = e.Time.Format("2006-01-02 15:04:05") + for kk, vv := range e.Data { + ins[kk] = vv + } + ins["tipInfo"] = e.Message + + return ins +} + +// indexName es index name +func (m *appLogDocModel) indexName() string { + return time.Now().Format("2006-01-02") +} diff --git a/pkg/common/log/file_line_hk.go b/pkg/common/log/file_line_hk.go new file mode 100644 index 000000000..bc908ee03 --- /dev/null +++ b/pkg/common/log/file_line_hk.go @@ -0,0 +1,71 @@ +/* +** description("get the name and line number of the calling file hook"). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/3/16 11:26). + */ +package log + +import ( + "fmt" + "github.com/sirupsen/logrus" + "runtime" + "strings" +) + +type fileHook struct{} + +func newFileHook() *fileHook { + return &fileHook{} +} + +func (f *fileHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (f *fileHook) Fire(entry *logrus.Entry) error { + entry.Data["FilePath"] = findCaller(6) + return nil +} + +//func (f *fileHook) Fire(entry *logrus.Entry) error { +// var s string +// _, b, c, _ := runtime.Caller(10) +// i := strings.SplitAfter(b, "/") +// if len(i) > 3 { +// s = i[len(i)-3] + i[len(i)-2] + i[len(i)-1] + ":" + utils.IntToString(c) +// } +// entry.Data["FilePath"] = s +// return nil +//} + +func findCaller(skip int) string { + file := "" + line := 0 + for i := 0; i < 10; i++ { + file, line = getCaller(skip + i) + if !strings.HasPrefix(file, "log") { + break + } + } + return fmt.Sprintf("%s:%d", file, line) +} + +func getCaller(skip int) (string, int) { + _, file, line, ok := runtime.Caller(skip) + if !ok { + return "", 0 + } + + n := 0 + for i := len(file) - 1; i > 0; i-- { + if file[i] == '/' { + n++ + if n >= 2 { + file = file[i+1:] + break + } + } + } + return file, line +} diff --git a/pkg/common/log/logrus.go b/pkg/common/log/logrus.go new file mode 100644 index 000000000..caf4c9126 --- /dev/null +++ b/pkg/common/log/logrus.go @@ -0,0 +1,199 @@ +package log + +import ( + "Open_IM/pkg/common/config" + "bufio" + "fmt" + "os" + "time" + + nested "github.com/antonfisher/nested-logrus-formatter" + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "github.com/rifflock/lfshook" + "github.com/sirupsen/logrus" +) + +var logger *Logger + +type Logger struct { + *logrus.Logger + Pid int +} + +func init() { + logger = loggerInit("") + +} +func NewPrivateLog(moduleName string) { + logger = loggerInit(moduleName) +} + +func loggerInit(moduleName string) *Logger { + var logger = logrus.New() + //All logs will be printed + logger.SetLevel(logrus.Level(config.Config.Log.RemainLogLevel)) + //Close std console output + src, err := os.OpenFile(os.DevNull, os.O_APPEND|os.O_WRONLY, os.ModeAppend) + if err != nil { + panic(err.Error()) + } + writer := bufio.NewWriter(src) + logger.SetOutput(writer) + //logger.SetOutput(os.Stdout) + //Log Console Print Style Setting + logger.SetFormatter(&nested.Formatter{ + TimestampFormat: "2006-01-02 15:04:05.000", + HideKeys: false, + FieldsOrder: []string{"PID", "FilePath", "OperationID"}, + }) + //File name and line number display hook + logger.AddHook(newFileHook()) + + //Send logs to elasticsearch hook + if config.Config.Log.ElasticSearchSwitch { + logger.AddHook(newEsHook(moduleName)) + } + //Log file segmentation hook + hook := NewLfsHook(time.Duration(config.Config.Log.RotationTime)*time.Hour, config.Config.Log.RemainRotationCount, moduleName) + logger.AddHook(hook) + return &Logger{ + logger, + os.Getpid(), + } +} +func NewLfsHook(rotationTime time.Duration, maxRemainNum uint, moduleName string) logrus.Hook { + lfsHook := lfshook.NewHook(lfshook.WriterMap{ + logrus.DebugLevel: initRotateLogs(rotationTime, maxRemainNum, "all", moduleName), + logrus.InfoLevel: initRotateLogs(rotationTime, maxRemainNum, "all", moduleName), + logrus.WarnLevel: initRotateLogs(rotationTime, maxRemainNum, "all", moduleName), + logrus.ErrorLevel: initRotateLogs(rotationTime, maxRemainNum, "all", moduleName), + }, &nested.Formatter{ + TimestampFormat: "2006-01-02 15:04:05.000", + HideKeys: false, + FieldsOrder: []string{"PID", "FilePath", "OperationID"}, + }) + return lfsHook +} +func initRotateLogs(rotationTime time.Duration, maxRemainNum uint, level string, moduleName string) *rotatelogs.RotateLogs { + if moduleName != "" { + moduleName = moduleName + "." + } + writer, err := rotatelogs.New( + config.Config.Log.StorageLocation+moduleName+level+"."+"%Y-%m-%d", + rotatelogs.WithRotationTime(rotationTime), + rotatelogs.WithRotationCount(maxRemainNum), + ) + if err != nil { + panic(err.Error()) + } else { + return writer + } +} + +func Info(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Infoln(args) +} + +func Error(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Errorln(args) +} + +func Debug(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Debugln(args) +} + +//Deprecated +func Warning(token, OperationID, format string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "PID": logger.Pid, + "OperationID": OperationID, + }).Warningf(format, args...) + +} + +//Deprecated +func InfoByArgs(format string, args ...interface{}) { + logger.WithFields(logrus.Fields{}).Infof(format, args) +} + +//Deprecated +func ErrorByArgs(format string, args ...interface{}) { + logger.WithFields(logrus.Fields{}).Errorf(format, args...) +} + +//Print log information in k, v format, +//kv is best to appear in pairs. tipInfo is the log prompt information for printing, +//and kv is the key and value for printing. +//Deprecated +func InfoByKv(tipInfo, OperationID string, args ...interface{}) { + fields := make(logrus.Fields) + argsHandle(OperationID, fields, args) + logger.WithFields(fields).Info(tipInfo) +} + +//Deprecated +func ErrorByKv(tipInfo, OperationID string, args ...interface{}) { + fields := make(logrus.Fields) + argsHandle(OperationID, fields, args) + logger.WithFields(fields).Error(tipInfo) +} + +//Deprecated +func DebugByKv(tipInfo, OperationID string, args ...interface{}) { + fields := make(logrus.Fields) + argsHandle(OperationID, fields, args) + logger.WithFields(fields).Debug(tipInfo) +} + +//Deprecated +func WarnByKv(tipInfo, OperationID string, args ...interface{}) { + fields := make(logrus.Fields) + argsHandle(OperationID, fields, args) + logger.WithFields(fields).Warn(tipInfo) +} + +//internal method +func argsHandle(OperationID string, fields logrus.Fields, args []interface{}) { + for i := 0; i < len(args); i += 2 { + if i+1 < len(args) { + fields[fmt.Sprintf("%v", args[i])] = args[i+1] + } else { + fields[fmt.Sprintf("%v", args[i])] = "" + } + } + fields["OperationID"] = OperationID + fields["PID"] = logger.Pid +} +func NewInfo(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Infoln(args) +} +func NewError(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Errorln(args) +} +func NewDebug(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Debugln(args) +} +func NewWarn(OperationID string, args ...interface{}) { + logger.WithFields(logrus.Fields{ + "OperationID": OperationID, + "PID": logger.Pid, + }).Warnln(args) +} diff --git a/pkg/common/log/time_format.go b/pkg/common/log/time_format.go new file mode 100644 index 000000000..e1bfc4a8c --- /dev/null +++ b/pkg/common/log/time_format.go @@ -0,0 +1,57 @@ +/* +** description(""). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/2/22 11:52). + */ +package log + +import ( + "strconv" + "time" +) + +const ( + TimeOffset = 8 * 3600 //8 hour offset + HalfOffset = 12 * 3600 //Half-day hourly offset +) + +//Get the current timestamp +func GetCurrentTimestamp() int64 { + return time.Now().Unix() +} + +//Get the current 0 o'clock timestamp +func GetCurDayZeroTimestamp() int64 { + timeStr := time.Now().Format("2006-01-02") + t, _ := time.Parse("2006-01-02", timeStr) + return t.Unix() - TimeOffset +} + +//Get the timestamp at 12 o'clock on the day +func GetCurDayHalfTimestamp() int64 { + return GetCurDayZeroTimestamp() + HalfOffset + +} + +//Get the formatted time at 0 o'clock of the day, the format is "2006-01-02_00-00-00" +func GetCurDayZeroTimeFormat() string { + return time.Unix(GetCurDayZeroTimestamp(), 0).Format("2006-01-02_15-04-05") +} + +//Get the formatted time at 12 o'clock of the day, the format is "2006-01-02_12-00-00" +func GetCurDayHalfTimeFormat() string { + return time.Unix(GetCurDayZeroTimestamp()+HalfOffset, 0).Format("2006-01-02_15-04-05") +} +func GetTimeStampByFormat(datetime string) string { + timeLayout := "2006-01-02 15:04:05" //转化所需模板 + loc, _ := time.LoadLocation("Local") //获取时区 + tmp, _ := time.ParseInLocation(timeLayout, datetime, loc) + timestamp := tmp.Unix() //转化为时间戳 类型是int64 + return strconv.FormatInt(timestamp, 10) +} + +func TimeStringFormatTimeUnix(timeFormat string, timeSrc string) int64 { + tm, _ := time.Parse(timeFormat, timeSrc) + return tm.Unix() +} diff --git a/pkg/common/multi_terminal_login/multi_terminal_login.go b/pkg/common/multi_terminal_login/multi_terminal_login.go new file mode 100644 index 000000000..3c3245e63 --- /dev/null +++ b/pkg/common/multi_terminal_login/multi_terminal_login.go @@ -0,0 +1,73 @@ +package multi_terminal_login + +// +//import ( +// "Open_IM/internal/push/content_struct" +// "Open_IM/internal/push/logic" +// "Open_IM/pkg/common/config" +// "Open_IM/pkg/common/constant" +// "Open_IM/pkg/common/db" +// pbChat "Open_IM/pkg/proto/chat" +// "Open_IM/pkg/utils" +//) +// +//const DayOfSecond = 24*60*60 +//func MultiTerminalLoginChecker(uid, token string, platformID int32) error { +// // 1.check userid and platform class 0 not exists and 1 exists +// exists, err := db.DB.ExistsUserIDAndPlatform(uid, constant.PlatformNameToClass(constant.PlatformIDToName(platformID))) +// if err != nil { +// return err +// } +// //get config multi login policy +// if config.Config.MultiLoginPolicy { +// //OnlyOneTerminalAccess policy need to check all terminal +// if constant.PlatformNameToClass(constant.PlatformIDToName(platformID)) == "PC" { +// exists, err = db.DB.ExistsUserIDAndPlatform(uid, "Mobile") +// if err != nil { +// return err +// } +// } else { +// exists, err = db.DB.ExistsUserIDAndPlatform(uid, "PC") +// if err != nil { +// return err +// } +// } +// if exists == 1 { +// err := db.DB.SetUserIDAndPlatform(uid, constant.PlatformNameToClass(constant.PlatformIDToName(platformID)), token, config.Config.TokenPolicy.AccessExpire*DayOfSecond) +// if err != nil { +// return err +// } +// PushMessageToTheTerminal(uid, platformID) +// return nil +// } +// } else if config.Config.MultiLoginPolicy.MobileAndPCTerminalAccessButOtherTerminalKickEachOther { +// // common terminal need to kick eich other +// if exists == 1 { +// err := db.DB.SetUserIDAndPlatform(uid, constant.PlatformNameToClass(constant.PlatformIDToName(platformID)), token, config.Config.TokenPolicy.AccessExpire*DayOfSecond) +// if err != nil { +// return err +// } +// PushMessageToTheTerminal(uid, platformID) +// return nil +// } +// } +// err = db.DB.SetUserIDAndPlatform(uid, constant.PlatformNameToClass(constant.PlatformIDToName(platformID)), token, config.Config.TokenPolicy.AccessExpire*DayOfSecond) +// if err != nil { +// return err +// } +// PushMessageToTheTerminal(uid, platformID) +// return nil +//} +//// +////func PushMessageToTheTerminal(uid string, platform int32) { +//// +//// logic.SendMsgByWS(&pbChat.WSToMsgSvrChatMsg{ +//// SendID: uid, +//// RecvID: uid, +//// Content: content_struct.NewContentStructString(1, "", "Your account is already logged on other terminal,please confirm"), +//// SendTime: utils.GetCurrentTimestampBySecond(), +//// MsgFrom: constant.SysMsgType, +//// ContentType: constant.KickOnlineTip, +//// PlatformID: platform, +//// }) +////} diff --git a/pkg/common/token_verify/jwt_token.go b/pkg/common/token_verify/jwt_token.go new file mode 100644 index 000000000..bfff43116 --- /dev/null +++ b/pkg/common/token_verify/jwt_token.go @@ -0,0 +1,231 @@ +package token_verify + +import ( + "Open_IM/pkg/common/config" + "Open_IM/pkg/common/constant" + commonDB "Open_IM/pkg/common/db" + "Open_IM/pkg/common/log" + "Open_IM/pkg/utils" + "github.com/garyburd/redigo/redis" + "github.com/golang-jwt/jwt/v4" + "time" +) + +//var ( +// TokenExpired = errors.New("token is timed out, please log in again") +// TokenInvalid = errors.New("token has been invalidated") +// TokenNotValidYet = errors.New("token not active yet") +// TokenMalformed = errors.New("that's not even a token") +// TokenUnknown = errors.New("couldn't handle this token") +//) + +type Claims struct { + UID string + Platform string //login platform + jwt.RegisteredClaims +} + +func BuildClaims(uid, platform string, ttl int64) Claims { + now := time.Now() + return Claims{ + UID: uid, + Platform: platform, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(ttl*24) * time.Hour)), //Expiration time + IssuedAt: jwt.NewNumericDate(now), //Issuing time + NotBefore: jwt.NewNumericDate(now), //Begin Effective time + }} +} + +func CreateToken(userID string, platformID int32) (string, int64, error) { + claims := BuildClaims(userID, constant.PlatformIDToName(platformID), config.Config.TokenPolicy.AccessExpire) + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + tokenString, err := token.SignedString([]byte(config.Config.TokenPolicy.AccessSecret)) + if err != nil { + return "", 0, err + } + //remove Invalid token + m, err := commonDB.DB.GetTokenMapByUidPid(userID, constant.PlatformIDToName(platformID)) + if err != nil && err != redis.ErrNil { + return "", 0, err + } + var deleteTokenKey []string + for k, v := range m { + _, err = GetClaimFromToken(k) + if err != nil || v != constant.NormalToken { + deleteTokenKey = append(deleteTokenKey, k) + } + } + if len(deleteTokenKey) != 0 { + err = commonDB.DB.DeleteTokenByUidPid(userID, platformID, deleteTokenKey) + if err != nil { + return "", 0, err + } + } + err = commonDB.DB.AddTokenFlag(userID, platformID, tokenString, constant.NormalToken) + if err != nil { + return "", 0, err + } + return tokenString, claims.ExpiresAt.Time.Unix(), err +} + +func secret() jwt.Keyfunc { + return func(token *jwt.Token) (interface{}, error) { + return []byte(config.Config.TokenPolicy.AccessSecret), nil + } +} + +func GetClaimFromToken(tokensString string) (*Claims, error) { + token, err := jwt.ParseWithClaims(tokensString, &Claims{}, secret()) + if err != nil { + if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + return nil, &constant.ErrTokenMalformed + } else if ve.Errors&jwt.ValidationErrorExpired != 0 { + return nil, &constant.ErrTokenExpired + } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { + return nil, &constant.ErrTokenNotValidYet + } else { + return nil, &constant.ErrTokenUnknown + } + } else { + return nil, &constant.ErrTokenNotValidYet + } + } else { + if claims, ok := token.Claims.(*Claims); ok && token.Valid { + //log.NewDebug("", claims.UID, claims.Platform) + return claims, nil + } + return nil, &constant.ErrTokenNotValidYet + } +} + +func IsAppManagerAccess(token string, OpUserID string) bool { + claims, err := ParseToken(token, "") + if err != nil { + return false + } + if utils.IsContain(claims.UID, config.Config.Manager.AppManagerUid) && claims.UID == OpUserID { + return true + } + return false +} + +func IsManagerUserID(OpUserID string) bool { + if utils.IsContain(OpUserID, config.Config.Manager.AppManagerUid) { + return true + } else { + return false + } +} + +func CheckAccess(OpUserID string, OwnerUserID string) bool { + if utils.IsContain(OpUserID, config.Config.Manager.AppManagerUid) { + return true + } + if OpUserID == OwnerUserID { + return true + } + return false +} + +func GetUserIDFromToken(token string, operationID string) (bool, string) { + claims, err := ParseToken(token, operationID) + if err != nil { + log.Error(operationID, "ParseToken failed, ", err.Error(), token) + return false, "" + } + return true, claims.UID +} + +func ParseTokenGetUserID(token string, operationID string) (error, string) { + claims, err := ParseToken(token, operationID) + if err != nil { + return utils.Wrap(err, ""), "" + } + return nil, claims.UID +} + +func ParseToken(tokensString, operationID string) (claims *Claims, err error) { + claims, err = GetClaimFromToken(tokensString) + if err != nil { + log.NewError(operationID, "token validate err", err.Error(), tokensString) + return nil, utils.Wrap(err, "") + } + + m, err := commonDB.DB.GetTokenMapByUidPid(claims.UID, claims.Platform) + if err != nil { + log.NewError(operationID, "get token from redis err", err.Error(), tokensString) + return nil, utils.Wrap(&constant.ErrTokenInvalid, "get token from redis err") + } + if m == nil { + log.NewError(operationID, "get token from redis err", "m is nil", tokensString) + return nil, utils.Wrap(&constant.ErrTokenInvalid, "get token from redis err") + } + if v, ok := m[tokensString]; ok { + switch v { + case constant.NormalToken: + log.NewDebug(operationID, "this is normal return", claims) + return claims, nil + case constant.InValidToken: + return nil, utils.Wrap(&constant.ErrTokenInvalid, "") + case constant.KickedToken: + log.Error(operationID, "this token has been kicked by other same terminal ", constant.ErrTokenKicked) + return nil, utils.Wrap(&constant.ErrTokenKicked, "this token has been kicked by other same terminal ") + case constant.ExpiredToken: + return nil, utils.Wrap(&constant.ErrTokenExpired, "") + default: + return nil, utils.Wrap(&constant.ErrTokenUnknown, "") + } + } + log.NewError(operationID, "redis token map not find", constant.ErrTokenUnknown) + return nil, utils.Wrap(&constant.ErrTokenUnknown, "redis token map not find") +} + +//func MakeTheTokenInvalid(currentClaims *Claims, platformClass string) (bool, error) { +// storedRedisTokenInterface, err := db.DB.GetPlatformToken(currentClaims.UID, platformClass) +// if err != nil { +// return false, err +// } +// storedRedisPlatformClaims, err := ParseRedisInterfaceToken(storedRedisTokenInterface) +// if err != nil { +// return false, err +// } +// //if issue time less than redis token then make this token invalid +// if currentClaims.IssuedAt.Time.Unix() < storedRedisPlatformClaims.IssuedAt.Time.Unix() { +// return true, constant.TokenInvalid +// } +// return false, nil +//} + +func ParseRedisInterfaceToken(redisToken interface{}) (*Claims, error) { + return GetClaimFromToken(string(redisToken.([]uint8))) +} + +//Validation token, false means failure, true means successful verification +func VerifyToken(token, uid string) (bool, error) { + claims, err := ParseToken(token, "") + if err != nil { + return false, err + } + if claims.UID != uid { + return false, &constant.ErrTokenUnknown + } + + log.NewDebug("", claims.UID, claims.Platform) + return true, nil +} +func WsVerifyToken(token, uid string, platformID string) (bool, error, string) { + claims, err := ParseToken(token, "") + if err != nil { + return false, err, "parse token err" + } + if claims.UID != uid { + return false, &constant.ErrTokenUnknown, "uid is not same to token uid" + } + if claims.Platform != constant.PlatformIDToName(utils.StringToInt32(platformID)) { + return false, &constant.ErrTokenUnknown, "platform is not same to token platform" + } + log.NewDebug("", claims.UID, claims.Platform) + return true, nil, "" +} diff --git a/pkg/common/utils/utils.go b/pkg/common/utils/utils.go new file mode 100644 index 000000000..003f659a9 --- /dev/null +++ b/pkg/common/utils/utils.go @@ -0,0 +1,161 @@ +package utils + +import ( + db "Open_IM/pkg/common/db" + imdb "Open_IM/pkg/common/db/mysql_model/im_mysql_model" + "Open_IM/pkg/common/token_verify" + open_im_sdk "Open_IM/pkg/proto/sdk_ws" + "Open_IM/pkg/utils" + "math/rand" + "strconv" + "time" +) + +func OperationIDGenerator() string { + return strconv.FormatInt(time.Now().UnixNano()+int64(rand.Uint32()), 10) +} + +func FriendOpenIMCopyDB(dst *db.Friend, src *open_im_sdk.FriendInfo) { + utils.CopyStructFields(dst, src) + dst.FriendUserID = src.FriendUser.UserID + dst.CreateTime = utils.UnixSecondToTime(int64(src.CreateTime)) +} + +func FriendDBCopyOpenIM(dst *open_im_sdk.FriendInfo, src *db.Friend) error { + utils.CopyStructFields(dst, src) + user, err := imdb.GetUserByUserID(src.FriendUserID) + if err != nil { + return utils.Wrap(err, "") + } + utils.CopyStructFields(dst.FriendUser, user) + dst.CreateTime = uint32(src.CreateTime.Unix()) + if dst.FriendUser == nil { + dst.FriendUser = &open_im_sdk.UserInfo{} + } + dst.FriendUser.CreateTime = uint32(user.CreateTime.Unix()) + return nil +} + +// +func FriendRequestOpenIMCopyDB(dst *db.FriendRequest, src *open_im_sdk.FriendRequest) { + utils.CopyStructFields(dst, src) + dst.CreateTime = utils.UnixSecondToTime(int64(src.CreateTime)) + dst.HandleTime = utils.UnixSecondToTime(int64(src.HandleTime)) +} + +func FriendRequestDBCopyOpenIM(dst *open_im_sdk.FriendRequest, src *db.FriendRequest) error { + utils.CopyStructFields(dst, src) + user, err := imdb.GetUserByUserID(src.FromUserID) + if err != nil { + return utils.Wrap(err, "") + } + dst.FromNickname = user.Nickname + dst.FromFaceURL = user.FaceURL + dst.FromGender = user.Gender + user, err = imdb.GetUserByUserID(src.ToUserID) + if err != nil { + return utils.Wrap(err, "") + } + dst.ToNickname = user.Nickname + dst.ToFaceURL = user.FaceURL + dst.ToGender = user.Gender + dst.CreateTime = uint32(src.CreateTime.Unix()) + dst.HandleTime = uint32(src.HandleTime.Unix()) + return nil +} + +func BlackOpenIMCopyDB(dst *db.Black, src *open_im_sdk.BlackInfo) { + utils.CopyStructFields(dst, src) + dst.BlockUserID = src.BlackUserInfo.UserID + dst.CreateTime = utils.UnixSecondToTime(int64(src.CreateTime)) +} + +func BlackDBCopyOpenIM(dst *open_im_sdk.BlackInfo, src *db.Black) error { + utils.CopyStructFields(dst, src) + dst.CreateTime = uint32(src.CreateTime.Unix()) + user, err := imdb.GetUserByUserID(src.BlockUserID) + if err != nil { + return utils.Wrap(err, "") + } + utils.CopyStructFields(dst.BlackUserInfo, user) + return nil +} + +func GroupOpenIMCopyDB(dst *db.Group, src *open_im_sdk.GroupInfo) { + utils.CopyStructFields(dst, src) +} + +func GroupDBCopyOpenIM(dst *open_im_sdk.GroupInfo, src *db.Group) error { + utils.CopyStructFields(dst, src) + user, err := imdb.GetGroupOwnerInfoByGroupID(src.GroupID) + if err != nil { + return utils.Wrap(err, "") + } + dst.OwnerUserID = user.UserID + + dst.MemberCount, err = imdb.GetGroupMemberNumByGroupID(src.GroupID) + if err != nil { + return utils.Wrap(err, "") + } + dst.CreateTime = uint32(src.CreateTime.Unix()) + return nil +} + +func GroupMemberOpenIMCopyDB(dst *db.GroupMember, src *open_im_sdk.GroupMemberFullInfo) { + utils.CopyStructFields(dst, src) +} + +func GroupMemberDBCopyOpenIM(dst *open_im_sdk.GroupMemberFullInfo, src *db.GroupMember) error { + utils.CopyStructFields(dst, src) + if token_verify.IsManagerUserID(src.UserID) { + u, err := imdb.GetUserByUserID(src.UserID) + if err != nil { + return utils.Wrap(err, "") + } + + utils.CopyStructFields(dst, u) + + dst.AppMangerLevel = 1 + } + dst.JoinTime = int32(src.JoinTime.Unix()) + if src.MuteEndTime.Unix() < 0 { + dst.JoinTime = 0 + return nil + } + dst.MuteEndTime = uint32(src.MuteEndTime.Unix()) + if dst.MuteEndTime < uint32(time.Now().Unix()) { + dst.MuteEndTime = 0 + } + return nil +} + +func GroupRequestOpenIMCopyDB(dst *db.GroupRequest, src *open_im_sdk.GroupRequest) { + utils.CopyStructFields(dst, src) +} + +func GroupRequestDBCopyOpenIM(dst *open_im_sdk.GroupRequest, src *db.GroupRequest) { + utils.CopyStructFields(dst, src) + dst.ReqTime = uint32(src.ReqTime.Unix()) + dst.HandleTime = uint32(src.HandledTime.Unix()) +} + +func UserOpenIMCopyDB(dst *db.User, src *open_im_sdk.UserInfo) { + utils.CopyStructFields(dst, src) + dst.Birth = utils.UnixSecondToTime(int64(src.Birth)) + dst.CreateTime = utils.UnixSecondToTime(int64(src.CreateTime)) +} + +func UserDBCopyOpenIM(dst *open_im_sdk.UserInfo, src *db.User) { + utils.CopyStructFields(dst, src) + dst.CreateTime = uint32(src.CreateTime.Unix()) + dst.Birth = uint32(src.Birth.Unix()) +} + +func UserDBCopyOpenIMPublicUser(dst *open_im_sdk.PublicUserInfo, src *db.User) { + utils.CopyStructFields(dst, src) +} + +// +//func PublicUserDBCopyOpenIM(dst *open_im_sdk.PublicUserInfo, src *db.User){ +// +//} diff --git a/pkg/grpc-etcdv3/getcdv3/pool.go b/pkg/grpc-etcdv3/getcdv3/pool.go new file mode 100644 index 000000000..943f4bd3f --- /dev/null +++ b/pkg/grpc-etcdv3/getcdv3/pool.go @@ -0,0 +1,254 @@ +// Package grpcpool provides a pool of grpc clients +package getcdv3 + +import ( + "context" + "errors" + "sync" + "time" + + "google.golang.org/grpc" +) + +var ( + // ErrClosed is the error when the client pool is closed + ErrClosed = errors.New("grpc pool: client pool is closed") + // ErrTimeout is the error when the client pool timed out + ErrTimeout = errors.New("grpc pool: client pool timed out") + // ErrAlreadyClosed is the error when the client conn was already closed + ErrAlreadyClosed = errors.New("grpc pool: the connection was already closed") + // ErrFullPool is the error when the pool is already full + ErrFullPool = errors.New("grpc pool: closing a ClientConn into a full pool") +) + +// Factory is a function type creating a grpc client +type Factory func(schema, etcdaddr, servicename string) (*grpc.ClientConn, error) + +// FactoryWithContext is a function type creating a grpc client +// that accepts the context parameter that could be passed from +// Get or NewWithContext method. +type FactoryWithContext func(context.Context) (*grpc.ClientConn, error) + +// Pool is the grpc client pool +type Pool struct { + clients chan ClientConn + factory FactoryWithContext + idleTimeout time.Duration + maxLifeDuration time.Duration + mu sync.RWMutex +} + +// ClientConn is the wrapper for a grpc client conn +type ClientConn struct { + *grpc.ClientConn + pool *Pool + timeUsed time.Time + timeInitiated time.Time + unhealthy bool +} + +// New creates a new clients pool with the given initial and maximum capacity, +// and the timeout for the idle clients. Returns an error if the initial +// clients could not be created +func New(factory Factory, schema, etcdaddr, servicename string, init, capacity int, idleTimeout time.Duration, + maxLifeDuration ...time.Duration) (*Pool, error) { + return NewWithContext(context.Background(), func(ctx context.Context) (*grpc.ClientConn, error) { return factory(schema, etcdaddr, servicename) }, + init, capacity, idleTimeout, maxLifeDuration...) +} + +// NewWithContext creates a new clients pool with the given initial and maximum +// capacity, and the timeout for the idle clients. The context parameter would +// be passed to the factory method during initialization. Returns an error if the +// initial clients could not be created. +func NewWithContext(ctx context.Context, factory FactoryWithContext, init, capacity int, idleTimeout time.Duration, + maxLifeDuration ...time.Duration) (*Pool, error) { + + if capacity <= 0 { + capacity = 1 + } + if init < 0 { + init = 0 + } + if init > capacity { + init = capacity + } + p := &Pool{ + clients: make(chan ClientConn, capacity), + factory: factory, + idleTimeout: idleTimeout, + } + if len(maxLifeDuration) > 0 { + p.maxLifeDuration = maxLifeDuration[0] + } + for i := 0; i < init; i++ { + c, err := factory(ctx) + if err != nil { + return nil, err + } + + p.clients <- ClientConn{ + ClientConn: c, + pool: p, + timeUsed: time.Now(), + timeInitiated: time.Now(), + } + } + // Fill the rest of the pool with empty clients + for i := 0; i < capacity-init; i++ { + p.clients <- ClientConn{ + pool: p, + } + } + return p, nil +} + +func (p *Pool) getClients() chan ClientConn { + p.mu.RLock() + defer p.mu.RUnlock() + + return p.clients +} + +// Close empties the pool calling Close on all its clients. +// You can call Close while there are outstanding clients. +// The pool channel is then closed, and Get will not be allowed anymore +func (p *Pool) Close() { + p.mu.Lock() + clients := p.clients + p.clients = nil + p.mu.Unlock() + + if clients == nil { + return + } + + close(clients) + for client := range clients { + if client.ClientConn == nil { + continue + } + client.ClientConn.Close() + } +} + +// IsClosed returns true if the client pool is closed. +func (p *Pool) IsClosed() bool { + return p == nil || p.getClients() == nil +} + +// Get will return the next available client. If capacity +// has not been reached, it will create a new one using the factory. Otherwise, +// it will wait till the next client becomes available or a timeout. +// A timeout of 0 is an indefinite wait +func (p *Pool) Get(ctx context.Context) (*ClientConn, error) { + clients := p.getClients() + if clients == nil { + return nil, ErrClosed + } + + wrapper := ClientConn{ + pool: p, + } + select { + case wrapper = <-clients: + // All good + case <-ctx.Done(): + return nil, ErrTimeout // it would better returns ctx.Err() + } + + // If the wrapper was idle too long, close the connection and create a new + // one. It's safe to assume that there isn't any newer client as the client + // we fetched is the first in the channel + idleTimeout := p.idleTimeout + if wrapper.ClientConn != nil && idleTimeout > 0 && + wrapper.timeUsed.Add(idleTimeout).Before(time.Now()) { + + wrapper.ClientConn.Close() + wrapper.ClientConn = nil + } + + var err error + if wrapper.ClientConn == nil { + wrapper.ClientConn, err = p.factory(ctx) + if err != nil { + // If there was an error, we want to put back a placeholder + // client in the channel + clients <- ClientConn{ + pool: p, + } + } + // This is a new connection, reset its initiated time + wrapper.timeInitiated = time.Now() + } + + return &wrapper, err +} + +// Unhealthy marks the client conn as unhealthy, so that the connection +// gets reset when closed +func (c *ClientConn) Unhealthy() { + c.unhealthy = true +} + +// Close returns a ClientConn to the pool. It is safe to call multiple time, +// but will return an error after first time +func (c *ClientConn) Close() error { + if c == nil { + return nil + } + if c.ClientConn == nil { + return ErrAlreadyClosed + } + if c.pool.IsClosed() { + return ErrClosed + } + // If the wrapper connection has become too old, we want to recycle it. To + // clarify the logic: if the sum of the initialization time and the max + // duration is before Now(), it means the initialization is so old adding + // the maximum duration couldn't put in the future. This sum therefore + // corresponds to the cut-off point: if it's in the future we still have + // time, if it's in the past it's too old + maxDuration := c.pool.maxLifeDuration + if maxDuration > 0 && c.timeInitiated.Add(maxDuration).Before(time.Now()) { + c.Unhealthy() + } + + // We're cloning the wrapper so we can set ClientConn to nil in the one + // used by the user + wrapper := ClientConn{ + pool: c.pool, + ClientConn: c.ClientConn, + timeUsed: time.Now(), + } + if c.unhealthy { + wrapper.ClientConn.Close() + wrapper.ClientConn = nil + } else { + wrapper.timeInitiated = c.timeInitiated + } + select { + case c.pool.clients <- wrapper: + // All good + default: + return ErrFullPool + } + + c.ClientConn = nil // Mark as closed + return nil +} + +// Capacity returns the capacity +func (p *Pool) Capacity() int { + if p.IsClosed() { + return 0 + } + return cap(p.clients) +} + +// Available returns the number of currently unused clients +func (p *Pool) Available() int { + if p.IsClosed() { + return 0 + } + return len(p.clients) +} diff --git a/pkg/grpc-etcdv3/getcdv3/register.go b/pkg/grpc-etcdv3/getcdv3/register.go new file mode 100644 index 000000000..6bfdb626c --- /dev/null +++ b/pkg/grpc-etcdv3/getcdv3/register.go @@ -0,0 +1,118 @@ +package getcdv3 + +import ( + "Open_IM/pkg/common/log" + "context" + "fmt" + "go.etcd.io/etcd/clientv3" + "net" + "strconv" + "strings" + "time" +) + +type RegEtcd struct { + cli *clientv3.Client + ctx context.Context + cancel context.CancelFunc + key string +} + +var rEtcd *RegEtcd + +// "%s:///%s/" +func GetPrefix(schema, serviceName string) string { + return fmt.Sprintf("%s:///%s/", schema, serviceName) +} + +// "%s:///%s" +func GetPrefix4Unique(schema, serviceName string) string { + return fmt.Sprintf("%s:///%s", schema, serviceName) +} + +// "%s:///%s/" -> "%s:///%s:ip:port" +func RegisterEtcd4Unique(schema, etcdAddr, myHost string, myPort int, serviceName string, ttl int) error { + serviceName = serviceName + ":" + net.JoinHostPort(myHost, strconv.Itoa(myPort)) + return RegisterEtcd(schema, etcdAddr, myHost, myPort, serviceName, ttl) +} + +//etcdAddr separated by commas +func RegisterEtcd(schema, etcdAddr, myHost string, myPort int, serviceName string, ttl int) error { + ttl = ttl * 3 + cli, err := clientv3.New(clientv3.Config{ + Endpoints: strings.Split(etcdAddr, ","), DialTimeout: 5 * time.Second}) + + log.Info("", "RegisterEtcd, ", schema, etcdAddr, myHost, myPort, serviceName, ttl) + if err != nil { + return fmt.Errorf("create etcd clientv3 client failed, errmsg:%v, etcd addr:%s", err, etcdAddr) + } + + //lease + ctx, cancel := context.WithCancel(context.Background()) + resp, err := cli.Grant(ctx, int64(ttl)) + if err != nil { + return fmt.Errorf("grant failed") + } + + // schema:///serviceName/ip:port ->ip:port + serviceValue := net.JoinHostPort(myHost, strconv.Itoa(myPort)) + serviceKey := GetPrefix(schema, serviceName) + serviceValue + + //set key->value + if _, err := cli.Put(ctx, serviceKey, serviceValue, clientv3.WithLease(resp.ID)); err != nil { + return fmt.Errorf("put failed, errmsg:%v, key:%s, value:%s", err, serviceKey, serviceValue) + } + + //keepalive + kresp, err := cli.KeepAlive(ctx, resp.ID) + if err != nil { + return fmt.Errorf("keepalive failed, errmsg:%v, lease id:%d", err, resp.ID) + } + //log.Info("", "RegisterEtcd ok ") + + go func() { + for { + select { + case pv, ok := <-kresp: + if ok == true { + log.Debug("", "KeepAlive kresp ok", pv) + } else { + log.Error("", "KeepAlive kresp failed", pv) + t := time.NewTicker(time.Duration(ttl/2) * time.Second) + for { + select { + case <-t.C: + } + ctx, _ := context.WithCancel(context.Background()) + resp, err := cli.Grant(ctx, int64(ttl)) + if err != nil { + log.Error("", "Grant failed ", err.Error()) + continue + } + + if _, err := cli.Put(ctx, serviceKey, serviceValue, clientv3.WithLease(resp.ID)); err != nil { + log.Error("", "etcd Put failed ", err.Error(), serviceKey, serviceValue, resp.ID) + continue + } else { + log.Info("", "etcd Put ok", serviceKey, serviceValue, resp.ID) + } + + } + } + } + } + }() + + rEtcd = &RegEtcd{ctx: ctx, + cli: cli, + cancel: cancel, + key: serviceKey} + + return nil +} + +func UnRegisterEtcd() { + //delete + rEtcd.cancel() + rEtcd.cli.Delete(rEtcd.ctx, rEtcd.key) +} diff --git a/pkg/grpc-etcdv3/getcdv3/resolver.go b/pkg/grpc-etcdv3/getcdv3/resolver.go new file mode 100644 index 000000000..1e57f8cdd --- /dev/null +++ b/pkg/grpc-etcdv3/getcdv3/resolver.go @@ -0,0 +1,262 @@ +package getcdv3 + +import ( + "context" + "fmt" + "go.etcd.io/etcd/clientv3" + "go.etcd.io/etcd/mvcc/mvccpb" + //"google.golang.org/genproto/googleapis/ads/googleads/v1/services" + "google.golang.org/grpc" + "google.golang.org/grpc/balancer/roundrobin" + "google.golang.org/grpc/resolver" + "strings" + "sync" + "time" +) + +type Resolver struct { + cc resolver.ClientConn + serviceName string + grpcClientConn *grpc.ClientConn + cli *clientv3.Client + schema string + etcdAddr string + watchStartRevision int64 +} + +var ( + nameResolver = make(map[string]*Resolver) + rwNameResolverMutex sync.RWMutex +) + +func NewResolver(schema, etcdAddr, serviceName string) (*Resolver, error) { + etcdCli, err := clientv3.New(clientv3.Config{ + Endpoints: strings.Split(etcdAddr, ","), + }) + if err != nil { + return nil, err + } + + var r Resolver + r.serviceName = serviceName + r.cli = etcdCli + r.schema = schema + r.etcdAddr = etcdAddr + resolver.Register(&r) + + conn, err := grpc.Dial( + GetPrefix(schema, serviceName), + grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)), + grpc.WithInsecure(), + grpc.WithTimeout(time.Duration(5)*time.Second), + ) + if err == nil { + r.grpcClientConn = conn + } + return &r, err +} + +func (r1 *Resolver) ResolveNow(rn resolver.ResolveNowOptions) { +} + +func (r1 *Resolver) Close() { +} + +func GetConn(schema, etcdaddr, serviceName string) *grpc.ClientConn { + rwNameResolverMutex.RLock() + r, ok := nameResolver[schema+serviceName] + rwNameResolverMutex.RUnlock() + if ok { + return r.grpcClientConn + } + + rwNameResolverMutex.Lock() + r, ok = nameResolver[schema+serviceName] + if ok { + rwNameResolverMutex.Unlock() + return r.grpcClientConn + } + + r, err := NewResolver(schema, etcdaddr, serviceName) + if err != nil { + rwNameResolverMutex.Unlock() + return nil + } + + nameResolver[schema+serviceName] = r + rwNameResolverMutex.Unlock() + return r.grpcClientConn +} + +func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { + if r.cli == nil { + return nil, fmt.Errorf("etcd clientv3 client failed, etcd:%s", target) + } + r.cc = cc + + ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) + // "%s:///%s" + prefix := GetPrefix(r.schema, r.serviceName) + // get key first + resp, err := r.cli.Get(ctx, prefix, clientv3.WithPrefix()) + if err == nil { + var addrList []resolver.Address + for i := range resp.Kvs { + //log.Debug("", "init addr: ", string(resp.Kvs[i].Value)) + addrList = append(addrList, resolver.Address{Addr: string(resp.Kvs[i].Value)}) + } + r.cc.UpdateState(resolver.State{Addresses: addrList}) + r.watchStartRevision = resp.Header.Revision + 1 + go r.watch(prefix, addrList) + } else { + return nil, fmt.Errorf("etcd get failed, prefix: %s", prefix) + } + + return r, nil +} + +func (r *Resolver) Scheme() string { + return r.schema +} + +func exists(addrList []resolver.Address, addr string) bool { + for _, v := range addrList { + if v.Addr == addr { + return true + } + } + return false +} + +func remove(s []resolver.Address, addr string) ([]resolver.Address, bool) { + for i := range s { + if s[i].Addr == addr { + s[i] = s[len(s)-1] + return s[:len(s)-1], true + } + } + return nil, false +} + +func (r *Resolver) watch(prefix string, addrList []resolver.Address) { + rch := r.cli.Watch(context.Background(), prefix, clientv3.WithPrefix(), clientv3.WithPrefix()) + for n := range rch { + flag := 0 + for _, ev := range n.Events { + switch ev.Type { + case mvccpb.PUT: + if !exists(addrList, string(ev.Kv.Value)) { + flag = 1 + addrList = append(addrList, resolver.Address{Addr: string(ev.Kv.Value)}) + //log.Debug("", "after add, new list: ", addrList) + } + case mvccpb.DELETE: + //log.Debug("remove addr key: ", string(ev.Kv.Key), "value:", string(ev.Kv.Value)) + i := strings.LastIndexAny(string(ev.Kv.Key), "/") + if i < 0 { + return + } + t := string(ev.Kv.Key)[i+1:] + //log.Debug("remove addr key: ", string(ev.Kv.Key), "value:", string(ev.Kv.Value), "addr:", t) + if s, ok := remove(addrList, t); ok { + flag = 1 + addrList = s + //log.Debug("after remove, new list: ", addrList) + } + } + } + + if flag == 1 { + r.cc.UpdateState(resolver.State{Addresses: addrList}) + //log.Debug("update: ", addrList) + } + } +} + +func GetConn4Unique(schema, etcdaddr, servicename string) []*grpc.ClientConn { + gEtcdCli, err := clientv3.New(clientv3.Config{Endpoints: strings.Split(etcdaddr, ",")}) + if err != nil { + //log.Error("clientv3.New failed", err.Error()) + return nil + } + + ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) + // "%s:///%s" + prefix := GetPrefix4Unique(schema, servicename) + + resp, err := gEtcdCli.Get(ctx, prefix, clientv3.WithPrefix()) + // "%s:///%s:ip:port" -> %s:ip:port + allService := make([]string, 0) + if err == nil { + for i := range resp.Kvs { + k := string(resp.Kvs[i].Key) + + b := strings.LastIndex(k, "///") + k1 := k[b+len("///"):] + + e := strings.Index(k1, "/") + k2 := k1[:e] + allService = append(allService, k2) + } + } else { + gEtcdCli.Close() + //log.Error("gEtcdCli.Get failed", err.Error()) + return nil + } + gEtcdCli.Close() + + allConn := make([]*grpc.ClientConn, 0) + for _, v := range allService { + r := GetConn(schema, etcdaddr, v) + allConn = append(allConn, r) + } + + return allConn +} + +var ( + service2pool = make(map[string]*Pool) + service2poolMu sync.Mutex +) + +func GetconnFactory(schema, etcdaddr, servicename string) (*grpc.ClientConn, error) { + c := GetConn(schema, etcdaddr, servicename) + if c != nil { + return c, nil + } else { + return c, fmt.Errorf("GetConn failed") + } +} + +func GetConnPool(schema, etcdaddr, servicename string) (*ClientConn, error) { + //get pool + p := NewPool(schema, etcdaddr, servicename) + //poo->get + + ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(1000*time.Millisecond)) + + c, err := p.Get(ctx) + //log.Info("", "Get ", err) + return c, err + +} + +func NewPool(schema, etcdaddr, servicename string) *Pool { + + if _, ok := service2pool[schema+servicename]; !ok { + // + service2poolMu.Lock() + if _, ok1 := service2pool[schema+servicename]; !ok1 { + p, err := New(GetconnFactory, schema, etcdaddr, servicename, 5, 10, 1) + if err == nil { + service2pool[schema+servicename] = p + } + } + service2poolMu.Unlock() + } + + return service2pool[schema+servicename] +} +func GetGrpcConn(schema, etcdaddr, servicename string) *grpc.ClientConn { + return nameResolver[schema+servicename].grpcClientConn +} diff --git a/pkg/proto/admin_cms/admin_cms.pb.go b/pkg/proto/admin_cms/admin_cms.pb.go new file mode 100644 index 000000000..890f409a9 --- /dev/null +++ b/pkg/proto/admin_cms/admin_cms.pb.go @@ -0,0 +1,317 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.5 +// source: admin_cms/admin_cms.proto + +package admin_cms + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AdminLoginReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OperationID string `protobuf:"bytes,1,opt,name=OperationID,proto3" json:"OperationID,omitempty"` + AdminID string `protobuf:"bytes,2,opt,name=AdminID,proto3" json:"AdminID,omitempty"` + Secret string `protobuf:"bytes,3,opt,name=Secret,proto3" json:"Secret,omitempty"` +} + +func (x *AdminLoginReq) Reset() { + *x = AdminLoginReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_cms_admin_cms_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AdminLoginReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdminLoginReq) ProtoMessage() {} + +func (x *AdminLoginReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_cms_admin_cms_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdminLoginReq.ProtoReflect.Descriptor instead. +func (*AdminLoginReq) Descriptor() ([]byte, []int) { + return file_admin_cms_admin_cms_proto_rawDescGZIP(), []int{0} +} + +func (x *AdminLoginReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +func (x *AdminLoginReq) GetAdminID() string { + if x != nil { + return x.AdminID + } + return "" +} + +func (x *AdminLoginReq) GetSecret() string { + if x != nil { + return x.Secret + } + return "" +} + +type AdminLoginResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` +} + +func (x *AdminLoginResp) Reset() { + *x = AdminLoginResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_cms_admin_cms_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AdminLoginResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdminLoginResp) ProtoMessage() {} + +func (x *AdminLoginResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_cms_admin_cms_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdminLoginResp.ProtoReflect.Descriptor instead. +func (*AdminLoginResp) Descriptor() ([]byte, []int) { + return file_admin_cms_admin_cms_proto_rawDescGZIP(), []int{1} +} + +func (x *AdminLoginResp) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +var File_admin_cms_admin_cms_proto protoreflect.FileDescriptor + +var file_admin_cms_admin_cms_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6d, 0x73, 0x2f, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x5f, 0x63, 0x6d, 0x73, 0x22, 0x63, 0x0a, 0x0d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x26, 0x0a, 0x0e, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x32, 0x4d, 0x0a, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x4d, 0x53, 0x12, + 0x41, 0x0a, 0x0a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x18, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, + 0x63, 0x6d, 0x73, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x42, 0x17, 0x5a, 0x15, 0x2e, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6d, + 0x73, 0x3b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_admin_cms_admin_cms_proto_rawDescOnce sync.Once + file_admin_cms_admin_cms_proto_rawDescData = file_admin_cms_admin_cms_proto_rawDesc +) + +func file_admin_cms_admin_cms_proto_rawDescGZIP() []byte { + file_admin_cms_admin_cms_proto_rawDescOnce.Do(func() { + file_admin_cms_admin_cms_proto_rawDescData = protoimpl.X.CompressGZIP(file_admin_cms_admin_cms_proto_rawDescData) + }) + return file_admin_cms_admin_cms_proto_rawDescData +} + +var file_admin_cms_admin_cms_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_admin_cms_admin_cms_proto_goTypes = []interface{}{ + (*AdminLoginReq)(nil), // 0: admin_cms.AdminLoginReq + (*AdminLoginResp)(nil), // 1: admin_cms.AdminLoginResp +} +var file_admin_cms_admin_cms_proto_depIdxs = []int32{ + 0, // 0: admin_cms.adminCMS.AdminLogin:input_type -> admin_cms.AdminLoginReq + 1, // 1: admin_cms.adminCMS.AdminLogin:output_type -> admin_cms.AdminLoginResp + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_admin_cms_admin_cms_proto_init() } +func file_admin_cms_admin_cms_proto_init() { + if File_admin_cms_admin_cms_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_admin_cms_admin_cms_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AdminLoginReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_cms_admin_cms_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AdminLoginResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_admin_cms_admin_cms_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_admin_cms_admin_cms_proto_goTypes, + DependencyIndexes: file_admin_cms_admin_cms_proto_depIdxs, + MessageInfos: file_admin_cms_admin_cms_proto_msgTypes, + }.Build() + File_admin_cms_admin_cms_proto = out.File + file_admin_cms_admin_cms_proto_rawDesc = nil + file_admin_cms_admin_cms_proto_goTypes = nil + file_admin_cms_admin_cms_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// AdminCMSClient is the client API for AdminCMS service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AdminCMSClient interface { + AdminLogin(ctx context.Context, in *AdminLoginReq, opts ...grpc.CallOption) (*AdminLoginResp, error) +} + +type adminCMSClient struct { + cc grpc.ClientConnInterface +} + +func NewAdminCMSClient(cc grpc.ClientConnInterface) AdminCMSClient { + return &adminCMSClient{cc} +} + +func (c *adminCMSClient) AdminLogin(ctx context.Context, in *AdminLoginReq, opts ...grpc.CallOption) (*AdminLoginResp, error) { + out := new(AdminLoginResp) + err := c.cc.Invoke(ctx, "/admin_cms.adminCMS/AdminLogin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdminCMSServer is the server API for AdminCMS service. +type AdminCMSServer interface { + AdminLogin(context.Context, *AdminLoginReq) (*AdminLoginResp, error) +} + +// UnimplementedAdminCMSServer can be embedded to have forward compatible implementations. +type UnimplementedAdminCMSServer struct { +} + +func (*UnimplementedAdminCMSServer) AdminLogin(context.Context, *AdminLoginReq) (*AdminLoginResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AdminLogin not implemented") +} + +func RegisterAdminCMSServer(s *grpc.Server, srv AdminCMSServer) { + s.RegisterService(&_AdminCMS_serviceDesc, srv) +} + +func _AdminCMS_AdminLogin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdminLoginReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminCMSServer).AdminLogin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/admin_cms.adminCMS/AdminLogin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminCMSServer).AdminLogin(ctx, req.(*AdminLoginReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _AdminCMS_serviceDesc = grpc.ServiceDesc{ + ServiceName: "admin_cms.adminCMS", + HandlerType: (*AdminCMSServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AdminLogin", + Handler: _AdminCMS_AdminLogin_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "admin_cms/admin_cms.proto", +} diff --git a/pkg/proto/admin_cms/admin_cms.proto b/pkg/proto/admin_cms/admin_cms.proto new file mode 100644 index 000000000..6759268ed --- /dev/null +++ b/pkg/proto/admin_cms/admin_cms.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +option go_package = "./admin_cms;admin_cms"; +package admin_cms; + +message AdminLoginReq { + string OperationID = 1; + string AdminID = 2; + string Secret = 3; +} + + +message AdminLoginResp { + string token = 1; +} + +service adminCMS { + rpc AdminLogin(AdminLoginReq) returns(AdminLoginResp); +} \ No newline at end of file diff --git a/pkg/proto/auth/auth.pb.go b/pkg/proto/auth/auth.pb.go new file mode 100644 index 000000000..3941570ee --- /dev/null +++ b/pkg/proto/auth/auth.pb.go @@ -0,0 +1,414 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: auth/auth.proto + +package pbAuth // import "./auth" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CommonResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommonResp) Reset() { *m = CommonResp{} } +func (m *CommonResp) String() string { return proto.CompactTextString(m) } +func (*CommonResp) ProtoMessage() {} +func (*CommonResp) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_88965eda3ab7f34d, []int{0} +} +func (m *CommonResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommonResp.Unmarshal(m, b) +} +func (m *CommonResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommonResp.Marshal(b, m, deterministic) +} +func (dst *CommonResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommonResp.Merge(dst, src) +} +func (m *CommonResp) XXX_Size() int { + return xxx_messageInfo_CommonResp.Size(m) +} +func (m *CommonResp) XXX_DiscardUnknown() { + xxx_messageInfo_CommonResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CommonResp proto.InternalMessageInfo + +func (m *CommonResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CommonResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type UserRegisterReq struct { + UserInfo *sdk_ws.UserInfo `protobuf:"bytes,1,opt,name=UserInfo" json:"UserInfo,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserRegisterReq) Reset() { *m = UserRegisterReq{} } +func (m *UserRegisterReq) String() string { return proto.CompactTextString(m) } +func (*UserRegisterReq) ProtoMessage() {} +func (*UserRegisterReq) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_88965eda3ab7f34d, []int{1} +} +func (m *UserRegisterReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserRegisterReq.Unmarshal(m, b) +} +func (m *UserRegisterReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserRegisterReq.Marshal(b, m, deterministic) +} +func (dst *UserRegisterReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserRegisterReq.Merge(dst, src) +} +func (m *UserRegisterReq) XXX_Size() int { + return xxx_messageInfo_UserRegisterReq.Size(m) +} +func (m *UserRegisterReq) XXX_DiscardUnknown() { + xxx_messageInfo_UserRegisterReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UserRegisterReq proto.InternalMessageInfo + +func (m *UserRegisterReq) GetUserInfo() *sdk_ws.UserInfo { + if m != nil { + return m.UserInfo + } + return nil +} + +func (m *UserRegisterReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type UserRegisterResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserRegisterResp) Reset() { *m = UserRegisterResp{} } +func (m *UserRegisterResp) String() string { return proto.CompactTextString(m) } +func (*UserRegisterResp) ProtoMessage() {} +func (*UserRegisterResp) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_88965eda3ab7f34d, []int{2} +} +func (m *UserRegisterResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserRegisterResp.Unmarshal(m, b) +} +func (m *UserRegisterResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserRegisterResp.Marshal(b, m, deterministic) +} +func (dst *UserRegisterResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserRegisterResp.Merge(dst, src) +} +func (m *UserRegisterResp) XXX_Size() int { + return xxx_messageInfo_UserRegisterResp.Size(m) +} +func (m *UserRegisterResp) XXX_DiscardUnknown() { + xxx_messageInfo_UserRegisterResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UserRegisterResp proto.InternalMessageInfo + +func (m *UserRegisterResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type UserTokenReq struct { + Platform int32 `protobuf:"varint,1,opt,name=Platform" json:"Platform,omitempty"` + FromUserID string `protobuf:"bytes,2,opt,name=FromUserID" json:"FromUserID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserTokenReq) Reset() { *m = UserTokenReq{} } +func (m *UserTokenReq) String() string { return proto.CompactTextString(m) } +func (*UserTokenReq) ProtoMessage() {} +func (*UserTokenReq) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_88965eda3ab7f34d, []int{3} +} +func (m *UserTokenReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserTokenReq.Unmarshal(m, b) +} +func (m *UserTokenReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserTokenReq.Marshal(b, m, deterministic) +} +func (dst *UserTokenReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserTokenReq.Merge(dst, src) +} +func (m *UserTokenReq) XXX_Size() int { + return xxx_messageInfo_UserTokenReq.Size(m) +} +func (m *UserTokenReq) XXX_DiscardUnknown() { + xxx_messageInfo_UserTokenReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UserTokenReq proto.InternalMessageInfo + +func (m *UserTokenReq) GetPlatform() int32 { + if m != nil { + return m.Platform + } + return 0 +} + +func (m *UserTokenReq) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +func (m *UserTokenReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *UserTokenReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type UserTokenResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + Token string `protobuf:"bytes,2,opt,name=Token" json:"Token,omitempty"` + ExpiredTime int64 `protobuf:"varint,3,opt,name=ExpiredTime" json:"ExpiredTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserTokenResp) Reset() { *m = UserTokenResp{} } +func (m *UserTokenResp) String() string { return proto.CompactTextString(m) } +func (*UserTokenResp) ProtoMessage() {} +func (*UserTokenResp) Descriptor() ([]byte, []int) { + return fileDescriptor_auth_88965eda3ab7f34d, []int{4} +} +func (m *UserTokenResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserTokenResp.Unmarshal(m, b) +} +func (m *UserTokenResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserTokenResp.Marshal(b, m, deterministic) +} +func (dst *UserTokenResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserTokenResp.Merge(dst, src) +} +func (m *UserTokenResp) XXX_Size() int { + return xxx_messageInfo_UserTokenResp.Size(m) +} +func (m *UserTokenResp) XXX_DiscardUnknown() { + xxx_messageInfo_UserTokenResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UserTokenResp proto.InternalMessageInfo + +func (m *UserTokenResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *UserTokenResp) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *UserTokenResp) GetExpiredTime() int64 { + if m != nil { + return m.ExpiredTime + } + return 0 +} + +func init() { + proto.RegisterType((*CommonResp)(nil), "pbAuth.CommonResp") + proto.RegisterType((*UserRegisterReq)(nil), "pbAuth.UserRegisterReq") + proto.RegisterType((*UserRegisterResp)(nil), "pbAuth.UserRegisterResp") + proto.RegisterType((*UserTokenReq)(nil), "pbAuth.UserTokenReq") + proto.RegisterType((*UserTokenResp)(nil), "pbAuth.UserTokenResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Auth service + +type AuthClient interface { + UserRegister(ctx context.Context, in *UserRegisterReq, opts ...grpc.CallOption) (*UserRegisterResp, error) + UserToken(ctx context.Context, in *UserTokenReq, opts ...grpc.CallOption) (*UserTokenResp, error) +} + +type authClient struct { + cc *grpc.ClientConn +} + +func NewAuthClient(cc *grpc.ClientConn) AuthClient { + return &authClient{cc} +} + +func (c *authClient) UserRegister(ctx context.Context, in *UserRegisterReq, opts ...grpc.CallOption) (*UserRegisterResp, error) { + out := new(UserRegisterResp) + err := grpc.Invoke(ctx, "/pbAuth.Auth/UserRegister", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authClient) UserToken(ctx context.Context, in *UserTokenReq, opts ...grpc.CallOption) (*UserTokenResp, error) { + out := new(UserTokenResp) + err := grpc.Invoke(ctx, "/pbAuth.Auth/UserToken", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Auth service + +type AuthServer interface { + UserRegister(context.Context, *UserRegisterReq) (*UserRegisterResp, error) + UserToken(context.Context, *UserTokenReq) (*UserTokenResp, error) +} + +func RegisterAuthServer(s *grpc.Server, srv AuthServer) { + s.RegisterService(&_Auth_serviceDesc, srv) +} + +func _Auth_UserRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserRegisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServer).UserRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pbAuth.Auth/UserRegister", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServer).UserRegister(ctx, req.(*UserRegisterReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Auth_UserToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserTokenReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServer).UserToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pbAuth.Auth/UserToken", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServer).UserToken(ctx, req.(*UserTokenReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _Auth_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pbAuth.Auth", + HandlerType: (*AuthServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UserRegister", + Handler: _Auth_UserRegister_Handler, + }, + { + MethodName: "UserToken", + Handler: _Auth_UserToken_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "auth/auth.proto", +} + +func init() { proto.RegisterFile("auth/auth.proto", fileDescriptor_auth_88965eda3ab7f34d) } + +var fileDescriptor_auth_88965eda3ab7f34d = []byte{ + // 369 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x4d, 0x4b, 0xc3, 0x40, + 0x10, 0x25, 0xf6, 0xc3, 0x76, 0x6a, 0xa9, 0x2c, 0x55, 0x43, 0x04, 0xa9, 0x39, 0xf5, 0x94, 0x40, + 0x3d, 0x28, 0x08, 0x42, 0xad, 0x16, 0x7a, 0x28, 0x95, 0xa5, 0x5e, 0xbc, 0x84, 0x94, 0x6e, 0xdb, + 0x90, 0x26, 0xbb, 0xee, 0xa6, 0x56, 0xf0, 0xe8, 0xc5, 0x9f, 0x2d, 0xbb, 0xf9, 0x70, 0xad, 0x3d, + 0x79, 0x49, 0x98, 0x79, 0x2f, 0xf3, 0xde, 0x9b, 0x0c, 0xb4, 0xfc, 0x4d, 0xb2, 0x72, 0xe5, 0xc3, + 0x61, 0x9c, 0x26, 0x14, 0x55, 0xd9, 0xac, 0xbf, 0x49, 0x56, 0xd6, 0xe5, 0x84, 0x91, 0xd8, 0x1b, + 0x8d, 0x5d, 0x16, 0x2e, 0x5d, 0x05, 0xb9, 0x62, 0x1e, 0x7a, 0x5b, 0xe1, 0x6e, 0x45, 0x4a, 0xb5, + 0xef, 0x00, 0x06, 0x34, 0x8a, 0x68, 0x8c, 0x89, 0x60, 0xc8, 0x84, 0x43, 0xc2, 0xf9, 0x80, 0xce, + 0x89, 0x69, 0x74, 0x8c, 0x6e, 0x05, 0xe7, 0x25, 0x3a, 0x85, 0x2a, 0xe1, 0x7c, 0x2c, 0x96, 0xe6, + 0x41, 0xc7, 0xe8, 0xd6, 0x71, 0x56, 0xd9, 0x6b, 0x68, 0x3d, 0x0b, 0xc2, 0x31, 0x59, 0x06, 0x22, + 0x91, 0xef, 0x57, 0x74, 0x0d, 0x35, 0xd9, 0x1a, 0xc5, 0x0b, 0xaa, 0xa6, 0x34, 0x7a, 0xe7, 0x8e, + 0x20, 0xfc, 0x8d, 0x70, 0xcf, 0x67, 0x81, 0xc7, 0x7c, 0xee, 0x47, 0xc2, 0xc9, 0x29, 0xb8, 0x20, + 0xa3, 0x0e, 0x34, 0x26, 0x8c, 0x70, 0x3f, 0x09, 0x68, 0x3c, 0x7a, 0xc8, 0x84, 0xf4, 0x96, 0x3d, + 0x84, 0xe3, 0xdf, 0x6a, 0x82, 0xa1, 0x9e, 0x9e, 0x20, 0x13, 0x44, 0x4e, 0xba, 0x01, 0xe7, 0x07, + 0xc1, 0x1a, 0xcb, 0xfe, 0x32, 0xe0, 0x48, 0x0e, 0x9a, 0xd2, 0x90, 0xc4, 0xd2, 0xb3, 0x05, 0xb5, + 0xa7, 0xb5, 0x9f, 0x2c, 0x28, 0x8f, 0xb2, 0xe4, 0x45, 0x8d, 0x2e, 0x00, 0x86, 0x9c, 0x46, 0xca, + 0x66, 0xee, 0x4a, 0xeb, 0xc8, 0x6f, 0x27, 0x2c, 0x43, 0x4b, 0x0a, 0x2d, 0xea, 0xdd, 0x48, 0xe5, + 0xbf, 0x91, 0x3e, 0xa0, 0xa9, 0x39, 0xf9, 0x5f, 0x1e, 0xd4, 0x86, 0x8a, 0x1a, 0x90, 0xb9, 0x4b, + 0x0b, 0x29, 0xfe, 0xf8, 0xce, 0x02, 0x4e, 0xe6, 0xd3, 0x20, 0x22, 0xca, 0x5b, 0x09, 0xeb, 0xad, + 0xde, 0xa7, 0x01, 0x65, 0x39, 0x17, 0xf5, 0xd3, 0x7d, 0xe4, 0x8b, 0x45, 0x67, 0xb9, 0xe0, 0xce, + 0xcf, 0xb5, 0xcc, 0xfd, 0x80, 0x60, 0xe8, 0x06, 0xea, 0x45, 0x10, 0xd4, 0xd6, 0x69, 0xf9, 0x96, + 0xad, 0x93, 0x3d, 0x5d, 0xc1, 0xee, 0x5b, 0x2f, 0x4d, 0x47, 0x9d, 0xef, 0x6d, 0x0a, 0xcf, 0xaa, + 0xea, 0x36, 0xaf, 0xbe, 0x03, 0x00, 0x00, 0xff, 0xff, 0x1b, 0x20, 0x74, 0x9f, 0xd9, 0x02, 0x00, + 0x00, +} diff --git a/pkg/proto/auth/auth.proto b/pkg/proto/auth/auth.proto new file mode 100644 index 000000000..c91921fe9 --- /dev/null +++ b/pkg/proto/auth/auth.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +package pbAuth; +option go_package = "./auth;pbAuth"; + +message CommonResp{ + int32 errCode = 1; + string errMsg = 2; +} + +message UserRegisterReq { + server_api_params.UserInfo UserInfo = 1; + string OperationID = 2; +} +message UserRegisterResp { + CommonResp CommonResp = 1; +} + + +message UserTokenReq { + int32 Platform = 1; + string FromUserID = 2; + string OpUserID = 3; + string OperationID = 4; +} +message UserTokenResp { + CommonResp CommonResp = 1; + string Token = 2; + int64 ExpiredTime = 3; +} + + +service Auth { + rpc UserRegister(UserRegisterReq) returns(UserRegisterResp); + rpc UserToken(UserTokenReq) returns(UserTokenResp); +} diff --git a/pkg/proto/auto_proto.sh b/pkg/proto/auto_proto.sh new file mode 100644 index 000000000..25408d46e --- /dev/null +++ b/pkg/proto/auto_proto.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +source ./proto_dir.cfg + +for ((i = 0; i < ${#all_proto[*]}; i++)); do + proto=${all_proto[$i]} + protoc -I ../../../ -I ./ --go_out=plugins=grpc:. $proto + s=`echo $proto | sed 's/ //g'` + v=${s//proto/pb.go} + protoc-go-inject-tag -input=./$v + echo "protoc --go_out=plugins=grpc:." $proto +done +echo "proto file generate success..." diff --git a/pkg/proto/base/base.proto b/pkg/proto/base/base.proto new file mode 100644 index 000000000..6d5144f0b --- /dev/null +++ b/pkg/proto/base/base.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; +package base; + + + diff --git a/pkg/proto/chat/chat.pb.go b/pkg/proto/chat/chat.pb.go new file mode 100644 index 000000000..cf1c6ba50 --- /dev/null +++ b/pkg/proto/chat/chat.pb.go @@ -0,0 +1,650 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: chat/chat.proto + +package pbChat // import "./chat" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type MsgDataToMQ struct { + Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + MsgData *sdk_ws.MsgData `protobuf:"bytes,3,opt,name=msgData" json:"msgData,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgDataToMQ) Reset() { *m = MsgDataToMQ{} } +func (m *MsgDataToMQ) String() string { return proto.CompactTextString(m) } +func (*MsgDataToMQ) ProtoMessage() {} +func (*MsgDataToMQ) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{0} +} +func (m *MsgDataToMQ) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgDataToMQ.Unmarshal(m, b) +} +func (m *MsgDataToMQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgDataToMQ.Marshal(b, m, deterministic) +} +func (dst *MsgDataToMQ) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDataToMQ.Merge(dst, src) +} +func (m *MsgDataToMQ) XXX_Size() int { + return xxx_messageInfo_MsgDataToMQ.Size(m) +} +func (m *MsgDataToMQ) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDataToMQ.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDataToMQ proto.InternalMessageInfo + +func (m *MsgDataToMQ) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *MsgDataToMQ) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *MsgDataToMQ) GetMsgData() *sdk_ws.MsgData { + if m != nil { + return m.MsgData + } + return nil +} + +type MsgDataToDB struct { + MsgData *sdk_ws.MsgData `protobuf:"bytes,1,opt,name=msgData" json:"msgData,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgDataToDB) Reset() { *m = MsgDataToDB{} } +func (m *MsgDataToDB) String() string { return proto.CompactTextString(m) } +func (*MsgDataToDB) ProtoMessage() {} +func (*MsgDataToDB) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{1} +} +func (m *MsgDataToDB) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgDataToDB.Unmarshal(m, b) +} +func (m *MsgDataToDB) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgDataToDB.Marshal(b, m, deterministic) +} +func (dst *MsgDataToDB) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDataToDB.Merge(dst, src) +} +func (m *MsgDataToDB) XXX_Size() int { + return xxx_messageInfo_MsgDataToDB.Size(m) +} +func (m *MsgDataToDB) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDataToDB.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDataToDB proto.InternalMessageInfo + +func (m *MsgDataToDB) GetMsgData() *sdk_ws.MsgData { + if m != nil { + return m.MsgData + } + return nil +} + +func (m *MsgDataToDB) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type PushMsgDataToMQ struct { + OperationID string `protobuf:"bytes,1,opt,name=OperationID" json:"OperationID,omitempty"` + MsgData *sdk_ws.MsgData `protobuf:"bytes,2,opt,name=msgData" json:"msgData,omitempty"` + PushToUserID string `protobuf:"bytes,3,opt,name=pushToUserID" json:"pushToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PushMsgDataToMQ) Reset() { *m = PushMsgDataToMQ{} } +func (m *PushMsgDataToMQ) String() string { return proto.CompactTextString(m) } +func (*PushMsgDataToMQ) ProtoMessage() {} +func (*PushMsgDataToMQ) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{2} +} +func (m *PushMsgDataToMQ) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PushMsgDataToMQ.Unmarshal(m, b) +} +func (m *PushMsgDataToMQ) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PushMsgDataToMQ.Marshal(b, m, deterministic) +} +func (dst *PushMsgDataToMQ) XXX_Merge(src proto.Message) { + xxx_messageInfo_PushMsgDataToMQ.Merge(dst, src) +} +func (m *PushMsgDataToMQ) XXX_Size() int { + return xxx_messageInfo_PushMsgDataToMQ.Size(m) +} +func (m *PushMsgDataToMQ) XXX_DiscardUnknown() { + xxx_messageInfo_PushMsgDataToMQ.DiscardUnknown(m) +} + +var xxx_messageInfo_PushMsgDataToMQ proto.InternalMessageInfo + +func (m *PushMsgDataToMQ) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *PushMsgDataToMQ) GetMsgData() *sdk_ws.MsgData { + if m != nil { + return m.MsgData + } + return nil +} + +func (m *PushMsgDataToMQ) GetPushToUserID() string { + if m != nil { + return m.PushToUserID + } + return "" +} + +// message PullMessageReq { +// string UserID = 1; +// int64 SeqBegin = 2; +// int64 SeqEnd = 3; +// string OperationID = 4; +// } +// +// message PullMessageResp { +// int32 ErrCode = 1; +// string ErrMsg = 2; +// int64 MaxSeq = 3; +// int64 MinSeq = 4; +// repeated GatherFormat SingleUserMsg = 5; +// repeated GatherFormat GroupUserMsg = 6; +// } +// message PullMessageBySeqListReq{ +// string UserID = 1; +// string OperationID = 2; +// repeated int64 seqList =3; +// } +type GetMaxAndMinSeqReq struct { + UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetMaxAndMinSeqReq) Reset() { *m = GetMaxAndMinSeqReq{} } +func (m *GetMaxAndMinSeqReq) String() string { return proto.CompactTextString(m) } +func (*GetMaxAndMinSeqReq) ProtoMessage() {} +func (*GetMaxAndMinSeqReq) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{3} +} +func (m *GetMaxAndMinSeqReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetMaxAndMinSeqReq.Unmarshal(m, b) +} +func (m *GetMaxAndMinSeqReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetMaxAndMinSeqReq.Marshal(b, m, deterministic) +} +func (dst *GetMaxAndMinSeqReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetMaxAndMinSeqReq.Merge(dst, src) +} +func (m *GetMaxAndMinSeqReq) XXX_Size() int { + return xxx_messageInfo_GetMaxAndMinSeqReq.Size(m) +} +func (m *GetMaxAndMinSeqReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetMaxAndMinSeqReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetMaxAndMinSeqReq proto.InternalMessageInfo + +func (m *GetMaxAndMinSeqReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetMaxAndMinSeqReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetMaxAndMinSeqResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + MaxSeq uint32 `protobuf:"varint,3,opt,name=MaxSeq" json:"MaxSeq,omitempty"` + MinSeq uint32 `protobuf:"varint,4,opt,name=MinSeq" json:"MinSeq,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetMaxAndMinSeqResp) Reset() { *m = GetMaxAndMinSeqResp{} } +func (m *GetMaxAndMinSeqResp) String() string { return proto.CompactTextString(m) } +func (*GetMaxAndMinSeqResp) ProtoMessage() {} +func (*GetMaxAndMinSeqResp) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{4} +} +func (m *GetMaxAndMinSeqResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetMaxAndMinSeqResp.Unmarshal(m, b) +} +func (m *GetMaxAndMinSeqResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetMaxAndMinSeqResp.Marshal(b, m, deterministic) +} +func (dst *GetMaxAndMinSeqResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetMaxAndMinSeqResp.Merge(dst, src) +} +func (m *GetMaxAndMinSeqResp) XXX_Size() int { + return xxx_messageInfo_GetMaxAndMinSeqResp.Size(m) +} +func (m *GetMaxAndMinSeqResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetMaxAndMinSeqResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetMaxAndMinSeqResp proto.InternalMessageInfo + +func (m *GetMaxAndMinSeqResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetMaxAndMinSeqResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetMaxAndMinSeqResp) GetMaxSeq() uint32 { + if m != nil { + return m.MaxSeq + } + return 0 +} + +func (m *GetMaxAndMinSeqResp) GetMinSeq() uint32 { + if m != nil { + return m.MinSeq + } + return 0 +} + +type SendMsgReq struct { + Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + MsgData *sdk_ws.MsgData `protobuf:"bytes,3,opt,name=msgData" json:"msgData,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SendMsgReq) Reset() { *m = SendMsgReq{} } +func (m *SendMsgReq) String() string { return proto.CompactTextString(m) } +func (*SendMsgReq) ProtoMessage() {} +func (*SendMsgReq) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{5} +} +func (m *SendMsgReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SendMsgReq.Unmarshal(m, b) +} +func (m *SendMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SendMsgReq.Marshal(b, m, deterministic) +} +func (dst *SendMsgReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendMsgReq.Merge(dst, src) +} +func (m *SendMsgReq) XXX_Size() int { + return xxx_messageInfo_SendMsgReq.Size(m) +} +func (m *SendMsgReq) XXX_DiscardUnknown() { + xxx_messageInfo_SendMsgReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SendMsgReq proto.InternalMessageInfo + +func (m *SendMsgReq) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *SendMsgReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *SendMsgReq) GetMsgData() *sdk_ws.MsgData { + if m != nil { + return m.MsgData + } + return nil +} + +type SendMsgResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + ServerMsgID string `protobuf:"bytes,4,opt,name=serverMsgID" json:"serverMsgID,omitempty"` + ClientMsgID string `protobuf:"bytes,5,opt,name=clientMsgID" json:"clientMsgID,omitempty"` + SendTime int64 `protobuf:"varint,6,opt,name=sendTime" json:"sendTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SendMsgResp) Reset() { *m = SendMsgResp{} } +func (m *SendMsgResp) String() string { return proto.CompactTextString(m) } +func (*SendMsgResp) ProtoMessage() {} +func (*SendMsgResp) Descriptor() ([]byte, []int) { + return fileDescriptor_chat_83f286704599d5b1, []int{6} +} +func (m *SendMsgResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SendMsgResp.Unmarshal(m, b) +} +func (m *SendMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SendMsgResp.Marshal(b, m, deterministic) +} +func (dst *SendMsgResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendMsgResp.Merge(dst, src) +} +func (m *SendMsgResp) XXX_Size() int { + return xxx_messageInfo_SendMsgResp.Size(m) +} +func (m *SendMsgResp) XXX_DiscardUnknown() { + xxx_messageInfo_SendMsgResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SendMsgResp proto.InternalMessageInfo + +func (m *SendMsgResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *SendMsgResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *SendMsgResp) GetServerMsgID() string { + if m != nil { + return m.ServerMsgID + } + return "" +} + +func (m *SendMsgResp) GetClientMsgID() string { + if m != nil { + return m.ClientMsgID + } + return "" +} + +func (m *SendMsgResp) GetSendTime() int64 { + if m != nil { + return m.SendTime + } + return 0 +} + +func init() { + proto.RegisterType((*MsgDataToMQ)(nil), "pbChat.MsgDataToMQ") + proto.RegisterType((*MsgDataToDB)(nil), "pbChat.MsgDataToDB") + proto.RegisterType((*PushMsgDataToMQ)(nil), "pbChat.PushMsgDataToMQ") + proto.RegisterType((*GetMaxAndMinSeqReq)(nil), "pbChat.GetMaxAndMinSeqReq") + proto.RegisterType((*GetMaxAndMinSeqResp)(nil), "pbChat.GetMaxAndMinSeqResp") + proto.RegisterType((*SendMsgReq)(nil), "pbChat.SendMsgReq") + proto.RegisterType((*SendMsgResp)(nil), "pbChat.SendMsgResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Chat service + +type ChatClient interface { + GetMaxAndMinSeq(ctx context.Context, in *GetMaxAndMinSeqReq, opts ...grpc.CallOption) (*GetMaxAndMinSeqResp, error) + PullMessageBySeqList(ctx context.Context, in *sdk_ws.PullMessageBySeqListReq, opts ...grpc.CallOption) (*sdk_ws.PullMessageBySeqListResp, error) + SendMsg(ctx context.Context, in *SendMsgReq, opts ...grpc.CallOption) (*SendMsgResp, error) + DelMsgList(ctx context.Context, in *sdk_ws.DelMsgListReq, opts ...grpc.CallOption) (*sdk_ws.DelMsgListResp, error) +} + +type chatClient struct { + cc *grpc.ClientConn +} + +func NewChatClient(cc *grpc.ClientConn) ChatClient { + return &chatClient{cc} +} + +func (c *chatClient) GetMaxAndMinSeq(ctx context.Context, in *GetMaxAndMinSeqReq, opts ...grpc.CallOption) (*GetMaxAndMinSeqResp, error) { + out := new(GetMaxAndMinSeqResp) + err := grpc.Invoke(ctx, "/pbChat.Chat/GetMaxAndMinSeq", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) PullMessageBySeqList(ctx context.Context, in *sdk_ws.PullMessageBySeqListReq, opts ...grpc.CallOption) (*sdk_ws.PullMessageBySeqListResp, error) { + out := new(sdk_ws.PullMessageBySeqListResp) + err := grpc.Invoke(ctx, "/pbChat.Chat/PullMessageBySeqList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) SendMsg(ctx context.Context, in *SendMsgReq, opts ...grpc.CallOption) (*SendMsgResp, error) { + out := new(SendMsgResp) + err := grpc.Invoke(ctx, "/pbChat.Chat/SendMsg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) DelMsgList(ctx context.Context, in *sdk_ws.DelMsgListReq, opts ...grpc.CallOption) (*sdk_ws.DelMsgListResp, error) { + out := new(sdk_ws.DelMsgListResp) + err := grpc.Invoke(ctx, "/pbChat.Chat/DelMsgList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Chat service + +type ChatServer interface { + GetMaxAndMinSeq(context.Context, *GetMaxAndMinSeqReq) (*GetMaxAndMinSeqResp, error) + PullMessageBySeqList(context.Context, *sdk_ws.PullMessageBySeqListReq) (*sdk_ws.PullMessageBySeqListResp, error) + SendMsg(context.Context, *SendMsgReq) (*SendMsgResp, error) + DelMsgList(context.Context, *sdk_ws.DelMsgListReq) (*sdk_ws.DelMsgListResp, error) +} + +func RegisterChatServer(s *grpc.Server, srv ChatServer) { + s.RegisterService(&_Chat_serviceDesc, srv) +} + +func _Chat_GetMaxAndMinSeq_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetMaxAndMinSeqReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetMaxAndMinSeq(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pbChat.Chat/GetMaxAndMinSeq", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetMaxAndMinSeq(ctx, req.(*GetMaxAndMinSeqReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_PullMessageBySeqList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(sdk_ws.PullMessageBySeqListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).PullMessageBySeqList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pbChat.Chat/PullMessageBySeqList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).PullMessageBySeqList(ctx, req.(*sdk_ws.PullMessageBySeqListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_SendMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendMsgReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SendMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pbChat.Chat/SendMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SendMsg(ctx, req.(*SendMsgReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_DelMsgList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(sdk_ws.DelMsgListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).DelMsgList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pbChat.Chat/DelMsgList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).DelMsgList(ctx, req.(*sdk_ws.DelMsgListReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _Chat_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pbChat.Chat", + HandlerType: (*ChatServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetMaxAndMinSeq", + Handler: _Chat_GetMaxAndMinSeq_Handler, + }, + { + MethodName: "PullMessageBySeqList", + Handler: _Chat_PullMessageBySeqList_Handler, + }, + { + MethodName: "SendMsg", + Handler: _Chat_SendMsg_Handler, + }, + { + MethodName: "DelMsgList", + Handler: _Chat_DelMsgList_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "chat/chat.proto", +} + +func init() { proto.RegisterFile("chat/chat.proto", fileDescriptor_chat_83f286704599d5b1) } + +var fileDescriptor_chat_83f286704599d5b1 = []byte{ + // 507 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0xcd, 0x6e, 0xda, 0x40, + 0x10, 0x96, 0x49, 0x80, 0x32, 0x34, 0x42, 0xda, 0x44, 0x95, 0xe5, 0x5e, 0x1c, 0x9f, 0x50, 0x2b, + 0x19, 0x89, 0xf6, 0xd6, 0x53, 0x89, 0xa3, 0x8a, 0xaa, 0xdb, 0x24, 0x86, 0x5e, 0x7a, 0x41, 0x9b, + 0x30, 0x32, 0x16, 0x60, 0x2f, 0x3b, 0xa6, 0xa4, 0xed, 0x33, 0xf4, 0x19, 0xfa, 0x3e, 0x7d, 0xaa, + 0xca, 0xbb, 0x26, 0x98, 0x40, 0x15, 0x4e, 0xbd, 0x58, 0x9a, 0x6f, 0x3e, 0x7f, 0x3f, 0xeb, 0x1f, + 0x68, 0xdd, 0x4d, 0x44, 0xd6, 0xc9, 0x2f, 0xbe, 0x54, 0x69, 0x96, 0xb2, 0x9a, 0xbc, 0xbd, 0x98, + 0x88, 0xcc, 0x39, 0xbf, 0x92, 0x98, 0x8c, 0xfa, 0xbc, 0x23, 0xa7, 0x51, 0x47, 0xaf, 0x3a, 0x34, + 0x9e, 0x8e, 0x56, 0xd4, 0x59, 0x91, 0xa1, 0x7a, 0x3f, 0xa1, 0xc9, 0x29, 0x0a, 0x44, 0x26, 0x86, + 0x29, 0xbf, 0x61, 0x67, 0x50, 0xcd, 0xd2, 0x29, 0x26, 0xb6, 0xe5, 0x5a, 0xed, 0x46, 0x68, 0x06, + 0xe6, 0x42, 0x33, 0x95, 0xa8, 0x44, 0x16, 0xa7, 0x49, 0x3f, 0xb0, 0x2b, 0x7a, 0x57, 0x86, 0xd8, + 0x5b, 0xa8, 0xcf, 0x8d, 0x8c, 0x7d, 0xe4, 0x5a, 0xed, 0x66, 0xd7, 0xf1, 0x09, 0xd5, 0x37, 0x54, + 0x23, 0x21, 0xe3, 0x91, 0x14, 0x4a, 0xcc, 0xc9, 0x2f, 0x8c, 0xc2, 0x35, 0xd5, 0xc3, 0x92, 0x79, + 0xd0, 0x2b, 0x8b, 0x58, 0x07, 0x8b, 0x3c, 0x1d, 0xce, 0xfb, 0x65, 0x41, 0xeb, 0x7a, 0x49, 0x93, + 0x72, 0x51, 0x17, 0x9a, 0x57, 0xa5, 0xbb, 0x4c, 0xdd, 0x32, 0x54, 0x4e, 0x53, 0x39, 0x3c, 0x8d, + 0x07, 0xcf, 0xe5, 0x92, 0x26, 0xc3, 0xf4, 0x0b, 0xa1, 0xea, 0x07, 0xfa, 0x34, 0x1a, 0xe1, 0x16, + 0xe6, 0x7d, 0x06, 0xf6, 0x01, 0x33, 0x2e, 0xee, 0xdf, 0x27, 0x63, 0x1e, 0x27, 0x03, 0x5c, 0x84, + 0xb8, 0x60, 0x2f, 0xa0, 0x56, 0xdc, 0x63, 0xc2, 0x14, 0xd3, 0xe3, 0xa4, 0x95, 0x9d, 0xa4, 0xde, + 0x0a, 0x4e, 0x77, 0xf4, 0x48, 0x32, 0x1b, 0xea, 0x97, 0x4a, 0x5d, 0xa4, 0x63, 0xd4, 0x8a, 0xd5, + 0x70, 0x3d, 0xe6, 0x56, 0x97, 0x4a, 0x71, 0x8a, 0x0a, 0xb5, 0x62, 0xca, 0x71, 0x2e, 0xee, 0x07, + 0xb8, 0xd0, 0xb1, 0x4f, 0xc2, 0x62, 0xd2, 0xb8, 0xd6, 0xb5, 0x8f, 0x0b, 0x5c, 0x4f, 0xde, 0x0f, + 0x80, 0x01, 0x26, 0x63, 0x4e, 0x51, 0x5e, 0xe0, 0xff, 0xbe, 0x3b, 0xbf, 0x2d, 0x68, 0x3e, 0x98, + 0x9b, 0xb6, 0xb8, 0xdd, 0x16, 0x37, 0x6d, 0x71, 0xab, 0xad, 0x99, 0xf2, 0x64, 0xc6, 0x87, 0x53, + 0xd4, 0x0f, 0x74, 0xb5, 0x46, 0x58, 0x86, 0x72, 0xc6, 0xdd, 0x2c, 0xc6, 0x24, 0x33, 0x8c, 0xaa, + 0x61, 0x94, 0x20, 0xe6, 0xc0, 0x33, 0xc2, 0x64, 0x3c, 0x8c, 0xe7, 0x68, 0xd7, 0x5c, 0xab, 0x7d, + 0x14, 0x3e, 0xcc, 0xdd, 0x3f, 0x15, 0x38, 0xce, 0x3f, 0x43, 0xf6, 0x11, 0x5a, 0x8f, 0x9e, 0x0f, + 0x73, 0x7c, 0xf3, 0x89, 0xfa, 0xbb, 0x2f, 0x82, 0xf3, 0xf2, 0x9f, 0x3b, 0x92, 0x2c, 0x85, 0xb3, + 0xeb, 0xe5, 0x6c, 0xc6, 0x91, 0x48, 0x44, 0xd8, 0xfb, 0x3e, 0xc0, 0xc5, 0xa7, 0x98, 0x32, 0xf6, + 0x6a, 0xcf, 0x99, 0xed, 0x23, 0xe6, 0x06, 0xaf, 0x0f, 0xe6, 0x92, 0x64, 0x5d, 0xa8, 0x17, 0xc7, + 0xcc, 0xd8, 0x3a, 0xd8, 0xe6, 0xa1, 0x3b, 0xa7, 0x3b, 0x18, 0x49, 0x76, 0x03, 0x10, 0xe0, 0x8c, + 0x53, 0xa4, 0xa3, 0xb9, 0x7b, 0xec, 0x36, 0xeb, 0x5c, 0xe4, 0xfc, 0x09, 0x06, 0xc9, 0x5e, 0xeb, + 0xeb, 0x89, 0xaf, 0x7f, 0x71, 0xef, 0x8c, 0xdf, 0x6d, 0x4d, 0xff, 0xbf, 0xde, 0xfc, 0x0d, 0x00, + 0x00, 0xff, 0xff, 0x6f, 0x9d, 0x6f, 0xa0, 0xfd, 0x04, 0x00, 0x00, +} diff --git a/pkg/proto/chat/chat.proto b/pkg/proto/chat/chat.proto new file mode 100644 index 000000000..146994f01 --- /dev/null +++ b/pkg/proto/chat/chat.proto @@ -0,0 +1,82 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./chat;pbChat"; +package pbChat; + + + +message MsgDataToMQ{ + string token =1; + string operationID = 2; + server_api_params.MsgData msgData = 3; +} + + +message MsgDataToDB { + server_api_params.MsgData msgData = 1; + string operationID = 2; + +} +message PushMsgDataToMQ{ + string OperationID = 1; + server_api_params.MsgData msgData = 2; + string pushToUserID = 3; +} + +//message PullMessageReq { +// string UserID = 1; +// int64 SeqBegin = 2; +// int64 SeqEnd = 3; +// string OperationID = 4; +//} +// +//message PullMessageResp { +// int32 ErrCode = 1; +// string ErrMsg = 2; +// int64 MaxSeq = 3; +// int64 MinSeq = 4; +// repeated GatherFormat SingleUserMsg = 5; +// repeated GatherFormat GroupUserMsg = 6; +//} +//message PullMessageBySeqListReq{ +// string UserID = 1; +// string OperationID = 2; +// repeated int64 seqList =3; +//} +message GetMaxAndMinSeqReq { + string UserID = 1; + string OperationID = 2; +} +message GetMaxAndMinSeqResp { + int32 ErrCode = 1; + string ErrMsg = 2; + uint32 MaxSeq = 3; + uint32 MinSeq = 4; +} + +message SendMsgReq { + +string token =1; +string operationID = 2; +server_api_params.MsgData msgData = 3; + + +} + +message SendMsgResp { + int32 errCode = 1; + string errMsg = 2; + string serverMsgID = 4; + string clientMsgID = 5; + int64 sendTime = 6; + +} + + + +service Chat { + rpc GetMaxAndMinSeq(GetMaxAndMinSeqReq) returns(GetMaxAndMinSeqResp); + rpc PullMessageBySeqList(server_api_params.PullMessageBySeqListReq) returns(server_api_params.PullMessageBySeqListResp); + rpc SendMsg(SendMsgReq) returns(SendMsgResp); + rpc DelMsgList(server_api_params.DelMsgListReq) returns(server_api_params.DelMsgListResp); +} diff --git a/pkg/proto/friend/friend.pb.go b/pkg/proto/friend/friend.pb.go new file mode 100644 index 000000000..88e92e2f5 --- /dev/null +++ b/pkg/proto/friend/friend.pb.go @@ -0,0 +1,1990 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: friend/friend.proto + +package friend // import "./friend" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CommonResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommonResp) Reset() { *m = CommonResp{} } +func (m *CommonResp) String() string { return proto.CompactTextString(m) } +func (*CommonResp) ProtoMessage() {} +func (*CommonResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{0} +} +func (m *CommonResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommonResp.Unmarshal(m, b) +} +func (m *CommonResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommonResp.Marshal(b, m, deterministic) +} +func (dst *CommonResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommonResp.Merge(dst, src) +} +func (m *CommonResp) XXX_Size() int { + return xxx_messageInfo_CommonResp.Size(m) +} +func (m *CommonResp) XXX_DiscardUnknown() { + xxx_messageInfo_CommonResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CommonResp proto.InternalMessageInfo + +func (m *CommonResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CommonResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type CommID struct { + OpUserID string `protobuf:"bytes,1,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + ToUserID string `protobuf:"bytes,4,opt,name=ToUserID" json:"ToUserID,omitempty"` + FromUserID string `protobuf:"bytes,5,opt,name=FromUserID" json:"FromUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommID) Reset() { *m = CommID{} } +func (m *CommID) String() string { return proto.CompactTextString(m) } +func (*CommID) ProtoMessage() {} +func (*CommID) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{1} +} +func (m *CommID) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommID.Unmarshal(m, b) +} +func (m *CommID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommID.Marshal(b, m, deterministic) +} +func (dst *CommID) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommID.Merge(dst, src) +} +func (m *CommID) XXX_Size() int { + return xxx_messageInfo_CommID.Size(m) +} +func (m *CommID) XXX_DiscardUnknown() { + xxx_messageInfo_CommID.DiscardUnknown(m) +} + +var xxx_messageInfo_CommID proto.InternalMessageInfo + +func (m *CommID) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *CommID) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CommID) GetToUserID() string { + if m != nil { + return m.ToUserID + } + return "" +} + +func (m *CommID) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +type GetFriendsInfoReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFriendsInfoReq) Reset() { *m = GetFriendsInfoReq{} } +func (m *GetFriendsInfoReq) String() string { return proto.CompactTextString(m) } +func (*GetFriendsInfoReq) ProtoMessage() {} +func (*GetFriendsInfoReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{2} +} +func (m *GetFriendsInfoReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFriendsInfoReq.Unmarshal(m, b) +} +func (m *GetFriendsInfoReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFriendsInfoReq.Marshal(b, m, deterministic) +} +func (dst *GetFriendsInfoReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFriendsInfoReq.Merge(dst, src) +} +func (m *GetFriendsInfoReq) XXX_Size() int { + return xxx_messageInfo_GetFriendsInfoReq.Size(m) +} +func (m *GetFriendsInfoReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetFriendsInfoReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFriendsInfoReq proto.InternalMessageInfo + +func (m *GetFriendsInfoReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type GetFriendInfoResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + FriendInfoList []*sdk_ws.FriendInfo `protobuf:"bytes,3,rep,name=FriendInfoList" json:"FriendInfoList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFriendInfoResp) Reset() { *m = GetFriendInfoResp{} } +func (m *GetFriendInfoResp) String() string { return proto.CompactTextString(m) } +func (*GetFriendInfoResp) ProtoMessage() {} +func (*GetFriendInfoResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{3} +} +func (m *GetFriendInfoResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFriendInfoResp.Unmarshal(m, b) +} +func (m *GetFriendInfoResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFriendInfoResp.Marshal(b, m, deterministic) +} +func (dst *GetFriendInfoResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFriendInfoResp.Merge(dst, src) +} +func (m *GetFriendInfoResp) XXX_Size() int { + return xxx_messageInfo_GetFriendInfoResp.Size(m) +} +func (m *GetFriendInfoResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetFriendInfoResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFriendInfoResp proto.InternalMessageInfo + +func (m *GetFriendInfoResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetFriendInfoResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetFriendInfoResp) GetFriendInfoList() []*sdk_ws.FriendInfo { + if m != nil { + return m.FriendInfoList + } + return nil +} + +type AddFriendReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + ReqMsg string `protobuf:"bytes,2,opt,name=ReqMsg" json:"ReqMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddFriendReq) Reset() { *m = AddFriendReq{} } +func (m *AddFriendReq) String() string { return proto.CompactTextString(m) } +func (*AddFriendReq) ProtoMessage() {} +func (*AddFriendReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{4} +} +func (m *AddFriendReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddFriendReq.Unmarshal(m, b) +} +func (m *AddFriendReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddFriendReq.Marshal(b, m, deterministic) +} +func (dst *AddFriendReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddFriendReq.Merge(dst, src) +} +func (m *AddFriendReq) XXX_Size() int { + return xxx_messageInfo_AddFriendReq.Size(m) +} +func (m *AddFriendReq) XXX_DiscardUnknown() { + xxx_messageInfo_AddFriendReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AddFriendReq proto.InternalMessageInfo + +func (m *AddFriendReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +func (m *AddFriendReq) GetReqMsg() string { + if m != nil { + return m.ReqMsg + } + return "" +} + +type AddFriendResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddFriendResp) Reset() { *m = AddFriendResp{} } +func (m *AddFriendResp) String() string { return proto.CompactTextString(m) } +func (*AddFriendResp) ProtoMessage() {} +func (*AddFriendResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{5} +} +func (m *AddFriendResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddFriendResp.Unmarshal(m, b) +} +func (m *AddFriendResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddFriendResp.Marshal(b, m, deterministic) +} +func (dst *AddFriendResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddFriendResp.Merge(dst, src) +} +func (m *AddFriendResp) XXX_Size() int { + return xxx_messageInfo_AddFriendResp.Size(m) +} +func (m *AddFriendResp) XXX_DiscardUnknown() { + xxx_messageInfo_AddFriendResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AddFriendResp proto.InternalMessageInfo + +func (m *AddFriendResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type ImportFriendReq struct { + FriendUserIDList []string `protobuf:"bytes,1,rep,name=FriendUserIDList" json:"FriendUserIDList,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + FromUserID string `protobuf:"bytes,3,opt,name=FromUserID" json:"FromUserID,omitempty"` + OpUserID string `protobuf:"bytes,4,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ImportFriendReq) Reset() { *m = ImportFriendReq{} } +func (m *ImportFriendReq) String() string { return proto.CompactTextString(m) } +func (*ImportFriendReq) ProtoMessage() {} +func (*ImportFriendReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{6} +} +func (m *ImportFriendReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ImportFriendReq.Unmarshal(m, b) +} +func (m *ImportFriendReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ImportFriendReq.Marshal(b, m, deterministic) +} +func (dst *ImportFriendReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImportFriendReq.Merge(dst, src) +} +func (m *ImportFriendReq) XXX_Size() int { + return xxx_messageInfo_ImportFriendReq.Size(m) +} +func (m *ImportFriendReq) XXX_DiscardUnknown() { + xxx_messageInfo_ImportFriendReq.DiscardUnknown(m) +} + +var xxx_messageInfo_ImportFriendReq proto.InternalMessageInfo + +func (m *ImportFriendReq) GetFriendUserIDList() []string { + if m != nil { + return m.FriendUserIDList + } + return nil +} + +func (m *ImportFriendReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *ImportFriendReq) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +func (m *ImportFriendReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type UserIDResult struct { + UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` + Result int32 `protobuf:"varint,2,opt,name=Result" json:"Result,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserIDResult) Reset() { *m = UserIDResult{} } +func (m *UserIDResult) String() string { return proto.CompactTextString(m) } +func (*UserIDResult) ProtoMessage() {} +func (*UserIDResult) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{7} +} +func (m *UserIDResult) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserIDResult.Unmarshal(m, b) +} +func (m *UserIDResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserIDResult.Marshal(b, m, deterministic) +} +func (dst *UserIDResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserIDResult.Merge(dst, src) +} +func (m *UserIDResult) XXX_Size() int { + return xxx_messageInfo_UserIDResult.Size(m) +} +func (m *UserIDResult) XXX_DiscardUnknown() { + xxx_messageInfo_UserIDResult.DiscardUnknown(m) +} + +var xxx_messageInfo_UserIDResult proto.InternalMessageInfo + +func (m *UserIDResult) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *UserIDResult) GetResult() int32 { + if m != nil { + return m.Result + } + return 0 +} + +type ImportFriendResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + UserIDResultList []*UserIDResult `protobuf:"bytes,2,rep,name=UserIDResultList" json:"UserIDResultList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ImportFriendResp) Reset() { *m = ImportFriendResp{} } +func (m *ImportFriendResp) String() string { return proto.CompactTextString(m) } +func (*ImportFriendResp) ProtoMessage() {} +func (*ImportFriendResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{8} +} +func (m *ImportFriendResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ImportFriendResp.Unmarshal(m, b) +} +func (m *ImportFriendResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ImportFriendResp.Marshal(b, m, deterministic) +} +func (dst *ImportFriendResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImportFriendResp.Merge(dst, src) +} +func (m *ImportFriendResp) XXX_Size() int { + return xxx_messageInfo_ImportFriendResp.Size(m) +} +func (m *ImportFriendResp) XXX_DiscardUnknown() { + xxx_messageInfo_ImportFriendResp.DiscardUnknown(m) +} + +var xxx_messageInfo_ImportFriendResp proto.InternalMessageInfo + +func (m *ImportFriendResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *ImportFriendResp) GetUserIDResultList() []*UserIDResult { + if m != nil { + return m.UserIDResultList + } + return nil +} + +type GetFriendApplyListReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFriendApplyListReq) Reset() { *m = GetFriendApplyListReq{} } +func (m *GetFriendApplyListReq) String() string { return proto.CompactTextString(m) } +func (*GetFriendApplyListReq) ProtoMessage() {} +func (*GetFriendApplyListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{9} +} +func (m *GetFriendApplyListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFriendApplyListReq.Unmarshal(m, b) +} +func (m *GetFriendApplyListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFriendApplyListReq.Marshal(b, m, deterministic) +} +func (dst *GetFriendApplyListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFriendApplyListReq.Merge(dst, src) +} +func (m *GetFriendApplyListReq) XXX_Size() int { + return xxx_messageInfo_GetFriendApplyListReq.Size(m) +} +func (m *GetFriendApplyListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetFriendApplyListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFriendApplyListReq proto.InternalMessageInfo + +func (m *GetFriendApplyListReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type GetFriendApplyListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + FriendRequestList []*sdk_ws.FriendRequest `protobuf:"bytes,3,rep,name=FriendRequestList" json:"FriendRequestList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFriendApplyListResp) Reset() { *m = GetFriendApplyListResp{} } +func (m *GetFriendApplyListResp) String() string { return proto.CompactTextString(m) } +func (*GetFriendApplyListResp) ProtoMessage() {} +func (*GetFriendApplyListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{10} +} +func (m *GetFriendApplyListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFriendApplyListResp.Unmarshal(m, b) +} +func (m *GetFriendApplyListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFriendApplyListResp.Marshal(b, m, deterministic) +} +func (dst *GetFriendApplyListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFriendApplyListResp.Merge(dst, src) +} +func (m *GetFriendApplyListResp) XXX_Size() int { + return xxx_messageInfo_GetFriendApplyListResp.Size(m) +} +func (m *GetFriendApplyListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetFriendApplyListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFriendApplyListResp proto.InternalMessageInfo + +func (m *GetFriendApplyListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetFriendApplyListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetFriendApplyListResp) GetFriendRequestList() []*sdk_ws.FriendRequest { + if m != nil { + return m.FriendRequestList + } + return nil +} + +type GetFriendListReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFriendListReq) Reset() { *m = GetFriendListReq{} } +func (m *GetFriendListReq) String() string { return proto.CompactTextString(m) } +func (*GetFriendListReq) ProtoMessage() {} +func (*GetFriendListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{11} +} +func (m *GetFriendListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFriendListReq.Unmarshal(m, b) +} +func (m *GetFriendListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFriendListReq.Marshal(b, m, deterministic) +} +func (dst *GetFriendListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFriendListReq.Merge(dst, src) +} +func (m *GetFriendListReq) XXX_Size() int { + return xxx_messageInfo_GetFriendListReq.Size(m) +} +func (m *GetFriendListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetFriendListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFriendListReq proto.InternalMessageInfo + +func (m *GetFriendListReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type GetFriendListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + FriendInfoList []*sdk_ws.FriendInfo `protobuf:"bytes,3,rep,name=FriendInfoList" json:"FriendInfoList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetFriendListResp) Reset() { *m = GetFriendListResp{} } +func (m *GetFriendListResp) String() string { return proto.CompactTextString(m) } +func (*GetFriendListResp) ProtoMessage() {} +func (*GetFriendListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{12} +} +func (m *GetFriendListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetFriendListResp.Unmarshal(m, b) +} +func (m *GetFriendListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetFriendListResp.Marshal(b, m, deterministic) +} +func (dst *GetFriendListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetFriendListResp.Merge(dst, src) +} +func (m *GetFriendListResp) XXX_Size() int { + return xxx_messageInfo_GetFriendListResp.Size(m) +} +func (m *GetFriendListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetFriendListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetFriendListResp proto.InternalMessageInfo + +func (m *GetFriendListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetFriendListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetFriendListResp) GetFriendInfoList() []*sdk_ws.FriendInfo { + if m != nil { + return m.FriendInfoList + } + return nil +} + +type AddBlacklistReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddBlacklistReq) Reset() { *m = AddBlacklistReq{} } +func (m *AddBlacklistReq) String() string { return proto.CompactTextString(m) } +func (*AddBlacklistReq) ProtoMessage() {} +func (*AddBlacklistReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{13} +} +func (m *AddBlacklistReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddBlacklistReq.Unmarshal(m, b) +} +func (m *AddBlacklistReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddBlacklistReq.Marshal(b, m, deterministic) +} +func (dst *AddBlacklistReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddBlacklistReq.Merge(dst, src) +} +func (m *AddBlacklistReq) XXX_Size() int { + return xxx_messageInfo_AddBlacklistReq.Size(m) +} +func (m *AddBlacklistReq) XXX_DiscardUnknown() { + xxx_messageInfo_AddBlacklistReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AddBlacklistReq proto.InternalMessageInfo + +func (m *AddBlacklistReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type AddBlacklistResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddBlacklistResp) Reset() { *m = AddBlacklistResp{} } +func (m *AddBlacklistResp) String() string { return proto.CompactTextString(m) } +func (*AddBlacklistResp) ProtoMessage() {} +func (*AddBlacklistResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{14} +} +func (m *AddBlacklistResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddBlacklistResp.Unmarshal(m, b) +} +func (m *AddBlacklistResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddBlacklistResp.Marshal(b, m, deterministic) +} +func (dst *AddBlacklistResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddBlacklistResp.Merge(dst, src) +} +func (m *AddBlacklistResp) XXX_Size() int { + return xxx_messageInfo_AddBlacklistResp.Size(m) +} +func (m *AddBlacklistResp) XXX_DiscardUnknown() { + xxx_messageInfo_AddBlacklistResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AddBlacklistResp proto.InternalMessageInfo + +func (m *AddBlacklistResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type RemoveBlacklistReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveBlacklistReq) Reset() { *m = RemoveBlacklistReq{} } +func (m *RemoveBlacklistReq) String() string { return proto.CompactTextString(m) } +func (*RemoveBlacklistReq) ProtoMessage() {} +func (*RemoveBlacklistReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{15} +} +func (m *RemoveBlacklistReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveBlacklistReq.Unmarshal(m, b) +} +func (m *RemoveBlacklistReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveBlacklistReq.Marshal(b, m, deterministic) +} +func (dst *RemoveBlacklistReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveBlacklistReq.Merge(dst, src) +} +func (m *RemoveBlacklistReq) XXX_Size() int { + return xxx_messageInfo_RemoveBlacklistReq.Size(m) +} +func (m *RemoveBlacklistReq) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveBlacklistReq.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveBlacklistReq proto.InternalMessageInfo + +func (m *RemoveBlacklistReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type RemoveBlacklistResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveBlacklistResp) Reset() { *m = RemoveBlacklistResp{} } +func (m *RemoveBlacklistResp) String() string { return proto.CompactTextString(m) } +func (*RemoveBlacklistResp) ProtoMessage() {} +func (*RemoveBlacklistResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{16} +} +func (m *RemoveBlacklistResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveBlacklistResp.Unmarshal(m, b) +} +func (m *RemoveBlacklistResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveBlacklistResp.Marshal(b, m, deterministic) +} +func (dst *RemoveBlacklistResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveBlacklistResp.Merge(dst, src) +} +func (m *RemoveBlacklistResp) XXX_Size() int { + return xxx_messageInfo_RemoveBlacklistResp.Size(m) +} +func (m *RemoveBlacklistResp) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveBlacklistResp.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveBlacklistResp proto.InternalMessageInfo + +func (m *RemoveBlacklistResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetBlacklistReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetBlacklistReq) Reset() { *m = GetBlacklistReq{} } +func (m *GetBlacklistReq) String() string { return proto.CompactTextString(m) } +func (*GetBlacklistReq) ProtoMessage() {} +func (*GetBlacklistReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{17} +} +func (m *GetBlacklistReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetBlacklistReq.Unmarshal(m, b) +} +func (m *GetBlacklistReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetBlacklistReq.Marshal(b, m, deterministic) +} +func (dst *GetBlacklistReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetBlacklistReq.Merge(dst, src) +} +func (m *GetBlacklistReq) XXX_Size() int { + return xxx_messageInfo_GetBlacklistReq.Size(m) +} +func (m *GetBlacklistReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetBlacklistReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetBlacklistReq proto.InternalMessageInfo + +func (m *GetBlacklistReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type GetBlacklistResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + BlackUserInfoList []*sdk_ws.PublicUserInfo `protobuf:"bytes,3,rep,name=BlackUserInfoList" json:"BlackUserInfoList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetBlacklistResp) Reset() { *m = GetBlacklistResp{} } +func (m *GetBlacklistResp) String() string { return proto.CompactTextString(m) } +func (*GetBlacklistResp) ProtoMessage() {} +func (*GetBlacklistResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{18} +} +func (m *GetBlacklistResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetBlacklistResp.Unmarshal(m, b) +} +func (m *GetBlacklistResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetBlacklistResp.Marshal(b, m, deterministic) +} +func (dst *GetBlacklistResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetBlacklistResp.Merge(dst, src) +} +func (m *GetBlacklistResp) XXX_Size() int { + return xxx_messageInfo_GetBlacklistResp.Size(m) +} +func (m *GetBlacklistResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetBlacklistResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetBlacklistResp proto.InternalMessageInfo + +func (m *GetBlacklistResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetBlacklistResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetBlacklistResp) GetBlackUserInfoList() []*sdk_ws.PublicUserInfo { + if m != nil { + return m.BlackUserInfoList + } + return nil +} + +type IsFriendReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IsFriendReq) Reset() { *m = IsFriendReq{} } +func (m *IsFriendReq) String() string { return proto.CompactTextString(m) } +func (*IsFriendReq) ProtoMessage() {} +func (*IsFriendReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{19} +} +func (m *IsFriendReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IsFriendReq.Unmarshal(m, b) +} +func (m *IsFriendReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IsFriendReq.Marshal(b, m, deterministic) +} +func (dst *IsFriendReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_IsFriendReq.Merge(dst, src) +} +func (m *IsFriendReq) XXX_Size() int { + return xxx_messageInfo_IsFriendReq.Size(m) +} +func (m *IsFriendReq) XXX_DiscardUnknown() { + xxx_messageInfo_IsFriendReq.DiscardUnknown(m) +} + +var xxx_messageInfo_IsFriendReq proto.InternalMessageInfo + +func (m *IsFriendReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type IsFriendResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + Response bool `protobuf:"varint,3,opt,name=Response" json:"Response,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IsFriendResp) Reset() { *m = IsFriendResp{} } +func (m *IsFriendResp) String() string { return proto.CompactTextString(m) } +func (*IsFriendResp) ProtoMessage() {} +func (*IsFriendResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{20} +} +func (m *IsFriendResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IsFriendResp.Unmarshal(m, b) +} +func (m *IsFriendResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IsFriendResp.Marshal(b, m, deterministic) +} +func (dst *IsFriendResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_IsFriendResp.Merge(dst, src) +} +func (m *IsFriendResp) XXX_Size() int { + return xxx_messageInfo_IsFriendResp.Size(m) +} +func (m *IsFriendResp) XXX_DiscardUnknown() { + xxx_messageInfo_IsFriendResp.DiscardUnknown(m) +} + +var xxx_messageInfo_IsFriendResp proto.InternalMessageInfo + +func (m *IsFriendResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *IsFriendResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *IsFriendResp) GetResponse() bool { + if m != nil { + return m.Response + } + return false +} + +type IsInBlackListReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IsInBlackListReq) Reset() { *m = IsInBlackListReq{} } +func (m *IsInBlackListReq) String() string { return proto.CompactTextString(m) } +func (*IsInBlackListReq) ProtoMessage() {} +func (*IsInBlackListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{21} +} +func (m *IsInBlackListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IsInBlackListReq.Unmarshal(m, b) +} +func (m *IsInBlackListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IsInBlackListReq.Marshal(b, m, deterministic) +} +func (dst *IsInBlackListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_IsInBlackListReq.Merge(dst, src) +} +func (m *IsInBlackListReq) XXX_Size() int { + return xxx_messageInfo_IsInBlackListReq.Size(m) +} +func (m *IsInBlackListReq) XXX_DiscardUnknown() { + xxx_messageInfo_IsInBlackListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_IsInBlackListReq proto.InternalMessageInfo + +func (m *IsInBlackListReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type IsInBlackListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + Response bool `protobuf:"varint,3,opt,name=Response" json:"Response,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IsInBlackListResp) Reset() { *m = IsInBlackListResp{} } +func (m *IsInBlackListResp) String() string { return proto.CompactTextString(m) } +func (*IsInBlackListResp) ProtoMessage() {} +func (*IsInBlackListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{22} +} +func (m *IsInBlackListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IsInBlackListResp.Unmarshal(m, b) +} +func (m *IsInBlackListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IsInBlackListResp.Marshal(b, m, deterministic) +} +func (dst *IsInBlackListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_IsInBlackListResp.Merge(dst, src) +} +func (m *IsInBlackListResp) XXX_Size() int { + return xxx_messageInfo_IsInBlackListResp.Size(m) +} +func (m *IsInBlackListResp) XXX_DiscardUnknown() { + xxx_messageInfo_IsInBlackListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_IsInBlackListResp proto.InternalMessageInfo + +func (m *IsInBlackListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *IsInBlackListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *IsInBlackListResp) GetResponse() bool { + if m != nil { + return m.Response + } + return false +} + +type DeleteFriendReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteFriendReq) Reset() { *m = DeleteFriendReq{} } +func (m *DeleteFriendReq) String() string { return proto.CompactTextString(m) } +func (*DeleteFriendReq) ProtoMessage() {} +func (*DeleteFriendReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{23} +} +func (m *DeleteFriendReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteFriendReq.Unmarshal(m, b) +} +func (m *DeleteFriendReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteFriendReq.Marshal(b, m, deterministic) +} +func (dst *DeleteFriendReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteFriendReq.Merge(dst, src) +} +func (m *DeleteFriendReq) XXX_Size() int { + return xxx_messageInfo_DeleteFriendReq.Size(m) +} +func (m *DeleteFriendReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteFriendReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteFriendReq proto.InternalMessageInfo + +func (m *DeleteFriendReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type DeleteFriendResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteFriendResp) Reset() { *m = DeleteFriendResp{} } +func (m *DeleteFriendResp) String() string { return proto.CompactTextString(m) } +func (*DeleteFriendResp) ProtoMessage() {} +func (*DeleteFriendResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{24} +} +func (m *DeleteFriendResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteFriendResp.Unmarshal(m, b) +} +func (m *DeleteFriendResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteFriendResp.Marshal(b, m, deterministic) +} +func (dst *DeleteFriendResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteFriendResp.Merge(dst, src) +} +func (m *DeleteFriendResp) XXX_Size() int { + return xxx_messageInfo_DeleteFriendResp.Size(m) +} +func (m *DeleteFriendResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteFriendResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteFriendResp proto.InternalMessageInfo + +func (m *DeleteFriendResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +// process +type AddFriendResponseReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + HandleResult int32 `protobuf:"varint,2,opt,name=handleResult" json:"handleResult,omitempty"` + HandleMsg string `protobuf:"bytes,3,opt,name=handleMsg" json:"handleMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddFriendResponseReq) Reset() { *m = AddFriendResponseReq{} } +func (m *AddFriendResponseReq) String() string { return proto.CompactTextString(m) } +func (*AddFriendResponseReq) ProtoMessage() {} +func (*AddFriendResponseReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{25} +} +func (m *AddFriendResponseReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddFriendResponseReq.Unmarshal(m, b) +} +func (m *AddFriendResponseReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddFriendResponseReq.Marshal(b, m, deterministic) +} +func (dst *AddFriendResponseReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddFriendResponseReq.Merge(dst, src) +} +func (m *AddFriendResponseReq) XXX_Size() int { + return xxx_messageInfo_AddFriendResponseReq.Size(m) +} +func (m *AddFriendResponseReq) XXX_DiscardUnknown() { + xxx_messageInfo_AddFriendResponseReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AddFriendResponseReq proto.InternalMessageInfo + +func (m *AddFriendResponseReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +func (m *AddFriendResponseReq) GetHandleResult() int32 { + if m != nil { + return m.HandleResult + } + return 0 +} + +func (m *AddFriendResponseReq) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +type AddFriendResponseResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddFriendResponseResp) Reset() { *m = AddFriendResponseResp{} } +func (m *AddFriendResponseResp) String() string { return proto.CompactTextString(m) } +func (*AddFriendResponseResp) ProtoMessage() {} +func (*AddFriendResponseResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{26} +} +func (m *AddFriendResponseResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddFriendResponseResp.Unmarshal(m, b) +} +func (m *AddFriendResponseResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddFriendResponseResp.Marshal(b, m, deterministic) +} +func (dst *AddFriendResponseResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddFriendResponseResp.Merge(dst, src) +} +func (m *AddFriendResponseResp) XXX_Size() int { + return xxx_messageInfo_AddFriendResponseResp.Size(m) +} +func (m *AddFriendResponseResp) XXX_DiscardUnknown() { + xxx_messageInfo_AddFriendResponseResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AddFriendResponseResp proto.InternalMessageInfo + +func (m *AddFriendResponseResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type SetFriendRemarkReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + Remark string `protobuf:"bytes,2,opt,name=Remark" json:"Remark,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetFriendRemarkReq) Reset() { *m = SetFriendRemarkReq{} } +func (m *SetFriendRemarkReq) String() string { return proto.CompactTextString(m) } +func (*SetFriendRemarkReq) ProtoMessage() {} +func (*SetFriendRemarkReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{27} +} +func (m *SetFriendRemarkReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetFriendRemarkReq.Unmarshal(m, b) +} +func (m *SetFriendRemarkReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetFriendRemarkReq.Marshal(b, m, deterministic) +} +func (dst *SetFriendRemarkReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetFriendRemarkReq.Merge(dst, src) +} +func (m *SetFriendRemarkReq) XXX_Size() int { + return xxx_messageInfo_SetFriendRemarkReq.Size(m) +} +func (m *SetFriendRemarkReq) XXX_DiscardUnknown() { + xxx_messageInfo_SetFriendRemarkReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SetFriendRemarkReq proto.InternalMessageInfo + +func (m *SetFriendRemarkReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +func (m *SetFriendRemarkReq) GetRemark() string { + if m != nil { + return m.Remark + } + return "" +} + +type SetFriendRemarkResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetFriendRemarkResp) Reset() { *m = SetFriendRemarkResp{} } +func (m *SetFriendRemarkResp) String() string { return proto.CompactTextString(m) } +func (*SetFriendRemarkResp) ProtoMessage() {} +func (*SetFriendRemarkResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{28} +} +func (m *SetFriendRemarkResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetFriendRemarkResp.Unmarshal(m, b) +} +func (m *SetFriendRemarkResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetFriendRemarkResp.Marshal(b, m, deterministic) +} +func (dst *SetFriendRemarkResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetFriendRemarkResp.Merge(dst, src) +} +func (m *SetFriendRemarkResp) XXX_Size() int { + return xxx_messageInfo_SetFriendRemarkResp.Size(m) +} +func (m *SetFriendRemarkResp) XXX_DiscardUnknown() { + xxx_messageInfo_SetFriendRemarkResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SetFriendRemarkResp proto.InternalMessageInfo + +func (m *SetFriendRemarkResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetSelfApplyListReq struct { + CommID *CommID `protobuf:"bytes,1,opt,name=CommID" json:"CommID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetSelfApplyListReq) Reset() { *m = GetSelfApplyListReq{} } +func (m *GetSelfApplyListReq) String() string { return proto.CompactTextString(m) } +func (*GetSelfApplyListReq) ProtoMessage() {} +func (*GetSelfApplyListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{29} +} +func (m *GetSelfApplyListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetSelfApplyListReq.Unmarshal(m, b) +} +func (m *GetSelfApplyListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetSelfApplyListReq.Marshal(b, m, deterministic) +} +func (dst *GetSelfApplyListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSelfApplyListReq.Merge(dst, src) +} +func (m *GetSelfApplyListReq) XXX_Size() int { + return xxx_messageInfo_GetSelfApplyListReq.Size(m) +} +func (m *GetSelfApplyListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetSelfApplyListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetSelfApplyListReq proto.InternalMessageInfo + +func (m *GetSelfApplyListReq) GetCommID() *CommID { + if m != nil { + return m.CommID + } + return nil +} + +type GetSelfApplyListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + FriendRequestList []*sdk_ws.FriendRequest `protobuf:"bytes,3,rep,name=FriendRequestList" json:"FriendRequestList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetSelfApplyListResp) Reset() { *m = GetSelfApplyListResp{} } +func (m *GetSelfApplyListResp) String() string { return proto.CompactTextString(m) } +func (*GetSelfApplyListResp) ProtoMessage() {} +func (*GetSelfApplyListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_friend_74b4824fb8c5de90, []int{30} +} +func (m *GetSelfApplyListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetSelfApplyListResp.Unmarshal(m, b) +} +func (m *GetSelfApplyListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetSelfApplyListResp.Marshal(b, m, deterministic) +} +func (dst *GetSelfApplyListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSelfApplyListResp.Merge(dst, src) +} +func (m *GetSelfApplyListResp) XXX_Size() int { + return xxx_messageInfo_GetSelfApplyListResp.Size(m) +} +func (m *GetSelfApplyListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetSelfApplyListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetSelfApplyListResp proto.InternalMessageInfo + +func (m *GetSelfApplyListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetSelfApplyListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetSelfApplyListResp) GetFriendRequestList() []*sdk_ws.FriendRequest { + if m != nil { + return m.FriendRequestList + } + return nil +} + +func init() { + proto.RegisterType((*CommonResp)(nil), "friend.CommonResp") + proto.RegisterType((*CommID)(nil), "friend.CommID") + proto.RegisterType((*GetFriendsInfoReq)(nil), "friend.GetFriendsInfoReq") + proto.RegisterType((*GetFriendInfoResp)(nil), "friend.GetFriendInfoResp") + proto.RegisterType((*AddFriendReq)(nil), "friend.AddFriendReq") + proto.RegisterType((*AddFriendResp)(nil), "friend.AddFriendResp") + proto.RegisterType((*ImportFriendReq)(nil), "friend.ImportFriendReq") + proto.RegisterType((*UserIDResult)(nil), "friend.UserIDResult") + proto.RegisterType((*ImportFriendResp)(nil), "friend.ImportFriendResp") + proto.RegisterType((*GetFriendApplyListReq)(nil), "friend.GetFriendApplyListReq") + proto.RegisterType((*GetFriendApplyListResp)(nil), "friend.GetFriendApplyListResp") + proto.RegisterType((*GetFriendListReq)(nil), "friend.GetFriendListReq") + proto.RegisterType((*GetFriendListResp)(nil), "friend.GetFriendListResp") + proto.RegisterType((*AddBlacklistReq)(nil), "friend.AddBlacklistReq") + proto.RegisterType((*AddBlacklistResp)(nil), "friend.AddBlacklistResp") + proto.RegisterType((*RemoveBlacklistReq)(nil), "friend.RemoveBlacklistReq") + proto.RegisterType((*RemoveBlacklistResp)(nil), "friend.RemoveBlacklistResp") + proto.RegisterType((*GetBlacklistReq)(nil), "friend.GetBlacklistReq") + proto.RegisterType((*GetBlacklistResp)(nil), "friend.GetBlacklistResp") + proto.RegisterType((*IsFriendReq)(nil), "friend.IsFriendReq") + proto.RegisterType((*IsFriendResp)(nil), "friend.IsFriendResp") + proto.RegisterType((*IsInBlackListReq)(nil), "friend.IsInBlackListReq") + proto.RegisterType((*IsInBlackListResp)(nil), "friend.IsInBlackListResp") + proto.RegisterType((*DeleteFriendReq)(nil), "friend.DeleteFriendReq") + proto.RegisterType((*DeleteFriendResp)(nil), "friend.DeleteFriendResp") + proto.RegisterType((*AddFriendResponseReq)(nil), "friend.AddFriendResponseReq") + proto.RegisterType((*AddFriendResponseResp)(nil), "friend.AddFriendResponseResp") + proto.RegisterType((*SetFriendRemarkReq)(nil), "friend.SetFriendRemarkReq") + proto.RegisterType((*SetFriendRemarkResp)(nil), "friend.SetFriendRemarkResp") + proto.RegisterType((*GetSelfApplyListReq)(nil), "friend.GetSelfApplyListReq") + proto.RegisterType((*GetSelfApplyListResp)(nil), "friend.GetSelfApplyListResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Friend service + +type FriendClient interface { + // rpc getFriendsInfo(GetFriendsInfoReq) returns(GetFriendInfoResp); + AddFriend(ctx context.Context, in *AddFriendReq, opts ...grpc.CallOption) (*AddFriendResp, error) + GetFriendApplyList(ctx context.Context, in *GetFriendApplyListReq, opts ...grpc.CallOption) (*GetFriendApplyListResp, error) + GetSelfApplyList(ctx context.Context, in *GetSelfApplyListReq, opts ...grpc.CallOption) (*GetSelfApplyListResp, error) + GetFriendList(ctx context.Context, in *GetFriendListReq, opts ...grpc.CallOption) (*GetFriendListResp, error) + AddBlacklist(ctx context.Context, in *AddBlacklistReq, opts ...grpc.CallOption) (*AddBlacklistResp, error) + RemoveBlacklist(ctx context.Context, in *RemoveBlacklistReq, opts ...grpc.CallOption) (*RemoveBlacklistResp, error) + IsFriend(ctx context.Context, in *IsFriendReq, opts ...grpc.CallOption) (*IsFriendResp, error) + IsInBlackList(ctx context.Context, in *IsInBlackListReq, opts ...grpc.CallOption) (*IsInBlackListResp, error) + GetBlacklist(ctx context.Context, in *GetBlacklistReq, opts ...grpc.CallOption) (*GetBlacklistResp, error) + DeleteFriend(ctx context.Context, in *DeleteFriendReq, opts ...grpc.CallOption) (*DeleteFriendResp, error) + AddFriendResponse(ctx context.Context, in *AddFriendResponseReq, opts ...grpc.CallOption) (*AddFriendResponseResp, error) + SetFriendRemark(ctx context.Context, in *SetFriendRemarkReq, opts ...grpc.CallOption) (*SetFriendRemarkResp, error) + ImportFriend(ctx context.Context, in *ImportFriendReq, opts ...grpc.CallOption) (*ImportFriendResp, error) +} + +type friendClient struct { + cc *grpc.ClientConn +} + +func NewFriendClient(cc *grpc.ClientConn) FriendClient { + return &friendClient{cc} +} + +func (c *friendClient) AddFriend(ctx context.Context, in *AddFriendReq, opts ...grpc.CallOption) (*AddFriendResp, error) { + out := new(AddFriendResp) + err := grpc.Invoke(ctx, "/friend.friend/addFriend", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) GetFriendApplyList(ctx context.Context, in *GetFriendApplyListReq, opts ...grpc.CallOption) (*GetFriendApplyListResp, error) { + out := new(GetFriendApplyListResp) + err := grpc.Invoke(ctx, "/friend.friend/getFriendApplyList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) GetSelfApplyList(ctx context.Context, in *GetSelfApplyListReq, opts ...grpc.CallOption) (*GetSelfApplyListResp, error) { + out := new(GetSelfApplyListResp) + err := grpc.Invoke(ctx, "/friend.friend/getSelfApplyList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) GetFriendList(ctx context.Context, in *GetFriendListReq, opts ...grpc.CallOption) (*GetFriendListResp, error) { + out := new(GetFriendListResp) + err := grpc.Invoke(ctx, "/friend.friend/getFriendList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) AddBlacklist(ctx context.Context, in *AddBlacklistReq, opts ...grpc.CallOption) (*AddBlacklistResp, error) { + out := new(AddBlacklistResp) + err := grpc.Invoke(ctx, "/friend.friend/addBlacklist", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) RemoveBlacklist(ctx context.Context, in *RemoveBlacklistReq, opts ...grpc.CallOption) (*RemoveBlacklistResp, error) { + out := new(RemoveBlacklistResp) + err := grpc.Invoke(ctx, "/friend.friend/removeBlacklist", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) IsFriend(ctx context.Context, in *IsFriendReq, opts ...grpc.CallOption) (*IsFriendResp, error) { + out := new(IsFriendResp) + err := grpc.Invoke(ctx, "/friend.friend/isFriend", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) IsInBlackList(ctx context.Context, in *IsInBlackListReq, opts ...grpc.CallOption) (*IsInBlackListResp, error) { + out := new(IsInBlackListResp) + err := grpc.Invoke(ctx, "/friend.friend/isInBlackList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) GetBlacklist(ctx context.Context, in *GetBlacklistReq, opts ...grpc.CallOption) (*GetBlacklistResp, error) { + out := new(GetBlacklistResp) + err := grpc.Invoke(ctx, "/friend.friend/getBlacklist", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) DeleteFriend(ctx context.Context, in *DeleteFriendReq, opts ...grpc.CallOption) (*DeleteFriendResp, error) { + out := new(DeleteFriendResp) + err := grpc.Invoke(ctx, "/friend.friend/deleteFriend", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) AddFriendResponse(ctx context.Context, in *AddFriendResponseReq, opts ...grpc.CallOption) (*AddFriendResponseResp, error) { + out := new(AddFriendResponseResp) + err := grpc.Invoke(ctx, "/friend.friend/addFriendResponse", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) SetFriendRemark(ctx context.Context, in *SetFriendRemarkReq, opts ...grpc.CallOption) (*SetFriendRemarkResp, error) { + out := new(SetFriendRemarkResp) + err := grpc.Invoke(ctx, "/friend.friend/setFriendRemark", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendClient) ImportFriend(ctx context.Context, in *ImportFriendReq, opts ...grpc.CallOption) (*ImportFriendResp, error) { + out := new(ImportFriendResp) + err := grpc.Invoke(ctx, "/friend.friend/importFriend", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Friend service + +type FriendServer interface { + // rpc getFriendsInfo(GetFriendsInfoReq) returns(GetFriendInfoResp); + AddFriend(context.Context, *AddFriendReq) (*AddFriendResp, error) + GetFriendApplyList(context.Context, *GetFriendApplyListReq) (*GetFriendApplyListResp, error) + GetSelfApplyList(context.Context, *GetSelfApplyListReq) (*GetSelfApplyListResp, error) + GetFriendList(context.Context, *GetFriendListReq) (*GetFriendListResp, error) + AddBlacklist(context.Context, *AddBlacklistReq) (*AddBlacklistResp, error) + RemoveBlacklist(context.Context, *RemoveBlacklistReq) (*RemoveBlacklistResp, error) + IsFriend(context.Context, *IsFriendReq) (*IsFriendResp, error) + IsInBlackList(context.Context, *IsInBlackListReq) (*IsInBlackListResp, error) + GetBlacklist(context.Context, *GetBlacklistReq) (*GetBlacklistResp, error) + DeleteFriend(context.Context, *DeleteFriendReq) (*DeleteFriendResp, error) + AddFriendResponse(context.Context, *AddFriendResponseReq) (*AddFriendResponseResp, error) + SetFriendRemark(context.Context, *SetFriendRemarkReq) (*SetFriendRemarkResp, error) + ImportFriend(context.Context, *ImportFriendReq) (*ImportFriendResp, error) +} + +func RegisterFriendServer(s *grpc.Server, srv FriendServer) { + s.RegisterService(&_Friend_serviceDesc, srv) +} + +func _Friend_AddFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).AddFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/AddFriend", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).AddFriend(ctx, req.(*AddFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_GetFriendApplyList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFriendApplyListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).GetFriendApplyList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/GetFriendApplyList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).GetFriendApplyList(ctx, req.(*GetFriendApplyListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_GetSelfApplyList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSelfApplyListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).GetSelfApplyList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/GetSelfApplyList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).GetSelfApplyList(ctx, req.(*GetSelfApplyListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_GetFriendList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFriendListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).GetFriendList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/GetFriendList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).GetFriendList(ctx, req.(*GetFriendListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_AddBlacklist_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddBlacklistReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).AddBlacklist(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/AddBlacklist", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).AddBlacklist(ctx, req.(*AddBlacklistReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_RemoveBlacklist_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveBlacklistReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).RemoveBlacklist(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/RemoveBlacklist", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).RemoveBlacklist(ctx, req.(*RemoveBlacklistReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_IsFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(IsFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).IsFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/IsFriend", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).IsFriend(ctx, req.(*IsFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_IsInBlackList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(IsInBlackListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).IsInBlackList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/IsInBlackList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).IsInBlackList(ctx, req.(*IsInBlackListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_GetBlacklist_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBlacklistReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).GetBlacklist(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/GetBlacklist", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).GetBlacklist(ctx, req.(*GetBlacklistReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_DeleteFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).DeleteFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/DeleteFriend", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).DeleteFriend(ctx, req.(*DeleteFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_AddFriendResponse_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddFriendResponseReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).AddFriendResponse(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/AddFriendResponse", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).AddFriendResponse(ctx, req.(*AddFriendResponseReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_SetFriendRemark_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetFriendRemarkReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).SetFriendRemark(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/SetFriendRemark", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).SetFriendRemark(ctx, req.(*SetFriendRemarkReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friend_ImportFriend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ImportFriendReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendServer).ImportFriend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/friend.friend/ImportFriend", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendServer).ImportFriend(ctx, req.(*ImportFriendReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _Friend_serviceDesc = grpc.ServiceDesc{ + ServiceName: "friend.friend", + HandlerType: (*FriendServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "addFriend", + Handler: _Friend_AddFriend_Handler, + }, + { + MethodName: "getFriendApplyList", + Handler: _Friend_GetFriendApplyList_Handler, + }, + { + MethodName: "getSelfApplyList", + Handler: _Friend_GetSelfApplyList_Handler, + }, + { + MethodName: "getFriendList", + Handler: _Friend_GetFriendList_Handler, + }, + { + MethodName: "addBlacklist", + Handler: _Friend_AddBlacklist_Handler, + }, + { + MethodName: "removeBlacklist", + Handler: _Friend_RemoveBlacklist_Handler, + }, + { + MethodName: "isFriend", + Handler: _Friend_IsFriend_Handler, + }, + { + MethodName: "isInBlackList", + Handler: _Friend_IsInBlackList_Handler, + }, + { + MethodName: "getBlacklist", + Handler: _Friend_GetBlacklist_Handler, + }, + { + MethodName: "deleteFriend", + Handler: _Friend_DeleteFriend_Handler, + }, + { + MethodName: "addFriendResponse", + Handler: _Friend_AddFriendResponse_Handler, + }, + { + MethodName: "setFriendRemark", + Handler: _Friend_SetFriendRemark_Handler, + }, + { + MethodName: "importFriend", + Handler: _Friend_ImportFriend_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "friend/friend.proto", +} + +func init() { proto.RegisterFile("friend/friend.proto", fileDescriptor_friend_74b4824fb8c5de90) } + +var fileDescriptor_friend_74b4824fb8c5de90 = []byte{ + // 950 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x57, 0xcf, 0x8f, 0xdb, 0x44, + 0x14, 0x96, 0x9b, 0x6e, 0x9a, 0xbc, 0xa4, 0x4d, 0x32, 0xc9, 0x96, 0xe0, 0xee, 0x56, 0xa9, 0x0f, + 0x28, 0xe2, 0x90, 0x48, 0x41, 0x95, 0x58, 0x0a, 0x85, 0x74, 0x93, 0xac, 0x0c, 0x6c, 0x53, 0xcd, + 0x96, 0x0b, 0x42, 0x8a, 0xdc, 0x7a, 0x36, 0x58, 0x71, 0xec, 0xa9, 0xc7, 0xdb, 0x15, 0x37, 0xc4, + 0x89, 0x03, 0x57, 0x24, 0x04, 0x07, 0xfe, 0x55, 0x64, 0x8f, 0x1d, 0xcf, 0xd8, 0xce, 0x0a, 0x9b, + 0x3d, 0x70, 0xda, 0x7d, 0xef, 0xcd, 0xf7, 0xf2, 0x7e, 0xcd, 0xfb, 0xc6, 0xd0, 0xbd, 0xf4, 0x2c, + 0xe2, 0x98, 0x63, 0xfe, 0x67, 0x44, 0x3d, 0xd7, 0x77, 0x51, 0x95, 0x4b, 0xea, 0x93, 0x25, 0x25, + 0xce, 0x4a, 0x3f, 0x1f, 0xd3, 0xcd, 0x7a, 0x1c, 0x9a, 0xc6, 0xcc, 0xdc, 0xac, 0xae, 0xd9, 0xf8, + 0x9a, 0xf1, 0xa3, 0xda, 0x73, 0x80, 0x53, 0x77, 0xbb, 0x75, 0x1d, 0x4c, 0x18, 0x45, 0x7d, 0xb8, + 0x47, 0x3c, 0xef, 0xd4, 0x35, 0x49, 0x5f, 0x19, 0x28, 0xc3, 0x03, 0x1c, 0x8b, 0xe8, 0x21, 0x54, + 0x89, 0xe7, 0x9d, 0xb3, 0x75, 0xff, 0xce, 0x40, 0x19, 0xd6, 0x71, 0x24, 0x69, 0xbf, 0x28, 0x50, + 0x0d, 0x1c, 0xe8, 0x33, 0xa4, 0x42, 0x6d, 0x49, 0xbf, 0x63, 0xc4, 0xd3, 0x67, 0x21, 0xba, 0x8e, + 0x77, 0x32, 0x1a, 0x40, 0x63, 0x49, 0x89, 0x67, 0xf8, 0x96, 0xeb, 0xe8, 0xb3, 0xc8, 0x87, 0xa8, + 0x0a, 0xd0, 0xaf, 0xdd, 0x08, 0x7d, 0x97, 0xa3, 0x63, 0x19, 0x3d, 0x06, 0x58, 0x78, 0xee, 0x36, + 0xb2, 0x1e, 0x84, 0x56, 0x41, 0xa3, 0x3d, 0x83, 0xce, 0x19, 0xf1, 0x17, 0x61, 0xd2, 0x4c, 0x77, + 0x2e, 0x5d, 0x4c, 0xde, 0xa1, 0x8f, 0xe2, 0xc0, 0xc2, 0x60, 0x1a, 0x93, 0x07, 0xa3, 0xa8, 0x46, + 0x5c, 0x8b, 0x23, 0xab, 0xf6, 0x9b, 0x22, 0xa0, 0x39, 0x98, 0x57, 0x62, 0x2e, 0x57, 0x62, 0x9e, + 0x54, 0x62, 0x2e, 0x55, 0x82, 0x4b, 0x68, 0x0e, 0x0f, 0x12, 0x1f, 0xdf, 0x5a, 0xcc, 0xef, 0x57, + 0x06, 0x95, 0x61, 0x63, 0x72, 0x3c, 0x62, 0xc4, 0x7b, 0x4f, 0xbc, 0x95, 0x41, 0xad, 0x15, 0x35, + 0x3c, 0x63, 0xcb, 0x46, 0xc2, 0x8f, 0xa5, 0x40, 0xda, 0x4b, 0x68, 0x4e, 0x4d, 0x93, 0x2b, 0x0b, + 0xa4, 0x11, 0x84, 0x85, 0xc9, 0x3b, 0x21, 0x2c, 0x2e, 0x69, 0xa7, 0x70, 0x5f, 0xf0, 0xc7, 0x28, + 0x9a, 0x88, 0x1d, 0x8f, 0x9c, 0x22, 0xd1, 0x29, 0xb7, 0x60, 0xe1, 0x94, 0xf6, 0x97, 0x02, 0x2d, + 0x7d, 0x4b, 0x5d, 0xcf, 0x4f, 0x02, 0xfb, 0x18, 0xda, 0x5c, 0xe0, 0x4d, 0x08, 0x33, 0x56, 0x06, + 0x95, 0x61, 0x1d, 0x67, 0xf4, 0xff, 0xa2, 0xfd, 0x72, 0x8b, 0x2b, 0xe9, 0x16, 0x4b, 0xc3, 0x75, + 0x57, 0x1e, 0x2e, 0xed, 0x39, 0x34, 0xf9, 0x7f, 0x98, 0xb0, 0x2b, 0xdb, 0x0f, 0x4a, 0x21, 0x8d, + 0x61, 0x24, 0xf1, 0x12, 0x05, 0x27, 0xc2, 0x00, 0x0e, 0x70, 0x24, 0x69, 0xbf, 0x2a, 0xd0, 0x96, + 0xb3, 0x2b, 0x57, 0x26, 0xf4, 0x15, 0xb4, 0xc5, 0x40, 0xc2, 0x92, 0xdc, 0x09, 0x87, 0xa0, 0x17, + 0x23, 0x45, 0x3b, 0xce, 0x9c, 0xd6, 0xbe, 0x84, 0xc3, 0xdd, 0x2c, 0x4e, 0x29, 0xb5, 0x7f, 0x0a, + 0xb4, 0x45, 0xa6, 0xf9, 0x4f, 0x05, 0x1e, 0xe6, 0x79, 0x28, 0x35, 0xd2, 0x2f, 0xa1, 0xb3, 0xeb, + 0xf7, 0x15, 0x61, 0xbe, 0x30, 0xd5, 0x83, 0xbd, 0x53, 0x1d, 0x9d, 0xc5, 0x59, 0xa8, 0xf6, 0x19, + 0xb4, 0x77, 0xb1, 0x15, 0x4d, 0x4c, 0xba, 0xa6, 0xff, 0x21, 0xa7, 0x5b, 0xba, 0xa6, 0x27, 0xd0, + 0x9a, 0x9a, 0xe6, 0x0b, 0xdb, 0x78, 0xbb, 0xb1, 0x0b, 0x66, 0xb2, 0x80, 0xb6, 0x0c, 0x2d, 0x79, + 0x29, 0x3f, 0x07, 0x84, 0xc9, 0xd6, 0x7d, 0x4f, 0x4a, 0x45, 0xa1, 0x43, 0x37, 0x83, 0x2e, 0x19, + 0xc8, 0x09, 0xb4, 0xce, 0x88, 0x5f, 0x2a, 0x8a, 0xdf, 0x95, 0x70, 0x24, 0xe4, 0x18, 0x8a, 0x37, + 0x75, 0x09, 0x9d, 0xd0, 0x45, 0x78, 0x9f, 0xe4, 0xbe, 0x3e, 0xc9, 0xe9, 0xeb, 0xab, 0xab, 0x37, + 0xb6, 0xf5, 0x36, 0x3e, 0x8c, 0xb3, 0x58, 0xed, 0x29, 0x34, 0x74, 0x56, 0x78, 0x09, 0x6b, 0x3f, + 0x40, 0x33, 0x81, 0x95, 0xca, 0x44, 0x85, 0x5a, 0x80, 0x74, 0x1d, 0x46, 0xc2, 0x2d, 0x58, 0xc3, + 0x3b, 0x39, 0xb8, 0x3e, 0x3a, 0xd3, 0x9d, 0x30, 0xda, 0xa2, 0xd7, 0xc7, 0x80, 0x4e, 0x0a, 0x7b, + 0xeb, 0xe1, 0x9d, 0x40, 0x6b, 0x46, 0x6c, 0xe2, 0x93, 0xe2, 0x75, 0x5b, 0x40, 0x5b, 0x86, 0x96, + 0x9c, 0xc4, 0x9f, 0x15, 0xe8, 0x49, 0x6c, 0x17, 0x04, 0x56, 0x84, 0x45, 0x35, 0x68, 0xfe, 0x68, + 0x38, 0xa6, 0x4d, 0x24, 0xa2, 0x90, 0x74, 0xe8, 0x08, 0xea, 0x5c, 0x0e, 0xca, 0xc3, 0x99, 0x2a, + 0x51, 0x68, 0xdf, 0xc0, 0x61, 0x4e, 0x04, 0x25, 0xf3, 0x79, 0x0d, 0xe8, 0x82, 0xec, 0x58, 0x69, + 0x6b, 0x78, 0x9b, 0xc2, 0x4f, 0x82, 0x00, 0x94, 0x3c, 0x09, 0x02, 0x29, 0xb8, 0xfa, 0x19, 0xaf, + 0x25, 0x03, 0xfc, 0x02, 0xba, 0x67, 0xc4, 0xbf, 0x20, 0xf6, 0x65, 0x29, 0xb6, 0xfa, 0x43, 0x81, + 0x5e, 0x16, 0xff, 0x7f, 0xe0, 0xaa, 0xc9, 0xdf, 0xf7, 0x20, 0x7a, 0x46, 0xa3, 0x4f, 0xa1, 0x6e, + 0xc4, 0x2d, 0x45, 0x3b, 0x26, 0x17, 0x5f, 0x69, 0xea, 0x61, 0x8e, 0x96, 0x51, 0x74, 0x01, 0x68, + 0x9d, 0x21, 0x63, 0x74, 0x1c, 0x1f, 0xce, 0xa5, 0x7a, 0xf5, 0xf1, 0x4d, 0x66, 0x46, 0xd1, 0x39, + 0xb4, 0xd7, 0xa9, 0x9a, 0xa1, 0x47, 0x02, 0x26, 0xdd, 0x0d, 0xf5, 0x68, 0xbf, 0x91, 0x51, 0x34, + 0x83, 0xfb, 0x6b, 0x91, 0x57, 0x51, 0x3f, 0xf3, 0xfb, 0xb1, 0xa3, 0x0f, 0xf7, 0x58, 0x18, 0x45, + 0x53, 0x68, 0x1a, 0x02, 0xa9, 0xa1, 0x0f, 0x84, 0x82, 0x88, 0xcc, 0xa0, 0xf6, 0xf3, 0x0d, 0x8c, + 0xa2, 0xaf, 0xa1, 0xe5, 0xc9, 0x8c, 0x84, 0xd4, 0xf8, 0x70, 0x96, 0xe8, 0xd4, 0x47, 0x7b, 0x6d, + 0x8c, 0xa2, 0xa7, 0x50, 0xb3, 0xa2, 0x45, 0x8c, 0xba, 0xf1, 0x41, 0x61, 0xa3, 0xab, 0xbd, 0xac, + 0x92, 0xd7, 0xc2, 0x12, 0xb7, 0x64, 0x52, 0x8b, 0xf4, 0xe2, 0x4d, 0x6a, 0x91, 0x5d, 0xab, 0x53, + 0x68, 0xae, 0x05, 0x4e, 0x4b, 0x6a, 0x91, 0x62, 0x49, 0xb5, 0x9f, 0x6f, 0xe0, 0x2e, 0x4c, 0x61, + 0x21, 0x26, 0x2e, 0x52, 0x1b, 0x36, 0x71, 0x91, 0xd9, 0x9f, 0xaf, 0xa0, 0x63, 0xa4, 0x17, 0x11, + 0x3a, 0xca, 0x9d, 0xd3, 0x68, 0x4b, 0xaa, 0xc7, 0x37, 0x58, 0x79, 0x83, 0x98, 0xbc, 0x37, 0x92, + 0x06, 0x65, 0xd7, 0x54, 0xd2, 0xa0, 0xbc, 0x65, 0x33, 0x85, 0xa6, 0x25, 0x3c, 0xb9, 0x93, 0x04, + 0x53, 0x9f, 0x19, 0x49, 0x82, 0xe9, 0x17, 0xfa, 0x8b, 0xce, 0xf7, 0xad, 0x51, 0xf4, 0xdd, 0xfb, + 0x8c, 0xff, 0x79, 0x53, 0x0d, 0x3f, 0x6a, 0x3f, 0xf9, 0x27, 0x00, 0x00, 0xff, 0xff, 0x26, 0xd5, + 0xdf, 0x90, 0x16, 0x0f, 0x00, 0x00, +} diff --git a/pkg/proto/friend/friend.proto b/pkg/proto/friend/friend.proto new file mode 100644 index 000000000..0050582d1 --- /dev/null +++ b/pkg/proto/friend/friend.proto @@ -0,0 +1,169 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./friend;friend"; +package friend; + +message CommonResp{ + int32 errCode = 1; + string errMsg = 2; +} + +message CommID{ + string OpUserID = 1; + string OperationID = 2; + string ToUserID = 4; + string FromUserID = 5; +} + + +message GetFriendsInfoReq{ + CommID CommID = 1; +} +message GetFriendInfoResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.FriendInfo FriendInfoList = 3; +// int32 IsBlack = 4; +} + + +message AddFriendReq{ + CommID CommID = 1; + string ReqMsg = 2; +} +message AddFriendResp{ + CommonResp CommonResp = 1; +} + + +message ImportFriendReq{ + repeated string FriendUserIDList = 1; + string OperationID = 2; + string FromUserID = 3; + string OpUserID = 4; +} +message UserIDResult{ + string UserID = 1; + int32 Result = 2; +} +message ImportFriendResp{ + CommonResp CommonResp = 1; + repeated UserIDResult UserIDResultList = 2; +} + + +message GetFriendApplyListReq{ + CommID CommID = 1; +} +message GetFriendApplyListResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.FriendRequest FriendRequestList = 3; +} + + +message GetFriendListReq{ + CommID CommID = 1; +} +message GetFriendListResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.FriendInfo FriendInfoList = 3; +} + + +message AddBlacklistReq{ + CommID CommID = 1; +} +message AddBlacklistResp{ + CommonResp CommonResp = 1; +} + + +message RemoveBlacklistReq{ + CommID CommID = 1; +} +message RemoveBlacklistResp{ + CommonResp CommonResp = 1; +} + +message GetBlacklistReq{ + CommID CommID = 1; +} +message GetBlacklistResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.PublicUserInfo BlackUserInfoList = 3; +} + + +message IsFriendReq{ + CommID CommID = 1; +} +message IsFriendResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + bool Response = 3; +} + + +message IsInBlackListReq{ + CommID CommID = 1; +} +message IsInBlackListResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + bool Response = 3; +} + + +message DeleteFriendReq{ + CommID CommID = 1; +} +message DeleteFriendResp{ + CommonResp CommonResp = 1; +} + +//process +message AddFriendResponseReq{ + CommID CommID = 1; + int32 handleResult = 2; + string handleMsg = 3; +} +message AddFriendResponseResp{ + CommonResp CommonResp = 1; +} + +message SetFriendRemarkReq{ + CommID CommID = 1; + string Remark = 2; +} +message SetFriendRemarkResp{ + CommonResp CommonResp = 1; +} + +message GetSelfApplyListReq{ + CommID CommID = 1; +} +message GetSelfApplyListResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.FriendRequest FriendRequestList = 3; +} + +service friend{ + // rpc getFriendsInfo(GetFriendsInfoReq) returns(GetFriendInfoResp); + rpc addFriend(AddFriendReq) returns(AddFriendResp); + rpc getFriendApplyList(GetFriendApplyListReq) returns(GetFriendApplyListResp); + rpc getSelfApplyList(GetSelfApplyListReq) returns(GetSelfApplyListResp); + rpc getFriendList(GetFriendListReq) returns(GetFriendListResp); + rpc addBlacklist(AddBlacklistReq) returns(AddBlacklistResp); + rpc removeBlacklist(RemoveBlacklistReq) returns(RemoveBlacklistResp); + rpc isFriend(IsFriendReq) returns(IsFriendResp); + rpc isInBlackList(IsInBlackListReq) returns(IsInBlackListResp); + rpc getBlacklist(GetBlacklistReq) returns(GetBlacklistResp); + rpc deleteFriend(DeleteFriendReq) returns(DeleteFriendResp); + rpc addFriendResponse(AddFriendResponseReq) returns(AddFriendResponseResp); + rpc setFriendRemark(SetFriendRemarkReq) returns(SetFriendRemarkResp); + rpc importFriend(ImportFriendReq) returns(ImportFriendResp); +} \ No newline at end of file diff --git a/pkg/proto/group/group.pb.go b/pkg/proto/group/group.pb.go new file mode 100644 index 000000000..2f8176fad --- /dev/null +++ b/pkg/proto/group/group.pb.go @@ -0,0 +1,4481 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: group/group.proto + +package group // import "./group" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CommonResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommonResp) Reset() { *m = CommonResp{} } +func (m *CommonResp) String() string { return proto.CompactTextString(m) } +func (*CommonResp) ProtoMessage() {} +func (*CommonResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{0} +} +func (m *CommonResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommonResp.Unmarshal(m, b) +} +func (m *CommonResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommonResp.Marshal(b, m, deterministic) +} +func (dst *CommonResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommonResp.Merge(dst, src) +} +func (m *CommonResp) XXX_Size() int { + return xxx_messageInfo_CommonResp.Size(m) +} +func (m *CommonResp) XXX_DiscardUnknown() { + xxx_messageInfo_CommonResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CommonResp proto.InternalMessageInfo + +func (m *CommonResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CommonResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type GroupAddMemberInfo struct { + UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` + RoleLevel int32 `protobuf:"varint,2,opt,name=RoleLevel" json:"RoleLevel,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupAddMemberInfo) Reset() { *m = GroupAddMemberInfo{} } +func (m *GroupAddMemberInfo) String() string { return proto.CompactTextString(m) } +func (*GroupAddMemberInfo) ProtoMessage() {} +func (*GroupAddMemberInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{1} +} +func (m *GroupAddMemberInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupAddMemberInfo.Unmarshal(m, b) +} +func (m *GroupAddMemberInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupAddMemberInfo.Marshal(b, m, deterministic) +} +func (dst *GroupAddMemberInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupAddMemberInfo.Merge(dst, src) +} +func (m *GroupAddMemberInfo) XXX_Size() int { + return xxx_messageInfo_GroupAddMemberInfo.Size(m) +} +func (m *GroupAddMemberInfo) XXX_DiscardUnknown() { + xxx_messageInfo_GroupAddMemberInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupAddMemberInfo proto.InternalMessageInfo + +func (m *GroupAddMemberInfo) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GroupAddMemberInfo) GetRoleLevel() int32 { + if m != nil { + return m.RoleLevel + } + return 0 +} + +type CreateGroupReq struct { + InitMemberList []*GroupAddMemberInfo `protobuf:"bytes,1,rep,name=InitMemberList" json:"InitMemberList,omitempty"` + GroupInfo *sdk_ws.GroupInfo `protobuf:"bytes,2,opt,name=GroupInfo" json:"GroupInfo,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserID string `protobuf:"bytes,4,opt,name=OpUserID" json:"OpUserID,omitempty"` + OwnerUserID string `protobuf:"bytes,5,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateGroupReq) Reset() { *m = CreateGroupReq{} } +func (m *CreateGroupReq) String() string { return proto.CompactTextString(m) } +func (*CreateGroupReq) ProtoMessage() {} +func (*CreateGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{2} +} +func (m *CreateGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateGroupReq.Unmarshal(m, b) +} +func (m *CreateGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateGroupReq.Marshal(b, m, deterministic) +} +func (dst *CreateGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateGroupReq.Merge(dst, src) +} +func (m *CreateGroupReq) XXX_Size() int { + return xxx_messageInfo_CreateGroupReq.Size(m) +} +func (m *CreateGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_CreateGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateGroupReq proto.InternalMessageInfo + +func (m *CreateGroupReq) GetInitMemberList() []*GroupAddMemberInfo { + if m != nil { + return m.InitMemberList + } + return nil +} + +func (m *CreateGroupReq) GetGroupInfo() *sdk_ws.GroupInfo { + if m != nil { + return m.GroupInfo + } + return nil +} + +func (m *CreateGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CreateGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *CreateGroupReq) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +type CreateGroupResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + GroupInfo *sdk_ws.GroupInfo `protobuf:"bytes,3,opt,name=GroupInfo" json:"GroupInfo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateGroupResp) Reset() { *m = CreateGroupResp{} } +func (m *CreateGroupResp) String() string { return proto.CompactTextString(m) } +func (*CreateGroupResp) ProtoMessage() {} +func (*CreateGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{3} +} +func (m *CreateGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateGroupResp.Unmarshal(m, b) +} +func (m *CreateGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateGroupResp.Marshal(b, m, deterministic) +} +func (dst *CreateGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateGroupResp.Merge(dst, src) +} +func (m *CreateGroupResp) XXX_Size() int { + return xxx_messageInfo_CreateGroupResp.Size(m) +} +func (m *CreateGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_CreateGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateGroupResp proto.InternalMessageInfo + +func (m *CreateGroupResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CreateGroupResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *CreateGroupResp) GetGroupInfo() *sdk_ws.GroupInfo { + if m != nil { + return m.GroupInfo + } + return nil +} + +type GetGroupsInfoReq struct { + GroupIDList []string `protobuf:"bytes,1,rep,name=GroupIDList" json:"GroupIDList,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupsInfoReq) Reset() { *m = GetGroupsInfoReq{} } +func (m *GetGroupsInfoReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupsInfoReq) ProtoMessage() {} +func (*GetGroupsInfoReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{4} +} +func (m *GetGroupsInfoReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupsInfoReq.Unmarshal(m, b) +} +func (m *GetGroupsInfoReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupsInfoReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupsInfoReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupsInfoReq.Merge(dst, src) +} +func (m *GetGroupsInfoReq) XXX_Size() int { + return xxx_messageInfo_GetGroupsInfoReq.Size(m) +} +func (m *GetGroupsInfoReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupsInfoReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupsInfoReq proto.InternalMessageInfo + +func (m *GetGroupsInfoReq) GetGroupIDList() []string { + if m != nil { + return m.GroupIDList + } + return nil +} + +func (m *GetGroupsInfoReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetGroupsInfoReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type GetGroupsInfoResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + GroupInfoList []*sdk_ws.GroupInfo `protobuf:"bytes,3,rep,name=GroupInfoList" json:"GroupInfoList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupsInfoResp) Reset() { *m = GetGroupsInfoResp{} } +func (m *GetGroupsInfoResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupsInfoResp) ProtoMessage() {} +func (*GetGroupsInfoResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{5} +} +func (m *GetGroupsInfoResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupsInfoResp.Unmarshal(m, b) +} +func (m *GetGroupsInfoResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupsInfoResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupsInfoResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupsInfoResp.Merge(dst, src) +} +func (m *GetGroupsInfoResp) XXX_Size() int { + return xxx_messageInfo_GetGroupsInfoResp.Size(m) +} +func (m *GetGroupsInfoResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupsInfoResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupsInfoResp proto.InternalMessageInfo + +func (m *GetGroupsInfoResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetGroupsInfoResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetGroupsInfoResp) GetGroupInfoList() []*sdk_ws.GroupInfo { + if m != nil { + return m.GroupInfoList + } + return nil +} + +type SetGroupInfoReq struct { + GroupInfo *sdk_ws.GroupInfo `protobuf:"bytes,1,opt,name=GroupInfo" json:"GroupInfo,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetGroupInfoReq) Reset() { *m = SetGroupInfoReq{} } +func (m *SetGroupInfoReq) String() string { return proto.CompactTextString(m) } +func (*SetGroupInfoReq) ProtoMessage() {} +func (*SetGroupInfoReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{6} +} +func (m *SetGroupInfoReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetGroupInfoReq.Unmarshal(m, b) +} +func (m *SetGroupInfoReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetGroupInfoReq.Marshal(b, m, deterministic) +} +func (dst *SetGroupInfoReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetGroupInfoReq.Merge(dst, src) +} +func (m *SetGroupInfoReq) XXX_Size() int { + return xxx_messageInfo_SetGroupInfoReq.Size(m) +} +func (m *SetGroupInfoReq) XXX_DiscardUnknown() { + xxx_messageInfo_SetGroupInfoReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SetGroupInfoReq proto.InternalMessageInfo + +func (m *SetGroupInfoReq) GetGroupInfo() *sdk_ws.GroupInfo { + if m != nil { + return m.GroupInfo + } + return nil +} + +func (m *SetGroupInfoReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SetGroupInfoReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type SetGroupInfoResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetGroupInfoResp) Reset() { *m = SetGroupInfoResp{} } +func (m *SetGroupInfoResp) String() string { return proto.CompactTextString(m) } +func (*SetGroupInfoResp) ProtoMessage() {} +func (*SetGroupInfoResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{7} +} +func (m *SetGroupInfoResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetGroupInfoResp.Unmarshal(m, b) +} +func (m *SetGroupInfoResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetGroupInfoResp.Marshal(b, m, deterministic) +} +func (dst *SetGroupInfoResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetGroupInfoResp.Merge(dst, src) +} +func (m *SetGroupInfoResp) XXX_Size() int { + return xxx_messageInfo_SetGroupInfoResp.Size(m) +} +func (m *SetGroupInfoResp) XXX_DiscardUnknown() { + xxx_messageInfo_SetGroupInfoResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SetGroupInfoResp proto.InternalMessageInfo + +func (m *SetGroupInfoResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetGroupApplicationListReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + FromUserID string `protobuf:"bytes,3,opt,name=FromUserID" json:"FromUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupApplicationListReq) Reset() { *m = GetGroupApplicationListReq{} } +func (m *GetGroupApplicationListReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupApplicationListReq) ProtoMessage() {} +func (*GetGroupApplicationListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{8} +} +func (m *GetGroupApplicationListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupApplicationListReq.Unmarshal(m, b) +} +func (m *GetGroupApplicationListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupApplicationListReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupApplicationListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupApplicationListReq.Merge(dst, src) +} +func (m *GetGroupApplicationListReq) XXX_Size() int { + return xxx_messageInfo_GetGroupApplicationListReq.Size(m) +} +func (m *GetGroupApplicationListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupApplicationListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupApplicationListReq proto.InternalMessageInfo + +func (m *GetGroupApplicationListReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetGroupApplicationListReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetGroupApplicationListReq) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +type GetGroupApplicationListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + GroupRequestList []*sdk_ws.GroupRequest `protobuf:"bytes,3,rep,name=GroupRequestList" json:"GroupRequestList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupApplicationListResp) Reset() { *m = GetGroupApplicationListResp{} } +func (m *GetGroupApplicationListResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupApplicationListResp) ProtoMessage() {} +func (*GetGroupApplicationListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{9} +} +func (m *GetGroupApplicationListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupApplicationListResp.Unmarshal(m, b) +} +func (m *GetGroupApplicationListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupApplicationListResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupApplicationListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupApplicationListResp.Merge(dst, src) +} +func (m *GetGroupApplicationListResp) XXX_Size() int { + return xxx_messageInfo_GetGroupApplicationListResp.Size(m) +} +func (m *GetGroupApplicationListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupApplicationListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupApplicationListResp proto.InternalMessageInfo + +func (m *GetGroupApplicationListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetGroupApplicationListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetGroupApplicationListResp) GetGroupRequestList() []*sdk_ws.GroupRequest { + if m != nil { + return m.GroupRequestList + } + return nil +} + +type GetUserReqApplicationListReq struct { + UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserReqApplicationListReq) Reset() { *m = GetUserReqApplicationListReq{} } +func (m *GetUserReqApplicationListReq) String() string { return proto.CompactTextString(m) } +func (*GetUserReqApplicationListReq) ProtoMessage() {} +func (*GetUserReqApplicationListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{10} +} +func (m *GetUserReqApplicationListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserReqApplicationListReq.Unmarshal(m, b) +} +func (m *GetUserReqApplicationListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserReqApplicationListReq.Marshal(b, m, deterministic) +} +func (dst *GetUserReqApplicationListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserReqApplicationListReq.Merge(dst, src) +} +func (m *GetUserReqApplicationListReq) XXX_Size() int { + return xxx_messageInfo_GetUserReqApplicationListReq.Size(m) +} +func (m *GetUserReqApplicationListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserReqApplicationListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserReqApplicationListReq proto.InternalMessageInfo + +func (m *GetUserReqApplicationListReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserReqApplicationListReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetUserReqApplicationListReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUserReqApplicationListResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + GroupRequestList []*sdk_ws.GroupRequest `protobuf:"bytes,2,rep,name=GroupRequestList" json:"GroupRequestList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserReqApplicationListResp) Reset() { *m = GetUserReqApplicationListResp{} } +func (m *GetUserReqApplicationListResp) String() string { return proto.CompactTextString(m) } +func (*GetUserReqApplicationListResp) ProtoMessage() {} +func (*GetUserReqApplicationListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{11} +} +func (m *GetUserReqApplicationListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserReqApplicationListResp.Unmarshal(m, b) +} +func (m *GetUserReqApplicationListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserReqApplicationListResp.Marshal(b, m, deterministic) +} +func (dst *GetUserReqApplicationListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserReqApplicationListResp.Merge(dst, src) +} +func (m *GetUserReqApplicationListResp) XXX_Size() int { + return xxx_messageInfo_GetUserReqApplicationListResp.Size(m) +} +func (m *GetUserReqApplicationListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserReqApplicationListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserReqApplicationListResp proto.InternalMessageInfo + +func (m *GetUserReqApplicationListResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserReqApplicationListResp) GetGroupRequestList() []*sdk_ws.GroupRequest { + if m != nil { + return m.GroupRequestList + } + return nil +} + +type TransferGroupOwnerReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + OldOwnerUserID string `protobuf:"bytes,2,opt,name=OldOwnerUserID" json:"OldOwnerUserID,omitempty"` + NewOwnerUserID string `protobuf:"bytes,3,opt,name=NewOwnerUserID" json:"NewOwnerUserID,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserID string `protobuf:"bytes,5,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TransferGroupOwnerReq) Reset() { *m = TransferGroupOwnerReq{} } +func (m *TransferGroupOwnerReq) String() string { return proto.CompactTextString(m) } +func (*TransferGroupOwnerReq) ProtoMessage() {} +func (*TransferGroupOwnerReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{12} +} +func (m *TransferGroupOwnerReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TransferGroupOwnerReq.Unmarshal(m, b) +} +func (m *TransferGroupOwnerReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TransferGroupOwnerReq.Marshal(b, m, deterministic) +} +func (dst *TransferGroupOwnerReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransferGroupOwnerReq.Merge(dst, src) +} +func (m *TransferGroupOwnerReq) XXX_Size() int { + return xxx_messageInfo_TransferGroupOwnerReq.Size(m) +} +func (m *TransferGroupOwnerReq) XXX_DiscardUnknown() { + xxx_messageInfo_TransferGroupOwnerReq.DiscardUnknown(m) +} + +var xxx_messageInfo_TransferGroupOwnerReq proto.InternalMessageInfo + +func (m *TransferGroupOwnerReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *TransferGroupOwnerReq) GetOldOwnerUserID() string { + if m != nil { + return m.OldOwnerUserID + } + return "" +} + +func (m *TransferGroupOwnerReq) GetNewOwnerUserID() string { + if m != nil { + return m.NewOwnerUserID + } + return "" +} + +func (m *TransferGroupOwnerReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *TransferGroupOwnerReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type TransferGroupOwnerResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TransferGroupOwnerResp) Reset() { *m = TransferGroupOwnerResp{} } +func (m *TransferGroupOwnerResp) String() string { return proto.CompactTextString(m) } +func (*TransferGroupOwnerResp) ProtoMessage() {} +func (*TransferGroupOwnerResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{13} +} +func (m *TransferGroupOwnerResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TransferGroupOwnerResp.Unmarshal(m, b) +} +func (m *TransferGroupOwnerResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TransferGroupOwnerResp.Marshal(b, m, deterministic) +} +func (dst *TransferGroupOwnerResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransferGroupOwnerResp.Merge(dst, src) +} +func (m *TransferGroupOwnerResp) XXX_Size() int { + return xxx_messageInfo_TransferGroupOwnerResp.Size(m) +} +func (m *TransferGroupOwnerResp) XXX_DiscardUnknown() { + xxx_messageInfo_TransferGroupOwnerResp.DiscardUnknown(m) +} + +var xxx_messageInfo_TransferGroupOwnerResp proto.InternalMessageInfo + +func (m *TransferGroupOwnerResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type JoinGroupReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + ReqMessage string `protobuf:"bytes,2,opt,name=ReqMessage" json:"ReqMessage,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *JoinGroupReq) Reset() { *m = JoinGroupReq{} } +func (m *JoinGroupReq) String() string { return proto.CompactTextString(m) } +func (*JoinGroupReq) ProtoMessage() {} +func (*JoinGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{14} +} +func (m *JoinGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_JoinGroupReq.Unmarshal(m, b) +} +func (m *JoinGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_JoinGroupReq.Marshal(b, m, deterministic) +} +func (dst *JoinGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_JoinGroupReq.Merge(dst, src) +} +func (m *JoinGroupReq) XXX_Size() int { + return xxx_messageInfo_JoinGroupReq.Size(m) +} +func (m *JoinGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_JoinGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_JoinGroupReq proto.InternalMessageInfo + +func (m *JoinGroupReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *JoinGroupReq) GetReqMessage() string { + if m != nil { + return m.ReqMessage + } + return "" +} + +func (m *JoinGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *JoinGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type JoinGroupResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *JoinGroupResp) Reset() { *m = JoinGroupResp{} } +func (m *JoinGroupResp) String() string { return proto.CompactTextString(m) } +func (*JoinGroupResp) ProtoMessage() {} +func (*JoinGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{15} +} +func (m *JoinGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_JoinGroupResp.Unmarshal(m, b) +} +func (m *JoinGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_JoinGroupResp.Marshal(b, m, deterministic) +} +func (dst *JoinGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_JoinGroupResp.Merge(dst, src) +} +func (m *JoinGroupResp) XXX_Size() int { + return xxx_messageInfo_JoinGroupResp.Size(m) +} +func (m *JoinGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_JoinGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_JoinGroupResp proto.InternalMessageInfo + +func (m *JoinGroupResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GroupApplicationResponseReq struct { + OperationID string `protobuf:"bytes,1,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=GroupID" json:"GroupID,omitempty"` + FromUserID string `protobuf:"bytes,4,opt,name=FromUserID" json:"FromUserID,omitempty"` + HandledMsg string `protobuf:"bytes,5,opt,name=HandledMsg" json:"HandledMsg,omitempty"` + HandleResult int32 `protobuf:"varint,6,opt,name=HandleResult" json:"HandleResult,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupApplicationResponseReq) Reset() { *m = GroupApplicationResponseReq{} } +func (m *GroupApplicationResponseReq) String() string { return proto.CompactTextString(m) } +func (*GroupApplicationResponseReq) ProtoMessage() {} +func (*GroupApplicationResponseReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{16} +} +func (m *GroupApplicationResponseReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupApplicationResponseReq.Unmarshal(m, b) +} +func (m *GroupApplicationResponseReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupApplicationResponseReq.Marshal(b, m, deterministic) +} +func (dst *GroupApplicationResponseReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupApplicationResponseReq.Merge(dst, src) +} +func (m *GroupApplicationResponseReq) XXX_Size() int { + return xxx_messageInfo_GroupApplicationResponseReq.Size(m) +} +func (m *GroupApplicationResponseReq) XXX_DiscardUnknown() { + xxx_messageInfo_GroupApplicationResponseReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupApplicationResponseReq proto.InternalMessageInfo + +func (m *GroupApplicationResponseReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GroupApplicationResponseReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GroupApplicationResponseReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *GroupApplicationResponseReq) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +func (m *GroupApplicationResponseReq) GetHandledMsg() string { + if m != nil { + return m.HandledMsg + } + return "" +} + +func (m *GroupApplicationResponseReq) GetHandleResult() int32 { + if m != nil { + return m.HandleResult + } + return 0 +} + +type GroupApplicationResponseResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupApplicationResponseResp) Reset() { *m = GroupApplicationResponseResp{} } +func (m *GroupApplicationResponseResp) String() string { return proto.CompactTextString(m) } +func (*GroupApplicationResponseResp) ProtoMessage() {} +func (*GroupApplicationResponseResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{17} +} +func (m *GroupApplicationResponseResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupApplicationResponseResp.Unmarshal(m, b) +} +func (m *GroupApplicationResponseResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupApplicationResponseResp.Marshal(b, m, deterministic) +} +func (dst *GroupApplicationResponseResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupApplicationResponseResp.Merge(dst, src) +} +func (m *GroupApplicationResponseResp) XXX_Size() int { + return xxx_messageInfo_GroupApplicationResponseResp.Size(m) +} +func (m *GroupApplicationResponseResp) XXX_DiscardUnknown() { + xxx_messageInfo_GroupApplicationResponseResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupApplicationResponseResp proto.InternalMessageInfo + +func (m *GroupApplicationResponseResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type QuitGroupReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *QuitGroupReq) Reset() { *m = QuitGroupReq{} } +func (m *QuitGroupReq) String() string { return proto.CompactTextString(m) } +func (*QuitGroupReq) ProtoMessage() {} +func (*QuitGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{18} +} +func (m *QuitGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_QuitGroupReq.Unmarshal(m, b) +} +func (m *QuitGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_QuitGroupReq.Marshal(b, m, deterministic) +} +func (dst *QuitGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuitGroupReq.Merge(dst, src) +} +func (m *QuitGroupReq) XXX_Size() int { + return xxx_messageInfo_QuitGroupReq.Size(m) +} +func (m *QuitGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_QuitGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_QuitGroupReq proto.InternalMessageInfo + +func (m *QuitGroupReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *QuitGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *QuitGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type QuitGroupResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *QuitGroupResp) Reset() { *m = QuitGroupResp{} } +func (m *QuitGroupResp) String() string { return proto.CompactTextString(m) } +func (*QuitGroupResp) ProtoMessage() {} +func (*QuitGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{19} +} +func (m *QuitGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_QuitGroupResp.Unmarshal(m, b) +} +func (m *QuitGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_QuitGroupResp.Marshal(b, m, deterministic) +} +func (dst *QuitGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuitGroupResp.Merge(dst, src) +} +func (m *QuitGroupResp) XXX_Size() int { + return xxx_messageInfo_QuitGroupResp.Size(m) +} +func (m *QuitGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_QuitGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_QuitGroupResp proto.InternalMessageInfo + +func (m *QuitGroupResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetGroupMemberListReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + Filter int32 `protobuf:"varint,4,opt,name=Filter" json:"Filter,omitempty"` + NextSeq int32 `protobuf:"varint,5,opt,name=NextSeq" json:"NextSeq,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMemberListReq) Reset() { *m = GetGroupMemberListReq{} } +func (m *GetGroupMemberListReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupMemberListReq) ProtoMessage() {} +func (*GetGroupMemberListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{20} +} +func (m *GetGroupMemberListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMemberListReq.Unmarshal(m, b) +} +func (m *GetGroupMemberListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMemberListReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupMemberListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMemberListReq.Merge(dst, src) +} +func (m *GetGroupMemberListReq) XXX_Size() int { + return xxx_messageInfo_GetGroupMemberListReq.Size(m) +} +func (m *GetGroupMemberListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMemberListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMemberListReq proto.InternalMessageInfo + +func (m *GetGroupMemberListReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *GetGroupMemberListReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetGroupMemberListReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetGroupMemberListReq) GetFilter() int32 { + if m != nil { + return m.Filter + } + return 0 +} + +func (m *GetGroupMemberListReq) GetNextSeq() int32 { + if m != nil { + return m.NextSeq + } + return 0 +} + +type GetGroupMemberListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + MemberList []*sdk_ws.GroupMemberFullInfo `protobuf:"bytes,3,rep,name=memberList" json:"memberList,omitempty"` + NextSeq int32 `protobuf:"varint,4,opt,name=nextSeq" json:"nextSeq,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMemberListResp) Reset() { *m = GetGroupMemberListResp{} } +func (m *GetGroupMemberListResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupMemberListResp) ProtoMessage() {} +func (*GetGroupMemberListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{21} +} +func (m *GetGroupMemberListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMemberListResp.Unmarshal(m, b) +} +func (m *GetGroupMemberListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMemberListResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupMemberListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMemberListResp.Merge(dst, src) +} +func (m *GetGroupMemberListResp) XXX_Size() int { + return xxx_messageInfo_GetGroupMemberListResp.Size(m) +} +func (m *GetGroupMemberListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMemberListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMemberListResp proto.InternalMessageInfo + +func (m *GetGroupMemberListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetGroupMemberListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetGroupMemberListResp) GetMemberList() []*sdk_ws.GroupMemberFullInfo { + if m != nil { + return m.MemberList + } + return nil +} + +func (m *GetGroupMemberListResp) GetNextSeq() int32 { + if m != nil { + return m.NextSeq + } + return 0 +} + +type GetGroupMembersInfoReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + MemberList []string `protobuf:"bytes,2,rep,name=memberList" json:"memberList,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMembersInfoReq) Reset() { *m = GetGroupMembersInfoReq{} } +func (m *GetGroupMembersInfoReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupMembersInfoReq) ProtoMessage() {} +func (*GetGroupMembersInfoReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{22} +} +func (m *GetGroupMembersInfoReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMembersInfoReq.Unmarshal(m, b) +} +func (m *GetGroupMembersInfoReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMembersInfoReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupMembersInfoReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMembersInfoReq.Merge(dst, src) +} +func (m *GetGroupMembersInfoReq) XXX_Size() int { + return xxx_messageInfo_GetGroupMembersInfoReq.Size(m) +} +func (m *GetGroupMembersInfoReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMembersInfoReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMembersInfoReq proto.InternalMessageInfo + +func (m *GetGroupMembersInfoReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *GetGroupMembersInfoReq) GetMemberList() []string { + if m != nil { + return m.MemberList + } + return nil +} + +func (m *GetGroupMembersInfoReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetGroupMembersInfoReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetGroupMembersInfoResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + MemberList []*sdk_ws.GroupMemberFullInfo `protobuf:"bytes,3,rep,name=memberList" json:"memberList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMembersInfoResp) Reset() { *m = GetGroupMembersInfoResp{} } +func (m *GetGroupMembersInfoResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupMembersInfoResp) ProtoMessage() {} +func (*GetGroupMembersInfoResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{23} +} +func (m *GetGroupMembersInfoResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMembersInfoResp.Unmarshal(m, b) +} +func (m *GetGroupMembersInfoResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMembersInfoResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupMembersInfoResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMembersInfoResp.Merge(dst, src) +} +func (m *GetGroupMembersInfoResp) XXX_Size() int { + return xxx_messageInfo_GetGroupMembersInfoResp.Size(m) +} +func (m *GetGroupMembersInfoResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMembersInfoResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMembersInfoResp proto.InternalMessageInfo + +func (m *GetGroupMembersInfoResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetGroupMembersInfoResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetGroupMembersInfoResp) GetMemberList() []*sdk_ws.GroupMemberFullInfo { + if m != nil { + return m.MemberList + } + return nil +} + +type KickGroupMemberReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + KickedUserIDList []string `protobuf:"bytes,2,rep,name=KickedUserIDList" json:"KickedUserIDList,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=Reason" json:"Reason,omitempty"` + OperationID string `protobuf:"bytes,5,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserID string `protobuf:"bytes,6,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KickGroupMemberReq) Reset() { *m = KickGroupMemberReq{} } +func (m *KickGroupMemberReq) String() string { return proto.CompactTextString(m) } +func (*KickGroupMemberReq) ProtoMessage() {} +func (*KickGroupMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{24} +} +func (m *KickGroupMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KickGroupMemberReq.Unmarshal(m, b) +} +func (m *KickGroupMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KickGroupMemberReq.Marshal(b, m, deterministic) +} +func (dst *KickGroupMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_KickGroupMemberReq.Merge(dst, src) +} +func (m *KickGroupMemberReq) XXX_Size() int { + return xxx_messageInfo_KickGroupMemberReq.Size(m) +} +func (m *KickGroupMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_KickGroupMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_KickGroupMemberReq proto.InternalMessageInfo + +func (m *KickGroupMemberReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *KickGroupMemberReq) GetKickedUserIDList() []string { + if m != nil { + return m.KickedUserIDList + } + return nil +} + +func (m *KickGroupMemberReq) GetReason() string { + if m != nil { + return m.Reason + } + return "" +} + +func (m *KickGroupMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *KickGroupMemberReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type Id2Result struct { + UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` + Result int32 `protobuf:"varint,2,opt,name=Result" json:"Result,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Id2Result) Reset() { *m = Id2Result{} } +func (m *Id2Result) String() string { return proto.CompactTextString(m) } +func (*Id2Result) ProtoMessage() {} +func (*Id2Result) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{25} +} +func (m *Id2Result) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Id2Result.Unmarshal(m, b) +} +func (m *Id2Result) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Id2Result.Marshal(b, m, deterministic) +} +func (dst *Id2Result) XXX_Merge(src proto.Message) { + xxx_messageInfo_Id2Result.Merge(dst, src) +} +func (m *Id2Result) XXX_Size() int { + return xxx_messageInfo_Id2Result.Size(m) +} +func (m *Id2Result) XXX_DiscardUnknown() { + xxx_messageInfo_Id2Result.DiscardUnknown(m) +} + +var xxx_messageInfo_Id2Result proto.InternalMessageInfo + +func (m *Id2Result) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *Id2Result) GetResult() int32 { + if m != nil { + return m.Result + } + return 0 +} + +type KickGroupMemberResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + Id2ResultList []*Id2Result `protobuf:"bytes,3,rep,name=Id2ResultList" json:"Id2ResultList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KickGroupMemberResp) Reset() { *m = KickGroupMemberResp{} } +func (m *KickGroupMemberResp) String() string { return proto.CompactTextString(m) } +func (*KickGroupMemberResp) ProtoMessage() {} +func (*KickGroupMemberResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{26} +} +func (m *KickGroupMemberResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KickGroupMemberResp.Unmarshal(m, b) +} +func (m *KickGroupMemberResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KickGroupMemberResp.Marshal(b, m, deterministic) +} +func (dst *KickGroupMemberResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_KickGroupMemberResp.Merge(dst, src) +} +func (m *KickGroupMemberResp) XXX_Size() int { + return xxx_messageInfo_KickGroupMemberResp.Size(m) +} +func (m *KickGroupMemberResp) XXX_DiscardUnknown() { + xxx_messageInfo_KickGroupMemberResp.DiscardUnknown(m) +} + +var xxx_messageInfo_KickGroupMemberResp proto.InternalMessageInfo + +func (m *KickGroupMemberResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *KickGroupMemberResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *KickGroupMemberResp) GetId2ResultList() []*Id2Result { + if m != nil { + return m.Id2ResultList + } + return nil +} + +type GetJoinedGroupListReq struct { + FromUserID string `protobuf:"bytes,1,opt,name=FromUserID" json:"FromUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetJoinedGroupListReq) Reset() { *m = GetJoinedGroupListReq{} } +func (m *GetJoinedGroupListReq) String() string { return proto.CompactTextString(m) } +func (*GetJoinedGroupListReq) ProtoMessage() {} +func (*GetJoinedGroupListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{27} +} +func (m *GetJoinedGroupListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetJoinedGroupListReq.Unmarshal(m, b) +} +func (m *GetJoinedGroupListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetJoinedGroupListReq.Marshal(b, m, deterministic) +} +func (dst *GetJoinedGroupListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetJoinedGroupListReq.Merge(dst, src) +} +func (m *GetJoinedGroupListReq) XXX_Size() int { + return xxx_messageInfo_GetJoinedGroupListReq.Size(m) +} +func (m *GetJoinedGroupListReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetJoinedGroupListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetJoinedGroupListReq proto.InternalMessageInfo + +func (m *GetJoinedGroupListReq) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +func (m *GetJoinedGroupListReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetJoinedGroupListReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type GetJoinedGroupListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + GroupList []*sdk_ws.GroupInfo `protobuf:"bytes,3,rep,name=GroupList" json:"GroupList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetJoinedGroupListResp) Reset() { *m = GetJoinedGroupListResp{} } +func (m *GetJoinedGroupListResp) String() string { return proto.CompactTextString(m) } +func (*GetJoinedGroupListResp) ProtoMessage() {} +func (*GetJoinedGroupListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{28} +} +func (m *GetJoinedGroupListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetJoinedGroupListResp.Unmarshal(m, b) +} +func (m *GetJoinedGroupListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetJoinedGroupListResp.Marshal(b, m, deterministic) +} +func (dst *GetJoinedGroupListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetJoinedGroupListResp.Merge(dst, src) +} +func (m *GetJoinedGroupListResp) XXX_Size() int { + return xxx_messageInfo_GetJoinedGroupListResp.Size(m) +} +func (m *GetJoinedGroupListResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetJoinedGroupListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetJoinedGroupListResp proto.InternalMessageInfo + +func (m *GetJoinedGroupListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetJoinedGroupListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetJoinedGroupListResp) GetGroupList() []*sdk_ws.GroupInfo { + if m != nil { + return m.GroupList + } + return nil +} + +type InviteUserToGroupReq struct { + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=GroupID" json:"GroupID,omitempty"` + Reason string `protobuf:"bytes,4,opt,name=Reason" json:"Reason,omitempty"` + InvitedUserIDList []string `protobuf:"bytes,5,rep,name=InvitedUserIDList" json:"InvitedUserIDList,omitempty"` + OpUserID string `protobuf:"bytes,6,opt,name=OpUserID" json:"OpUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InviteUserToGroupReq) Reset() { *m = InviteUserToGroupReq{} } +func (m *InviteUserToGroupReq) String() string { return proto.CompactTextString(m) } +func (*InviteUserToGroupReq) ProtoMessage() {} +func (*InviteUserToGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{29} +} +func (m *InviteUserToGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InviteUserToGroupReq.Unmarshal(m, b) +} +func (m *InviteUserToGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InviteUserToGroupReq.Marshal(b, m, deterministic) +} +func (dst *InviteUserToGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_InviteUserToGroupReq.Merge(dst, src) +} +func (m *InviteUserToGroupReq) XXX_Size() int { + return xxx_messageInfo_InviteUserToGroupReq.Size(m) +} +func (m *InviteUserToGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_InviteUserToGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_InviteUserToGroupReq proto.InternalMessageInfo + +func (m *InviteUserToGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *InviteUserToGroupReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *InviteUserToGroupReq) GetReason() string { + if m != nil { + return m.Reason + } + return "" +} + +func (m *InviteUserToGroupReq) GetInvitedUserIDList() []string { + if m != nil { + return m.InvitedUserIDList + } + return nil +} + +func (m *InviteUserToGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type InviteUserToGroupResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + Id2ResultList []*Id2Result `protobuf:"bytes,3,rep,name=Id2ResultList" json:"Id2ResultList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InviteUserToGroupResp) Reset() { *m = InviteUserToGroupResp{} } +func (m *InviteUserToGroupResp) String() string { return proto.CompactTextString(m) } +func (*InviteUserToGroupResp) ProtoMessage() {} +func (*InviteUserToGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{30} +} +func (m *InviteUserToGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InviteUserToGroupResp.Unmarshal(m, b) +} +func (m *InviteUserToGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InviteUserToGroupResp.Marshal(b, m, deterministic) +} +func (dst *InviteUserToGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_InviteUserToGroupResp.Merge(dst, src) +} +func (m *InviteUserToGroupResp) XXX_Size() int { + return xxx_messageInfo_InviteUserToGroupResp.Size(m) +} +func (m *InviteUserToGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_InviteUserToGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_InviteUserToGroupResp proto.InternalMessageInfo + +func (m *InviteUserToGroupResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *InviteUserToGroupResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *InviteUserToGroupResp) GetId2ResultList() []*Id2Result { + if m != nil { + return m.Id2ResultList + } + return nil +} + +type GetGroupAllMemberReq struct { + GroupID string `protobuf:"bytes,1,opt,name=GroupID" json:"GroupID,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupAllMemberReq) Reset() { *m = GetGroupAllMemberReq{} } +func (m *GetGroupAllMemberReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupAllMemberReq) ProtoMessage() {} +func (*GetGroupAllMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{31} +} +func (m *GetGroupAllMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupAllMemberReq.Unmarshal(m, b) +} +func (m *GetGroupAllMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupAllMemberReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupAllMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupAllMemberReq.Merge(dst, src) +} +func (m *GetGroupAllMemberReq) XXX_Size() int { + return xxx_messageInfo_GetGroupAllMemberReq.Size(m) +} +func (m *GetGroupAllMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupAllMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupAllMemberReq proto.InternalMessageInfo + +func (m *GetGroupAllMemberReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *GetGroupAllMemberReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetGroupAllMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetGroupAllMemberResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=ErrCode" json:"ErrCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=ErrMsg" json:"ErrMsg,omitempty"` + MemberList []*sdk_ws.GroupMemberFullInfo `protobuf:"bytes,3,rep,name=memberList" json:"memberList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupAllMemberResp) Reset() { *m = GetGroupAllMemberResp{} } +func (m *GetGroupAllMemberResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupAllMemberResp) ProtoMessage() {} +func (*GetGroupAllMemberResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{32} +} +func (m *GetGroupAllMemberResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupAllMemberResp.Unmarshal(m, b) +} +func (m *GetGroupAllMemberResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupAllMemberResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupAllMemberResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupAllMemberResp.Merge(dst, src) +} +func (m *GetGroupAllMemberResp) XXX_Size() int { + return xxx_messageInfo_GetGroupAllMemberResp.Size(m) +} +func (m *GetGroupAllMemberResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupAllMemberResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupAllMemberResp proto.InternalMessageInfo + +func (m *GetGroupAllMemberResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetGroupAllMemberResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetGroupAllMemberResp) GetMemberList() []*sdk_ws.GroupMemberFullInfo { + if m != nil { + return m.MemberList + } + return nil +} + +type CMSGroup struct { + GroupInfo *sdk_ws.GroupInfo `protobuf:"bytes,1,opt,name=GroupInfo" json:"GroupInfo,omitempty"` + GroupMasterName string `protobuf:"bytes,2,opt,name=GroupMasterName" json:"GroupMasterName,omitempty"` + GroupMasterId string `protobuf:"bytes,3,opt,name=GroupMasterId" json:"GroupMasterId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CMSGroup) Reset() { *m = CMSGroup{} } +func (m *CMSGroup) String() string { return proto.CompactTextString(m) } +func (*CMSGroup) ProtoMessage() {} +func (*CMSGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{33} +} +func (m *CMSGroup) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CMSGroup.Unmarshal(m, b) +} +func (m *CMSGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CMSGroup.Marshal(b, m, deterministic) +} +func (dst *CMSGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_CMSGroup.Merge(dst, src) +} +func (m *CMSGroup) XXX_Size() int { + return xxx_messageInfo_CMSGroup.Size(m) +} +func (m *CMSGroup) XXX_DiscardUnknown() { + xxx_messageInfo_CMSGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_CMSGroup proto.InternalMessageInfo + +func (m *CMSGroup) GetGroupInfo() *sdk_ws.GroupInfo { + if m != nil { + return m.GroupInfo + } + return nil +} + +func (m *CMSGroup) GetGroupMasterName() string { + if m != nil { + return m.GroupMasterName + } + return "" +} + +func (m *CMSGroup) GetGroupMasterId() string { + if m != nil { + return m.GroupMasterId + } + return "" +} + +type GetGroupReq struct { + GroupName string `protobuf:"bytes,1,opt,name=GroupName" json:"GroupName,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupReq) Reset() { *m = GetGroupReq{} } +func (m *GetGroupReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupReq) ProtoMessage() {} +func (*GetGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{34} +} +func (m *GetGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupReq.Unmarshal(m, b) +} +func (m *GetGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupReq.Merge(dst, src) +} +func (m *GetGroupReq) XXX_Size() int { + return xxx_messageInfo_GetGroupReq.Size(m) +} +func (m *GetGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupReq proto.InternalMessageInfo + +func (m *GetGroupReq) GetGroupName() string { + if m != nil { + return m.GroupName + } + return "" +} + +func (m *GetGroupReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetGroupResp struct { + CMSGroups []*CMSGroup `protobuf:"bytes,1,rep,name=CMSGroups" json:"CMSGroups,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + GroupNums int32 `protobuf:"varint,3,opt,name=GroupNums" json:"GroupNums,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupResp) Reset() { *m = GetGroupResp{} } +func (m *GetGroupResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupResp) ProtoMessage() {} +func (*GetGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{35} +} +func (m *GetGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupResp.Unmarshal(m, b) +} +func (m *GetGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupResp.Merge(dst, src) +} +func (m *GetGroupResp) XXX_Size() int { + return xxx_messageInfo_GetGroupResp.Size(m) +} +func (m *GetGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupResp proto.InternalMessageInfo + +func (m *GetGroupResp) GetCMSGroups() []*CMSGroup { + if m != nil { + return m.CMSGroups + } + return nil +} + +func (m *GetGroupResp) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetGroupResp) GetGroupNums() int32 { + if m != nil { + return m.GroupNums + } + return 0 +} + +type GetGroupsReq struct { + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,1,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupsReq) Reset() { *m = GetGroupsReq{} } +func (m *GetGroupsReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupsReq) ProtoMessage() {} +func (*GetGroupsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{36} +} +func (m *GetGroupsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupsReq.Unmarshal(m, b) +} +func (m *GetGroupsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupsReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupsReq.Merge(dst, src) +} +func (m *GetGroupsReq) XXX_Size() int { + return xxx_messageInfo_GetGroupsReq.Size(m) +} +func (m *GetGroupsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupsReq proto.InternalMessageInfo + +func (m *GetGroupsReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetGroupsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetGroupsResp struct { + CMSGroups []*CMSGroup `protobuf:"bytes,1,rep,name=CMSGroups" json:"CMSGroups,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + GroupNum int32 `protobuf:"varint,3,opt,name=GroupNum" json:"GroupNum,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupsResp) Reset() { *m = GetGroupsResp{} } +func (m *GetGroupsResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupsResp) ProtoMessage() {} +func (*GetGroupsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{37} +} +func (m *GetGroupsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupsResp.Unmarshal(m, b) +} +func (m *GetGroupsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupsResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupsResp.Merge(dst, src) +} +func (m *GetGroupsResp) XXX_Size() int { + return xxx_messageInfo_GetGroupsResp.Size(m) +} +func (m *GetGroupsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupsResp proto.InternalMessageInfo + +func (m *GetGroupsResp) GetCMSGroups() []*CMSGroup { + if m != nil { + return m.CMSGroups + } + return nil +} + +func (m *GetGroupsResp) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetGroupsResp) GetGroupNum() int32 { + if m != nil { + return m.GroupNum + } + return 0 +} + +type GetGroupMemberReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMemberReq) Reset() { *m = GetGroupMemberReq{} } +func (m *GetGroupMemberReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupMemberReq) ProtoMessage() {} +func (*GetGroupMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{38} +} +func (m *GetGroupMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMemberReq.Unmarshal(m, b) +} +func (m *GetGroupMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMemberReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMemberReq.Merge(dst, src) +} +func (m *GetGroupMemberReq) XXX_Size() int { + return xxx_messageInfo_GetGroupMemberReq.Size(m) +} +func (m *GetGroupMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMemberReq proto.InternalMessageInfo + +func (m *GetGroupMemberReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *GetGroupMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type OperateGroupStatusReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + Status int32 `protobuf:"varint,2,opt,name=Status" json:"Status,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OperateGroupStatusReq) Reset() { *m = OperateGroupStatusReq{} } +func (m *OperateGroupStatusReq) String() string { return proto.CompactTextString(m) } +func (*OperateGroupStatusReq) ProtoMessage() {} +func (*OperateGroupStatusReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{39} +} +func (m *OperateGroupStatusReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OperateGroupStatusReq.Unmarshal(m, b) +} +func (m *OperateGroupStatusReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OperateGroupStatusReq.Marshal(b, m, deterministic) +} +func (dst *OperateGroupStatusReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperateGroupStatusReq.Merge(dst, src) +} +func (m *OperateGroupStatusReq) XXX_Size() int { + return xxx_messageInfo_OperateGroupStatusReq.Size(m) +} +func (m *OperateGroupStatusReq) XXX_DiscardUnknown() { + xxx_messageInfo_OperateGroupStatusReq.DiscardUnknown(m) +} + +var xxx_messageInfo_OperateGroupStatusReq proto.InternalMessageInfo + +func (m *OperateGroupStatusReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *OperateGroupStatusReq) GetStatus() int32 { + if m != nil { + return m.Status + } + return 0 +} + +func (m *OperateGroupStatusReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type OperateGroupStatusResp struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OperateGroupStatusResp) Reset() { *m = OperateGroupStatusResp{} } +func (m *OperateGroupStatusResp) String() string { return proto.CompactTextString(m) } +func (*OperateGroupStatusResp) ProtoMessage() {} +func (*OperateGroupStatusResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{40} +} +func (m *OperateGroupStatusResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OperateGroupStatusResp.Unmarshal(m, b) +} +func (m *OperateGroupStatusResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OperateGroupStatusResp.Marshal(b, m, deterministic) +} +func (dst *OperateGroupStatusResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperateGroupStatusResp.Merge(dst, src) +} +func (m *OperateGroupStatusResp) XXX_Size() int { + return xxx_messageInfo_OperateGroupStatusResp.Size(m) +} +func (m *OperateGroupStatusResp) XXX_DiscardUnknown() { + xxx_messageInfo_OperateGroupStatusResp.DiscardUnknown(m) +} + +var xxx_messageInfo_OperateGroupStatusResp proto.InternalMessageInfo + +type OperateUserRoleReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + UserId string `protobuf:"bytes,2,opt,name=UserId" json:"UserId,omitempty"` + RoleLevel int32 `protobuf:"varint,3,opt,name=RoleLevel" json:"RoleLevel,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OperateUserRoleReq) Reset() { *m = OperateUserRoleReq{} } +func (m *OperateUserRoleReq) String() string { return proto.CompactTextString(m) } +func (*OperateUserRoleReq) ProtoMessage() {} +func (*OperateUserRoleReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{41} +} +func (m *OperateUserRoleReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OperateUserRoleReq.Unmarshal(m, b) +} +func (m *OperateUserRoleReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OperateUserRoleReq.Marshal(b, m, deterministic) +} +func (dst *OperateUserRoleReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperateUserRoleReq.Merge(dst, src) +} +func (m *OperateUserRoleReq) XXX_Size() int { + return xxx_messageInfo_OperateUserRoleReq.Size(m) +} +func (m *OperateUserRoleReq) XXX_DiscardUnknown() { + xxx_messageInfo_OperateUserRoleReq.DiscardUnknown(m) +} + +var xxx_messageInfo_OperateUserRoleReq proto.InternalMessageInfo + +func (m *OperateUserRoleReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *OperateUserRoleReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *OperateUserRoleReq) GetRoleLevel() int32 { + if m != nil { + return m.RoleLevel + } + return 0 +} + +func (m *OperateUserRoleReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type OperateUserRoleResp struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OperateUserRoleResp) Reset() { *m = OperateUserRoleResp{} } +func (m *OperateUserRoleResp) String() string { return proto.CompactTextString(m) } +func (*OperateUserRoleResp) ProtoMessage() {} +func (*OperateUserRoleResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{42} +} +func (m *OperateUserRoleResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OperateUserRoleResp.Unmarshal(m, b) +} +func (m *OperateUserRoleResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OperateUserRoleResp.Marshal(b, m, deterministic) +} +func (dst *OperateUserRoleResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperateUserRoleResp.Merge(dst, src) +} +func (m *OperateUserRoleResp) XXX_Size() int { + return xxx_messageInfo_OperateUserRoleResp.Size(m) +} +func (m *OperateUserRoleResp) XXX_DiscardUnknown() { + xxx_messageInfo_OperateUserRoleResp.DiscardUnknown(m) +} + +var xxx_messageInfo_OperateUserRoleResp proto.InternalMessageInfo + +type DeleteGroupReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteGroupReq) Reset() { *m = DeleteGroupReq{} } +func (m *DeleteGroupReq) String() string { return proto.CompactTextString(m) } +func (*DeleteGroupReq) ProtoMessage() {} +func (*DeleteGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{43} +} +func (m *DeleteGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteGroupReq.Unmarshal(m, b) +} +func (m *DeleteGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteGroupReq.Marshal(b, m, deterministic) +} +func (dst *DeleteGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteGroupReq.Merge(dst, src) +} +func (m *DeleteGroupReq) XXX_Size() int { + return xxx_messageInfo_DeleteGroupReq.Size(m) +} +func (m *DeleteGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteGroupReq proto.InternalMessageInfo + +func (m *DeleteGroupReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *DeleteGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type DeleteGroupResp struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteGroupResp) Reset() { *m = DeleteGroupResp{} } +func (m *DeleteGroupResp) String() string { return proto.CompactTextString(m) } +func (*DeleteGroupResp) ProtoMessage() {} +func (*DeleteGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{44} +} +func (m *DeleteGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteGroupResp.Unmarshal(m, b) +} +func (m *DeleteGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteGroupResp.Marshal(b, m, deterministic) +} +func (dst *DeleteGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteGroupResp.Merge(dst, src) +} +func (m *DeleteGroupResp) XXX_Size() int { + return xxx_messageInfo_DeleteGroupResp.Size(m) +} +func (m *DeleteGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteGroupResp proto.InternalMessageInfo + +type GetGroupByIdReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupByIdReq) Reset() { *m = GetGroupByIdReq{} } +func (m *GetGroupByIdReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupByIdReq) ProtoMessage() {} +func (*GetGroupByIdReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{45} +} +func (m *GetGroupByIdReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupByIdReq.Unmarshal(m, b) +} +func (m *GetGroupByIdReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupByIdReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupByIdReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupByIdReq.Merge(dst, src) +} +func (m *GetGroupByIdReq) XXX_Size() int { + return xxx_messageInfo_GetGroupByIdReq.Size(m) +} +func (m *GetGroupByIdReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupByIdReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupByIdReq proto.InternalMessageInfo + +func (m *GetGroupByIdReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *GetGroupByIdReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetGroupByIdResp struct { + CMSGroup *CMSGroup `protobuf:"bytes,1,opt,name=CMSGroup" json:"CMSGroup,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupByIdResp) Reset() { *m = GetGroupByIdResp{} } +func (m *GetGroupByIdResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupByIdResp) ProtoMessage() {} +func (*GetGroupByIdResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{46} +} +func (m *GetGroupByIdResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupByIdResp.Unmarshal(m, b) +} +func (m *GetGroupByIdResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupByIdResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupByIdResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupByIdResp.Merge(dst, src) +} +func (m *GetGroupByIdResp) XXX_Size() int { + return xxx_messageInfo_GetGroupByIdResp.Size(m) +} +func (m *GetGroupByIdResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupByIdResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupByIdResp proto.InternalMessageInfo + +func (m *GetGroupByIdResp) GetCMSGroup() *CMSGroup { + if m != nil { + return m.CMSGroup + } + return nil +} + +type GetGroupMembersCMSReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + UserName string `protobuf:"bytes,2,opt,name=UserName" json:"UserName,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMembersCMSReq) Reset() { *m = GetGroupMembersCMSReq{} } +func (m *GetGroupMembersCMSReq) String() string { return proto.CompactTextString(m) } +func (*GetGroupMembersCMSReq) ProtoMessage() {} +func (*GetGroupMembersCMSReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{47} +} +func (m *GetGroupMembersCMSReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMembersCMSReq.Unmarshal(m, b) +} +func (m *GetGroupMembersCMSReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMembersCMSReq.Marshal(b, m, deterministic) +} +func (dst *GetGroupMembersCMSReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMembersCMSReq.Merge(dst, src) +} +func (m *GetGroupMembersCMSReq) XXX_Size() int { + return xxx_messageInfo_GetGroupMembersCMSReq.Size(m) +} +func (m *GetGroupMembersCMSReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMembersCMSReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMembersCMSReq proto.InternalMessageInfo + +func (m *GetGroupMembersCMSReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *GetGroupMembersCMSReq) GetUserName() string { + if m != nil { + return m.UserName + } + return "" +} + +func (m *GetGroupMembersCMSReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetGroupMembersCMSReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetGroupMembersCMSResp struct { + Members []*sdk_ws.GroupMemberFullInfo `protobuf:"bytes,1,rep,name=members" json:"members,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + MemberNums int32 `protobuf:"varint,3,opt,name=MemberNums" json:"MemberNums,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetGroupMembersCMSResp) Reset() { *m = GetGroupMembersCMSResp{} } +func (m *GetGroupMembersCMSResp) String() string { return proto.CompactTextString(m) } +func (*GetGroupMembersCMSResp) ProtoMessage() {} +func (*GetGroupMembersCMSResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{48} +} +func (m *GetGroupMembersCMSResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetGroupMembersCMSResp.Unmarshal(m, b) +} +func (m *GetGroupMembersCMSResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetGroupMembersCMSResp.Marshal(b, m, deterministic) +} +func (dst *GetGroupMembersCMSResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetGroupMembersCMSResp.Merge(dst, src) +} +func (m *GetGroupMembersCMSResp) XXX_Size() int { + return xxx_messageInfo_GetGroupMembersCMSResp.Size(m) +} +func (m *GetGroupMembersCMSResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetGroupMembersCMSResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetGroupMembersCMSResp proto.InternalMessageInfo + +func (m *GetGroupMembersCMSResp) GetMembers() []*sdk_ws.GroupMemberFullInfo { + if m != nil { + return m.Members + } + return nil +} + +func (m *GetGroupMembersCMSResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetGroupMembersCMSResp) GetMemberNums() int32 { + if m != nil { + return m.MemberNums + } + return 0 +} + +type RemoveGroupMembersCMSReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + UserIds []string `protobuf:"bytes,2,rep,name=UserIds" json:"UserIds,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserId string `protobuf:"bytes,4,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveGroupMembersCMSReq) Reset() { *m = RemoveGroupMembersCMSReq{} } +func (m *RemoveGroupMembersCMSReq) String() string { return proto.CompactTextString(m) } +func (*RemoveGroupMembersCMSReq) ProtoMessage() {} +func (*RemoveGroupMembersCMSReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{49} +} +func (m *RemoveGroupMembersCMSReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveGroupMembersCMSReq.Unmarshal(m, b) +} +func (m *RemoveGroupMembersCMSReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveGroupMembersCMSReq.Marshal(b, m, deterministic) +} +func (dst *RemoveGroupMembersCMSReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveGroupMembersCMSReq.Merge(dst, src) +} +func (m *RemoveGroupMembersCMSReq) XXX_Size() int { + return xxx_messageInfo_RemoveGroupMembersCMSReq.Size(m) +} +func (m *RemoveGroupMembersCMSReq) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveGroupMembersCMSReq.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveGroupMembersCMSReq proto.InternalMessageInfo + +func (m *RemoveGroupMembersCMSReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *RemoveGroupMembersCMSReq) GetUserIds() []string { + if m != nil { + return m.UserIds + } + return nil +} + +func (m *RemoveGroupMembersCMSReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *RemoveGroupMembersCMSReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type RemoveGroupMembersCMSResp struct { + Success []string `protobuf:"bytes,1,rep,name=success" json:"success,omitempty"` + Failed []string `protobuf:"bytes,2,rep,name=failed" json:"failed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveGroupMembersCMSResp) Reset() { *m = RemoveGroupMembersCMSResp{} } +func (m *RemoveGroupMembersCMSResp) String() string { return proto.CompactTextString(m) } +func (*RemoveGroupMembersCMSResp) ProtoMessage() {} +func (*RemoveGroupMembersCMSResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{50} +} +func (m *RemoveGroupMembersCMSResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveGroupMembersCMSResp.Unmarshal(m, b) +} +func (m *RemoveGroupMembersCMSResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveGroupMembersCMSResp.Marshal(b, m, deterministic) +} +func (dst *RemoveGroupMembersCMSResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveGroupMembersCMSResp.Merge(dst, src) +} +func (m *RemoveGroupMembersCMSResp) XXX_Size() int { + return xxx_messageInfo_RemoveGroupMembersCMSResp.Size(m) +} +func (m *RemoveGroupMembersCMSResp) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveGroupMembersCMSResp.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveGroupMembersCMSResp proto.InternalMessageInfo + +func (m *RemoveGroupMembersCMSResp) GetSuccess() []string { + if m != nil { + return m.Success + } + return nil +} + +func (m *RemoveGroupMembersCMSResp) GetFailed() []string { + if m != nil { + return m.Failed + } + return nil +} + +type AddGroupMembersCMSReq struct { + GroupId string `protobuf:"bytes,1,opt,name=GroupId" json:"GroupId,omitempty"` + UserIds []string `protobuf:"bytes,2,rep,name=UserIds" json:"UserIds,omitempty"` + OperationId string `protobuf:"bytes,3,opt,name=OperationId" json:"OperationId,omitempty"` + OpUserId string `protobuf:"bytes,4,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddGroupMembersCMSReq) Reset() { *m = AddGroupMembersCMSReq{} } +func (m *AddGroupMembersCMSReq) String() string { return proto.CompactTextString(m) } +func (*AddGroupMembersCMSReq) ProtoMessage() {} +func (*AddGroupMembersCMSReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{51} +} +func (m *AddGroupMembersCMSReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddGroupMembersCMSReq.Unmarshal(m, b) +} +func (m *AddGroupMembersCMSReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddGroupMembersCMSReq.Marshal(b, m, deterministic) +} +func (dst *AddGroupMembersCMSReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddGroupMembersCMSReq.Merge(dst, src) +} +func (m *AddGroupMembersCMSReq) XXX_Size() int { + return xxx_messageInfo_AddGroupMembersCMSReq.Size(m) +} +func (m *AddGroupMembersCMSReq) XXX_DiscardUnknown() { + xxx_messageInfo_AddGroupMembersCMSReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AddGroupMembersCMSReq proto.InternalMessageInfo + +func (m *AddGroupMembersCMSReq) GetGroupId() string { + if m != nil { + return m.GroupId + } + return "" +} + +func (m *AddGroupMembersCMSReq) GetUserIds() []string { + if m != nil { + return m.UserIds + } + return nil +} + +func (m *AddGroupMembersCMSReq) GetOperationId() string { + if m != nil { + return m.OperationId + } + return "" +} + +func (m *AddGroupMembersCMSReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type AddGroupMembersCMSResp struct { + Success []string `protobuf:"bytes,1,rep,name=success" json:"success,omitempty"` + Failed []string `protobuf:"bytes,2,rep,name=failed" json:"failed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddGroupMembersCMSResp) Reset() { *m = AddGroupMembersCMSResp{} } +func (m *AddGroupMembersCMSResp) String() string { return proto.CompactTextString(m) } +func (*AddGroupMembersCMSResp) ProtoMessage() {} +func (*AddGroupMembersCMSResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{52} +} +func (m *AddGroupMembersCMSResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddGroupMembersCMSResp.Unmarshal(m, b) +} +func (m *AddGroupMembersCMSResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddGroupMembersCMSResp.Marshal(b, m, deterministic) +} +func (dst *AddGroupMembersCMSResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddGroupMembersCMSResp.Merge(dst, src) +} +func (m *AddGroupMembersCMSResp) XXX_Size() int { + return xxx_messageInfo_AddGroupMembersCMSResp.Size(m) +} +func (m *AddGroupMembersCMSResp) XXX_DiscardUnknown() { + xxx_messageInfo_AddGroupMembersCMSResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AddGroupMembersCMSResp proto.InternalMessageInfo + +func (m *AddGroupMembersCMSResp) GetSuccess() []string { + if m != nil { + return m.Success + } + return nil +} + +func (m *AddGroupMembersCMSResp) GetFailed() []string { + if m != nil { + return m.Failed + } + return nil +} + +type DismissGroupReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DismissGroupReq) Reset() { *m = DismissGroupReq{} } +func (m *DismissGroupReq) String() string { return proto.CompactTextString(m) } +func (*DismissGroupReq) ProtoMessage() {} +func (*DismissGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{53} +} +func (m *DismissGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DismissGroupReq.Unmarshal(m, b) +} +func (m *DismissGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DismissGroupReq.Marshal(b, m, deterministic) +} +func (dst *DismissGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DismissGroupReq.Merge(dst, src) +} +func (m *DismissGroupReq) XXX_Size() int { + return xxx_messageInfo_DismissGroupReq.Size(m) +} +func (m *DismissGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_DismissGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DismissGroupReq proto.InternalMessageInfo + +func (m *DismissGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *DismissGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *DismissGroupReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +type DismissGroupResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DismissGroupResp) Reset() { *m = DismissGroupResp{} } +func (m *DismissGroupResp) String() string { return proto.CompactTextString(m) } +func (*DismissGroupResp) ProtoMessage() {} +func (*DismissGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{54} +} +func (m *DismissGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DismissGroupResp.Unmarshal(m, b) +} +func (m *DismissGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DismissGroupResp.Marshal(b, m, deterministic) +} +func (dst *DismissGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DismissGroupResp.Merge(dst, src) +} +func (m *DismissGroupResp) XXX_Size() int { + return xxx_messageInfo_DismissGroupResp.Size(m) +} +func (m *DismissGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_DismissGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DismissGroupResp proto.InternalMessageInfo + +func (m *DismissGroupResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type MuteGroupMemberReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` + UserID string `protobuf:"bytes,4,opt,name=userID" json:"userID,omitempty"` + MutedSeconds uint32 `protobuf:"varint,5,opt,name=mutedSeconds" json:"mutedSeconds,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MuteGroupMemberReq) Reset() { *m = MuteGroupMemberReq{} } +func (m *MuteGroupMemberReq) String() string { return proto.CompactTextString(m) } +func (*MuteGroupMemberReq) ProtoMessage() {} +func (*MuteGroupMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{55} +} +func (m *MuteGroupMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MuteGroupMemberReq.Unmarshal(m, b) +} +func (m *MuteGroupMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MuteGroupMemberReq.Marshal(b, m, deterministic) +} +func (dst *MuteGroupMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_MuteGroupMemberReq.Merge(dst, src) +} +func (m *MuteGroupMemberReq) XXX_Size() int { + return xxx_messageInfo_MuteGroupMemberReq.Size(m) +} +func (m *MuteGroupMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_MuteGroupMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_MuteGroupMemberReq proto.InternalMessageInfo + +func (m *MuteGroupMemberReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *MuteGroupMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *MuteGroupMemberReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *MuteGroupMemberReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *MuteGroupMemberReq) GetMutedSeconds() uint32 { + if m != nil { + return m.MutedSeconds + } + return 0 +} + +type MuteGroupMemberResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MuteGroupMemberResp) Reset() { *m = MuteGroupMemberResp{} } +func (m *MuteGroupMemberResp) String() string { return proto.CompactTextString(m) } +func (*MuteGroupMemberResp) ProtoMessage() {} +func (*MuteGroupMemberResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{56} +} +func (m *MuteGroupMemberResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MuteGroupMemberResp.Unmarshal(m, b) +} +func (m *MuteGroupMemberResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MuteGroupMemberResp.Marshal(b, m, deterministic) +} +func (dst *MuteGroupMemberResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_MuteGroupMemberResp.Merge(dst, src) +} +func (m *MuteGroupMemberResp) XXX_Size() int { + return xxx_messageInfo_MuteGroupMemberResp.Size(m) +} +func (m *MuteGroupMemberResp) XXX_DiscardUnknown() { + xxx_messageInfo_MuteGroupMemberResp.DiscardUnknown(m) +} + +var xxx_messageInfo_MuteGroupMemberResp proto.InternalMessageInfo + +func (m *MuteGroupMemberResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type CancelMuteGroupMemberReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` + UserID string `protobuf:"bytes,4,opt,name=userID" json:"userID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CancelMuteGroupMemberReq) Reset() { *m = CancelMuteGroupMemberReq{} } +func (m *CancelMuteGroupMemberReq) String() string { return proto.CompactTextString(m) } +func (*CancelMuteGroupMemberReq) ProtoMessage() {} +func (*CancelMuteGroupMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{57} +} +func (m *CancelMuteGroupMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CancelMuteGroupMemberReq.Unmarshal(m, b) +} +func (m *CancelMuteGroupMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CancelMuteGroupMemberReq.Marshal(b, m, deterministic) +} +func (dst *CancelMuteGroupMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CancelMuteGroupMemberReq.Merge(dst, src) +} +func (m *CancelMuteGroupMemberReq) XXX_Size() int { + return xxx_messageInfo_CancelMuteGroupMemberReq.Size(m) +} +func (m *CancelMuteGroupMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_CancelMuteGroupMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CancelMuteGroupMemberReq proto.InternalMessageInfo + +func (m *CancelMuteGroupMemberReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *CancelMuteGroupMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CancelMuteGroupMemberReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *CancelMuteGroupMemberReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +type CancelMuteGroupMemberResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CancelMuteGroupMemberResp) Reset() { *m = CancelMuteGroupMemberResp{} } +func (m *CancelMuteGroupMemberResp) String() string { return proto.CompactTextString(m) } +func (*CancelMuteGroupMemberResp) ProtoMessage() {} +func (*CancelMuteGroupMemberResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{58} +} +func (m *CancelMuteGroupMemberResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CancelMuteGroupMemberResp.Unmarshal(m, b) +} +func (m *CancelMuteGroupMemberResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CancelMuteGroupMemberResp.Marshal(b, m, deterministic) +} +func (dst *CancelMuteGroupMemberResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CancelMuteGroupMemberResp.Merge(dst, src) +} +func (m *CancelMuteGroupMemberResp) XXX_Size() int { + return xxx_messageInfo_CancelMuteGroupMemberResp.Size(m) +} +func (m *CancelMuteGroupMemberResp) XXX_DiscardUnknown() { + xxx_messageInfo_CancelMuteGroupMemberResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CancelMuteGroupMemberResp proto.InternalMessageInfo + +func (m *CancelMuteGroupMemberResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type MuteGroupReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MuteGroupReq) Reset() { *m = MuteGroupReq{} } +func (m *MuteGroupReq) String() string { return proto.CompactTextString(m) } +func (*MuteGroupReq) ProtoMessage() {} +func (*MuteGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{59} +} +func (m *MuteGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MuteGroupReq.Unmarshal(m, b) +} +func (m *MuteGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MuteGroupReq.Marshal(b, m, deterministic) +} +func (dst *MuteGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_MuteGroupReq.Merge(dst, src) +} +func (m *MuteGroupReq) XXX_Size() int { + return xxx_messageInfo_MuteGroupReq.Size(m) +} +func (m *MuteGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_MuteGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_MuteGroupReq proto.InternalMessageInfo + +func (m *MuteGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *MuteGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *MuteGroupReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +type MuteGroupResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MuteGroupResp) Reset() { *m = MuteGroupResp{} } +func (m *MuteGroupResp) String() string { return proto.CompactTextString(m) } +func (*MuteGroupResp) ProtoMessage() {} +func (*MuteGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{60} +} +func (m *MuteGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MuteGroupResp.Unmarshal(m, b) +} +func (m *MuteGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MuteGroupResp.Marshal(b, m, deterministic) +} +func (dst *MuteGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_MuteGroupResp.Merge(dst, src) +} +func (m *MuteGroupResp) XXX_Size() int { + return xxx_messageInfo_MuteGroupResp.Size(m) +} +func (m *MuteGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_MuteGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_MuteGroupResp proto.InternalMessageInfo + +func (m *MuteGroupResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type CancelMuteGroupReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CancelMuteGroupReq) Reset() { *m = CancelMuteGroupReq{} } +func (m *CancelMuteGroupReq) String() string { return proto.CompactTextString(m) } +func (*CancelMuteGroupReq) ProtoMessage() {} +func (*CancelMuteGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{61} +} +func (m *CancelMuteGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CancelMuteGroupReq.Unmarshal(m, b) +} +func (m *CancelMuteGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CancelMuteGroupReq.Marshal(b, m, deterministic) +} +func (dst *CancelMuteGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CancelMuteGroupReq.Merge(dst, src) +} +func (m *CancelMuteGroupReq) XXX_Size() int { + return xxx_messageInfo_CancelMuteGroupReq.Size(m) +} +func (m *CancelMuteGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_CancelMuteGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CancelMuteGroupReq proto.InternalMessageInfo + +func (m *CancelMuteGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *CancelMuteGroupReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CancelMuteGroupReq) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +type CancelMuteGroupResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CancelMuteGroupResp) Reset() { *m = CancelMuteGroupResp{} } +func (m *CancelMuteGroupResp) String() string { return proto.CompactTextString(m) } +func (*CancelMuteGroupResp) ProtoMessage() {} +func (*CancelMuteGroupResp) Descriptor() ([]byte, []int) { + return fileDescriptor_group_3c77315b028a1402, []int{62} +} +func (m *CancelMuteGroupResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CancelMuteGroupResp.Unmarshal(m, b) +} +func (m *CancelMuteGroupResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CancelMuteGroupResp.Marshal(b, m, deterministic) +} +func (dst *CancelMuteGroupResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CancelMuteGroupResp.Merge(dst, src) +} +func (m *CancelMuteGroupResp) XXX_Size() int { + return xxx_messageInfo_CancelMuteGroupResp.Size(m) +} +func (m *CancelMuteGroupResp) XXX_DiscardUnknown() { + xxx_messageInfo_CancelMuteGroupResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CancelMuteGroupResp proto.InternalMessageInfo + +func (m *CancelMuteGroupResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func init() { + proto.RegisterType((*CommonResp)(nil), "group.CommonResp") + proto.RegisterType((*GroupAddMemberInfo)(nil), "group.GroupAddMemberInfo") + proto.RegisterType((*CreateGroupReq)(nil), "group.CreateGroupReq") + proto.RegisterType((*CreateGroupResp)(nil), "group.CreateGroupResp") + proto.RegisterType((*GetGroupsInfoReq)(nil), "group.GetGroupsInfoReq") + proto.RegisterType((*GetGroupsInfoResp)(nil), "group.GetGroupsInfoResp") + proto.RegisterType((*SetGroupInfoReq)(nil), "group.SetGroupInfoReq") + proto.RegisterType((*SetGroupInfoResp)(nil), "group.SetGroupInfoResp") + proto.RegisterType((*GetGroupApplicationListReq)(nil), "group.GetGroupApplicationListReq") + proto.RegisterType((*GetGroupApplicationListResp)(nil), "group.GetGroupApplicationListResp") + proto.RegisterType((*GetUserReqApplicationListReq)(nil), "group.GetUserReqApplicationListReq") + proto.RegisterType((*GetUserReqApplicationListResp)(nil), "group.GetUserReqApplicationListResp") + proto.RegisterType((*TransferGroupOwnerReq)(nil), "group.TransferGroupOwnerReq") + proto.RegisterType((*TransferGroupOwnerResp)(nil), "group.TransferGroupOwnerResp") + proto.RegisterType((*JoinGroupReq)(nil), "group.JoinGroupReq") + proto.RegisterType((*JoinGroupResp)(nil), "group.JoinGroupResp") + proto.RegisterType((*GroupApplicationResponseReq)(nil), "group.GroupApplicationResponseReq") + proto.RegisterType((*GroupApplicationResponseResp)(nil), "group.GroupApplicationResponseResp") + proto.RegisterType((*QuitGroupReq)(nil), "group.QuitGroupReq") + proto.RegisterType((*QuitGroupResp)(nil), "group.QuitGroupResp") + proto.RegisterType((*GetGroupMemberListReq)(nil), "group.GetGroupMemberListReq") + proto.RegisterType((*GetGroupMemberListResp)(nil), "group.GetGroupMemberListResp") + proto.RegisterType((*GetGroupMembersInfoReq)(nil), "group.GetGroupMembersInfoReq") + proto.RegisterType((*GetGroupMembersInfoResp)(nil), "group.GetGroupMembersInfoResp") + proto.RegisterType((*KickGroupMemberReq)(nil), "group.KickGroupMemberReq") + proto.RegisterType((*Id2Result)(nil), "group.Id2Result") + proto.RegisterType((*KickGroupMemberResp)(nil), "group.KickGroupMemberResp") + proto.RegisterType((*GetJoinedGroupListReq)(nil), "group.GetJoinedGroupListReq") + proto.RegisterType((*GetJoinedGroupListResp)(nil), "group.GetJoinedGroupListResp") + proto.RegisterType((*InviteUserToGroupReq)(nil), "group.InviteUserToGroupReq") + proto.RegisterType((*InviteUserToGroupResp)(nil), "group.InviteUserToGroupResp") + proto.RegisterType((*GetGroupAllMemberReq)(nil), "group.GetGroupAllMemberReq") + proto.RegisterType((*GetGroupAllMemberResp)(nil), "group.GetGroupAllMemberResp") + proto.RegisterType((*CMSGroup)(nil), "group.CMSGroup") + proto.RegisterType((*GetGroupReq)(nil), "group.GetGroupReq") + proto.RegisterType((*GetGroupResp)(nil), "group.GetGroupResp") + proto.RegisterType((*GetGroupsReq)(nil), "group.GetGroupsReq") + proto.RegisterType((*GetGroupsResp)(nil), "group.GetGroupsResp") + proto.RegisterType((*GetGroupMemberReq)(nil), "group.GetGroupMemberReq") + proto.RegisterType((*OperateGroupStatusReq)(nil), "group.OperateGroupStatusReq") + proto.RegisterType((*OperateGroupStatusResp)(nil), "group.OperateGroupStatusResp") + proto.RegisterType((*OperateUserRoleReq)(nil), "group.OperateUserRoleReq") + proto.RegisterType((*OperateUserRoleResp)(nil), "group.OperateUserRoleResp") + proto.RegisterType((*DeleteGroupReq)(nil), "group.DeleteGroupReq") + proto.RegisterType((*DeleteGroupResp)(nil), "group.DeleteGroupResp") + proto.RegisterType((*GetGroupByIdReq)(nil), "group.GetGroupByIdReq") + proto.RegisterType((*GetGroupByIdResp)(nil), "group.GetGroupByIdResp") + proto.RegisterType((*GetGroupMembersCMSReq)(nil), "group.GetGroupMembersCMSReq") + proto.RegisterType((*GetGroupMembersCMSResp)(nil), "group.GetGroupMembersCMSResp") + proto.RegisterType((*RemoveGroupMembersCMSReq)(nil), "group.RemoveGroupMembersCMSReq") + proto.RegisterType((*RemoveGroupMembersCMSResp)(nil), "group.RemoveGroupMembersCMSResp") + proto.RegisterType((*AddGroupMembersCMSReq)(nil), "group.AddGroupMembersCMSReq") + proto.RegisterType((*AddGroupMembersCMSResp)(nil), "group.AddGroupMembersCMSResp") + proto.RegisterType((*DismissGroupReq)(nil), "group.DismissGroupReq") + proto.RegisterType((*DismissGroupResp)(nil), "group.DismissGroupResp") + proto.RegisterType((*MuteGroupMemberReq)(nil), "group.MuteGroupMemberReq") + proto.RegisterType((*MuteGroupMemberResp)(nil), "group.MuteGroupMemberResp") + proto.RegisterType((*CancelMuteGroupMemberReq)(nil), "group.CancelMuteGroupMemberReq") + proto.RegisterType((*CancelMuteGroupMemberResp)(nil), "group.CancelMuteGroupMemberResp") + proto.RegisterType((*MuteGroupReq)(nil), "group.MuteGroupReq") + proto.RegisterType((*MuteGroupResp)(nil), "group.MuteGroupResp") + proto.RegisterType((*CancelMuteGroupReq)(nil), "group.CancelMuteGroupReq") + proto.RegisterType((*CancelMuteGroupResp)(nil), "group.CancelMuteGroupResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Group service + +type GroupClient interface { + CreateGroup(ctx context.Context, in *CreateGroupReq, opts ...grpc.CallOption) (*CreateGroupResp, error) + JoinGroup(ctx context.Context, in *JoinGroupReq, opts ...grpc.CallOption) (*JoinGroupResp, error) + QuitGroup(ctx context.Context, in *QuitGroupReq, opts ...grpc.CallOption) (*QuitGroupResp, error) + GetGroupsInfo(ctx context.Context, in *GetGroupsInfoReq, opts ...grpc.CallOption) (*GetGroupsInfoResp, error) + SetGroupInfo(ctx context.Context, in *SetGroupInfoReq, opts ...grpc.CallOption) (*SetGroupInfoResp, error) + GetGroupApplicationList(ctx context.Context, in *GetGroupApplicationListReq, opts ...grpc.CallOption) (*GetGroupApplicationListResp, error) + GetUserReqApplicationList(ctx context.Context, in *GetUserReqApplicationListReq, opts ...grpc.CallOption) (*GetUserReqApplicationListResp, error) + TransferGroupOwner(ctx context.Context, in *TransferGroupOwnerReq, opts ...grpc.CallOption) (*TransferGroupOwnerResp, error) + GroupApplicationResponse(ctx context.Context, in *GroupApplicationResponseReq, opts ...grpc.CallOption) (*GroupApplicationResponseResp, error) + GetGroupMemberList(ctx context.Context, in *GetGroupMemberListReq, opts ...grpc.CallOption) (*GetGroupMemberListResp, error) + GetGroupMembersInfo(ctx context.Context, in *GetGroupMembersInfoReq, opts ...grpc.CallOption) (*GetGroupMembersInfoResp, error) + KickGroupMember(ctx context.Context, in *KickGroupMemberReq, opts ...grpc.CallOption) (*KickGroupMemberResp, error) + GetJoinedGroupList(ctx context.Context, in *GetJoinedGroupListReq, opts ...grpc.CallOption) (*GetJoinedGroupListResp, error) + InviteUserToGroup(ctx context.Context, in *InviteUserToGroupReq, opts ...grpc.CallOption) (*InviteUserToGroupResp, error) + GetGroupAllMember(ctx context.Context, in *GetGroupAllMemberReq, opts ...grpc.CallOption) (*GetGroupAllMemberResp, error) + GetGroupById(ctx context.Context, in *GetGroupByIdReq, opts ...grpc.CallOption) (*GetGroupByIdResp, error) + GetGroup(ctx context.Context, in *GetGroupReq, opts ...grpc.CallOption) (*GetGroupResp, error) + GetGroups(ctx context.Context, in *GetGroupsReq, opts ...grpc.CallOption) (*GetGroupsResp, error) + OperateGroupStatus(ctx context.Context, in *OperateGroupStatusReq, opts ...grpc.CallOption) (*OperateGroupStatusResp, error) + OperateUserRole(ctx context.Context, in *OperateUserRoleReq, opts ...grpc.CallOption) (*OperateUserRoleResp, error) + DeleteGroup(ctx context.Context, in *DeleteGroupReq, opts ...grpc.CallOption) (*DeleteGroupResp, error) + GetGroupMembersCMS(ctx context.Context, in *GetGroupMembersCMSReq, opts ...grpc.CallOption) (*GetGroupMembersCMSResp, error) + RemoveGroupMembersCMS(ctx context.Context, in *RemoveGroupMembersCMSReq, opts ...grpc.CallOption) (*RemoveGroupMembersCMSResp, error) + AddGroupMembersCMS(ctx context.Context, in *AddGroupMembersCMSReq, opts ...grpc.CallOption) (*AddGroupMembersCMSResp, error) + DismissGroup(ctx context.Context, in *DismissGroupReq, opts ...grpc.CallOption) (*DismissGroupResp, error) + MuteGroupMember(ctx context.Context, in *MuteGroupMemberReq, opts ...grpc.CallOption) (*MuteGroupMemberResp, error) + CancelMuteGroupMember(ctx context.Context, in *CancelMuteGroupMemberReq, opts ...grpc.CallOption) (*CancelMuteGroupMemberResp, error) + MuteGroup(ctx context.Context, in *MuteGroupReq, opts ...grpc.CallOption) (*MuteGroupResp, error) + CancelMuteGroup(ctx context.Context, in *CancelMuteGroupReq, opts ...grpc.CallOption) (*CancelMuteGroupResp, error) +} + +type groupClient struct { + cc *grpc.ClientConn +} + +func NewGroupClient(cc *grpc.ClientConn) GroupClient { + return &groupClient{cc} +} + +func (c *groupClient) CreateGroup(ctx context.Context, in *CreateGroupReq, opts ...grpc.CallOption) (*CreateGroupResp, error) { + out := new(CreateGroupResp) + err := grpc.Invoke(ctx, "/group.group/createGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) JoinGroup(ctx context.Context, in *JoinGroupReq, opts ...grpc.CallOption) (*JoinGroupResp, error) { + out := new(JoinGroupResp) + err := grpc.Invoke(ctx, "/group.group/joinGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) QuitGroup(ctx context.Context, in *QuitGroupReq, opts ...grpc.CallOption) (*QuitGroupResp, error) { + out := new(QuitGroupResp) + err := grpc.Invoke(ctx, "/group.group/quitGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupsInfo(ctx context.Context, in *GetGroupsInfoReq, opts ...grpc.CallOption) (*GetGroupsInfoResp, error) { + out := new(GetGroupsInfoResp) + err := grpc.Invoke(ctx, "/group.group/getGroupsInfo", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) SetGroupInfo(ctx context.Context, in *SetGroupInfoReq, opts ...grpc.CallOption) (*SetGroupInfoResp, error) { + out := new(SetGroupInfoResp) + err := grpc.Invoke(ctx, "/group.group/setGroupInfo", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupApplicationList(ctx context.Context, in *GetGroupApplicationListReq, opts ...grpc.CallOption) (*GetGroupApplicationListResp, error) { + out := new(GetGroupApplicationListResp) + err := grpc.Invoke(ctx, "/group.group/getGroupApplicationList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetUserReqApplicationList(ctx context.Context, in *GetUserReqApplicationListReq, opts ...grpc.CallOption) (*GetUserReqApplicationListResp, error) { + out := new(GetUserReqApplicationListResp) + err := grpc.Invoke(ctx, "/group.group/getUserReqApplicationList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) TransferGroupOwner(ctx context.Context, in *TransferGroupOwnerReq, opts ...grpc.CallOption) (*TransferGroupOwnerResp, error) { + out := new(TransferGroupOwnerResp) + err := grpc.Invoke(ctx, "/group.group/transferGroupOwner", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GroupApplicationResponse(ctx context.Context, in *GroupApplicationResponseReq, opts ...grpc.CallOption) (*GroupApplicationResponseResp, error) { + out := new(GroupApplicationResponseResp) + err := grpc.Invoke(ctx, "/group.group/groupApplicationResponse", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupMemberList(ctx context.Context, in *GetGroupMemberListReq, opts ...grpc.CallOption) (*GetGroupMemberListResp, error) { + out := new(GetGroupMemberListResp) + err := grpc.Invoke(ctx, "/group.group/getGroupMemberList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupMembersInfo(ctx context.Context, in *GetGroupMembersInfoReq, opts ...grpc.CallOption) (*GetGroupMembersInfoResp, error) { + out := new(GetGroupMembersInfoResp) + err := grpc.Invoke(ctx, "/group.group/getGroupMembersInfo", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) KickGroupMember(ctx context.Context, in *KickGroupMemberReq, opts ...grpc.CallOption) (*KickGroupMemberResp, error) { + out := new(KickGroupMemberResp) + err := grpc.Invoke(ctx, "/group.group/kickGroupMember", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetJoinedGroupList(ctx context.Context, in *GetJoinedGroupListReq, opts ...grpc.CallOption) (*GetJoinedGroupListResp, error) { + out := new(GetJoinedGroupListResp) + err := grpc.Invoke(ctx, "/group.group/getJoinedGroupList", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) InviteUserToGroup(ctx context.Context, in *InviteUserToGroupReq, opts ...grpc.CallOption) (*InviteUserToGroupResp, error) { + out := new(InviteUserToGroupResp) + err := grpc.Invoke(ctx, "/group.group/inviteUserToGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupAllMember(ctx context.Context, in *GetGroupAllMemberReq, opts ...grpc.CallOption) (*GetGroupAllMemberResp, error) { + out := new(GetGroupAllMemberResp) + err := grpc.Invoke(ctx, "/group.group/getGroupAllMember", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupById(ctx context.Context, in *GetGroupByIdReq, opts ...grpc.CallOption) (*GetGroupByIdResp, error) { + out := new(GetGroupByIdResp) + err := grpc.Invoke(ctx, "/group.group/GetGroupById", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroup(ctx context.Context, in *GetGroupReq, opts ...grpc.CallOption) (*GetGroupResp, error) { + out := new(GetGroupResp) + err := grpc.Invoke(ctx, "/group.group/GetGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroups(ctx context.Context, in *GetGroupsReq, opts ...grpc.CallOption) (*GetGroupsResp, error) { + out := new(GetGroupsResp) + err := grpc.Invoke(ctx, "/group.group/GetGroups", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) OperateGroupStatus(ctx context.Context, in *OperateGroupStatusReq, opts ...grpc.CallOption) (*OperateGroupStatusResp, error) { + out := new(OperateGroupStatusResp) + err := grpc.Invoke(ctx, "/group.group/OperateGroupStatus", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) OperateUserRole(ctx context.Context, in *OperateUserRoleReq, opts ...grpc.CallOption) (*OperateUserRoleResp, error) { + out := new(OperateUserRoleResp) + err := grpc.Invoke(ctx, "/group.group/OperateUserRole", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) DeleteGroup(ctx context.Context, in *DeleteGroupReq, opts ...grpc.CallOption) (*DeleteGroupResp, error) { + out := new(DeleteGroupResp) + err := grpc.Invoke(ctx, "/group.group/DeleteGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) GetGroupMembersCMS(ctx context.Context, in *GetGroupMembersCMSReq, opts ...grpc.CallOption) (*GetGroupMembersCMSResp, error) { + out := new(GetGroupMembersCMSResp) + err := grpc.Invoke(ctx, "/group.group/GetGroupMembersCMS", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) RemoveGroupMembersCMS(ctx context.Context, in *RemoveGroupMembersCMSReq, opts ...grpc.CallOption) (*RemoveGroupMembersCMSResp, error) { + out := new(RemoveGroupMembersCMSResp) + err := grpc.Invoke(ctx, "/group.group/RemoveGroupMembersCMS", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) AddGroupMembersCMS(ctx context.Context, in *AddGroupMembersCMSReq, opts ...grpc.CallOption) (*AddGroupMembersCMSResp, error) { + out := new(AddGroupMembersCMSResp) + err := grpc.Invoke(ctx, "/group.group/AddGroupMembersCMS", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) DismissGroup(ctx context.Context, in *DismissGroupReq, opts ...grpc.CallOption) (*DismissGroupResp, error) { + out := new(DismissGroupResp) + err := grpc.Invoke(ctx, "/group.group/DismissGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) MuteGroupMember(ctx context.Context, in *MuteGroupMemberReq, opts ...grpc.CallOption) (*MuteGroupMemberResp, error) { + out := new(MuteGroupMemberResp) + err := grpc.Invoke(ctx, "/group.group/MuteGroupMember", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) CancelMuteGroupMember(ctx context.Context, in *CancelMuteGroupMemberReq, opts ...grpc.CallOption) (*CancelMuteGroupMemberResp, error) { + out := new(CancelMuteGroupMemberResp) + err := grpc.Invoke(ctx, "/group.group/CancelMuteGroupMember", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) MuteGroup(ctx context.Context, in *MuteGroupReq, opts ...grpc.CallOption) (*MuteGroupResp, error) { + out := new(MuteGroupResp) + err := grpc.Invoke(ctx, "/group.group/MuteGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupClient) CancelMuteGroup(ctx context.Context, in *CancelMuteGroupReq, opts ...grpc.CallOption) (*CancelMuteGroupResp, error) { + out := new(CancelMuteGroupResp) + err := grpc.Invoke(ctx, "/group.group/CancelMuteGroup", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Group service + +type GroupServer interface { + CreateGroup(context.Context, *CreateGroupReq) (*CreateGroupResp, error) + JoinGroup(context.Context, *JoinGroupReq) (*JoinGroupResp, error) + QuitGroup(context.Context, *QuitGroupReq) (*QuitGroupResp, error) + GetGroupsInfo(context.Context, *GetGroupsInfoReq) (*GetGroupsInfoResp, error) + SetGroupInfo(context.Context, *SetGroupInfoReq) (*SetGroupInfoResp, error) + GetGroupApplicationList(context.Context, *GetGroupApplicationListReq) (*GetGroupApplicationListResp, error) + GetUserReqApplicationList(context.Context, *GetUserReqApplicationListReq) (*GetUserReqApplicationListResp, error) + TransferGroupOwner(context.Context, *TransferGroupOwnerReq) (*TransferGroupOwnerResp, error) + GroupApplicationResponse(context.Context, *GroupApplicationResponseReq) (*GroupApplicationResponseResp, error) + GetGroupMemberList(context.Context, *GetGroupMemberListReq) (*GetGroupMemberListResp, error) + GetGroupMembersInfo(context.Context, *GetGroupMembersInfoReq) (*GetGroupMembersInfoResp, error) + KickGroupMember(context.Context, *KickGroupMemberReq) (*KickGroupMemberResp, error) + GetJoinedGroupList(context.Context, *GetJoinedGroupListReq) (*GetJoinedGroupListResp, error) + InviteUserToGroup(context.Context, *InviteUserToGroupReq) (*InviteUserToGroupResp, error) + GetGroupAllMember(context.Context, *GetGroupAllMemberReq) (*GetGroupAllMemberResp, error) + GetGroupById(context.Context, *GetGroupByIdReq) (*GetGroupByIdResp, error) + GetGroup(context.Context, *GetGroupReq) (*GetGroupResp, error) + GetGroups(context.Context, *GetGroupsReq) (*GetGroupsResp, error) + OperateGroupStatus(context.Context, *OperateGroupStatusReq) (*OperateGroupStatusResp, error) + OperateUserRole(context.Context, *OperateUserRoleReq) (*OperateUserRoleResp, error) + DeleteGroup(context.Context, *DeleteGroupReq) (*DeleteGroupResp, error) + GetGroupMembersCMS(context.Context, *GetGroupMembersCMSReq) (*GetGroupMembersCMSResp, error) + RemoveGroupMembersCMS(context.Context, *RemoveGroupMembersCMSReq) (*RemoveGroupMembersCMSResp, error) + AddGroupMembersCMS(context.Context, *AddGroupMembersCMSReq) (*AddGroupMembersCMSResp, error) + DismissGroup(context.Context, *DismissGroupReq) (*DismissGroupResp, error) + MuteGroupMember(context.Context, *MuteGroupMemberReq) (*MuteGroupMemberResp, error) + CancelMuteGroupMember(context.Context, *CancelMuteGroupMemberReq) (*CancelMuteGroupMemberResp, error) + MuteGroup(context.Context, *MuteGroupReq) (*MuteGroupResp, error) + CancelMuteGroup(context.Context, *CancelMuteGroupReq) (*CancelMuteGroupResp, error) +} + +func RegisterGroupServer(s *grpc.Server, srv GroupServer) { + s.RegisterService(&_Group_serviceDesc, srv) +} + +func _Group_CreateGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).CreateGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/CreateGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).CreateGroup(ctx, req.(*CreateGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_JoinGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(JoinGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).JoinGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/JoinGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).JoinGroup(ctx, req.(*JoinGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_QuitGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuitGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).QuitGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/QuitGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).QuitGroup(ctx, req.(*QuitGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupsInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupsInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupsInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupsInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupsInfo(ctx, req.(*GetGroupsInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_SetGroupInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetGroupInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).SetGroupInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/SetGroupInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).SetGroupInfo(ctx, req.(*SetGroupInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupApplicationList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupApplicationListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupApplicationList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupApplicationList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupApplicationList(ctx, req.(*GetGroupApplicationListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetUserReqApplicationList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserReqApplicationListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetUserReqApplicationList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetUserReqApplicationList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetUserReqApplicationList(ctx, req.(*GetUserReqApplicationListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_TransferGroupOwner_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TransferGroupOwnerReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).TransferGroupOwner(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/TransferGroupOwner", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).TransferGroupOwner(ctx, req.(*TransferGroupOwnerReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GroupApplicationResponse_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GroupApplicationResponseReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GroupApplicationResponse(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GroupApplicationResponse", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GroupApplicationResponse(ctx, req.(*GroupApplicationResponseReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupMemberList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupMemberListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupMemberList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupMemberList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupMemberList(ctx, req.(*GetGroupMemberListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupMembersInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupMembersInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupMembersInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupMembersInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupMembersInfo(ctx, req.(*GetGroupMembersInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_KickGroupMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(KickGroupMemberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).KickGroupMember(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/KickGroupMember", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).KickGroupMember(ctx, req.(*KickGroupMemberReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetJoinedGroupList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetJoinedGroupListReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetJoinedGroupList(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetJoinedGroupList", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetJoinedGroupList(ctx, req.(*GetJoinedGroupListReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_InviteUserToGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InviteUserToGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).InviteUserToGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/InviteUserToGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).InviteUserToGroup(ctx, req.(*InviteUserToGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupAllMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupAllMemberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupAllMember(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupAllMember", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupAllMember(ctx, req.(*GetGroupAllMemberReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupByIdReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupById(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupById", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupById(ctx, req.(*GetGroupByIdReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroup(ctx, req.(*GetGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroups_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroups(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroups", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroups(ctx, req.(*GetGroupsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_OperateGroupStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OperateGroupStatusReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).OperateGroupStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/OperateGroupStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).OperateGroupStatus(ctx, req.(*OperateGroupStatusReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_OperateUserRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OperateUserRoleReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).OperateUserRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/OperateUserRole", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).OperateUserRole(ctx, req.(*OperateUserRoleReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_DeleteGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).DeleteGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/DeleteGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).DeleteGroup(ctx, req.(*DeleteGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_GetGroupMembersCMS_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupMembersCMSReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).GetGroupMembersCMS(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/GetGroupMembersCMS", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).GetGroupMembersCMS(ctx, req.(*GetGroupMembersCMSReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_RemoveGroupMembersCMS_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveGroupMembersCMSReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).RemoveGroupMembersCMS(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/RemoveGroupMembersCMS", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).RemoveGroupMembersCMS(ctx, req.(*RemoveGroupMembersCMSReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_AddGroupMembersCMS_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddGroupMembersCMSReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).AddGroupMembersCMS(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/AddGroupMembersCMS", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).AddGroupMembersCMS(ctx, req.(*AddGroupMembersCMSReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_DismissGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DismissGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).DismissGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/DismissGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).DismissGroup(ctx, req.(*DismissGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_MuteGroupMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MuteGroupMemberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).MuteGroupMember(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/MuteGroupMember", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).MuteGroupMember(ctx, req.(*MuteGroupMemberReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_CancelMuteGroupMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CancelMuteGroupMemberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).CancelMuteGroupMember(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/CancelMuteGroupMember", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).CancelMuteGroupMember(ctx, req.(*CancelMuteGroupMemberReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_MuteGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MuteGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).MuteGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/MuteGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).MuteGroup(ctx, req.(*MuteGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Group_CancelMuteGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CancelMuteGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServer).CancelMuteGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/group.group/CancelMuteGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServer).CancelMuteGroup(ctx, req.(*CancelMuteGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _Group_serviceDesc = grpc.ServiceDesc{ + ServiceName: "group.group", + HandlerType: (*GroupServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "createGroup", + Handler: _Group_CreateGroup_Handler, + }, + { + MethodName: "joinGroup", + Handler: _Group_JoinGroup_Handler, + }, + { + MethodName: "quitGroup", + Handler: _Group_QuitGroup_Handler, + }, + { + MethodName: "getGroupsInfo", + Handler: _Group_GetGroupsInfo_Handler, + }, + { + MethodName: "setGroupInfo", + Handler: _Group_SetGroupInfo_Handler, + }, + { + MethodName: "getGroupApplicationList", + Handler: _Group_GetGroupApplicationList_Handler, + }, + { + MethodName: "getUserReqApplicationList", + Handler: _Group_GetUserReqApplicationList_Handler, + }, + { + MethodName: "transferGroupOwner", + Handler: _Group_TransferGroupOwner_Handler, + }, + { + MethodName: "groupApplicationResponse", + Handler: _Group_GroupApplicationResponse_Handler, + }, + { + MethodName: "getGroupMemberList", + Handler: _Group_GetGroupMemberList_Handler, + }, + { + MethodName: "getGroupMembersInfo", + Handler: _Group_GetGroupMembersInfo_Handler, + }, + { + MethodName: "kickGroupMember", + Handler: _Group_KickGroupMember_Handler, + }, + { + MethodName: "getJoinedGroupList", + Handler: _Group_GetJoinedGroupList_Handler, + }, + { + MethodName: "inviteUserToGroup", + Handler: _Group_InviteUserToGroup_Handler, + }, + { + MethodName: "getGroupAllMember", + Handler: _Group_GetGroupAllMember_Handler, + }, + { + MethodName: "GetGroupById", + Handler: _Group_GetGroupById_Handler, + }, + { + MethodName: "GetGroup", + Handler: _Group_GetGroup_Handler, + }, + { + MethodName: "GetGroups", + Handler: _Group_GetGroups_Handler, + }, + { + MethodName: "OperateGroupStatus", + Handler: _Group_OperateGroupStatus_Handler, + }, + { + MethodName: "OperateUserRole", + Handler: _Group_OperateUserRole_Handler, + }, + { + MethodName: "DeleteGroup", + Handler: _Group_DeleteGroup_Handler, + }, + { + MethodName: "GetGroupMembersCMS", + Handler: _Group_GetGroupMembersCMS_Handler, + }, + { + MethodName: "RemoveGroupMembersCMS", + Handler: _Group_RemoveGroupMembersCMS_Handler, + }, + { + MethodName: "AddGroupMembersCMS", + Handler: _Group_AddGroupMembersCMS_Handler, + }, + { + MethodName: "DismissGroup", + Handler: _Group_DismissGroup_Handler, + }, + { + MethodName: "MuteGroupMember", + Handler: _Group_MuteGroupMember_Handler, + }, + { + MethodName: "CancelMuteGroupMember", + Handler: _Group_CancelMuteGroupMember_Handler, + }, + { + MethodName: "MuteGroup", + Handler: _Group_MuteGroup_Handler, + }, + { + MethodName: "CancelMuteGroup", + Handler: _Group_CancelMuteGroup_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "group/group.proto", +} + +func init() { proto.RegisterFile("group/group.proto", fileDescriptor_group_3c77315b028a1402) } + +var fileDescriptor_group_3c77315b028a1402 = []byte{ + // 2068 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0x4f, 0x6f, 0xdb, 0xc8, + 0x15, 0x07, 0xed, 0xc8, 0xb6, 0x9e, 0xad, 0xc8, 0x1e, 0x47, 0xb6, 0xc2, 0xf5, 0x66, 0xbd, 0xb3, + 0xe9, 0x22, 0xe8, 0x1f, 0x1b, 0xcd, 0x02, 0x39, 0x74, 0x8b, 0xa6, 0xf1, 0x9f, 0xc4, 0x4a, 0x22, + 0xbb, 0xa1, 0xd3, 0x4b, 0x2e, 0xa9, 0x56, 0x1c, 0x0b, 0xaa, 0x25, 0x92, 0xe6, 0x50, 0x4e, 0xdb, + 0xcb, 0xa2, 0x97, 0x05, 0xb6, 0xed, 0xa1, 0x45, 0x81, 0x3d, 0x15, 0x68, 0x73, 0xeb, 0xa1, 0x87, + 0x1e, 0xda, 0x73, 0xd1, 0x8f, 0xd1, 0x4f, 0xd1, 0xaf, 0x50, 0x70, 0x66, 0x38, 0x1c, 0x0e, 0x87, + 0xb4, 0x42, 0x25, 0xcd, 0x45, 0xc0, 0xbc, 0x79, 0xc3, 0xf7, 0x7b, 0x6f, 0xe6, 0xbd, 0x79, 0xef, + 0x8d, 0x60, 0x6d, 0x10, 0xfa, 0x93, 0x60, 0x97, 0xfd, 0xee, 0x04, 0xa1, 0x1f, 0xf9, 0xa8, 0xc6, + 0x06, 0xf6, 0xc7, 0x27, 0x01, 0xf1, 0x5e, 0x76, 0xba, 0xbb, 0xc1, 0xf9, 0x60, 0x97, 0xcd, 0xec, + 0x52, 0xf7, 0xfc, 0xe5, 0x2b, 0xba, 0xfb, 0x8a, 0x72, 0x4e, 0xfc, 0x23, 0x80, 0x7d, 0x7f, 0x3c, + 0xf6, 0x3d, 0x87, 0xd0, 0x00, 0xb5, 0x61, 0xf1, 0x30, 0x0c, 0xf7, 0x7d, 0x97, 0xb4, 0xad, 0x6d, + 0xeb, 0x4e, 0xcd, 0x49, 0x86, 0x68, 0x03, 0x16, 0x0e, 0xc3, 0xb0, 0x4b, 0x07, 0xed, 0xb9, 0x6d, + 0xeb, 0x4e, 0xdd, 0x11, 0x23, 0xfc, 0x18, 0xd0, 0xa3, 0x58, 0xd6, 0x03, 0xd7, 0xed, 0x92, 0xf1, + 0x17, 0x24, 0xec, 0x78, 0x67, 0x7e, 0xcc, 0xfd, 0x53, 0x4a, 0xc2, 0xce, 0x01, 0xfb, 0x4c, 0xdd, + 0x11, 0x23, 0xb4, 0x05, 0x75, 0xc7, 0x1f, 0x91, 0xa7, 0xe4, 0x92, 0x8c, 0xd8, 0x87, 0x6a, 0x4e, + 0x4a, 0xc0, 0xff, 0xb5, 0xe0, 0xfa, 0x7e, 0x48, 0x7a, 0x11, 0x61, 0x9f, 0x74, 0xc8, 0x05, 0x7a, + 0x00, 0xd7, 0x3b, 0xde, 0x30, 0xe2, 0x9f, 0x7e, 0x3a, 0xa4, 0x51, 0xdb, 0xda, 0x9e, 0xbf, 0xb3, + 0x7c, 0xf7, 0xe6, 0x0e, 0x57, 0x37, 0x2f, 0xdb, 0xd1, 0x16, 0xa0, 0x1f, 0x40, 0x9d, 0x71, 0xc5, + 0x93, 0x4c, 0xe6, 0xf2, 0xdd, 0xad, 0x1d, 0x4a, 0xc2, 0x4b, 0x12, 0xbe, 0xec, 0x05, 0xc3, 0x97, + 0x41, 0x2f, 0xec, 0x8d, 0xe9, 0x8e, 0xe4, 0x71, 0x52, 0x76, 0xb4, 0x0d, 0xcb, 0x27, 0x01, 0x09, + 0x7b, 0xd1, 0xd0, 0xf7, 0x3a, 0x07, 0xed, 0x79, 0xa6, 0x8c, 0x4a, 0x42, 0x36, 0x2c, 0x9d, 0x04, + 0x42, 0xd7, 0x6b, 0x6c, 0x5a, 0x8e, 0xd9, 0xea, 0x57, 0x1e, 0x09, 0xc5, 0x74, 0x4d, 0xac, 0x4e, + 0x49, 0xf8, 0x4b, 0x68, 0x66, 0x14, 0xae, 0xb2, 0x05, 0x59, 0x05, 0xe7, 0xdf, 0x48, 0x41, 0x1c, + 0xc2, 0xea, 0x23, 0x12, 0xb1, 0x31, 0x65, 0x73, 0xe4, 0x22, 0x86, 0xcd, 0x19, 0x0e, 0xa4, 0xc1, + 0xeb, 0x8e, 0x4a, 0xd2, 0xcd, 0x32, 0x57, 0x6e, 0x96, 0xf9, 0xac, 0x59, 0xf0, 0xd7, 0x16, 0xac, + 0x69, 0x42, 0x2b, 0xe9, 0xbd, 0x07, 0x0d, 0xa9, 0x08, 0x43, 0x3a, 0xcf, 0x8e, 0x46, 0xb9, 0xee, + 0xd9, 0x25, 0xf8, 0xb7, 0x16, 0x34, 0x4f, 0x05, 0x96, 0x44, 0xff, 0x8c, 0x3d, 0xad, 0x37, 0x3b, + 0x30, 0xaa, 0xde, 0x73, 0x86, 0xe3, 0x50, 0x7a, 0x98, 0xf0, 0x21, 0xac, 0x66, 0xc1, 0xd0, 0x00, + 0x7d, 0x5f, 0x75, 0x50, 0x01, 0x67, 0x4d, 0x9c, 0xfe, 0x74, 0xc2, 0x51, 0x98, 0xf0, 0xaf, 0xc0, + 0x4e, 0xec, 0xfb, 0x20, 0x08, 0x46, 0xc3, 0x3e, 0xfb, 0x7e, 0xac, 0x6f, 0xac, 0x9e, 0x0a, 0xd1, + 0x2a, 0x87, 0x68, 0xd8, 0xd8, 0x5b, 0x00, 0x0f, 0x43, 0x7f, 0x9c, 0xd9, 0x5a, 0x85, 0x82, 0xff, + 0x64, 0xc1, 0x07, 0x85, 0xc2, 0x2b, 0x6d, 0xf3, 0x13, 0x58, 0x4d, 0xc2, 0xc1, 0x84, 0xd0, 0x48, + 0xd9, 0xe9, 0x8f, 0x8a, 0x76, 0x45, 0xb0, 0x3a, 0xb9, 0x85, 0x38, 0x82, 0xad, 0x47, 0x24, 0x8a, + 0xb1, 0x3a, 0xe4, 0xc2, 0x60, 0x9c, 0xa2, 0xc0, 0x35, 0xdb, 0xbe, 0xfe, 0xd9, 0x82, 0x0f, 0x4b, + 0xc4, 0x56, 0xda, 0x65, 0xa3, 0x5d, 0xe6, 0xaa, 0xda, 0xe5, 0x5f, 0x16, 0xb4, 0x9e, 0x87, 0x3d, + 0x8f, 0x9e, 0x91, 0x90, 0x4d, 0xb2, 0x28, 0x15, 0x5b, 0xa4, 0x0d, 0x8b, 0xc2, 0xf5, 0x85, 0x49, + 0x92, 0x21, 0xfa, 0x14, 0xae, 0x9f, 0x8c, 0x5c, 0x35, 0xc2, 0x71, 0xcb, 0x68, 0xd4, 0x98, 0xef, + 0x98, 0xbc, 0x52, 0xf9, 0xb8, 0x89, 0x34, 0xaa, 0x6e, 0xc7, 0x6b, 0xe5, 0x51, 0xa5, 0xa6, 0x45, + 0x95, 0x27, 0xb0, 0x61, 0x52, 0xa0, 0x9a, 0x07, 0x7d, 0x65, 0xc1, 0xca, 0x63, 0x7f, 0xe8, 0xc9, + 0x7b, 0xa8, 0xd8, 0x0a, 0xb7, 0x00, 0x1c, 0x72, 0xd1, 0x25, 0x94, 0xf6, 0x06, 0x44, 0x58, 0x40, + 0xa1, 0x94, 0x45, 0xc2, 0xab, 0x35, 0xc6, 0x7b, 0xd0, 0x50, 0x70, 0x54, 0x53, 0xe6, 0x3f, 0xb1, + 0x4b, 0x6a, 0xfe, 0x18, 0x4f, 0xf8, 0x1e, 0x25, 0x22, 0xde, 0xab, 0x28, 0xac, 0x72, 0xbb, 0xeb, + 0xa7, 0x5f, 0xb1, 0xcc, 0x7c, 0xce, 0x32, 0x4a, 0xa8, 0xb8, 0xa6, 0x87, 0x8a, 0x78, 0xfe, 0xa8, + 0xe7, 0xb9, 0x23, 0xe2, 0xc6, 0x4e, 0xcf, 0xf7, 0x53, 0xa1, 0x20, 0x0c, 0x2b, 0x7c, 0xe4, 0x10, + 0x3a, 0x19, 0x45, 0xed, 0x05, 0x16, 0x2f, 0x32, 0x34, 0xfc, 0x0c, 0xb6, 0x8a, 0x55, 0xab, 0x66, + 0xae, 0x33, 0x58, 0x79, 0x36, 0x19, 0x46, 0x53, 0x6c, 0xfd, 0x6c, 0xd7, 0xe0, 0x1e, 0x34, 0x14, + 0x39, 0xd5, 0xb0, 0xbe, 0xb6, 0xa0, 0x95, 0x44, 0xdb, 0x34, 0xe5, 0x29, 0x47, 0x3d, 0x53, 0x28, + 0x8b, 0x03, 0xe4, 0xc3, 0xe1, 0x28, 0x22, 0x21, 0xdb, 0xd0, 0x9a, 0x23, 0x46, 0xb1, 0xbc, 0x63, + 0xf2, 0x8b, 0xe8, 0x94, 0x5c, 0xb0, 0x9d, 0xac, 0x39, 0xc9, 0x10, 0xff, 0xcd, 0x82, 0x0d, 0x13, + 0xc6, 0x4a, 0x97, 0xc1, 0x43, 0x80, 0x71, 0x9a, 0x0b, 0xf2, 0x6b, 0xe0, 0xd3, 0xa2, 0x70, 0xc7, + 0xa5, 0x3d, 0x9c, 0x8c, 0x46, 0xec, 0x36, 0x55, 0x56, 0xc6, 0x92, 0x3d, 0x01, 0x97, 0xeb, 0x91, + 0x0c, 0xf1, 0xef, 0x73, 0x70, 0x65, 0x62, 0x54, 0x1a, 0x04, 0x14, 0x58, 0x73, 0x2c, 0x63, 0x52, + 0xc5, 0xcd, 0x16, 0x04, 0xfe, 0x68, 0xc1, 0xa6, 0x11, 0xd2, 0xfb, 0x34, 0x21, 0xfe, 0xbb, 0x05, + 0xe8, 0xc9, 0xb0, 0x7f, 0xae, 0xf0, 0x95, 0x1b, 0xe9, 0xdb, 0xb0, 0x1a, 0xf3, 0x13, 0x97, 0x2b, + 0xae, 0x98, 0x2a, 0x47, 0x8f, 0xc1, 0x3b, 0xa4, 0x47, 0x7d, 0x4f, 0x98, 0x4b, 0x8c, 0x74, 0x63, + 0xd5, 0xca, 0x5d, 0x6e, 0x41, 0x73, 0xb9, 0xcf, 0xa1, 0xde, 0x71, 0xef, 0xf2, 0xd0, 0x51, 0x78, + 0xd5, 0x33, 0xd1, 0x2c, 0xe0, 0xf0, 0x02, 0x45, 0x8c, 0xf0, 0x97, 0xb0, 0x9e, 0x53, 0xb7, 0xd2, + 0x06, 0xdc, 0x83, 0x86, 0x44, 0xa1, 0xec, 0xc1, 0xaa, 0x70, 0x75, 0x39, 0xe7, 0x64, 0xd9, 0xf0, + 0x84, 0xf9, 0x7a, 0x7c, 0x1d, 0x10, 0x97, 0xa1, 0x48, 0x7c, 0x3d, 0x1b, 0x68, 0xad, 0x5c, 0xa0, + 0xdd, 0x86, 0x65, 0x3f, 0x1f, 0xa7, 0xfc, 0x29, 0xe3, 0xd4, 0x57, 0xdc, 0x21, 0x72, 0x72, 0x67, + 0xaa, 0x55, 0xa6, 0xce, 0xd7, 0x53, 0x76, 0xfc, 0x0f, 0x0b, 0x6e, 0x74, 0xbc, 0xcb, 0x61, 0x44, + 0x62, 0x64, 0xcf, 0x7d, 0x19, 0xa1, 0xaf, 0x8e, 0xc3, 0xc5, 0x97, 0x54, 0x7a, 0xd0, 0xae, 0x65, + 0x0e, 0xda, 0x77, 0x61, 0x8d, 0xcb, 0x52, 0x4f, 0x6b, 0x8d, 0x9d, 0xd6, 0xfc, 0x44, 0xe9, 0xa1, + 0xfb, 0xb5, 0x05, 0x2d, 0x03, 0xec, 0xff, 0xeb, 0xd1, 0xf1, 0xe0, 0x86, 0x4c, 0xca, 0x47, 0xa3, + 0x69, 0x9c, 0x75, 0xb6, 0x84, 0xf7, 0x0f, 0xca, 0xbd, 0xa4, 0x08, 0x7c, 0xaf, 0xf1, 0xea, 0x1b, + 0x0b, 0x96, 0xf6, 0xbb, 0xa7, 0x8c, 0x6d, 0xa6, 0x1a, 0xef, 0x0e, 0x34, 0xb9, 0xac, 0x1e, 0x8d, + 0x48, 0x78, 0xdc, 0x1b, 0x27, 0x69, 0x9f, 0x4e, 0x46, 0xb7, 0x45, 0x85, 0xca, 0x49, 0x1d, 0x57, + 0x98, 0x2a, 0x4b, 0x8c, 0xc3, 0xfb, 0x72, 0x62, 0xac, 0x78, 0x53, 0xb6, 0x04, 0x36, 0xf6, 0x65, + 0xbe, 0x2d, 0x29, 0x01, 0x1d, 0x00, 0xfc, 0xa4, 0x37, 0x18, 0x7a, 0xcc, 0xd4, 0xa2, 0x9f, 0x71, + 0xdb, 0x00, 0x5d, 0x64, 0xf7, 0x29, 0xaf, 0xa3, 0xac, 0x9b, 0x62, 0x0b, 0x5f, 0x5b, 0xb0, 0x92, + 0xa2, 0xa2, 0x01, 0xfa, 0x1e, 0xd4, 0x13, 0xf3, 0x51, 0xd1, 0x85, 0x69, 0x26, 0xd9, 0x89, 0xa0, + 0x3b, 0x29, 0xc7, 0x5b, 0xc2, 0x29, 0x6d, 0x31, 0x19, 0x53, 0x86, 0xb2, 0xe6, 0xa4, 0x04, 0x7c, + 0x99, 0x42, 0xa4, 0xb1, 0xe5, 0xb2, 0x32, 0xad, 0xb7, 0x63, 0x9b, 0x7c, 0x38, 0xc1, 0x7f, 0xb1, + 0xa0, 0xa1, 0x08, 0x7e, 0x5f, 0xc6, 0xb1, 0x61, 0x29, 0xb1, 0x85, 0xb0, 0x8d, 0x1c, 0xe3, 0x93, + 0xb4, 0xc7, 0x62, 0x70, 0x77, 0x37, 0xeb, 0xee, 0xee, 0x14, 0x3a, 0x9f, 0x43, 0x8b, 0x0f, 0x79, + 0xaf, 0xea, 0x34, 0xea, 0x45, 0x13, 0x5a, 0xfe, 0xd1, 0x0d, 0x58, 0xe0, 0x6c, 0xc9, 0x4d, 0xca, + 0x47, 0x53, 0x1c, 0xbe, 0x36, 0x6c, 0x98, 0x84, 0xf1, 0xca, 0x0c, 0x89, 0x29, 0x56, 0x4e, 0xfb, + 0x23, 0x72, 0x25, 0x08, 0x16, 0xb6, 0xdc, 0x24, 0xac, 0xf0, 0x51, 0xb6, 0x15, 0x39, 0xaf, 0xb5, + 0x22, 0xa7, 0x48, 0xca, 0x5a, 0xb0, 0x9e, 0xc3, 0x41, 0x03, 0xfc, 0x14, 0xae, 0x1f, 0x90, 0x11, + 0x51, 0x5a, 0x98, 0xb3, 0x18, 0x7d, 0x0d, 0x9a, 0x99, 0xaf, 0xd1, 0x00, 0x77, 0xa1, 0x99, 0x6c, + 0xec, 0xde, 0x2f, 0x3b, 0xee, 0xac, 0x12, 0xee, 0xa7, 0x0d, 0x40, 0xfe, 0x39, 0x1a, 0xa0, 0xef, + 0xa4, 0x81, 0x52, 0x38, 0x51, 0xee, 0x2c, 0x4b, 0x06, 0xfc, 0xcf, 0x5c, 0x09, 0x42, 0xf7, 0xbb, + 0xa7, 0xe5, 0xb0, 0x6c, 0x58, 0x8a, 0x8d, 0xa6, 0x84, 0x4e, 0x39, 0xd6, 0x5c, 0x63, 0xfe, 0xed, + 0xf8, 0xb0, 0x61, 0xff, 0xfe, 0x9d, 0xcf, 0xf3, 0x19, 0x6e, 0x1a, 0xa0, 0x1f, 0xc3, 0x22, 0xbf, + 0x37, 0x12, 0x57, 0x9e, 0xf6, 0xba, 0x49, 0x96, 0xa1, 0x43, 0x83, 0x7f, 0x7f, 0xcb, 0xa8, 0x04, + 0xaf, 0x55, 0x0b, 0xb4, 0xb8, 0x05, 0xc0, 0x25, 0x28, 0xe1, 0x4f, 0xa1, 0xe0, 0xdf, 0x59, 0xd0, + 0x76, 0xc8, 0xd8, 0xbf, 0x24, 0x6f, 0x64, 0xfe, 0x36, 0x2c, 0x72, 0x27, 0xa0, 0x22, 0xff, 0x4e, + 0x86, 0x6f, 0xd4, 0xef, 0x76, 0xb5, 0x7e, 0xb7, 0x8b, 0xbb, 0x70, 0xb3, 0x00, 0x0d, 0xbf, 0xf8, + 0xe9, 0xa4, 0xdf, 0x27, 0x94, 0x8a, 0x8e, 0x72, 0x32, 0x8c, 0x3d, 0xf4, 0xac, 0x37, 0x1c, 0x11, + 0x57, 0xa0, 0x11, 0x23, 0xfc, 0xb5, 0x05, 0xad, 0x07, 0xae, 0xfb, 0x2e, 0x54, 0x73, 0xf3, 0xaa, + 0xb9, 0xa5, 0xaa, 0x3d, 0x86, 0x0d, 0x13, 0x94, 0x4a, 0x7a, 0x0d, 0xa1, 0x79, 0x30, 0xa4, 0xe3, + 0x21, 0xa5, 0x32, 0x46, 0xd8, 0xb0, 0xe4, 0x6b, 0x3d, 0x59, 0x3f, 0x98, 0x3a, 0x7b, 0x6f, 0xc3, + 0xe2, 0x20, 0x9b, 0xdd, 0x8a, 0x21, 0x3e, 0x84, 0xd5, 0xac, 0x28, 0xde, 0x66, 0xe8, 0x4f, 0xd3, + 0x66, 0x48, 0x99, 0xf0, 0x5f, 0x2d, 0x40, 0xdd, 0x49, 0x44, 0xb4, 0xeb, 0xe4, 0x1d, 0xa1, 0x8e, + 0x0d, 0x37, 0x51, 0x9b, 0x46, 0x62, 0x84, 0x30, 0xac, 0x8c, 0x27, 0x11, 0x71, 0x4f, 0x49, 0xdf, + 0xf7, 0x5c, 0xca, 0xaa, 0xbf, 0x86, 0x93, 0xa1, 0xe1, 0x23, 0x58, 0xcf, 0x21, 0xad, 0xa6, 0xf4, + 0x6f, 0x2c, 0x68, 0xef, 0xf7, 0xbc, 0x3e, 0x19, 0xbd, 0x7f, 0xd5, 0xf1, 0x31, 0xdc, 0x2c, 0xc0, + 0x52, 0x4d, 0xb9, 0x33, 0x58, 0x91, 0x5f, 0x7a, 0x97, 0x07, 0x70, 0x0f, 0x1a, 0x8a, 0x9c, 0x6a, + 0x58, 0x47, 0x80, 0x34, 0xdd, 0xdf, 0x25, 0xe2, 0x23, 0x58, 0xcf, 0x49, 0xab, 0x84, 0xfb, 0xee, + 0x37, 0x6b, 0xc0, 0xdf, 0x61, 0xd1, 0x0f, 0x61, 0xb9, 0x9f, 0x3e, 0xf3, 0xa1, 0x56, 0xb2, 0x2e, + 0xf3, 0xd6, 0x69, 0x6f, 0x98, 0xc8, 0x34, 0x40, 0xf7, 0xa0, 0xfe, 0xf3, 0xa4, 0x07, 0x8c, 0xd6, + 0x05, 0x93, 0xda, 0x9d, 0xb6, 0x6f, 0xe4, 0x89, 0x7c, 0xdd, 0x45, 0xd2, 0x60, 0x94, 0xeb, 0xd4, + 0xd6, 0xa6, 0x5c, 0x97, 0xed, 0x43, 0xee, 0x41, 0x63, 0xa0, 0x3e, 0xcf, 0xa1, 0xcd, 0xe4, 0xb1, + 0x55, 0x7b, 0x29, 0xb4, 0xdb, 0xe6, 0x09, 0x1a, 0xa0, 0xfb, 0xb0, 0x42, 0x95, 0x97, 0x2c, 0x94, + 0xe8, 0xa6, 0xbd, 0xb5, 0xd9, 0x9b, 0x46, 0x3a, 0x0d, 0xd0, 0xcf, 0x60, 0x73, 0x60, 0x7e, 0x46, + 0x42, 0x1f, 0x6b, 0x52, 0xf3, 0xcf, 0x38, 0x36, 0xbe, 0x8a, 0x85, 0x06, 0xe8, 0x0c, 0x6e, 0x0e, + 0x8a, 0xde, 0x64, 0xd0, 0x27, 0xe9, 0x07, 0x0a, 0x1f, 0x8b, 0xec, 0xdb, 0x57, 0x33, 0xd1, 0x00, + 0x3d, 0x03, 0x14, 0xe5, 0x1e, 0x26, 0xd0, 0x96, 0x58, 0x6b, 0x7c, 0x74, 0xb1, 0x3f, 0x2c, 0x99, + 0xa5, 0x01, 0xea, 0x43, 0x7b, 0x50, 0xd0, 0xf5, 0x46, 0x38, 0xf3, 0x32, 0x6e, 0xec, 0xf8, 0xdb, + 0x9f, 0x5c, 0xc9, 0xc3, 0x71, 0x0f, 0x72, 0x6d, 0x5b, 0x89, 0xdb, 0xd8, 0x75, 0x96, 0xb8, 0x0b, + 0xfa, 0xbd, 0xcf, 0x61, 0x7d, 0x90, 0xef, 0x63, 0x22, 0xf3, 0x2a, 0x79, 0xca, 0x6e, 0x95, 0x4d, + 0xd3, 0x00, 0x1d, 0x41, 0xf3, 0x3c, 0xdb, 0x98, 0x43, 0xc9, 0xdf, 0x03, 0xf2, 0xfd, 0x49, 0xdb, + 0x2e, 0x9a, 0x92, 0x2a, 0x6b, 0x9d, 0x2e, 0x55, 0xe5, 0x7c, 0xf3, 0x4d, 0x55, 0xd9, 0xd4, 0x22, + 0x3b, 0x86, 0xb5, 0xa1, 0xde, 0xfc, 0x41, 0x1f, 0x24, 0xfd, 0x1a, 0x43, 0x37, 0xcb, 0xde, 0x2a, + 0x9e, 0xe4, 0xdf, 0x1b, 0xe8, 0x8d, 0x15, 0xf9, 0x3d, 0x53, 0x8f, 0xc7, 0xde, 0x2a, 0x9e, 0xe4, + 0x8e, 0xaa, 0xe6, 0xff, 0xd2, 0x51, 0xb5, 0x1a, 0xc3, 0xde, 0x34, 0xd2, 0x69, 0x80, 0x3e, 0x83, + 0xa5, 0x84, 0x86, 0x90, 0xc6, 0x14, 0x2f, 0x5c, 0xcf, 0xd1, 0x78, 0x68, 0x92, 0x31, 0x03, 0xe9, + 0x1c, 0x54, 0x0d, 0x4d, 0xd9, 0x32, 0xfb, 0x99, 0x2c, 0xfe, 0x94, 0xba, 0x50, 0x6e, 0x90, 0xb1, + 0x3e, 0x95, 0x1b, 0x64, 0x2e, 0x28, 0xe3, 0xd3, 0xa3, 0xd5, 0x71, 0xf2, 0xf4, 0xe4, 0xeb, 0x4c, + 0x79, 0x7a, 0x0c, 0xa5, 0x5f, 0x1c, 0xe5, 0x95, 0x62, 0x4d, 0x46, 0xf9, 0x6c, 0x39, 0x28, 0xa3, + 0xbc, 0x56, 0xd7, 0xc5, 0xaa, 0xe5, 0xcb, 0x91, 0x02, 0x77, 0x13, 0x79, 0x70, 0x81, 0xbb, 0xc9, + 0xd4, 0xf4, 0x05, 0xb4, 0x8c, 0xf9, 0x38, 0xfa, 0x48, 0xac, 0x2b, 0xaa, 0x1d, 0xec, 0xed, 0x72, + 0x06, 0x0e, 0x37, 0x9f, 0x10, 0x4b, 0xb8, 0xc6, 0xb4, 0x5d, 0xc2, 0x2d, 0xc8, 0xa4, 0xef, 0xc3, + 0x8a, 0x9a, 0xac, 0xca, 0xa3, 0xa8, 0x25, 0xcb, 0xf2, 0x28, 0xe6, 0x32, 0xdb, 0x23, 0x68, 0x6a, + 0xe9, 0x91, 0xdc, 0xca, 0x7c, 0x0a, 0x27, 0xb7, 0xd2, 0x94, 0x51, 0xbd, 0x80, 0x96, 0x31, 0xdd, + 0x92, 0x96, 0x2b, 0x4a, 0x0c, 0xa5, 0xe5, 0x8a, 0xb3, 0xb5, 0x7b, 0x50, 0x97, 0x64, 0x79, 0xf6, + 0xd5, 0xd4, 0x46, 0x9e, 0xfd, 0x6c, 0x06, 0x72, 0x04, 0x4d, 0xed, 0xa3, 0x52, 0xbb, 0x7c, 0x7a, + 0x24, 0xb5, 0x33, 0xe4, 0x32, 0x7b, 0xcd, 0x17, 0x8d, 0x1d, 0xfe, 0x77, 0xb1, 0xcf, 0xd9, 0xef, + 0x17, 0x0b, 0xec, 0xbf, 0x60, 0x9f, 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xa9, 0x2b, 0x24, 0xa7, + 0x4a, 0x26, 0x00, 0x00, +} diff --git a/pkg/proto/group/group.proto b/pkg/proto/group/group.proto new file mode 100644 index 000000000..201bf6ef5 --- /dev/null +++ b/pkg/proto/group/group.proto @@ -0,0 +1,423 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./group;group"; +package group; + +message CommonResp{ + int32 ErrCode = 1; + string ErrMsg = 2; +} + +message GroupAddMemberInfo{ + string UserID = 1; + int32 RoleLevel = 2; +} + + +message CreateGroupReq{ + repeated GroupAddMemberInfo InitMemberList = 1; + server_api_params.GroupInfo GroupInfo = 2; + string OperationID = 3; + string OpUserID = 4; //app manager or group owner + string OwnerUserID = 5; //owner + + +} +message CreateGroupResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + server_api_params.GroupInfo GroupInfo = 3; +} + + +message GetGroupsInfoReq{ + repeated string GroupIDList = 1; + string OperationID = 2; + string OpUserID = 3; //No verification permission +} +message GetGroupsInfoResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.GroupInfo GroupInfoList = 3; +} + + +message SetGroupInfoReq{ + server_api_params.GroupInfo GroupInfo = 1; + string OpUserID = 2; //app manager or group owner + string OperationID = 3; +} +message SetGroupInfoResp{ + CommonResp CommonResp = 1; +} + + +message GetGroupApplicationListReq { + string OpUserID = 1; //app manager or group owner(manager) + string OperationID = 2; + string FromUserID = 3; //owner or manager +} +message GetGroupApplicationListResp { + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.GroupRequest GroupRequestList = 3; +} + +message GetUserReqApplicationListReq{ + string UserID = 1; + string OpUserID = 2; + string OperationID = 3; +} + +message GetUserReqApplicationListResp{ + CommonResp CommonResp = 1; + repeated server_api_params.GroupRequest GroupRequestList = 2; +} + + +message TransferGroupOwnerReq { + string GroupID = 1; + string OldOwnerUserID = 2; + string NewOwnerUserID = 3; + string OperationID = 4; + string OpUserID = 5; //app manager or group owner +} +message TransferGroupOwnerResp{ + CommonResp CommonResp = 1; +} + +message JoinGroupReq{ + string GroupID = 1; + string ReqMessage = 2; + string OpUserID = 3; + string OperationID = 4; +} +message JoinGroupResp{ + CommonResp CommonResp = 1; +} + + +message GroupApplicationResponseReq{ + string OperationID = 1; + string OpUserID = 2; + string GroupID = 3; + string FromUserID = 4; // + string HandledMsg = 5; + int32 HandleResult = 6; +} +message GroupApplicationResponseResp{ + CommonResp CommonResp = 1; +} + + + +message QuitGroupReq{ + string GroupID = 1; + string OperationID = 2; + string OpUserID = 3; +} +message QuitGroupResp{ + CommonResp CommonResp = 1; +} + + + +message GetGroupMemberListReq { + string GroupID = 1; + string OpUserID = 2; //No verification permission + string OperationID = 3; + int32 Filter = 4; + int32 NextSeq = 5; +} + +message GetGroupMemberListResp { + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.GroupMemberFullInfo memberList = 3; + int32 nextSeq = 4; +} + + +message GetGroupMembersInfoReq { + string GroupID = 1; + repeated string memberList = 2; + string OpUserID = 3; //No verification permission + string OperationID = 4; +} + +message GetGroupMembersInfoResp { + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.GroupMemberFullInfo memberList = 3; +} + +message KickGroupMemberReq { + string GroupID = 1; + repeated string KickedUserIDList = 2; + string Reason = 3; + string OperationID = 5; + string OpUserID = 6; //app manger or group manager +} + +message Id2Result { + string UserID = 1; + int32 Result = 2; //0 ok; -1 error +} + +message KickGroupMemberResp { + int32 ErrCode = 1; + string ErrMsg = 2; + repeated Id2Result Id2ResultList = 3; +} + + +message GetJoinedGroupListReq { + string FromUserID = 1; + string operationID = 2; + string OpUserID = 3; //app manager or FromUserID +} +message GetJoinedGroupListResp{ + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.GroupInfo GroupList = 3; +} + + +message InviteUserToGroupReq { + string OperationID = 2; + string GroupID = 3; + string Reason = 4; + repeated string InvitedUserIDList = 5; + string OpUserID = 6; //group member or app manager +} +message InviteUserToGroupResp { + int32 ErrCode = 1; + string ErrMsg = 2; + repeated Id2Result Id2ResultList = 3; // 0 ok, -1 error +} + + +message GetGroupAllMemberReq { + string GroupID = 1; + string OpUserID = 2; //No verification permission + string OperationID = 3; +} +message GetGroupAllMemberResp { + int32 ErrCode = 1; + string ErrMsg = 2; + repeated server_api_params.GroupMemberFullInfo memberList = 3; +} + +message CMSGroup { + server_api_params.GroupInfo GroupInfo = 1; + string GroupMasterName = 2; + string GroupMasterId = 3; +} + +message GetGroupReq { + string GroupName = 1; + server_api_params.RequestPagination Pagination = 2; + string OperationID = 3; +} + +message GetGroupResp { + repeated CMSGroup CMSGroups = 1; + server_api_params.RequestPagination Pagination = 2; + int32 GroupNums = 3; +} + +message GetGroupsReq { + server_api_params.RequestPagination Pagination = 1; + string OperationID = 2; +} + +message GetGroupsResp { + repeated CMSGroup CMSGroups = 1; + server_api_params.RequestPagination Pagination = 2; + int32 GroupNum = 3; +} + +message GetGroupMemberReq { + string GroupId = 1; + string OperationID = 2; +} + +message OperateGroupStatusReq { + string GroupId = 1; + int32 Status = 2; + string OperationID = 3; +} + +message OperateGroupStatusResp { + +} + +message OperateUserRoleReq { + string GroupId = 1; + string UserId = 2; + int32 RoleLevel = 3; + string OperationID = 4; +} + +message OperateUserRoleResp { + +} + +message DeleteGroupReq { + string GroupId = 1; + string OperationID = 2; +} + +message DeleteGroupResp { + +} + +message GetGroupByIdReq { + string GroupId = 1; + string OperationID = 2; +} + +message GetGroupByIdResp { + CMSGroup CMSGroup = 1; +} + +message GetGroupMembersCMSReq { + string GroupId = 1; + string UserName = 2; + server_api_params.RequestPagination Pagination = 3; + string OperationID = 4; +} + +message GetGroupMembersCMSResp { + repeated server_api_params.GroupMemberFullInfo members = 1; + server_api_params.ResponsePagination Pagination = 2; + int32 MemberNums = 3; +} + +message RemoveGroupMembersCMSReq { + string GroupId = 1; + repeated string UserIds = 2; + string OperationID = 3; + string OpUserId = 4; +} + +message RemoveGroupMembersCMSResp { + repeated string success = 1; + repeated string failed = 2; +} + +message AddGroupMembersCMSReq { + string GroupId = 1; + repeated string UserIds = 2; + string OperationId = 3; + string OpUserId = 4; +} + +message AddGroupMembersCMSResp { + repeated string success = 1; + repeated string failed = 2; +} + +message DismissGroupReq{ + string opUserID = 1; //group or app manager + string operationID = 2; + string groupID = 3; +} + +message DismissGroupResp{ + CommonResp commonResp = 1; +} + + +message MuteGroupMemberReq{ + string opUserID = 1; //group or app manager + string operationID = 2; + string groupID = 3; + string userID = 4; + uint32 mutedSeconds = 5; +} + +message MuteGroupMemberResp{ + CommonResp commonResp = 1; +} + + + +message CancelMuteGroupMemberReq{ + string opUserID = 1; //group or app manager + string operationID = 2; + string groupID = 3; + string userID = 4; +} + +message CancelMuteGroupMemberResp{ + CommonResp commonResp = 1; +} + + +message MuteGroupReq{ + string opUserID = 1; //group or app manager + string operationID = 2; + string groupID = 3; +} + +message MuteGroupResp{ + CommonResp commonResp = 1; +} + + + +message CancelMuteGroupReq{ + string opUserID = 1; //group or app manager + string operationID = 2; + string groupID = 3; +} + +message CancelMuteGroupResp{ + CommonResp commonResp = 1; +} + + + + + +service group{ + rpc createGroup(CreateGroupReq) returns(CreateGroupResp); + rpc joinGroup(JoinGroupReq) returns(JoinGroupResp); + rpc quitGroup(QuitGroupReq) returns(QuitGroupResp); + rpc getGroupsInfo(GetGroupsInfoReq) returns(GetGroupsInfoResp); + rpc setGroupInfo(SetGroupInfoReq) returns(SetGroupInfoResp); + rpc getGroupApplicationList(GetGroupApplicationListReq) returns(GetGroupApplicationListResp); + rpc getUserReqApplicationList(GetUserReqApplicationListReq) returns(GetUserReqApplicationListResp); + rpc transferGroupOwner(TransferGroupOwnerReq) returns(TransferGroupOwnerResp); + rpc groupApplicationResponse(GroupApplicationResponseReq) returns(GroupApplicationResponseResp); + rpc getGroupMemberList(GetGroupMemberListReq) returns(GetGroupMemberListResp); + rpc getGroupMembersInfo(GetGroupMembersInfoReq) returns(GetGroupMembersInfoResp); + rpc kickGroupMember(KickGroupMemberReq) returns (KickGroupMemberResp); + rpc getJoinedGroupList(GetJoinedGroupListReq) returns (GetJoinedGroupListResp); + rpc inviteUserToGroup(InviteUserToGroupReq) returns (InviteUserToGroupResp); + rpc getGroupAllMember(GetGroupAllMemberReq) returns(GetGroupAllMemberResp); + + rpc GetGroupById(GetGroupByIdReq) returns(GetGroupByIdResp); + rpc GetGroup(GetGroupReq) returns(GetGroupResp); + rpc GetGroups(GetGroupsReq) returns(GetGroupsResp); + rpc OperateGroupStatus(OperateGroupStatusReq) returns(OperateGroupStatusResp); + rpc OperateUserRole(OperateUserRoleReq) returns(OperateUserRoleResp); + rpc DeleteGroup(DeleteGroupReq) returns(DeleteGroupResp); + rpc GetGroupMembersCMS(GetGroupMembersCMSReq) returns(GetGroupMembersCMSResp); + rpc RemoveGroupMembersCMS(RemoveGroupMembersCMSReq) returns(RemoveGroupMembersCMSResp); + rpc AddGroupMembersCMS(AddGroupMembersCMSReq) returns(AddGroupMembersCMSResp); + + rpc DismissGroup(DismissGroupReq) returns(DismissGroupResp); + rpc MuteGroupMember(MuteGroupMemberReq) returns(MuteGroupMemberResp); + rpc CancelMuteGroupMember(CancelMuteGroupMemberReq) returns(CancelMuteGroupMemberResp); + rpc MuteGroup(MuteGroupReq) returns(MuteGroupResp); + rpc CancelMuteGroup(CancelMuteGroupReq) returns(CancelMuteGroupResp); +} + + + + + + + diff --git a/pkg/proto/message_cms/message_cms.pb.go b/pkg/proto/message_cms/message_cms.pb.go new file mode 100644 index 000000000..317439903 --- /dev/null +++ b/pkg/proto/message_cms/message_cms.pb.go @@ -0,0 +1,1083 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.5 +// source: message_cms/message_cms.proto + +package message_cms + +import ( + sdk_ws "Open_IM/pkg/proto/sdk_ws" + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type BoradcastMessageReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=Message,proto3" json:"Message,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *BoradcastMessageReq) Reset() { + *x = BoradcastMessageReq{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BoradcastMessageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BoradcastMessageReq) ProtoMessage() {} + +func (x *BoradcastMessageReq) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BoradcastMessageReq.ProtoReflect.Descriptor instead. +func (*BoradcastMessageReq) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{0} +} + +func (x *BoradcastMessageReq) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *BoradcastMessageReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type BoradcastMessageResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BoradcastMessageResp) Reset() { + *x = BoradcastMessageResp{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BoradcastMessageResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BoradcastMessageResp) ProtoMessage() {} + +func (x *BoradcastMessageResp) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BoradcastMessageResp.ProtoReflect.Descriptor instead. +func (*BoradcastMessageResp) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{1} +} + +type MassSendMessageReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=Message,proto3" json:"Message,omitempty"` + UserIds []string `protobuf:"bytes,2,rep,name=UserIds,proto3" json:"UserIds,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *MassSendMessageReq) Reset() { + *x = MassSendMessageReq{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MassSendMessageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MassSendMessageReq) ProtoMessage() {} + +func (x *MassSendMessageReq) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MassSendMessageReq.ProtoReflect.Descriptor instead. +func (*MassSendMessageReq) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{2} +} + +func (x *MassSendMessageReq) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *MassSendMessageReq) GetUserIds() []string { + if x != nil { + return x.UserIds + } + return nil +} + +func (x *MassSendMessageReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type MassSendMessageResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MassSendMessageResp) Reset() { + *x = MassSendMessageResp{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MassSendMessageResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MassSendMessageResp) ProtoMessage() {} + +func (x *MassSendMessageResp) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MassSendMessageResp.ProtoReflect.Descriptor instead. +func (*MassSendMessageResp) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{3} +} + +type GetChatLogsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content string `protobuf:"bytes,1,opt,name=Content,proto3" json:"Content,omitempty"` + UserId string `protobuf:"bytes,2,opt,name=UserId,proto3" json:"UserId,omitempty"` + GroupId string `protobuf:"bytes,3,opt,name=GroupId,proto3" json:"GroupId,omitempty"` + Date string `protobuf:"bytes,4,opt,name=Date,proto3" json:"Date,omitempty"` + SessionType int32 `protobuf:"varint,5,opt,name=SessionType,proto3" json:"SessionType,omitempty"` + ContentType int32 `protobuf:"varint,6,opt,name=ContentType,proto3" json:"ContentType,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,7,opt,name=Pagination,proto3" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,8,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *GetChatLogsReq) Reset() { + *x = GetChatLogsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetChatLogsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetChatLogsReq) ProtoMessage() {} + +func (x *GetChatLogsReq) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetChatLogsReq.ProtoReflect.Descriptor instead. +func (*GetChatLogsReq) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{4} +} + +func (x *GetChatLogsReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *GetChatLogsReq) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetChatLogsReq) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *GetChatLogsReq) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *GetChatLogsReq) GetSessionType() int32 { + if x != nil { + return x.SessionType + } + return 0 +} + +func (x *GetChatLogsReq) GetContentType() int32 { + if x != nil { + return x.ContentType + } + return 0 +} + +func (x *GetChatLogsReq) GetPagination() *sdk_ws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *GetChatLogsReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type ChatLogs struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionType int32 `protobuf:"varint,1,opt,name=SessionType,proto3" json:"SessionType,omitempty"` + ContentType int32 `protobuf:"varint,2,opt,name=ContentType,proto3" json:"ContentType,omitempty"` + SenderNickName string `protobuf:"bytes,3,opt,name=SenderNickName,proto3" json:"SenderNickName,omitempty"` + SenderId string `protobuf:"bytes,4,opt,name=SenderId,proto3" json:"SenderId,omitempty"` + ReciverNickName string `protobuf:"bytes,5,opt,name=ReciverNickName,proto3" json:"ReciverNickName,omitempty"` + ReciverId string `protobuf:"bytes,6,opt,name=ReciverId,proto3" json:"ReciverId,omitempty"` + SearchContent string `protobuf:"bytes,7,opt,name=SearchContent,proto3" json:"SearchContent,omitempty"` + WholeContent string `protobuf:"bytes,8,opt,name=WholeContent,proto3" json:"WholeContent,omitempty"` + GroupId string `protobuf:"bytes,9,opt,name=GroupId,proto3" json:"GroupId,omitempty"` + GroupName string `protobuf:"bytes,10,opt,name=GroupName,proto3" json:"GroupName,omitempty"` + Date string `protobuf:"bytes,11,opt,name=Date,proto3" json:"Date,omitempty"` +} + +func (x *ChatLogs) Reset() { + *x = ChatLogs{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChatLogs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatLogs) ProtoMessage() {} + +func (x *ChatLogs) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChatLogs.ProtoReflect.Descriptor instead. +func (*ChatLogs) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{5} +} + +func (x *ChatLogs) GetSessionType() int32 { + if x != nil { + return x.SessionType + } + return 0 +} + +func (x *ChatLogs) GetContentType() int32 { + if x != nil { + return x.ContentType + } + return 0 +} + +func (x *ChatLogs) GetSenderNickName() string { + if x != nil { + return x.SenderNickName + } + return "" +} + +func (x *ChatLogs) GetSenderId() string { + if x != nil { + return x.SenderId + } + return "" +} + +func (x *ChatLogs) GetReciverNickName() string { + if x != nil { + return x.ReciverNickName + } + return "" +} + +func (x *ChatLogs) GetReciverId() string { + if x != nil { + return x.ReciverId + } + return "" +} + +func (x *ChatLogs) GetSearchContent() string { + if x != nil { + return x.SearchContent + } + return "" +} + +func (x *ChatLogs) GetWholeContent() string { + if x != nil { + return x.WholeContent + } + return "" +} + +func (x *ChatLogs) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *ChatLogs) GetGroupName() string { + if x != nil { + return x.GroupName + } + return "" +} + +func (x *ChatLogs) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +type GetChatLogsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ChatLogs []*ChatLogs `protobuf:"bytes,1,rep,name=ChatLogs,proto3" json:"ChatLogs,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,2,opt,name=Pagination,proto3" json:"Pagination,omitempty"` + ChatLogsNum int32 `protobuf:"varint,3,opt,name=ChatLogsNum,proto3" json:"ChatLogsNum,omitempty"` +} + +func (x *GetChatLogsResp) Reset() { + *x = GetChatLogsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetChatLogsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetChatLogsResp) ProtoMessage() {} + +func (x *GetChatLogsResp) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetChatLogsResp.ProtoReflect.Descriptor instead. +func (*GetChatLogsResp) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{6} +} + +func (x *GetChatLogsResp) GetChatLogs() []*ChatLogs { + if x != nil { + return x.ChatLogs + } + return nil +} + +func (x *GetChatLogsResp) GetPagination() *sdk_ws.ResponsePagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *GetChatLogsResp) GetChatLogsNum() int32 { + if x != nil { + return x.ChatLogsNum + } + return 0 +} + +type WithdrawMessageReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServerMsgId string `protobuf:"bytes,1,opt,name=ServerMsgId,proto3" json:"ServerMsgId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *WithdrawMessageReq) Reset() { + *x = WithdrawMessageReq{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WithdrawMessageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithdrawMessageReq) ProtoMessage() {} + +func (x *WithdrawMessageReq) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithdrawMessageReq.ProtoReflect.Descriptor instead. +func (*WithdrawMessageReq) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{7} +} + +func (x *WithdrawMessageReq) GetServerMsgId() string { + if x != nil { + return x.ServerMsgId + } + return "" +} + +func (x *WithdrawMessageReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type WithdrawMessageResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *WithdrawMessageResp) Reset() { + *x = WithdrawMessageResp{} + if protoimpl.UnsafeEnabled { + mi := &file_message_cms_message_cms_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WithdrawMessageResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WithdrawMessageResp) ProtoMessage() {} + +func (x *WithdrawMessageResp) ProtoReflect() protoreflect.Message { + mi := &file_message_cms_message_cms_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WithdrawMessageResp.ProtoReflect.Descriptor instead. +func (*WithdrawMessageResp) Descriptor() ([]byte, []int) { + return file_message_cms_message_cms_proto_rawDescGZIP(), []int{8} +} + +var File_message_cms_message_cms_proto protoreflect.FileDescriptor + +var file_message_cms_message_cms_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2f, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x1a, 0x21, 0x4f, 0x70, + 0x65, 0x6e, 0x5f, 0x49, 0x4d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x73, 0x64, 0x6b, 0x5f, 0x77, 0x73, 0x2f, 0x77, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x51, 0x0a, 0x13, 0x42, 0x6f, 0x72, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x44, 0x22, 0x16, 0x0a, 0x14, 0x42, 0x6f, 0x72, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x6a, 0x0a, 0x12, 0x4d, 0x61, + 0x73, 0x73, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x15, 0x0a, 0x13, 0x4d, 0x61, 0x73, 0x73, 0x53, 0x65, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x9c, 0x02, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, + 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x44, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x44, 0x61, 0x74, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x44, 0x0a, 0x0a, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x5f, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0xf0, 0x02, 0x0a, + 0x08, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, + 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x69, 0x63, + 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x69, 0x76, 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x52, 0x65, 0x63, 0x69, + 0x76, 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x52, + 0x65, 0x63, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x52, 0x65, 0x63, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x22, 0x0a, 0x0c, 0x57, 0x68, 0x6f, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x57, 0x68, 0x6f, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, + 0x61, 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x44, 0x61, 0x74, 0x65, 0x22, + 0xad, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x31, 0x0a, 0x08, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6d, 0x73, 0x2e, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x08, 0x43, 0x68, + 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x45, 0x0a, 0x0a, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x5f, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0a, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, + 0x0b, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x4e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0b, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x4e, 0x75, 0x6d, 0x22, + 0x58, 0x0a, 0x12, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, + 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x15, 0x0a, 0x13, 0x57, 0x69, 0x74, + 0x68, 0x64, 0x72, 0x61, 0x77, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x32, 0xdb, 0x02, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x4d, 0x53, 0x12, + 0x57, 0x0a, 0x10, 0x42, 0x6f, 0x72, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x20, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, + 0x73, 0x2e, 0x42, 0x6f, 0x72, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, + 0x63, 0x6d, 0x73, 0x2e, 0x42, 0x6f, 0x72, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x4d, 0x61, 0x73, 0x73, + 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x4d, 0x61, 0x73, 0x73, 0x53, 0x65, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x4d, 0x61, 0x73, 0x73, 0x53, + 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x48, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1b, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x68, 0x61, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x74, + 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x57, 0x69, 0x74, 0x68, + 0x64, 0x72, 0x61, 0x77, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, + 0x72, 0x61, 0x77, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x1b, + 0x5a, 0x19, 0x2e, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x3b, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_message_cms_message_cms_proto_rawDescOnce sync.Once + file_message_cms_message_cms_proto_rawDescData = file_message_cms_message_cms_proto_rawDesc +) + +func file_message_cms_message_cms_proto_rawDescGZIP() []byte { + file_message_cms_message_cms_proto_rawDescOnce.Do(func() { + file_message_cms_message_cms_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_cms_message_cms_proto_rawDescData) + }) + return file_message_cms_message_cms_proto_rawDescData +} + +var file_message_cms_message_cms_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_message_cms_message_cms_proto_goTypes = []interface{}{ + (*BoradcastMessageReq)(nil), // 0: message_cms.BoradcastMessageReq + (*BoradcastMessageResp)(nil), // 1: message_cms.BoradcastMessageResp + (*MassSendMessageReq)(nil), // 2: message_cms.MassSendMessageReq + (*MassSendMessageResp)(nil), // 3: message_cms.MassSendMessageResp + (*GetChatLogsReq)(nil), // 4: message_cms.GetChatLogsReq + (*ChatLogs)(nil), // 5: message_cms.ChatLogs + (*GetChatLogsResp)(nil), // 6: message_cms.GetChatLogsResp + (*WithdrawMessageReq)(nil), // 7: message_cms.WithdrawMessageReq + (*WithdrawMessageResp)(nil), // 8: message_cms.WithdrawMessageResp + (*sdk_ws.RequestPagination)(nil), // 9: server_api_params.RequestPagination + (*sdk_ws.ResponsePagination)(nil), // 10: server_api_params.ResponsePagination +} +var file_message_cms_message_cms_proto_depIdxs = []int32{ + 9, // 0: message_cms.GetChatLogsReq.Pagination:type_name -> server_api_params.RequestPagination + 5, // 1: message_cms.GetChatLogsResp.ChatLogs:type_name -> message_cms.ChatLogs + 10, // 2: message_cms.GetChatLogsResp.Pagination:type_name -> server_api_params.ResponsePagination + 0, // 3: message_cms.messageCMS.BoradcastMessage:input_type -> message_cms.BoradcastMessageReq + 2, // 4: message_cms.messageCMS.MassSendMessage:input_type -> message_cms.MassSendMessageReq + 4, // 5: message_cms.messageCMS.GetChatLogs:input_type -> message_cms.GetChatLogsReq + 7, // 6: message_cms.messageCMS.WithdrawMessage:input_type -> message_cms.WithdrawMessageReq + 1, // 7: message_cms.messageCMS.BoradcastMessage:output_type -> message_cms.BoradcastMessageResp + 3, // 8: message_cms.messageCMS.MassSendMessage:output_type -> message_cms.MassSendMessageResp + 6, // 9: message_cms.messageCMS.GetChatLogs:output_type -> message_cms.GetChatLogsResp + 8, // 10: message_cms.messageCMS.WithdrawMessage:output_type -> message_cms.WithdrawMessageResp + 7, // [7:11] is the sub-list for method output_type + 3, // [3:7] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_message_cms_message_cms_proto_init() } +func file_message_cms_message_cms_proto_init() { + if File_message_cms_message_cms_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_message_cms_message_cms_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BoradcastMessageReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BoradcastMessageResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MassSendMessageReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MassSendMessageResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetChatLogsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChatLogs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetChatLogsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WithdrawMessageReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_cms_message_cms_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WithdrawMessageResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_message_cms_message_cms_proto_rawDesc, + NumEnums: 0, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_message_cms_message_cms_proto_goTypes, + DependencyIndexes: file_message_cms_message_cms_proto_depIdxs, + MessageInfos: file_message_cms_message_cms_proto_msgTypes, + }.Build() + File_message_cms_message_cms_proto = out.File + file_message_cms_message_cms_proto_rawDesc = nil + file_message_cms_message_cms_proto_goTypes = nil + file_message_cms_message_cms_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// MessageCMSClient is the client API for MessageCMS service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MessageCMSClient interface { + BoradcastMessage(ctx context.Context, in *BoradcastMessageReq, opts ...grpc.CallOption) (*BoradcastMessageResp, error) + MassSendMessage(ctx context.Context, in *MassSendMessageReq, opts ...grpc.CallOption) (*MassSendMessageResp, error) + GetChatLogs(ctx context.Context, in *GetChatLogsReq, opts ...grpc.CallOption) (*GetChatLogsResp, error) + WithdrawMessage(ctx context.Context, in *WithdrawMessageReq, opts ...grpc.CallOption) (*WithdrawMessageResp, error) +} + +type messageCMSClient struct { + cc grpc.ClientConnInterface +} + +func NewMessageCMSClient(cc grpc.ClientConnInterface) MessageCMSClient { + return &messageCMSClient{cc} +} + +func (c *messageCMSClient) BoradcastMessage(ctx context.Context, in *BoradcastMessageReq, opts ...grpc.CallOption) (*BoradcastMessageResp, error) { + out := new(BoradcastMessageResp) + err := c.cc.Invoke(ctx, "/message_cms.messageCMS/BoradcastMessage", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageCMSClient) MassSendMessage(ctx context.Context, in *MassSendMessageReq, opts ...grpc.CallOption) (*MassSendMessageResp, error) { + out := new(MassSendMessageResp) + err := c.cc.Invoke(ctx, "/message_cms.messageCMS/MassSendMessage", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageCMSClient) GetChatLogs(ctx context.Context, in *GetChatLogsReq, opts ...grpc.CallOption) (*GetChatLogsResp, error) { + out := new(GetChatLogsResp) + err := c.cc.Invoke(ctx, "/message_cms.messageCMS/GetChatLogs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *messageCMSClient) WithdrawMessage(ctx context.Context, in *WithdrawMessageReq, opts ...grpc.CallOption) (*WithdrawMessageResp, error) { + out := new(WithdrawMessageResp) + err := c.cc.Invoke(ctx, "/message_cms.messageCMS/WithdrawMessage", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MessageCMSServer is the server API for MessageCMS service. +type MessageCMSServer interface { + BoradcastMessage(context.Context, *BoradcastMessageReq) (*BoradcastMessageResp, error) + MassSendMessage(context.Context, *MassSendMessageReq) (*MassSendMessageResp, error) + GetChatLogs(context.Context, *GetChatLogsReq) (*GetChatLogsResp, error) + WithdrawMessage(context.Context, *WithdrawMessageReq) (*WithdrawMessageResp, error) +} + +// UnimplementedMessageCMSServer can be embedded to have forward compatible implementations. +type UnimplementedMessageCMSServer struct { +} + +func (*UnimplementedMessageCMSServer) BoradcastMessage(context.Context, *BoradcastMessageReq) (*BoradcastMessageResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method BoradcastMessage not implemented") +} +func (*UnimplementedMessageCMSServer) MassSendMessage(context.Context, *MassSendMessageReq) (*MassSendMessageResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method MassSendMessage not implemented") +} +func (*UnimplementedMessageCMSServer) GetChatLogs(context.Context, *GetChatLogsReq) (*GetChatLogsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetChatLogs not implemented") +} +func (*UnimplementedMessageCMSServer) WithdrawMessage(context.Context, *WithdrawMessageReq) (*WithdrawMessageResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawMessage not implemented") +} + +func RegisterMessageCMSServer(s *grpc.Server, srv MessageCMSServer) { + s.RegisterService(&_MessageCMS_serviceDesc, srv) +} + +func _MessageCMS_BoradcastMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BoradcastMessageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageCMSServer).BoradcastMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/message_cms.messageCMS/BoradcastMessage", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageCMSServer).BoradcastMessage(ctx, req.(*BoradcastMessageReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageCMS_MassSendMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MassSendMessageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageCMSServer).MassSendMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/message_cms.messageCMS/MassSendMessage", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageCMSServer).MassSendMessage(ctx, req.(*MassSendMessageReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageCMS_GetChatLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetChatLogsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageCMSServer).GetChatLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/message_cms.messageCMS/GetChatLogs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageCMSServer).GetChatLogs(ctx, req.(*GetChatLogsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _MessageCMS_WithdrawMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(WithdrawMessageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MessageCMSServer).WithdrawMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/message_cms.messageCMS/WithdrawMessage", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MessageCMSServer).WithdrawMessage(ctx, req.(*WithdrawMessageReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _MessageCMS_serviceDesc = grpc.ServiceDesc{ + ServiceName: "message_cms.messageCMS", + HandlerType: (*MessageCMSServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "BoradcastMessage", + Handler: _MessageCMS_BoradcastMessage_Handler, + }, + { + MethodName: "MassSendMessage", + Handler: _MessageCMS_MassSendMessage_Handler, + }, + { + MethodName: "GetChatLogs", + Handler: _MessageCMS_GetChatLogs_Handler, + }, + { + MethodName: "WithdrawMessage", + Handler: _MessageCMS_WithdrawMessage_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "message_cms/message_cms.proto", +} diff --git a/pkg/proto/message_cms/message_cms.proto b/pkg/proto/message_cms/message_cms.proto new file mode 100644 index 000000000..2a9647bb7 --- /dev/null +++ b/pkg/proto/message_cms/message_cms.proto @@ -0,0 +1,71 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./message_cms;message_cms"; +package message_cms; + +message BoradcastMessageReq { + string Message = 1; + string OperationID = 2; +} + +message BoradcastMessageResp { + +} + +message MassSendMessageReq { + string Message = 1; + repeated string UserIds = 2; + string OperationID = 3; +} + +message MassSendMessageResp { + +} + +message GetChatLogsReq { + string Content = 1; + string UserId = 2; + string GroupId = 3; + string Date = 4; + int32 SessionType = 5; + int32 ContentType = 6; + server_api_params.RequestPagination Pagination = 7; + string OperationID = 8; + +} + +message ChatLogs { + int32 SessionType = 1; + int32 ContentType = 2; + string SenderNickName = 3; + string SenderId = 4; + string ReciverNickName = 5; + string ReciverId = 6; + string SearchContent = 7; + string WholeContent = 8; + string GroupId = 9; + string GroupName = 10; + string Date = 11; +} + +message GetChatLogsResp { + repeated ChatLogs ChatLogs = 1; + server_api_params.ResponsePagination Pagination = 2; + int32 ChatLogsNum = 3; +} + +message WithdrawMessageReq { + string ServerMsgId = 1; + string OperationID = 2; +} + +message WithdrawMessageResp { + +} + +service messageCMS { + rpc BoradcastMessage(BoradcastMessageReq) returns(BoradcastMessageResp); + rpc MassSendMessage(MassSendMessageReq) returns(MassSendMessageResp); + rpc GetChatLogs(GetChatLogsReq) returns(GetChatLogsResp); + rpc WithdrawMessage(WithdrawMessageReq) returns(WithdrawMessageResp); +} \ No newline at end of file diff --git a/pkg/proto/office/office.pb.go b/pkg/proto/office/office.pb.go new file mode 100644 index 000000000..32a6a004d --- /dev/null +++ b/pkg/proto/office/office.pb.go @@ -0,0 +1,2851 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: office/office.proto + +package office // import "./office" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CommonResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommonResp) Reset() { *m = CommonResp{} } +func (m *CommonResp) String() string { return proto.CompactTextString(m) } +func (*CommonResp) ProtoMessage() {} +func (*CommonResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{0} +} +func (m *CommonResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommonResp.Unmarshal(m, b) +} +func (m *CommonResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommonResp.Marshal(b, m, deterministic) +} +func (dst *CommonResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommonResp.Merge(dst, src) +} +func (m *CommonResp) XXX_Size() int { + return xxx_messageInfo_CommonResp.Size(m) +} +func (m *CommonResp) XXX_DiscardUnknown() { + xxx_messageInfo_CommonResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CommonResp proto.InternalMessageInfo + +func (m *CommonResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CommonResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type TagUser struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + UserName string `protobuf:"bytes,2,opt,name=userName" json:"userName,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TagUser) Reset() { *m = TagUser{} } +func (m *TagUser) String() string { return proto.CompactTextString(m) } +func (*TagUser) ProtoMessage() {} +func (*TagUser) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{1} +} +func (m *TagUser) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TagUser.Unmarshal(m, b) +} +func (m *TagUser) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TagUser.Marshal(b, m, deterministic) +} +func (dst *TagUser) XXX_Merge(src proto.Message) { + xxx_messageInfo_TagUser.Merge(dst, src) +} +func (m *TagUser) XXX_Size() int { + return xxx_messageInfo_TagUser.Size(m) +} +func (m *TagUser) XXX_DiscardUnknown() { + xxx_messageInfo_TagUser.DiscardUnknown(m) +} + +var xxx_messageInfo_TagUser proto.InternalMessageInfo + +func (m *TagUser) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *TagUser) GetUserName() string { + if m != nil { + return m.UserName + } + return "" +} + +type Tag struct { + TagID string `protobuf:"bytes,1,opt,name=tagID" json:"tagID,omitempty"` + TagName string `protobuf:"bytes,2,opt,name=tagName" json:"tagName,omitempty"` + UserList []*TagUser `protobuf:"bytes,3,rep,name=userList" json:"userList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Tag) Reset() { *m = Tag{} } +func (m *Tag) String() string { return proto.CompactTextString(m) } +func (*Tag) ProtoMessage() {} +func (*Tag) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{2} +} +func (m *Tag) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Tag.Unmarshal(m, b) +} +func (m *Tag) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Tag.Marshal(b, m, deterministic) +} +func (dst *Tag) XXX_Merge(src proto.Message) { + xxx_messageInfo_Tag.Merge(dst, src) +} +func (m *Tag) XXX_Size() int { + return xxx_messageInfo_Tag.Size(m) +} +func (m *Tag) XXX_DiscardUnknown() { + xxx_messageInfo_Tag.DiscardUnknown(m) +} + +var xxx_messageInfo_Tag proto.InternalMessageInfo + +func (m *Tag) GetTagID() string { + if m != nil { + return m.TagID + } + return "" +} + +func (m *Tag) GetTagName() string { + if m != nil { + return m.TagName + } + return "" +} + +func (m *Tag) GetUserList() []*TagUser { + if m != nil { + return m.UserList + } + return nil +} + +type GetUserTagsReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserTagsReq) Reset() { *m = GetUserTagsReq{} } +func (m *GetUserTagsReq) String() string { return proto.CompactTextString(m) } +func (*GetUserTagsReq) ProtoMessage() {} +func (*GetUserTagsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{3} +} +func (m *GetUserTagsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserTagsReq.Unmarshal(m, b) +} +func (m *GetUserTagsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserTagsReq.Marshal(b, m, deterministic) +} +func (dst *GetUserTagsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserTagsReq.Merge(dst, src) +} +func (m *GetUserTagsReq) XXX_Size() int { + return xxx_messageInfo_GetUserTagsReq.Size(m) +} +func (m *GetUserTagsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserTagsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserTagsReq proto.InternalMessageInfo + +func (m *GetUserTagsReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserTagsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUserTagsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Tags []*Tag `protobuf:"bytes,2,rep,name=tags" json:"tags,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserTagsResp) Reset() { *m = GetUserTagsResp{} } +func (m *GetUserTagsResp) String() string { return proto.CompactTextString(m) } +func (*GetUserTagsResp) ProtoMessage() {} +func (*GetUserTagsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{4} +} +func (m *GetUserTagsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserTagsResp.Unmarshal(m, b) +} +func (m *GetUserTagsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserTagsResp.Marshal(b, m, deterministic) +} +func (dst *GetUserTagsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserTagsResp.Merge(dst, src) +} +func (m *GetUserTagsResp) XXX_Size() int { + return xxx_messageInfo_GetUserTagsResp.Size(m) +} +func (m *GetUserTagsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserTagsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserTagsResp proto.InternalMessageInfo + +func (m *GetUserTagsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserTagsResp) GetTags() []*Tag { + if m != nil { + return m.Tags + } + return nil +} + +type CreateTagReq struct { + TagName string `protobuf:"bytes,1,opt,name=tagName" json:"tagName,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + UserIDList []string `protobuf:"bytes,3,rep,name=userIDList" json:"userIDList,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTagReq) Reset() { *m = CreateTagReq{} } +func (m *CreateTagReq) String() string { return proto.CompactTextString(m) } +func (*CreateTagReq) ProtoMessage() {} +func (*CreateTagReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{5} +} +func (m *CreateTagReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateTagReq.Unmarshal(m, b) +} +func (m *CreateTagReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateTagReq.Marshal(b, m, deterministic) +} +func (dst *CreateTagReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTagReq.Merge(dst, src) +} +func (m *CreateTagReq) XXX_Size() int { + return xxx_messageInfo_CreateTagReq.Size(m) +} +func (m *CreateTagReq) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTagReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateTagReq proto.InternalMessageInfo + +func (m *CreateTagReq) GetTagName() string { + if m != nil { + return m.TagName + } + return "" +} + +func (m *CreateTagReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *CreateTagReq) GetUserIDList() []string { + if m != nil { + return m.UserIDList + } + return nil +} + +func (m *CreateTagReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type CreateTagResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTagResp) Reset() { *m = CreateTagResp{} } +func (m *CreateTagResp) String() string { return proto.CompactTextString(m) } +func (*CreateTagResp) ProtoMessage() {} +func (*CreateTagResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{6} +} +func (m *CreateTagResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateTagResp.Unmarshal(m, b) +} +func (m *CreateTagResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateTagResp.Marshal(b, m, deterministic) +} +func (dst *CreateTagResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTagResp.Merge(dst, src) +} +func (m *CreateTagResp) XXX_Size() int { + return xxx_messageInfo_CreateTagResp.Size(m) +} +func (m *CreateTagResp) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTagResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateTagResp proto.InternalMessageInfo + +func (m *CreateTagResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type DeleteTagReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + TagID string `protobuf:"bytes,2,opt,name=tagID" json:"tagID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteTagReq) Reset() { *m = DeleteTagReq{} } +func (m *DeleteTagReq) String() string { return proto.CompactTextString(m) } +func (*DeleteTagReq) ProtoMessage() {} +func (*DeleteTagReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{7} +} +func (m *DeleteTagReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteTagReq.Unmarshal(m, b) +} +func (m *DeleteTagReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteTagReq.Marshal(b, m, deterministic) +} +func (dst *DeleteTagReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteTagReq.Merge(dst, src) +} +func (m *DeleteTagReq) XXX_Size() int { + return xxx_messageInfo_DeleteTagReq.Size(m) +} +func (m *DeleteTagReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteTagReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteTagReq proto.InternalMessageInfo + +func (m *DeleteTagReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *DeleteTagReq) GetTagID() string { + if m != nil { + return m.TagID + } + return "" +} + +func (m *DeleteTagReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type DeleteTagResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteTagResp) Reset() { *m = DeleteTagResp{} } +func (m *DeleteTagResp) String() string { return proto.CompactTextString(m) } +func (*DeleteTagResp) ProtoMessage() {} +func (*DeleteTagResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{8} +} +func (m *DeleteTagResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteTagResp.Unmarshal(m, b) +} +func (m *DeleteTagResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteTagResp.Marshal(b, m, deterministic) +} +func (dst *DeleteTagResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteTagResp.Merge(dst, src) +} +func (m *DeleteTagResp) XXX_Size() int { + return xxx_messageInfo_DeleteTagResp.Size(m) +} +func (m *DeleteTagResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteTagResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteTagResp proto.InternalMessageInfo + +func (m *DeleteTagResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type SetTagReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + TagID string `protobuf:"bytes,2,opt,name=tagID" json:"tagID,omitempty"` + NewName string `protobuf:"bytes,3,opt,name=newName" json:"newName,omitempty"` + IncreaseUserIDList []string `protobuf:"bytes,4,rep,name=increaseUserIDList" json:"increaseUserIDList,omitempty"` + ReduceUserIDList []string `protobuf:"bytes,5,rep,name=reduceUserIDList" json:"reduceUserIDList,omitempty"` + OperationID string `protobuf:"bytes,6,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetTagReq) Reset() { *m = SetTagReq{} } +func (m *SetTagReq) String() string { return proto.CompactTextString(m) } +func (*SetTagReq) ProtoMessage() {} +func (*SetTagReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{9} +} +func (m *SetTagReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetTagReq.Unmarshal(m, b) +} +func (m *SetTagReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetTagReq.Marshal(b, m, deterministic) +} +func (dst *SetTagReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetTagReq.Merge(dst, src) +} +func (m *SetTagReq) XXX_Size() int { + return xxx_messageInfo_SetTagReq.Size(m) +} +func (m *SetTagReq) XXX_DiscardUnknown() { + xxx_messageInfo_SetTagReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SetTagReq proto.InternalMessageInfo + +func (m *SetTagReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *SetTagReq) GetTagID() string { + if m != nil { + return m.TagID + } + return "" +} + +func (m *SetTagReq) GetNewName() string { + if m != nil { + return m.NewName + } + return "" +} + +func (m *SetTagReq) GetIncreaseUserIDList() []string { + if m != nil { + return m.IncreaseUserIDList + } + return nil +} + +func (m *SetTagReq) GetReduceUserIDList() []string { + if m != nil { + return m.ReduceUserIDList + } + return nil +} + +func (m *SetTagReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type SetTagResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetTagResp) Reset() { *m = SetTagResp{} } +func (m *SetTagResp) String() string { return proto.CompactTextString(m) } +func (*SetTagResp) ProtoMessage() {} +func (*SetTagResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{10} +} +func (m *SetTagResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetTagResp.Unmarshal(m, b) +} +func (m *SetTagResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetTagResp.Marshal(b, m, deterministic) +} +func (dst *SetTagResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetTagResp.Merge(dst, src) +} +func (m *SetTagResp) XXX_Size() int { + return xxx_messageInfo_SetTagResp.Size(m) +} +func (m *SetTagResp) XXX_DiscardUnknown() { + xxx_messageInfo_SetTagResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SetTagResp proto.InternalMessageInfo + +func (m *SetTagResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type SendMsg2TagReq struct { + TagList []string `protobuf:"bytes,1,rep,name=tagList" json:"tagList,omitempty"` + UserList []string `protobuf:"bytes,2,rep,name=UserList" json:"UserList,omitempty"` + GroupList []string `protobuf:"bytes,3,rep,name=GroupList" json:"GroupList,omitempty"` + SendID string `protobuf:"bytes,4,opt,name=sendID" json:"sendID,omitempty"` + SenderPlatformID int32 `protobuf:"varint,5,opt,name=senderPlatformID" json:"senderPlatformID,omitempty"` + Content string `protobuf:"bytes,6,opt,name=content" json:"content,omitempty"` + OperationID string `protobuf:"bytes,7,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SendMsg2TagReq) Reset() { *m = SendMsg2TagReq{} } +func (m *SendMsg2TagReq) String() string { return proto.CompactTextString(m) } +func (*SendMsg2TagReq) ProtoMessage() {} +func (*SendMsg2TagReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{11} +} +func (m *SendMsg2TagReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SendMsg2TagReq.Unmarshal(m, b) +} +func (m *SendMsg2TagReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SendMsg2TagReq.Marshal(b, m, deterministic) +} +func (dst *SendMsg2TagReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendMsg2TagReq.Merge(dst, src) +} +func (m *SendMsg2TagReq) XXX_Size() int { + return xxx_messageInfo_SendMsg2TagReq.Size(m) +} +func (m *SendMsg2TagReq) XXX_DiscardUnknown() { + xxx_messageInfo_SendMsg2TagReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SendMsg2TagReq proto.InternalMessageInfo + +func (m *SendMsg2TagReq) GetTagList() []string { + if m != nil { + return m.TagList + } + return nil +} + +func (m *SendMsg2TagReq) GetUserList() []string { + if m != nil { + return m.UserList + } + return nil +} + +func (m *SendMsg2TagReq) GetGroupList() []string { + if m != nil { + return m.GroupList + } + return nil +} + +func (m *SendMsg2TagReq) GetSendID() string { + if m != nil { + return m.SendID + } + return "" +} + +func (m *SendMsg2TagReq) GetSenderPlatformID() int32 { + if m != nil { + return m.SenderPlatformID + } + return 0 +} + +func (m *SendMsg2TagReq) GetContent() string { + if m != nil { + return m.Content + } + return "" +} + +func (m *SendMsg2TagReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type SendMsg2TagResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SendMsg2TagResp) Reset() { *m = SendMsg2TagResp{} } +func (m *SendMsg2TagResp) String() string { return proto.CompactTextString(m) } +func (*SendMsg2TagResp) ProtoMessage() {} +func (*SendMsg2TagResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{12} +} +func (m *SendMsg2TagResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SendMsg2TagResp.Unmarshal(m, b) +} +func (m *SendMsg2TagResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SendMsg2TagResp.Marshal(b, m, deterministic) +} +func (dst *SendMsg2TagResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendMsg2TagResp.Merge(dst, src) +} +func (m *SendMsg2TagResp) XXX_Size() int { + return xxx_messageInfo_SendMsg2TagResp.Size(m) +} +func (m *SendMsg2TagResp) XXX_DiscardUnknown() { + xxx_messageInfo_SendMsg2TagResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SendMsg2TagResp proto.InternalMessageInfo + +func (m *SendMsg2TagResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetTagSendLogsReq struct { + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,1,opt,name=Pagination" json:"Pagination,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTagSendLogsReq) Reset() { *m = GetTagSendLogsReq{} } +func (m *GetTagSendLogsReq) String() string { return proto.CompactTextString(m) } +func (*GetTagSendLogsReq) ProtoMessage() {} +func (*GetTagSendLogsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{13} +} +func (m *GetTagSendLogsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTagSendLogsReq.Unmarshal(m, b) +} +func (m *GetTagSendLogsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTagSendLogsReq.Marshal(b, m, deterministic) +} +func (dst *GetTagSendLogsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTagSendLogsReq.Merge(dst, src) +} +func (m *GetTagSendLogsReq) XXX_Size() int { + return xxx_messageInfo_GetTagSendLogsReq.Size(m) +} +func (m *GetTagSendLogsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetTagSendLogsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTagSendLogsReq proto.InternalMessageInfo + +func (m *GetTagSendLogsReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetTagSendLogsReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetTagSendLogsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type TagSendLog struct { + UserList []*TagUser `protobuf:"bytes,1,rep,name=userList" json:"userList,omitempty"` + Content string `protobuf:"bytes,2,opt,name=content" json:"content,omitempty"` + SendTime int64 `protobuf:"varint,3,opt,name=sendTime" json:"sendTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TagSendLog) Reset() { *m = TagSendLog{} } +func (m *TagSendLog) String() string { return proto.CompactTextString(m) } +func (*TagSendLog) ProtoMessage() {} +func (*TagSendLog) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{14} +} +func (m *TagSendLog) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TagSendLog.Unmarshal(m, b) +} +func (m *TagSendLog) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TagSendLog.Marshal(b, m, deterministic) +} +func (dst *TagSendLog) XXX_Merge(src proto.Message) { + xxx_messageInfo_TagSendLog.Merge(dst, src) +} +func (m *TagSendLog) XXX_Size() int { + return xxx_messageInfo_TagSendLog.Size(m) +} +func (m *TagSendLog) XXX_DiscardUnknown() { + xxx_messageInfo_TagSendLog.DiscardUnknown(m) +} + +var xxx_messageInfo_TagSendLog proto.InternalMessageInfo + +func (m *TagSendLog) GetUserList() []*TagUser { + if m != nil { + return m.UserList + } + return nil +} + +func (m *TagSendLog) GetContent() string { + if m != nil { + return m.Content + } + return "" +} + +func (m *TagSendLog) GetSendTime() int64 { + if m != nil { + return m.SendTime + } + return 0 +} + +type GetTagSendLogsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + TagSendLogs []*TagSendLog `protobuf:"bytes,3,rep,name=tagSendLogs" json:"tagSendLogs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTagSendLogsResp) Reset() { *m = GetTagSendLogsResp{} } +func (m *GetTagSendLogsResp) String() string { return proto.CompactTextString(m) } +func (*GetTagSendLogsResp) ProtoMessage() {} +func (*GetTagSendLogsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{15} +} +func (m *GetTagSendLogsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTagSendLogsResp.Unmarshal(m, b) +} +func (m *GetTagSendLogsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTagSendLogsResp.Marshal(b, m, deterministic) +} +func (dst *GetTagSendLogsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTagSendLogsResp.Merge(dst, src) +} +func (m *GetTagSendLogsResp) XXX_Size() int { + return xxx_messageInfo_GetTagSendLogsResp.Size(m) +} +func (m *GetTagSendLogsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetTagSendLogsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTagSendLogsResp proto.InternalMessageInfo + +func (m *GetTagSendLogsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetTagSendLogsResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetTagSendLogsResp) GetTagSendLogs() []*TagSendLog { + if m != nil { + return m.TagSendLogs + } + return nil +} + +type GetUserTagByIDReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + TagID string `protobuf:"bytes,2,opt,name=tagID" json:"tagID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserTagByIDReq) Reset() { *m = GetUserTagByIDReq{} } +func (m *GetUserTagByIDReq) String() string { return proto.CompactTextString(m) } +func (*GetUserTagByIDReq) ProtoMessage() {} +func (*GetUserTagByIDReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{16} +} +func (m *GetUserTagByIDReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserTagByIDReq.Unmarshal(m, b) +} +func (m *GetUserTagByIDReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserTagByIDReq.Marshal(b, m, deterministic) +} +func (dst *GetUserTagByIDReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserTagByIDReq.Merge(dst, src) +} +func (m *GetUserTagByIDReq) XXX_Size() int { + return xxx_messageInfo_GetUserTagByIDReq.Size(m) +} +func (m *GetUserTagByIDReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserTagByIDReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserTagByIDReq proto.InternalMessageInfo + +func (m *GetUserTagByIDReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserTagByIDReq) GetTagID() string { + if m != nil { + return m.TagID + } + return "" +} + +func (m *GetUserTagByIDReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUserTagByIDResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Tag *Tag `protobuf:"bytes,2,opt,name=tag" json:"tag,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserTagByIDResp) Reset() { *m = GetUserTagByIDResp{} } +func (m *GetUserTagByIDResp) String() string { return proto.CompactTextString(m) } +func (*GetUserTagByIDResp) ProtoMessage() {} +func (*GetUserTagByIDResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{17} +} +func (m *GetUserTagByIDResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserTagByIDResp.Unmarshal(m, b) +} +func (m *GetUserTagByIDResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserTagByIDResp.Marshal(b, m, deterministic) +} +func (dst *GetUserTagByIDResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserTagByIDResp.Merge(dst, src) +} +func (m *GetUserTagByIDResp) XXX_Size() int { + return xxx_messageInfo_GetUserTagByIDResp.Size(m) +} +func (m *GetUserTagByIDResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserTagByIDResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserTagByIDResp proto.InternalMessageInfo + +func (m *GetUserTagByIDResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserTagByIDResp) GetTag() *Tag { + if m != nil { + return m.Tag + } + return nil +} + +type LikeUser struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + UserName string `protobuf:"bytes,2,opt,name=userName" json:"userName,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LikeUser) Reset() { *m = LikeUser{} } +func (m *LikeUser) String() string { return proto.CompactTextString(m) } +func (*LikeUser) ProtoMessage() {} +func (*LikeUser) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{18} +} +func (m *LikeUser) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LikeUser.Unmarshal(m, b) +} +func (m *LikeUser) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LikeUser.Marshal(b, m, deterministic) +} +func (dst *LikeUser) XXX_Merge(src proto.Message) { + xxx_messageInfo_LikeUser.Merge(dst, src) +} +func (m *LikeUser) XXX_Size() int { + return xxx_messageInfo_LikeUser.Size(m) +} +func (m *LikeUser) XXX_DiscardUnknown() { + xxx_messageInfo_LikeUser.DiscardUnknown(m) +} + +var xxx_messageInfo_LikeUser proto.InternalMessageInfo + +func (m *LikeUser) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *LikeUser) GetUserName() string { + if m != nil { + return m.UserName + } + return "" +} + +type Comment struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + UserName string `protobuf:"bytes,2,opt,name=userName" json:"userName,omitempty"` + ReplyUserID string `protobuf:"bytes,3,opt,name=replyUserID" json:"replyUserID,omitempty"` + ReplyUserName string `protobuf:"bytes,4,opt,name=replyUserName" json:"replyUserName,omitempty"` + ContentID string `protobuf:"bytes,5,opt,name=contentID" json:"contentID,omitempty"` + Content string `protobuf:"bytes,6,opt,name=content" json:"content,omitempty"` + CreateTime int32 `protobuf:"varint,7,opt,name=createTime" json:"createTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Comment) Reset() { *m = Comment{} } +func (m *Comment) String() string { return proto.CompactTextString(m) } +func (*Comment) ProtoMessage() {} +func (*Comment) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{19} +} +func (m *Comment) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Comment.Unmarshal(m, b) +} +func (m *Comment) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Comment.Marshal(b, m, deterministic) +} +func (dst *Comment) XXX_Merge(src proto.Message) { + xxx_messageInfo_Comment.Merge(dst, src) +} +func (m *Comment) XXX_Size() int { + return xxx_messageInfo_Comment.Size(m) +} +func (m *Comment) XXX_DiscardUnknown() { + xxx_messageInfo_Comment.DiscardUnknown(m) +} + +var xxx_messageInfo_Comment proto.InternalMessageInfo + +func (m *Comment) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *Comment) GetUserName() string { + if m != nil { + return m.UserName + } + return "" +} + +func (m *Comment) GetReplyUserID() string { + if m != nil { + return m.ReplyUserID + } + return "" +} + +func (m *Comment) GetReplyUserName() string { + if m != nil { + return m.ReplyUserName + } + return "" +} + +func (m *Comment) GetContentID() string { + if m != nil { + return m.ContentID + } + return "" +} + +func (m *Comment) GetContent() string { + if m != nil { + return m.Content + } + return "" +} + +func (m *Comment) GetCreateTime() int32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +type WorkMoment struct { + WorkMomentID string `protobuf:"bytes,1,opt,name=workMomentID" json:"workMomentID,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content" json:"content,omitempty"` + LikeUsers []*LikeUser `protobuf:"bytes,4,rep,name=likeUsers" json:"likeUsers,omitempty"` + Comments []*Comment `protobuf:"bytes,5,rep,name=comments" json:"comments,omitempty"` + WhoCanSeeUserIDList []string `protobuf:"bytes,6,rep,name=whoCanSeeUserIDList" json:"whoCanSeeUserIDList,omitempty"` + WhoCantSeeUserIDList []string `protobuf:"bytes,7,rep,name=whoCantSeeUserIDList" json:"whoCantSeeUserIDList,omitempty"` + IsPrivate bool `protobuf:"varint,8,opt,name=isPrivate" json:"isPrivate,omitempty"` + IsPublic bool `protobuf:"varint,9,opt,name=isPublic" json:"isPublic,omitempty"` + CreateTime int32 `protobuf:"varint,10,opt,name=CreateTime" json:"CreateTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WorkMoment) Reset() { *m = WorkMoment{} } +func (m *WorkMoment) String() string { return proto.CompactTextString(m) } +func (*WorkMoment) ProtoMessage() {} +func (*WorkMoment) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{20} +} +func (m *WorkMoment) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_WorkMoment.Unmarshal(m, b) +} +func (m *WorkMoment) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_WorkMoment.Marshal(b, m, deterministic) +} +func (dst *WorkMoment) XXX_Merge(src proto.Message) { + xxx_messageInfo_WorkMoment.Merge(dst, src) +} +func (m *WorkMoment) XXX_Size() int { + return xxx_messageInfo_WorkMoment.Size(m) +} +func (m *WorkMoment) XXX_DiscardUnknown() { + xxx_messageInfo_WorkMoment.DiscardUnknown(m) +} + +var xxx_messageInfo_WorkMoment proto.InternalMessageInfo + +func (m *WorkMoment) GetWorkMomentID() string { + if m != nil { + return m.WorkMomentID + } + return "" +} + +func (m *WorkMoment) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *WorkMoment) GetContent() string { + if m != nil { + return m.Content + } + return "" +} + +func (m *WorkMoment) GetLikeUsers() []*LikeUser { + if m != nil { + return m.LikeUsers + } + return nil +} + +func (m *WorkMoment) GetComments() []*Comment { + if m != nil { + return m.Comments + } + return nil +} + +func (m *WorkMoment) GetWhoCanSeeUserIDList() []string { + if m != nil { + return m.WhoCanSeeUserIDList + } + return nil +} + +func (m *WorkMoment) GetWhoCantSeeUserIDList() []string { + if m != nil { + return m.WhoCantSeeUserIDList + } + return nil +} + +func (m *WorkMoment) GetIsPrivate() bool { + if m != nil { + return m.IsPrivate + } + return false +} + +func (m *WorkMoment) GetIsPublic() bool { + if m != nil { + return m.IsPublic + } + return false +} + +func (m *WorkMoment) GetCreateTime() int32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +type CreateOneWorkMomentReq struct { + WorkMoment *WorkMoment `protobuf:"bytes,1,opt,name=workMoment" json:"workMoment,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateOneWorkMomentReq) Reset() { *m = CreateOneWorkMomentReq{} } +func (m *CreateOneWorkMomentReq) String() string { return proto.CompactTextString(m) } +func (*CreateOneWorkMomentReq) ProtoMessage() {} +func (*CreateOneWorkMomentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{21} +} +func (m *CreateOneWorkMomentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateOneWorkMomentReq.Unmarshal(m, b) +} +func (m *CreateOneWorkMomentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateOneWorkMomentReq.Marshal(b, m, deterministic) +} +func (dst *CreateOneWorkMomentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateOneWorkMomentReq.Merge(dst, src) +} +func (m *CreateOneWorkMomentReq) XXX_Size() int { + return xxx_messageInfo_CreateOneWorkMomentReq.Size(m) +} +func (m *CreateOneWorkMomentReq) XXX_DiscardUnknown() { + xxx_messageInfo_CreateOneWorkMomentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateOneWorkMomentReq proto.InternalMessageInfo + +func (m *CreateOneWorkMomentReq) GetWorkMoment() *WorkMoment { + if m != nil { + return m.WorkMoment + } + return nil +} + +func (m *CreateOneWorkMomentReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *CreateOneWorkMomentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type CreateOneWorkMomentResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateOneWorkMomentResp) Reset() { *m = CreateOneWorkMomentResp{} } +func (m *CreateOneWorkMomentResp) String() string { return proto.CompactTextString(m) } +func (*CreateOneWorkMomentResp) ProtoMessage() {} +func (*CreateOneWorkMomentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{22} +} +func (m *CreateOneWorkMomentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateOneWorkMomentResp.Unmarshal(m, b) +} +func (m *CreateOneWorkMomentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateOneWorkMomentResp.Marshal(b, m, deterministic) +} +func (dst *CreateOneWorkMomentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateOneWorkMomentResp.Merge(dst, src) +} +func (m *CreateOneWorkMomentResp) XXX_Size() int { + return xxx_messageInfo_CreateOneWorkMomentResp.Size(m) +} +func (m *CreateOneWorkMomentResp) XXX_DiscardUnknown() { + xxx_messageInfo_CreateOneWorkMomentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateOneWorkMomentResp proto.InternalMessageInfo + +func (m *CreateOneWorkMomentResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type DeleteOneWorkMomentReq struct { + WorkMomentID string `protobuf:"bytes,1,opt,name=workMomentID" json:"workMomentID,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteOneWorkMomentReq) Reset() { *m = DeleteOneWorkMomentReq{} } +func (m *DeleteOneWorkMomentReq) String() string { return proto.CompactTextString(m) } +func (*DeleteOneWorkMomentReq) ProtoMessage() {} +func (*DeleteOneWorkMomentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{23} +} +func (m *DeleteOneWorkMomentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteOneWorkMomentReq.Unmarshal(m, b) +} +func (m *DeleteOneWorkMomentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteOneWorkMomentReq.Marshal(b, m, deterministic) +} +func (dst *DeleteOneWorkMomentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteOneWorkMomentReq.Merge(dst, src) +} +func (m *DeleteOneWorkMomentReq) XXX_Size() int { + return xxx_messageInfo_DeleteOneWorkMomentReq.Size(m) +} +func (m *DeleteOneWorkMomentReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteOneWorkMomentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteOneWorkMomentReq proto.InternalMessageInfo + +func (m *DeleteOneWorkMomentReq) GetWorkMomentID() string { + if m != nil { + return m.WorkMomentID + } + return "" +} + +func (m *DeleteOneWorkMomentReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *DeleteOneWorkMomentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type DeleteOneWorkMomentResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteOneWorkMomentResp) Reset() { *m = DeleteOneWorkMomentResp{} } +func (m *DeleteOneWorkMomentResp) String() string { return proto.CompactTextString(m) } +func (*DeleteOneWorkMomentResp) ProtoMessage() {} +func (*DeleteOneWorkMomentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{24} +} +func (m *DeleteOneWorkMomentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteOneWorkMomentResp.Unmarshal(m, b) +} +func (m *DeleteOneWorkMomentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteOneWorkMomentResp.Marshal(b, m, deterministic) +} +func (dst *DeleteOneWorkMomentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteOneWorkMomentResp.Merge(dst, src) +} +func (m *DeleteOneWorkMomentResp) XXX_Size() int { + return xxx_messageInfo_DeleteOneWorkMomentResp.Size(m) +} +func (m *DeleteOneWorkMomentResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteOneWorkMomentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteOneWorkMomentResp proto.InternalMessageInfo + +func (m *DeleteOneWorkMomentResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type LikeOneWorkMomentReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + WorkMomentID string `protobuf:"bytes,2,opt,name=WorkMomentID" json:"WorkMomentID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LikeOneWorkMomentReq) Reset() { *m = LikeOneWorkMomentReq{} } +func (m *LikeOneWorkMomentReq) String() string { return proto.CompactTextString(m) } +func (*LikeOneWorkMomentReq) ProtoMessage() {} +func (*LikeOneWorkMomentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{25} +} +func (m *LikeOneWorkMomentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LikeOneWorkMomentReq.Unmarshal(m, b) +} +func (m *LikeOneWorkMomentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LikeOneWorkMomentReq.Marshal(b, m, deterministic) +} +func (dst *LikeOneWorkMomentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_LikeOneWorkMomentReq.Merge(dst, src) +} +func (m *LikeOneWorkMomentReq) XXX_Size() int { + return xxx_messageInfo_LikeOneWorkMomentReq.Size(m) +} +func (m *LikeOneWorkMomentReq) XXX_DiscardUnknown() { + xxx_messageInfo_LikeOneWorkMomentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_LikeOneWorkMomentReq proto.InternalMessageInfo + +func (m *LikeOneWorkMomentReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *LikeOneWorkMomentReq) GetWorkMomentID() string { + if m != nil { + return m.WorkMomentID + } + return "" +} + +func (m *LikeOneWorkMomentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type LikeOneWorkMomentResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LikeOneWorkMomentResp) Reset() { *m = LikeOneWorkMomentResp{} } +func (m *LikeOneWorkMomentResp) String() string { return proto.CompactTextString(m) } +func (*LikeOneWorkMomentResp) ProtoMessage() {} +func (*LikeOneWorkMomentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{26} +} +func (m *LikeOneWorkMomentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LikeOneWorkMomentResp.Unmarshal(m, b) +} +func (m *LikeOneWorkMomentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LikeOneWorkMomentResp.Marshal(b, m, deterministic) +} +func (dst *LikeOneWorkMomentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_LikeOneWorkMomentResp.Merge(dst, src) +} +func (m *LikeOneWorkMomentResp) XXX_Size() int { + return xxx_messageInfo_LikeOneWorkMomentResp.Size(m) +} +func (m *LikeOneWorkMomentResp) XXX_DiscardUnknown() { + xxx_messageInfo_LikeOneWorkMomentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_LikeOneWorkMomentResp proto.InternalMessageInfo + +func (m *LikeOneWorkMomentResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type CommentOneWorkMomentReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + WorkMomentID string `protobuf:"bytes,2,opt,name=workMomentID" json:"workMomentID,omitempty"` + ReplyUserID string `protobuf:"bytes,3,opt,name=replyUserID" json:"replyUserID,omitempty"` + Content string `protobuf:"bytes,4,opt,name=content" json:"content,omitempty"` + OperationID string `protobuf:"bytes,5,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommentOneWorkMomentReq) Reset() { *m = CommentOneWorkMomentReq{} } +func (m *CommentOneWorkMomentReq) String() string { return proto.CompactTextString(m) } +func (*CommentOneWorkMomentReq) ProtoMessage() {} +func (*CommentOneWorkMomentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{27} +} +func (m *CommentOneWorkMomentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommentOneWorkMomentReq.Unmarshal(m, b) +} +func (m *CommentOneWorkMomentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommentOneWorkMomentReq.Marshal(b, m, deterministic) +} +func (dst *CommentOneWorkMomentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommentOneWorkMomentReq.Merge(dst, src) +} +func (m *CommentOneWorkMomentReq) XXX_Size() int { + return xxx_messageInfo_CommentOneWorkMomentReq.Size(m) +} +func (m *CommentOneWorkMomentReq) XXX_DiscardUnknown() { + xxx_messageInfo_CommentOneWorkMomentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CommentOneWorkMomentReq proto.InternalMessageInfo + +func (m *CommentOneWorkMomentReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *CommentOneWorkMomentReq) GetWorkMomentID() string { + if m != nil { + return m.WorkMomentID + } + return "" +} + +func (m *CommentOneWorkMomentReq) GetReplyUserID() string { + if m != nil { + return m.ReplyUserID + } + return "" +} + +func (m *CommentOneWorkMomentReq) GetContent() string { + if m != nil { + return m.Content + } + return "" +} + +func (m *CommentOneWorkMomentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type CommentOneWorkMomentResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommentOneWorkMomentResp) Reset() { *m = CommentOneWorkMomentResp{} } +func (m *CommentOneWorkMomentResp) String() string { return proto.CompactTextString(m) } +func (*CommentOneWorkMomentResp) ProtoMessage() {} +func (*CommentOneWorkMomentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{28} +} +func (m *CommentOneWorkMomentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommentOneWorkMomentResp.Unmarshal(m, b) +} +func (m *CommentOneWorkMomentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommentOneWorkMomentResp.Marshal(b, m, deterministic) +} +func (dst *CommentOneWorkMomentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommentOneWorkMomentResp.Merge(dst, src) +} +func (m *CommentOneWorkMomentResp) XXX_Size() int { + return xxx_messageInfo_CommentOneWorkMomentResp.Size(m) +} +func (m *CommentOneWorkMomentResp) XXX_DiscardUnknown() { + xxx_messageInfo_CommentOneWorkMomentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CommentOneWorkMomentResp proto.InternalMessageInfo + +func (m *CommentOneWorkMomentResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetUserWorkMomentsReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserWorkMomentsReq) Reset() { *m = GetUserWorkMomentsReq{} } +func (m *GetUserWorkMomentsReq) String() string { return proto.CompactTextString(m) } +func (*GetUserWorkMomentsReq) ProtoMessage() {} +func (*GetUserWorkMomentsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{29} +} +func (m *GetUserWorkMomentsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserWorkMomentsReq.Unmarshal(m, b) +} +func (m *GetUserWorkMomentsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserWorkMomentsReq.Marshal(b, m, deterministic) +} +func (dst *GetUserWorkMomentsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserWorkMomentsReq.Merge(dst, src) +} +func (m *GetUserWorkMomentsReq) XXX_Size() int { + return xxx_messageInfo_GetUserWorkMomentsReq.Size(m) +} +func (m *GetUserWorkMomentsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserWorkMomentsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserWorkMomentsReq proto.InternalMessageInfo + +func (m *GetUserWorkMomentsReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserWorkMomentsReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetUserWorkMomentsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUserWorkMomentsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + WorkMoments []*WorkMoment `protobuf:"bytes,2,rep,name=workMoments" json:"workMoments,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserWorkMomentsResp) Reset() { *m = GetUserWorkMomentsResp{} } +func (m *GetUserWorkMomentsResp) String() string { return proto.CompactTextString(m) } +func (*GetUserWorkMomentsResp) ProtoMessage() {} +func (*GetUserWorkMomentsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{30} +} +func (m *GetUserWorkMomentsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserWorkMomentsResp.Unmarshal(m, b) +} +func (m *GetUserWorkMomentsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserWorkMomentsResp.Marshal(b, m, deterministic) +} +func (dst *GetUserWorkMomentsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserWorkMomentsResp.Merge(dst, src) +} +func (m *GetUserWorkMomentsResp) XXX_Size() int { + return xxx_messageInfo_GetUserWorkMomentsResp.Size(m) +} +func (m *GetUserWorkMomentsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserWorkMomentsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserWorkMomentsResp proto.InternalMessageInfo + +func (m *GetUserWorkMomentsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserWorkMomentsResp) GetWorkMoments() []*WorkMoment { + if m != nil { + return m.WorkMoments + } + return nil +} + +func (m *GetUserWorkMomentsResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +type GetUserFriendWorkMomentsReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserFriendWorkMomentsReq) Reset() { *m = GetUserFriendWorkMomentsReq{} } +func (m *GetUserFriendWorkMomentsReq) String() string { return proto.CompactTextString(m) } +func (*GetUserFriendWorkMomentsReq) ProtoMessage() {} +func (*GetUserFriendWorkMomentsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{31} +} +func (m *GetUserFriendWorkMomentsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserFriendWorkMomentsReq.Unmarshal(m, b) +} +func (m *GetUserFriendWorkMomentsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserFriendWorkMomentsReq.Marshal(b, m, deterministic) +} +func (dst *GetUserFriendWorkMomentsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserFriendWorkMomentsReq.Merge(dst, src) +} +func (m *GetUserFriendWorkMomentsReq) XXX_Size() int { + return xxx_messageInfo_GetUserFriendWorkMomentsReq.Size(m) +} +func (m *GetUserFriendWorkMomentsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserFriendWorkMomentsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserFriendWorkMomentsReq proto.InternalMessageInfo + +func (m *GetUserFriendWorkMomentsReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserFriendWorkMomentsReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetUserFriendWorkMomentsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUserFriendWorkMomentsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + WorkMoments []*WorkMoment `protobuf:"bytes,2,rep,name=workMoments" json:"workMoments,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserFriendWorkMomentsResp) Reset() { *m = GetUserFriendWorkMomentsResp{} } +func (m *GetUserFriendWorkMomentsResp) String() string { return proto.CompactTextString(m) } +func (*GetUserFriendWorkMomentsResp) ProtoMessage() {} +func (*GetUserFriendWorkMomentsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{32} +} +func (m *GetUserFriendWorkMomentsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserFriendWorkMomentsResp.Unmarshal(m, b) +} +func (m *GetUserFriendWorkMomentsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserFriendWorkMomentsResp.Marshal(b, m, deterministic) +} +func (dst *GetUserFriendWorkMomentsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserFriendWorkMomentsResp.Merge(dst, src) +} +func (m *GetUserFriendWorkMomentsResp) XXX_Size() int { + return xxx_messageInfo_GetUserFriendWorkMomentsResp.Size(m) +} +func (m *GetUserFriendWorkMomentsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserFriendWorkMomentsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserFriendWorkMomentsResp proto.InternalMessageInfo + +func (m *GetUserFriendWorkMomentsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserFriendWorkMomentsResp) GetWorkMoments() []*WorkMoment { + if m != nil { + return m.WorkMoments + } + return nil +} + +func (m *GetUserFriendWorkMomentsResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +type CommentsMsg struct { + Comment *Comment `protobuf:"bytes,1,opt,name=comment" json:"comment,omitempty"` + WorkMomentID string `protobuf:"bytes,2,opt,name=workMomentID" json:"workMomentID,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content" json:"content,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommentsMsg) Reset() { *m = CommentsMsg{} } +func (m *CommentsMsg) String() string { return proto.CompactTextString(m) } +func (*CommentsMsg) ProtoMessage() {} +func (*CommentsMsg) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{33} +} +func (m *CommentsMsg) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommentsMsg.Unmarshal(m, b) +} +func (m *CommentsMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommentsMsg.Marshal(b, m, deterministic) +} +func (dst *CommentsMsg) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommentsMsg.Merge(dst, src) +} +func (m *CommentsMsg) XXX_Size() int { + return xxx_messageInfo_CommentsMsg.Size(m) +} +func (m *CommentsMsg) XXX_DiscardUnknown() { + xxx_messageInfo_CommentsMsg.DiscardUnknown(m) +} + +var xxx_messageInfo_CommentsMsg proto.InternalMessageInfo + +func (m *CommentsMsg) GetComment() *Comment { + if m != nil { + return m.Comment + } + return nil +} + +func (m *CommentsMsg) GetWorkMomentID() string { + if m != nil { + return m.WorkMomentID + } + return "" +} + +func (m *CommentsMsg) GetContent() string { + if m != nil { + return m.Content + } + return "" +} + +type GetUserWorkMomentsCommentsMsgReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserWorkMomentsCommentsMsgReq) Reset() { *m = GetUserWorkMomentsCommentsMsgReq{} } +func (m *GetUserWorkMomentsCommentsMsgReq) String() string { return proto.CompactTextString(m) } +func (*GetUserWorkMomentsCommentsMsgReq) ProtoMessage() {} +func (*GetUserWorkMomentsCommentsMsgReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{34} +} +func (m *GetUserWorkMomentsCommentsMsgReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserWorkMomentsCommentsMsgReq.Unmarshal(m, b) +} +func (m *GetUserWorkMomentsCommentsMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserWorkMomentsCommentsMsgReq.Marshal(b, m, deterministic) +} +func (dst *GetUserWorkMomentsCommentsMsgReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserWorkMomentsCommentsMsgReq.Merge(dst, src) +} +func (m *GetUserWorkMomentsCommentsMsgReq) XXX_Size() int { + return xxx_messageInfo_GetUserWorkMomentsCommentsMsgReq.Size(m) +} +func (m *GetUserWorkMomentsCommentsMsgReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserWorkMomentsCommentsMsgReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserWorkMomentsCommentsMsgReq proto.InternalMessageInfo + +func (m *GetUserWorkMomentsCommentsMsgReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserWorkMomentsCommentsMsgReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetUserWorkMomentsCommentsMsgReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +type GetUserWorkMomentsCommentsMsgResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + CommentsMsgs []*CommentsMsg `protobuf:"bytes,2,rep,name=commentsMsgs" json:"commentsMsgs,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserWorkMomentsCommentsMsgResp) Reset() { *m = GetUserWorkMomentsCommentsMsgResp{} } +func (m *GetUserWorkMomentsCommentsMsgResp) String() string { return proto.CompactTextString(m) } +func (*GetUserWorkMomentsCommentsMsgResp) ProtoMessage() {} +func (*GetUserWorkMomentsCommentsMsgResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{35} +} +func (m *GetUserWorkMomentsCommentsMsgResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserWorkMomentsCommentsMsgResp.Unmarshal(m, b) +} +func (m *GetUserWorkMomentsCommentsMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserWorkMomentsCommentsMsgResp.Marshal(b, m, deterministic) +} +func (dst *GetUserWorkMomentsCommentsMsgResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserWorkMomentsCommentsMsgResp.Merge(dst, src) +} +func (m *GetUserWorkMomentsCommentsMsgResp) XXX_Size() int { + return xxx_messageInfo_GetUserWorkMomentsCommentsMsgResp.Size(m) +} +func (m *GetUserWorkMomentsCommentsMsgResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserWorkMomentsCommentsMsgResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserWorkMomentsCommentsMsgResp proto.InternalMessageInfo + +func (m *GetUserWorkMomentsCommentsMsgResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserWorkMomentsCommentsMsgResp) GetCommentsMsgs() []*CommentsMsg { + if m != nil { + return m.CommentsMsgs + } + return nil +} + +func (m *GetUserWorkMomentsCommentsMsgResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +type ClearUserWorkMomentsCommentsMsgReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ClearUserWorkMomentsCommentsMsgReq) Reset() { *m = ClearUserWorkMomentsCommentsMsgReq{} } +func (m *ClearUserWorkMomentsCommentsMsgReq) String() string { return proto.CompactTextString(m) } +func (*ClearUserWorkMomentsCommentsMsgReq) ProtoMessage() {} +func (*ClearUserWorkMomentsCommentsMsgReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{36} +} +func (m *ClearUserWorkMomentsCommentsMsgReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ClearUserWorkMomentsCommentsMsgReq.Unmarshal(m, b) +} +func (m *ClearUserWorkMomentsCommentsMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ClearUserWorkMomentsCommentsMsgReq.Marshal(b, m, deterministic) +} +func (dst *ClearUserWorkMomentsCommentsMsgReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClearUserWorkMomentsCommentsMsgReq.Merge(dst, src) +} +func (m *ClearUserWorkMomentsCommentsMsgReq) XXX_Size() int { + return xxx_messageInfo_ClearUserWorkMomentsCommentsMsgReq.Size(m) +} +func (m *ClearUserWorkMomentsCommentsMsgReq) XXX_DiscardUnknown() { + xxx_messageInfo_ClearUserWorkMomentsCommentsMsgReq.DiscardUnknown(m) +} + +var xxx_messageInfo_ClearUserWorkMomentsCommentsMsgReq proto.InternalMessageInfo + +func (m *ClearUserWorkMomentsCommentsMsgReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *ClearUserWorkMomentsCommentsMsgReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type ClearUserWorkMomentsCommentsMsgResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ClearUserWorkMomentsCommentsMsgResp) Reset() { *m = ClearUserWorkMomentsCommentsMsgResp{} } +func (m *ClearUserWorkMomentsCommentsMsgResp) String() string { return proto.CompactTextString(m) } +func (*ClearUserWorkMomentsCommentsMsgResp) ProtoMessage() {} +func (*ClearUserWorkMomentsCommentsMsgResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{37} +} +func (m *ClearUserWorkMomentsCommentsMsgResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ClearUserWorkMomentsCommentsMsgResp.Unmarshal(m, b) +} +func (m *ClearUserWorkMomentsCommentsMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ClearUserWorkMomentsCommentsMsgResp.Marshal(b, m, deterministic) +} +func (dst *ClearUserWorkMomentsCommentsMsgResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClearUserWorkMomentsCommentsMsgResp.Merge(dst, src) +} +func (m *ClearUserWorkMomentsCommentsMsgResp) XXX_Size() int { + return xxx_messageInfo_ClearUserWorkMomentsCommentsMsgResp.Size(m) +} +func (m *ClearUserWorkMomentsCommentsMsgResp) XXX_DiscardUnknown() { + xxx_messageInfo_ClearUserWorkMomentsCommentsMsgResp.DiscardUnknown(m) +} + +var xxx_messageInfo_ClearUserWorkMomentsCommentsMsgResp proto.InternalMessageInfo + +func (m *ClearUserWorkMomentsCommentsMsgResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type SetUserWorkMomentsLevelReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Level int32 `protobuf:"varint,2,opt,name=level" json:"level,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetUserWorkMomentsLevelReq) Reset() { *m = SetUserWorkMomentsLevelReq{} } +func (m *SetUserWorkMomentsLevelReq) String() string { return proto.CompactTextString(m) } +func (*SetUserWorkMomentsLevelReq) ProtoMessage() {} +func (*SetUserWorkMomentsLevelReq) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{38} +} +func (m *SetUserWorkMomentsLevelReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetUserWorkMomentsLevelReq.Unmarshal(m, b) +} +func (m *SetUserWorkMomentsLevelReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetUserWorkMomentsLevelReq.Marshal(b, m, deterministic) +} +func (dst *SetUserWorkMomentsLevelReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetUserWorkMomentsLevelReq.Merge(dst, src) +} +func (m *SetUserWorkMomentsLevelReq) XXX_Size() int { + return xxx_messageInfo_SetUserWorkMomentsLevelReq.Size(m) +} +func (m *SetUserWorkMomentsLevelReq) XXX_DiscardUnknown() { + xxx_messageInfo_SetUserWorkMomentsLevelReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SetUserWorkMomentsLevelReq proto.InternalMessageInfo + +func (m *SetUserWorkMomentsLevelReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *SetUserWorkMomentsLevelReq) GetLevel() int32 { + if m != nil { + return m.Level + } + return 0 +} + +func (m *SetUserWorkMomentsLevelReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type SetUserWorkMomentsLevelResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetUserWorkMomentsLevelResp) Reset() { *m = SetUserWorkMomentsLevelResp{} } +func (m *SetUserWorkMomentsLevelResp) String() string { return proto.CompactTextString(m) } +func (*SetUserWorkMomentsLevelResp) ProtoMessage() {} +func (*SetUserWorkMomentsLevelResp) Descriptor() ([]byte, []int) { + return fileDescriptor_office_8a5f7d4f1783db20, []int{39} +} +func (m *SetUserWorkMomentsLevelResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetUserWorkMomentsLevelResp.Unmarshal(m, b) +} +func (m *SetUserWorkMomentsLevelResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetUserWorkMomentsLevelResp.Marshal(b, m, deterministic) +} +func (dst *SetUserWorkMomentsLevelResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetUserWorkMomentsLevelResp.Merge(dst, src) +} +func (m *SetUserWorkMomentsLevelResp) XXX_Size() int { + return xxx_messageInfo_SetUserWorkMomentsLevelResp.Size(m) +} +func (m *SetUserWorkMomentsLevelResp) XXX_DiscardUnknown() { + xxx_messageInfo_SetUserWorkMomentsLevelResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SetUserWorkMomentsLevelResp proto.InternalMessageInfo + +func (m *SetUserWorkMomentsLevelResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func init() { + proto.RegisterType((*CommonResp)(nil), "office.CommonResp") + proto.RegisterType((*TagUser)(nil), "office.TagUser") + proto.RegisterType((*Tag)(nil), "office.Tag") + proto.RegisterType((*GetUserTagsReq)(nil), "office.GetUserTagsReq") + proto.RegisterType((*GetUserTagsResp)(nil), "office.GetUserTagsResp") + proto.RegisterType((*CreateTagReq)(nil), "office.CreateTagReq") + proto.RegisterType((*CreateTagResp)(nil), "office.CreateTagResp") + proto.RegisterType((*DeleteTagReq)(nil), "office.DeleteTagReq") + proto.RegisterType((*DeleteTagResp)(nil), "office.DeleteTagResp") + proto.RegisterType((*SetTagReq)(nil), "office.SetTagReq") + proto.RegisterType((*SetTagResp)(nil), "office.SetTagResp") + proto.RegisterType((*SendMsg2TagReq)(nil), "office.SendMsg2TagReq") + proto.RegisterType((*SendMsg2TagResp)(nil), "office.SendMsg2TagResp") + proto.RegisterType((*GetTagSendLogsReq)(nil), "office.GetTagSendLogsReq") + proto.RegisterType((*TagSendLog)(nil), "office.TagSendLog") + proto.RegisterType((*GetTagSendLogsResp)(nil), "office.GetTagSendLogsResp") + proto.RegisterType((*GetUserTagByIDReq)(nil), "office.GetUserTagByIDReq") + proto.RegisterType((*GetUserTagByIDResp)(nil), "office.GetUserTagByIDResp") + proto.RegisterType((*LikeUser)(nil), "office.LikeUser") + proto.RegisterType((*Comment)(nil), "office.Comment") + proto.RegisterType((*WorkMoment)(nil), "office.WorkMoment") + proto.RegisterType((*CreateOneWorkMomentReq)(nil), "office.CreateOneWorkMomentReq") + proto.RegisterType((*CreateOneWorkMomentResp)(nil), "office.CreateOneWorkMomentResp") + proto.RegisterType((*DeleteOneWorkMomentReq)(nil), "office.DeleteOneWorkMomentReq") + proto.RegisterType((*DeleteOneWorkMomentResp)(nil), "office.DeleteOneWorkMomentResp") + proto.RegisterType((*LikeOneWorkMomentReq)(nil), "office.LikeOneWorkMomentReq") + proto.RegisterType((*LikeOneWorkMomentResp)(nil), "office.LikeOneWorkMomentResp") + proto.RegisterType((*CommentOneWorkMomentReq)(nil), "office.CommentOneWorkMomentReq") + proto.RegisterType((*CommentOneWorkMomentResp)(nil), "office.CommentOneWorkMomentResp") + proto.RegisterType((*GetUserWorkMomentsReq)(nil), "office.GetUserWorkMomentsReq") + proto.RegisterType((*GetUserWorkMomentsResp)(nil), "office.GetUserWorkMomentsResp") + proto.RegisterType((*GetUserFriendWorkMomentsReq)(nil), "office.GetUserFriendWorkMomentsReq") + proto.RegisterType((*GetUserFriendWorkMomentsResp)(nil), "office.GetUserFriendWorkMomentsResp") + proto.RegisterType((*CommentsMsg)(nil), "office.CommentsMsg") + proto.RegisterType((*GetUserWorkMomentsCommentsMsgReq)(nil), "office.GetUserWorkMomentsCommentsMsgReq") + proto.RegisterType((*GetUserWorkMomentsCommentsMsgResp)(nil), "office.GetUserWorkMomentsCommentsMsgResp") + proto.RegisterType((*ClearUserWorkMomentsCommentsMsgReq)(nil), "office.ClearUserWorkMomentsCommentsMsgReq") + proto.RegisterType((*ClearUserWorkMomentsCommentsMsgResp)(nil), "office.ClearUserWorkMomentsCommentsMsgResp") + proto.RegisterType((*SetUserWorkMomentsLevelReq)(nil), "office.SetUserWorkMomentsLevelReq") + proto.RegisterType((*SetUserWorkMomentsLevelResp)(nil), "office.SetUserWorkMomentsLevelResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for OfficeService service + +type OfficeServiceClient interface { + GetUserTags(ctx context.Context, in *GetUserTagsReq, opts ...grpc.CallOption) (*GetUserTagsResp, error) + CreateTag(ctx context.Context, in *CreateTagReq, opts ...grpc.CallOption) (*CreateTagResp, error) + DeleteTag(ctx context.Context, in *DeleteTagReq, opts ...grpc.CallOption) (*DeleteTagResp, error) + SetTag(ctx context.Context, in *SetTagReq, opts ...grpc.CallOption) (*SetTagResp, error) + SendMsg2Tag(ctx context.Context, in *SendMsg2TagReq, opts ...grpc.CallOption) (*SendMsg2TagResp, error) + GetTagSendLogs(ctx context.Context, in *GetTagSendLogsReq, opts ...grpc.CallOption) (*GetTagSendLogsResp, error) + GetUserTagByID(ctx context.Context, in *GetUserTagByIDReq, opts ...grpc.CallOption) (*GetUserTagByIDResp, error) + CreateOneWorkMoment(ctx context.Context, in *CreateOneWorkMomentReq, opts ...grpc.CallOption) (*CreateOneWorkMomentResp, error) + DeleteOneWorkMoment(ctx context.Context, in *DeleteOneWorkMomentReq, opts ...grpc.CallOption) (*DeleteOneWorkMomentResp, error) + LikeOneWorkMoment(ctx context.Context, in *LikeOneWorkMomentReq, opts ...grpc.CallOption) (*LikeOneWorkMomentResp, error) + CommentOneWorkMoment(ctx context.Context, in *CommentOneWorkMomentReq, opts ...grpc.CallOption) (*CommentOneWorkMomentResp, error) + // / user self + GetUserWorkMoments(ctx context.Context, in *GetUserWorkMomentsReq, opts ...grpc.CallOption) (*GetUserWorkMomentsResp, error) + // / users friend + GetUserFriendWorkMoments(ctx context.Context, in *GetUserFriendWorkMomentsReq, opts ...grpc.CallOption) (*GetUserFriendWorkMomentsResp, error) + GetUserWorkMomentsCommentsMsg(ctx context.Context, in *GetUserWorkMomentsCommentsMsgReq, opts ...grpc.CallOption) (*GetUserWorkMomentsCommentsMsgResp, error) + ClearUserWorkMomentsCommentsMsg(ctx context.Context, in *ClearUserWorkMomentsCommentsMsgReq, opts ...grpc.CallOption) (*ClearUserWorkMomentsCommentsMsgResp, error) + SetUserWorkMomentsLevel(ctx context.Context, in *SetUserWorkMomentsLevelReq, opts ...grpc.CallOption) (*SetUserWorkMomentsLevelResp, error) +} + +type officeServiceClient struct { + cc *grpc.ClientConn +} + +func NewOfficeServiceClient(cc *grpc.ClientConn) OfficeServiceClient { + return &officeServiceClient{cc} +} + +func (c *officeServiceClient) GetUserTags(ctx context.Context, in *GetUserTagsReq, opts ...grpc.CallOption) (*GetUserTagsResp, error) { + out := new(GetUserTagsResp) + err := grpc.Invoke(ctx, "/office.OfficeService/GetUserTags", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) CreateTag(ctx context.Context, in *CreateTagReq, opts ...grpc.CallOption) (*CreateTagResp, error) { + out := new(CreateTagResp) + err := grpc.Invoke(ctx, "/office.OfficeService/CreateTag", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) DeleteTag(ctx context.Context, in *DeleteTagReq, opts ...grpc.CallOption) (*DeleteTagResp, error) { + out := new(DeleteTagResp) + err := grpc.Invoke(ctx, "/office.OfficeService/DeleteTag", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) SetTag(ctx context.Context, in *SetTagReq, opts ...grpc.CallOption) (*SetTagResp, error) { + out := new(SetTagResp) + err := grpc.Invoke(ctx, "/office.OfficeService/SetTag", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) SendMsg2Tag(ctx context.Context, in *SendMsg2TagReq, opts ...grpc.CallOption) (*SendMsg2TagResp, error) { + out := new(SendMsg2TagResp) + err := grpc.Invoke(ctx, "/office.OfficeService/SendMsg2Tag", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) GetTagSendLogs(ctx context.Context, in *GetTagSendLogsReq, opts ...grpc.CallOption) (*GetTagSendLogsResp, error) { + out := new(GetTagSendLogsResp) + err := grpc.Invoke(ctx, "/office.OfficeService/GetTagSendLogs", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) GetUserTagByID(ctx context.Context, in *GetUserTagByIDReq, opts ...grpc.CallOption) (*GetUserTagByIDResp, error) { + out := new(GetUserTagByIDResp) + err := grpc.Invoke(ctx, "/office.OfficeService/GetUserTagByID", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) CreateOneWorkMoment(ctx context.Context, in *CreateOneWorkMomentReq, opts ...grpc.CallOption) (*CreateOneWorkMomentResp, error) { + out := new(CreateOneWorkMomentResp) + err := grpc.Invoke(ctx, "/office.OfficeService/CreateOneWorkMoment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) DeleteOneWorkMoment(ctx context.Context, in *DeleteOneWorkMomentReq, opts ...grpc.CallOption) (*DeleteOneWorkMomentResp, error) { + out := new(DeleteOneWorkMomentResp) + err := grpc.Invoke(ctx, "/office.OfficeService/DeleteOneWorkMoment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) LikeOneWorkMoment(ctx context.Context, in *LikeOneWorkMomentReq, opts ...grpc.CallOption) (*LikeOneWorkMomentResp, error) { + out := new(LikeOneWorkMomentResp) + err := grpc.Invoke(ctx, "/office.OfficeService/LikeOneWorkMoment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) CommentOneWorkMoment(ctx context.Context, in *CommentOneWorkMomentReq, opts ...grpc.CallOption) (*CommentOneWorkMomentResp, error) { + out := new(CommentOneWorkMomentResp) + err := grpc.Invoke(ctx, "/office.OfficeService/CommentOneWorkMoment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) GetUserWorkMoments(ctx context.Context, in *GetUserWorkMomentsReq, opts ...grpc.CallOption) (*GetUserWorkMomentsResp, error) { + out := new(GetUserWorkMomentsResp) + err := grpc.Invoke(ctx, "/office.OfficeService/GetUserWorkMoments", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) GetUserFriendWorkMoments(ctx context.Context, in *GetUserFriendWorkMomentsReq, opts ...grpc.CallOption) (*GetUserFriendWorkMomentsResp, error) { + out := new(GetUserFriendWorkMomentsResp) + err := grpc.Invoke(ctx, "/office.OfficeService/GetUserFriendWorkMoments", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) GetUserWorkMomentsCommentsMsg(ctx context.Context, in *GetUserWorkMomentsCommentsMsgReq, opts ...grpc.CallOption) (*GetUserWorkMomentsCommentsMsgResp, error) { + out := new(GetUserWorkMomentsCommentsMsgResp) + err := grpc.Invoke(ctx, "/office.OfficeService/GetUserWorkMomentsCommentsMsg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) ClearUserWorkMomentsCommentsMsg(ctx context.Context, in *ClearUserWorkMomentsCommentsMsgReq, opts ...grpc.CallOption) (*ClearUserWorkMomentsCommentsMsgResp, error) { + out := new(ClearUserWorkMomentsCommentsMsgResp) + err := grpc.Invoke(ctx, "/office.OfficeService/ClearUserWorkMomentsCommentsMsg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *officeServiceClient) SetUserWorkMomentsLevel(ctx context.Context, in *SetUserWorkMomentsLevelReq, opts ...grpc.CallOption) (*SetUserWorkMomentsLevelResp, error) { + out := new(SetUserWorkMomentsLevelResp) + err := grpc.Invoke(ctx, "/office.OfficeService/SetUserWorkMomentsLevel", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for OfficeService service + +type OfficeServiceServer interface { + GetUserTags(context.Context, *GetUserTagsReq) (*GetUserTagsResp, error) + CreateTag(context.Context, *CreateTagReq) (*CreateTagResp, error) + DeleteTag(context.Context, *DeleteTagReq) (*DeleteTagResp, error) + SetTag(context.Context, *SetTagReq) (*SetTagResp, error) + SendMsg2Tag(context.Context, *SendMsg2TagReq) (*SendMsg2TagResp, error) + GetTagSendLogs(context.Context, *GetTagSendLogsReq) (*GetTagSendLogsResp, error) + GetUserTagByID(context.Context, *GetUserTagByIDReq) (*GetUserTagByIDResp, error) + CreateOneWorkMoment(context.Context, *CreateOneWorkMomentReq) (*CreateOneWorkMomentResp, error) + DeleteOneWorkMoment(context.Context, *DeleteOneWorkMomentReq) (*DeleteOneWorkMomentResp, error) + LikeOneWorkMoment(context.Context, *LikeOneWorkMomentReq) (*LikeOneWorkMomentResp, error) + CommentOneWorkMoment(context.Context, *CommentOneWorkMomentReq) (*CommentOneWorkMomentResp, error) + // / user self + GetUserWorkMoments(context.Context, *GetUserWorkMomentsReq) (*GetUserWorkMomentsResp, error) + // / users friend + GetUserFriendWorkMoments(context.Context, *GetUserFriendWorkMomentsReq) (*GetUserFriendWorkMomentsResp, error) + GetUserWorkMomentsCommentsMsg(context.Context, *GetUserWorkMomentsCommentsMsgReq) (*GetUserWorkMomentsCommentsMsgResp, error) + ClearUserWorkMomentsCommentsMsg(context.Context, *ClearUserWorkMomentsCommentsMsgReq) (*ClearUserWorkMomentsCommentsMsgResp, error) + SetUserWorkMomentsLevel(context.Context, *SetUserWorkMomentsLevelReq) (*SetUserWorkMomentsLevelResp, error) +} + +func RegisterOfficeServiceServer(s *grpc.Server, srv OfficeServiceServer) { + s.RegisterService(&_OfficeService_serviceDesc, srv) +} + +func _OfficeService_GetUserTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserTagsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).GetUserTags(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/GetUserTags", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).GetUserTags(ctx, req.(*GetUserTagsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_CreateTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateTagReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).CreateTag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/CreateTag", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).CreateTag(ctx, req.(*CreateTagReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_DeleteTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteTagReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).DeleteTag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/DeleteTag", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).DeleteTag(ctx, req.(*DeleteTagReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_SetTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetTagReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).SetTag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/SetTag", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).SetTag(ctx, req.(*SetTagReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_SendMsg2Tag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendMsg2TagReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).SendMsg2Tag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/SendMsg2Tag", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).SendMsg2Tag(ctx, req.(*SendMsg2TagReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_GetTagSendLogs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTagSendLogsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).GetTagSendLogs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/GetTagSendLogs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).GetTagSendLogs(ctx, req.(*GetTagSendLogsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_GetUserTagByID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserTagByIDReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).GetUserTagByID(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/GetUserTagByID", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).GetUserTagByID(ctx, req.(*GetUserTagByIDReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_CreateOneWorkMoment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateOneWorkMomentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).CreateOneWorkMoment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/CreateOneWorkMoment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).CreateOneWorkMoment(ctx, req.(*CreateOneWorkMomentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_DeleteOneWorkMoment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteOneWorkMomentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).DeleteOneWorkMoment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/DeleteOneWorkMoment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).DeleteOneWorkMoment(ctx, req.(*DeleteOneWorkMomentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_LikeOneWorkMoment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LikeOneWorkMomentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).LikeOneWorkMoment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/LikeOneWorkMoment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).LikeOneWorkMoment(ctx, req.(*LikeOneWorkMomentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_CommentOneWorkMoment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CommentOneWorkMomentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).CommentOneWorkMoment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/CommentOneWorkMoment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).CommentOneWorkMoment(ctx, req.(*CommentOneWorkMomentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_GetUserWorkMoments_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserWorkMomentsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).GetUserWorkMoments(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/GetUserWorkMoments", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).GetUserWorkMoments(ctx, req.(*GetUserWorkMomentsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_GetUserFriendWorkMoments_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserFriendWorkMomentsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).GetUserFriendWorkMoments(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/GetUserFriendWorkMoments", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).GetUserFriendWorkMoments(ctx, req.(*GetUserFriendWorkMomentsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_GetUserWorkMomentsCommentsMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserWorkMomentsCommentsMsgReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).GetUserWorkMomentsCommentsMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/GetUserWorkMomentsCommentsMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).GetUserWorkMomentsCommentsMsg(ctx, req.(*GetUserWorkMomentsCommentsMsgReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_ClearUserWorkMomentsCommentsMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ClearUserWorkMomentsCommentsMsgReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).ClearUserWorkMomentsCommentsMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/ClearUserWorkMomentsCommentsMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).ClearUserWorkMomentsCommentsMsg(ctx, req.(*ClearUserWorkMomentsCommentsMsgReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OfficeService_SetUserWorkMomentsLevel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetUserWorkMomentsLevelReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OfficeServiceServer).SetUserWorkMomentsLevel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/office.OfficeService/SetUserWorkMomentsLevel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OfficeServiceServer).SetUserWorkMomentsLevel(ctx, req.(*SetUserWorkMomentsLevelReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _OfficeService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "office.OfficeService", + HandlerType: (*OfficeServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetUserTags", + Handler: _OfficeService_GetUserTags_Handler, + }, + { + MethodName: "CreateTag", + Handler: _OfficeService_CreateTag_Handler, + }, + { + MethodName: "DeleteTag", + Handler: _OfficeService_DeleteTag_Handler, + }, + { + MethodName: "SetTag", + Handler: _OfficeService_SetTag_Handler, + }, + { + MethodName: "SendMsg2Tag", + Handler: _OfficeService_SendMsg2Tag_Handler, + }, + { + MethodName: "GetTagSendLogs", + Handler: _OfficeService_GetTagSendLogs_Handler, + }, + { + MethodName: "GetUserTagByID", + Handler: _OfficeService_GetUserTagByID_Handler, + }, + { + MethodName: "CreateOneWorkMoment", + Handler: _OfficeService_CreateOneWorkMoment_Handler, + }, + { + MethodName: "DeleteOneWorkMoment", + Handler: _OfficeService_DeleteOneWorkMoment_Handler, + }, + { + MethodName: "LikeOneWorkMoment", + Handler: _OfficeService_LikeOneWorkMoment_Handler, + }, + { + MethodName: "CommentOneWorkMoment", + Handler: _OfficeService_CommentOneWorkMoment_Handler, + }, + { + MethodName: "GetUserWorkMoments", + Handler: _OfficeService_GetUserWorkMoments_Handler, + }, + { + MethodName: "GetUserFriendWorkMoments", + Handler: _OfficeService_GetUserFriendWorkMoments_Handler, + }, + { + MethodName: "GetUserWorkMomentsCommentsMsg", + Handler: _OfficeService_GetUserWorkMomentsCommentsMsg_Handler, + }, + { + MethodName: "ClearUserWorkMomentsCommentsMsg", + Handler: _OfficeService_ClearUserWorkMomentsCommentsMsg_Handler, + }, + { + MethodName: "SetUserWorkMomentsLevel", + Handler: _OfficeService_SetUserWorkMomentsLevel_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "office/office.proto", +} + +func init() { proto.RegisterFile("office/office.proto", fileDescriptor_office_8a5f7d4f1783db20) } + +var fileDescriptor_office_8a5f7d4f1783db20 = []byte{ + // 1494 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xcd, 0x6e, 0xdb, 0xc6, + 0x13, 0x07, 0x25, 0x4b, 0xb2, 0x46, 0x4e, 0x1c, 0xaf, 0x1d, 0x5b, 0x7f, 0x26, 0xb6, 0x15, 0x26, + 0x7f, 0xc0, 0x49, 0x00, 0xa9, 0x50, 0x03, 0xb4, 0x40, 0xd1, 0xa0, 0x88, 0x94, 0x1a, 0x6e, 0xad, + 0xc4, 0xa5, 0x9c, 0x06, 0xe9, 0x21, 0x06, 0x2d, 0xad, 0x59, 0xc2, 0x12, 0xc9, 0x70, 0x69, 0x09, + 0xe9, 0xb1, 0x87, 0xbe, 0x40, 0x0f, 0x3d, 0xf5, 0xd2, 0x57, 0x28, 0xfa, 0x08, 0x3d, 0xf4, 0x54, + 0xf4, 0xd4, 0x53, 0x6f, 0x7d, 0x8f, 0x16, 0xbb, 0xfc, 0xda, 0xe5, 0x87, 0xa4, 0xd0, 0x0d, 0xd0, + 0x9e, 0xc4, 0x99, 0x9d, 0x9d, 0x9d, 0xf9, 0xcd, 0xee, 0xcc, 0xee, 0x08, 0xd6, 0xad, 0xb3, 0x33, + 0x63, 0x80, 0x5b, 0xde, 0x4f, 0xd3, 0x76, 0x2c, 0xd7, 0x42, 0x65, 0x8f, 0x92, 0x6f, 0x3d, 0xb5, + 0xb1, 0x79, 0x72, 0xd0, 0x6b, 0xd9, 0xe7, 0x7a, 0x8b, 0x0d, 0xb5, 0xc8, 0xf0, 0xfc, 0x64, 0x4a, + 0x5a, 0x53, 0xe2, 0x89, 0x2a, 0x0f, 0x01, 0x3a, 0xd6, 0x78, 0x6c, 0x99, 0x2a, 0x26, 0x36, 0xaa, + 0x43, 0x05, 0x3b, 0x4e, 0xc7, 0x1a, 0xe2, 0xba, 0xd4, 0x90, 0xf6, 0x4a, 0x6a, 0x40, 0xa2, 0x4d, + 0x28, 0x63, 0xc7, 0xe9, 0x11, 0xbd, 0x5e, 0x68, 0x48, 0x7b, 0x55, 0xd5, 0xa7, 0x94, 0x0f, 0xa1, + 0x72, 0xac, 0xe9, 0xcf, 0x08, 0x76, 0xa8, 0xc8, 0x05, 0xc1, 0xce, 0x41, 0x97, 0xcd, 0xad, 0xaa, + 0x3e, 0x85, 0x64, 0x58, 0xa6, 0x5f, 0x4f, 0xb4, 0x31, 0xf6, 0x27, 0x87, 0xb4, 0x72, 0x0a, 0xc5, + 0x63, 0x4d, 0x47, 0x1b, 0x50, 0x72, 0x35, 0x3d, 0x9c, 0xe9, 0x11, 0xd4, 0x1a, 0x57, 0xd3, 0xb9, + 0x79, 0x01, 0x89, 0xee, 0x7b, 0x2a, 0x0f, 0x0d, 0xe2, 0xd6, 0x8b, 0x8d, 0xe2, 0x5e, 0xad, 0xbd, + 0xda, 0xf4, 0x11, 0xf0, 0xad, 0x51, 0x43, 0x01, 0xe5, 0x13, 0xb8, 0xba, 0x8f, 0x5d, 0xca, 0x3c, + 0xd6, 0x74, 0xa2, 0xe2, 0x57, 0x99, 0x96, 0x36, 0xa0, 0x66, 0xd9, 0xd8, 0xd1, 0x5c, 0xc3, 0x32, + 0x0f, 0xba, 0xfe, 0xa2, 0x3c, 0x4b, 0x39, 0x83, 0x55, 0x41, 0x17, 0xb1, 0x51, 0x1b, 0x60, 0x10, + 0x22, 0xc8, 0x14, 0xd6, 0xda, 0x28, 0xb0, 0x26, 0xc2, 0x56, 0xe5, 0xa4, 0xd0, 0x2e, 0x2c, 0xb9, + 0x9a, 0x4e, 0xea, 0x05, 0x66, 0x7b, 0x8d, 0xb3, 0x5d, 0x65, 0x03, 0xca, 0xd7, 0x12, 0xac, 0x74, + 0x1c, 0xac, 0xb9, 0x98, 0xf2, 0xf0, 0x2b, 0x1e, 0x0b, 0x49, 0xc4, 0x22, 0x72, 0xa6, 0x20, 0x38, + 0xb3, 0x03, 0xe0, 0x7d, 0x85, 0x28, 0x55, 0x55, 0x8e, 0x13, 0x77, 0x76, 0x29, 0xe9, 0x6c, 0x07, + 0xae, 0x70, 0x36, 0xe4, 0x73, 0x55, 0x79, 0x09, 0x2b, 0x5d, 0x3c, 0xc2, 0xa1, 0x23, 0x59, 0xd8, + 0x87, 0x5b, 0xa0, 0xc0, 0x6f, 0x81, 0x98, 0x91, 0xc5, 0x54, 0x23, 0x39, 0xfd, 0x39, 0x8d, 0xfc, + 0x4d, 0x82, 0x6a, 0x1f, 0xbb, 0xb9, 0x4c, 0xac, 0x43, 0xc5, 0xc4, 0x53, 0x16, 0x19, 0xcf, 0xbc, + 0x80, 0x44, 0x4d, 0x40, 0x86, 0x39, 0x70, 0xb0, 0x46, 0xf0, 0xb3, 0x28, 0x12, 0x4b, 0x2c, 0x12, + 0x29, 0x23, 0xe8, 0x1e, 0x5c, 0x73, 0xf0, 0xf0, 0x62, 0xc0, 0x4b, 0x97, 0x98, 0x74, 0x82, 0x1f, + 0x07, 0xa6, 0x9c, 0x04, 0xe6, 0x23, 0x80, 0xc0, 0xa5, 0x9c, 0xa8, 0xfc, 0x29, 0xc1, 0xd5, 0x3e, + 0x36, 0x87, 0x3d, 0xa2, 0xb7, 0x85, 0x6d, 0xc8, 0x2c, 0x93, 0x98, 0x65, 0x01, 0x49, 0x4f, 0xf9, + 0xb3, 0xe0, 0x48, 0x16, 0xd8, 0x50, 0x48, 0xa3, 0x9b, 0x50, 0xdd, 0x77, 0xac, 0x0b, 0x9b, 0xdb, + 0x89, 0x11, 0x83, 0xc2, 0x4d, 0xb0, 0x39, 0x0c, 0xf7, 0xa0, 0x4f, 0x51, 0x38, 0xe8, 0x17, 0x76, + 0x8e, 0x46, 0x9a, 0x7b, 0x66, 0x39, 0xe3, 0x83, 0x6e, 0xbd, 0xc4, 0xb2, 0x52, 0x82, 0x4f, 0xed, + 0x1a, 0x58, 0xa6, 0x8b, 0x4d, 0xd7, 0x87, 0x22, 0x20, 0xe3, 0x40, 0x55, 0x92, 0x40, 0x3d, 0x86, + 0x55, 0xc1, 0xcb, 0x9c, 0x68, 0x7d, 0x2b, 0xc1, 0xda, 0x3e, 0x03, 0x9c, 0x6a, 0x3b, 0xb4, 0xbc, + 0x54, 0xd3, 0x05, 0x38, 0xd2, 0x74, 0xc3, 0x64, 0x8b, 0xf9, 0x9a, 0xee, 0x34, 0x09, 0x76, 0x26, + 0xd8, 0x39, 0xd1, 0x6c, 0xe3, 0xc4, 0xd6, 0x1c, 0x6d, 0x4c, 0x9a, 0x2a, 0x7e, 0x75, 0x81, 0x89, + 0x1b, 0xc9, 0xaa, 0xdc, 0xbc, 0xcc, 0x33, 0x3e, 0xff, 0x78, 0x58, 0x00, 0x91, 0x45, 0x42, 0xde, + 0x94, 0xe6, 0xe4, 0x4d, 0x1e, 0xd3, 0x82, 0x88, 0xa9, 0x0c, 0xcb, 0x34, 0x02, 0xc7, 0x86, 0xbf, + 0xe7, 0x8b, 0x6a, 0x48, 0x2b, 0x3f, 0x4b, 0x80, 0xe2, 0x30, 0xe4, 0xcc, 0x92, 0x8f, 0x05, 0xec, + 0x0a, 0x6c, 0xce, 0xff, 0x53, 0xb1, 0x23, 0xb6, 0x65, 0x12, 0x9c, 0x01, 0xde, 0x03, 0xa8, 0xb9, + 0x91, 0x35, 0x7e, 0xbd, 0x40, 0x9c, 0xdf, 0xfe, 0x90, 0xca, 0x8b, 0x29, 0x03, 0x16, 0x4d, 0x3f, + 0xd3, 0x3f, 0x7a, 0x7d, 0xd0, 0x7d, 0x1b, 0xc9, 0x4b, 0x67, 0x58, 0x09, 0x8b, 0xe4, 0xc4, 0x6a, + 0x1b, 0x8a, 0xae, 0xa6, 0xfb, 0x20, 0x09, 0x05, 0x85, 0xf2, 0x95, 0x87, 0xb0, 0x7c, 0x68, 0x9c, + 0xe3, 0xdc, 0x75, 0xfa, 0x0f, 0x09, 0x2a, 0x74, 0x65, 0x1a, 0xfd, 0x1c, 0xf3, 0x29, 0x14, 0x0e, + 0xb6, 0x47, 0xaf, 0xbd, 0x0c, 0x16, 0x40, 0xc1, 0xb1, 0xd0, 0x1d, 0xb8, 0x12, 0x92, 0x4c, 0x85, + 0x97, 0x0c, 0x44, 0x26, 0xcd, 0x24, 0xfe, 0x26, 0xf4, 0x93, 0x41, 0x55, 0x8d, 0x18, 0x33, 0xb2, + 0xc0, 0x0e, 0xc0, 0xc0, 0x2b, 0x65, 0x74, 0xcf, 0x56, 0x58, 0x16, 0xe1, 0x38, 0xca, 0x5f, 0x05, + 0x80, 0xe7, 0x96, 0x73, 0xde, 0xb3, 0x98, 0x8b, 0x0a, 0xac, 0x4c, 0x43, 0x2a, 0x74, 0x54, 0xe0, + 0x65, 0x9e, 0x49, 0xce, 0x88, 0xa2, 0x68, 0x44, 0x13, 0xaa, 0x23, 0x3f, 0x08, 0x84, 0x95, 0x81, + 0x5a, 0xfb, 0x5a, 0x10, 0xa9, 0x20, 0x3a, 0x6a, 0x24, 0x42, 0x4f, 0xeb, 0xc0, 0xc3, 0x9c, 0xb0, + 0x3a, 0xc0, 0x9d, 0x56, 0x3f, 0x16, 0x6a, 0x28, 0x80, 0xde, 0x81, 0xf5, 0xe9, 0x97, 0x56, 0x47, + 0x33, 0xfb, 0x98, 0xaf, 0x1f, 0x65, 0x96, 0x6d, 0xd3, 0x86, 0x50, 0x1b, 0x36, 0x3c, 0xb6, 0x2b, + 0x4e, 0xa9, 0xb0, 0x29, 0xa9, 0x63, 0x14, 0x7f, 0x83, 0x1c, 0x39, 0xc6, 0x44, 0x73, 0x71, 0x7d, + 0xb9, 0x21, 0xed, 0x2d, 0xab, 0x11, 0x83, 0xee, 0x00, 0x83, 0x1c, 0x5d, 0x9c, 0x8e, 0x8c, 0x41, + 0xbd, 0xca, 0x06, 0x43, 0x9a, 0x46, 0xa0, 0x13, 0x45, 0x00, 0xbc, 0x08, 0x44, 0x1c, 0xe5, 0x1b, + 0x09, 0x36, 0x3d, 0xf2, 0xa9, 0x89, 0xa3, 0x50, 0xd0, 0x53, 0xd7, 0x06, 0x88, 0x90, 0x8f, 0x9f, + 0x07, 0x4e, 0x94, 0x93, 0xba, 0x44, 0xc6, 0xec, 0xc1, 0x56, 0xaa, 0x1d, 0x39, 0xcb, 0xc2, 0x04, + 0x36, 0xbd, 0xfb, 0x49, 0xc2, 0xad, 0xcb, 0x6c, 0xb2, 0x85, 0xdc, 0x48, 0x5d, 0x37, 0xa7, 0x1b, + 0x2e, 0x6c, 0xd0, 0x2d, 0x9a, 0x70, 0x22, 0x2b, 0x19, 0x28, 0xb0, 0xf2, 0x9c, 0x77, 0xce, 0x33, + 0x5f, 0xe0, 0x2d, 0xe0, 0xc4, 0xa7, 0x70, 0x3d, 0x65, 0xd5, 0x9c, 0x2e, 0xfc, 0x28, 0xc1, 0x96, + 0x7f, 0x6e, 0xde, 0xc4, 0x8d, 0x69, 0x8a, 0x1b, 0xd3, 0x98, 0x1b, 0x73, 0x72, 0x1b, 0x97, 0x12, + 0x96, 0x66, 0xde, 0x4e, 0x4a, 0x49, 0x08, 0x9e, 0x40, 0x3d, 0xdd, 0xe8, 0x9c, 0x28, 0x7c, 0x27, + 0xc1, 0x75, 0xbf, 0xe6, 0x44, 0xda, 0x66, 0xbe, 0x8a, 0xba, 0x29, 0x65, 0xf8, 0xcd, 0xaf, 0x30, + 0xf3, 0x83, 0xfd, 0x8b, 0x04, 0x9b, 0x69, 0x96, 0xe5, 0xac, 0x88, 0x0f, 0xa0, 0x16, 0x85, 0x29, + 0x78, 0x6a, 0xa5, 0xa5, 0x0d, 0x5e, 0x2c, 0x76, 0xe7, 0x28, 0xe6, 0xbc, 0x73, 0x28, 0xdf, 0x4b, + 0x70, 0xc3, 0xf7, 0xe5, 0x63, 0xc7, 0xc0, 0xe6, 0xf0, 0x5f, 0x86, 0xf5, 0xaf, 0x12, 0xdc, 0xcc, + 0xb6, 0xef, 0xbf, 0x88, 0xf8, 0x04, 0x6a, 0xfe, 0x39, 0x21, 0x3d, 0xa2, 0xa3, 0xbb, 0xf4, 0xc8, + 0x8d, 0xb9, 0x82, 0x91, 0x28, 0x9d, 0xc1, 0xf8, 0x42, 0x67, 0x3c, 0xb3, 0xa8, 0x2b, 0x3f, 0x48, + 0xd0, 0x48, 0xee, 0x5a, 0xce, 0x94, 0x4b, 0x35, 0x1c, 0x62, 0x1b, 0xa2, 0x98, 0x6f, 0x43, 0x28, + 0xbf, 0x4b, 0x70, 0x6b, 0x8e, 0x91, 0x39, 0x63, 0xfe, 0x1e, 0xac, 0x0c, 0x22, 0x35, 0x41, 0xd0, + 0xd7, 0x63, 0x60, 0xb3, 0x25, 0x04, 0xc1, 0x7f, 0x2a, 0xec, 0x2f, 0x41, 0xe9, 0x8c, 0xb0, 0xe6, + 0xbc, 0x25, 0xfc, 0x95, 0x17, 0x70, 0x7b, 0xae, 0xfe, 0x9c, 0x99, 0x78, 0x04, 0x72, 0x3f, 0x11, + 0x93, 0x43, 0x3c, 0xc1, 0xa3, 0x39, 0x4f, 0x8d, 0x11, 0x95, 0x61, 0xc6, 0x96, 0x54, 0x8f, 0x58, + 0xe0, 0xc4, 0x7f, 0x06, 0x37, 0x32, 0x57, 0xcb, 0xe7, 0x40, 0xfb, 0x27, 0x80, 0x2b, 0x4f, 0x99, + 0x44, 0x1f, 0x3b, 0x13, 0x63, 0x80, 0xd1, 0x43, 0xa8, 0x71, 0xed, 0x31, 0xb4, 0x19, 0x28, 0x10, + 0xfb, 0x6f, 0xf2, 0x56, 0x2a, 0x9f, 0xd8, 0xe8, 0x7d, 0xa8, 0x86, 0x1d, 0x27, 0xb4, 0x11, 0x2e, + 0xcf, 0x35, 0xc2, 0xe4, 0xeb, 0x29, 0x5c, 0x6f, 0x66, 0xd8, 0x06, 0x8a, 0x66, 0xf2, 0x9d, 0xa7, + 0x68, 0xa6, 0xd8, 0x2f, 0x6a, 0x41, 0xd9, 0xeb, 0x93, 0xa0, 0xb5, 0x40, 0x20, 0x6c, 0x05, 0xc9, + 0x28, 0xce, 0x22, 0x36, 0x75, 0x92, 0xeb, 0x17, 0x44, 0x4e, 0x8a, 0xad, 0x92, 0xc8, 0xc9, 0x78, + 0x73, 0x61, 0x9f, 0xf5, 0x23, 0xb9, 0x07, 0x32, 0xfa, 0x1f, 0x87, 0x87, 0xd8, 0x3f, 0x90, 0xe5, + 0xac, 0xa1, 0x50, 0x11, 0xf7, 0x7a, 0x14, 0x14, 0x89, 0x4f, 0x57, 0x41, 0x51, 0xfc, 0xc1, 0xf9, + 0x39, 0xac, 0xa7, 0x5c, 0x79, 0xd1, 0x8e, 0x08, 0x75, 0xfc, 0xd2, 0x24, 0xef, 0xce, 0x1c, 0xf7, + 0xf4, 0xa6, 0xdc, 0x41, 0x23, 0xbd, 0xe9, 0x17, 0xe3, 0x48, 0x6f, 0xd6, 0x05, 0xf6, 0x08, 0xd6, + 0x12, 0xd7, 0x42, 0x74, 0x93, 0x7f, 0x4a, 0x25, 0x74, 0x6e, 0xcf, 0x18, 0x25, 0x36, 0x7a, 0x01, + 0x1b, 0x69, 0xb7, 0x2c, 0xb4, 0x1b, 0x4b, 0x64, 0x09, 0xbd, 0x8d, 0xd9, 0x02, 0xc4, 0x46, 0xfd, + 0xf0, 0x8d, 0xcf, 0x1d, 0x3c, 0xb4, 0x1d, 0x0b, 0x87, 0x78, 0x3f, 0x90, 0x77, 0x66, 0x0d, 0x13, + 0x1b, 0x61, 0xa8, 0x67, 0x95, 0x6f, 0x74, 0x3b, 0x36, 0x37, 0xed, 0x02, 0x22, 0xdf, 0x99, 0x2f, + 0x44, 0x6c, 0xe4, 0xc2, 0xf6, 0xcc, 0xb2, 0x81, 0xf6, 0xb2, 0xed, 0x14, 0x53, 0xb0, 0x7c, 0x77, + 0x41, 0x49, 0x62, 0xa3, 0xaf, 0x60, 0x77, 0x4e, 0xce, 0x45, 0xf7, 0x42, 0xd8, 0xe7, 0x26, 0x7f, + 0xf9, 0xfe, 0xc2, 0xb2, 0xc4, 0x46, 0xa7, 0xb0, 0x95, 0x91, 0x26, 0x91, 0xc2, 0xe5, 0x82, 0x8c, + 0xac, 0x2d, 0xdf, 0x9e, 0x2b, 0x43, 0xec, 0x47, 0x6b, 0x5f, 0xac, 0x36, 0xfd, 0x3f, 0x6c, 0x3e, + 0xf0, 0x7e, 0x4e, 0xcb, 0xec, 0xdf, 0x98, 0x77, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xb2, 0xc1, + 0x31, 0xd6, 0xcf, 0x19, 0x00, 0x00, +} diff --git a/pkg/proto/office/office.proto b/pkg/proto/office/office.proto new file mode 100644 index 000000000..6642f674f --- /dev/null +++ b/pkg/proto/office/office.proto @@ -0,0 +1,263 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./office;office"; +package office; + +message CommonResp{ + int32 errCode = 1; + string errMsg = 2; +} + +message TagUser { + string userID = 1; + string userName = 2; +} + +message Tag { + string tagID = 1; + string tagName = 2; + repeated TagUser userList = 3; +} + +message GetUserTagsReq{ + string userID = 1; + string operationID = 2; +} + +message GetUserTagsResp{ + CommonResp commonResp = 1; + repeated Tag tags = 2; +} + +message CreateTagReq { + string tagName = 1; + string userID = 2; + repeated string userIDList = 3; + string operationID = 4; +} + +message CreateTagResp { + CommonResp commonResp = 1; +} + +message DeleteTagReq { + string userID = 1; + string tagID = 2; + string operationID = 3; +} + +message DeleteTagResp { + CommonResp commonResp = 1; +} + +message SetTagReq { + string userID = 1; + string tagID = 2; + string newName = 3; + repeated string increaseUserIDList = 4; + repeated string reduceUserIDList = 5; + string operationID = 6; +} + +message SetTagResp { + CommonResp commonResp = 1; +} + +message SendMsg2TagReq { + repeated string tagList = 1; + repeated string UserList = 2; + repeated string GroupList = 3; + string sendID = 4; + int32 senderPlatformID = 5; + string content = 6; + string operationID = 7; +} + +message SendMsg2TagResp { + CommonResp commonResp = 1; +} + +message GetTagSendLogsReq { + server_api_params.RequestPagination Pagination = 1; + string userID = 2; + string operationID = 3; +} + +message TagSendLog { + repeated TagUser userList = 1; + string content = 2; + int64 sendTime = 3; +} + +message GetTagSendLogsResp { + CommonResp commonResp = 1; + server_api_params.ResponsePagination Pagination = 2; + repeated TagSendLog tagSendLogs = 3; +} + +message GetUserTagByIDReq { + string userID = 1; + string tagID = 2; + string operationID = 3; +} + +message GetUserTagByIDResp { + CommonResp commonResp = 1; + Tag tag = 2; +} + +/// WorkMoment + +message LikeUser { + string userID = 1; + string userName = 2; +} + +message Comment { + string userID = 1; + string userName = 2; + string replyUserID = 3; + string replyUserName = 4; + string contentID = 5; + string content = 6; + int32 createTime = 7; +} + +message WorkMoment { + string workMomentID = 1; + string userID = 2; + string content = 3; + repeated LikeUser likeUsers = 4; + repeated Comment comments = 5; + repeated string whoCanSeeUserIDList = 6; + repeated string whoCantSeeUserIDList = 7; + bool isPrivate = 8; + bool isPublic = 9; + int32 CreateTime = 10; +} + +message CreateOneWorkMomentReq { + WorkMoment workMoment = 1; + string userID = 2; + string operationID = 3; +} + +message CreateOneWorkMomentResp { + CommonResp commonResp = 1; +} + +message DeleteOneWorkMomentReq { + string workMomentID = 1; + string userID = 2; + string operationID = 3; +} + +message DeleteOneWorkMomentResp { + CommonResp commonResp = 1; +} + +message LikeOneWorkMomentReq { + string userID = 1; + string WorkMomentID = 2; + string operationID = 3; +} + +message LikeOneWorkMomentResp { + CommonResp commonResp = 1; +} + +message CommentOneWorkMomentReq { + string userID = 1; + string workMomentID = 2; + string replyUserID = 3; + string content = 4; + string operationID = 5; +} + +message CommentOneWorkMomentResp { + CommonResp commonResp = 1; +} + +message GetUserWorkMomentsReq { + string userID = 1; + server_api_params.RequestPagination Pagination = 2; + string operationID = 3; +} + +message GetUserWorkMomentsResp { + CommonResp commonResp = 1; + repeated WorkMoment workMoments = 2; + server_api_params.ResponsePagination Pagination = 3; +} + +message GetUserFriendWorkMomentsReq { + string userID = 1; + server_api_params.RequestPagination Pagination = 2; + string operationID = 3; +} + +message GetUserFriendWorkMomentsResp { + CommonResp commonResp = 1; + repeated WorkMoment workMoments = 2; + server_api_params.ResponsePagination Pagination = 3; +} + +message CommentsMsg { + Comment comment = 1; + string workMomentID = 2; + string content = 3; +} + +message GetUserWorkMomentsCommentsMsgReq { + string userID = 1; + string operationID = 2; + server_api_params.RequestPagination Pagination = 3; +} + +message GetUserWorkMomentsCommentsMsgResp { + CommonResp commonResp = 1; + repeated CommentsMsg commentsMsgs = 2; + server_api_params.ResponsePagination Pagination = 3; +} + +message ClearUserWorkMomentsCommentsMsgReq { + string userID = 1; + string operationID = 2; +} + +message ClearUserWorkMomentsCommentsMsgResp { + CommonResp commonResp = 1; +} + +message SetUserWorkMomentsLevelReq { + string userID = 1; + int32 level = 2; + string operationID = 3; +} + +message SetUserWorkMomentsLevelResp { + CommonResp commonResp = 1; +} + +service OfficeService { + rpc GetUserTags(GetUserTagsReq) returns(GetUserTagsResp); + rpc CreateTag(CreateTagReq) returns(CreateTagResp); + rpc DeleteTag(DeleteTagReq) returns(DeleteTagResp); + rpc SetTag(SetTagReq) returns(SetTagResp); + rpc SendMsg2Tag(SendMsg2TagReq) returns(SendMsg2TagResp); + rpc GetTagSendLogs(GetTagSendLogsReq) returns(GetTagSendLogsResp); + rpc GetUserTagByID(GetUserTagByIDReq) returns(GetUserTagByIDResp); + + rpc CreateOneWorkMoment(CreateOneWorkMomentReq) returns(CreateOneWorkMomentResp); + rpc DeleteOneWorkMoment(DeleteOneWorkMomentReq) returns(DeleteOneWorkMomentResp); + rpc LikeOneWorkMoment(LikeOneWorkMomentReq) returns(LikeOneWorkMomentResp); + rpc CommentOneWorkMoment(CommentOneWorkMomentReq) returns(CommentOneWorkMomentResp); + /// user self + rpc GetUserWorkMoments(GetUserWorkMomentsReq) returns(GetUserWorkMomentsResp); + /// users friend + rpc GetUserFriendWorkMoments(GetUserFriendWorkMomentsReq) returns(GetUserFriendWorkMomentsResp); + rpc GetUserWorkMomentsCommentsMsg(GetUserWorkMomentsCommentsMsgReq) returns(GetUserWorkMomentsCommentsMsgResp); + rpc ClearUserWorkMomentsCommentsMsg(ClearUserWorkMomentsCommentsMsgReq) returns(ClearUserWorkMomentsCommentsMsgResp); + rpc SetUserWorkMomentsLevel(SetUserWorkMomentsLevelReq) returns(SetUserWorkMomentsLevelResp); +} + diff --git a/pkg/proto/organization/organization.pb.go b/pkg/proto/organization/organization.pb.go new file mode 100644 index 000000000..844dfd947 --- /dev/null +++ b/pkg/proto/organization/organization.pb.go @@ -0,0 +1,1780 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: organization/organization.proto + +package organization // import "./organization" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CreateDepartmentReq struct { + DepartmentInfo *sdk_ws.Department `protobuf:"bytes,1,opt,name=departmentInfo" json:"departmentInfo,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateDepartmentReq) Reset() { *m = CreateDepartmentReq{} } +func (m *CreateDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*CreateDepartmentReq) ProtoMessage() {} +func (*CreateDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{0} +} +func (m *CreateDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateDepartmentReq.Unmarshal(m, b) +} +func (m *CreateDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *CreateDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateDepartmentReq.Merge(dst, src) +} +func (m *CreateDepartmentReq) XXX_Size() int { + return xxx_messageInfo_CreateDepartmentReq.Size(m) +} +func (m *CreateDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_CreateDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateDepartmentReq proto.InternalMessageInfo + +func (m *CreateDepartmentReq) GetDepartmentInfo() *sdk_ws.Department { + if m != nil { + return m.DepartmentInfo + } + return nil +} + +func (m *CreateDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CreateDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type CreateDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + DepartmentInfo *sdk_ws.Department `protobuf:"bytes,3,opt,name=departmentInfo" json:"departmentInfo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateDepartmentResp) Reset() { *m = CreateDepartmentResp{} } +func (m *CreateDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*CreateDepartmentResp) ProtoMessage() {} +func (*CreateDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{1} +} +func (m *CreateDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateDepartmentResp.Unmarshal(m, b) +} +func (m *CreateDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *CreateDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateDepartmentResp.Merge(dst, src) +} +func (m *CreateDepartmentResp) XXX_Size() int { + return xxx_messageInfo_CreateDepartmentResp.Size(m) +} +func (m *CreateDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_CreateDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateDepartmentResp proto.InternalMessageInfo + +func (m *CreateDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CreateDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *CreateDepartmentResp) GetDepartmentInfo() *sdk_ws.Department { + if m != nil { + return m.DepartmentInfo + } + return nil +} + +type UpdateDepartmentReq struct { + DepartmentInfo *sdk_ws.Department `protobuf:"bytes,1,opt,name=departmentInfo" json:"departmentInfo,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateDepartmentReq) Reset() { *m = UpdateDepartmentReq{} } +func (m *UpdateDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*UpdateDepartmentReq) ProtoMessage() {} +func (*UpdateDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{2} +} +func (m *UpdateDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateDepartmentReq.Unmarshal(m, b) +} +func (m *UpdateDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *UpdateDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateDepartmentReq.Merge(dst, src) +} +func (m *UpdateDepartmentReq) XXX_Size() int { + return xxx_messageInfo_UpdateDepartmentReq.Size(m) +} +func (m *UpdateDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateDepartmentReq proto.InternalMessageInfo + +func (m *UpdateDepartmentReq) GetDepartmentInfo() *sdk_ws.Department { + if m != nil { + return m.DepartmentInfo + } + return nil +} + +func (m *UpdateDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *UpdateDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type UpdateDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateDepartmentResp) Reset() { *m = UpdateDepartmentResp{} } +func (m *UpdateDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*UpdateDepartmentResp) ProtoMessage() {} +func (*UpdateDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{3} +} +func (m *UpdateDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateDepartmentResp.Unmarshal(m, b) +} +func (m *UpdateDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *UpdateDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateDepartmentResp.Merge(dst, src) +} +func (m *UpdateDepartmentResp) XXX_Size() int { + return xxx_messageInfo_UpdateDepartmentResp.Size(m) +} +func (m *UpdateDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateDepartmentResp proto.InternalMessageInfo + +func (m *UpdateDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *UpdateDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type GetSubDepartmentReq struct { + DepartmentID string `protobuf:"bytes,1,opt,name=departmentID" json:"departmentID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetSubDepartmentReq) Reset() { *m = GetSubDepartmentReq{} } +func (m *GetSubDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*GetSubDepartmentReq) ProtoMessage() {} +func (*GetSubDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{4} +} +func (m *GetSubDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetSubDepartmentReq.Unmarshal(m, b) +} +func (m *GetSubDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetSubDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *GetSubDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSubDepartmentReq.Merge(dst, src) +} +func (m *GetSubDepartmentReq) XXX_Size() int { + return xxx_messageInfo_GetSubDepartmentReq.Size(m) +} +func (m *GetSubDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetSubDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetSubDepartmentReq proto.InternalMessageInfo + +func (m *GetSubDepartmentReq) GetDepartmentID() string { + if m != nil { + return m.DepartmentID + } + return "" +} + +func (m *GetSubDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetSubDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type GetSubDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + DepartmentList []*sdk_ws.Department `protobuf:"bytes,3,rep,name=departmentList" json:"departmentList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetSubDepartmentResp) Reset() { *m = GetSubDepartmentResp{} } +func (m *GetSubDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*GetSubDepartmentResp) ProtoMessage() {} +func (*GetSubDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{5} +} +func (m *GetSubDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetSubDepartmentResp.Unmarshal(m, b) +} +func (m *GetSubDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetSubDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *GetSubDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSubDepartmentResp.Merge(dst, src) +} +func (m *GetSubDepartmentResp) XXX_Size() int { + return xxx_messageInfo_GetSubDepartmentResp.Size(m) +} +func (m *GetSubDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetSubDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetSubDepartmentResp proto.InternalMessageInfo + +func (m *GetSubDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetSubDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetSubDepartmentResp) GetDepartmentList() []*sdk_ws.Department { + if m != nil { + return m.DepartmentList + } + return nil +} + +type DeleteDepartmentReq struct { + DepartmentID string `protobuf:"bytes,1,opt,name=departmentID" json:"departmentID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteDepartmentReq) Reset() { *m = DeleteDepartmentReq{} } +func (m *DeleteDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*DeleteDepartmentReq) ProtoMessage() {} +func (*DeleteDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{6} +} +func (m *DeleteDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteDepartmentReq.Unmarshal(m, b) +} +func (m *DeleteDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *DeleteDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteDepartmentReq.Merge(dst, src) +} +func (m *DeleteDepartmentReq) XXX_Size() int { + return xxx_messageInfo_DeleteDepartmentReq.Size(m) +} +func (m *DeleteDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteDepartmentReq proto.InternalMessageInfo + +func (m *DeleteDepartmentReq) GetDepartmentID() string { + if m != nil { + return m.DepartmentID + } + return "" +} + +func (m *DeleteDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *DeleteDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type DeleteDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteDepartmentResp) Reset() { *m = DeleteDepartmentResp{} } +func (m *DeleteDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*DeleteDepartmentResp) ProtoMessage() {} +func (*DeleteDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{7} +} +func (m *DeleteDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteDepartmentResp.Unmarshal(m, b) +} +func (m *DeleteDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *DeleteDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteDepartmentResp.Merge(dst, src) +} +func (m *DeleteDepartmentResp) XXX_Size() int { + return xxx_messageInfo_DeleteDepartmentResp.Size(m) +} +func (m *DeleteDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteDepartmentResp proto.InternalMessageInfo + +func (m *DeleteDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *DeleteDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type CreateOrganizationUserReq struct { + OrganizationUser *sdk_ws.OrganizationUser `protobuf:"bytes,1,opt,name=organizationUser" json:"organizationUser,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateOrganizationUserReq) Reset() { *m = CreateOrganizationUserReq{} } +func (m *CreateOrganizationUserReq) String() string { return proto.CompactTextString(m) } +func (*CreateOrganizationUserReq) ProtoMessage() {} +func (*CreateOrganizationUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{8} +} +func (m *CreateOrganizationUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateOrganizationUserReq.Unmarshal(m, b) +} +func (m *CreateOrganizationUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateOrganizationUserReq.Marshal(b, m, deterministic) +} +func (dst *CreateOrganizationUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateOrganizationUserReq.Merge(dst, src) +} +func (m *CreateOrganizationUserReq) XXX_Size() int { + return xxx_messageInfo_CreateOrganizationUserReq.Size(m) +} +func (m *CreateOrganizationUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_CreateOrganizationUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateOrganizationUserReq proto.InternalMessageInfo + +func (m *CreateOrganizationUserReq) GetOrganizationUser() *sdk_ws.OrganizationUser { + if m != nil { + return m.OrganizationUser + } + return nil +} + +func (m *CreateOrganizationUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CreateOrganizationUserReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type CreateOrganizationUserResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateOrganizationUserResp) Reset() { *m = CreateOrganizationUserResp{} } +func (m *CreateOrganizationUserResp) String() string { return proto.CompactTextString(m) } +func (*CreateOrganizationUserResp) ProtoMessage() {} +func (*CreateOrganizationUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{9} +} +func (m *CreateOrganizationUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateOrganizationUserResp.Unmarshal(m, b) +} +func (m *CreateOrganizationUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateOrganizationUserResp.Marshal(b, m, deterministic) +} +func (dst *CreateOrganizationUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateOrganizationUserResp.Merge(dst, src) +} +func (m *CreateOrganizationUserResp) XXX_Size() int { + return xxx_messageInfo_CreateOrganizationUserResp.Size(m) +} +func (m *CreateOrganizationUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_CreateOrganizationUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateOrganizationUserResp proto.InternalMessageInfo + +func (m *CreateOrganizationUserResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CreateOrganizationUserResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type UpdateOrganizationUserReq struct { + OrganizationUser *sdk_ws.OrganizationUser `protobuf:"bytes,1,opt,name=organizationUser" json:"organizationUser,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateOrganizationUserReq) Reset() { *m = UpdateOrganizationUserReq{} } +func (m *UpdateOrganizationUserReq) String() string { return proto.CompactTextString(m) } +func (*UpdateOrganizationUserReq) ProtoMessage() {} +func (*UpdateOrganizationUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{10} +} +func (m *UpdateOrganizationUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateOrganizationUserReq.Unmarshal(m, b) +} +func (m *UpdateOrganizationUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateOrganizationUserReq.Marshal(b, m, deterministic) +} +func (dst *UpdateOrganizationUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateOrganizationUserReq.Merge(dst, src) +} +func (m *UpdateOrganizationUserReq) XXX_Size() int { + return xxx_messageInfo_UpdateOrganizationUserReq.Size(m) +} +func (m *UpdateOrganizationUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateOrganizationUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateOrganizationUserReq proto.InternalMessageInfo + +func (m *UpdateOrganizationUserReq) GetOrganizationUser() *sdk_ws.OrganizationUser { + if m != nil { + return m.OrganizationUser + } + return nil +} + +func (m *UpdateOrganizationUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *UpdateOrganizationUserReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type UpdateOrganizationUserResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateOrganizationUserResp) Reset() { *m = UpdateOrganizationUserResp{} } +func (m *UpdateOrganizationUserResp) String() string { return proto.CompactTextString(m) } +func (*UpdateOrganizationUserResp) ProtoMessage() {} +func (*UpdateOrganizationUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{11} +} +func (m *UpdateOrganizationUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateOrganizationUserResp.Unmarshal(m, b) +} +func (m *UpdateOrganizationUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateOrganizationUserResp.Marshal(b, m, deterministic) +} +func (dst *UpdateOrganizationUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateOrganizationUserResp.Merge(dst, src) +} +func (m *UpdateOrganizationUserResp) XXX_Size() int { + return xxx_messageInfo_UpdateOrganizationUserResp.Size(m) +} +func (m *UpdateOrganizationUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateOrganizationUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateOrganizationUserResp proto.InternalMessageInfo + +func (m *UpdateOrganizationUserResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *UpdateOrganizationUserResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type CreateDepartmentMemberReq struct { + UserInDepartment *sdk_ws.UserInDepartment `protobuf:"bytes,1,opt,name=userInDepartment" json:"userInDepartment,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateDepartmentMemberReq) Reset() { *m = CreateDepartmentMemberReq{} } +func (m *CreateDepartmentMemberReq) String() string { return proto.CompactTextString(m) } +func (*CreateDepartmentMemberReq) ProtoMessage() {} +func (*CreateDepartmentMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{12} +} +func (m *CreateDepartmentMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateDepartmentMemberReq.Unmarshal(m, b) +} +func (m *CreateDepartmentMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateDepartmentMemberReq.Marshal(b, m, deterministic) +} +func (dst *CreateDepartmentMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateDepartmentMemberReq.Merge(dst, src) +} +func (m *CreateDepartmentMemberReq) XXX_Size() int { + return xxx_messageInfo_CreateDepartmentMemberReq.Size(m) +} +func (m *CreateDepartmentMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_CreateDepartmentMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateDepartmentMemberReq proto.InternalMessageInfo + +func (m *CreateDepartmentMemberReq) GetUserInDepartment() *sdk_ws.UserInDepartment { + if m != nil { + return m.UserInDepartment + } + return nil +} + +func (m *CreateDepartmentMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *CreateDepartmentMemberReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type CreateDepartmentMemberResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateDepartmentMemberResp) Reset() { *m = CreateDepartmentMemberResp{} } +func (m *CreateDepartmentMemberResp) String() string { return proto.CompactTextString(m) } +func (*CreateDepartmentMemberResp) ProtoMessage() {} +func (*CreateDepartmentMemberResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{13} +} +func (m *CreateDepartmentMemberResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateDepartmentMemberResp.Unmarshal(m, b) +} +func (m *CreateDepartmentMemberResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateDepartmentMemberResp.Marshal(b, m, deterministic) +} +func (dst *CreateDepartmentMemberResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateDepartmentMemberResp.Merge(dst, src) +} +func (m *CreateDepartmentMemberResp) XXX_Size() int { + return xxx_messageInfo_CreateDepartmentMemberResp.Size(m) +} +func (m *CreateDepartmentMemberResp) XXX_DiscardUnknown() { + xxx_messageInfo_CreateDepartmentMemberResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateDepartmentMemberResp proto.InternalMessageInfo + +func (m *CreateDepartmentMemberResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CreateDepartmentMemberResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type GetUserInDepartmentReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserInDepartmentReq) Reset() { *m = GetUserInDepartmentReq{} } +func (m *GetUserInDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*GetUserInDepartmentReq) ProtoMessage() {} +func (*GetUserInDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{14} +} +func (m *GetUserInDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserInDepartmentReq.Unmarshal(m, b) +} +func (m *GetUserInDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserInDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *GetUserInDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserInDepartmentReq.Merge(dst, src) +} +func (m *GetUserInDepartmentReq) XXX_Size() int { + return xxx_messageInfo_GetUserInDepartmentReq.Size(m) +} +func (m *GetUserInDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserInDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserInDepartmentReq proto.InternalMessageInfo + +func (m *GetUserInDepartmentReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUserInDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetUserInDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type GetUserInDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + UserInDepartment *sdk_ws.UserInDepartment `protobuf:"bytes,3,opt,name=userInDepartment" json:"userInDepartment,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserInDepartmentResp) Reset() { *m = GetUserInDepartmentResp{} } +func (m *GetUserInDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*GetUserInDepartmentResp) ProtoMessage() {} +func (*GetUserInDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{15} +} +func (m *GetUserInDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserInDepartmentResp.Unmarshal(m, b) +} +func (m *GetUserInDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserInDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *GetUserInDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserInDepartmentResp.Merge(dst, src) +} +func (m *GetUserInDepartmentResp) XXX_Size() int { + return xxx_messageInfo_GetUserInDepartmentResp.Size(m) +} +func (m *GetUserInDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserInDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserInDepartmentResp proto.InternalMessageInfo + +func (m *GetUserInDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetUserInDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetUserInDepartmentResp) GetUserInDepartment() *sdk_ws.UserInDepartment { + if m != nil { + return m.UserInDepartment + } + return nil +} + +type UpdateUserInDepartmentReq struct { + DepartmentMember *sdk_ws.DepartmentMember `protobuf:"bytes,1,opt,name=departmentMember" json:"departmentMember,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateUserInDepartmentReq) Reset() { *m = UpdateUserInDepartmentReq{} } +func (m *UpdateUserInDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*UpdateUserInDepartmentReq) ProtoMessage() {} +func (*UpdateUserInDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{16} +} +func (m *UpdateUserInDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateUserInDepartmentReq.Unmarshal(m, b) +} +func (m *UpdateUserInDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateUserInDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *UpdateUserInDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateUserInDepartmentReq.Merge(dst, src) +} +func (m *UpdateUserInDepartmentReq) XXX_Size() int { + return xxx_messageInfo_UpdateUserInDepartmentReq.Size(m) +} +func (m *UpdateUserInDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateUserInDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateUserInDepartmentReq proto.InternalMessageInfo + +func (m *UpdateUserInDepartmentReq) GetDepartmentMember() *sdk_ws.DepartmentMember { + if m != nil { + return m.DepartmentMember + } + return nil +} + +func (m *UpdateUserInDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *UpdateUserInDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type UpdateUserInDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateUserInDepartmentResp) Reset() { *m = UpdateUserInDepartmentResp{} } +func (m *UpdateUserInDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*UpdateUserInDepartmentResp) ProtoMessage() {} +func (*UpdateUserInDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{17} +} +func (m *UpdateUserInDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateUserInDepartmentResp.Unmarshal(m, b) +} +func (m *UpdateUserInDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateUserInDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *UpdateUserInDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateUserInDepartmentResp.Merge(dst, src) +} +func (m *UpdateUserInDepartmentResp) XXX_Size() int { + return xxx_messageInfo_UpdateUserInDepartmentResp.Size(m) +} +func (m *UpdateUserInDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateUserInDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateUserInDepartmentResp proto.InternalMessageInfo + +func (m *UpdateUserInDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *UpdateUserInDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type DeleteUserInDepartmentReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + DepartmentID string `protobuf:"bytes,4,opt,name=departmentID" json:"departmentID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteUserInDepartmentReq) Reset() { *m = DeleteUserInDepartmentReq{} } +func (m *DeleteUserInDepartmentReq) String() string { return proto.CompactTextString(m) } +func (*DeleteUserInDepartmentReq) ProtoMessage() {} +func (*DeleteUserInDepartmentReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{18} +} +func (m *DeleteUserInDepartmentReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteUserInDepartmentReq.Unmarshal(m, b) +} +func (m *DeleteUserInDepartmentReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteUserInDepartmentReq.Marshal(b, m, deterministic) +} +func (dst *DeleteUserInDepartmentReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteUserInDepartmentReq.Merge(dst, src) +} +func (m *DeleteUserInDepartmentReq) XXX_Size() int { + return xxx_messageInfo_DeleteUserInDepartmentReq.Size(m) +} +func (m *DeleteUserInDepartmentReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteUserInDepartmentReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteUserInDepartmentReq proto.InternalMessageInfo + +func (m *DeleteUserInDepartmentReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *DeleteUserInDepartmentReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *DeleteUserInDepartmentReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *DeleteUserInDepartmentReq) GetDepartmentID() string { + if m != nil { + return m.DepartmentID + } + return "" +} + +type DeleteUserInDepartmentResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteUserInDepartmentResp) Reset() { *m = DeleteUserInDepartmentResp{} } +func (m *DeleteUserInDepartmentResp) String() string { return proto.CompactTextString(m) } +func (*DeleteUserInDepartmentResp) ProtoMessage() {} +func (*DeleteUserInDepartmentResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{19} +} +func (m *DeleteUserInDepartmentResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteUserInDepartmentResp.Unmarshal(m, b) +} +func (m *DeleteUserInDepartmentResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteUserInDepartmentResp.Marshal(b, m, deterministic) +} +func (dst *DeleteUserInDepartmentResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteUserInDepartmentResp.Merge(dst, src) +} +func (m *DeleteUserInDepartmentResp) XXX_Size() int { + return xxx_messageInfo_DeleteUserInDepartmentResp.Size(m) +} +func (m *DeleteUserInDepartmentResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteUserInDepartmentResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteUserInDepartmentResp proto.InternalMessageInfo + +func (m *DeleteUserInDepartmentResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *DeleteUserInDepartmentResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type DeleteOrganizationUserReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteOrganizationUserReq) Reset() { *m = DeleteOrganizationUserReq{} } +func (m *DeleteOrganizationUserReq) String() string { return proto.CompactTextString(m) } +func (*DeleteOrganizationUserReq) ProtoMessage() {} +func (*DeleteOrganizationUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{20} +} +func (m *DeleteOrganizationUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteOrganizationUserReq.Unmarshal(m, b) +} +func (m *DeleteOrganizationUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteOrganizationUserReq.Marshal(b, m, deterministic) +} +func (dst *DeleteOrganizationUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteOrganizationUserReq.Merge(dst, src) +} +func (m *DeleteOrganizationUserReq) XXX_Size() int { + return xxx_messageInfo_DeleteOrganizationUserReq.Size(m) +} +func (m *DeleteOrganizationUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteOrganizationUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteOrganizationUserReq proto.InternalMessageInfo + +func (m *DeleteOrganizationUserReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *DeleteOrganizationUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *DeleteOrganizationUserReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type DeleteOrganizationUserResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteOrganizationUserResp) Reset() { *m = DeleteOrganizationUserResp{} } +func (m *DeleteOrganizationUserResp) String() string { return proto.CompactTextString(m) } +func (*DeleteOrganizationUserResp) ProtoMessage() {} +func (*DeleteOrganizationUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{21} +} +func (m *DeleteOrganizationUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteOrganizationUserResp.Unmarshal(m, b) +} +func (m *DeleteOrganizationUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteOrganizationUserResp.Marshal(b, m, deterministic) +} +func (dst *DeleteOrganizationUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteOrganizationUserResp.Merge(dst, src) +} +func (m *DeleteOrganizationUserResp) XXX_Size() int { + return xxx_messageInfo_DeleteOrganizationUserResp.Size(m) +} +func (m *DeleteOrganizationUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteOrganizationUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteOrganizationUserResp proto.InternalMessageInfo + +func (m *DeleteOrganizationUserResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *DeleteOrganizationUserResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type GetDepartmentMemberReq struct { + DepartmentID string `protobuf:"bytes,1,opt,name=departmentID" json:"departmentID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetDepartmentMemberReq) Reset() { *m = GetDepartmentMemberReq{} } +func (m *GetDepartmentMemberReq) String() string { return proto.CompactTextString(m) } +func (*GetDepartmentMemberReq) ProtoMessage() {} +func (*GetDepartmentMemberReq) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{22} +} +func (m *GetDepartmentMemberReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetDepartmentMemberReq.Unmarshal(m, b) +} +func (m *GetDepartmentMemberReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetDepartmentMemberReq.Marshal(b, m, deterministic) +} +func (dst *GetDepartmentMemberReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetDepartmentMemberReq.Merge(dst, src) +} +func (m *GetDepartmentMemberReq) XXX_Size() int { + return xxx_messageInfo_GetDepartmentMemberReq.Size(m) +} +func (m *GetDepartmentMemberReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetDepartmentMemberReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetDepartmentMemberReq proto.InternalMessageInfo + +func (m *GetDepartmentMemberReq) GetDepartmentID() string { + if m != nil { + return m.DepartmentID + } + return "" +} + +func (m *GetDepartmentMemberReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetDepartmentMemberReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type GetDepartmentMemberResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + UserInDepartmentList []*sdk_ws.UserInDepartment `protobuf:"bytes,3,rep,name=userInDepartmentList" json:"userInDepartmentList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetDepartmentMemberResp) Reset() { *m = GetDepartmentMemberResp{} } +func (m *GetDepartmentMemberResp) String() string { return proto.CompactTextString(m) } +func (*GetDepartmentMemberResp) ProtoMessage() {} +func (*GetDepartmentMemberResp) Descriptor() ([]byte, []int) { + return fileDescriptor_organization_a03f9a4144ed1081, []int{23} +} +func (m *GetDepartmentMemberResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetDepartmentMemberResp.Unmarshal(m, b) +} +func (m *GetDepartmentMemberResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetDepartmentMemberResp.Marshal(b, m, deterministic) +} +func (dst *GetDepartmentMemberResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetDepartmentMemberResp.Merge(dst, src) +} +func (m *GetDepartmentMemberResp) XXX_Size() int { + return xxx_messageInfo_GetDepartmentMemberResp.Size(m) +} +func (m *GetDepartmentMemberResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetDepartmentMemberResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetDepartmentMemberResp proto.InternalMessageInfo + +func (m *GetDepartmentMemberResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetDepartmentMemberResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetDepartmentMemberResp) GetUserInDepartmentList() []*sdk_ws.UserInDepartment { + if m != nil { + return m.UserInDepartmentList + } + return nil +} + +func init() { + proto.RegisterType((*CreateDepartmentReq)(nil), "organization.CreateDepartmentReq") + proto.RegisterType((*CreateDepartmentResp)(nil), "organization.CreateDepartmentResp") + proto.RegisterType((*UpdateDepartmentReq)(nil), "organization.UpdateDepartmentReq") + proto.RegisterType((*UpdateDepartmentResp)(nil), "organization.UpdateDepartmentResp") + proto.RegisterType((*GetSubDepartmentReq)(nil), "organization.GetSubDepartmentReq") + proto.RegisterType((*GetSubDepartmentResp)(nil), "organization.GetSubDepartmentResp") + proto.RegisterType((*DeleteDepartmentReq)(nil), "organization.DeleteDepartmentReq") + proto.RegisterType((*DeleteDepartmentResp)(nil), "organization.DeleteDepartmentResp") + proto.RegisterType((*CreateOrganizationUserReq)(nil), "organization.CreateOrganizationUserReq") + proto.RegisterType((*CreateOrganizationUserResp)(nil), "organization.CreateOrganizationUserResp") + proto.RegisterType((*UpdateOrganizationUserReq)(nil), "organization.UpdateOrganizationUserReq") + proto.RegisterType((*UpdateOrganizationUserResp)(nil), "organization.UpdateOrganizationUserResp") + proto.RegisterType((*CreateDepartmentMemberReq)(nil), "organization.CreateDepartmentMemberReq") + proto.RegisterType((*CreateDepartmentMemberResp)(nil), "organization.CreateDepartmentMemberResp") + proto.RegisterType((*GetUserInDepartmentReq)(nil), "organization.GetUserInDepartmentReq") + proto.RegisterType((*GetUserInDepartmentResp)(nil), "organization.GetUserInDepartmentResp") + proto.RegisterType((*UpdateUserInDepartmentReq)(nil), "organization.UpdateUserInDepartmentReq") + proto.RegisterType((*UpdateUserInDepartmentResp)(nil), "organization.UpdateUserInDepartmentResp") + proto.RegisterType((*DeleteUserInDepartmentReq)(nil), "organization.DeleteUserInDepartmentReq") + proto.RegisterType((*DeleteUserInDepartmentResp)(nil), "organization.DeleteUserInDepartmentResp") + proto.RegisterType((*DeleteOrganizationUserReq)(nil), "organization.DeleteOrganizationUserReq") + proto.RegisterType((*DeleteOrganizationUserResp)(nil), "organization.DeleteOrganizationUserResp") + proto.RegisterType((*GetDepartmentMemberReq)(nil), "organization.GetDepartmentMemberReq") + proto.RegisterType((*GetDepartmentMemberResp)(nil), "organization.GetDepartmentMemberResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Organization service + +type OrganizationClient interface { + CreateDepartment(ctx context.Context, in *CreateDepartmentReq, opts ...grpc.CallOption) (*CreateDepartmentResp, error) + UpdateDepartment(ctx context.Context, in *UpdateDepartmentReq, opts ...grpc.CallOption) (*UpdateDepartmentResp, error) + GetSubDepartment(ctx context.Context, in *GetSubDepartmentReq, opts ...grpc.CallOption) (*GetSubDepartmentResp, error) + DeleteDepartment(ctx context.Context, in *DeleteDepartmentReq, opts ...grpc.CallOption) (*DeleteDepartmentResp, error) + CreateOrganizationUser(ctx context.Context, in *CreateOrganizationUserReq, opts ...grpc.CallOption) (*CreateOrganizationUserResp, error) + UpdateOrganizationUser(ctx context.Context, in *UpdateOrganizationUserReq, opts ...grpc.CallOption) (*UpdateOrganizationUserResp, error) + DeleteOrganizationUser(ctx context.Context, in *DeleteOrganizationUserReq, opts ...grpc.CallOption) (*DeleteOrganizationUserResp, error) + CreateDepartmentMember(ctx context.Context, in *CreateDepartmentMemberReq, opts ...grpc.CallOption) (*CreateDepartmentMemberResp, error) + GetUserInDepartment(ctx context.Context, in *GetUserInDepartmentReq, opts ...grpc.CallOption) (*GetUserInDepartmentResp, error) + DeleteUserInDepartment(ctx context.Context, in *DeleteUserInDepartmentReq, opts ...grpc.CallOption) (*DeleteUserInDepartmentResp, error) + UpdateUserInDepartment(ctx context.Context, in *UpdateUserInDepartmentReq, opts ...grpc.CallOption) (*UpdateUserInDepartmentResp, error) + GetDepartmentMember(ctx context.Context, in *GetDepartmentMemberReq, opts ...grpc.CallOption) (*GetDepartmentMemberResp, error) +} + +type organizationClient struct { + cc *grpc.ClientConn +} + +func NewOrganizationClient(cc *grpc.ClientConn) OrganizationClient { + return &organizationClient{cc} +} + +func (c *organizationClient) CreateDepartment(ctx context.Context, in *CreateDepartmentReq, opts ...grpc.CallOption) (*CreateDepartmentResp, error) { + out := new(CreateDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/CreateDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) UpdateDepartment(ctx context.Context, in *UpdateDepartmentReq, opts ...grpc.CallOption) (*UpdateDepartmentResp, error) { + out := new(UpdateDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/UpdateDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) GetSubDepartment(ctx context.Context, in *GetSubDepartmentReq, opts ...grpc.CallOption) (*GetSubDepartmentResp, error) { + out := new(GetSubDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/GetSubDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) DeleteDepartment(ctx context.Context, in *DeleteDepartmentReq, opts ...grpc.CallOption) (*DeleteDepartmentResp, error) { + out := new(DeleteDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/DeleteDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) CreateOrganizationUser(ctx context.Context, in *CreateOrganizationUserReq, opts ...grpc.CallOption) (*CreateOrganizationUserResp, error) { + out := new(CreateOrganizationUserResp) + err := grpc.Invoke(ctx, "/organization.organization/CreateOrganizationUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) UpdateOrganizationUser(ctx context.Context, in *UpdateOrganizationUserReq, opts ...grpc.CallOption) (*UpdateOrganizationUserResp, error) { + out := new(UpdateOrganizationUserResp) + err := grpc.Invoke(ctx, "/organization.organization/UpdateOrganizationUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) DeleteOrganizationUser(ctx context.Context, in *DeleteOrganizationUserReq, opts ...grpc.CallOption) (*DeleteOrganizationUserResp, error) { + out := new(DeleteOrganizationUserResp) + err := grpc.Invoke(ctx, "/organization.organization/DeleteOrganizationUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) CreateDepartmentMember(ctx context.Context, in *CreateDepartmentMemberReq, opts ...grpc.CallOption) (*CreateDepartmentMemberResp, error) { + out := new(CreateDepartmentMemberResp) + err := grpc.Invoke(ctx, "/organization.organization/CreateDepartmentMember", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) GetUserInDepartment(ctx context.Context, in *GetUserInDepartmentReq, opts ...grpc.CallOption) (*GetUserInDepartmentResp, error) { + out := new(GetUserInDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/GetUserInDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) DeleteUserInDepartment(ctx context.Context, in *DeleteUserInDepartmentReq, opts ...grpc.CallOption) (*DeleteUserInDepartmentResp, error) { + out := new(DeleteUserInDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/DeleteUserInDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) UpdateUserInDepartment(ctx context.Context, in *UpdateUserInDepartmentReq, opts ...grpc.CallOption) (*UpdateUserInDepartmentResp, error) { + out := new(UpdateUserInDepartmentResp) + err := grpc.Invoke(ctx, "/organization.organization/UpdateUserInDepartment", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *organizationClient) GetDepartmentMember(ctx context.Context, in *GetDepartmentMemberReq, opts ...grpc.CallOption) (*GetDepartmentMemberResp, error) { + out := new(GetDepartmentMemberResp) + err := grpc.Invoke(ctx, "/organization.organization/GetDepartmentMember", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Organization service + +type OrganizationServer interface { + CreateDepartment(context.Context, *CreateDepartmentReq) (*CreateDepartmentResp, error) + UpdateDepartment(context.Context, *UpdateDepartmentReq) (*UpdateDepartmentResp, error) + GetSubDepartment(context.Context, *GetSubDepartmentReq) (*GetSubDepartmentResp, error) + DeleteDepartment(context.Context, *DeleteDepartmentReq) (*DeleteDepartmentResp, error) + CreateOrganizationUser(context.Context, *CreateOrganizationUserReq) (*CreateOrganizationUserResp, error) + UpdateOrganizationUser(context.Context, *UpdateOrganizationUserReq) (*UpdateOrganizationUserResp, error) + DeleteOrganizationUser(context.Context, *DeleteOrganizationUserReq) (*DeleteOrganizationUserResp, error) + CreateDepartmentMember(context.Context, *CreateDepartmentMemberReq) (*CreateDepartmentMemberResp, error) + GetUserInDepartment(context.Context, *GetUserInDepartmentReq) (*GetUserInDepartmentResp, error) + DeleteUserInDepartment(context.Context, *DeleteUserInDepartmentReq) (*DeleteUserInDepartmentResp, error) + UpdateUserInDepartment(context.Context, *UpdateUserInDepartmentReq) (*UpdateUserInDepartmentResp, error) + GetDepartmentMember(context.Context, *GetDepartmentMemberReq) (*GetDepartmentMemberResp, error) +} + +func RegisterOrganizationServer(s *grpc.Server, srv OrganizationServer) { + s.RegisterService(&_Organization_serviceDesc, srv) +} + +func _Organization_CreateDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).CreateDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/CreateDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).CreateDepartment(ctx, req.(*CreateDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_UpdateDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).UpdateDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/UpdateDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).UpdateDepartment(ctx, req.(*UpdateDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_GetSubDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSubDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).GetSubDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/GetSubDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).GetSubDepartment(ctx, req.(*GetSubDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_DeleteDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).DeleteDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/DeleteDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).DeleteDepartment(ctx, req.(*DeleteDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_CreateOrganizationUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateOrganizationUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).CreateOrganizationUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/CreateOrganizationUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).CreateOrganizationUser(ctx, req.(*CreateOrganizationUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_UpdateOrganizationUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateOrganizationUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).UpdateOrganizationUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/UpdateOrganizationUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).UpdateOrganizationUser(ctx, req.(*UpdateOrganizationUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_DeleteOrganizationUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteOrganizationUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).DeleteOrganizationUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/DeleteOrganizationUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).DeleteOrganizationUser(ctx, req.(*DeleteOrganizationUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_CreateDepartmentMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateDepartmentMemberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).CreateDepartmentMember(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/CreateDepartmentMember", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).CreateDepartmentMember(ctx, req.(*CreateDepartmentMemberReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_GetUserInDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserInDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).GetUserInDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/GetUserInDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).GetUserInDepartment(ctx, req.(*GetUserInDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_DeleteUserInDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserInDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).DeleteUserInDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/DeleteUserInDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).DeleteUserInDepartment(ctx, req.(*DeleteUserInDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_UpdateUserInDepartment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserInDepartmentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).UpdateUserInDepartment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/UpdateUserInDepartment", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).UpdateUserInDepartment(ctx, req.(*UpdateUserInDepartmentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Organization_GetDepartmentMember_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetDepartmentMemberReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrganizationServer).GetDepartmentMember(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/organization.organization/GetDepartmentMember", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrganizationServer).GetDepartmentMember(ctx, req.(*GetDepartmentMemberReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _Organization_serviceDesc = grpc.ServiceDesc{ + ServiceName: "organization.organization", + HandlerType: (*OrganizationServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateDepartment", + Handler: _Organization_CreateDepartment_Handler, + }, + { + MethodName: "UpdateDepartment", + Handler: _Organization_UpdateDepartment_Handler, + }, + { + MethodName: "GetSubDepartment", + Handler: _Organization_GetSubDepartment_Handler, + }, + { + MethodName: "DeleteDepartment", + Handler: _Organization_DeleteDepartment_Handler, + }, + { + MethodName: "CreateOrganizationUser", + Handler: _Organization_CreateOrganizationUser_Handler, + }, + { + MethodName: "UpdateOrganizationUser", + Handler: _Organization_UpdateOrganizationUser_Handler, + }, + { + MethodName: "DeleteOrganizationUser", + Handler: _Organization_DeleteOrganizationUser_Handler, + }, + { + MethodName: "CreateDepartmentMember", + Handler: _Organization_CreateDepartmentMember_Handler, + }, + { + MethodName: "GetUserInDepartment", + Handler: _Organization_GetUserInDepartment_Handler, + }, + { + MethodName: "DeleteUserInDepartment", + Handler: _Organization_DeleteUserInDepartment_Handler, + }, + { + MethodName: "UpdateUserInDepartment", + Handler: _Organization_UpdateUserInDepartment_Handler, + }, + { + MethodName: "GetDepartmentMember", + Handler: _Organization_GetDepartmentMember_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "organization/organization.proto", +} + +func init() { + proto.RegisterFile("organization/organization.proto", fileDescriptor_organization_a03f9a4144ed1081) +} + +var fileDescriptor_organization_a03f9a4144ed1081 = []byte{ + // 713 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0x4f, 0x6f, 0x12, 0x41, + 0x14, 0xcf, 0x8a, 0x56, 0xfb, 0xda, 0x18, 0x32, 0x25, 0x48, 0xd7, 0x34, 0xd2, 0xd5, 0x46, 0x4e, + 0x90, 0xd4, 0xa3, 0x37, 0x8b, 0x69, 0x49, 0xac, 0x24, 0x18, 0x62, 0xf0, 0x42, 0x96, 0x30, 0x12, + 0x82, 0xec, 0x0e, 0x33, 0x8b, 0x24, 0xfd, 0x12, 0x9e, 0xbc, 0x18, 0x8f, 0x9e, 0xfc, 0x34, 0x7e, + 0x24, 0xb3, 0xbb, 0x94, 0x0e, 0x6f, 0xde, 0x52, 0x5c, 0x16, 0xa3, 0xc7, 0x19, 0x66, 0xde, 0xef, + 0xbd, 0xdf, 0xfb, 0x33, 0x3f, 0x16, 0x9e, 0xf8, 0x72, 0xe0, 0x7a, 0xc3, 0x2b, 0x37, 0x18, 0xfa, + 0x5e, 0x4d, 0x5f, 0x54, 0x85, 0xf4, 0x03, 0x9f, 0xed, 0xeb, 0x7b, 0xf6, 0x71, 0x53, 0x70, 0xaf, + 0xdb, 0xb8, 0xac, 0x89, 0xd1, 0xa0, 0x16, 0x1d, 0xa8, 0xa9, 0xfe, 0xa8, 0x3b, 0x53, 0xb5, 0x99, + 0x8a, 0x2f, 0x38, 0xdf, 0x2c, 0x38, 0x38, 0x93, 0xdc, 0x0d, 0x78, 0x9d, 0x0b, 0x57, 0x06, 0x63, + 0xee, 0x05, 0x2d, 0x3e, 0x61, 0xaf, 0xe1, 0x61, 0x7f, 0xb1, 0xd1, 0xf0, 0x3e, 0xfa, 0x25, 0xab, + 0x6c, 0x55, 0xf6, 0x4e, 0x8f, 0xaa, 0x8a, 0xcb, 0xcf, 0x5c, 0x76, 0x5d, 0x31, 0xec, 0x0a, 0x57, + 0xba, 0x63, 0x55, 0xd5, 0x6e, 0xa2, 0x4b, 0xac, 0x0c, 0x7b, 0xbe, 0xe0, 0x32, 0x72, 0xa7, 0x51, + 0x2f, 0xdd, 0x29, 0x5b, 0x95, 0xdd, 0x96, 0xbe, 0xc5, 0x6c, 0x78, 0xe0, 0x8b, 0xb6, 0xe2, 0xb2, + 0x51, 0x2f, 0xe5, 0xa2, 0x9f, 0x17, 0x6b, 0xe7, 0x8b, 0x05, 0x05, 0xd3, 0x39, 0x25, 0x58, 0x09, + 0xee, 0x73, 0x29, 0xcf, 0xfc, 0x3e, 0x8f, 0xdc, 0xba, 0xd7, 0xba, 0x5e, 0xb2, 0x22, 0xec, 0x70, + 0x29, 0x2f, 0xd5, 0x60, 0x8e, 0x35, 0x5f, 0x11, 0xf1, 0xe4, 0x52, 0xc4, 0x13, 0xd1, 0xd5, 0x16, + 0xfd, 0x7f, 0x93, 0xae, 0x0b, 0x28, 0x98, 0xbe, 0xa5, 0x61, 0xcb, 0x99, 0xc1, 0xc1, 0x39, 0x0f, + 0xde, 0x4d, 0x7b, 0xcb, 0x51, 0x3a, 0xb0, 0xaf, 0x39, 0x5c, 0x8f, 0xac, 0xed, 0xb6, 0x96, 0xf6, + 0x32, 0xc8, 0xb8, 0x89, 0xbc, 0x79, 0xc6, 0xdf, 0x0c, 0x55, 0x50, 0xca, 0x95, 0x73, 0x7f, 0x94, + 0x92, 0xf0, 0x52, 0x48, 0x45, 0x9d, 0x7f, 0xe2, 0x38, 0xe1, 0xdb, 0xa7, 0xe2, 0x02, 0x0a, 0x26, + 0x70, 0xaa, 0x6c, 0xfe, 0xb4, 0xe0, 0x30, 0x6e, 0xa3, 0xa6, 0x36, 0x1d, 0x42, 0x98, 0x30, 0x92, + 0x26, 0xe4, 0x7d, 0xb4, 0x3d, 0x2f, 0xde, 0xa7, 0x04, 0x53, 0x86, 0x05, 0xe3, 0xf2, 0x86, 0x61, + 0xbf, 0x05, 0x3b, 0xc9, 0xd7, 0xd4, 0xc1, 0xc7, 0x5d, 0xf1, 0x7f, 0x04, 0x9f, 0xe4, 0xeb, 0x86, + 0x99, 0xbf, 0x29, 0xa2, 0x4b, 0x3e, 0xee, 0x2d, 0x82, 0x9f, 0x86, 0xb8, 0xde, 0xcd, 0x8f, 0x2b, + 0x82, 0x6f, 0xa3, 0xa3, 0x2d, 0xe3, 0x72, 0x56, 0x99, 0x37, 0x7d, 0x4d, 0x15, 0xbc, 0x07, 0xc5, + 0x73, 0x1e, 0x18, 0x6e, 0xf3, 0x49, 0x78, 0x63, 0x1a, 0xfb, 0x10, 0xb7, 0xed, 0x7c, 0xb5, 0xa1, + 0xff, 0xdf, 0x2d, 0x78, 0x44, 0x02, 0xa6, 0x1a, 0x5f, 0x54, 0x72, 0x72, 0x1b, 0x24, 0x47, 0x6b, + 0x04, 0x8a, 0x92, 0x26, 0xe4, 0xfb, 0x88, 0xf6, 0x15, 0xb5, 0x60, 0x64, 0xc8, 0xb8, 0x9c, 0x55, + 0x23, 0x64, 0xc3, 0xa6, 0xf3, 0xd5, 0x82, 0xc3, 0x78, 0x9a, 0xfe, 0xb5, 0x7a, 0x30, 0x9e, 0x88, + 0xbb, 0xe6, 0x13, 0x11, 0xc6, 0x99, 0xe4, 0x56, 0xaa, 0x38, 0x27, 0xd7, 0x61, 0x52, 0xc3, 0x6e, + 0x3b, 0x65, 0xbf, 0x08, 0x21, 0xa3, 0x99, 0x75, 0x15, 0xb5, 0x2d, 0x35, 0xaf, 0xb6, 0xff, 0xe6, + 0xfe, 0x88, 0x5b, 0x38, 0x9b, 0x01, 0xc4, 0xde, 0x43, 0x01, 0x77, 0xa1, 0xa6, 0x43, 0xd6, 0x6a, + 0x63, 0xd2, 0xc0, 0xe9, 0xaf, 0x5d, 0x58, 0x12, 0xfa, 0xac, 0x03, 0x79, 0x3c, 0x3a, 0xd9, 0x71, + 0x75, 0xe9, 0xff, 0x01, 0x21, 0xf2, 0x6d, 0xe7, 0xb6, 0x23, 0x4a, 0x84, 0xa6, 0xb1, 0xa8, 0xc4, + 0xa6, 0x09, 0x41, 0x8c, 0x4d, 0x93, 0xba, 0xb4, 0x03, 0x79, 0xac, 0xf5, 0xb0, 0x69, 0x42, 0x85, + 0x62, 0xd3, 0xa4, 0x5c, 0xec, 0x40, 0x1e, 0x8b, 0x27, 0x6c, 0x9a, 0x50, 0x75, 0xd8, 0x34, 0xa9, + 0xbf, 0x46, 0x50, 0xa4, 0x05, 0x0a, 0x7b, 0x4e, 0xd1, 0x49, 0x34, 0xa2, 0x5d, 0x59, 0xef, 0x60, + 0x0c, 0x46, 0x0b, 0x02, 0x0c, 0x96, 0x28, 0x71, 0x30, 0xd8, 0x0a, 0x7d, 0x31, 0x82, 0x22, 0xdd, + 0xc9, 0x18, 0x2c, 0x71, 0xc4, 0x60, 0xb0, 0x15, 0x83, 0x61, 0x41, 0x23, 0x6e, 0x36, 0x9a, 0x46, + 0x62, 0x1e, 0xd0, 0x34, 0x92, 0xbd, 0xdb, 0x8b, 0xfe, 0xcf, 0xe0, 0xee, 0x62, 0xcf, 0x8c, 0x4a, + 0x22, 0x5e, 0x07, 0xfb, 0x64, 0x8d, 0x53, 0x3a, 0x7b, 0x06, 0x0c, 0xc9, 0x1e, 0x85, 0x54, 0x59, + 0xef, 0xa0, 0x5e, 0x17, 0xb7, 0x81, 0x25, 0xbe, 0xf8, 0x74, 0x5d, 0x90, 0x60, 0x31, 0x7b, 0x46, + 0x9e, 0x4c, 0xf6, 0xa8, 0x24, 0x9d, 0xac, 0x71, 0x4a, 0x89, 0x57, 0x47, 0x1f, 0x1e, 0x57, 0x97, + 0x3e, 0x68, 0xbc, 0xd4, 0x17, 0xbd, 0x9d, 0xe8, 0x6b, 0xc5, 0x8b, 0xdf, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x33, 0x0d, 0x37, 0x72, 0x01, 0x11, 0x00, 0x00, +} diff --git a/pkg/proto/organization/organization.proto b/pkg/proto/organization/organization.proto new file mode 100644 index 000000000..343ac43ea --- /dev/null +++ b/pkg/proto/organization/organization.proto @@ -0,0 +1,172 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./organization;organization"; +package organization; + + +message CreateDepartmentReq{ + server_api_params.Department departmentInfo = 1; + string operationID = 2; + string opUserID = 3; +} + +message CreateDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; + server_api_params.Department departmentInfo = 3; +} + +message UpdateDepartmentReq{ + server_api_params.Department departmentInfo = 1; + string operationID = 2; + string opUserID = 3; +} + +message UpdateDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; +} + + +message GetSubDepartmentReq{ + string departmentID = 1; + string operationID = 2; + string opUserID = 3; +} + +message GetSubDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; + repeated server_api_params.Department departmentList = 3; +} + +message DeleteDepartmentReq{ + string departmentID = 1; + string operationID = 2; + string opUserID = 3; +} + +message DeleteDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; +} + + +message CreateOrganizationUserReq{ + server_api_params.OrganizationUser organizationUser = 1; + string operationID = 2; + string opUserID = 3; +} + + +message CreateOrganizationUserResp{ + int32 errCode = 1; + string errMsg = 2; +} + + +message UpdateOrganizationUserReq{ + server_api_params.OrganizationUser organizationUser = 1; + string operationID = 2; + string opUserID = 3; +} + + +message UpdateOrganizationUserResp{ + int32 errCode = 1; + string errMsg = 2; +} + + + + +message CreateDepartmentMemberReq{ + server_api_params.UserInDepartment userInDepartment = 1; + string operationID = 2; + string opUserID = 3; +} +message CreateDepartmentMemberResp{ + int32 errCode = 1; + string errMsg = 2; +} + + +message GetUserInDepartmentReq{ + string userID = 1; + string operationID = 2; + string opUserID = 3; +} +message GetUserInDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; + server_api_params.UserInDepartment userInDepartment = 3; +} + + +message UpdateUserInDepartmentReq{ + server_api_params.DepartmentMember departmentMember = 1; + string operationID = 2; + string opUserID = 3; +} +message UpdateUserInDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; +} + + +message DeleteUserInDepartmentReq{ + string userID = 1; + string operationID = 2; + string opUserID = 3; + string departmentID = 4; +} +message DeleteUserInDepartmentResp{ + int32 errCode = 1; + string errMsg = 2; +} + +message DeleteOrganizationUserReq{ + string userID = 1; + string operationID = 2; + string opUserID = 3; +} +message DeleteOrganizationUserResp{ + int32 errCode = 1; + string errMsg = 2; +} + + +message GetDepartmentMemberReq{ + string departmentID = 1; + string operationID = 2; + string opUserID = 3; +} + +message GetDepartmentMemberResp{ + int32 errCode = 1; + string errMsg = 2; + repeated server_api_params.UserInDepartment userInDepartmentList = 3; +} + + +service organization{ + rpc CreateDepartment(CreateDepartmentReq) returns(CreateDepartmentResp); + rpc UpdateDepartment(UpdateDepartmentReq) returns(UpdateDepartmentResp); + rpc GetSubDepartment(GetSubDepartmentReq) returns(GetSubDepartmentResp); + rpc DeleteDepartment(DeleteDepartmentReq) returns(DeleteDepartmentResp); + + rpc CreateOrganizationUser(CreateOrganizationUserReq) returns(CreateOrganizationUserResp); + rpc UpdateOrganizationUser(UpdateOrganizationUserReq) returns(UpdateOrganizationUserResp); + rpc DeleteOrganizationUser(DeleteOrganizationUserReq) returns(DeleteOrganizationUserResp); + + + rpc CreateDepartmentMember(CreateDepartmentMemberReq) returns(CreateDepartmentMemberResp); + rpc GetUserInDepartment(GetUserInDepartmentReq) returns(GetUserInDepartmentResp); + rpc DeleteUserInDepartment(DeleteUserInDepartmentReq) returns(DeleteUserInDepartmentResp); + rpc UpdateUserInDepartment(UpdateUserInDepartmentReq) returns(UpdateUserInDepartmentResp); + rpc GetDepartmentMember(GetDepartmentMemberReq) returns(GetDepartmentMemberResp); +} + + + + diff --git a/pkg/proto/proto_dir.cfg b/pkg/proto/proto_dir.cfg new file mode 100644 index 000000000..bc7945472 --- /dev/null +++ b/pkg/proto/proto_dir.cfg @@ -0,0 +1,15 @@ + +all_proto=( + message_cms/message_cms.proto + admin_cms/admin_cms.proto + statistics/statistics.proto + auth/auth.proto + friend/friend.proto + group/group.proto + user/user.proto + rtc/rtc.proto + chat/chat.proto + push/push.proto + relay/relay.proto + sdk_ws/ws.proto +) diff --git a/pkg/proto/push/push.pb.go b/pkg/proto/push/push.pb.go new file mode 100644 index 000000000..e9354ae69 --- /dev/null +++ b/pkg/proto/push/push.pb.go @@ -0,0 +1,216 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: push/push.proto + +package pbPush // import "./push" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type PushMsgReq struct { + OperationID string `protobuf:"bytes,1,opt,name=operationID" json:"operationID,omitempty"` + MsgData *sdk_ws.MsgData `protobuf:"bytes,2,opt,name=msgData" json:"msgData,omitempty"` + PushToUserID string `protobuf:"bytes,3,opt,name=pushToUserID" json:"pushToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PushMsgReq) Reset() { *m = PushMsgReq{} } +func (m *PushMsgReq) String() string { return proto.CompactTextString(m) } +func (*PushMsgReq) ProtoMessage() {} +func (*PushMsgReq) Descriptor() ([]byte, []int) { + return fileDescriptor_push_76409d0b017416ef, []int{0} +} +func (m *PushMsgReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PushMsgReq.Unmarshal(m, b) +} +func (m *PushMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PushMsgReq.Marshal(b, m, deterministic) +} +func (dst *PushMsgReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_PushMsgReq.Merge(dst, src) +} +func (m *PushMsgReq) XXX_Size() int { + return xxx_messageInfo_PushMsgReq.Size(m) +} +func (m *PushMsgReq) XXX_DiscardUnknown() { + xxx_messageInfo_PushMsgReq.DiscardUnknown(m) +} + +var xxx_messageInfo_PushMsgReq proto.InternalMessageInfo + +func (m *PushMsgReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *PushMsgReq) GetMsgData() *sdk_ws.MsgData { + if m != nil { + return m.MsgData + } + return nil +} + +func (m *PushMsgReq) GetPushToUserID() string { + if m != nil { + return m.PushToUserID + } + return "" +} + +type PushMsgResp struct { + ResultCode int32 `protobuf:"varint,1,opt,name=ResultCode" json:"ResultCode,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PushMsgResp) Reset() { *m = PushMsgResp{} } +func (m *PushMsgResp) String() string { return proto.CompactTextString(m) } +func (*PushMsgResp) ProtoMessage() {} +func (*PushMsgResp) Descriptor() ([]byte, []int) { + return fileDescriptor_push_76409d0b017416ef, []int{1} +} +func (m *PushMsgResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PushMsgResp.Unmarshal(m, b) +} +func (m *PushMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PushMsgResp.Marshal(b, m, deterministic) +} +func (dst *PushMsgResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_PushMsgResp.Merge(dst, src) +} +func (m *PushMsgResp) XXX_Size() int { + return xxx_messageInfo_PushMsgResp.Size(m) +} +func (m *PushMsgResp) XXX_DiscardUnknown() { + xxx_messageInfo_PushMsgResp.DiscardUnknown(m) +} + +var xxx_messageInfo_PushMsgResp proto.InternalMessageInfo + +func (m *PushMsgResp) GetResultCode() int32 { + if m != nil { + return m.ResultCode + } + return 0 +} + +func init() { + proto.RegisterType((*PushMsgReq)(nil), "push.PushMsgReq") + proto.RegisterType((*PushMsgResp)(nil), "push.PushMsgResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for PushMsgService service + +type PushMsgServiceClient interface { + PushMsg(ctx context.Context, in *PushMsgReq, opts ...grpc.CallOption) (*PushMsgResp, error) +} + +type pushMsgServiceClient struct { + cc *grpc.ClientConn +} + +func NewPushMsgServiceClient(cc *grpc.ClientConn) PushMsgServiceClient { + return &pushMsgServiceClient{cc} +} + +func (c *pushMsgServiceClient) PushMsg(ctx context.Context, in *PushMsgReq, opts ...grpc.CallOption) (*PushMsgResp, error) { + out := new(PushMsgResp) + err := grpc.Invoke(ctx, "/push.PushMsgService/PushMsg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for PushMsgService service + +type PushMsgServiceServer interface { + PushMsg(context.Context, *PushMsgReq) (*PushMsgResp, error) +} + +func RegisterPushMsgServiceServer(s *grpc.Server, srv PushMsgServiceServer) { + s.RegisterService(&_PushMsgService_serviceDesc, srv) +} + +func _PushMsgService_PushMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PushMsgReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PushMsgServiceServer).PushMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/push.PushMsgService/PushMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PushMsgServiceServer).PushMsg(ctx, req.(*PushMsgReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _PushMsgService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "push.PushMsgService", + HandlerType: (*PushMsgServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "PushMsg", + Handler: _PushMsgService_PushMsg_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "push/push.proto", +} + +func init() { proto.RegisterFile("push/push.proto", fileDescriptor_push_76409d0b017416ef) } + +var fileDescriptor_push_76409d0b017416ef = []byte{ + // 249 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0x3d, 0x4f, 0xc3, 0x30, + 0x10, 0x86, 0x15, 0xbe, 0x2a, 0x2e, 0x40, 0xc1, 0x53, 0x94, 0x01, 0x85, 0x4c, 0x5d, 0xb0, 0xa5, + 0xc2, 0xc6, 0x82, 0x20, 0x4b, 0x86, 0x08, 0x64, 0x60, 0x61, 0x89, 0x5c, 0x7a, 0x4a, 0xa3, 0xd2, + 0xfa, 0xf0, 0x25, 0xed, 0x5f, 0xe0, 0x67, 0xa3, 0xb8, 0x05, 0x02, 0x8b, 0x65, 0x3d, 0xf7, 0xe8, + 0xf4, 0xde, 0x0b, 0x43, 0x6a, 0x79, 0xa6, 0xba, 0x47, 0x92, 0xb3, 0x8d, 0x15, 0x7b, 0xdd, 0x3f, + 0xbe, 0x78, 0x20, 0x5c, 0x96, 0x79, 0xa1, 0x68, 0x5e, 0x29, 0x3f, 0x50, 0x3c, 0x9d, 0x97, 0x6b, + 0x56, 0x6b, 0xde, 0x88, 0xe9, 0x67, 0x00, 0xf0, 0xd8, 0xf2, 0xac, 0xe0, 0x4a, 0xe3, 0x87, 0x48, + 0x20, 0xb4, 0x84, 0xce, 0x34, 0xb5, 0x5d, 0xe6, 0x59, 0x14, 0x24, 0xc1, 0xe8, 0x50, 0xf7, 0x91, + 0xb8, 0x86, 0xc1, 0x82, 0xab, 0xcc, 0x34, 0x26, 0xda, 0x49, 0x82, 0x51, 0x38, 0x8e, 0x25, 0xa3, + 0x5b, 0xa1, 0x2b, 0x0d, 0xd5, 0x25, 0x19, 0x67, 0x16, 0x2c, 0x8b, 0x8d, 0xa1, 0xbf, 0x55, 0x91, + 0xc2, 0x51, 0x97, 0xe8, 0xd9, 0xbe, 0x30, 0xba, 0x3c, 0x8b, 0x76, 0xfd, 0xe2, 0x3f, 0x2c, 0xbd, + 0x84, 0xf0, 0x27, 0x09, 0x93, 0x38, 0x07, 0xd0, 0xc8, 0xed, 0x7b, 0x73, 0x6f, 0xa7, 0xe8, 0x93, + 0xec, 0xeb, 0x1e, 0x19, 0xdf, 0xc2, 0xc9, 0x56, 0x7f, 0x42, 0xb7, 0xaa, 0xdf, 0x50, 0x48, 0x18, + 0x6c, 0x89, 0x38, 0x95, 0xbe, 0x8c, 0xdf, 0xcb, 0xe2, 0xb3, 0x7f, 0x84, 0xe9, 0x6e, 0xf8, 0x7a, + 0x2c, 0x7d, 0x69, 0x37, 0x34, 0xe9, 0xf8, 0xe4, 0xc0, 0x77, 0x72, 0xf5, 0x15, 0x00, 0x00, 0xff, + 0xff, 0xbe, 0xb7, 0x7c, 0x1c, 0x4f, 0x01, 0x00, 0x00, +} diff --git a/pkg/proto/push/push.proto b/pkg/proto/push/push.proto new file mode 100644 index 000000000..5d91083b3 --- /dev/null +++ b/pkg/proto/push/push.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./push;pbPush"; +package push; + +message PushMsgReq { + string operationID = 1; + server_api_params.MsgData msgData = 2; + string pushToUserID = 3; +} +message PushMsgResp{ + int32 ResultCode = 1; +} +//message InternalPushMsgReq{ +// int32 ReqIdentifier = 1; +// string Token = 2; +// string SendID = 3; +// string OperationID = 4; +// int32 MsgIncr = 5; +// int32 PlatformID = 6; +// int32 SessionType = 7; +// int32 MsgFrom = 8; +// int32 ContentType = 9; +// string RecvID = 10; +// repeated string ForceList = 11; +// string Content = 12; +// string Options = 13; +// string ClientMsgID = 14; +// string OffLineInfo = 15; +// string Ex = 16; +// +//} + +service PushMsgService { + rpc PushMsg(PushMsgReq) returns(PushMsgResp); +// rpc InternalPushMsg(InternalPushMsgReq)returns(PushMsgResp); +} + diff --git a/pkg/proto/relay/relay.pb.go b/pkg/proto/relay/relay.pb.go new file mode 100644 index 000000000..37334a8b2 --- /dev/null +++ b/pkg/proto/relay/relay.pb.go @@ -0,0 +1,602 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: relay/relay.proto + +package pbRelay // import "./relay" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type OnlinePushMsgReq struct { + OperationID string `protobuf:"bytes,1,opt,name=OperationID" json:"OperationID,omitempty"` + MsgData *sdk_ws.MsgData `protobuf:"bytes,2,opt,name=msgData" json:"msgData,omitempty"` + PushToUserID string `protobuf:"bytes,3,opt,name=pushToUserID" json:"pushToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OnlinePushMsgReq) Reset() { *m = OnlinePushMsgReq{} } +func (m *OnlinePushMsgReq) String() string { return proto.CompactTextString(m) } +func (*OnlinePushMsgReq) ProtoMessage() {} +func (*OnlinePushMsgReq) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{0} +} +func (m *OnlinePushMsgReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OnlinePushMsgReq.Unmarshal(m, b) +} +func (m *OnlinePushMsgReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OnlinePushMsgReq.Marshal(b, m, deterministic) +} +func (dst *OnlinePushMsgReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_OnlinePushMsgReq.Merge(dst, src) +} +func (m *OnlinePushMsgReq) XXX_Size() int { + return xxx_messageInfo_OnlinePushMsgReq.Size(m) +} +func (m *OnlinePushMsgReq) XXX_DiscardUnknown() { + xxx_messageInfo_OnlinePushMsgReq.DiscardUnknown(m) +} + +var xxx_messageInfo_OnlinePushMsgReq proto.InternalMessageInfo + +func (m *OnlinePushMsgReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *OnlinePushMsgReq) GetMsgData() *sdk_ws.MsgData { + if m != nil { + return m.MsgData + } + return nil +} + +func (m *OnlinePushMsgReq) GetPushToUserID() string { + if m != nil { + return m.PushToUserID + } + return "" +} + +type OnlinePushMsgResp struct { + Resp []*SingleMsgToUser `protobuf:"bytes,1,rep,name=resp" json:"resp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OnlinePushMsgResp) Reset() { *m = OnlinePushMsgResp{} } +func (m *OnlinePushMsgResp) String() string { return proto.CompactTextString(m) } +func (*OnlinePushMsgResp) ProtoMessage() {} +func (*OnlinePushMsgResp) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{1} +} +func (m *OnlinePushMsgResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OnlinePushMsgResp.Unmarshal(m, b) +} +func (m *OnlinePushMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OnlinePushMsgResp.Marshal(b, m, deterministic) +} +func (dst *OnlinePushMsgResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_OnlinePushMsgResp.Merge(dst, src) +} +func (m *OnlinePushMsgResp) XXX_Size() int { + return xxx_messageInfo_OnlinePushMsgResp.Size(m) +} +func (m *OnlinePushMsgResp) XXX_DiscardUnknown() { + xxx_messageInfo_OnlinePushMsgResp.DiscardUnknown(m) +} + +var xxx_messageInfo_OnlinePushMsgResp proto.InternalMessageInfo + +func (m *OnlinePushMsgResp) GetResp() []*SingleMsgToUser { + if m != nil { + return m.Resp + } + return nil +} + +type SingleMsgToUser struct { + ResultCode int64 `protobuf:"varint,1,opt,name=ResultCode" json:"ResultCode,omitempty"` + RecvID string `protobuf:"bytes,2,opt,name=RecvID" json:"RecvID,omitempty"` + RecvPlatFormID int32 `protobuf:"varint,3,opt,name=RecvPlatFormID" json:"RecvPlatFormID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SingleMsgToUser) Reset() { *m = SingleMsgToUser{} } +func (m *SingleMsgToUser) String() string { return proto.CompactTextString(m) } +func (*SingleMsgToUser) ProtoMessage() {} +func (*SingleMsgToUser) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{2} +} +func (m *SingleMsgToUser) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SingleMsgToUser.Unmarshal(m, b) +} +func (m *SingleMsgToUser) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SingleMsgToUser.Marshal(b, m, deterministic) +} +func (dst *SingleMsgToUser) XXX_Merge(src proto.Message) { + xxx_messageInfo_SingleMsgToUser.Merge(dst, src) +} +func (m *SingleMsgToUser) XXX_Size() int { + return xxx_messageInfo_SingleMsgToUser.Size(m) +} +func (m *SingleMsgToUser) XXX_DiscardUnknown() { + xxx_messageInfo_SingleMsgToUser.DiscardUnknown(m) +} + +var xxx_messageInfo_SingleMsgToUser proto.InternalMessageInfo + +func (m *SingleMsgToUser) GetResultCode() int64 { + if m != nil { + return m.ResultCode + } + return 0 +} + +func (m *SingleMsgToUser) GetRecvID() string { + if m != nil { + return m.RecvID + } + return "" +} + +func (m *SingleMsgToUser) GetRecvPlatFormID() int32 { + if m != nil { + return m.RecvPlatFormID + } + return 0 +} + +type GetUsersOnlineStatusReq struct { + UserIDList []string `protobuf:"bytes,1,rep,name=userIDList" json:"userIDList,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=opUserID" json:"opUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersOnlineStatusReq) Reset() { *m = GetUsersOnlineStatusReq{} } +func (m *GetUsersOnlineStatusReq) String() string { return proto.CompactTextString(m) } +func (*GetUsersOnlineStatusReq) ProtoMessage() {} +func (*GetUsersOnlineStatusReq) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{3} +} +func (m *GetUsersOnlineStatusReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersOnlineStatusReq.Unmarshal(m, b) +} +func (m *GetUsersOnlineStatusReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersOnlineStatusReq.Marshal(b, m, deterministic) +} +func (dst *GetUsersOnlineStatusReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersOnlineStatusReq.Merge(dst, src) +} +func (m *GetUsersOnlineStatusReq) XXX_Size() int { + return xxx_messageInfo_GetUsersOnlineStatusReq.Size(m) +} +func (m *GetUsersOnlineStatusReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersOnlineStatusReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersOnlineStatusReq proto.InternalMessageInfo + +func (m *GetUsersOnlineStatusReq) GetUserIDList() []string { + if m != nil { + return m.UserIDList + } + return nil +} + +func (m *GetUsersOnlineStatusReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetUsersOnlineStatusReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +type GetUsersOnlineStatusResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + SuccessResult []*GetUsersOnlineStatusResp_SuccessResult `protobuf:"bytes,3,rep,name=successResult" json:"successResult,omitempty"` + FailedResult []*GetUsersOnlineStatusResp_FailedDetail `protobuf:"bytes,4,rep,name=failedResult" json:"failedResult,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersOnlineStatusResp) Reset() { *m = GetUsersOnlineStatusResp{} } +func (m *GetUsersOnlineStatusResp) String() string { return proto.CompactTextString(m) } +func (*GetUsersOnlineStatusResp) ProtoMessage() {} +func (*GetUsersOnlineStatusResp) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{4} +} +func (m *GetUsersOnlineStatusResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersOnlineStatusResp.Unmarshal(m, b) +} +func (m *GetUsersOnlineStatusResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersOnlineStatusResp.Marshal(b, m, deterministic) +} +func (dst *GetUsersOnlineStatusResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersOnlineStatusResp.Merge(dst, src) +} +func (m *GetUsersOnlineStatusResp) XXX_Size() int { + return xxx_messageInfo_GetUsersOnlineStatusResp.Size(m) +} +func (m *GetUsersOnlineStatusResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersOnlineStatusResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersOnlineStatusResp proto.InternalMessageInfo + +func (m *GetUsersOnlineStatusResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetUsersOnlineStatusResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *GetUsersOnlineStatusResp) GetSuccessResult() []*GetUsersOnlineStatusResp_SuccessResult { + if m != nil { + return m.SuccessResult + } + return nil +} + +func (m *GetUsersOnlineStatusResp) GetFailedResult() []*GetUsersOnlineStatusResp_FailedDetail { + if m != nil { + return m.FailedResult + } + return nil +} + +type GetUsersOnlineStatusResp_SuccessDetail struct { + Platform string `protobuf:"bytes,1,opt,name=platform" json:"platform,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersOnlineStatusResp_SuccessDetail) Reset() { + *m = GetUsersOnlineStatusResp_SuccessDetail{} +} +func (m *GetUsersOnlineStatusResp_SuccessDetail) String() string { return proto.CompactTextString(m) } +func (*GetUsersOnlineStatusResp_SuccessDetail) ProtoMessage() {} +func (*GetUsersOnlineStatusResp_SuccessDetail) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{4, 0} +} +func (m *GetUsersOnlineStatusResp_SuccessDetail) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersOnlineStatusResp_SuccessDetail.Unmarshal(m, b) +} +func (m *GetUsersOnlineStatusResp_SuccessDetail) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersOnlineStatusResp_SuccessDetail.Marshal(b, m, deterministic) +} +func (dst *GetUsersOnlineStatusResp_SuccessDetail) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersOnlineStatusResp_SuccessDetail.Merge(dst, src) +} +func (m *GetUsersOnlineStatusResp_SuccessDetail) XXX_Size() int { + return xxx_messageInfo_GetUsersOnlineStatusResp_SuccessDetail.Size(m) +} +func (m *GetUsersOnlineStatusResp_SuccessDetail) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersOnlineStatusResp_SuccessDetail.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersOnlineStatusResp_SuccessDetail proto.InternalMessageInfo + +func (m *GetUsersOnlineStatusResp_SuccessDetail) GetPlatform() string { + if m != nil { + return m.Platform + } + return "" +} + +func (m *GetUsersOnlineStatusResp_SuccessDetail) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + +type GetUsersOnlineStatusResp_FailedDetail struct { + UserID string `protobuf:"bytes,3,opt,name=userID" json:"userID,omitempty"` + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersOnlineStatusResp_FailedDetail) Reset() { *m = GetUsersOnlineStatusResp_FailedDetail{} } +func (m *GetUsersOnlineStatusResp_FailedDetail) String() string { return proto.CompactTextString(m) } +func (*GetUsersOnlineStatusResp_FailedDetail) ProtoMessage() {} +func (*GetUsersOnlineStatusResp_FailedDetail) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{4, 1} +} +func (m *GetUsersOnlineStatusResp_FailedDetail) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersOnlineStatusResp_FailedDetail.Unmarshal(m, b) +} +func (m *GetUsersOnlineStatusResp_FailedDetail) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersOnlineStatusResp_FailedDetail.Marshal(b, m, deterministic) +} +func (dst *GetUsersOnlineStatusResp_FailedDetail) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersOnlineStatusResp_FailedDetail.Merge(dst, src) +} +func (m *GetUsersOnlineStatusResp_FailedDetail) XXX_Size() int { + return xxx_messageInfo_GetUsersOnlineStatusResp_FailedDetail.Size(m) +} +func (m *GetUsersOnlineStatusResp_FailedDetail) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersOnlineStatusResp_FailedDetail.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersOnlineStatusResp_FailedDetail proto.InternalMessageInfo + +func (m *GetUsersOnlineStatusResp_FailedDetail) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUsersOnlineStatusResp_FailedDetail) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *GetUsersOnlineStatusResp_FailedDetail) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type GetUsersOnlineStatusResp_SuccessResult struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"` + DetailPlatformStatus []*GetUsersOnlineStatusResp_SuccessDetail `protobuf:"bytes,3,rep,name=detailPlatformStatus" json:"detailPlatformStatus,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersOnlineStatusResp_SuccessResult) Reset() { + *m = GetUsersOnlineStatusResp_SuccessResult{} +} +func (m *GetUsersOnlineStatusResp_SuccessResult) String() string { return proto.CompactTextString(m) } +func (*GetUsersOnlineStatusResp_SuccessResult) ProtoMessage() {} +func (*GetUsersOnlineStatusResp_SuccessResult) Descriptor() ([]byte, []int) { + return fileDescriptor_relay_34094e5333f6005a, []int{4, 2} +} +func (m *GetUsersOnlineStatusResp_SuccessResult) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersOnlineStatusResp_SuccessResult.Unmarshal(m, b) +} +func (m *GetUsersOnlineStatusResp_SuccessResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersOnlineStatusResp_SuccessResult.Marshal(b, m, deterministic) +} +func (dst *GetUsersOnlineStatusResp_SuccessResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersOnlineStatusResp_SuccessResult.Merge(dst, src) +} +func (m *GetUsersOnlineStatusResp_SuccessResult) XXX_Size() int { + return xxx_messageInfo_GetUsersOnlineStatusResp_SuccessResult.Size(m) +} +func (m *GetUsersOnlineStatusResp_SuccessResult) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersOnlineStatusResp_SuccessResult.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersOnlineStatusResp_SuccessResult proto.InternalMessageInfo + +func (m *GetUsersOnlineStatusResp_SuccessResult) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GetUsersOnlineStatusResp_SuccessResult) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + +func (m *GetUsersOnlineStatusResp_SuccessResult) GetDetailPlatformStatus() []*GetUsersOnlineStatusResp_SuccessDetail { + if m != nil { + return m.DetailPlatformStatus + } + return nil +} + +func init() { + proto.RegisterType((*OnlinePushMsgReq)(nil), "relay.OnlinePushMsgReq") + proto.RegisterType((*OnlinePushMsgResp)(nil), "relay.OnlinePushMsgResp") + proto.RegisterType((*SingleMsgToUser)(nil), "relay.SingleMsgToUser") + proto.RegisterType((*GetUsersOnlineStatusReq)(nil), "relay.GetUsersOnlineStatusReq") + proto.RegisterType((*GetUsersOnlineStatusResp)(nil), "relay.GetUsersOnlineStatusResp") + proto.RegisterType((*GetUsersOnlineStatusResp_SuccessDetail)(nil), "relay.GetUsersOnlineStatusResp.SuccessDetail") + proto.RegisterType((*GetUsersOnlineStatusResp_FailedDetail)(nil), "relay.GetUsersOnlineStatusResp.FailedDetail") + proto.RegisterType((*GetUsersOnlineStatusResp_SuccessResult)(nil), "relay.GetUsersOnlineStatusResp.SuccessResult") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for OnlineMessageRelayService service + +type OnlineMessageRelayServiceClient interface { + OnlinePushMsg(ctx context.Context, in *OnlinePushMsgReq, opts ...grpc.CallOption) (*OnlinePushMsgResp, error) + GetUsersOnlineStatus(ctx context.Context, in *GetUsersOnlineStatusReq, opts ...grpc.CallOption) (*GetUsersOnlineStatusResp, error) +} + +type onlineMessageRelayServiceClient struct { + cc *grpc.ClientConn +} + +func NewOnlineMessageRelayServiceClient(cc *grpc.ClientConn) OnlineMessageRelayServiceClient { + return &onlineMessageRelayServiceClient{cc} +} + +func (c *onlineMessageRelayServiceClient) OnlinePushMsg(ctx context.Context, in *OnlinePushMsgReq, opts ...grpc.CallOption) (*OnlinePushMsgResp, error) { + out := new(OnlinePushMsgResp) + err := grpc.Invoke(ctx, "/relay.OnlineMessageRelayService/OnlinePushMsg", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *onlineMessageRelayServiceClient) GetUsersOnlineStatus(ctx context.Context, in *GetUsersOnlineStatusReq, opts ...grpc.CallOption) (*GetUsersOnlineStatusResp, error) { + out := new(GetUsersOnlineStatusResp) + err := grpc.Invoke(ctx, "/relay.OnlineMessageRelayService/GetUsersOnlineStatus", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for OnlineMessageRelayService service + +type OnlineMessageRelayServiceServer interface { + OnlinePushMsg(context.Context, *OnlinePushMsgReq) (*OnlinePushMsgResp, error) + GetUsersOnlineStatus(context.Context, *GetUsersOnlineStatusReq) (*GetUsersOnlineStatusResp, error) +} + +func RegisterOnlineMessageRelayServiceServer(s *grpc.Server, srv OnlineMessageRelayServiceServer) { + s.RegisterService(&_OnlineMessageRelayService_serviceDesc, srv) +} + +func _OnlineMessageRelayService_OnlinePushMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OnlinePushMsgReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OnlineMessageRelayServiceServer).OnlinePushMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.OnlineMessageRelayService/OnlinePushMsg", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OnlineMessageRelayServiceServer).OnlinePushMsg(ctx, req.(*OnlinePushMsgReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _OnlineMessageRelayService_GetUsersOnlineStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUsersOnlineStatusReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OnlineMessageRelayServiceServer).GetUsersOnlineStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.OnlineMessageRelayService/GetUsersOnlineStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OnlineMessageRelayServiceServer).GetUsersOnlineStatus(ctx, req.(*GetUsersOnlineStatusReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _OnlineMessageRelayService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "relay.OnlineMessageRelayService", + HandlerType: (*OnlineMessageRelayServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "OnlinePushMsg", + Handler: _OnlineMessageRelayService_OnlinePushMsg_Handler, + }, + { + MethodName: "GetUsersOnlineStatus", + Handler: _OnlineMessageRelayService_GetUsersOnlineStatus_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "relay/relay.proto", +} + +func init() { proto.RegisterFile("relay/relay.proto", fileDescriptor_relay_34094e5333f6005a) } + +var fileDescriptor_relay_34094e5333f6005a = []byte{ + // 554 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x5d, 0x8f, 0xd2, 0x40, + 0x14, 0x4d, 0x65, 0x3f, 0xdc, 0x0b, 0xb8, 0x32, 0xd9, 0xec, 0xd6, 0x3e, 0x20, 0xf6, 0xc1, 0x10, + 0xa3, 0x25, 0x41, 0xdf, 0x7c, 0x30, 0xd9, 0x25, 0x6b, 0x48, 0x6c, 0x20, 0x83, 0x46, 0xe3, 0x0b, + 0x99, 0x85, 0xbb, 0xdd, 0x66, 0x0b, 0x1d, 0xe6, 0xb6, 0x10, 0xff, 0x84, 0x3f, 0xc2, 0x3f, 0xa1, + 0x3f, 0xcf, 0x74, 0xa6, 0x60, 0x4b, 0x58, 0x37, 0xfb, 0x42, 0x38, 0x77, 0xee, 0x3d, 0xf7, 0x9c, + 0xd3, 0x76, 0xa0, 0xa1, 0x30, 0x12, 0x3f, 0x3a, 0xfa, 0xd7, 0x93, 0x2a, 0x4e, 0x62, 0xb6, 0xaf, + 0x81, 0xf3, 0x62, 0x20, 0x71, 0x3e, 0xee, 0xfb, 0x1d, 0x79, 0x1b, 0x74, 0xf4, 0x49, 0x87, 0xa6, + 0xb7, 0xe3, 0x15, 0x75, 0x56, 0x64, 0x3a, 0xdd, 0x9f, 0x16, 0x3c, 0x1d, 0xcc, 0xa3, 0x70, 0x8e, + 0xc3, 0x94, 0x6e, 0x7c, 0x0a, 0x38, 0x2e, 0x58, 0x0b, 0xaa, 0x03, 0x89, 0x4a, 0x24, 0x61, 0x3c, + 0xef, 0xf7, 0x6c, 0xab, 0x65, 0xb5, 0x8f, 0x78, 0xb1, 0xc4, 0xde, 0xc1, 0xe1, 0x8c, 0x82, 0x9e, + 0x48, 0x84, 0xfd, 0xa8, 0x65, 0xb5, 0xab, 0x5d, 0xc7, 0x23, 0x54, 0x4b, 0x54, 0x63, 0x21, 0xc3, + 0xb1, 0x14, 0x4a, 0xcc, 0xc8, 0xf3, 0x4d, 0x07, 0x5f, 0xb7, 0x32, 0x17, 0x6a, 0x32, 0xa5, 0x9b, + 0xcf, 0xf1, 0x17, 0x42, 0xd5, 0xef, 0xd9, 0x15, 0x4d, 0x5c, 0xaa, 0xb9, 0x1f, 0xa0, 0xb1, 0xa5, + 0x87, 0x24, 0x7b, 0x05, 0x7b, 0x0a, 0x49, 0xda, 0x56, 0xab, 0xd2, 0xae, 0x76, 0x4f, 0x3d, 0xe3, + 0x75, 0x14, 0xce, 0x83, 0x08, 0x7d, 0x0a, 0xcc, 0x30, 0xd7, 0x3d, 0xee, 0x02, 0x8e, 0xb7, 0x0e, + 0x58, 0x13, 0x80, 0x23, 0xa5, 0x51, 0x72, 0x11, 0x4f, 0x51, 0xdb, 0xa9, 0xf0, 0x42, 0x85, 0x9d, + 0xc2, 0x01, 0xc7, 0xc9, 0xb2, 0xdf, 0xd3, 0x66, 0x8e, 0x78, 0x8e, 0xd8, 0x4b, 0x78, 0x92, 0xfd, + 0x1b, 0x46, 0x22, 0xb9, 0x8c, 0xd5, 0x2c, 0x57, 0xbc, 0xcf, 0xb7, 0xaa, 0xee, 0x0a, 0xce, 0x3e, + 0x62, 0x92, 0xad, 0x22, 0xa3, 0x7d, 0x94, 0x88, 0x24, 0xa5, 0x2c, 0xca, 0x26, 0x40, 0xaa, 0x8d, + 0x7d, 0x0a, 0x29, 0xd1, 0xfa, 0x8f, 0x78, 0xa1, 0x92, 0x45, 0x1d, 0x17, 0xa2, 0x36, 0xfb, 0x8b, + 0x25, 0xe6, 0xc0, 0xe3, 0x58, 0x96, 0x02, 0xdb, 0x60, 0xf7, 0xf7, 0x1e, 0xd8, 0xbb, 0x37, 0x93, + 0x64, 0x36, 0x1c, 0xa2, 0x52, 0x1b, 0xcb, 0xfb, 0x7c, 0x0d, 0x33, 0xbf, 0xa8, 0x94, 0x4f, 0xc1, + 0xda, 0xaf, 0x41, 0x6c, 0x04, 0x75, 0x4a, 0x27, 0x13, 0x24, 0x32, 0xe1, 0xd8, 0x15, 0x9d, 0xf7, + 0x9b, 0x3c, 0xef, 0xbb, 0x36, 0x79, 0xa3, 0xe2, 0x10, 0x2f, 0x73, 0xb0, 0x21, 0xd4, 0xae, 0x45, + 0x18, 0xe1, 0x34, 0xe7, 0xdc, 0xd3, 0x9c, 0xaf, 0xef, 0xe3, 0xbc, 0xd4, 0x33, 0x3d, 0x4c, 0x44, + 0x18, 0xf1, 0x12, 0x83, 0x73, 0x01, 0xf5, 0x7c, 0xa3, 0x39, 0xce, 0x22, 0x92, 0x91, 0x48, 0xae, + 0x63, 0x35, 0xcb, 0x5f, 0xd6, 0x0d, 0xce, 0xbc, 0x92, 0x66, 0x5d, 0x7b, 0x35, 0xc8, 0xf9, 0x06, + 0xb5, 0xe2, 0x8a, 0xac, 0x2f, 0x2d, 0x86, 0x9c, 0xa3, 0x87, 0xa7, 0xe8, 0xfc, 0xb2, 0x36, 0xfa, + 0xf2, 0x08, 0xfe, 0x71, 0x5b, 0x25, 0xee, 0x3b, 0xb4, 0x31, 0x01, 0x27, 0x53, 0xad, 0x6a, 0x98, + 0xbb, 0x30, 0xb9, 0x3c, 0xf0, 0x71, 0xe4, 0xd9, 0xed, 0xa4, 0xea, 0xfe, 0xb1, 0xe0, 0x99, 0x19, + 0xf4, 0x91, 0x48, 0x04, 0xc8, 0x33, 0xce, 0x11, 0xaa, 0x65, 0x38, 0x41, 0x76, 0x0e, 0xf5, 0xd2, + 0x47, 0xc8, 0xce, 0xf2, 0x9d, 0xdb, 0x57, 0x85, 0x63, 0xef, 0x3e, 0x20, 0xc9, 0xbe, 0xc2, 0xc9, + 0x2e, 0x85, 0xac, 0xf9, 0x5f, 0xf9, 0x0b, 0xe7, 0xf9, 0x3d, 0xf6, 0xce, 0x1b, 0xdf, 0x8f, 0x3d, + 0x73, 0xdb, 0xbd, 0x97, 0x57, 0x5a, 0xf6, 0xd5, 0x81, 0xbe, 0xcc, 0xde, 0xfe, 0x0d, 0x00, 0x00, + 0xff, 0xff, 0x8e, 0xdc, 0xcc, 0x70, 0x0b, 0x05, 0x00, 0x00, +} diff --git a/pkg/proto/relay/relay.proto b/pkg/proto/relay/relay.proto new file mode 100644 index 000000000..d8c5f1b7e --- /dev/null +++ b/pkg/proto/relay/relay.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./relay;pbRelay"; +package relay; + +message OnlinePushMsgReq { + string OperationID = 1; + server_api_params.MsgData msgData = 2; + string pushToUserID = 3; +} +message OnlinePushMsgResp{ +repeated SingleMsgToUser resp = 1; +}//message SendMsgByWSReq{ +// string SendID = 1; +// string RecvID = 2; +// string Content = 3; +// int64 SendTime = 4; +// int64 MsgFrom = 5; +// int64 ContentType = 6; +// int64 SessionType = 7; +// string OperationID = 8; +// int64 PlatformID = 9; +//} + +message SingleMsgToUser{ + int64 ResultCode = 1; + string RecvID = 2; + int32 RecvPlatFormID = 3; +} +message GetUsersOnlineStatusReq{ + repeated string userIDList = 1; + string operationID = 2; + string opUserID = 3; +} +message GetUsersOnlineStatusResp{ + int32 errCode = 1; + string errMsg = 2; + repeated SuccessResult successResult = 3; + repeated FailedDetail failedResult = 4; + message SuccessDetail{ + string platform = 1; + string status = 2; + } + message FailedDetail{ + string userID = 3; + int32 errCode = 1; + string errMsg = 2; + } + message SuccessResult{ + string userID = 1; + string status = 2; + repeated SuccessDetail detailPlatformStatus = 3; + + } +} +service OnlineMessageRelayService { + rpc OnlinePushMsg(OnlinePushMsgReq) returns(OnlinePushMsgResp); + rpc GetUsersOnlineStatus(GetUsersOnlineStatusReq)returns(GetUsersOnlineStatusResp); +// rpc SendMsgByWS(SendMsgByWSReq) returns(MsgToUserResp); +} + diff --git a/pkg/proto/rtc/rtc.pb.go b/pkg/proto/rtc/rtc.pb.go new file mode 100644 index 000000000..a546f0f12 --- /dev/null +++ b/pkg/proto/rtc/rtc.pb.go @@ -0,0 +1,2990 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.5 +// source: proto/rtc.proto + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CommonResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ErrCode int32 `protobuf:"varint,1,opt,name=errCode,proto3" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg,proto3" json:"errMsg,omitempty"` +} + +func (x *CommonResp) Reset() { + *x = CommonResp{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommonResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommonResp) ProtoMessage() {} + +func (x *CommonResp) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommonResp.ProtoReflect.Descriptor instead. +func (*CommonResp) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{0} +} + +func (x *CommonResp) GetErrCode() int32 { + if x != nil { + return x.ErrCode + } + return 0 +} + +func (x *CommonResp) GetErrMsg() string { + if x != nil { + return x.ErrMsg + } + return "" +} + +type MsgData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SendID string `protobuf:"bytes,1,opt,name=sendID,proto3" json:"sendID,omitempty"` + RecvID string `protobuf:"bytes,2,opt,name=recvID,proto3" json:"recvID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID,proto3" json:"groupID,omitempty"` + ClientMsgID string `protobuf:"bytes,4,opt,name=clientMsgID,proto3" json:"clientMsgID,omitempty"` + ServerMsgID string `protobuf:"bytes,5,opt,name=serverMsgID,proto3" json:"serverMsgID,omitempty"` + SenderPlatformID int32 `protobuf:"varint,6,opt,name=senderPlatformID,proto3" json:"senderPlatformID,omitempty"` + SenderNickname string `protobuf:"bytes,7,opt,name=senderNickname,proto3" json:"senderNickname,omitempty"` + SenderFaceURL string `protobuf:"bytes,8,opt,name=senderFaceURL,proto3" json:"senderFaceURL,omitempty"` + SessionType int32 `protobuf:"varint,9,opt,name=sessionType,proto3" json:"sessionType,omitempty"` + MsgFrom int32 `protobuf:"varint,10,opt,name=msgFrom,proto3" json:"msgFrom,omitempty"` + ContentType int32 `protobuf:"varint,11,opt,name=contentType,proto3" json:"contentType,omitempty"` + Content []byte `protobuf:"bytes,12,opt,name=content,proto3" json:"content,omitempty"` + Seq uint32 `protobuf:"varint,14,opt,name=seq,proto3" json:"seq,omitempty"` + SendTime int64 `protobuf:"varint,15,opt,name=sendTime,proto3" json:"sendTime,omitempty"` + CreateTime int64 `protobuf:"varint,16,opt,name=createTime,proto3" json:"createTime,omitempty"` + Status int32 `protobuf:"varint,17,opt,name=status,proto3" json:"status,omitempty"` + Options map[string]bool `protobuf:"bytes,18,rep,name=options,proto3" json:"options,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,19,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` +} + +func (x *MsgData) Reset() { + *x = MsgData{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgData) ProtoMessage() {} + +func (x *MsgData) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MsgData.ProtoReflect.Descriptor instead. +func (*MsgData) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{1} +} + +func (x *MsgData) GetSendID() string { + if x != nil { + return x.SendID + } + return "" +} + +func (x *MsgData) GetRecvID() string { + if x != nil { + return x.RecvID + } + return "" +} + +func (x *MsgData) GetGroupID() string { + if x != nil { + return x.GroupID + } + return "" +} + +func (x *MsgData) GetClientMsgID() string { + if x != nil { + return x.ClientMsgID + } + return "" +} + +func (x *MsgData) GetServerMsgID() string { + if x != nil { + return x.ServerMsgID + } + return "" +} + +func (x *MsgData) GetSenderPlatformID() int32 { + if x != nil { + return x.SenderPlatformID + } + return 0 +} + +func (x *MsgData) GetSenderNickname() string { + if x != nil { + return x.SenderNickname + } + return "" +} + +func (x *MsgData) GetSenderFaceURL() string { + if x != nil { + return x.SenderFaceURL + } + return "" +} + +func (x *MsgData) GetSessionType() int32 { + if x != nil { + return x.SessionType + } + return 0 +} + +func (x *MsgData) GetMsgFrom() int32 { + if x != nil { + return x.MsgFrom + } + return 0 +} + +func (x *MsgData) GetContentType() int32 { + if x != nil { + return x.ContentType + } + return 0 +} + +func (x *MsgData) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +func (x *MsgData) GetSeq() uint32 { + if x != nil { + return x.Seq + } + return 0 +} + +func (x *MsgData) GetSendTime() int64 { + if x != nil { + return x.SendTime + } + return 0 +} + +func (x *MsgData) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *MsgData) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *MsgData) GetOptions() map[string]bool { + if x != nil { + return x.Options + } + return nil +} + +func (x *MsgData) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +type GroupInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupID string `protobuf:"bytes,1,opt,name=groupID,proto3" json:"groupID,omitempty"` + GroupName string `protobuf:"bytes,2,opt,name=groupName,proto3" json:"groupName,omitempty"` + Notification string `protobuf:"bytes,3,opt,name=notification,proto3" json:"notification,omitempty"` + Introduction string `protobuf:"bytes,4,opt,name=introduction,proto3" json:"introduction,omitempty"` + FaceURL string `protobuf:"bytes,5,opt,name=faceURL,proto3" json:"faceURL,omitempty"` + OwnerUserID string `protobuf:"bytes,6,opt,name=ownerUserID,proto3" json:"ownerUserID,omitempty"` + CreateTime uint32 `protobuf:"varint,7,opt,name=createTime,proto3" json:"createTime,omitempty"` + MemberCount uint32 `protobuf:"varint,8,opt,name=memberCount,proto3" json:"memberCount,omitempty"` + Ex string `protobuf:"bytes,9,opt,name=ex,proto3" json:"ex,omitempty"` + Status int32 `protobuf:"varint,10,opt,name=status,proto3" json:"status,omitempty"` + CreatorUserID string `protobuf:"bytes,11,opt,name=creatorUserID,proto3" json:"creatorUserID,omitempty"` + GroupType int32 `protobuf:"varint,12,opt,name=groupType,proto3" json:"groupType,omitempty"` +} + +func (x *GroupInfo) Reset() { + *x = GroupInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInfo) ProtoMessage() {} + +func (x *GroupInfo) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupInfo.ProtoReflect.Descriptor instead. +func (*GroupInfo) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{2} +} + +func (x *GroupInfo) GetGroupID() string { + if x != nil { + return x.GroupID + } + return "" +} + +func (x *GroupInfo) GetGroupName() string { + if x != nil { + return x.GroupName + } + return "" +} + +func (x *GroupInfo) GetNotification() string { + if x != nil { + return x.Notification + } + return "" +} + +func (x *GroupInfo) GetIntroduction() string { + if x != nil { + return x.Introduction + } + return "" +} + +func (x *GroupInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *GroupInfo) GetOwnerUserID() string { + if x != nil { + return x.OwnerUserID + } + return "" +} + +func (x *GroupInfo) GetCreateTime() uint32 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *GroupInfo) GetMemberCount() uint32 { + if x != nil { + return x.MemberCount + } + return 0 +} + +func (x *GroupInfo) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +func (x *GroupInfo) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *GroupInfo) GetCreatorUserID() string { + if x != nil { + return x.CreatorUserID + } + return "" +} + +func (x *GroupInfo) GetGroupType() int32 { + if x != nil { + return x.GroupType + } + return 0 +} + +type GroupMemberFullInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupID string `protobuf:"bytes,1,opt,name=groupID,proto3" json:"groupID,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID,proto3" json:"userID,omitempty"` + RoleLevel int32 `protobuf:"varint,3,opt,name=roleLevel,proto3" json:"roleLevel,omitempty"` + JoinTime int32 `protobuf:"varint,4,opt,name=joinTime,proto3" json:"joinTime,omitempty"` + Nickname string `protobuf:"bytes,5,opt,name=nickname,proto3" json:"nickname,omitempty"` + FaceURL string `protobuf:"bytes,6,opt,name=faceURL,proto3" json:"faceURL,omitempty"` + AppMangerLevel int32 `protobuf:"varint,7,opt,name=appMangerLevel,proto3" json:"appMangerLevel,omitempty"` //if >0 + JoinSource int32 `protobuf:"varint,8,opt,name=joinSource,proto3" json:"joinSource,omitempty"` + OperatorUserID string `protobuf:"bytes,9,opt,name=operatorUserID,proto3" json:"operatorUserID,omitempty"` + Ex string `protobuf:"bytes,10,opt,name=ex,proto3" json:"ex,omitempty"` +} + +func (x *GroupMemberFullInfo) Reset() { + *x = GroupMemberFullInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupMemberFullInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberFullInfo) ProtoMessage() {} + +func (x *GroupMemberFullInfo) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupMemberFullInfo.ProtoReflect.Descriptor instead. +func (*GroupMemberFullInfo) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{3} +} + +func (x *GroupMemberFullInfo) GetGroupID() string { + if x != nil { + return x.GroupID + } + return "" +} + +func (x *GroupMemberFullInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *GroupMemberFullInfo) GetRoleLevel() int32 { + if x != nil { + return x.RoleLevel + } + return 0 +} + +func (x *GroupMemberFullInfo) GetJoinTime() int32 { + if x != nil { + return x.JoinTime + } + return 0 +} + +func (x *GroupMemberFullInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *GroupMemberFullInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *GroupMemberFullInfo) GetAppMangerLevel() int32 { + if x != nil { + return x.AppMangerLevel + } + return 0 +} + +func (x *GroupMemberFullInfo) GetJoinSource() int32 { + if x != nil { + return x.JoinSource + } + return 0 +} + +func (x *GroupMemberFullInfo) GetOperatorUserID() string { + if x != nil { + return x.OperatorUserID + } + return "" +} + +func (x *GroupMemberFullInfo) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +type ParticipantMetaData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupInfo *GroupInfo `protobuf:"bytes,1,opt,name=groupInfo,proto3" json:"groupInfo,omitempty"` + GroupMemberInfo *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=groupMemberInfo,proto3" json:"groupMemberInfo,omitempty"` + UserInfo *PublicUserInfo `protobuf:"bytes,3,opt,name=userInfo,proto3" json:"userInfo,omitempty"` +} + +func (x *ParticipantMetaData) Reset() { + *x = ParticipantMetaData{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ParticipantMetaData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParticipantMetaData) ProtoMessage() {} + +func (x *ParticipantMetaData) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParticipantMetaData.ProtoReflect.Descriptor instead. +func (*ParticipantMetaData) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{4} +} + +func (x *ParticipantMetaData) GetGroupInfo() *GroupInfo { + if x != nil { + return x.GroupInfo + } + return nil +} + +func (x *ParticipantMetaData) GetGroupMemberInfo() *GroupMemberFullInfo { + if x != nil { + return x.GroupMemberInfo + } + return nil +} + +func (x *ParticipantMetaData) GetUserInfo() *PublicUserInfo { + if x != nil { + return x.UserInfo + } + return nil +} + +type PublicUserInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL,omitempty"` + Gender int32 `protobuf:"varint,4,opt,name=gender,proto3" json:"gender,omitempty"` + Ex string `protobuf:"bytes,5,opt,name=ex,proto3" json:"ex,omitempty"` +} + +func (x *PublicUserInfo) Reset() { + *x = PublicUserInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PublicUserInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PublicUserInfo) ProtoMessage() {} + +func (x *PublicUserInfo) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PublicUserInfo.ProtoReflect.Descriptor instead. +func (*PublicUserInfo) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{5} +} + +func (x *PublicUserInfo) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *PublicUserInfo) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *PublicUserInfo) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *PublicUserInfo) GetGender() int32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *PublicUserInfo) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +type GetJoinTokenReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Room string `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` + Identity string `protobuf:"bytes,2,opt,name=identity,proto3" json:"identity,omitempty"` + MetaData *ParticipantMetaData `protobuf:"bytes,3,opt,name=metaData,proto3" json:"metaData,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=operationID,proto3" json:"operationID,omitempty"` +} + +func (x *GetJoinTokenReq) Reset() { + *x = GetJoinTokenReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetJoinTokenReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetJoinTokenReq) ProtoMessage() {} + +func (x *GetJoinTokenReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetJoinTokenReq.ProtoReflect.Descriptor instead. +func (*GetJoinTokenReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{6} +} + +func (x *GetJoinTokenReq) GetRoom() string { + if x != nil { + return x.Room + } + return "" +} + +func (x *GetJoinTokenReq) GetIdentity() string { + if x != nil { + return x.Identity + } + return "" +} + +func (x *GetJoinTokenReq) GetMetaData() *ParticipantMetaData { + if x != nil { + return x.MetaData + } + return nil +} + +func (x *GetJoinTokenReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type GetJoinTokenResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp,proto3" json:"CommonResp,omitempty"` + Jwt string `protobuf:"bytes,2,opt,name=jwt,proto3" json:"jwt,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL,proto3" json:"liveURL,omitempty"` +} + +func (x *GetJoinTokenResp) Reset() { + *x = GetJoinTokenResp{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetJoinTokenResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetJoinTokenResp) ProtoMessage() {} + +func (x *GetJoinTokenResp) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetJoinTokenResp.ProtoReflect.Descriptor instead. +func (*GetJoinTokenResp) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{7} +} + +func (x *GetJoinTokenResp) GetCommonResp() *CommonResp { + if x != nil { + return x.CommonResp + } + return nil +} + +func (x *GetJoinTokenResp) GetJwt() string { + if x != nil { + return x.Jwt + } + return "" +} + +func (x *GetJoinTokenResp) GetLiveURL() string { + if x != nil { + return x.LiveURL + } + return "" +} + +type OfflinePushInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Ex string `protobuf:"bytes,3,opt,name=ex,proto3" json:"ex,omitempty"` + IOSPushSound string `protobuf:"bytes,4,opt,name=iOSPushSound,proto3" json:"iOSPushSound,omitempty"` + IOSBadgeCount bool `protobuf:"varint,5,opt,name=iOSBadgeCount,proto3" json:"iOSBadgeCount,omitempty"` +} + +func (x *OfflinePushInfo) Reset() { + *x = OfflinePushInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OfflinePushInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OfflinePushInfo) ProtoMessage() {} + +func (x *OfflinePushInfo) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OfflinePushInfo.ProtoReflect.Descriptor instead. +func (*OfflinePushInfo) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{8} +} + +func (x *OfflinePushInfo) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *OfflinePushInfo) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *OfflinePushInfo) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +func (x *OfflinePushInfo) GetIOSPushSound() string { + if x != nil { + return x.IOSPushSound + } + return "" +} + +func (x *OfflinePushInfo) GetIOSBadgeCount() bool { + if x != nil { + return x.IOSBadgeCount + } + return false +} + +type SignalReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Payload: + // *SignalReq_Invite + // *SignalReq_InviteInGroup + // *SignalReq_Cancel + // *SignalReq_Accept + // *SignalReq_HungUp + // *SignalReq_Reject + Payload isSignalReq_Payload `protobuf_oneof:"payload"` +} + +func (x *SignalReq) Reset() { + *x = SignalReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalReq) ProtoMessage() {} + +func (x *SignalReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalReq.ProtoReflect.Descriptor instead. +func (*SignalReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{9} +} + +func (m *SignalReq) GetPayload() isSignalReq_Payload { + if m != nil { + return m.Payload + } + return nil +} + +func (x *SignalReq) GetInvite() *SignalInviteReq { + if x, ok := x.GetPayload().(*SignalReq_Invite); ok { + return x.Invite + } + return nil +} + +func (x *SignalReq) GetInviteInGroup() *SignalInviteInGroupReq { + if x, ok := x.GetPayload().(*SignalReq_InviteInGroup); ok { + return x.InviteInGroup + } + return nil +} + +func (x *SignalReq) GetCancel() *SignalCancelReq { + if x, ok := x.GetPayload().(*SignalReq_Cancel); ok { + return x.Cancel + } + return nil +} + +func (x *SignalReq) GetAccept() *SignalAcceptReq { + if x, ok := x.GetPayload().(*SignalReq_Accept); ok { + return x.Accept + } + return nil +} + +func (x *SignalReq) GetHungUp() *SignalHungUpReq { + if x, ok := x.GetPayload().(*SignalReq_HungUp); ok { + return x.HungUp + } + return nil +} + +func (x *SignalReq) GetReject() *SignalRejectReq { + if x, ok := x.GetPayload().(*SignalReq_Reject); ok { + return x.Reject + } + return nil +} + +type isSignalReq_Payload interface { + isSignalReq_Payload() +} + +type SignalReq_Invite struct { + Invite *SignalInviteReq `protobuf:"bytes,1,opt,name=invite,proto3,oneof"` +} + +type SignalReq_InviteInGroup struct { + InviteInGroup *SignalInviteInGroupReq `protobuf:"bytes,2,opt,name=inviteInGroup,proto3,oneof"` +} + +type SignalReq_Cancel struct { + Cancel *SignalCancelReq `protobuf:"bytes,3,opt,name=cancel,proto3,oneof"` +} + +type SignalReq_Accept struct { + Accept *SignalAcceptReq `protobuf:"bytes,4,opt,name=accept,proto3,oneof"` +} + +type SignalReq_HungUp struct { + HungUp *SignalHungUpReq `protobuf:"bytes,5,opt,name=hungUp,proto3,oneof"` +} + +type SignalReq_Reject struct { + Reject *SignalRejectReq `protobuf:"bytes,6,opt,name=reject,proto3,oneof"` +} + +func (*SignalReq_Invite) isSignalReq_Payload() {} + +func (*SignalReq_InviteInGroup) isSignalReq_Payload() {} + +func (*SignalReq_Cancel) isSignalReq_Payload() {} + +func (*SignalReq_Accept) isSignalReq_Payload() {} + +func (*SignalReq_HungUp) isSignalReq_Payload() {} + +func (*SignalReq_Reject) isSignalReq_Payload() {} + +type SignalResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Payload: + // *SignalResp_Invite + // *SignalResp_InviteInGroup + // *SignalResp_Cancel + // *SignalResp_Accept + // *SignalResp_HungUp + // *SignalResp_Reject + Payload isSignalResp_Payload `protobuf_oneof:"payload"` +} + +func (x *SignalResp) Reset() { + *x = SignalResp{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalResp) ProtoMessage() {} + +func (x *SignalResp) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalResp.ProtoReflect.Descriptor instead. +func (*SignalResp) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{10} +} + +func (m *SignalResp) GetPayload() isSignalResp_Payload { + if m != nil { + return m.Payload + } + return nil +} + +func (x *SignalResp) GetInvite() *SignalInviteReply { + if x, ok := x.GetPayload().(*SignalResp_Invite); ok { + return x.Invite + } + return nil +} + +func (x *SignalResp) GetInviteInGroup() *SignalInviteInGroupReply { + if x, ok := x.GetPayload().(*SignalResp_InviteInGroup); ok { + return x.InviteInGroup + } + return nil +} + +func (x *SignalResp) GetCancel() *SignalCancelReply { + if x, ok := x.GetPayload().(*SignalResp_Cancel); ok { + return x.Cancel + } + return nil +} + +func (x *SignalResp) GetAccept() *SignalAcceptReply { + if x, ok := x.GetPayload().(*SignalResp_Accept); ok { + return x.Accept + } + return nil +} + +func (x *SignalResp) GetHungUp() *SignalHungUpReply { + if x, ok := x.GetPayload().(*SignalResp_HungUp); ok { + return x.HungUp + } + return nil +} + +func (x *SignalResp) GetReject() *SignalRejectReply { + if x, ok := x.GetPayload().(*SignalResp_Reject); ok { + return x.Reject + } + return nil +} + +type isSignalResp_Payload interface { + isSignalResp_Payload() +} + +type SignalResp_Invite struct { + Invite *SignalInviteReply `protobuf:"bytes,1,opt,name=invite,proto3,oneof"` +} + +type SignalResp_InviteInGroup struct { + InviteInGroup *SignalInviteInGroupReply `protobuf:"bytes,2,opt,name=inviteInGroup,proto3,oneof"` +} + +type SignalResp_Cancel struct { + Cancel *SignalCancelReply `protobuf:"bytes,3,opt,name=cancel,proto3,oneof"` +} + +type SignalResp_Accept struct { + Accept *SignalAcceptReply `protobuf:"bytes,4,opt,name=accept,proto3,oneof"` +} + +type SignalResp_HungUp struct { + HungUp *SignalHungUpReply `protobuf:"bytes,5,opt,name=hungUp,proto3,oneof"` +} + +type SignalResp_Reject struct { + Reject *SignalRejectReply `protobuf:"bytes,6,opt,name=reject,proto3,oneof"` +} + +func (*SignalResp_Invite) isSignalResp_Payload() {} + +func (*SignalResp_InviteInGroup) isSignalResp_Payload() {} + +func (*SignalResp_Cancel) isSignalResp_Payload() {} + +func (*SignalResp_Accept) isSignalResp_Payload() {} + +func (*SignalResp_HungUp) isSignalResp_Payload() {} + +func (*SignalResp_Reject) isSignalResp_Payload() {} + +type InvitationInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + InviterUserID string `protobuf:"bytes,1,opt,name=inviterUserID,proto3" json:"inviterUserID,omitempty"` + InviteeUserIDList []string `protobuf:"bytes,2,rep,name=inviteeUserIDList,proto3" json:"inviteeUserIDList,omitempty"` + CustomData string `protobuf:"bytes,3,opt,name=customData,proto3" json:"customData,omitempty"` + GroupID string `protobuf:"bytes,4,opt,name=groupID,proto3" json:"groupID,omitempty"` + RoomID string `protobuf:"bytes,5,opt,name=roomID,proto3" json:"roomID,omitempty"` + Timeout int32 `protobuf:"varint,6,opt,name=timeout,proto3" json:"timeout,omitempty"` + MediaType string `protobuf:"bytes,7,opt,name=mediaType,proto3" json:"mediaType,omitempty"` + PlatformID int32 `protobuf:"varint,8,opt,name=platformID,proto3" json:"platformID,omitempty"` + SessionType int32 `protobuf:"varint,9,opt,name=sessionType,proto3" json:"sessionType,omitempty"` +} + +func (x *InvitationInfo) Reset() { + *x = InvitationInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvitationInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvitationInfo) ProtoMessage() {} + +func (x *InvitationInfo) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvitationInfo.ProtoReflect.Descriptor instead. +func (*InvitationInfo) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{11} +} + +func (x *InvitationInfo) GetInviterUserID() string { + if x != nil { + return x.InviterUserID + } + return "" +} + +func (x *InvitationInfo) GetInviteeUserIDList() []string { + if x != nil { + return x.InviteeUserIDList + } + return nil +} + +func (x *InvitationInfo) GetCustomData() string { + if x != nil { + return x.CustomData + } + return "" +} + +func (x *InvitationInfo) GetGroupID() string { + if x != nil { + return x.GroupID + } + return "" +} + +func (x *InvitationInfo) GetRoomID() string { + if x != nil { + return x.RoomID + } + return "" +} + +func (x *InvitationInfo) GetTimeout() int32 { + if x != nil { + return x.Timeout + } + return 0 +} + +func (x *InvitationInfo) GetMediaType() string { + if x != nil { + return x.MediaType + } + return "" +} + +func (x *InvitationInfo) GetPlatformID() int32 { + if x != nil { + return x.PlatformID + } + return 0 +} + +func (x *InvitationInfo) GetSessionType() int32 { + if x != nil { + return x.SessionType + } + return 0 +} + +type SignalInviteReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpUserID string `protobuf:"bytes,1,opt,name=opUserID,proto3" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation,proto3" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant,proto3" json:"participant,omitempty"` +} + +func (x *SignalInviteReq) Reset() { + *x = SignalInviteReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalInviteReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalInviteReq) ProtoMessage() {} + +func (x *SignalInviteReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalInviteReq.ProtoReflect.Descriptor instead. +func (*SignalInviteReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{12} +} + +func (x *SignalInviteReq) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *SignalInviteReq) GetInvitation() *InvitationInfo { + if x != nil { + return x.Invitation + } + return nil +} + +func (x *SignalInviteReq) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +func (x *SignalInviteReq) GetParticipant() *ParticipantMetaData { + if x != nil { + return x.Participant + } + return nil +} + +type SignalInviteReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + RoomID string `protobuf:"bytes,2,opt,name=roomID,proto3" json:"roomID,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL,proto3" json:"liveURL,omitempty"` +} + +func (x *SignalInviteReply) Reset() { + *x = SignalInviteReply{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalInviteReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalInviteReply) ProtoMessage() {} + +func (x *SignalInviteReply) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalInviteReply.ProtoReflect.Descriptor instead. +func (*SignalInviteReply) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{13} +} + +func (x *SignalInviteReply) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *SignalInviteReply) GetRoomID() string { + if x != nil { + return x.RoomID + } + return "" +} + +func (x *SignalInviteReply) GetLiveURL() string { + if x != nil { + return x.LiveURL + } + return "" +} + +type SignalInviteInGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpUserID string `protobuf:"bytes,1,opt,name=opUserID,proto3" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation,proto3" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant,proto3" json:"participant,omitempty"` +} + +func (x *SignalInviteInGroupReq) Reset() { + *x = SignalInviteInGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalInviteInGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalInviteInGroupReq) ProtoMessage() {} + +func (x *SignalInviteInGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalInviteInGroupReq.ProtoReflect.Descriptor instead. +func (*SignalInviteInGroupReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{14} +} + +func (x *SignalInviteInGroupReq) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *SignalInviteInGroupReq) GetInvitation() *InvitationInfo { + if x != nil { + return x.Invitation + } + return nil +} + +func (x *SignalInviteInGroupReq) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +func (x *SignalInviteInGroupReq) GetParticipant() *ParticipantMetaData { + if x != nil { + return x.Participant + } + return nil +} + +type SignalInviteInGroupReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + RoomID string `protobuf:"bytes,2,opt,name=roomID,proto3" json:"roomID,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL,proto3" json:"liveURL,omitempty"` +} + +func (x *SignalInviteInGroupReply) Reset() { + *x = SignalInviteInGroupReply{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalInviteInGroupReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalInviteInGroupReply) ProtoMessage() {} + +func (x *SignalInviteInGroupReply) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalInviteInGroupReply.ProtoReflect.Descriptor instead. +func (*SignalInviteInGroupReply) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{15} +} + +func (x *SignalInviteInGroupReply) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *SignalInviteInGroupReply) GetRoomID() string { + if x != nil { + return x.RoomID + } + return "" +} + +func (x *SignalInviteInGroupReply) GetLiveURL() string { + if x != nil { + return x.LiveURL + } + return "" +} + +type SignalCancelReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpUserID string `protobuf:"bytes,1,opt,name=opUserID,proto3" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation,proto3" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant,proto3" json:"participant,omitempty"` +} + +func (x *SignalCancelReq) Reset() { + *x = SignalCancelReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalCancelReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalCancelReq) ProtoMessage() {} + +func (x *SignalCancelReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalCancelReq.ProtoReflect.Descriptor instead. +func (*SignalCancelReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{16} +} + +func (x *SignalCancelReq) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *SignalCancelReq) GetInvitation() *InvitationInfo { + if x != nil { + return x.Invitation + } + return nil +} + +func (x *SignalCancelReq) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +func (x *SignalCancelReq) GetParticipant() *ParticipantMetaData { + if x != nil { + return x.Participant + } + return nil +} + +type SignalCancelReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SignalCancelReply) Reset() { + *x = SignalCancelReply{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalCancelReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalCancelReply) ProtoMessage() {} + +func (x *SignalCancelReply) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalCancelReply.ProtoReflect.Descriptor instead. +func (*SignalCancelReply) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{17} +} + +type SignalAcceptReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpUserID string `protobuf:"bytes,1,opt,name=opUserID,proto3" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation,proto3" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant,proto3" json:"participant,omitempty"` + OpUserPlatformID int32 `protobuf:"varint,5,opt,name=opUserPlatformID,proto3" json:"opUserPlatformID,omitempty"` +} + +func (x *SignalAcceptReq) Reset() { + *x = SignalAcceptReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalAcceptReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalAcceptReq) ProtoMessage() {} + +func (x *SignalAcceptReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalAcceptReq.ProtoReflect.Descriptor instead. +func (*SignalAcceptReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{18} +} + +func (x *SignalAcceptReq) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *SignalAcceptReq) GetInvitation() *InvitationInfo { + if x != nil { + return x.Invitation + } + return nil +} + +func (x *SignalAcceptReq) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +func (x *SignalAcceptReq) GetParticipant() *ParticipantMetaData { + if x != nil { + return x.Participant + } + return nil +} + +func (x *SignalAcceptReq) GetOpUserPlatformID() int32 { + if x != nil { + return x.OpUserPlatformID + } + return 0 +} + +type SignalAcceptReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + RoomID string `protobuf:"bytes,2,opt,name=roomID,proto3" json:"roomID,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL,proto3" json:"liveURL,omitempty"` +} + +func (x *SignalAcceptReply) Reset() { + *x = SignalAcceptReply{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalAcceptReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalAcceptReply) ProtoMessage() {} + +func (x *SignalAcceptReply) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalAcceptReply.ProtoReflect.Descriptor instead. +func (*SignalAcceptReply) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{19} +} + +func (x *SignalAcceptReply) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *SignalAcceptReply) GetRoomID() string { + if x != nil { + return x.RoomID + } + return "" +} + +func (x *SignalAcceptReply) GetLiveURL() string { + if x != nil { + return x.LiveURL + } + return "" +} + +type SignalHungUpReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpUserID string `protobuf:"bytes,1,opt,name=opUserID,proto3" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation,proto3" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` +} + +func (x *SignalHungUpReq) Reset() { + *x = SignalHungUpReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalHungUpReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalHungUpReq) ProtoMessage() {} + +func (x *SignalHungUpReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalHungUpReq.ProtoReflect.Descriptor instead. +func (*SignalHungUpReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{20} +} + +func (x *SignalHungUpReq) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *SignalHungUpReq) GetInvitation() *InvitationInfo { + if x != nil { + return x.Invitation + } + return nil +} + +func (x *SignalHungUpReq) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +type SignalHungUpReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SignalHungUpReply) Reset() { + *x = SignalHungUpReply{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalHungUpReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalHungUpReply) ProtoMessage() {} + +func (x *SignalHungUpReply) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalHungUpReply.ProtoReflect.Descriptor instead. +func (*SignalHungUpReply) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{21} +} + +type SignalRejectReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpUserID string `protobuf:"bytes,1,opt,name=opUserID,proto3" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation,proto3" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo,proto3" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant,proto3" json:"participant,omitempty"` + OpUserPlatformID int32 `protobuf:"varint,5,opt,name=opUserPlatformID,proto3" json:"opUserPlatformID,omitempty"` +} + +func (x *SignalRejectReq) Reset() { + *x = SignalRejectReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalRejectReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalRejectReq) ProtoMessage() {} + +func (x *SignalRejectReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalRejectReq.ProtoReflect.Descriptor instead. +func (*SignalRejectReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{22} +} + +func (x *SignalRejectReq) GetOpUserID() string { + if x != nil { + return x.OpUserID + } + return "" +} + +func (x *SignalRejectReq) GetInvitation() *InvitationInfo { + if x != nil { + return x.Invitation + } + return nil +} + +func (x *SignalRejectReq) GetOfflinePushInfo() *OfflinePushInfo { + if x != nil { + return x.OfflinePushInfo + } + return nil +} + +func (x *SignalRejectReq) GetParticipant() *ParticipantMetaData { + if x != nil { + return x.Participant + } + return nil +} + +func (x *SignalRejectReq) GetOpUserPlatformID() int32 { + if x != nil { + return x.OpUserPlatformID + } + return 0 +} + +type SignalRejectReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SignalRejectReply) Reset() { + *x = SignalRejectReply{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalRejectReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalRejectReply) ProtoMessage() {} + +func (x *SignalRejectReply) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalRejectReply.ProtoReflect.Descriptor instead. +func (*SignalRejectReply) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{23} +} + +type SignalMessageAssembleReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SignalReq *SignalReq `protobuf:"bytes,1,opt,name=signalReq,proto3" json:"signalReq,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` +} + +func (x *SignalMessageAssembleReq) Reset() { + *x = SignalMessageAssembleReq{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalMessageAssembleReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalMessageAssembleReq) ProtoMessage() {} + +func (x *SignalMessageAssembleReq) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalMessageAssembleReq.ProtoReflect.Descriptor instead. +func (*SignalMessageAssembleReq) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{24} +} + +func (x *SignalMessageAssembleReq) GetSignalReq() *SignalReq { + if x != nil { + return x.SignalReq + } + return nil +} + +func (x *SignalMessageAssembleReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type SignalMessageAssembleResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp,proto3" json:"commonResp,omitempty"` + IsPass bool `protobuf:"varint,2,opt,name=isPass,proto3" json:"isPass,omitempty"` + SignalResp *SignalResp `protobuf:"bytes,3,opt,name=signalResp,proto3" json:"signalResp,omitempty"` + MsgData *MsgData `protobuf:"bytes,4,opt,name=msgData,proto3" json:"msgData,omitempty"` +} + +func (x *SignalMessageAssembleResp) Reset() { + *x = SignalMessageAssembleResp{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_rtc_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignalMessageAssembleResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignalMessageAssembleResp) ProtoMessage() {} + +func (x *SignalMessageAssembleResp) ProtoReflect() protoreflect.Message { + mi := &file_proto_rtc_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignalMessageAssembleResp.ProtoReflect.Descriptor instead. +func (*SignalMessageAssembleResp) Descriptor() ([]byte, []int) { + return file_proto_rtc_proto_rawDescGZIP(), []int{25} +} + +func (x *SignalMessageAssembleResp) GetCommonResp() *CommonResp { + if x != nil { + return x.CommonResp + } + return nil +} + +func (x *SignalMessageAssembleResp) GetIsPass() bool { + if x != nil { + return x.IsPass + } + return false +} + +func (x *SignalMessageAssembleResp) GetSignalResp() *SignalResp { + if x != nil { + return x.SignalResp + } + return nil +} + +func (x *SignalMessageAssembleResp) GetMsgData() *MsgData { + if x != nil { + return x.MsgData + } + return nil +} + +var File_proto_rtc_proto protoreflect.FileDescriptor + +var file_proto_rtc_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x74, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3e, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x22, 0xa4, 0x05, 0x0a, 0x07, 0x4d, 0x73, 0x67, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x65, 0x63, 0x76, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, + 0x63, 0x76, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x20, + 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x49, 0x44, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x49, 0x44, + 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x49, 0x44, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x73, 0x67, + 0x49, 0x44, 0x12, 0x2a, 0x0a, 0x10, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x73, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x44, 0x12, 0x26, + 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x69, + 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x46, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x20, 0x0a, 0x0b, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x46, 0x72, 0x6f, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x6d, 0x73, 0x67, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x71, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x73, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x73, 0x67, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, + 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x1a, 0x3a, 0x0a, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xf5, 0x02, 0x0a, 0x09, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, + 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x74, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x77, + 0x6e, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x65, + 0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x22, 0xb7, 0x02, 0x0a, 0x13, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, + 0x1a, 0x0a, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6e, + 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, + 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, + 0x52, 0x4c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, + 0x4c, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x70, 0x70, 0x4d, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x4c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x61, 0x70, 0x70, 0x4d, 0x61, + 0x6e, 0x67, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x6a, 0x6f, 0x69, + 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6a, + 0x6f, 0x69, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x65, 0x78, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, + 0x78, 0x22, 0xbe, 0x01, 0x0a, 0x13, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x09, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, 0x0a, 0x0f, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x31, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x22, 0x86, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, + 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, + 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x65, + 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x78, 0x22, 0x9b, 0x01, 0x0a, 0x0f, + 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, + 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, + 0x6f, 0x6f, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, + 0x36, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x71, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x31, 0x0a, + 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x52, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x10, 0x0a, 0x03, 0x6a, 0x77, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6a, + 0x77, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x22, 0x95, 0x01, 0x0a, + 0x0f, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x65, 0x78, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x78, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x4f, + 0x53, 0x50, 0x75, 0x73, 0x68, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x69, 0x4f, 0x53, 0x50, 0x75, 0x73, 0x68, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x24, + 0x0a, 0x0d, 0x69, 0x4f, 0x53, 0x42, 0x61, 0x64, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x4f, 0x53, 0x42, 0x61, 0x64, 0x67, 0x65, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xd7, 0x02, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, + 0x65, 0x71, 0x12, 0x30, 0x0a, 0x06, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x49, 0x6e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, + 0x49, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x30, 0x0a, 0x06, 0x63, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x30, 0x0a, + 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, + 0x30, 0x0a, 0x06, 0x68, 0x75, 0x6e, 0x67, 0x55, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x48, 0x75, + 0x6e, 0x67, 0x55, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x68, 0x75, 0x6e, 0x67, 0x55, + 0x70, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, + 0x65, 0x63, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xe4, + 0x02, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x32, 0x0a, + 0x06, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x06, 0x69, 0x6e, 0x76, 0x69, 0x74, + 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, 0x76, + 0x69, 0x74, 0x65, 0x49, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x32, 0x0a, 0x06, 0x63, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x32, + 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x68, 0x75, 0x6e, 0x67, 0x55, 0x70, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x48, 0x75, 0x6e, 0x67, 0x55, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x06, + 0x68, 0x75, 0x6e, 0x67, 0x55, 0x70, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xb0, 0x02, 0x0a, 0x0e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x69, + 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2c, + 0x0a, 0x11, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x4c, + 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x69, 0x6e, 0x76, 0x69, 0x74, + 0x65, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x44, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x44, 0x12, 0x18, + 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x65, 0x64, 0x69, + 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, + 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x49, 0x44, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x22, 0xe4, 0x01, 0x0a, 0x0f, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, + 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x0a, 0x69, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x40, 0x0a, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x22, + 0x5b, 0x0a, 0x11, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, + 0x6f, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, + 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x22, 0xeb, 0x01, 0x0a, + 0x16, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, + 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0f, 0x6f, 0x66, + 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4f, 0x66, 0x66, 0x6c, + 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6f, 0x66, 0x66, + 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3c, 0x0a, 0x0b, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x22, 0x62, 0x0a, 0x18, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, + 0x6f, 0x6d, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x22, 0xe4, + 0x01, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, + 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x35, + 0x0a, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, + 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, + 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, + 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x90, 0x02, 0x0a, 0x0f, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x71, 0x12, 0x1a, + 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x0a, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x40, 0x0a, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, + 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, + 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6f, 0x70, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x44, 0x22, 0x5b, 0x0a, + 0x11, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x6f, 0x6f, 0x6d, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x44, + 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6c, 0x69, 0x76, 0x65, 0x55, 0x52, 0x4c, 0x22, 0xa6, 0x01, 0x0a, 0x0f, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x48, 0x75, 0x6e, 0x67, 0x55, 0x70, 0x52, 0x65, 0x71, 0x12, 0x1a, + 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x0a, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x40, 0x0a, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, + 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x48, 0x75, 0x6e, + 0x67, 0x55, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x90, 0x02, 0x0a, 0x0f, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, + 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x0a, 0x69, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x40, 0x0a, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x0f, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x75, 0x73, 0x68, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x12, + 0x2a, 0x0a, 0x10, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6f, 0x70, 0x55, 0x73, 0x65, + 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x44, 0x22, 0x13, 0x0a, 0x11, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x6c, 0x0a, 0x18, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x2e, 0x0a, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, + 0x71, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0xc3, + 0x01, 0x0a, 0x19, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x31, 0x0a, 0x0a, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x16, 0x0a, 0x06, 0x69, 0x73, 0x50, 0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x06, 0x69, 0x73, 0x50, 0x61, 0x73, 0x73, 0x12, 0x31, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x52, 0x65, 0x73, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x52, 0x0a, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x28, 0x0a, 0x07, 0x6d, 0x73, + 0x67, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x73, 0x67, 0x44, 0x61, 0x74, 0x61, 0x52, 0x07, 0x6d, 0x73, 0x67, + 0x44, 0x61, 0x74, 0x61, 0x32, 0x68, 0x0a, 0x0a, 0x52, 0x74, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x15, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x0b, + 0x5a, 0x09, 0x2e, 0x2f, 0x72, 0x74, 0x63, 0x3b, 0x72, 0x74, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_proto_rtc_proto_rawDescOnce sync.Once + file_proto_rtc_proto_rawDescData = file_proto_rtc_proto_rawDesc +) + +func file_proto_rtc_proto_rawDescGZIP() []byte { + file_proto_rtc_proto_rawDescOnce.Do(func() { + file_proto_rtc_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_rtc_proto_rawDescData) + }) + return file_proto_rtc_proto_rawDescData +} + +var file_proto_rtc_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_proto_rtc_proto_goTypes = []interface{}{ + (*CommonResp)(nil), // 0: proto.CommonResp + (*MsgData)(nil), // 1: proto.MsgData + (*GroupInfo)(nil), // 2: proto.GroupInfo + (*GroupMemberFullInfo)(nil), // 3: proto.GroupMemberFullInfo + (*ParticipantMetaData)(nil), // 4: proto.ParticipantMetaData + (*PublicUserInfo)(nil), // 5: proto.PublicUserInfo + (*GetJoinTokenReq)(nil), // 6: proto.GetJoinTokenReq + (*GetJoinTokenResp)(nil), // 7: proto.GetJoinTokenResp + (*OfflinePushInfo)(nil), // 8: proto.OfflinePushInfo + (*SignalReq)(nil), // 9: proto.SignalReq + (*SignalResp)(nil), // 10: proto.SignalResp + (*InvitationInfo)(nil), // 11: proto.InvitationInfo + (*SignalInviteReq)(nil), // 12: proto.SignalInviteReq + (*SignalInviteReply)(nil), // 13: proto.SignalInviteReply + (*SignalInviteInGroupReq)(nil), // 14: proto.SignalInviteInGroupReq + (*SignalInviteInGroupReply)(nil), // 15: proto.SignalInviteInGroupReply + (*SignalCancelReq)(nil), // 16: proto.SignalCancelReq + (*SignalCancelReply)(nil), // 17: proto.SignalCancelReply + (*SignalAcceptReq)(nil), // 18: proto.SignalAcceptReq + (*SignalAcceptReply)(nil), // 19: proto.SignalAcceptReply + (*SignalHungUpReq)(nil), // 20: proto.SignalHungUpReq + (*SignalHungUpReply)(nil), // 21: proto.SignalHungUpReply + (*SignalRejectReq)(nil), // 22: proto.SignalRejectReq + (*SignalRejectReply)(nil), // 23: proto.SignalRejectReply + (*SignalMessageAssembleReq)(nil), // 24: proto.SignalMessageAssembleReq + (*SignalMessageAssembleResp)(nil), // 25: proto.SignalMessageAssembleResp + nil, // 26: proto.MsgData.OptionsEntry +} +var file_proto_rtc_proto_depIdxs = []int32{ + 26, // 0: proto.MsgData.options:type_name -> proto.MsgData.OptionsEntry + 8, // 1: proto.MsgData.offlinePushInfo:type_name -> proto.OfflinePushInfo + 2, // 2: proto.ParticipantMetaData.groupInfo:type_name -> proto.GroupInfo + 3, // 3: proto.ParticipantMetaData.groupMemberInfo:type_name -> proto.GroupMemberFullInfo + 5, // 4: proto.ParticipantMetaData.userInfo:type_name -> proto.PublicUserInfo + 4, // 5: proto.GetJoinTokenReq.metaData:type_name -> proto.ParticipantMetaData + 0, // 6: proto.GetJoinTokenResp.CommonResp:type_name -> proto.CommonResp + 12, // 7: proto.SignalReq.invite:type_name -> proto.SignalInviteReq + 14, // 8: proto.SignalReq.inviteInGroup:type_name -> proto.SignalInviteInGroupReq + 16, // 9: proto.SignalReq.cancel:type_name -> proto.SignalCancelReq + 18, // 10: proto.SignalReq.accept:type_name -> proto.SignalAcceptReq + 20, // 11: proto.SignalReq.hungUp:type_name -> proto.SignalHungUpReq + 22, // 12: proto.SignalReq.reject:type_name -> proto.SignalRejectReq + 13, // 13: proto.SignalResp.invite:type_name -> proto.SignalInviteReply + 15, // 14: proto.SignalResp.inviteInGroup:type_name -> proto.SignalInviteInGroupReply + 17, // 15: proto.SignalResp.cancel:type_name -> proto.SignalCancelReply + 19, // 16: proto.SignalResp.accept:type_name -> proto.SignalAcceptReply + 21, // 17: proto.SignalResp.hungUp:type_name -> proto.SignalHungUpReply + 23, // 18: proto.SignalResp.reject:type_name -> proto.SignalRejectReply + 11, // 19: proto.SignalInviteReq.invitation:type_name -> proto.InvitationInfo + 8, // 20: proto.SignalInviteReq.offlinePushInfo:type_name -> proto.OfflinePushInfo + 4, // 21: proto.SignalInviteReq.participant:type_name -> proto.ParticipantMetaData + 11, // 22: proto.SignalInviteInGroupReq.invitation:type_name -> proto.InvitationInfo + 8, // 23: proto.SignalInviteInGroupReq.offlinePushInfo:type_name -> proto.OfflinePushInfo + 4, // 24: proto.SignalInviteInGroupReq.participant:type_name -> proto.ParticipantMetaData + 11, // 25: proto.SignalCancelReq.invitation:type_name -> proto.InvitationInfo + 8, // 26: proto.SignalCancelReq.offlinePushInfo:type_name -> proto.OfflinePushInfo + 4, // 27: proto.SignalCancelReq.participant:type_name -> proto.ParticipantMetaData + 11, // 28: proto.SignalAcceptReq.invitation:type_name -> proto.InvitationInfo + 8, // 29: proto.SignalAcceptReq.offlinePushInfo:type_name -> proto.OfflinePushInfo + 4, // 30: proto.SignalAcceptReq.participant:type_name -> proto.ParticipantMetaData + 11, // 31: proto.SignalHungUpReq.invitation:type_name -> proto.InvitationInfo + 8, // 32: proto.SignalHungUpReq.offlinePushInfo:type_name -> proto.OfflinePushInfo + 11, // 33: proto.SignalRejectReq.invitation:type_name -> proto.InvitationInfo + 8, // 34: proto.SignalRejectReq.offlinePushInfo:type_name -> proto.OfflinePushInfo + 4, // 35: proto.SignalRejectReq.participant:type_name -> proto.ParticipantMetaData + 9, // 36: proto.SignalMessageAssembleReq.signalReq:type_name -> proto.SignalReq + 0, // 37: proto.SignalMessageAssembleResp.commonResp:type_name -> proto.CommonResp + 10, // 38: proto.SignalMessageAssembleResp.signalResp:type_name -> proto.SignalResp + 1, // 39: proto.SignalMessageAssembleResp.msgData:type_name -> proto.MsgData + 24, // 40: proto.RtcService.SignalMessageAssemble:input_type -> proto.SignalMessageAssembleReq + 25, // 41: proto.RtcService.SignalMessageAssemble:output_type -> proto.SignalMessageAssembleResp + 41, // [41:42] is the sub-list for method output_type + 40, // [40:41] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name +} + +func init() { file_proto_rtc_proto_init() } +func file_proto_rtc_proto_init() { + if File_proto_rtc_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_rtc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommonResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupMemberFullInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ParticipantMetaData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PublicUserInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetJoinTokenReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetJoinTokenResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OfflinePushInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvitationInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalInviteReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalInviteReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalInviteInGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalInviteInGroupReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalCancelReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalCancelReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalAcceptReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalAcceptReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalHungUpReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalHungUpReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalRejectReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalRejectReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalMessageAssembleReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_rtc_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignalMessageAssembleResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_proto_rtc_proto_msgTypes[9].OneofWrappers = []interface{}{ + (*SignalReq_Invite)(nil), + (*SignalReq_InviteInGroup)(nil), + (*SignalReq_Cancel)(nil), + (*SignalReq_Accept)(nil), + (*SignalReq_HungUp)(nil), + (*SignalReq_Reject)(nil), + } + file_proto_rtc_proto_msgTypes[10].OneofWrappers = []interface{}{ + (*SignalResp_Invite)(nil), + (*SignalResp_InviteInGroup)(nil), + (*SignalResp_Cancel)(nil), + (*SignalResp_Accept)(nil), + (*SignalResp_HungUp)(nil), + (*SignalResp_Reject)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_rtc_proto_rawDesc, + NumEnums: 0, + NumMessages: 27, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_rtc_proto_goTypes, + DependencyIndexes: file_proto_rtc_proto_depIdxs, + MessageInfos: file_proto_rtc_proto_msgTypes, + }.Build() + File_proto_rtc_proto = out.File + file_proto_rtc_proto_rawDesc = nil + file_proto_rtc_proto_goTypes = nil + file_proto_rtc_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// RtcServiceClient is the client API for RtcService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RtcServiceClient interface { + SignalMessageAssemble(ctx context.Context, in *SignalMessageAssembleReq, opts ...grpc.CallOption) (*SignalMessageAssembleResp, error) +} + +type rtcServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewRtcServiceClient(cc grpc.ClientConnInterface) RtcServiceClient { + return &rtcServiceClient{cc} +} + +func (c *rtcServiceClient) SignalMessageAssemble(ctx context.Context, in *SignalMessageAssembleReq, opts ...grpc.CallOption) (*SignalMessageAssembleResp, error) { + out := new(SignalMessageAssembleResp) + err := c.cc.Invoke(ctx, "/proto.RtcService/SignalMessageAssemble", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RtcServiceServer is the server API for RtcService service. +type RtcServiceServer interface { + SignalMessageAssemble(context.Context, *SignalMessageAssembleReq) (*SignalMessageAssembleResp, error) +} + +// UnimplementedRtcServiceServer can be embedded to have forward compatible implementations. +type UnimplementedRtcServiceServer struct { +} + +func (*UnimplementedRtcServiceServer) SignalMessageAssemble(context.Context, *SignalMessageAssembleReq) (*SignalMessageAssembleResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignalMessageAssemble not implemented") +} + +func RegisterRtcServiceServer(s *grpc.Server, srv RtcServiceServer) { + s.RegisterService(&_RtcService_serviceDesc, srv) +} + +func _RtcService_SignalMessageAssemble_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SignalMessageAssembleReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RtcServiceServer).SignalMessageAssemble(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.RtcService/SignalMessageAssemble", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RtcServiceServer).SignalMessageAssemble(ctx, req.(*SignalMessageAssembleReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _RtcService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.RtcService", + HandlerType: (*RtcServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SignalMessageAssemble", + Handler: _RtcService_SignalMessageAssemble_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/rtc.proto", +} diff --git a/pkg/proto/rtc/rtc.proto b/pkg/proto/rtc/rtc.proto new file mode 100644 index 000000000..ce9ca472b --- /dev/null +++ b/pkg/proto/rtc/rtc.proto @@ -0,0 +1,219 @@ +syntax = "proto3"; +option go_package = "./rtc;rtc"; +package proto; + +message CommonResp{ + int32 errCode = 1; + string errMsg = 2; +} + +message MsgData { + string sendID = 1; + string recvID = 2; + string groupID = 3; + string clientMsgID = 4; + string serverMsgID = 5; + int32 senderPlatformID = 6; + string senderNickname = 7; + string senderFaceURL = 8; + int32 sessionType = 9; + int32 msgFrom = 10; + int32 contentType = 11; + bytes content = 12; + uint32 seq = 14; + int64 sendTime = 15; + int64 createTime = 16; + int32 status = 17; + map<string, bool> options = 18; + OfflinePushInfo offlinePushInfo = 19; +} + + +message GroupInfo{ + string groupID = 1; + string groupName = 2; + string notification = 3; + string introduction = 4; + string faceURL = 5; + string ownerUserID = 6; + uint32 createTime = 7; + uint32 memberCount = 8; + string ex = 9; + int32 status = 10; + string creatorUserID = 11; + int32 groupType = 12; +} + +message GroupMemberFullInfo { + string groupID = 1 ; + string userID = 2 ; + int32 roleLevel = 3; + int32 joinTime = 4; + string nickname = 5; + string faceURL = 6; + int32 appMangerLevel = 7; //if >0 + int32 joinSource = 8; + string operatorUserID = 9; + string ex = 10; +} + +message ParticipantMetaData{ + GroupInfo groupInfo = 1; + GroupMemberFullInfo groupMemberInfo = 2; + PublicUserInfo userInfo = 3; +} + +message PublicUserInfo{ + string userID = 1; + string nickname = 2; + string faceURL = 3; + int32 gender = 4; + string ex = 5; +} + +message GetJoinTokenReq{ + string room = 1; + string identity = 2; + ParticipantMetaData metaData = 3; + string operationID = 4; +} + +message GetJoinTokenResp{ + CommonResp CommonResp = 1; + string jwt = 2; + string liveURL = 3; +} + +message OfflinePushInfo{ + string title = 1; + string desc = 2; + string ex = 3; + string iOSPushSound = 4; + bool iOSBadgeCount = 5; +} + +message SignalReq { + oneof payload { + SignalInviteReq invite = 1; + SignalInviteInGroupReq inviteInGroup= 2; + SignalCancelReq cancel = 3; + SignalAcceptReq accept = 4; + SignalHungUpReq hungUp = 5; + SignalRejectReq reject = 6; + } +} + +message SignalResp { + oneof payload { + SignalInviteReply invite = 1; + SignalInviteInGroupReply inviteInGroup= 2; + SignalCancelReply cancel = 3; + SignalAcceptReply accept = 4; + SignalHungUpReply hungUp = 5; + SignalRejectReply reject = 6; + } +} + +message InvitationInfo { + string inviterUserID = 1; + repeated string inviteeUserIDList = 2; + string customData = 3; + string groupID = 4; + string roomID = 5; + int32 timeout = 6; + string mediaType = 7; + int32 platformID = 8; + int32 sessionType = 9; +} + + +message SignalInviteReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; + +} + +message SignalInviteReply { + string token = 1; + string roomID = 2; + string liveURL = 3; +} + +message SignalInviteInGroupReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; +} + +message SignalInviteInGroupReply { + string token = 1; + string roomID = 2; + string liveURL = 3; +} + +message SignalCancelReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; +} + +message SignalCancelReply { + +} + +message SignalAcceptReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; + int32 opUserPlatformID = 5; +} + +message SignalAcceptReply { + string token = 1; + string roomID = 2; + string liveURL = 3; +} + +message SignalHungUpReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; +} + +message SignalHungUpReply { + +} + + +message SignalRejectReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; + int32 opUserPlatformID = 5; +} + +message SignalRejectReply { + +} + +message SignalMessageAssembleReq { + SignalReq signalReq = 1; + string operationID = 2; +} + +message SignalMessageAssembleResp { + CommonResp commonResp = 1; + bool isPass = 2; + SignalResp signalResp = 3; + MsgData msgData = 4; +} + +service RtcService { + rpc SignalMessageAssemble(SignalMessageAssembleReq) returns(SignalMessageAssembleResp); +} diff --git a/pkg/proto/sdk_ws/ws.pb.go b/pkg/proto/sdk_ws/ws.pb.go new file mode 100644 index 000000000..27901e90f --- /dev/null +++ b/pkg/proto/sdk_ws/ws.pb.go @@ -0,0 +1,5002 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: sdk_ws/ws.proto + +package server_api_params // import "Open_IM/pkg/proto/sdk_ws" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type GroupInfo struct { + GroupID string `protobuf:"bytes,1,opt,name=groupID" json:"groupID,omitempty"` + GroupName string `protobuf:"bytes,2,opt,name=groupName" json:"groupName,omitempty"` + Notification string `protobuf:"bytes,3,opt,name=notification" json:"notification,omitempty"` + Introduction string `protobuf:"bytes,4,opt,name=introduction" json:"introduction,omitempty"` + FaceURL string `protobuf:"bytes,5,opt,name=faceURL" json:"faceURL,omitempty"` + OwnerUserID string `protobuf:"bytes,6,opt,name=ownerUserID" json:"ownerUserID,omitempty"` + CreateTime uint32 `protobuf:"varint,7,opt,name=createTime" json:"createTime,omitempty"` + MemberCount uint32 `protobuf:"varint,8,opt,name=memberCount" json:"memberCount,omitempty"` + Ex string `protobuf:"bytes,9,opt,name=ex" json:"ex,omitempty"` + Status int32 `protobuf:"varint,10,opt,name=status" json:"status,omitempty"` + CreatorUserID string `protobuf:"bytes,11,opt,name=creatorUserID" json:"creatorUserID,omitempty"` + GroupType int32 `protobuf:"varint,12,opt,name=groupType" json:"groupType,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupInfo) Reset() { *m = GroupInfo{} } +func (m *GroupInfo) String() string { return proto.CompactTextString(m) } +func (*GroupInfo) ProtoMessage() {} +func (*GroupInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{0} +} +func (m *GroupInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupInfo.Unmarshal(m, b) +} +func (m *GroupInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupInfo.Marshal(b, m, deterministic) +} +func (dst *GroupInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupInfo.Merge(dst, src) +} +func (m *GroupInfo) XXX_Size() int { + return xxx_messageInfo_GroupInfo.Size(m) +} +func (m *GroupInfo) XXX_DiscardUnknown() { + xxx_messageInfo_GroupInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupInfo proto.InternalMessageInfo + +func (m *GroupInfo) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *GroupInfo) GetGroupName() string { + if m != nil { + return m.GroupName + } + return "" +} + +func (m *GroupInfo) GetNotification() string { + if m != nil { + return m.Notification + } + return "" +} + +func (m *GroupInfo) GetIntroduction() string { + if m != nil { + return m.Introduction + } + return "" +} + +func (m *GroupInfo) GetFaceURL() string { + if m != nil { + return m.FaceURL + } + return "" +} + +func (m *GroupInfo) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *GroupInfo) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *GroupInfo) GetMemberCount() uint32 { + if m != nil { + return m.MemberCount + } + return 0 +} + +func (m *GroupInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +func (m *GroupInfo) GetStatus() int32 { + if m != nil { + return m.Status + } + return 0 +} + +func (m *GroupInfo) GetCreatorUserID() string { + if m != nil { + return m.CreatorUserID + } + return "" +} + +func (m *GroupInfo) GetGroupType() int32 { + if m != nil { + return m.GroupType + } + return 0 +} + +type GroupMemberFullInfo struct { + GroupID string `protobuf:"bytes,1,opt,name=groupID" json:"groupID,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + RoleLevel int32 `protobuf:"varint,3,opt,name=roleLevel" json:"roleLevel,omitempty"` + JoinTime int32 `protobuf:"varint,4,opt,name=joinTime" json:"joinTime,omitempty"` + Nickname string `protobuf:"bytes,5,opt,name=nickname" json:"nickname,omitempty"` + FaceURL string `protobuf:"bytes,6,opt,name=faceURL" json:"faceURL,omitempty"` + AppMangerLevel int32 `protobuf:"varint,7,opt,name=appMangerLevel" json:"appMangerLevel,omitempty"` + JoinSource int32 `protobuf:"varint,8,opt,name=joinSource" json:"joinSource,omitempty"` + OperatorUserID string `protobuf:"bytes,9,opt,name=operatorUserID" json:"operatorUserID,omitempty"` + Ex string `protobuf:"bytes,10,opt,name=ex" json:"ex,omitempty"` + MuteEndTime uint32 `protobuf:"varint,11,opt,name=muteEndTime" json:"muteEndTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupMemberFullInfo) Reset() { *m = GroupMemberFullInfo{} } +func (m *GroupMemberFullInfo) String() string { return proto.CompactTextString(m) } +func (*GroupMemberFullInfo) ProtoMessage() {} +func (*GroupMemberFullInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{1} +} +func (m *GroupMemberFullInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupMemberFullInfo.Unmarshal(m, b) +} +func (m *GroupMemberFullInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupMemberFullInfo.Marshal(b, m, deterministic) +} +func (dst *GroupMemberFullInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupMemberFullInfo.Merge(dst, src) +} +func (m *GroupMemberFullInfo) XXX_Size() int { + return xxx_messageInfo_GroupMemberFullInfo.Size(m) +} +func (m *GroupMemberFullInfo) XXX_DiscardUnknown() { + xxx_messageInfo_GroupMemberFullInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupMemberFullInfo proto.InternalMessageInfo + +func (m *GroupMemberFullInfo) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *GroupMemberFullInfo) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *GroupMemberFullInfo) GetRoleLevel() int32 { + if m != nil { + return m.RoleLevel + } + return 0 +} + +func (m *GroupMemberFullInfo) GetJoinTime() int32 { + if m != nil { + return m.JoinTime + } + return 0 +} + +func (m *GroupMemberFullInfo) GetNickname() string { + if m != nil { + return m.Nickname + } + return "" +} + +func (m *GroupMemberFullInfo) GetFaceURL() string { + if m != nil { + return m.FaceURL + } + return "" +} + +func (m *GroupMemberFullInfo) GetAppMangerLevel() int32 { + if m != nil { + return m.AppMangerLevel + } + return 0 +} + +func (m *GroupMemberFullInfo) GetJoinSource() int32 { + if m != nil { + return m.JoinSource + } + return 0 +} + +func (m *GroupMemberFullInfo) GetOperatorUserID() string { + if m != nil { + return m.OperatorUserID + } + return "" +} + +func (m *GroupMemberFullInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +func (m *GroupMemberFullInfo) GetMuteEndTime() uint32 { + if m != nil { + return m.MuteEndTime + } + return 0 +} + +type PublicUserInfo struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname" json:"nickname,omitempty"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL" json:"faceURL,omitempty"` + Gender int32 `protobuf:"varint,4,opt,name=gender" json:"gender,omitempty"` + Ex string `protobuf:"bytes,5,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PublicUserInfo) Reset() { *m = PublicUserInfo{} } +func (m *PublicUserInfo) String() string { return proto.CompactTextString(m) } +func (*PublicUserInfo) ProtoMessage() {} +func (*PublicUserInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{2} +} +func (m *PublicUserInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PublicUserInfo.Unmarshal(m, b) +} +func (m *PublicUserInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PublicUserInfo.Marshal(b, m, deterministic) +} +func (dst *PublicUserInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_PublicUserInfo.Merge(dst, src) +} +func (m *PublicUserInfo) XXX_Size() int { + return xxx_messageInfo_PublicUserInfo.Size(m) +} +func (m *PublicUserInfo) XXX_DiscardUnknown() { + xxx_messageInfo_PublicUserInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_PublicUserInfo proto.InternalMessageInfo + +func (m *PublicUserInfo) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *PublicUserInfo) GetNickname() string { + if m != nil { + return m.Nickname + } + return "" +} + +func (m *PublicUserInfo) GetFaceURL() string { + if m != nil { + return m.FaceURL + } + return "" +} + +func (m *PublicUserInfo) GetGender() int32 { + if m != nil { + return m.Gender + } + return 0 +} + +func (m *PublicUserInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type UserInfo struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname" json:"nickname,omitempty"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL" json:"faceURL,omitempty"` + Gender int32 `protobuf:"varint,4,opt,name=gender" json:"gender,omitempty"` + PhoneNumber string `protobuf:"bytes,5,opt,name=phoneNumber" json:"phoneNumber,omitempty"` + Birth uint32 `protobuf:"varint,6,opt,name=birth" json:"birth,omitempty"` + Email string `protobuf:"bytes,7,opt,name=email" json:"email,omitempty"` + Ex string `protobuf:"bytes,8,opt,name=ex" json:"ex,omitempty"` + CreateTime uint32 `protobuf:"varint,9,opt,name=createTime" json:"createTime,omitempty"` + AppMangerLevel int32 `protobuf:"varint,10,opt,name=appMangerLevel" json:"appMangerLevel,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserInfo) Reset() { *m = UserInfo{} } +func (m *UserInfo) String() string { return proto.CompactTextString(m) } +func (*UserInfo) ProtoMessage() {} +func (*UserInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{3} +} +func (m *UserInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserInfo.Unmarshal(m, b) +} +func (m *UserInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserInfo.Marshal(b, m, deterministic) +} +func (dst *UserInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserInfo.Merge(dst, src) +} +func (m *UserInfo) XXX_Size() int { + return xxx_messageInfo_UserInfo.Size(m) +} +func (m *UserInfo) XXX_DiscardUnknown() { + xxx_messageInfo_UserInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_UserInfo proto.InternalMessageInfo + +func (m *UserInfo) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *UserInfo) GetNickname() string { + if m != nil { + return m.Nickname + } + return "" +} + +func (m *UserInfo) GetFaceURL() string { + if m != nil { + return m.FaceURL + } + return "" +} + +func (m *UserInfo) GetGender() int32 { + if m != nil { + return m.Gender + } + return 0 +} + +func (m *UserInfo) GetPhoneNumber() string { + if m != nil { + return m.PhoneNumber + } + return "" +} + +func (m *UserInfo) GetBirth() uint32 { + if m != nil { + return m.Birth + } + return 0 +} + +func (m *UserInfo) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *UserInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +func (m *UserInfo) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *UserInfo) GetAppMangerLevel() int32 { + if m != nil { + return m.AppMangerLevel + } + return 0 +} + +type FriendInfo struct { + OwnerUserID string `protobuf:"bytes,1,opt,name=ownerUserID" json:"ownerUserID,omitempty"` + Remark string `protobuf:"bytes,2,opt,name=remark" json:"remark,omitempty"` + CreateTime uint32 `protobuf:"varint,3,opt,name=createTime" json:"createTime,omitempty"` + FriendUser *UserInfo `protobuf:"bytes,4,opt,name=friendUser" json:"friendUser,omitempty"` + AddSource int32 `protobuf:"varint,5,opt,name=addSource" json:"addSource,omitempty"` + OperatorUserID string `protobuf:"bytes,6,opt,name=operatorUserID" json:"operatorUserID,omitempty"` + Ex string `protobuf:"bytes,7,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendInfo) Reset() { *m = FriendInfo{} } +func (m *FriendInfo) String() string { return proto.CompactTextString(m) } +func (*FriendInfo) ProtoMessage() {} +func (*FriendInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{4} +} +func (m *FriendInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendInfo.Unmarshal(m, b) +} +func (m *FriendInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendInfo.Marshal(b, m, deterministic) +} +func (dst *FriendInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendInfo.Merge(dst, src) +} +func (m *FriendInfo) XXX_Size() int { + return xxx_messageInfo_FriendInfo.Size(m) +} +func (m *FriendInfo) XXX_DiscardUnknown() { + xxx_messageInfo_FriendInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendInfo proto.InternalMessageInfo + +func (m *FriendInfo) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *FriendInfo) GetRemark() string { + if m != nil { + return m.Remark + } + return "" +} + +func (m *FriendInfo) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *FriendInfo) GetFriendUser() *UserInfo { + if m != nil { + return m.FriendUser + } + return nil +} + +func (m *FriendInfo) GetAddSource() int32 { + if m != nil { + return m.AddSource + } + return 0 +} + +func (m *FriendInfo) GetOperatorUserID() string { + if m != nil { + return m.OperatorUserID + } + return "" +} + +func (m *FriendInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type BlackInfo struct { + OwnerUserID string `protobuf:"bytes,1,opt,name=ownerUserID" json:"ownerUserID,omitempty"` + CreateTime uint32 `protobuf:"varint,2,opt,name=createTime" json:"createTime,omitempty"` + BlackUserInfo *PublicUserInfo `protobuf:"bytes,3,opt,name=blackUserInfo" json:"blackUserInfo,omitempty"` + AddSource int32 `protobuf:"varint,4,opt,name=addSource" json:"addSource,omitempty"` + OperatorUserID string `protobuf:"bytes,5,opt,name=operatorUserID" json:"operatorUserID,omitempty"` + Ex string `protobuf:"bytes,6,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlackInfo) Reset() { *m = BlackInfo{} } +func (m *BlackInfo) String() string { return proto.CompactTextString(m) } +func (*BlackInfo) ProtoMessage() {} +func (*BlackInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{5} +} +func (m *BlackInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BlackInfo.Unmarshal(m, b) +} +func (m *BlackInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BlackInfo.Marshal(b, m, deterministic) +} +func (dst *BlackInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlackInfo.Merge(dst, src) +} +func (m *BlackInfo) XXX_Size() int { + return xxx_messageInfo_BlackInfo.Size(m) +} +func (m *BlackInfo) XXX_DiscardUnknown() { + xxx_messageInfo_BlackInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_BlackInfo proto.InternalMessageInfo + +func (m *BlackInfo) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *BlackInfo) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *BlackInfo) GetBlackUserInfo() *PublicUserInfo { + if m != nil { + return m.BlackUserInfo + } + return nil +} + +func (m *BlackInfo) GetAddSource() int32 { + if m != nil { + return m.AddSource + } + return 0 +} + +func (m *BlackInfo) GetOperatorUserID() string { + if m != nil { + return m.OperatorUserID + } + return "" +} + +func (m *BlackInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type GroupRequest struct { + UserInfo *PublicUserInfo `protobuf:"bytes,1,opt,name=userInfo" json:"userInfo,omitempty"` + GroupInfo *GroupInfo `protobuf:"bytes,2,opt,name=groupInfo" json:"groupInfo,omitempty"` + HandleResult int32 `protobuf:"varint,3,opt,name=handleResult" json:"handleResult,omitempty"` + ReqMsg string `protobuf:"bytes,4,opt,name=reqMsg" json:"reqMsg,omitempty"` + HandleMsg string `protobuf:"bytes,5,opt,name=handleMsg" json:"handleMsg,omitempty"` + ReqTime uint32 `protobuf:"varint,6,opt,name=reqTime" json:"reqTime,omitempty"` + HandleUserID string `protobuf:"bytes,7,opt,name=handleUserID" json:"handleUserID,omitempty"` + HandleTime uint32 `protobuf:"varint,8,opt,name=handleTime" json:"handleTime,omitempty"` + Ex string `protobuf:"bytes,9,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupRequest) Reset() { *m = GroupRequest{} } +func (m *GroupRequest) String() string { return proto.CompactTextString(m) } +func (*GroupRequest) ProtoMessage() {} +func (*GroupRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{6} +} +func (m *GroupRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupRequest.Unmarshal(m, b) +} +func (m *GroupRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupRequest.Marshal(b, m, deterministic) +} +func (dst *GroupRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupRequest.Merge(dst, src) +} +func (m *GroupRequest) XXX_Size() int { + return xxx_messageInfo_GroupRequest.Size(m) +} +func (m *GroupRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GroupRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupRequest proto.InternalMessageInfo + +func (m *GroupRequest) GetUserInfo() *PublicUserInfo { + if m != nil { + return m.UserInfo + } + return nil +} + +func (m *GroupRequest) GetGroupInfo() *GroupInfo { + if m != nil { + return m.GroupInfo + } + return nil +} + +func (m *GroupRequest) GetHandleResult() int32 { + if m != nil { + return m.HandleResult + } + return 0 +} + +func (m *GroupRequest) GetReqMsg() string { + if m != nil { + return m.ReqMsg + } + return "" +} + +func (m *GroupRequest) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +func (m *GroupRequest) GetReqTime() uint32 { + if m != nil { + return m.ReqTime + } + return 0 +} + +func (m *GroupRequest) GetHandleUserID() string { + if m != nil { + return m.HandleUserID + } + return "" +} + +func (m *GroupRequest) GetHandleTime() uint32 { + if m != nil { + return m.HandleTime + } + return 0 +} + +func (m *GroupRequest) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type FriendRequest struct { + FromUserID string `protobuf:"bytes,1,opt,name=fromUserID" json:"fromUserID,omitempty"` + FromNickname string `protobuf:"bytes,2,opt,name=fromNickname" json:"fromNickname,omitempty"` + FromFaceURL string `protobuf:"bytes,3,opt,name=fromFaceURL" json:"fromFaceURL,omitempty"` + FromGender int32 `protobuf:"varint,4,opt,name=fromGender" json:"fromGender,omitempty"` + ToUserID string `protobuf:"bytes,5,opt,name=toUserID" json:"toUserID,omitempty"` + ToNickname string `protobuf:"bytes,6,opt,name=toNickname" json:"toNickname,omitempty"` + ToFaceURL string `protobuf:"bytes,7,opt,name=toFaceURL" json:"toFaceURL,omitempty"` + ToGender int32 `protobuf:"varint,8,opt,name=toGender" json:"toGender,omitempty"` + HandleResult int32 `protobuf:"varint,9,opt,name=handleResult" json:"handleResult,omitempty"` + ReqMsg string `protobuf:"bytes,10,opt,name=reqMsg" json:"reqMsg,omitempty"` + CreateTime uint32 `protobuf:"varint,11,opt,name=createTime" json:"createTime,omitempty"` + HandlerUserID string `protobuf:"bytes,12,opt,name=handlerUserID" json:"handlerUserID,omitempty"` + HandleMsg string `protobuf:"bytes,13,opt,name=handleMsg" json:"handleMsg,omitempty"` + HandleTime uint32 `protobuf:"varint,14,opt,name=handleTime" json:"handleTime,omitempty"` + Ex string `protobuf:"bytes,15,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendRequest) Reset() { *m = FriendRequest{} } +func (m *FriendRequest) String() string { return proto.CompactTextString(m) } +func (*FriendRequest) ProtoMessage() {} +func (*FriendRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{7} +} +func (m *FriendRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendRequest.Unmarshal(m, b) +} +func (m *FriendRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendRequest.Marshal(b, m, deterministic) +} +func (dst *FriendRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendRequest.Merge(dst, src) +} +func (m *FriendRequest) XXX_Size() int { + return xxx_messageInfo_FriendRequest.Size(m) +} +func (m *FriendRequest) XXX_DiscardUnknown() { + xxx_messageInfo_FriendRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendRequest proto.InternalMessageInfo + +func (m *FriendRequest) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +func (m *FriendRequest) GetFromNickname() string { + if m != nil { + return m.FromNickname + } + return "" +} + +func (m *FriendRequest) GetFromFaceURL() string { + if m != nil { + return m.FromFaceURL + } + return "" +} + +func (m *FriendRequest) GetFromGender() int32 { + if m != nil { + return m.FromGender + } + return 0 +} + +func (m *FriendRequest) GetToUserID() string { + if m != nil { + return m.ToUserID + } + return "" +} + +func (m *FriendRequest) GetToNickname() string { + if m != nil { + return m.ToNickname + } + return "" +} + +func (m *FriendRequest) GetToFaceURL() string { + if m != nil { + return m.ToFaceURL + } + return "" +} + +func (m *FriendRequest) GetToGender() int32 { + if m != nil { + return m.ToGender + } + return 0 +} + +func (m *FriendRequest) GetHandleResult() int32 { + if m != nil { + return m.HandleResult + } + return 0 +} + +func (m *FriendRequest) GetReqMsg() string { + if m != nil { + return m.ReqMsg + } + return "" +} + +func (m *FriendRequest) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *FriendRequest) GetHandlerUserID() string { + if m != nil { + return m.HandlerUserID + } + return "" +} + +func (m *FriendRequest) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +func (m *FriendRequest) GetHandleTime() uint32 { + if m != nil { + return m.HandleTime + } + return 0 +} + +func (m *FriendRequest) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type Department struct { + DepartmentID string `protobuf:"bytes,1,opt,name=departmentID" json:"departmentID,omitempty"` + FaceURL string `protobuf:"bytes,2,opt,name=faceURL" json:"faceURL,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + ParentID string `protobuf:"bytes,4,opt,name=parentID" json:"parentID,omitempty"` + Order int32 `protobuf:"varint,5,opt,name=order" json:"order,omitempty"` + DepartmentType int32 `protobuf:"varint,6,opt,name=departmentType" json:"departmentType,omitempty"` + CreateTime uint32 `protobuf:"varint,7,opt,name=createTime" json:"createTime,omitempty"` + SubDepartmentNum uint32 `protobuf:"varint,8,opt,name=subDepartmentNum" json:"subDepartmentNum,omitempty"` + MemberNum uint32 `protobuf:"varint,9,opt,name=memberNum" json:"memberNum,omitempty"` + Ex string `protobuf:"bytes,10,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Department) Reset() { *m = Department{} } +func (m *Department) String() string { return proto.CompactTextString(m) } +func (*Department) ProtoMessage() {} +func (*Department) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{8} +} +func (m *Department) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Department.Unmarshal(m, b) +} +func (m *Department) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Department.Marshal(b, m, deterministic) +} +func (dst *Department) XXX_Merge(src proto.Message) { + xxx_messageInfo_Department.Merge(dst, src) +} +func (m *Department) XXX_Size() int { + return xxx_messageInfo_Department.Size(m) +} +func (m *Department) XXX_DiscardUnknown() { + xxx_messageInfo_Department.DiscardUnknown(m) +} + +var xxx_messageInfo_Department proto.InternalMessageInfo + +func (m *Department) GetDepartmentID() string { + if m != nil { + return m.DepartmentID + } + return "" +} + +func (m *Department) GetFaceURL() string { + if m != nil { + return m.FaceURL + } + return "" +} + +func (m *Department) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Department) GetParentID() string { + if m != nil { + return m.ParentID + } + return "" +} + +func (m *Department) GetOrder() int32 { + if m != nil { + return m.Order + } + return 0 +} + +func (m *Department) GetDepartmentType() int32 { + if m != nil { + return m.DepartmentType + } + return 0 +} + +func (m *Department) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *Department) GetSubDepartmentNum() uint32 { + if m != nil { + return m.SubDepartmentNum + } + return 0 +} + +func (m *Department) GetMemberNum() uint32 { + if m != nil { + return m.MemberNum + } + return 0 +} + +func (m *Department) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type OrganizationUser struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=nickname" json:"nickname,omitempty"` + EnglishName string `protobuf:"bytes,3,opt,name=englishName" json:"englishName,omitempty"` + FaceURL string `protobuf:"bytes,4,opt,name=faceURL" json:"faceURL,omitempty"` + Gender int32 `protobuf:"varint,5,opt,name=gender" json:"gender,omitempty"` + Mobile string `protobuf:"bytes,6,opt,name=mobile" json:"mobile,omitempty"` + Telephone string `protobuf:"bytes,7,opt,name=telephone" json:"telephone,omitempty"` + Birth uint32 `protobuf:"varint,8,opt,name=birth" json:"birth,omitempty"` + Email string `protobuf:"bytes,9,opt,name=email" json:"email,omitempty"` + CreateTime uint32 `protobuf:"varint,10,opt,name=createTime" json:"createTime,omitempty"` + Ex string `protobuf:"bytes,11,opt,name=ex" json:"ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OrganizationUser) Reset() { *m = OrganizationUser{} } +func (m *OrganizationUser) String() string { return proto.CompactTextString(m) } +func (*OrganizationUser) ProtoMessage() {} +func (*OrganizationUser) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{9} +} +func (m *OrganizationUser) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OrganizationUser.Unmarshal(m, b) +} +func (m *OrganizationUser) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OrganizationUser.Marshal(b, m, deterministic) +} +func (dst *OrganizationUser) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrganizationUser.Merge(dst, src) +} +func (m *OrganizationUser) XXX_Size() int { + return xxx_messageInfo_OrganizationUser.Size(m) +} +func (m *OrganizationUser) XXX_DiscardUnknown() { + xxx_messageInfo_OrganizationUser.DiscardUnknown(m) +} + +var xxx_messageInfo_OrganizationUser proto.InternalMessageInfo + +func (m *OrganizationUser) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *OrganizationUser) GetNickname() string { + if m != nil { + return m.Nickname + } + return "" +} + +func (m *OrganizationUser) GetEnglishName() string { + if m != nil { + return m.EnglishName + } + return "" +} + +func (m *OrganizationUser) GetFaceURL() string { + if m != nil { + return m.FaceURL + } + return "" +} + +func (m *OrganizationUser) GetGender() int32 { + if m != nil { + return m.Gender + } + return 0 +} + +func (m *OrganizationUser) GetMobile() string { + if m != nil { + return m.Mobile + } + return "" +} + +func (m *OrganizationUser) GetTelephone() string { + if m != nil { + return m.Telephone + } + return "" +} + +func (m *OrganizationUser) GetBirth() uint32 { + if m != nil { + return m.Birth + } + return 0 +} + +func (m *OrganizationUser) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *OrganizationUser) GetCreateTime() uint32 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *OrganizationUser) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type DepartmentMember struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + DepartmentID string `protobuf:"bytes,2,opt,name=DepartmentID" json:"DepartmentID,omitempty"` + Order int32 `protobuf:"varint,3,opt,name=Order" json:"Order,omitempty"` + Position string `protobuf:"bytes,4,opt,name=Position" json:"Position,omitempty"` + Leader int32 `protobuf:"varint,5,opt,name=Leader" json:"Leader,omitempty"` + Status int32 `protobuf:"varint,6,opt,name=Status" json:"Status,omitempty"` + Ex string `protobuf:"bytes,7,opt,name=Ex" json:"Ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DepartmentMember) Reset() { *m = DepartmentMember{} } +func (m *DepartmentMember) String() string { return proto.CompactTextString(m) } +func (*DepartmentMember) ProtoMessage() {} +func (*DepartmentMember) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{10} +} +func (m *DepartmentMember) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DepartmentMember.Unmarshal(m, b) +} +func (m *DepartmentMember) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DepartmentMember.Marshal(b, m, deterministic) +} +func (dst *DepartmentMember) XXX_Merge(src proto.Message) { + xxx_messageInfo_DepartmentMember.Merge(dst, src) +} +func (m *DepartmentMember) XXX_Size() int { + return xxx_messageInfo_DepartmentMember.Size(m) +} +func (m *DepartmentMember) XXX_DiscardUnknown() { + xxx_messageInfo_DepartmentMember.DiscardUnknown(m) +} + +var xxx_messageInfo_DepartmentMember proto.InternalMessageInfo + +func (m *DepartmentMember) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *DepartmentMember) GetDepartmentID() string { + if m != nil { + return m.DepartmentID + } + return "" +} + +func (m *DepartmentMember) GetOrder() int32 { + if m != nil { + return m.Order + } + return 0 +} + +func (m *DepartmentMember) GetPosition() string { + if m != nil { + return m.Position + } + return "" +} + +func (m *DepartmentMember) GetLeader() int32 { + if m != nil { + return m.Leader + } + return 0 +} + +func (m *DepartmentMember) GetStatus() int32 { + if m != nil { + return m.Status + } + return 0 +} + +func (m *DepartmentMember) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type UserInDepartment struct { + OrganizationUser *OrganizationUser `protobuf:"bytes,1,opt,name=organizationUser" json:"organizationUser,omitempty"` + DepartmentMemberList []*DepartmentMember `protobuf:"bytes,2,rep,name=departmentMemberList" json:"departmentMemberList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserInDepartment) Reset() { *m = UserInDepartment{} } +func (m *UserInDepartment) String() string { return proto.CompactTextString(m) } +func (*UserInDepartment) ProtoMessage() {} +func (*UserInDepartment) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{11} +} +func (m *UserInDepartment) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserInDepartment.Unmarshal(m, b) +} +func (m *UserInDepartment) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserInDepartment.Marshal(b, m, deterministic) +} +func (dst *UserInDepartment) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserInDepartment.Merge(dst, src) +} +func (m *UserInDepartment) XXX_Size() int { + return xxx_messageInfo_UserInDepartment.Size(m) +} +func (m *UserInDepartment) XXX_DiscardUnknown() { + xxx_messageInfo_UserInDepartment.DiscardUnknown(m) +} + +var xxx_messageInfo_UserInDepartment proto.InternalMessageInfo + +func (m *UserInDepartment) GetOrganizationUser() *OrganizationUser { + if m != nil { + return m.OrganizationUser + } + return nil +} + +func (m *UserInDepartment) GetDepartmentMemberList() []*DepartmentMember { + if m != nil { + return m.DepartmentMemberList + } + return nil +} + +type PullMessageBySeqListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + List []*MsgData `protobuf:"bytes,3,rep,name=list" json:"list,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PullMessageBySeqListResp) Reset() { *m = PullMessageBySeqListResp{} } +func (m *PullMessageBySeqListResp) String() string { return proto.CompactTextString(m) } +func (*PullMessageBySeqListResp) ProtoMessage() {} +func (*PullMessageBySeqListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{12} +} +func (m *PullMessageBySeqListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PullMessageBySeqListResp.Unmarshal(m, b) +} +func (m *PullMessageBySeqListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PullMessageBySeqListResp.Marshal(b, m, deterministic) +} +func (dst *PullMessageBySeqListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_PullMessageBySeqListResp.Merge(dst, src) +} +func (m *PullMessageBySeqListResp) XXX_Size() int { + return xxx_messageInfo_PullMessageBySeqListResp.Size(m) +} +func (m *PullMessageBySeqListResp) XXX_DiscardUnknown() { + xxx_messageInfo_PullMessageBySeqListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_PullMessageBySeqListResp proto.InternalMessageInfo + +func (m *PullMessageBySeqListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *PullMessageBySeqListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func (m *PullMessageBySeqListResp) GetList() []*MsgData { + if m != nil { + return m.List + } + return nil +} + +type PullMessageBySeqListReq struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + SeqList []uint32 `protobuf:"varint,3,rep,packed,name=seqList" json:"seqList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PullMessageBySeqListReq) Reset() { *m = PullMessageBySeqListReq{} } +func (m *PullMessageBySeqListReq) String() string { return proto.CompactTextString(m) } +func (*PullMessageBySeqListReq) ProtoMessage() {} +func (*PullMessageBySeqListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{13} +} +func (m *PullMessageBySeqListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PullMessageBySeqListReq.Unmarshal(m, b) +} +func (m *PullMessageBySeqListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PullMessageBySeqListReq.Marshal(b, m, deterministic) +} +func (dst *PullMessageBySeqListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_PullMessageBySeqListReq.Merge(dst, src) +} +func (m *PullMessageBySeqListReq) XXX_Size() int { + return xxx_messageInfo_PullMessageBySeqListReq.Size(m) +} +func (m *PullMessageBySeqListReq) XXX_DiscardUnknown() { + xxx_messageInfo_PullMessageBySeqListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_PullMessageBySeqListReq proto.InternalMessageInfo + +func (m *PullMessageBySeqListReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *PullMessageBySeqListReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *PullMessageBySeqListReq) GetSeqList() []uint32 { + if m != nil { + return m.SeqList + } + return nil +} + +type GetMaxAndMinSeqReq struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetMaxAndMinSeqReq) Reset() { *m = GetMaxAndMinSeqReq{} } +func (m *GetMaxAndMinSeqReq) String() string { return proto.CompactTextString(m) } +func (*GetMaxAndMinSeqReq) ProtoMessage() {} +func (*GetMaxAndMinSeqReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{14} +} +func (m *GetMaxAndMinSeqReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetMaxAndMinSeqReq.Unmarshal(m, b) +} +func (m *GetMaxAndMinSeqReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetMaxAndMinSeqReq.Marshal(b, m, deterministic) +} +func (dst *GetMaxAndMinSeqReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetMaxAndMinSeqReq.Merge(dst, src) +} +func (m *GetMaxAndMinSeqReq) XXX_Size() int { + return xxx_messageInfo_GetMaxAndMinSeqReq.Size(m) +} +func (m *GetMaxAndMinSeqReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetMaxAndMinSeqReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetMaxAndMinSeqReq proto.InternalMessageInfo + +type GetMaxAndMinSeqResp struct { + MaxSeq uint32 `protobuf:"varint,1,opt,name=maxSeq" json:"maxSeq,omitempty"` + MinSeq uint32 `protobuf:"varint,2,opt,name=minSeq" json:"minSeq,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetMaxAndMinSeqResp) Reset() { *m = GetMaxAndMinSeqResp{} } +func (m *GetMaxAndMinSeqResp) String() string { return proto.CompactTextString(m) } +func (*GetMaxAndMinSeqResp) ProtoMessage() {} +func (*GetMaxAndMinSeqResp) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{15} +} +func (m *GetMaxAndMinSeqResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetMaxAndMinSeqResp.Unmarshal(m, b) +} +func (m *GetMaxAndMinSeqResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetMaxAndMinSeqResp.Marshal(b, m, deterministic) +} +func (dst *GetMaxAndMinSeqResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetMaxAndMinSeqResp.Merge(dst, src) +} +func (m *GetMaxAndMinSeqResp) XXX_Size() int { + return xxx_messageInfo_GetMaxAndMinSeqResp.Size(m) +} +func (m *GetMaxAndMinSeqResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetMaxAndMinSeqResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetMaxAndMinSeqResp proto.InternalMessageInfo + +func (m *GetMaxAndMinSeqResp) GetMaxSeq() uint32 { + if m != nil { + return m.MaxSeq + } + return 0 +} + +func (m *GetMaxAndMinSeqResp) GetMinSeq() uint32 { + if m != nil { + return m.MinSeq + } + return 0 +} + +type UserSendMsgResp struct { + ServerMsgID string `protobuf:"bytes,1,opt,name=serverMsgID" json:"serverMsgID,omitempty"` + ClientMsgID string `protobuf:"bytes,2,opt,name=clientMsgID" json:"clientMsgID,omitempty"` + SendTime int64 `protobuf:"varint,3,opt,name=sendTime" json:"sendTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserSendMsgResp) Reset() { *m = UserSendMsgResp{} } +func (m *UserSendMsgResp) String() string { return proto.CompactTextString(m) } +func (*UserSendMsgResp) ProtoMessage() {} +func (*UserSendMsgResp) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{16} +} +func (m *UserSendMsgResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserSendMsgResp.Unmarshal(m, b) +} +func (m *UserSendMsgResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserSendMsgResp.Marshal(b, m, deterministic) +} +func (dst *UserSendMsgResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserSendMsgResp.Merge(dst, src) +} +func (m *UserSendMsgResp) XXX_Size() int { + return xxx_messageInfo_UserSendMsgResp.Size(m) +} +func (m *UserSendMsgResp) XXX_DiscardUnknown() { + xxx_messageInfo_UserSendMsgResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UserSendMsgResp proto.InternalMessageInfo + +func (m *UserSendMsgResp) GetServerMsgID() string { + if m != nil { + return m.ServerMsgID + } + return "" +} + +func (m *UserSendMsgResp) GetClientMsgID() string { + if m != nil { + return m.ClientMsgID + } + return "" +} + +func (m *UserSendMsgResp) GetSendTime() int64 { + if m != nil { + return m.SendTime + } + return 0 +} + +type MsgData struct { + SendID string `protobuf:"bytes,1,opt,name=sendID" json:"sendID,omitempty"` + RecvID string `protobuf:"bytes,2,opt,name=recvID" json:"recvID,omitempty"` + GroupID string `protobuf:"bytes,3,opt,name=groupID" json:"groupID,omitempty"` + ClientMsgID string `protobuf:"bytes,4,opt,name=clientMsgID" json:"clientMsgID,omitempty"` + ServerMsgID string `protobuf:"bytes,5,opt,name=serverMsgID" json:"serverMsgID,omitempty"` + SenderPlatformID int32 `protobuf:"varint,6,opt,name=senderPlatformID" json:"senderPlatformID,omitempty"` + SenderNickname string `protobuf:"bytes,7,opt,name=senderNickname" json:"senderNickname,omitempty"` + SenderFaceURL string `protobuf:"bytes,8,opt,name=senderFaceURL" json:"senderFaceURL,omitempty"` + SessionType int32 `protobuf:"varint,9,opt,name=sessionType" json:"sessionType,omitempty"` + MsgFrom int32 `protobuf:"varint,10,opt,name=msgFrom" json:"msgFrom,omitempty"` + ContentType int32 `protobuf:"varint,11,opt,name=contentType" json:"contentType,omitempty"` + Content []byte `protobuf:"bytes,12,opt,name=content,proto3" json:"content,omitempty"` + Seq uint32 `protobuf:"varint,14,opt,name=seq" json:"seq,omitempty"` + SendTime int64 `protobuf:"varint,15,opt,name=sendTime" json:"sendTime,omitempty"` + CreateTime int64 `protobuf:"varint,16,opt,name=createTime" json:"createTime,omitempty"` + Status int32 `protobuf:"varint,17,opt,name=status" json:"status,omitempty"` + Options map[string]bool `protobuf:"bytes,18,rep,name=options" json:"options,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,19,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MsgData) Reset() { *m = MsgData{} } +func (m *MsgData) String() string { return proto.CompactTextString(m) } +func (*MsgData) ProtoMessage() {} +func (*MsgData) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{17} +} +func (m *MsgData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MsgData.Unmarshal(m, b) +} +func (m *MsgData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MsgData.Marshal(b, m, deterministic) +} +func (dst *MsgData) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgData.Merge(dst, src) +} +func (m *MsgData) XXX_Size() int { + return xxx_messageInfo_MsgData.Size(m) +} +func (m *MsgData) XXX_DiscardUnknown() { + xxx_messageInfo_MsgData.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgData proto.InternalMessageInfo + +func (m *MsgData) GetSendID() string { + if m != nil { + return m.SendID + } + return "" +} + +func (m *MsgData) GetRecvID() string { + if m != nil { + return m.RecvID + } + return "" +} + +func (m *MsgData) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *MsgData) GetClientMsgID() string { + if m != nil { + return m.ClientMsgID + } + return "" +} + +func (m *MsgData) GetServerMsgID() string { + if m != nil { + return m.ServerMsgID + } + return "" +} + +func (m *MsgData) GetSenderPlatformID() int32 { + if m != nil { + return m.SenderPlatformID + } + return 0 +} + +func (m *MsgData) GetSenderNickname() string { + if m != nil { + return m.SenderNickname + } + return "" +} + +func (m *MsgData) GetSenderFaceURL() string { + if m != nil { + return m.SenderFaceURL + } + return "" +} + +func (m *MsgData) GetSessionType() int32 { + if m != nil { + return m.SessionType + } + return 0 +} + +func (m *MsgData) GetMsgFrom() int32 { + if m != nil { + return m.MsgFrom + } + return 0 +} + +func (m *MsgData) GetContentType() int32 { + if m != nil { + return m.ContentType + } + return 0 +} + +func (m *MsgData) GetContent() []byte { + if m != nil { + return m.Content + } + return nil +} + +func (m *MsgData) GetSeq() uint32 { + if m != nil { + return m.Seq + } + return 0 +} + +func (m *MsgData) GetSendTime() int64 { + if m != nil { + return m.SendTime + } + return 0 +} + +func (m *MsgData) GetCreateTime() int64 { + if m != nil { + return m.CreateTime + } + return 0 +} + +func (m *MsgData) GetStatus() int32 { + if m != nil { + return m.Status + } + return 0 +} + +func (m *MsgData) GetOptions() map[string]bool { + if m != nil { + return m.Options + } + return nil +} + +func (m *MsgData) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +type OfflinePushInfo struct { + Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc" json:"desc,omitempty"` + Ex string `protobuf:"bytes,3,opt,name=ex" json:"ex,omitempty"` + IOSPushSound string `protobuf:"bytes,4,opt,name=iOSPushSound" json:"iOSPushSound,omitempty"` + IOSBadgeCount bool `protobuf:"varint,5,opt,name=iOSBadgeCount" json:"iOSBadgeCount,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OfflinePushInfo) Reset() { *m = OfflinePushInfo{} } +func (m *OfflinePushInfo) String() string { return proto.CompactTextString(m) } +func (*OfflinePushInfo) ProtoMessage() {} +func (*OfflinePushInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{18} +} +func (m *OfflinePushInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OfflinePushInfo.Unmarshal(m, b) +} +func (m *OfflinePushInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OfflinePushInfo.Marshal(b, m, deterministic) +} +func (dst *OfflinePushInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_OfflinePushInfo.Merge(dst, src) +} +func (m *OfflinePushInfo) XXX_Size() int { + return xxx_messageInfo_OfflinePushInfo.Size(m) +} +func (m *OfflinePushInfo) XXX_DiscardUnknown() { + xxx_messageInfo_OfflinePushInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_OfflinePushInfo proto.InternalMessageInfo + +func (m *OfflinePushInfo) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *OfflinePushInfo) GetDesc() string { + if m != nil { + return m.Desc + } + return "" +} + +func (m *OfflinePushInfo) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +func (m *OfflinePushInfo) GetIOSPushSound() string { + if m != nil { + return m.IOSPushSound + } + return "" +} + +func (m *OfflinePushInfo) GetIOSBadgeCount() bool { + if m != nil { + return m.IOSBadgeCount + } + return false +} + +type TipsComm struct { + Detail []byte `protobuf:"bytes,1,opt,name=detail,proto3" json:"detail,omitempty"` + DefaultTips string `protobuf:"bytes,2,opt,name=defaultTips" json:"defaultTips,omitempty"` + JsonDetail string `protobuf:"bytes,3,opt,name=jsonDetail" json:"jsonDetail,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TipsComm) Reset() { *m = TipsComm{} } +func (m *TipsComm) String() string { return proto.CompactTextString(m) } +func (*TipsComm) ProtoMessage() {} +func (*TipsComm) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{19} +} +func (m *TipsComm) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TipsComm.Unmarshal(m, b) +} +func (m *TipsComm) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TipsComm.Marshal(b, m, deterministic) +} +func (dst *TipsComm) XXX_Merge(src proto.Message) { + xxx_messageInfo_TipsComm.Merge(dst, src) +} +func (m *TipsComm) XXX_Size() int { + return xxx_messageInfo_TipsComm.Size(m) +} +func (m *TipsComm) XXX_DiscardUnknown() { + xxx_messageInfo_TipsComm.DiscardUnknown(m) +} + +var xxx_messageInfo_TipsComm proto.InternalMessageInfo + +func (m *TipsComm) GetDetail() []byte { + if m != nil { + return m.Detail + } + return nil +} + +func (m *TipsComm) GetDefaultTips() string { + if m != nil { + return m.DefaultTips + } + return "" +} + +func (m *TipsComm) GetJsonDetail() string { + if m != nil { + return m.JsonDetail + } + return "" +} + +// OnGroupCreated() +type GroupCreatedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + MemberList []*GroupMemberFullInfo `protobuf:"bytes,3,rep,name=memberList" json:"memberList,omitempty"` + OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` + GroupOwnerUser *GroupMemberFullInfo `protobuf:"bytes,5,opt,name=groupOwnerUser" json:"groupOwnerUser,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupCreatedTips) Reset() { *m = GroupCreatedTips{} } +func (m *GroupCreatedTips) String() string { return proto.CompactTextString(m) } +func (*GroupCreatedTips) ProtoMessage() {} +func (*GroupCreatedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{20} +} +func (m *GroupCreatedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupCreatedTips.Unmarshal(m, b) +} +func (m *GroupCreatedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupCreatedTips.Marshal(b, m, deterministic) +} +func (dst *GroupCreatedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupCreatedTips.Merge(dst, src) +} +func (m *GroupCreatedTips) XXX_Size() int { + return xxx_messageInfo_GroupCreatedTips.Size(m) +} +func (m *GroupCreatedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupCreatedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupCreatedTips proto.InternalMessageInfo + +func (m *GroupCreatedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupCreatedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupCreatedTips) GetMemberList() []*GroupMemberFullInfo { + if m != nil { + return m.MemberList + } + return nil +} + +func (m *GroupCreatedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +func (m *GroupCreatedTips) GetGroupOwnerUser() *GroupMemberFullInfo { + if m != nil { + return m.GroupOwnerUser + } + return nil +} + +// OnGroupInfoSet() +type GroupInfoSetTips struct { + OpUser *GroupMemberFullInfo `protobuf:"bytes,1,opt,name=opUser" json:"opUser,omitempty"` + MuteTime int64 `protobuf:"varint,2,opt,name=muteTime" json:"muteTime,omitempty"` + Group *GroupInfo `protobuf:"bytes,3,opt,name=group" json:"group,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupInfoSetTips) Reset() { *m = GroupInfoSetTips{} } +func (m *GroupInfoSetTips) String() string { return proto.CompactTextString(m) } +func (*GroupInfoSetTips) ProtoMessage() {} +func (*GroupInfoSetTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{21} +} +func (m *GroupInfoSetTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupInfoSetTips.Unmarshal(m, b) +} +func (m *GroupInfoSetTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupInfoSetTips.Marshal(b, m, deterministic) +} +func (dst *GroupInfoSetTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupInfoSetTips.Merge(dst, src) +} +func (m *GroupInfoSetTips) XXX_Size() int { + return xxx_messageInfo_GroupInfoSetTips.Size(m) +} +func (m *GroupInfoSetTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupInfoSetTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupInfoSetTips proto.InternalMessageInfo + +func (m *GroupInfoSetTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupInfoSetTips) GetMuteTime() int64 { + if m != nil { + return m.MuteTime + } + return 0 +} + +func (m *GroupInfoSetTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +// OnJoinGroupApplication() +type JoinGroupApplicationTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + Applicant *PublicUserInfo `protobuf:"bytes,2,opt,name=applicant" json:"applicant,omitempty"` + ReqMsg string `protobuf:"bytes,3,opt,name=reqMsg" json:"reqMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *JoinGroupApplicationTips) Reset() { *m = JoinGroupApplicationTips{} } +func (m *JoinGroupApplicationTips) String() string { return proto.CompactTextString(m) } +func (*JoinGroupApplicationTips) ProtoMessage() {} +func (*JoinGroupApplicationTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{22} +} +func (m *JoinGroupApplicationTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_JoinGroupApplicationTips.Unmarshal(m, b) +} +func (m *JoinGroupApplicationTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_JoinGroupApplicationTips.Marshal(b, m, deterministic) +} +func (dst *JoinGroupApplicationTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_JoinGroupApplicationTips.Merge(dst, src) +} +func (m *JoinGroupApplicationTips) XXX_Size() int { + return xxx_messageInfo_JoinGroupApplicationTips.Size(m) +} +func (m *JoinGroupApplicationTips) XXX_DiscardUnknown() { + xxx_messageInfo_JoinGroupApplicationTips.DiscardUnknown(m) +} + +var xxx_messageInfo_JoinGroupApplicationTips proto.InternalMessageInfo + +func (m *JoinGroupApplicationTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *JoinGroupApplicationTips) GetApplicant() *PublicUserInfo { + if m != nil { + return m.Applicant + } + return nil +} + +func (m *JoinGroupApplicationTips) GetReqMsg() string { + if m != nil { + return m.ReqMsg + } + return "" +} + +// OnQuitGroup() +// Actively leave the group +type MemberQuitTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + QuitUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=quitUser" json:"quitUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemberQuitTips) Reset() { *m = MemberQuitTips{} } +func (m *MemberQuitTips) String() string { return proto.CompactTextString(m) } +func (*MemberQuitTips) ProtoMessage() {} +func (*MemberQuitTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{23} +} +func (m *MemberQuitTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MemberQuitTips.Unmarshal(m, b) +} +func (m *MemberQuitTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MemberQuitTips.Marshal(b, m, deterministic) +} +func (dst *MemberQuitTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemberQuitTips.Merge(dst, src) +} +func (m *MemberQuitTips) XXX_Size() int { + return xxx_messageInfo_MemberQuitTips.Size(m) +} +func (m *MemberQuitTips) XXX_DiscardUnknown() { + xxx_messageInfo_MemberQuitTips.DiscardUnknown(m) +} + +var xxx_messageInfo_MemberQuitTips proto.InternalMessageInfo + +func (m *MemberQuitTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *MemberQuitTips) GetQuitUser() *GroupMemberFullInfo { + if m != nil { + return m.QuitUser + } + return nil +} + +func (m *MemberQuitTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +// OnApplicationGroupAccepted() +type GroupApplicationAcceptedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + HandleMsg string `protobuf:"bytes,4,opt,name=handleMsg" json:"handleMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupApplicationAcceptedTips) Reset() { *m = GroupApplicationAcceptedTips{} } +func (m *GroupApplicationAcceptedTips) String() string { return proto.CompactTextString(m) } +func (*GroupApplicationAcceptedTips) ProtoMessage() {} +func (*GroupApplicationAcceptedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{24} +} +func (m *GroupApplicationAcceptedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupApplicationAcceptedTips.Unmarshal(m, b) +} +func (m *GroupApplicationAcceptedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupApplicationAcceptedTips.Marshal(b, m, deterministic) +} +func (dst *GroupApplicationAcceptedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupApplicationAcceptedTips.Merge(dst, src) +} +func (m *GroupApplicationAcceptedTips) XXX_Size() int { + return xxx_messageInfo_GroupApplicationAcceptedTips.Size(m) +} +func (m *GroupApplicationAcceptedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupApplicationAcceptedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupApplicationAcceptedTips proto.InternalMessageInfo + +func (m *GroupApplicationAcceptedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupApplicationAcceptedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupApplicationAcceptedTips) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +// OnApplicationGroupRejected() +type GroupApplicationRejectedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + HandleMsg string `protobuf:"bytes,4,opt,name=handleMsg" json:"handleMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupApplicationRejectedTips) Reset() { *m = GroupApplicationRejectedTips{} } +func (m *GroupApplicationRejectedTips) String() string { return proto.CompactTextString(m) } +func (*GroupApplicationRejectedTips) ProtoMessage() {} +func (*GroupApplicationRejectedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{25} +} +func (m *GroupApplicationRejectedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupApplicationRejectedTips.Unmarshal(m, b) +} +func (m *GroupApplicationRejectedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupApplicationRejectedTips.Marshal(b, m, deterministic) +} +func (dst *GroupApplicationRejectedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupApplicationRejectedTips.Merge(dst, src) +} +func (m *GroupApplicationRejectedTips) XXX_Size() int { + return xxx_messageInfo_GroupApplicationRejectedTips.Size(m) +} +func (m *GroupApplicationRejectedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupApplicationRejectedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupApplicationRejectedTips proto.InternalMessageInfo + +func (m *GroupApplicationRejectedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupApplicationRejectedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupApplicationRejectedTips) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +// OnTransferGroupOwner() +type GroupOwnerTransferredTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + NewGroupOwner *GroupMemberFullInfo `protobuf:"bytes,3,opt,name=newGroupOwner" json:"newGroupOwner,omitempty"` + OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupOwnerTransferredTips) Reset() { *m = GroupOwnerTransferredTips{} } +func (m *GroupOwnerTransferredTips) String() string { return proto.CompactTextString(m) } +func (*GroupOwnerTransferredTips) ProtoMessage() {} +func (*GroupOwnerTransferredTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{26} +} +func (m *GroupOwnerTransferredTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupOwnerTransferredTips.Unmarshal(m, b) +} +func (m *GroupOwnerTransferredTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupOwnerTransferredTips.Marshal(b, m, deterministic) +} +func (dst *GroupOwnerTransferredTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupOwnerTransferredTips.Merge(dst, src) +} +func (m *GroupOwnerTransferredTips) XXX_Size() int { + return xxx_messageInfo_GroupOwnerTransferredTips.Size(m) +} +func (m *GroupOwnerTransferredTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupOwnerTransferredTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupOwnerTransferredTips proto.InternalMessageInfo + +func (m *GroupOwnerTransferredTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupOwnerTransferredTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupOwnerTransferredTips) GetNewGroupOwner() *GroupMemberFullInfo { + if m != nil { + return m.NewGroupOwner + } + return nil +} + +func (m *GroupOwnerTransferredTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +// OnMemberKicked() +type MemberKickedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + KickedUserList []*GroupMemberFullInfo `protobuf:"bytes,3,rep,name=kickedUserList" json:"kickedUserList,omitempty"` + OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemberKickedTips) Reset() { *m = MemberKickedTips{} } +func (m *MemberKickedTips) String() string { return proto.CompactTextString(m) } +func (*MemberKickedTips) ProtoMessage() {} +func (*MemberKickedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{27} +} +func (m *MemberKickedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MemberKickedTips.Unmarshal(m, b) +} +func (m *MemberKickedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MemberKickedTips.Marshal(b, m, deterministic) +} +func (dst *MemberKickedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemberKickedTips.Merge(dst, src) +} +func (m *MemberKickedTips) XXX_Size() int { + return xxx_messageInfo_MemberKickedTips.Size(m) +} +func (m *MemberKickedTips) XXX_DiscardUnknown() { + xxx_messageInfo_MemberKickedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_MemberKickedTips proto.InternalMessageInfo + +func (m *MemberKickedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *MemberKickedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *MemberKickedTips) GetKickedUserList() []*GroupMemberFullInfo { + if m != nil { + return m.KickedUserList + } + return nil +} + +func (m *MemberKickedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +// OnMemberInvited() +type MemberInvitedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + InvitedUserList []*GroupMemberFullInfo `protobuf:"bytes,3,rep,name=invitedUserList" json:"invitedUserList,omitempty"` + OperationTime int64 `protobuf:"varint,4,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemberInvitedTips) Reset() { *m = MemberInvitedTips{} } +func (m *MemberInvitedTips) String() string { return proto.CompactTextString(m) } +func (*MemberInvitedTips) ProtoMessage() {} +func (*MemberInvitedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{28} +} +func (m *MemberInvitedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MemberInvitedTips.Unmarshal(m, b) +} +func (m *MemberInvitedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MemberInvitedTips.Marshal(b, m, deterministic) +} +func (dst *MemberInvitedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemberInvitedTips.Merge(dst, src) +} +func (m *MemberInvitedTips) XXX_Size() int { + return xxx_messageInfo_MemberInvitedTips.Size(m) +} +func (m *MemberInvitedTips) XXX_DiscardUnknown() { + xxx_messageInfo_MemberInvitedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_MemberInvitedTips proto.InternalMessageInfo + +func (m *MemberInvitedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *MemberInvitedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *MemberInvitedTips) GetInvitedUserList() []*GroupMemberFullInfo { + if m != nil { + return m.InvitedUserList + } + return nil +} + +func (m *MemberInvitedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +// Actively join the group +type MemberEnterTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + EntrantUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=entrantUser" json:"entrantUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemberEnterTips) Reset() { *m = MemberEnterTips{} } +func (m *MemberEnterTips) String() string { return proto.CompactTextString(m) } +func (*MemberEnterTips) ProtoMessage() {} +func (*MemberEnterTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{29} +} +func (m *MemberEnterTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MemberEnterTips.Unmarshal(m, b) +} +func (m *MemberEnterTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MemberEnterTips.Marshal(b, m, deterministic) +} +func (dst *MemberEnterTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemberEnterTips.Merge(dst, src) +} +func (m *MemberEnterTips) XXX_Size() int { + return xxx_messageInfo_MemberEnterTips.Size(m) +} +func (m *MemberEnterTips) XXX_DiscardUnknown() { + xxx_messageInfo_MemberEnterTips.DiscardUnknown(m) +} + +var xxx_messageInfo_MemberEnterTips proto.InternalMessageInfo + +func (m *MemberEnterTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *MemberEnterTips) GetEntrantUser() *GroupMemberFullInfo { + if m != nil { + return m.EntrantUser + } + return nil +} + +func (m *MemberEnterTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +type GroupDismissedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupDismissedTips) Reset() { *m = GroupDismissedTips{} } +func (m *GroupDismissedTips) String() string { return proto.CompactTextString(m) } +func (*GroupDismissedTips) ProtoMessage() {} +func (*GroupDismissedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{30} +} +func (m *GroupDismissedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupDismissedTips.Unmarshal(m, b) +} +func (m *GroupDismissedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupDismissedTips.Marshal(b, m, deterministic) +} +func (dst *GroupDismissedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupDismissedTips.Merge(dst, src) +} +func (m *GroupDismissedTips) XXX_Size() int { + return xxx_messageInfo_GroupDismissedTips.Size(m) +} +func (m *GroupDismissedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupDismissedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupDismissedTips proto.InternalMessageInfo + +func (m *GroupDismissedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupDismissedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupDismissedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +type GroupMemberMutedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + MutedUser *GroupMemberFullInfo `protobuf:"bytes,4,opt,name=mutedUser" json:"mutedUser,omitempty"` + MutedSeconds uint32 `protobuf:"varint,5,opt,name=mutedSeconds" json:"mutedSeconds,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupMemberMutedTips) Reset() { *m = GroupMemberMutedTips{} } +func (m *GroupMemberMutedTips) String() string { return proto.CompactTextString(m) } +func (*GroupMemberMutedTips) ProtoMessage() {} +func (*GroupMemberMutedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{31} +} +func (m *GroupMemberMutedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupMemberMutedTips.Unmarshal(m, b) +} +func (m *GroupMemberMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupMemberMutedTips.Marshal(b, m, deterministic) +} +func (dst *GroupMemberMutedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupMemberMutedTips.Merge(dst, src) +} +func (m *GroupMemberMutedTips) XXX_Size() int { + return xxx_messageInfo_GroupMemberMutedTips.Size(m) +} +func (m *GroupMemberMutedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupMemberMutedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupMemberMutedTips proto.InternalMessageInfo + +func (m *GroupMemberMutedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupMemberMutedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupMemberMutedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +func (m *GroupMemberMutedTips) GetMutedUser() *GroupMemberFullInfo { + if m != nil { + return m.MutedUser + } + return nil +} + +func (m *GroupMemberMutedTips) GetMutedSeconds() uint32 { + if m != nil { + return m.MutedSeconds + } + return 0 +} + +type GroupMemberCancelMutedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + MutedUser *GroupMemberFullInfo `protobuf:"bytes,4,opt,name=mutedUser" json:"mutedUser,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupMemberCancelMutedTips) Reset() { *m = GroupMemberCancelMutedTips{} } +func (m *GroupMemberCancelMutedTips) String() string { return proto.CompactTextString(m) } +func (*GroupMemberCancelMutedTips) ProtoMessage() {} +func (*GroupMemberCancelMutedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{32} +} +func (m *GroupMemberCancelMutedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupMemberCancelMutedTips.Unmarshal(m, b) +} +func (m *GroupMemberCancelMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupMemberCancelMutedTips.Marshal(b, m, deterministic) +} +func (dst *GroupMemberCancelMutedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupMemberCancelMutedTips.Merge(dst, src) +} +func (m *GroupMemberCancelMutedTips) XXX_Size() int { + return xxx_messageInfo_GroupMemberCancelMutedTips.Size(m) +} +func (m *GroupMemberCancelMutedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupMemberCancelMutedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupMemberCancelMutedTips proto.InternalMessageInfo + +func (m *GroupMemberCancelMutedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupMemberCancelMutedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupMemberCancelMutedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +func (m *GroupMemberCancelMutedTips) GetMutedUser() *GroupMemberFullInfo { + if m != nil { + return m.MutedUser + } + return nil +} + +type GroupMutedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupMutedTips) Reset() { *m = GroupMutedTips{} } +func (m *GroupMutedTips) String() string { return proto.CompactTextString(m) } +func (*GroupMutedTips) ProtoMessage() {} +func (*GroupMutedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{33} +} +func (m *GroupMutedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupMutedTips.Unmarshal(m, b) +} +func (m *GroupMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupMutedTips.Marshal(b, m, deterministic) +} +func (dst *GroupMutedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupMutedTips.Merge(dst, src) +} +func (m *GroupMutedTips) XXX_Size() int { + return xxx_messageInfo_GroupMutedTips.Size(m) +} +func (m *GroupMutedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupMutedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupMutedTips proto.InternalMessageInfo + +func (m *GroupMutedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupMutedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupMutedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +type GroupCancelMutedTips struct { + Group *GroupInfo `protobuf:"bytes,1,opt,name=group" json:"group,omitempty"` + OpUser *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=opUser" json:"opUser,omitempty"` + OperationTime int64 `protobuf:"varint,3,opt,name=operationTime" json:"operationTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GroupCancelMutedTips) Reset() { *m = GroupCancelMutedTips{} } +func (m *GroupCancelMutedTips) String() string { return proto.CompactTextString(m) } +func (*GroupCancelMutedTips) ProtoMessage() {} +func (*GroupCancelMutedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{34} +} +func (m *GroupCancelMutedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GroupCancelMutedTips.Unmarshal(m, b) +} +func (m *GroupCancelMutedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GroupCancelMutedTips.Marshal(b, m, deterministic) +} +func (dst *GroupCancelMutedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupCancelMutedTips.Merge(dst, src) +} +func (m *GroupCancelMutedTips) XXX_Size() int { + return xxx_messageInfo_GroupCancelMutedTips.Size(m) +} +func (m *GroupCancelMutedTips) XXX_DiscardUnknown() { + xxx_messageInfo_GroupCancelMutedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupCancelMutedTips proto.InternalMessageInfo + +func (m *GroupCancelMutedTips) GetGroup() *GroupInfo { + if m != nil { + return m.Group + } + return nil +} + +func (m *GroupCancelMutedTips) GetOpUser() *GroupMemberFullInfo { + if m != nil { + return m.OpUser + } + return nil +} + +func (m *GroupCancelMutedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +type FriendApplication struct { + AddTime int64 `protobuf:"varint,1,opt,name=addTime" json:"addTime,omitempty"` + AddSource string `protobuf:"bytes,2,opt,name=addSource" json:"addSource,omitempty"` + AddWording string `protobuf:"bytes,3,opt,name=addWording" json:"addWording,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendApplication) Reset() { *m = FriendApplication{} } +func (m *FriendApplication) String() string { return proto.CompactTextString(m) } +func (*FriendApplication) ProtoMessage() {} +func (*FriendApplication) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{35} +} +func (m *FriendApplication) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendApplication.Unmarshal(m, b) +} +func (m *FriendApplication) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendApplication.Marshal(b, m, deterministic) +} +func (dst *FriendApplication) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendApplication.Merge(dst, src) +} +func (m *FriendApplication) XXX_Size() int { + return xxx_messageInfo_FriendApplication.Size(m) +} +func (m *FriendApplication) XXX_DiscardUnknown() { + xxx_messageInfo_FriendApplication.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendApplication proto.InternalMessageInfo + +func (m *FriendApplication) GetAddTime() int64 { + if m != nil { + return m.AddTime + } + return 0 +} + +func (m *FriendApplication) GetAddSource() string { + if m != nil { + return m.AddSource + } + return "" +} + +func (m *FriendApplication) GetAddWording() string { + if m != nil { + return m.AddWording + } + return "" +} + +type FromToUserID struct { + FromUserID string `protobuf:"bytes,1,opt,name=fromUserID" json:"fromUserID,omitempty"` + ToUserID string `protobuf:"bytes,2,opt,name=toUserID" json:"toUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FromToUserID) Reset() { *m = FromToUserID{} } +func (m *FromToUserID) String() string { return proto.CompactTextString(m) } +func (*FromToUserID) ProtoMessage() {} +func (*FromToUserID) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{36} +} +func (m *FromToUserID) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FromToUserID.Unmarshal(m, b) +} +func (m *FromToUserID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FromToUserID.Marshal(b, m, deterministic) +} +func (dst *FromToUserID) XXX_Merge(src proto.Message) { + xxx_messageInfo_FromToUserID.Merge(dst, src) +} +func (m *FromToUserID) XXX_Size() int { + return xxx_messageInfo_FromToUserID.Size(m) +} +func (m *FromToUserID) XXX_DiscardUnknown() { + xxx_messageInfo_FromToUserID.DiscardUnknown(m) +} + +var xxx_messageInfo_FromToUserID proto.InternalMessageInfo + +func (m *FromToUserID) GetFromUserID() string { + if m != nil { + return m.FromUserID + } + return "" +} + +func (m *FromToUserID) GetToUserID() string { + if m != nil { + return m.ToUserID + } + return "" +} + +// FromUserID apply to add ToUserID +type FriendApplicationTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendApplicationTips) Reset() { *m = FriendApplicationTips{} } +func (m *FriendApplicationTips) String() string { return proto.CompactTextString(m) } +func (*FriendApplicationTips) ProtoMessage() {} +func (*FriendApplicationTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{37} +} +func (m *FriendApplicationTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendApplicationTips.Unmarshal(m, b) +} +func (m *FriendApplicationTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendApplicationTips.Marshal(b, m, deterministic) +} +func (dst *FriendApplicationTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendApplicationTips.Merge(dst, src) +} +func (m *FriendApplicationTips) XXX_Size() int { + return xxx_messageInfo_FriendApplicationTips.Size(m) +} +func (m *FriendApplicationTips) XXX_DiscardUnknown() { + xxx_messageInfo_FriendApplicationTips.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendApplicationTips proto.InternalMessageInfo + +func (m *FriendApplicationTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +// FromUserID accept or reject ToUserID +type FriendApplicationApprovedTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + HandleMsg string `protobuf:"bytes,2,opt,name=handleMsg" json:"handleMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendApplicationApprovedTips) Reset() { *m = FriendApplicationApprovedTips{} } +func (m *FriendApplicationApprovedTips) String() string { return proto.CompactTextString(m) } +func (*FriendApplicationApprovedTips) ProtoMessage() {} +func (*FriendApplicationApprovedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{38} +} +func (m *FriendApplicationApprovedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendApplicationApprovedTips.Unmarshal(m, b) +} +func (m *FriendApplicationApprovedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendApplicationApprovedTips.Marshal(b, m, deterministic) +} +func (dst *FriendApplicationApprovedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendApplicationApprovedTips.Merge(dst, src) +} +func (m *FriendApplicationApprovedTips) XXX_Size() int { + return xxx_messageInfo_FriendApplicationApprovedTips.Size(m) +} +func (m *FriendApplicationApprovedTips) XXX_DiscardUnknown() { + xxx_messageInfo_FriendApplicationApprovedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendApplicationApprovedTips proto.InternalMessageInfo + +func (m *FriendApplicationApprovedTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +func (m *FriendApplicationApprovedTips) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +// FromUserID accept or reject ToUserID +type FriendApplicationRejectedTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + HandleMsg string `protobuf:"bytes,2,opt,name=handleMsg" json:"handleMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendApplicationRejectedTips) Reset() { *m = FriendApplicationRejectedTips{} } +func (m *FriendApplicationRejectedTips) String() string { return proto.CompactTextString(m) } +func (*FriendApplicationRejectedTips) ProtoMessage() {} +func (*FriendApplicationRejectedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{39} +} +func (m *FriendApplicationRejectedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendApplicationRejectedTips.Unmarshal(m, b) +} +func (m *FriendApplicationRejectedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendApplicationRejectedTips.Marshal(b, m, deterministic) +} +func (dst *FriendApplicationRejectedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendApplicationRejectedTips.Merge(dst, src) +} +func (m *FriendApplicationRejectedTips) XXX_Size() int { + return xxx_messageInfo_FriendApplicationRejectedTips.Size(m) +} +func (m *FriendApplicationRejectedTips) XXX_DiscardUnknown() { + xxx_messageInfo_FriendApplicationRejectedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendApplicationRejectedTips proto.InternalMessageInfo + +func (m *FriendApplicationRejectedTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +func (m *FriendApplicationRejectedTips) GetHandleMsg() string { + if m != nil { + return m.HandleMsg + } + return "" +} + +// FromUserID Added a friend ToUserID +type FriendAddedTips struct { + Friend *FriendInfo `protobuf:"bytes,1,opt,name=friend" json:"friend,omitempty"` + OperationTime int64 `protobuf:"varint,2,opt,name=operationTime" json:"operationTime,omitempty"` + OpUser *PublicUserInfo `protobuf:"bytes,3,opt,name=opUser" json:"opUser,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendAddedTips) Reset() { *m = FriendAddedTips{} } +func (m *FriendAddedTips) String() string { return proto.CompactTextString(m) } +func (*FriendAddedTips) ProtoMessage() {} +func (*FriendAddedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{40} +} +func (m *FriendAddedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendAddedTips.Unmarshal(m, b) +} +func (m *FriendAddedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendAddedTips.Marshal(b, m, deterministic) +} +func (dst *FriendAddedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendAddedTips.Merge(dst, src) +} +func (m *FriendAddedTips) XXX_Size() int { + return xxx_messageInfo_FriendAddedTips.Size(m) +} +func (m *FriendAddedTips) XXX_DiscardUnknown() { + xxx_messageInfo_FriendAddedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendAddedTips proto.InternalMessageInfo + +func (m *FriendAddedTips) GetFriend() *FriendInfo { + if m != nil { + return m.Friend + } + return nil +} + +func (m *FriendAddedTips) GetOperationTime() int64 { + if m != nil { + return m.OperationTime + } + return 0 +} + +func (m *FriendAddedTips) GetOpUser() *PublicUserInfo { + if m != nil { + return m.OpUser + } + return nil +} + +// FromUserID deleted a friend ToUserID +type FriendDeletedTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendDeletedTips) Reset() { *m = FriendDeletedTips{} } +func (m *FriendDeletedTips) String() string { return proto.CompactTextString(m) } +func (*FriendDeletedTips) ProtoMessage() {} +func (*FriendDeletedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{41} +} +func (m *FriendDeletedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendDeletedTips.Unmarshal(m, b) +} +func (m *FriendDeletedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendDeletedTips.Marshal(b, m, deterministic) +} +func (dst *FriendDeletedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendDeletedTips.Merge(dst, src) +} +func (m *FriendDeletedTips) XXX_Size() int { + return xxx_messageInfo_FriendDeletedTips.Size(m) +} +func (m *FriendDeletedTips) XXX_DiscardUnknown() { + xxx_messageInfo_FriendDeletedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendDeletedTips proto.InternalMessageInfo + +func (m *FriendDeletedTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +type BlackAddedTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlackAddedTips) Reset() { *m = BlackAddedTips{} } +func (m *BlackAddedTips) String() string { return proto.CompactTextString(m) } +func (*BlackAddedTips) ProtoMessage() {} +func (*BlackAddedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{42} +} +func (m *BlackAddedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BlackAddedTips.Unmarshal(m, b) +} +func (m *BlackAddedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BlackAddedTips.Marshal(b, m, deterministic) +} +func (dst *BlackAddedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlackAddedTips.Merge(dst, src) +} +func (m *BlackAddedTips) XXX_Size() int { + return xxx_messageInfo_BlackAddedTips.Size(m) +} +func (m *BlackAddedTips) XXX_DiscardUnknown() { + xxx_messageInfo_BlackAddedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_BlackAddedTips proto.InternalMessageInfo + +func (m *BlackAddedTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +type BlackDeletedTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlackDeletedTips) Reset() { *m = BlackDeletedTips{} } +func (m *BlackDeletedTips) String() string { return proto.CompactTextString(m) } +func (*BlackDeletedTips) ProtoMessage() {} +func (*BlackDeletedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{43} +} +func (m *BlackDeletedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BlackDeletedTips.Unmarshal(m, b) +} +func (m *BlackDeletedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BlackDeletedTips.Marshal(b, m, deterministic) +} +func (dst *BlackDeletedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlackDeletedTips.Merge(dst, src) +} +func (m *BlackDeletedTips) XXX_Size() int { + return xxx_messageInfo_BlackDeletedTips.Size(m) +} +func (m *BlackDeletedTips) XXX_DiscardUnknown() { + xxx_messageInfo_BlackDeletedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_BlackDeletedTips proto.InternalMessageInfo + +func (m *BlackDeletedTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +type FriendInfoChangedTips struct { + FromToUserID *FromToUserID `protobuf:"bytes,1,opt,name=fromToUserID" json:"fromToUserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FriendInfoChangedTips) Reset() { *m = FriendInfoChangedTips{} } +func (m *FriendInfoChangedTips) String() string { return proto.CompactTextString(m) } +func (*FriendInfoChangedTips) ProtoMessage() {} +func (*FriendInfoChangedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{44} +} +func (m *FriendInfoChangedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FriendInfoChangedTips.Unmarshal(m, b) +} +func (m *FriendInfoChangedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FriendInfoChangedTips.Marshal(b, m, deterministic) +} +func (dst *FriendInfoChangedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_FriendInfoChangedTips.Merge(dst, src) +} +func (m *FriendInfoChangedTips) XXX_Size() int { + return xxx_messageInfo_FriendInfoChangedTips.Size(m) +} +func (m *FriendInfoChangedTips) XXX_DiscardUnknown() { + xxx_messageInfo_FriendInfoChangedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_FriendInfoChangedTips proto.InternalMessageInfo + +func (m *FriendInfoChangedTips) GetFromToUserID() *FromToUserID { + if m != nil { + return m.FromToUserID + } + return nil +} + +// ////////////////////user///////////////////// +type UserInfoUpdatedTips struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserInfoUpdatedTips) Reset() { *m = UserInfoUpdatedTips{} } +func (m *UserInfoUpdatedTips) String() string { return proto.CompactTextString(m) } +func (*UserInfoUpdatedTips) ProtoMessage() {} +func (*UserInfoUpdatedTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{45} +} +func (m *UserInfoUpdatedTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UserInfoUpdatedTips.Unmarshal(m, b) +} +func (m *UserInfoUpdatedTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UserInfoUpdatedTips.Marshal(b, m, deterministic) +} +func (dst *UserInfoUpdatedTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserInfoUpdatedTips.Merge(dst, src) +} +func (m *UserInfoUpdatedTips) XXX_Size() int { + return xxx_messageInfo_UserInfoUpdatedTips.Size(m) +} +func (m *UserInfoUpdatedTips) XXX_DiscardUnknown() { + xxx_messageInfo_UserInfoUpdatedTips.DiscardUnknown(m) +} + +var xxx_messageInfo_UserInfoUpdatedTips proto.InternalMessageInfo + +func (m *UserInfoUpdatedTips) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +// ////////////////////conversation///////////////////// +type ConversationUpdateTips struct { + UserID string `protobuf:"bytes,1,opt,name=UserID" json:"UserID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConversationUpdateTips) Reset() { *m = ConversationUpdateTips{} } +func (m *ConversationUpdateTips) String() string { return proto.CompactTextString(m) } +func (*ConversationUpdateTips) ProtoMessage() {} +func (*ConversationUpdateTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{46} +} +func (m *ConversationUpdateTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConversationUpdateTips.Unmarshal(m, b) +} +func (m *ConversationUpdateTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConversationUpdateTips.Marshal(b, m, deterministic) +} +func (dst *ConversationUpdateTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConversationUpdateTips.Merge(dst, src) +} +func (m *ConversationUpdateTips) XXX_Size() int { + return xxx_messageInfo_ConversationUpdateTips.Size(m) +} +func (m *ConversationUpdateTips) XXX_DiscardUnknown() { + xxx_messageInfo_ConversationUpdateTips.DiscardUnknown(m) +} + +var xxx_messageInfo_ConversationUpdateTips proto.InternalMessageInfo + +func (m *ConversationUpdateTips) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +type ConversationSetPrivateTips struct { + RecvID string `protobuf:"bytes,1,opt,name=recvID" json:"recvID,omitempty"` + SendID string `protobuf:"bytes,2,opt,name=sendID" json:"sendID,omitempty"` + IsPrivate bool `protobuf:"varint,3,opt,name=isPrivate" json:"isPrivate,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConversationSetPrivateTips) Reset() { *m = ConversationSetPrivateTips{} } +func (m *ConversationSetPrivateTips) String() string { return proto.CompactTextString(m) } +func (*ConversationSetPrivateTips) ProtoMessage() {} +func (*ConversationSetPrivateTips) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{47} +} +func (m *ConversationSetPrivateTips) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConversationSetPrivateTips.Unmarshal(m, b) +} +func (m *ConversationSetPrivateTips) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConversationSetPrivateTips.Marshal(b, m, deterministic) +} +func (dst *ConversationSetPrivateTips) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConversationSetPrivateTips.Merge(dst, src) +} +func (m *ConversationSetPrivateTips) XXX_Size() int { + return xxx_messageInfo_ConversationSetPrivateTips.Size(m) +} +func (m *ConversationSetPrivateTips) XXX_DiscardUnknown() { + xxx_messageInfo_ConversationSetPrivateTips.DiscardUnknown(m) +} + +var xxx_messageInfo_ConversationSetPrivateTips proto.InternalMessageInfo + +func (m *ConversationSetPrivateTips) GetRecvID() string { + if m != nil { + return m.RecvID + } + return "" +} + +func (m *ConversationSetPrivateTips) GetSendID() string { + if m != nil { + return m.SendID + } + return "" +} + +func (m *ConversationSetPrivateTips) GetIsPrivate() bool { + if m != nil { + return m.IsPrivate + } + return false +} + +// /cms +type RequestPagination struct { + PageNumber int32 `protobuf:"varint,1,opt,name=pageNumber" json:"pageNumber,omitempty"` + ShowNumber int32 `protobuf:"varint,2,opt,name=showNumber" json:"showNumber,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RequestPagination) Reset() { *m = RequestPagination{} } +func (m *RequestPagination) String() string { return proto.CompactTextString(m) } +func (*RequestPagination) ProtoMessage() {} +func (*RequestPagination) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{48} +} +func (m *RequestPagination) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RequestPagination.Unmarshal(m, b) +} +func (m *RequestPagination) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RequestPagination.Marshal(b, m, deterministic) +} +func (dst *RequestPagination) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestPagination.Merge(dst, src) +} +func (m *RequestPagination) XXX_Size() int { + return xxx_messageInfo_RequestPagination.Size(m) +} +func (m *RequestPagination) XXX_DiscardUnknown() { + xxx_messageInfo_RequestPagination.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestPagination proto.InternalMessageInfo + +func (m *RequestPagination) GetPageNumber() int32 { + if m != nil { + return m.PageNumber + } + return 0 +} + +func (m *RequestPagination) GetShowNumber() int32 { + if m != nil { + return m.ShowNumber + } + return 0 +} + +type ResponsePagination struct { + CurrentPage int32 `protobuf:"varint,5,opt,name=CurrentPage" json:"CurrentPage,omitempty"` + ShowNumber int32 `protobuf:"varint,6,opt,name=ShowNumber" json:"ShowNumber,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponsePagination) Reset() { *m = ResponsePagination{} } +func (m *ResponsePagination) String() string { return proto.CompactTextString(m) } +func (*ResponsePagination) ProtoMessage() {} +func (*ResponsePagination) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{49} +} +func (m *ResponsePagination) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponsePagination.Unmarshal(m, b) +} +func (m *ResponsePagination) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponsePagination.Marshal(b, m, deterministic) +} +func (dst *ResponsePagination) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponsePagination.Merge(dst, src) +} +func (m *ResponsePagination) XXX_Size() int { + return xxx_messageInfo_ResponsePagination.Size(m) +} +func (m *ResponsePagination) XXX_DiscardUnknown() { + xxx_messageInfo_ResponsePagination.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponsePagination proto.InternalMessageInfo + +func (m *ResponsePagination) GetCurrentPage() int32 { + if m != nil { + return m.CurrentPage + } + return 0 +} + +func (m *ResponsePagination) GetShowNumber() int32 { + if m != nil { + return m.ShowNumber + } + return 0 +} + +// /////////////////signal////////////// +type SignalReq struct { + // Types that are valid to be assigned to Payload: + // *SignalReq_Invite + // *SignalReq_InviteInGroup + // *SignalReq_Cancel + // *SignalReq_Accept + // *SignalReq_HungUp + // *SignalReq_Reject + Payload isSignalReq_Payload `protobuf_oneof:"payload"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalReq) Reset() { *m = SignalReq{} } +func (m *SignalReq) String() string { return proto.CompactTextString(m) } +func (*SignalReq) ProtoMessage() {} +func (*SignalReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{50} +} +func (m *SignalReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalReq.Unmarshal(m, b) +} +func (m *SignalReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalReq.Marshal(b, m, deterministic) +} +func (dst *SignalReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalReq.Merge(dst, src) +} +func (m *SignalReq) XXX_Size() int { + return xxx_messageInfo_SignalReq.Size(m) +} +func (m *SignalReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalReq proto.InternalMessageInfo + +type isSignalReq_Payload interface { + isSignalReq_Payload() +} + +type SignalReq_Invite struct { + Invite *SignalInviteReq `protobuf:"bytes,1,opt,name=invite,oneof"` +} +type SignalReq_InviteInGroup struct { + InviteInGroup *SignalInviteInGroupReq `protobuf:"bytes,2,opt,name=inviteInGroup,oneof"` +} +type SignalReq_Cancel struct { + Cancel *SignalCancelReq `protobuf:"bytes,3,opt,name=cancel,oneof"` +} +type SignalReq_Accept struct { + Accept *SignalAcceptReq `protobuf:"bytes,4,opt,name=accept,oneof"` +} +type SignalReq_HungUp struct { + HungUp *SignalHungUpReq `protobuf:"bytes,5,opt,name=hungUp,oneof"` +} +type SignalReq_Reject struct { + Reject *SignalRejectReq `protobuf:"bytes,6,opt,name=reject,oneof"` +} + +func (*SignalReq_Invite) isSignalReq_Payload() {} +func (*SignalReq_InviteInGroup) isSignalReq_Payload() {} +func (*SignalReq_Cancel) isSignalReq_Payload() {} +func (*SignalReq_Accept) isSignalReq_Payload() {} +func (*SignalReq_HungUp) isSignalReq_Payload() {} +func (*SignalReq_Reject) isSignalReq_Payload() {} + +func (m *SignalReq) GetPayload() isSignalReq_Payload { + if m != nil { + return m.Payload + } + return nil +} + +func (m *SignalReq) GetInvite() *SignalInviteReq { + if x, ok := m.GetPayload().(*SignalReq_Invite); ok { + return x.Invite + } + return nil +} + +func (m *SignalReq) GetInviteInGroup() *SignalInviteInGroupReq { + if x, ok := m.GetPayload().(*SignalReq_InviteInGroup); ok { + return x.InviteInGroup + } + return nil +} + +func (m *SignalReq) GetCancel() *SignalCancelReq { + if x, ok := m.GetPayload().(*SignalReq_Cancel); ok { + return x.Cancel + } + return nil +} + +func (m *SignalReq) GetAccept() *SignalAcceptReq { + if x, ok := m.GetPayload().(*SignalReq_Accept); ok { + return x.Accept + } + return nil +} + +func (m *SignalReq) GetHungUp() *SignalHungUpReq { + if x, ok := m.GetPayload().(*SignalReq_HungUp); ok { + return x.HungUp + } + return nil +} + +func (m *SignalReq) GetReject() *SignalRejectReq { + if x, ok := m.GetPayload().(*SignalReq_Reject); ok { + return x.Reject + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SignalReq) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SignalReq_OneofMarshaler, _SignalReq_OneofUnmarshaler, _SignalReq_OneofSizer, []interface{}{ + (*SignalReq_Invite)(nil), + (*SignalReq_InviteInGroup)(nil), + (*SignalReq_Cancel)(nil), + (*SignalReq_Accept)(nil), + (*SignalReq_HungUp)(nil), + (*SignalReq_Reject)(nil), + } +} + +func _SignalReq_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SignalReq) + // payload + switch x := m.Payload.(type) { + case *SignalReq_Invite: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Invite); err != nil { + return err + } + case *SignalReq_InviteInGroup: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.InviteInGroup); err != nil { + return err + } + case *SignalReq_Cancel: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Cancel); err != nil { + return err + } + case *SignalReq_Accept: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Accept); err != nil { + return err + } + case *SignalReq_HungUp: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.HungUp); err != nil { + return err + } + case *SignalReq_Reject: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Reject); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("SignalReq.Payload has unexpected type %T", x) + } + return nil +} + +func _SignalReq_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SignalReq) + switch tag { + case 1: // payload.invite + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalInviteReq) + err := b.DecodeMessage(msg) + m.Payload = &SignalReq_Invite{msg} + return true, err + case 2: // payload.inviteInGroup + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalInviteInGroupReq) + err := b.DecodeMessage(msg) + m.Payload = &SignalReq_InviteInGroup{msg} + return true, err + case 3: // payload.cancel + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalCancelReq) + err := b.DecodeMessage(msg) + m.Payload = &SignalReq_Cancel{msg} + return true, err + case 4: // payload.accept + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalAcceptReq) + err := b.DecodeMessage(msg) + m.Payload = &SignalReq_Accept{msg} + return true, err + case 5: // payload.hungUp + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalHungUpReq) + err := b.DecodeMessage(msg) + m.Payload = &SignalReq_HungUp{msg} + return true, err + case 6: // payload.reject + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalRejectReq) + err := b.DecodeMessage(msg) + m.Payload = &SignalReq_Reject{msg} + return true, err + default: + return false, nil + } +} + +func _SignalReq_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SignalReq) + // payload + switch x := m.Payload.(type) { + case *SignalReq_Invite: + s := proto.Size(x.Invite) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalReq_InviteInGroup: + s := proto.Size(x.InviteInGroup) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalReq_Cancel: + s := proto.Size(x.Cancel) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalReq_Accept: + s := proto.Size(x.Accept) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalReq_HungUp: + s := proto.Size(x.HungUp) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalReq_Reject: + s := proto.Size(x.Reject) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type SignalResp struct { + // Types that are valid to be assigned to Payload: + // *SignalResp_Invite + // *SignalResp_InviteInGroup + // *SignalResp_Cancel + // *SignalResp_Accept + // *SignalResp_HungUp + // *SignalResp_Reject + Payload isSignalResp_Payload `protobuf_oneof:"payload"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalResp) Reset() { *m = SignalResp{} } +func (m *SignalResp) String() string { return proto.CompactTextString(m) } +func (*SignalResp) ProtoMessage() {} +func (*SignalResp) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{51} +} +func (m *SignalResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalResp.Unmarshal(m, b) +} +func (m *SignalResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalResp.Marshal(b, m, deterministic) +} +func (dst *SignalResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalResp.Merge(dst, src) +} +func (m *SignalResp) XXX_Size() int { + return xxx_messageInfo_SignalResp.Size(m) +} +func (m *SignalResp) XXX_DiscardUnknown() { + xxx_messageInfo_SignalResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalResp proto.InternalMessageInfo + +type isSignalResp_Payload interface { + isSignalResp_Payload() +} + +type SignalResp_Invite struct { + Invite *SignalInviteReply `protobuf:"bytes,1,opt,name=invite,oneof"` +} +type SignalResp_InviteInGroup struct { + InviteInGroup *SignalInviteInGroupReply `protobuf:"bytes,2,opt,name=inviteInGroup,oneof"` +} +type SignalResp_Cancel struct { + Cancel *SignalCancelReply `protobuf:"bytes,3,opt,name=cancel,oneof"` +} +type SignalResp_Accept struct { + Accept *SignalAcceptReply `protobuf:"bytes,4,opt,name=accept,oneof"` +} +type SignalResp_HungUp struct { + HungUp *SignalHungUpReply `protobuf:"bytes,5,opt,name=hungUp,oneof"` +} +type SignalResp_Reject struct { + Reject *SignalRejectReply `protobuf:"bytes,6,opt,name=reject,oneof"` +} + +func (*SignalResp_Invite) isSignalResp_Payload() {} +func (*SignalResp_InviteInGroup) isSignalResp_Payload() {} +func (*SignalResp_Cancel) isSignalResp_Payload() {} +func (*SignalResp_Accept) isSignalResp_Payload() {} +func (*SignalResp_HungUp) isSignalResp_Payload() {} +func (*SignalResp_Reject) isSignalResp_Payload() {} + +func (m *SignalResp) GetPayload() isSignalResp_Payload { + if m != nil { + return m.Payload + } + return nil +} + +func (m *SignalResp) GetInvite() *SignalInviteReply { + if x, ok := m.GetPayload().(*SignalResp_Invite); ok { + return x.Invite + } + return nil +} + +func (m *SignalResp) GetInviteInGroup() *SignalInviteInGroupReply { + if x, ok := m.GetPayload().(*SignalResp_InviteInGroup); ok { + return x.InviteInGroup + } + return nil +} + +func (m *SignalResp) GetCancel() *SignalCancelReply { + if x, ok := m.GetPayload().(*SignalResp_Cancel); ok { + return x.Cancel + } + return nil +} + +func (m *SignalResp) GetAccept() *SignalAcceptReply { + if x, ok := m.GetPayload().(*SignalResp_Accept); ok { + return x.Accept + } + return nil +} + +func (m *SignalResp) GetHungUp() *SignalHungUpReply { + if x, ok := m.GetPayload().(*SignalResp_HungUp); ok { + return x.HungUp + } + return nil +} + +func (m *SignalResp) GetReject() *SignalRejectReply { + if x, ok := m.GetPayload().(*SignalResp_Reject); ok { + return x.Reject + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SignalResp) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SignalResp_OneofMarshaler, _SignalResp_OneofUnmarshaler, _SignalResp_OneofSizer, []interface{}{ + (*SignalResp_Invite)(nil), + (*SignalResp_InviteInGroup)(nil), + (*SignalResp_Cancel)(nil), + (*SignalResp_Accept)(nil), + (*SignalResp_HungUp)(nil), + (*SignalResp_Reject)(nil), + } +} + +func _SignalResp_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SignalResp) + // payload + switch x := m.Payload.(type) { + case *SignalResp_Invite: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Invite); err != nil { + return err + } + case *SignalResp_InviteInGroup: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.InviteInGroup); err != nil { + return err + } + case *SignalResp_Cancel: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Cancel); err != nil { + return err + } + case *SignalResp_Accept: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Accept); err != nil { + return err + } + case *SignalResp_HungUp: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.HungUp); err != nil { + return err + } + case *SignalResp_Reject: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Reject); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("SignalResp.Payload has unexpected type %T", x) + } + return nil +} + +func _SignalResp_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SignalResp) + switch tag { + case 1: // payload.invite + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalInviteReply) + err := b.DecodeMessage(msg) + m.Payload = &SignalResp_Invite{msg} + return true, err + case 2: // payload.inviteInGroup + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalInviteInGroupReply) + err := b.DecodeMessage(msg) + m.Payload = &SignalResp_InviteInGroup{msg} + return true, err + case 3: // payload.cancel + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalCancelReply) + err := b.DecodeMessage(msg) + m.Payload = &SignalResp_Cancel{msg} + return true, err + case 4: // payload.accept + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalAcceptReply) + err := b.DecodeMessage(msg) + m.Payload = &SignalResp_Accept{msg} + return true, err + case 5: // payload.hungUp + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalHungUpReply) + err := b.DecodeMessage(msg) + m.Payload = &SignalResp_HungUp{msg} + return true, err + case 6: // payload.reject + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SignalRejectReply) + err := b.DecodeMessage(msg) + m.Payload = &SignalResp_Reject{msg} + return true, err + default: + return false, nil + } +} + +func _SignalResp_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SignalResp) + // payload + switch x := m.Payload.(type) { + case *SignalResp_Invite: + s := proto.Size(x.Invite) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalResp_InviteInGroup: + s := proto.Size(x.InviteInGroup) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalResp_Cancel: + s := proto.Size(x.Cancel) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalResp_Accept: + s := proto.Size(x.Accept) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalResp_HungUp: + s := proto.Size(x.HungUp) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *SignalResp_Reject: + s := proto.Size(x.Reject) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type InvitationInfo struct { + InviterUserID string `protobuf:"bytes,1,opt,name=inviterUserID" json:"inviterUserID,omitempty"` + InviteeUserIDList []string `protobuf:"bytes,2,rep,name=inviteeUserIDList" json:"inviteeUserIDList,omitempty"` + CustomData string `protobuf:"bytes,3,opt,name=customData" json:"customData,omitempty"` + GroupID string `protobuf:"bytes,4,opt,name=groupID" json:"groupID,omitempty"` + RoomID string `protobuf:"bytes,5,opt,name=roomID" json:"roomID,omitempty"` + Timeout int32 `protobuf:"varint,6,opt,name=timeout" json:"timeout,omitempty"` + MediaType string `protobuf:"bytes,7,opt,name=mediaType" json:"mediaType,omitempty"` + PlatformID int32 `protobuf:"varint,8,opt,name=platformID" json:"platformID,omitempty"` + SessionType int32 `protobuf:"varint,9,opt,name=sessionType" json:"sessionType,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InvitationInfo) Reset() { *m = InvitationInfo{} } +func (m *InvitationInfo) String() string { return proto.CompactTextString(m) } +func (*InvitationInfo) ProtoMessage() {} +func (*InvitationInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{52} +} +func (m *InvitationInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InvitationInfo.Unmarshal(m, b) +} +func (m *InvitationInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InvitationInfo.Marshal(b, m, deterministic) +} +func (dst *InvitationInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_InvitationInfo.Merge(dst, src) +} +func (m *InvitationInfo) XXX_Size() int { + return xxx_messageInfo_InvitationInfo.Size(m) +} +func (m *InvitationInfo) XXX_DiscardUnknown() { + xxx_messageInfo_InvitationInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_InvitationInfo proto.InternalMessageInfo + +func (m *InvitationInfo) GetInviterUserID() string { + if m != nil { + return m.InviterUserID + } + return "" +} + +func (m *InvitationInfo) GetInviteeUserIDList() []string { + if m != nil { + return m.InviteeUserIDList + } + return nil +} + +func (m *InvitationInfo) GetCustomData() string { + if m != nil { + return m.CustomData + } + return "" +} + +func (m *InvitationInfo) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *InvitationInfo) GetRoomID() string { + if m != nil { + return m.RoomID + } + return "" +} + +func (m *InvitationInfo) GetTimeout() int32 { + if m != nil { + return m.Timeout + } + return 0 +} + +func (m *InvitationInfo) GetMediaType() string { + if m != nil { + return m.MediaType + } + return "" +} + +func (m *InvitationInfo) GetPlatformID() int32 { + if m != nil { + return m.PlatformID + } + return 0 +} + +func (m *InvitationInfo) GetSessionType() int32 { + if m != nil { + return m.SessionType + } + return 0 +} + +type ParticipantMetaData struct { + GroupInfo *GroupInfo `protobuf:"bytes,1,opt,name=groupInfo" json:"groupInfo,omitempty"` + GroupMemberInfo *GroupMemberFullInfo `protobuf:"bytes,2,opt,name=groupMemberInfo" json:"groupMemberInfo,omitempty"` + UserInfo *PublicUserInfo `protobuf:"bytes,3,opt,name=userInfo" json:"userInfo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ParticipantMetaData) Reset() { *m = ParticipantMetaData{} } +func (m *ParticipantMetaData) String() string { return proto.CompactTextString(m) } +func (*ParticipantMetaData) ProtoMessage() {} +func (*ParticipantMetaData) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{53} +} +func (m *ParticipantMetaData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ParticipantMetaData.Unmarshal(m, b) +} +func (m *ParticipantMetaData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ParticipantMetaData.Marshal(b, m, deterministic) +} +func (dst *ParticipantMetaData) XXX_Merge(src proto.Message) { + xxx_messageInfo_ParticipantMetaData.Merge(dst, src) +} +func (m *ParticipantMetaData) XXX_Size() int { + return xxx_messageInfo_ParticipantMetaData.Size(m) +} +func (m *ParticipantMetaData) XXX_DiscardUnknown() { + xxx_messageInfo_ParticipantMetaData.DiscardUnknown(m) +} + +var xxx_messageInfo_ParticipantMetaData proto.InternalMessageInfo + +func (m *ParticipantMetaData) GetGroupInfo() *GroupInfo { + if m != nil { + return m.GroupInfo + } + return nil +} + +func (m *ParticipantMetaData) GetGroupMemberInfo() *GroupMemberFullInfo { + if m != nil { + return m.GroupMemberInfo + } + return nil +} + +func (m *ParticipantMetaData) GetUserInfo() *PublicUserInfo { + if m != nil { + return m.UserInfo + } + return nil +} + +type SignalInviteReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalInviteReq) Reset() { *m = SignalInviteReq{} } +func (m *SignalInviteReq) String() string { return proto.CompactTextString(m) } +func (*SignalInviteReq) ProtoMessage() {} +func (*SignalInviteReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{54} +} +func (m *SignalInviteReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalInviteReq.Unmarshal(m, b) +} +func (m *SignalInviteReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalInviteReq.Marshal(b, m, deterministic) +} +func (dst *SignalInviteReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalInviteReq.Merge(dst, src) +} +func (m *SignalInviteReq) XXX_Size() int { + return xxx_messageInfo_SignalInviteReq.Size(m) +} +func (m *SignalInviteReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalInviteReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalInviteReq proto.InternalMessageInfo + +func (m *SignalInviteReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SignalInviteReq) GetInvitation() *InvitationInfo { + if m != nil { + return m.Invitation + } + return nil +} + +func (m *SignalInviteReq) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +func (m *SignalInviteReq) GetParticipant() *ParticipantMetaData { + if m != nil { + return m.Participant + } + return nil +} + +type SignalInviteReply struct { + Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` + RoomID string `protobuf:"bytes,2,opt,name=roomID" json:"roomID,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL" json:"liveURL,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalInviteReply) Reset() { *m = SignalInviteReply{} } +func (m *SignalInviteReply) String() string { return proto.CompactTextString(m) } +func (*SignalInviteReply) ProtoMessage() {} +func (*SignalInviteReply) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{55} +} +func (m *SignalInviteReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalInviteReply.Unmarshal(m, b) +} +func (m *SignalInviteReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalInviteReply.Marshal(b, m, deterministic) +} +func (dst *SignalInviteReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalInviteReply.Merge(dst, src) +} +func (m *SignalInviteReply) XXX_Size() int { + return xxx_messageInfo_SignalInviteReply.Size(m) +} +func (m *SignalInviteReply) XXX_DiscardUnknown() { + xxx_messageInfo_SignalInviteReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalInviteReply proto.InternalMessageInfo + +func (m *SignalInviteReply) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *SignalInviteReply) GetRoomID() string { + if m != nil { + return m.RoomID + } + return "" +} + +func (m *SignalInviteReply) GetLiveURL() string { + if m != nil { + return m.LiveURL + } + return "" +} + +type SignalInviteInGroupReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalInviteInGroupReq) Reset() { *m = SignalInviteInGroupReq{} } +func (m *SignalInviteInGroupReq) String() string { return proto.CompactTextString(m) } +func (*SignalInviteInGroupReq) ProtoMessage() {} +func (*SignalInviteInGroupReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{56} +} +func (m *SignalInviteInGroupReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalInviteInGroupReq.Unmarshal(m, b) +} +func (m *SignalInviteInGroupReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalInviteInGroupReq.Marshal(b, m, deterministic) +} +func (dst *SignalInviteInGroupReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalInviteInGroupReq.Merge(dst, src) +} +func (m *SignalInviteInGroupReq) XXX_Size() int { + return xxx_messageInfo_SignalInviteInGroupReq.Size(m) +} +func (m *SignalInviteInGroupReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalInviteInGroupReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalInviteInGroupReq proto.InternalMessageInfo + +func (m *SignalInviteInGroupReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SignalInviteInGroupReq) GetInvitation() *InvitationInfo { + if m != nil { + return m.Invitation + } + return nil +} + +func (m *SignalInviteInGroupReq) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +func (m *SignalInviteInGroupReq) GetParticipant() *ParticipantMetaData { + if m != nil { + return m.Participant + } + return nil +} + +type SignalInviteInGroupReply struct { + Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` + RoomID string `protobuf:"bytes,2,opt,name=roomID" json:"roomID,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL" json:"liveURL,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalInviteInGroupReply) Reset() { *m = SignalInviteInGroupReply{} } +func (m *SignalInviteInGroupReply) String() string { return proto.CompactTextString(m) } +func (*SignalInviteInGroupReply) ProtoMessage() {} +func (*SignalInviteInGroupReply) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{57} +} +func (m *SignalInviteInGroupReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalInviteInGroupReply.Unmarshal(m, b) +} +func (m *SignalInviteInGroupReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalInviteInGroupReply.Marshal(b, m, deterministic) +} +func (dst *SignalInviteInGroupReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalInviteInGroupReply.Merge(dst, src) +} +func (m *SignalInviteInGroupReply) XXX_Size() int { + return xxx_messageInfo_SignalInviteInGroupReply.Size(m) +} +func (m *SignalInviteInGroupReply) XXX_DiscardUnknown() { + xxx_messageInfo_SignalInviteInGroupReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalInviteInGroupReply proto.InternalMessageInfo + +func (m *SignalInviteInGroupReply) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *SignalInviteInGroupReply) GetRoomID() string { + if m != nil { + return m.RoomID + } + return "" +} + +func (m *SignalInviteInGroupReply) GetLiveURL() string { + if m != nil { + return m.LiveURL + } + return "" +} + +type SignalCancelReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalCancelReq) Reset() { *m = SignalCancelReq{} } +func (m *SignalCancelReq) String() string { return proto.CompactTextString(m) } +func (*SignalCancelReq) ProtoMessage() {} +func (*SignalCancelReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{58} +} +func (m *SignalCancelReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalCancelReq.Unmarshal(m, b) +} +func (m *SignalCancelReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalCancelReq.Marshal(b, m, deterministic) +} +func (dst *SignalCancelReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalCancelReq.Merge(dst, src) +} +func (m *SignalCancelReq) XXX_Size() int { + return xxx_messageInfo_SignalCancelReq.Size(m) +} +func (m *SignalCancelReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalCancelReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalCancelReq proto.InternalMessageInfo + +func (m *SignalCancelReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SignalCancelReq) GetInvitation() *InvitationInfo { + if m != nil { + return m.Invitation + } + return nil +} + +func (m *SignalCancelReq) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +func (m *SignalCancelReq) GetParticipant() *ParticipantMetaData { + if m != nil { + return m.Participant + } + return nil +} + +type SignalCancelReply struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalCancelReply) Reset() { *m = SignalCancelReply{} } +func (m *SignalCancelReply) String() string { return proto.CompactTextString(m) } +func (*SignalCancelReply) ProtoMessage() {} +func (*SignalCancelReply) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{59} +} +func (m *SignalCancelReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalCancelReply.Unmarshal(m, b) +} +func (m *SignalCancelReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalCancelReply.Marshal(b, m, deterministic) +} +func (dst *SignalCancelReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalCancelReply.Merge(dst, src) +} +func (m *SignalCancelReply) XXX_Size() int { + return xxx_messageInfo_SignalCancelReply.Size(m) +} +func (m *SignalCancelReply) XXX_DiscardUnknown() { + xxx_messageInfo_SignalCancelReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalCancelReply proto.InternalMessageInfo + +type SignalAcceptReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` + OpUserPlatformID int32 `protobuf:"varint,5,opt,name=opUserPlatformID" json:"opUserPlatformID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalAcceptReq) Reset() { *m = SignalAcceptReq{} } +func (m *SignalAcceptReq) String() string { return proto.CompactTextString(m) } +func (*SignalAcceptReq) ProtoMessage() {} +func (*SignalAcceptReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{60} +} +func (m *SignalAcceptReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalAcceptReq.Unmarshal(m, b) +} +func (m *SignalAcceptReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalAcceptReq.Marshal(b, m, deterministic) +} +func (dst *SignalAcceptReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalAcceptReq.Merge(dst, src) +} +func (m *SignalAcceptReq) XXX_Size() int { + return xxx_messageInfo_SignalAcceptReq.Size(m) +} +func (m *SignalAcceptReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalAcceptReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalAcceptReq proto.InternalMessageInfo + +func (m *SignalAcceptReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SignalAcceptReq) GetInvitation() *InvitationInfo { + if m != nil { + return m.Invitation + } + return nil +} + +func (m *SignalAcceptReq) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +func (m *SignalAcceptReq) GetParticipant() *ParticipantMetaData { + if m != nil { + return m.Participant + } + return nil +} + +func (m *SignalAcceptReq) GetOpUserPlatformID() int32 { + if m != nil { + return m.OpUserPlatformID + } + return 0 +} + +type SignalAcceptReply struct { + Token string `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` + RoomID string `protobuf:"bytes,2,opt,name=roomID" json:"roomID,omitempty"` + LiveURL string `protobuf:"bytes,3,opt,name=liveURL" json:"liveURL,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalAcceptReply) Reset() { *m = SignalAcceptReply{} } +func (m *SignalAcceptReply) String() string { return proto.CompactTextString(m) } +func (*SignalAcceptReply) ProtoMessage() {} +func (*SignalAcceptReply) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{61} +} +func (m *SignalAcceptReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalAcceptReply.Unmarshal(m, b) +} +func (m *SignalAcceptReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalAcceptReply.Marshal(b, m, deterministic) +} +func (dst *SignalAcceptReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalAcceptReply.Merge(dst, src) +} +func (m *SignalAcceptReply) XXX_Size() int { + return xxx_messageInfo_SignalAcceptReply.Size(m) +} +func (m *SignalAcceptReply) XXX_DiscardUnknown() { + xxx_messageInfo_SignalAcceptReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalAcceptReply proto.InternalMessageInfo + +func (m *SignalAcceptReply) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *SignalAcceptReply) GetRoomID() string { + if m != nil { + return m.RoomID + } + return "" +} + +func (m *SignalAcceptReply) GetLiveURL() string { + if m != nil { + return m.LiveURL + } + return "" +} + +type SignalHungUpReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalHungUpReq) Reset() { *m = SignalHungUpReq{} } +func (m *SignalHungUpReq) String() string { return proto.CompactTextString(m) } +func (*SignalHungUpReq) ProtoMessage() {} +func (*SignalHungUpReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{62} +} +func (m *SignalHungUpReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalHungUpReq.Unmarshal(m, b) +} +func (m *SignalHungUpReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalHungUpReq.Marshal(b, m, deterministic) +} +func (dst *SignalHungUpReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalHungUpReq.Merge(dst, src) +} +func (m *SignalHungUpReq) XXX_Size() int { + return xxx_messageInfo_SignalHungUpReq.Size(m) +} +func (m *SignalHungUpReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalHungUpReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalHungUpReq proto.InternalMessageInfo + +func (m *SignalHungUpReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SignalHungUpReq) GetInvitation() *InvitationInfo { + if m != nil { + return m.Invitation + } + return nil +} + +func (m *SignalHungUpReq) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +type SignalHungUpReply struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalHungUpReply) Reset() { *m = SignalHungUpReply{} } +func (m *SignalHungUpReply) String() string { return proto.CompactTextString(m) } +func (*SignalHungUpReply) ProtoMessage() {} +func (*SignalHungUpReply) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{63} +} +func (m *SignalHungUpReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalHungUpReply.Unmarshal(m, b) +} +func (m *SignalHungUpReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalHungUpReply.Marshal(b, m, deterministic) +} +func (dst *SignalHungUpReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalHungUpReply.Merge(dst, src) +} +func (m *SignalHungUpReply) XXX_Size() int { + return xxx_messageInfo_SignalHungUpReply.Size(m) +} +func (m *SignalHungUpReply) XXX_DiscardUnknown() { + xxx_messageInfo_SignalHungUpReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalHungUpReply proto.InternalMessageInfo + +type SignalRejectReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + Invitation *InvitationInfo `protobuf:"bytes,2,opt,name=invitation" json:"invitation,omitempty"` + OfflinePushInfo *OfflinePushInfo `protobuf:"bytes,3,opt,name=offlinePushInfo" json:"offlinePushInfo,omitempty"` + Participant *ParticipantMetaData `protobuf:"bytes,4,opt,name=participant" json:"participant,omitempty"` + OpUserPlatformID int32 `protobuf:"varint,5,opt,name=opUserPlatformID" json:"opUserPlatformID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalRejectReq) Reset() { *m = SignalRejectReq{} } +func (m *SignalRejectReq) String() string { return proto.CompactTextString(m) } +func (*SignalRejectReq) ProtoMessage() {} +func (*SignalRejectReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{64} +} +func (m *SignalRejectReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalRejectReq.Unmarshal(m, b) +} +func (m *SignalRejectReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalRejectReq.Marshal(b, m, deterministic) +} +func (dst *SignalRejectReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalRejectReq.Merge(dst, src) +} +func (m *SignalRejectReq) XXX_Size() int { + return xxx_messageInfo_SignalRejectReq.Size(m) +} +func (m *SignalRejectReq) XXX_DiscardUnknown() { + xxx_messageInfo_SignalRejectReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalRejectReq proto.InternalMessageInfo + +func (m *SignalRejectReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *SignalRejectReq) GetInvitation() *InvitationInfo { + if m != nil { + return m.Invitation + } + return nil +} + +func (m *SignalRejectReq) GetOfflinePushInfo() *OfflinePushInfo { + if m != nil { + return m.OfflinePushInfo + } + return nil +} + +func (m *SignalRejectReq) GetParticipant() *ParticipantMetaData { + if m != nil { + return m.Participant + } + return nil +} + +func (m *SignalRejectReq) GetOpUserPlatformID() int32 { + if m != nil { + return m.OpUserPlatformID + } + return 0 +} + +type SignalRejectReply struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignalRejectReply) Reset() { *m = SignalRejectReply{} } +func (m *SignalRejectReply) String() string { return proto.CompactTextString(m) } +func (*SignalRejectReply) ProtoMessage() {} +func (*SignalRejectReply) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{65} +} +func (m *SignalRejectReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignalRejectReply.Unmarshal(m, b) +} +func (m *SignalRejectReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignalRejectReply.Marshal(b, m, deterministic) +} +func (dst *SignalRejectReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignalRejectReply.Merge(dst, src) +} +func (m *SignalRejectReply) XXX_Size() int { + return xxx_messageInfo_SignalRejectReply.Size(m) +} +func (m *SignalRejectReply) XXX_DiscardUnknown() { + xxx_messageInfo_SignalRejectReply.DiscardUnknown(m) +} + +var xxx_messageInfo_SignalRejectReply proto.InternalMessageInfo + +type DelMsgListReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=userID" json:"userID,omitempty"` + SeqList []uint32 `protobuf:"varint,3,rep,packed,name=seqList" json:"seqList,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DelMsgListReq) Reset() { *m = DelMsgListReq{} } +func (m *DelMsgListReq) String() string { return proto.CompactTextString(m) } +func (*DelMsgListReq) ProtoMessage() {} +func (*DelMsgListReq) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{66} +} +func (m *DelMsgListReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DelMsgListReq.Unmarshal(m, b) +} +func (m *DelMsgListReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DelMsgListReq.Marshal(b, m, deterministic) +} +func (dst *DelMsgListReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelMsgListReq.Merge(dst, src) +} +func (m *DelMsgListReq) XXX_Size() int { + return xxx_messageInfo_DelMsgListReq.Size(m) +} +func (m *DelMsgListReq) XXX_DiscardUnknown() { + xxx_messageInfo_DelMsgListReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DelMsgListReq proto.InternalMessageInfo + +func (m *DelMsgListReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *DelMsgListReq) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *DelMsgListReq) GetSeqList() []uint32 { + if m != nil { + return m.SeqList + } + return nil +} + +func (m *DelMsgListReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type DelMsgListResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DelMsgListResp) Reset() { *m = DelMsgListResp{} } +func (m *DelMsgListResp) String() string { return proto.CompactTextString(m) } +func (*DelMsgListResp) ProtoMessage() {} +func (*DelMsgListResp) Descriptor() ([]byte, []int) { + return fileDescriptor_ws_822d08ca95807876, []int{67} +} +func (m *DelMsgListResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DelMsgListResp.Unmarshal(m, b) +} +func (m *DelMsgListResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DelMsgListResp.Marshal(b, m, deterministic) +} +func (dst *DelMsgListResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelMsgListResp.Merge(dst, src) +} +func (m *DelMsgListResp) XXX_Size() int { + return xxx_messageInfo_DelMsgListResp.Size(m) +} +func (m *DelMsgListResp) XXX_DiscardUnknown() { + xxx_messageInfo_DelMsgListResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DelMsgListResp proto.InternalMessageInfo + +func (m *DelMsgListResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *DelMsgListResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +func init() { + proto.RegisterType((*GroupInfo)(nil), "server_api_params.GroupInfo") + proto.RegisterType((*GroupMemberFullInfo)(nil), "server_api_params.GroupMemberFullInfo") + proto.RegisterType((*PublicUserInfo)(nil), "server_api_params.PublicUserInfo") + proto.RegisterType((*UserInfo)(nil), "server_api_params.UserInfo") + proto.RegisterType((*FriendInfo)(nil), "server_api_params.FriendInfo") + proto.RegisterType((*BlackInfo)(nil), "server_api_params.BlackInfo") + proto.RegisterType((*GroupRequest)(nil), "server_api_params.GroupRequest") + proto.RegisterType((*FriendRequest)(nil), "server_api_params.FriendRequest") + proto.RegisterType((*Department)(nil), "server_api_params.Department") + proto.RegisterType((*OrganizationUser)(nil), "server_api_params.OrganizationUser") + proto.RegisterType((*DepartmentMember)(nil), "server_api_params.DepartmentMember") + proto.RegisterType((*UserInDepartment)(nil), "server_api_params.UserInDepartment") + proto.RegisterType((*PullMessageBySeqListResp)(nil), "server_api_params.PullMessageBySeqListResp") + proto.RegisterType((*PullMessageBySeqListReq)(nil), "server_api_params.PullMessageBySeqListReq") + proto.RegisterType((*GetMaxAndMinSeqReq)(nil), "server_api_params.GetMaxAndMinSeqReq") + proto.RegisterType((*GetMaxAndMinSeqResp)(nil), "server_api_params.GetMaxAndMinSeqResp") + proto.RegisterType((*UserSendMsgResp)(nil), "server_api_params.UserSendMsgResp") + proto.RegisterType((*MsgData)(nil), "server_api_params.MsgData") + proto.RegisterMapType((map[string]bool)(nil), "server_api_params.MsgData.OptionsEntry") + proto.RegisterType((*OfflinePushInfo)(nil), "server_api_params.OfflinePushInfo") + proto.RegisterType((*TipsComm)(nil), "server_api_params.TipsComm") + proto.RegisterType((*GroupCreatedTips)(nil), "server_api_params.GroupCreatedTips") + proto.RegisterType((*GroupInfoSetTips)(nil), "server_api_params.GroupInfoSetTips") + proto.RegisterType((*JoinGroupApplicationTips)(nil), "server_api_params.JoinGroupApplicationTips") + proto.RegisterType((*MemberQuitTips)(nil), "server_api_params.MemberQuitTips") + proto.RegisterType((*GroupApplicationAcceptedTips)(nil), "server_api_params.GroupApplicationAcceptedTips") + proto.RegisterType((*GroupApplicationRejectedTips)(nil), "server_api_params.GroupApplicationRejectedTips") + proto.RegisterType((*GroupOwnerTransferredTips)(nil), "server_api_params.GroupOwnerTransferredTips") + proto.RegisterType((*MemberKickedTips)(nil), "server_api_params.MemberKickedTips") + proto.RegisterType((*MemberInvitedTips)(nil), "server_api_params.MemberInvitedTips") + proto.RegisterType((*MemberEnterTips)(nil), "server_api_params.MemberEnterTips") + proto.RegisterType((*GroupDismissedTips)(nil), "server_api_params.GroupDismissedTips") + proto.RegisterType((*GroupMemberMutedTips)(nil), "server_api_params.GroupMemberMutedTips") + proto.RegisterType((*GroupMemberCancelMutedTips)(nil), "server_api_params.GroupMemberCancelMutedTips") + proto.RegisterType((*GroupMutedTips)(nil), "server_api_params.GroupMutedTips") + proto.RegisterType((*GroupCancelMutedTips)(nil), "server_api_params.GroupCancelMutedTips") + proto.RegisterType((*FriendApplication)(nil), "server_api_params.FriendApplication") + proto.RegisterType((*FromToUserID)(nil), "server_api_params.FromToUserID") + proto.RegisterType((*FriendApplicationTips)(nil), "server_api_params.FriendApplicationTips") + proto.RegisterType((*FriendApplicationApprovedTips)(nil), "server_api_params.FriendApplicationApprovedTips") + proto.RegisterType((*FriendApplicationRejectedTips)(nil), "server_api_params.FriendApplicationRejectedTips") + proto.RegisterType((*FriendAddedTips)(nil), "server_api_params.FriendAddedTips") + proto.RegisterType((*FriendDeletedTips)(nil), "server_api_params.FriendDeletedTips") + proto.RegisterType((*BlackAddedTips)(nil), "server_api_params.BlackAddedTips") + proto.RegisterType((*BlackDeletedTips)(nil), "server_api_params.BlackDeletedTips") + proto.RegisterType((*FriendInfoChangedTips)(nil), "server_api_params.FriendInfoChangedTips") + proto.RegisterType((*UserInfoUpdatedTips)(nil), "server_api_params.UserInfoUpdatedTips") + proto.RegisterType((*ConversationUpdateTips)(nil), "server_api_params.ConversationUpdateTips") + proto.RegisterType((*ConversationSetPrivateTips)(nil), "server_api_params.ConversationSetPrivateTips") + proto.RegisterType((*RequestPagination)(nil), "server_api_params.RequestPagination") + proto.RegisterType((*ResponsePagination)(nil), "server_api_params.ResponsePagination") + proto.RegisterType((*SignalReq)(nil), "server_api_params.SignalReq") + proto.RegisterType((*SignalResp)(nil), "server_api_params.SignalResp") + proto.RegisterType((*InvitationInfo)(nil), "server_api_params.InvitationInfo") + proto.RegisterType((*ParticipantMetaData)(nil), "server_api_params.ParticipantMetaData") + proto.RegisterType((*SignalInviteReq)(nil), "server_api_params.SignalInviteReq") + proto.RegisterType((*SignalInviteReply)(nil), "server_api_params.SignalInviteReply") + proto.RegisterType((*SignalInviteInGroupReq)(nil), "server_api_params.SignalInviteInGroupReq") + proto.RegisterType((*SignalInviteInGroupReply)(nil), "server_api_params.SignalInviteInGroupReply") + proto.RegisterType((*SignalCancelReq)(nil), "server_api_params.SignalCancelReq") + proto.RegisterType((*SignalCancelReply)(nil), "server_api_params.SignalCancelReply") + proto.RegisterType((*SignalAcceptReq)(nil), "server_api_params.SignalAcceptReq") + proto.RegisterType((*SignalAcceptReply)(nil), "server_api_params.SignalAcceptReply") + proto.RegisterType((*SignalHungUpReq)(nil), "server_api_params.SignalHungUpReq") + proto.RegisterType((*SignalHungUpReply)(nil), "server_api_params.SignalHungUpReply") + proto.RegisterType((*SignalRejectReq)(nil), "server_api_params.SignalRejectReq") + proto.RegisterType((*SignalRejectReply)(nil), "server_api_params.SignalRejectReply") + proto.RegisterType((*DelMsgListReq)(nil), "server_api_params.DelMsgListReq") + proto.RegisterType((*DelMsgListResp)(nil), "server_api_params.DelMsgListResp") +} + +func init() { proto.RegisterFile("sdk_ws/ws.proto", fileDescriptor_ws_822d08ca95807876) } + +var fileDescriptor_ws_822d08ca95807876 = []byte{ + // 2985 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0xcd, 0x6f, 0x24, 0x47, + 0x15, 0xa7, 0x7b, 0x3c, 0x63, 0xcf, 0x1b, 0x8f, 0x3f, 0x7a, 0x17, 0x33, 0x98, 0xcd, 0x62, 0x1a, + 0x2b, 0x84, 0x00, 0x1b, 0x14, 0x84, 0x04, 0x09, 0x2c, 0xf2, 0xd7, 0x7e, 0x04, 0x8f, 0xed, 0xf4, + 0xec, 0x12, 0x04, 0x48, 0x51, 0x7b, 0xba, 0x3c, 0xee, 0xb8, 0xa7, 0xab, 0xa7, 0x3f, 0xbc, 0x6b, + 0x84, 0x84, 0x04, 0x12, 0xe2, 0xc6, 0x09, 0x0e, 0x5c, 0x90, 0xb8, 0x20, 0x50, 0x14, 0x45, 0x08, + 0x6e, 0x11, 0xe2, 0xc0, 0x3f, 0xc0, 0x11, 0x71, 0xe3, 0xcc, 0x95, 0x03, 0x12, 0x12, 0xa8, 0xea, + 0x55, 0x57, 0x57, 0x75, 0xcf, 0xd8, 0x13, 0xcb, 0xca, 0x6e, 0xb4, 0xdc, 0xfc, 0xde, 0xd4, 0x7b, + 0xf5, 0xea, 0xf7, 0x5e, 0xbd, 0xf7, 0xaa, 0xaa, 0x0d, 0x8b, 0x89, 0x77, 0xf2, 0xe6, 0xa3, 0xe4, + 0xa5, 0x47, 0xc9, 0xad, 0x28, 0xa6, 0x29, 0xb5, 0x96, 0x13, 0x12, 0x9f, 0x92, 0xf8, 0x4d, 0x37, + 0xf2, 0xdf, 0x8c, 0xdc, 0xd8, 0x1d, 0x26, 0xf6, 0xbf, 0x4c, 0x68, 0xde, 0x8d, 0x69, 0x16, 0xdd, + 0x0f, 0x8f, 0xa8, 0xd5, 0x81, 0xd9, 0x01, 0x27, 0xb6, 0x3b, 0xc6, 0x9a, 0xf1, 0x42, 0xd3, 0xc9, + 0x49, 0xeb, 0x06, 0x34, 0xf9, 0x9f, 0x7b, 0xee, 0x90, 0x74, 0x4c, 0xfe, 0x5b, 0xc1, 0xb0, 0x6c, + 0x98, 0x0f, 0x69, 0xea, 0x1f, 0xf9, 0x7d, 0x37, 0xf5, 0x69, 0xd8, 0xa9, 0xf1, 0x01, 0x1a, 0x8f, + 0x8d, 0xf1, 0xc3, 0x34, 0xa6, 0x5e, 0xd6, 0xe7, 0x63, 0x66, 0x70, 0x8c, 0xca, 0x63, 0xf3, 0x1f, + 0xb9, 0x7d, 0xf2, 0xd0, 0xd9, 0xed, 0xd4, 0x71, 0x7e, 0x41, 0x5a, 0x6b, 0xd0, 0xa2, 0x8f, 0x42, + 0x12, 0x3f, 0x4c, 0x48, 0x7c, 0x7f, 0xbb, 0xd3, 0xe0, 0xbf, 0xaa, 0x2c, 0xeb, 0x26, 0x40, 0x3f, + 0x26, 0x6e, 0x4a, 0x1e, 0xf8, 0x43, 0xd2, 0x99, 0x5d, 0x33, 0x5e, 0x68, 0x3b, 0x0a, 0x87, 0x69, + 0x18, 0x92, 0xe1, 0x21, 0x89, 0xb7, 0x68, 0x16, 0xa6, 0x9d, 0x39, 0x3e, 0x40, 0x65, 0x59, 0x0b, + 0x60, 0x92, 0xc7, 0x9d, 0x26, 0x57, 0x6d, 0x92, 0xc7, 0xd6, 0x0a, 0x34, 0x92, 0xd4, 0x4d, 0xb3, + 0xa4, 0x03, 0x6b, 0xc6, 0x0b, 0x75, 0x47, 0x50, 0xd6, 0x3a, 0xb4, 0xb9, 0x5e, 0x9a, 0x5b, 0xd3, + 0xe2, 0x22, 0x3a, 0x53, 0x22, 0xf6, 0xe0, 0x2c, 0x22, 0x9d, 0x79, 0xae, 0xa0, 0x60, 0xd8, 0x7f, + 0x33, 0xe1, 0x1a, 0xc7, 0xbd, 0xcb, 0x0d, 0xb8, 0x93, 0x05, 0xc1, 0x05, 0x1e, 0x58, 0x81, 0x46, + 0x86, 0xd3, 0x21, 0xfc, 0x82, 0x62, 0xf3, 0xc4, 0x34, 0x20, 0xbb, 0xe4, 0x94, 0x04, 0x1c, 0xf8, + 0xba, 0x53, 0x30, 0xac, 0x55, 0x98, 0x7b, 0x8b, 0xfa, 0x21, 0xc7, 0x64, 0x86, 0xff, 0x28, 0x69, + 0xf6, 0x5b, 0xe8, 0xf7, 0x4f, 0x42, 0xe6, 0x52, 0x84, 0x5b, 0xd2, 0xaa, 0x27, 0x1a, 0xba, 0x27, + 0x9e, 0x87, 0x05, 0x37, 0x8a, 0xba, 0x6e, 0x38, 0x20, 0x31, 0x4e, 0x3a, 0xcb, 0xf5, 0x96, 0xb8, + 0xcc, 0x1f, 0x6c, 0xa6, 0x1e, 0xcd, 0xe2, 0x3e, 0xe1, 0x70, 0xd7, 0x1d, 0x85, 0xc3, 0xf4, 0xd0, + 0x88, 0xc4, 0x0a, 0x8c, 0x88, 0x7c, 0x89, 0x2b, 0xbc, 0x02, 0xd2, 0x2b, 0xcc, 0x8f, 0x59, 0x4a, + 0x76, 0x42, 0x8f, 0x2f, 0xaa, 0x25, 0xfc, 0x58, 0xb0, 0xec, 0x9f, 0x18, 0xb0, 0x70, 0x90, 0x1d, + 0x06, 0x7e, 0x9f, 0xab, 0x60, 0xb0, 0x16, 0xe0, 0x19, 0x1a, 0x78, 0x2a, 0x04, 0xe6, 0x64, 0x08, + 0x6a, 0x3a, 0x04, 0x2b, 0xd0, 0x18, 0x90, 0xd0, 0x23, 0xb1, 0x80, 0x54, 0x50, 0xc2, 0xd4, 0x7a, + 0x6e, 0xaa, 0xfd, 0x0b, 0x13, 0xe6, 0x3e, 0x60, 0x13, 0xd6, 0xa0, 0x15, 0x1d, 0xd3, 0x90, 0xec, + 0x65, 0x2c, 0xac, 0x84, 0x2d, 0x2a, 0xcb, 0xba, 0x0e, 0xf5, 0x43, 0x3f, 0x4e, 0x8f, 0xb9, 0x5f, + 0xdb, 0x0e, 0x12, 0x8c, 0x4b, 0x86, 0xae, 0x8f, 0xce, 0x6c, 0x3a, 0x48, 0x88, 0x05, 0xcd, 0x49, + 0xec, 0xf5, 0x3d, 0xd6, 0xac, 0xec, 0xb1, 0x6a, 0x6c, 0xc0, 0xb8, 0xd8, 0xb0, 0xff, 0x6d, 0x00, + 0xdc, 0x89, 0x7d, 0x12, 0x7a, 0x1c, 0x9a, 0xd2, 0xe6, 0x36, 0xaa, 0x9b, 0x7b, 0x05, 0x1a, 0x31, + 0x19, 0xba, 0xf1, 0x49, 0x1e, 0xfc, 0x48, 0x95, 0x0c, 0xaa, 0x55, 0x0c, 0x7a, 0x15, 0xe0, 0x88, + 0xcf, 0xc3, 0xf4, 0x70, 0xa8, 0x5a, 0x2f, 0x7f, 0xe2, 0x56, 0x25, 0x0d, 0xde, 0xca, 0xbd, 0xe4, + 0x28, 0xc3, 0xd9, 0xce, 0x72, 0x3d, 0x4f, 0x04, 0x70, 0x1d, 0x77, 0x96, 0x64, 0x8c, 0x89, 0xdf, + 0xc6, 0x39, 0xf1, 0x3b, 0x2b, 0x83, 0xe2, 0x9f, 0x06, 0x34, 0x37, 0x03, 0xb7, 0x7f, 0x32, 0xe5, + 0xd2, 0xf5, 0x25, 0x9a, 0x95, 0x25, 0xde, 0x85, 0xf6, 0x21, 0x53, 0x97, 0x2f, 0x81, 0xa3, 0xd0, + 0x7a, 0xf9, 0x53, 0x63, 0x56, 0xa9, 0x6f, 0x0a, 0x47, 0x97, 0xd3, 0x97, 0x3b, 0x73, 0xf1, 0x72, + 0xeb, 0xe7, 0x2c, 0xb7, 0x21, 0x97, 0xfb, 0x57, 0x13, 0xe6, 0x79, 0xa2, 0x73, 0xc8, 0x28, 0x23, + 0x49, 0x6a, 0x7d, 0x1d, 0xe6, 0xb2, 0xdc, 0x54, 0x63, 0x5a, 0x53, 0xa5, 0x88, 0xf5, 0x8a, 0x48, + 0xab, 0x5c, 0xde, 0xe4, 0xf2, 0x37, 0xc6, 0xc8, 0xcb, 0x9a, 0xe6, 0x14, 0xc3, 0x59, 0x09, 0x3a, + 0x76, 0x43, 0x2f, 0x20, 0x0e, 0x49, 0xb2, 0x20, 0x15, 0xd9, 0x52, 0xe3, 0x61, 0xa4, 0x8d, 0xba, + 0xc9, 0x40, 0x14, 0x28, 0x41, 0x31, 0x74, 0x70, 0x1c, 0xfb, 0x09, 0x97, 0x5e, 0x30, 0xd8, 0x46, + 0x8d, 0xc9, 0x88, 0x7b, 0x08, 0xb7, 0x55, 0x4e, 0x16, 0x73, 0x0a, 0xd4, 0x30, 0x10, 0x34, 0x1e, + 0x73, 0x31, 0xd2, 0x5c, 0x01, 0x56, 0x26, 0x85, 0x53, 0x2e, 0x4c, 0xf6, 0xdf, 0x6b, 0xd0, 0xc6, + 0xed, 0x93, 0x83, 0x7a, 0x93, 0xc5, 0x39, 0x1d, 0x6a, 0x51, 0xa4, 0x70, 0x98, 0x15, 0x8c, 0xda, + 0xd3, 0x13, 0x8d, 0xc6, 0x63, 0xa1, 0xc8, 0xe8, 0x3b, 0x5a, 0xc2, 0x51, 0x59, 0xf9, 0x2c, 0x77, + 0xd5, 0xc4, 0xa3, 0x70, 0x58, 0x2a, 0x4b, 0xa9, 0x16, 0x1d, 0x92, 0x66, 0xb2, 0x29, 0x95, 0xf3, + 0x63, 0x7c, 0x28, 0x1c, 0x86, 0x6f, 0x4a, 0xf3, 0xb9, 0x11, 0xa4, 0x82, 0x81, 0x9a, 0xc5, 0xbc, + 0x58, 0x4a, 0x24, 0x5d, 0xf1, 0x6a, 0xf3, 0x5c, 0xaf, 0x82, 0xe6, 0x55, 0x7d, 0x73, 0xb5, 0x2a, + 0x9b, 0x6b, 0x1d, 0xda, 0xa8, 0x27, 0x0f, 0xfa, 0x79, 0x2c, 0xf5, 0x1a, 0x53, 0x8f, 0x8d, 0x76, + 0x39, 0x36, 0x74, 0xef, 0x2e, 0x4c, 0xf0, 0xee, 0xa2, 0xf4, 0xee, 0xef, 0x4d, 0x80, 0x6d, 0x12, + 0xb9, 0x71, 0x3a, 0x24, 0x61, 0xca, 0x96, 0xe7, 0x49, 0x4a, 0x3a, 0x57, 0xe3, 0xa9, 0x75, 0xc2, + 0xd4, 0xeb, 0x84, 0x05, 0x33, 0x1c, 0x70, 0xf4, 0x26, 0xff, 0x9b, 0x81, 0x19, 0xb9, 0x31, 0x6a, + 0xc3, 0x20, 0x97, 0x34, 0xab, 0x03, 0x34, 0xf6, 0x44, 0xe5, 0xa8, 0x3b, 0x48, 0xb0, 0xcd, 0x5f, + 0xcc, 0xc7, 0x1b, 0x9a, 0x06, 0xe6, 0x75, 0x9d, 0x7b, 0x61, 0x0f, 0xf6, 0x22, 0x2c, 0x25, 0xd9, + 0x61, 0xb1, 0xb8, 0xbd, 0x6c, 0x28, 0xc2, 0xbd, 0xc2, 0x67, 0xa0, 0x62, 0x73, 0xc6, 0x06, 0x61, + 0xa9, 0x29, 0x18, 0xe5, 0xae, 0xc0, 0x7e, 0xdb, 0x84, 0xa5, 0xfd, 0x78, 0xe0, 0x86, 0xfe, 0xf7, + 0x79, 0xbb, 0xc9, 0x13, 0xf8, 0x65, 0x4a, 0xee, 0x1a, 0xb4, 0x48, 0x38, 0x08, 0xfc, 0xe4, 0x78, + 0xaf, 0xc0, 0x4d, 0x65, 0xa9, 0x60, 0xcf, 0x4c, 0x2a, 0xca, 0x75, 0xad, 0x28, 0xaf, 0x40, 0x63, + 0x48, 0x0f, 0xfd, 0x20, 0x8f, 0x7b, 0x41, 0xf1, 0x98, 0x27, 0x01, 0xe1, 0xd5, 0x59, 0xc6, 0x7c, + 0xce, 0x28, 0x0a, 0xf5, 0xdc, 0xd8, 0x42, 0xdd, 0x54, 0x0b, 0xb5, 0x0e, 0x3c, 0x54, 0x80, 0x47, + 0xb8, 0x5a, 0x12, 0xae, 0x3f, 0x1b, 0xb0, 0x54, 0xc0, 0x8d, 0x3d, 0xe8, 0x44, 0xb8, 0x6c, 0x98, + 0xdf, 0x56, 0x23, 0x50, 0x24, 0x0f, 0x95, 0xc7, 0xcc, 0xda, 0xe7, 0x71, 0x83, 0x39, 0x15, 0x09, + 0x06, 0xf4, 0x01, 0x4d, 0x7c, 0xa5, 0xdf, 0x97, 0x34, 0x9b, 0x6d, 0x97, 0xb8, 0x0a, 0x58, 0x48, + 0x31, 0x7e, 0x0f, 0xbb, 0x6e, 0x8c, 0x31, 0x41, 0xb1, 0x25, 0xec, 0xc8, 0x3a, 0xba, 0xf3, 0xd8, + 0x7e, 0xcf, 0x80, 0x25, 0xac, 0x0f, 0xca, 0x66, 0xd9, 0x87, 0x25, 0x5a, 0x8a, 0x02, 0x51, 0x64, + 0x3e, 0x3d, 0xa6, 0x48, 0x94, 0x03, 0xc6, 0xa9, 0x08, 0x5b, 0x6f, 0xc0, 0x75, 0xaf, 0x84, 0xd3, + 0xae, 0x9f, 0xa4, 0x1d, 0x73, 0xad, 0x36, 0x41, 0x69, 0x19, 0x56, 0x67, 0xac, 0x02, 0xfb, 0x07, + 0xd0, 0x39, 0xc8, 0x82, 0xa0, 0x4b, 0x92, 0xc4, 0x1d, 0x90, 0xcd, 0xb3, 0x1e, 0x19, 0x31, 0xbe, + 0x43, 0x92, 0x88, 0x45, 0x18, 0x89, 0xe3, 0x2d, 0xea, 0x11, 0x6e, 0x7c, 0xdd, 0xc9, 0x49, 0x06, + 0x0e, 0x89, 0x63, 0x96, 0x66, 0x44, 0x1f, 0x84, 0x94, 0x75, 0x0b, 0x66, 0x02, 0x66, 0x56, 0x8d, + 0x9b, 0xb5, 0x3a, 0xc6, 0xac, 0x6e, 0x32, 0xd8, 0x76, 0x53, 0xd7, 0xe1, 0xe3, 0xec, 0x21, 0x7c, + 0x6c, 0xfc, 0xec, 0xa3, 0x89, 0x51, 0xc0, 0x3a, 0x15, 0x5e, 0xea, 0x7d, 0x1a, 0xca, 0x20, 0x50, + 0x59, 0xcc, 0xec, 0x04, 0xf5, 0x70, 0x3b, 0xda, 0x4e, 0x4e, 0xda, 0xd7, 0xc1, 0xba, 0x4b, 0xd2, + 0xae, 0xfb, 0x78, 0x23, 0xf4, 0xba, 0x7e, 0xd8, 0x23, 0x23, 0x87, 0x8c, 0xec, 0x1d, 0xb8, 0x56, + 0xe1, 0x26, 0x11, 0xdf, 0x2d, 0xee, 0xe3, 0x1e, 0x19, 0x71, 0x03, 0xda, 0x8e, 0xa0, 0x38, 0x9f, + 0x8f, 0x12, 0x4d, 0x90, 0xa0, 0xec, 0x11, 0x2c, 0x32, 0x57, 0xf5, 0x48, 0xe8, 0x75, 0x93, 0x01, + 0x57, 0xb1, 0x06, 0x2d, 0x44, 0xa0, 0x9b, 0x0c, 0x8a, 0xae, 0x4a, 0x61, 0xb1, 0x11, 0xfd, 0xc0, + 0x67, 0x2e, 0xe1, 0x23, 0xc4, 0x6a, 0x14, 0x16, 0x8b, 0xdd, 0x84, 0x88, 0x43, 0x06, 0x0b, 0xea, + 0x9a, 0x23, 0x69, 0xfb, 0xbd, 0x3a, 0xcc, 0x0a, 0x40, 0xf9, 0x29, 0x91, 0x35, 0xb2, 0x12, 0x2f, + 0xa4, 0xb0, 0xe4, 0xf4, 0x4f, 0x8b, 0xf3, 0x1a, 0x52, 0xea, 0x09, 0xaf, 0xa6, 0x9f, 0xf0, 0x4a, + 0x36, 0xcd, 0x54, 0x6d, 0x2a, 0xad, 0xab, 0x5e, 0x5d, 0x17, 0xcb, 0xb0, 0x3c, 0xe9, 0x1c, 0x04, + 0x6e, 0x7a, 0x44, 0xe3, 0xa1, 0xe8, 0x4b, 0xeb, 0x4e, 0x85, 0xcf, 0xb2, 0x3a, 0xf2, 0x64, 0x59, + 0xc6, 0xdd, 0x55, 0xe2, 0xb2, 0x22, 0x88, 0x9c, 0xbc, 0x3c, 0xe3, 0x81, 0x40, 0x67, 0xa2, 0x6d, + 0x49, 0xe2, 0xd3, 0x90, 0x17, 0x08, 0xac, 0xc2, 0x2a, 0x8b, 0xad, 0x7c, 0x98, 0x0c, 0xee, 0xc4, + 0x74, 0x28, 0x8e, 0x05, 0x39, 0xc9, 0x57, 0x4e, 0xc3, 0x34, 0x2f, 0x2e, 0x2d, 0x94, 0x55, 0x58, + 0x4c, 0x56, 0x90, 0xbc, 0x04, 0xcf, 0x3b, 0x39, 0x69, 0x2d, 0x41, 0x2d, 0x21, 0x23, 0x51, 0x57, + 0xd9, 0x9f, 0x9a, 0xe7, 0x16, 0x75, 0xcf, 0x95, 0x12, 0xe5, 0x12, 0xff, 0x55, 0x4d, 0x94, 0xc5, + 0x99, 0x7f, 0x59, 0x3b, 0xf3, 0x6f, 0xc0, 0x2c, 0x8d, 0x58, 0x9c, 0x27, 0x1d, 0x8b, 0xef, 0xb1, + 0xcf, 0x4c, 0xde, 0x63, 0xb7, 0xf6, 0x71, 0xe4, 0x4e, 0x98, 0xc6, 0x67, 0x4e, 0x2e, 0x67, 0xed, + 0xc2, 0x22, 0x3d, 0x3a, 0x0a, 0xfc, 0x90, 0x1c, 0x64, 0xc9, 0x31, 0xef, 0x5f, 0xaf, 0xf1, 0xd4, + 0x64, 0x8f, 0x4b, 0x4d, 0xfa, 0x48, 0xa7, 0x2c, 0xba, 0xfa, 0x0a, 0xcc, 0xab, 0xd3, 0x30, 0x18, + 0x4e, 0xc8, 0x99, 0x88, 0x41, 0xf6, 0x27, 0x4b, 0xc9, 0xa7, 0x6e, 0x90, 0x61, 0x89, 0x9b, 0x73, + 0x90, 0x78, 0xc5, 0xfc, 0x8a, 0x61, 0xff, 0xdc, 0x80, 0xc5, 0xd2, 0x04, 0x6c, 0x74, 0xea, 0xa7, + 0x01, 0x11, 0x1a, 0x90, 0x60, 0xed, 0x83, 0x47, 0x92, 0xbe, 0x08, 0x61, 0xfe, 0xb7, 0xa8, 0x25, + 0x35, 0x79, 0x28, 0xb4, 0x61, 0xde, 0xdf, 0xef, 0x31, 0x45, 0x3d, 0x9a, 0x85, 0x9e, 0xbc, 0xd8, + 0x51, 0x78, 0x2c, 0x84, 0xfc, 0xfd, 0xde, 0xa6, 0xeb, 0x0d, 0x08, 0x5e, 0xbf, 0xd4, 0xb9, 0x4d, + 0x3a, 0xd3, 0xf6, 0x60, 0xee, 0x81, 0x1f, 0x25, 0x5b, 0x74, 0x38, 0x64, 0x8e, 0xf0, 0x48, 0xca, + 0x0a, 0x9d, 0xc1, 0xfd, 0x2d, 0x28, 0x16, 0x2a, 0x1e, 0x39, 0x72, 0xb3, 0x20, 0x65, 0x43, 0xf3, + 0x8d, 0xab, 0xb0, 0xf8, 0xc5, 0x43, 0x42, 0xc3, 0x6d, 0x94, 0x46, 0x3b, 0x15, 0x8e, 0xfd, 0x17, + 0x13, 0x96, 0xf8, 0xf1, 0x60, 0x8b, 0xbb, 0xdd, 0xe3, 0x42, 0x2f, 0x43, 0x9d, 0x6f, 0x43, 0x51, + 0x2d, 0xce, 0x3f, 0x52, 0xe0, 0x50, 0xeb, 0x36, 0x34, 0x68, 0xc4, 0x4b, 0x0c, 0x9e, 0x43, 0x9e, + 0x9f, 0x24, 0xa4, 0xdf, 0xf1, 0x38, 0x42, 0xca, 0xba, 0x03, 0x30, 0x2c, 0x2a, 0x0a, 0xa6, 0xee, + 0x69, 0x75, 0x28, 0x92, 0x0c, 0x5c, 0x99, 0x86, 0xe5, 0x45, 0x4f, 0xcd, 0xd1, 0x99, 0xd6, 0x1e, + 0x2c, 0x70, 0xb3, 0xf7, 0xf3, 0xb3, 0x25, 0xf7, 0xc1, 0xf4, 0x33, 0x96, 0xa4, 0xed, 0x5f, 0x1b, + 0x02, 0x46, 0xf6, 0x6b, 0x8f, 0x20, 0xf6, 0x05, 0x24, 0xc6, 0xa5, 0x20, 0x59, 0x85, 0xb9, 0x61, + 0xa6, 0x1c, 0x75, 0x6b, 0x8e, 0xa4, 0x0b, 0x17, 0xd5, 0xa6, 0x76, 0x91, 0xfd, 0x1b, 0x03, 0x3a, + 0xaf, 0x51, 0x3f, 0xe4, 0x3f, 0x6c, 0x44, 0x51, 0x20, 0x6e, 0x23, 0x2f, 0xed, 0xf3, 0x6f, 0x40, + 0xd3, 0x45, 0x35, 0x61, 0x2a, 0xdc, 0x3e, 0xc5, 0xf1, 0xb5, 0x90, 0x51, 0x4e, 0x22, 0x35, 0xf5, + 0x24, 0x62, 0xbf, 0x63, 0xc0, 0x02, 0x82, 0xf2, 0x7a, 0xe6, 0xa7, 0x97, 0xb6, 0x6f, 0x13, 0xe6, + 0x46, 0x99, 0x9f, 0x5e, 0x22, 0x2a, 0xa5, 0x5c, 0x35, 0x9e, 0x6a, 0x63, 0xe2, 0xc9, 0x7e, 0xd7, + 0x80, 0x1b, 0x65, 0x58, 0x37, 0xfa, 0x7d, 0x12, 0x3d, 0xc9, 0x2d, 0xa5, 0x9d, 0xc4, 0x66, 0x4a, + 0x27, 0xb1, 0xb1, 0x26, 0x3b, 0xe4, 0x2d, 0xd2, 0x7f, 0x7a, 0x4d, 0xfe, 0xb1, 0x09, 0x1f, 0xbf, + 0x2b, 0x37, 0xde, 0x83, 0xd8, 0x0d, 0x93, 0x23, 0x12, 0xc7, 0x4f, 0xd0, 0xde, 0x5d, 0x68, 0x87, + 0xe4, 0x51, 0x61, 0x93, 0xd8, 0x8e, 0xd3, 0xaa, 0xd1, 0x85, 0xa7, 0xcb, 0x5d, 0xf6, 0x7f, 0x0c, + 0x58, 0x42, 0x3d, 0xdf, 0xf4, 0xfb, 0x27, 0x4f, 0x70, 0xf1, 0x7b, 0xb0, 0x70, 0xc2, 0x2d, 0x60, + 0xd4, 0x25, 0xd2, 0x76, 0x49, 0x7a, 0xca, 0xe5, 0xff, 0xd7, 0x80, 0x65, 0x54, 0x74, 0x3f, 0x3c, + 0xf5, 0x9f, 0x64, 0xb0, 0x1e, 0xc0, 0xa2, 0x8f, 0x26, 0x5c, 0x12, 0x80, 0xb2, 0xf8, 0x94, 0x08, + 0xfc, 0xd1, 0x80, 0x45, 0xd4, 0xb4, 0x13, 0xa6, 0x24, 0xbe, 0xf4, 0xfa, 0xef, 0xb1, 0xd3, 0x7d, + 0x1a, 0xbb, 0xe1, 0x65, 0x32, 0xa4, 0x2a, 0x3a, 0x65, 0x92, 0x7c, 0xc7, 0x00, 0x8b, 0xab, 0xda, + 0xf6, 0x93, 0xa1, 0x9f, 0x24, 0x4f, 0xd0, 0x75, 0xd3, 0x19, 0xfc, 0x4b, 0x13, 0xae, 0x2b, 0x5a, + 0xba, 0x59, 0xfa, 0xb4, 0x9b, 0x6c, 0x6d, 0x43, 0x93, 0xf5, 0x08, 0xea, 0x15, 0xff, 0xb4, 0x13, + 0x15, 0x82, 0xac, 0x8b, 0xe5, 0x44, 0x8f, 0xf4, 0x69, 0xe8, 0x25, 0xbc, 0x39, 0x6a, 0x3b, 0x1a, + 0x8f, 0xa5, 0xa1, 0x55, 0x45, 0xcd, 0x96, 0x1b, 0xf6, 0x49, 0xf0, 0xcc, 0x40, 0x64, 0xff, 0xce, + 0x80, 0x05, 0x1c, 0xf2, 0xf4, 0x2f, 0x99, 0xd5, 0x7a, 0x0c, 0xe4, 0x0f, 0x8d, 0x97, 0xec, 0x13, + 0x58, 0xc6, 0x5b, 0x7d, 0xa5, 0x3d, 0x61, 0x07, 0x5f, 0xd7, 0xc3, 0xb3, 0xac, 0xc1, 0x85, 0x72, + 0x52, 0x7f, 0xaf, 0x11, 0x4f, 0xf2, 0xc5, 0x7b, 0xcd, 0x4d, 0x00, 0xd7, 0xf3, 0xde, 0xa0, 0xb1, + 0xe7, 0x87, 0x79, 0xaf, 0xa9, 0x70, 0xec, 0xd7, 0x60, 0x9e, 0x1d, 0xbd, 0x1f, 0x28, 0xf7, 0xf3, + 0xe7, 0xbe, 0x20, 0xa8, 0x77, 0xfb, 0xa6, 0x7e, 0xb7, 0x6f, 0x7f, 0x0f, 0x3e, 0x5a, 0x31, 0x9c, + 0x63, 0xbd, 0x85, 0xcf, 0x0e, 0xf9, 0x24, 0x02, 0xf2, 0x4f, 0x8e, 0x41, 0x4f, 0xb5, 0xc5, 0xd1, + 0x84, 0xec, 0x1f, 0x19, 0xf0, 0x5c, 0x45, 0xfd, 0x46, 0x14, 0xc5, 0xf4, 0x54, 0xb8, 0xf4, 0x2a, + 0xa6, 0xd1, 0xfb, 0x30, 0xb3, 0xdc, 0x87, 0x8d, 0x35, 0x42, 0xeb, 0x1d, 0x3f, 0x00, 0x23, 0x7e, + 0x6b, 0xc0, 0xa2, 0x30, 0xc2, 0xf3, 0xc4, 0xb4, 0x5f, 0x86, 0x06, 0x3e, 0x59, 0x8a, 0x09, 0x9f, + 0x1b, 0x3b, 0x61, 0xfe, 0xd4, 0xea, 0x88, 0xc1, 0xd5, 0x88, 0x34, 0xc7, 0xe5, 0x8d, 0xaf, 0xca, + 0xb8, 0x9f, 0xfa, 0x51, 0x51, 0x08, 0xd8, 0xdf, 0xce, 0x83, 0x79, 0x9b, 0x04, 0xe4, 0x2a, 0x31, + 0xb2, 0x1f, 0xc2, 0x02, 0x7f, 0x3f, 0x2d, 0x30, 0xb8, 0x12, 0xb5, 0x6f, 0xc0, 0x12, 0x57, 0x7b, + 0xe5, 0xf6, 0xca, 0xdd, 0xc1, 0xf0, 0xd9, 0x3a, 0x76, 0xc3, 0xc1, 0x55, 0x6a, 0xff, 0x02, 0x5c, + 0xcb, 0xb1, 0x7f, 0x18, 0x79, 0xf2, 0x3e, 0x63, 0xc2, 0x2d, 0xae, 0xfd, 0x45, 0x58, 0xd9, 0xa2, + 0xe1, 0x29, 0x89, 0x13, 0xbc, 0xe3, 0xe6, 0x22, 0xb9, 0x84, 0xb6, 0xf9, 0x05, 0x65, 0xbf, 0x05, + 0xab, 0xaa, 0x44, 0x8f, 0xa4, 0x07, 0xb1, 0x7f, 0xaa, 0x48, 0x89, 0x5b, 0x4e, 0x43, 0xbb, 0xe5, + 0x2c, 0x6e, 0x45, 0x4d, 0xed, 0x56, 0xf4, 0x06, 0x34, 0xfd, 0x44, 0x28, 0xe0, 0x41, 0x35, 0xe7, + 0x14, 0x0c, 0xbb, 0x07, 0xcb, 0xe2, 0x45, 0xf3, 0xc0, 0x1d, 0xf8, 0x21, 0x66, 0xc0, 0x9b, 0x00, + 0x91, 0x3b, 0xc8, 0xbf, 0x68, 0xc0, 0x0b, 0x71, 0x85, 0xc3, 0x7e, 0x4f, 0x8e, 0xe9, 0x23, 0xf1, + 0xbb, 0x89, 0xbf, 0x17, 0x1c, 0xfb, 0x5b, 0x60, 0x39, 0x24, 0x89, 0x68, 0x98, 0x10, 0x45, 0xeb, + 0x1a, 0xb4, 0xb6, 0xb2, 0x38, 0x26, 0x21, 0x9b, 0x2a, 0x7f, 0xde, 0x57, 0x59, 0x4c, 0x6f, 0xaf, + 0xd0, 0x8b, 0x97, 0xa8, 0x0a, 0xc7, 0xfe, 0x55, 0x0d, 0x9a, 0x3d, 0x7f, 0x10, 0xba, 0x81, 0x43, + 0x46, 0xd6, 0xd7, 0xa0, 0x81, 0xad, 0xad, 0x70, 0xe3, 0xb8, 0x4b, 0x3d, 0x1c, 0x8d, 0x3d, 0xbc, + 0x43, 0x46, 0xf7, 0x3e, 0xe2, 0x08, 0x19, 0xeb, 0x75, 0x68, 0xe3, 0x5f, 0xf7, 0xf1, 0xaa, 0x42, + 0xd4, 0x99, 0xcf, 0x5e, 0xa0, 0x44, 0x8c, 0x46, 0x5d, 0xba, 0x06, 0x66, 0x50, 0x9f, 0x97, 0x3e, + 0xb1, 0x77, 0x27, 0x1b, 0x84, 0x15, 0x52, 0x18, 0x84, 0x32, 0x4c, 0xda, 0xe5, 0x87, 0x79, 0xd1, + 0x2e, 0x4c, 0x96, 0xc6, 0x33, 0xbf, 0x90, 0x46, 0x19, 0x26, 0x7d, 0x9c, 0x85, 0x83, 0x87, 0x91, + 0xb8, 0x63, 0x9a, 0x2c, 0x7d, 0x8f, 0x0f, 0x13, 0xd2, 0x28, 0xc3, 0xa4, 0x63, 0x9e, 0x59, 0x39, + 0xe8, 0xe7, 0x49, 0x63, 0x02, 0x16, 0xd2, 0x28, 0xb3, 0xd9, 0x84, 0xd9, 0xc8, 0x3d, 0x0b, 0xa8, + 0xeb, 0xd9, 0x6f, 0xd7, 0x00, 0xf2, 0x81, 0x09, 0xaf, 0xe2, 0x9a, 0x8b, 0xd6, 0x2f, 0x74, 0x51, + 0x14, 0x9c, 0x29, 0x4e, 0xea, 0x8d, 0x77, 0xd2, 0xe7, 0xa6, 0x75, 0x12, 0x6a, 0x2b, 0xb9, 0xe9, + 0x76, 0xc9, 0x4d, 0xeb, 0x17, 0xba, 0x49, 0x18, 0x25, 0x1c, 0x75, 0xbb, 0xe4, 0xa8, 0xf5, 0x0b, + 0x1d, 0x25, 0xe4, 0x85, 0xab, 0x6e, 0x97, 0x5c, 0xb5, 0x7e, 0xa1, 0xab, 0x84, 0xbc, 0x70, 0xd6, + 0xed, 0x92, 0xb3, 0xd6, 0x2f, 0x74, 0x96, 0x90, 0xaf, 0xba, 0xeb, 0x5d, 0x13, 0x16, 0x38, 0x64, + 0xf8, 0xa0, 0x14, 0x1e, 0x51, 0x7e, 0x6f, 0xcc, 0xe1, 0xd2, 0x3f, 0x90, 0xd1, 0x99, 0xd6, 0xe7, + 0x61, 0x19, 0x19, 0xe2, 0x83, 0x0a, 0xf9, 0x42, 0xd7, 0x74, 0xaa, 0x3f, 0xf0, 0x27, 0x80, 0x2c, + 0x49, 0xe9, 0x70, 0xdb, 0x4d, 0xdd, 0xbc, 0x33, 0x2a, 0x38, 0xea, 0x03, 0xcd, 0x4c, 0xe5, 0x13, + 0xbc, 0x98, 0xd2, 0xa1, 0x7c, 0x79, 0x11, 0x14, 0x93, 0x48, 0xfd, 0x21, 0xa1, 0x59, 0x2a, 0xd2, + 0x44, 0x4e, 0xe2, 0x23, 0xb6, 0xe7, 0xbb, 0xfc, 0x59, 0x43, 0xbc, 0xf0, 0x4a, 0x06, 0xcf, 0x6c, + 0xc5, 0x33, 0x8d, 0xf8, 0x44, 0xae, 0xe0, 0x5c, 0xfc, 0xa4, 0x62, 0xff, 0xc3, 0x80, 0x6b, 0x07, + 0x6e, 0x9c, 0xfa, 0x7d, 0x3f, 0x72, 0xc3, 0xb4, 0x4b, 0x52, 0x97, 0xaf, 0x41, 0xfb, 0x4a, 0xc6, + 0x78, 0x7f, 0x5f, 0xc9, 0x1c, 0xc0, 0xe2, 0xa0, 0xe8, 0x65, 0x95, 0xef, 0x6c, 0xa6, 0x3e, 0xe3, + 0x97, 0xc4, 0xb5, 0x4f, 0x7e, 0x6a, 0xef, 0xfb, 0x93, 0x1f, 0xfb, 0xa7, 0x26, 0x2c, 0x96, 0x52, + 0x27, 0x6b, 0x47, 0xb1, 0xd1, 0x90, 0x31, 0x21, 0x69, 0x6b, 0x03, 0xc0, 0x97, 0x61, 0x74, 0xce, + 0x25, 0xad, 0x1e, 0x6b, 0x8e, 0x22, 0x34, 0xee, 0xad, 0xa6, 0x76, 0xe9, 0xb7, 0x1a, 0xeb, 0x1e, + 0xb4, 0xa2, 0xc2, 0x49, 0xe7, 0x1c, 0xc0, 0xc6, 0xb8, 0xd2, 0x51, 0x45, 0xed, 0xef, 0xc2, 0x72, + 0x25, 0x43, 0xf1, 0xa7, 0x1b, 0x7a, 0x42, 0x42, 0xf9, 0x74, 0xc3, 0x08, 0x25, 0x58, 0xcd, 0x72, + 0xb0, 0x06, 0xfe, 0xa9, 0xfa, 0x4d, 0xa1, 0x20, 0xed, 0x9f, 0x99, 0xb0, 0x32, 0xbe, 0xba, 0x3c, + 0xab, 0x70, 0x1f, 0x42, 0x67, 0x52, 0x26, 0xbf, 0x32, 0xd4, 0x8b, 0xe8, 0x96, 0x75, 0xf8, 0x59, + 0x85, 0xfb, 0x5a, 0x1e, 0xdd, 0x4a, 0xa9, 0xb3, 0xff, 0x20, 0xf1, 0x91, 0x9d, 0xc6, 0x33, 0x8a, + 0x8f, 0xf5, 0x22, 0x2c, 0xe1, 0x32, 0x95, 0xc7, 0x7d, 0x6c, 0x5c, 0x2b, 0xfc, 0x22, 0x53, 0x28, + 0x65, 0xff, 0xca, 0x62, 0xf6, 0x4f, 0x46, 0xee, 0x13, 0xd9, 0xbf, 0x7d, 0xa8, 0x7c, 0x52, 0x44, + 0x9a, 0xd2, 0xd4, 0x28, 0x91, 0x26, 0xfb, 0xca, 0xff, 0x47, 0xda, 0xc5, 0x91, 0x26, 0xb1, 0x54, + 0x1a, 0x3c, 0xfb, 0x87, 0xd0, 0xde, 0x26, 0x41, 0x37, 0x19, 0xe4, 0x9f, 0x15, 0x9d, 0x07, 0xe4, + 0xa4, 0x7f, 0x6d, 0x98, 0xf8, 0x41, 0x51, 0xf9, 0x63, 0xa4, 0x99, 0xca, 0xc7, 0x48, 0xf6, 0x26, + 0x2c, 0xa8, 0x06, 0x5c, 0xe6, 0xab, 0xaa, 0xcd, 0x1b, 0xdf, 0x59, 0xbd, 0xf5, 0x12, 0xfe, 0x13, + 0xcd, 0xab, 0x15, 0x10, 0x0f, 0x1b, 0xfc, 0x9f, 0x6a, 0xbe, 0xf4, 0xbf, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x6c, 0xa8, 0x04, 0xcf, 0x67, 0x33, 0x00, 0x00, +} diff --git a/pkg/proto/sdk_ws/ws.proto b/pkg/proto/sdk_ws/ws.proto new file mode 100644 index 000000000..ad4de4737 --- /dev/null +++ b/pkg/proto/sdk_ws/ws.proto @@ -0,0 +1,571 @@ +syntax = "proto3"; +option go_package = "./sdk_ws;server_api_params"; +package server_api_params; + +////////////////////////////////base/////////////////////////////// + + +message GroupInfo{ + string groupID = 1; + string groupName = 2; + string notification = 3; + string introduction = 4; + string faceURL = 5; + string ownerUserID = 6; + uint32 createTime = 7; + uint32 memberCount = 8; + string ex = 9; + int32 status = 10; + string creatorUserID = 11; + int32 groupType = 12; +} + + +message GroupMemberFullInfo { + string groupID = 1 ; + string userID = 2 ; + int32 roleLevel = 3; + int32 joinTime = 4; + string nickname = 5; + string faceURL = 6; + int32 appMangerLevel = 7; //if >0 + int32 joinSource = 8; + string operatorUserID = 9; + string ex = 10; + uint32 muteEndTime = 11; +} + +message PublicUserInfo{ + string userID = 1; + string nickname = 2; + string faceURL = 3; + int32 gender = 4; + string ex = 5; +} + +message UserInfo{ + string userID = 1; + string nickname = 2; + string faceURL = 3; + int32 gender = 4; + string phoneNumber = 5; + uint32 birth = 6; + string email = 7; + string ex = 8; + uint32 createTime = 9; + int32 appMangerLevel = 10; +} + +message FriendInfo{ + string ownerUserID = 1; + string remark = 2; + uint32 createTime = 3; + UserInfo friendUser = 4; + int32 addSource = 5; + string operatorUserID = 6; + string ex = 7; +} + +message BlackInfo{ + string ownerUserID = 1; + uint32 createTime = 2; + PublicUserInfo blackUserInfo = 3; + int32 addSource = 4; + string operatorUserID = 5; + string ex = 6; +} + +message GroupRequest{ + PublicUserInfo userInfo = 1; + GroupInfo groupInfo = 2; + int32 handleResult = 3; + string reqMsg = 4; + string handleMsg = 5; + uint32 reqTime = 6; + string handleUserID = 7; + uint32 handleTime = 8; + string ex = 9; +} + +message FriendRequest{ + string fromUserID = 1; + string fromNickname = 2; + string fromFaceURL = 3; + int32 fromGender = 4; + string toUserID = 5; + string toNickname = 6; + string toFaceURL = 7; + int32 toGender = 8; + int32 handleResult = 9; + string reqMsg = 10; + uint32 createTime = 11; + string handlerUserID = 12; + string handleMsg = 13; + uint32 handleTime = 14; + string ex = 15; +} + +///////////////////////////////////organization///////////////////////////////////// + +message Department { + string departmentID = 1; + string faceURL = 2; + string name = 3; + string parentID = 4; + int32 order = 5; + int32 departmentType = 6; + uint32 createTime = 7; + uint32 subDepartmentNum = 8; + uint32 memberNum = 9; + string ex = 10; +} + + + +message OrganizationUser { + string userID = 1; + string nickname = 2; + string englishName = 3; + string faceURL = 4; + int32 gender = 5; + string mobile = 6; + string telephone = 7; + uint32 birth = 8; + string email = 9; + uint32 createTime = 10; + string ex = 11; +} + +message DepartmentMember { + string userID = 1; + string DepartmentID = 2; + int32 Order = 3; + string Position = 4; + int32 Leader = 5; + int32 Status = 6; + string Ex = 7; +} + + + +message UserInDepartment { + OrganizationUser organizationUser = 1; + repeated DepartmentMember departmentMemberList = 2; +} + + + + + +///////////////////////////////////organization end////////////////////////////////// + + + + + + +///////////////////////////////////base end///////////////////////////////////// + +message PullMessageBySeqListResp { + int32 errCode = 1; + string errMsg = 2; + repeated MsgData list = 3; +} +message PullMessageBySeqListReq{ + string userID = 1; + string operationID = 2; + repeated uint32 seqList = 3; +} +message GetMaxAndMinSeqReq { +} +message GetMaxAndMinSeqResp { + uint32 maxSeq = 1; + uint32 minSeq = 2; +} + +message UserSendMsgResp { + string serverMsgID = 1; + string clientMsgID = 2; + int64 sendTime = 3; + +} +message MsgData { + string sendID = 1; + string recvID = 2; + string groupID = 3; + string clientMsgID = 4; + string serverMsgID = 5; + int32 senderPlatformID = 6; + string senderNickname = 7; + string senderFaceURL = 8; + int32 sessionType = 9; + int32 msgFrom = 10; + int32 contentType = 11; + bytes content = 12; + uint32 seq = 14; + int64 sendTime = 15; + int64 createTime = 16; + int32 status = 17; + map<string, bool> options = 18; + OfflinePushInfo offlinePushInfo = 19; +} + +message OfflinePushInfo{ + string title = 1; + string desc = 2; + string ex = 3; + string iOSPushSound = 4; + bool iOSBadgeCount = 5; +} + + + + + + + + + +message TipsComm{ + bytes detail = 1; + string defaultTips = 2; + string jsonDetail = 3; +} + +//////////////////////group///////////////////// + + +// OnGroupCreated() +message GroupCreatedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + repeated GroupMemberFullInfo memberList = 3; + int64 operationTime = 4; + GroupMemberFullInfo groupOwnerUser = 5; +} + +// OnGroupInfoSet() +message GroupInfoSetTips{ + GroupMemberFullInfo opUser = 1; //who do this + int64 muteTime = 2; + GroupInfo group = 3; +} + +// OnJoinGroupApplication() +message JoinGroupApplicationTips{ + GroupInfo group = 1; + PublicUserInfo applicant = 2; + string reqMsg = 3; +} + +// OnQuitGroup() +//Actively leave the group +message MemberQuitTips{ + GroupInfo group = 1; + GroupMemberFullInfo quitUser = 2; + int64 operationTime = 3; +} + + +// OnApplicationGroupAccepted() +message GroupApplicationAcceptedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + string handleMsg = 4; +} + +// OnApplicationGroupRejected() +message GroupApplicationRejectedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + string handleMsg = 4; +} + +// OnTransferGroupOwner() +message GroupOwnerTransferredTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + GroupMemberFullInfo newGroupOwner = 3; + int64 operationTime = 4; +} + + +// OnMemberKicked() +message MemberKickedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + repeated GroupMemberFullInfo kickedUserList = 3; + int64 operationTime = 4; +} + +// OnMemberInvited() +message MemberInvitedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + repeated GroupMemberFullInfo invitedUserList = 3; + int64 operationTime = 4; +} + +//Actively join the group +message MemberEnterTips{ + GroupInfo group = 1; + GroupMemberFullInfo entrantUser = 2; + int64 operationTime = 3; +} + +message GroupDismissedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; +} + +message GroupMemberMutedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; + GroupMemberFullInfo mutedUser = 4; + uint32 mutedSeconds = 5; +} + +message GroupMemberCancelMutedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; + GroupMemberFullInfo mutedUser = 4; +} + +message GroupMutedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; +} + +message GroupCancelMutedTips{ + GroupInfo group = 1; + GroupMemberFullInfo opUser = 2; + int64 operationTime = 3; +} + + +//////////////////////friend///////////////////// +//message FriendInfo{ +// UserInfo OwnerUser = 1; +// string Remark = 2; +// uint64 CreateTime = 3; +// UserInfo FriendUser = 4; +//} + +message FriendApplication{ + int64 addTime = 1; + string addSource = 2; + string addWording = 3; +} + +message FromToUserID{ + string fromUserID = 1; + string toUserID = 2; +} + +//FromUserID apply to add ToUserID +message FriendApplicationTips{ + FromToUserID fromToUserID = 1; +} + +//FromUserID accept or reject ToUserID +message FriendApplicationApprovedTips{ + FromToUserID fromToUserID = 1; + string handleMsg = 2; +} + +//FromUserID accept or reject ToUserID +message FriendApplicationRejectedTips{ + FromToUserID fromToUserID = 1; + string handleMsg = 2; +} + + +// FromUserID Added a friend ToUserID +message FriendAddedTips{ + FriendInfo friend = 1; + int64 operationTime = 2; + PublicUserInfo opUser = 3; //who do this + +} + +// FromUserID deleted a friend ToUserID +message FriendDeletedTips{ + FromToUserID fromToUserID = 1; +} + + + +message BlackAddedTips{ + FromToUserID fromToUserID = 1; +} + +message BlackDeletedTips{ + FromToUserID fromToUserID = 1; +} + +message FriendInfoChangedTips{ + FromToUserID fromToUserID = 1; +} +//////////////////////user///////////////////// +message UserInfoUpdatedTips{ + string userID = 1; +} + +//////////////////////conversation///////////////////// +message ConversationUpdateTips{ + string UserID = 1; +} + +message ConversationSetPrivateTips{ + string recvID = 1; + string sendID = 2; + bool isPrivate = 3; +} + + +///cms +message RequestPagination { + int32 pageNumber = 1; + int32 showNumber = 2; +} + +message ResponsePagination { + int32 CurrentPage = 5; + int32 ShowNumber = 6; +} + + +///////////////////signal////////////// +message SignalReq { + oneof payload { + SignalInviteReq invite = 1; + SignalInviteInGroupReq inviteInGroup= 2; + SignalCancelReq cancel = 3; + SignalAcceptReq accept = 4; + SignalHungUpReq hungUp = 5; + SignalRejectReq reject = 6; + } +} + +message SignalResp { + oneof payload { + SignalInviteReply invite = 1; + SignalInviteInGroupReply inviteInGroup= 2; + SignalCancelReply cancel = 3; + SignalAcceptReply accept = 4; + SignalHungUpReply hungUp = 5; + SignalRejectReply reject = 6; + } +} + +message InvitationInfo { + string inviterUserID = 1; + repeated string inviteeUserIDList = 2; + string customData = 3; + string groupID = 4; + string roomID = 5; + int32 timeout = 6; + string mediaType = 7; + int32 platformID = 8; + int32 sessionType = 9; +} + +message ParticipantMetaData{ + GroupInfo groupInfo = 1; + GroupMemberFullInfo groupMemberInfo = 2; + PublicUserInfo userInfo = 3; +} + +message SignalInviteReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; + +} + +message SignalInviteReply { + string token = 1; + string roomID = 2; + string liveURL = 3; +} + +message SignalInviteInGroupReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; +} + +message SignalInviteInGroupReply { + string token = 1; + string roomID = 2; + string liveURL = 3; +} + +message SignalCancelReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; +} + +message SignalCancelReply { + +} + +message SignalAcceptReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; + int32 opUserPlatformID = 5; +} + +message SignalAcceptReply { + string token = 1; + string roomID = 2; + string liveURL = 3; +} + +message SignalHungUpReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; +} + +message SignalHungUpReply { + +} + + +message SignalRejectReq { + string opUserID = 1; + InvitationInfo invitation = 2; + OfflinePushInfo offlinePushInfo = 3; + ParticipantMetaData participant = 4; + int32 opUserPlatformID = 5; +} + +message SignalRejectReply { + +} + + +message DelMsgListReq{ + string opUserID = 1; + string userID = 2; + repeated uint32 seqList = 3; + string operationID = 4; +} + +message DelMsgListResp{ + int32 errCode = 1; + string errMsg = 2; +} + + diff --git a/pkg/proto/statistics/statistics.pb.go b/pkg/proto/statistics/statistics.pb.go new file mode 100644 index 000000000..5fd528d97 --- /dev/null +++ b/pkg/proto/statistics/statistics.pb.go @@ -0,0 +1,1498 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.19.3 +// source: statistics/statistics.proto + +package statistics + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type StatisticsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` +} + +func (x *StatisticsReq) Reset() { + *x = StatisticsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatisticsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatisticsReq) ProtoMessage() {} + +func (x *StatisticsReq) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatisticsReq.ProtoReflect.Descriptor instead. +func (*StatisticsReq) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{0} +} + +func (x *StatisticsReq) GetFrom() string { + if x != nil { + return x.From + } + return "" +} + +func (x *StatisticsReq) GetTo() string { + if x != nil { + return x.To + } + return "" +} + +type GetActiveUserReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatisticsReq *StatisticsReq `protobuf:"bytes,1,opt,name=StatisticsReq,proto3" json:"StatisticsReq,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *GetActiveUserReq) Reset() { + *x = GetActiveUserReq{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetActiveUserReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetActiveUserReq) ProtoMessage() {} + +func (x *GetActiveUserReq) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetActiveUserReq.ProtoReflect.Descriptor instead. +func (*GetActiveUserReq) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{1} +} + +func (x *GetActiveUserReq) GetStatisticsReq() *StatisticsReq { + if x != nil { + return x.StatisticsReq + } + return nil +} + +func (x *GetActiveUserReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type UserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NickName string `protobuf:"bytes,1,opt,name=NickName,proto3" json:"NickName,omitempty"` + UserId string `protobuf:"bytes,2,opt,name=UserId,proto3" json:"UserId,omitempty"` + MessageNum int32 `protobuf:"varint,3,opt,name=MessageNum,proto3" json:"MessageNum,omitempty"` +} + +func (x *UserResp) Reset() { + *x = UserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserResp) ProtoMessage() {} + +func (x *UserResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserResp.ProtoReflect.Descriptor instead. +func (*UserResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{2} +} + +func (x *UserResp) GetNickName() string { + if x != nil { + return x.NickName + } + return "" +} + +func (x *UserResp) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UserResp) GetMessageNum() int32 { + if x != nil { + return x.MessageNum + } + return 0 +} + +type GetActiveUserResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users []*UserResp `protobuf:"bytes,1,rep,name=Users,proto3" json:"Users,omitempty"` +} + +func (x *GetActiveUserResp) Reset() { + *x = GetActiveUserResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetActiveUserResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetActiveUserResp) ProtoMessage() {} + +func (x *GetActiveUserResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetActiveUserResp.ProtoReflect.Descriptor instead. +func (*GetActiveUserResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{3} +} + +func (x *GetActiveUserResp) GetUsers() []*UserResp { + if x != nil { + return x.Users + } + return nil +} + +type GetActiveGroupReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatisticsReq *StatisticsReq `protobuf:"bytes,1,opt,name=StatisticsReq,proto3" json:"StatisticsReq,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *GetActiveGroupReq) Reset() { + *x = GetActiveGroupReq{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetActiveGroupReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetActiveGroupReq) ProtoMessage() {} + +func (x *GetActiveGroupReq) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetActiveGroupReq.ProtoReflect.Descriptor instead. +func (*GetActiveGroupReq) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{4} +} + +func (x *GetActiveGroupReq) GetStatisticsReq() *StatisticsReq { + if x != nil { + return x.StatisticsReq + } + return nil +} + +func (x *GetActiveGroupReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type GroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupName string `protobuf:"bytes,1,opt,name=GroupName,proto3" json:"GroupName,omitempty"` + GroupId string `protobuf:"bytes,2,opt,name=GroupId,proto3" json:"GroupId,omitempty"` + MessageNum int32 `protobuf:"varint,3,opt,name=MessageNum,proto3" json:"MessageNum,omitempty"` +} + +func (x *GroupResp) Reset() { + *x = GroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupResp) ProtoMessage() {} + +func (x *GroupResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupResp.ProtoReflect.Descriptor instead. +func (*GroupResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{5} +} + +func (x *GroupResp) GetGroupName() string { + if x != nil { + return x.GroupName + } + return "" +} + +func (x *GroupResp) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *GroupResp) GetMessageNum() int32 { + if x != nil { + return x.MessageNum + } + return 0 +} + +type GetActiveGroupResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Groups []*GroupResp `protobuf:"bytes,1,rep,name=Groups,proto3" json:"Groups,omitempty"` +} + +func (x *GetActiveGroupResp) Reset() { + *x = GetActiveGroupResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetActiveGroupResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetActiveGroupResp) ProtoMessage() {} + +func (x *GetActiveGroupResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetActiveGroupResp.ProtoReflect.Descriptor instead. +func (*GetActiveGroupResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{6} +} + +func (x *GetActiveGroupResp) GetGroups() []*GroupResp { + if x != nil { + return x.Groups + } + return nil +} + +type DateNumList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Date string `protobuf:"bytes,1,opt,name=Date,proto3" json:"Date,omitempty"` + Num int32 `protobuf:"varint,2,opt,name=Num,proto3" json:"Num,omitempty"` +} + +func (x *DateNumList) Reset() { + *x = DateNumList{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DateNumList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DateNumList) ProtoMessage() {} + +func (x *DateNumList) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DateNumList.ProtoReflect.Descriptor instead. +func (*DateNumList) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{7} +} + +func (x *DateNumList) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *DateNumList) GetNum() int32 { + if x != nil { + return x.Num + } + return 0 +} + +type GetMessageStatisticsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatisticsReq *StatisticsReq `protobuf:"bytes,1,opt,name=StatisticsReq,proto3" json:"StatisticsReq,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *GetMessageStatisticsReq) Reset() { + *x = GetMessageStatisticsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMessageStatisticsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMessageStatisticsReq) ProtoMessage() {} + +func (x *GetMessageStatisticsReq) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMessageStatisticsReq.ProtoReflect.Descriptor instead. +func (*GetMessageStatisticsReq) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{8} +} + +func (x *GetMessageStatisticsReq) GetStatisticsReq() *StatisticsReq { + if x != nil { + return x.StatisticsReq + } + return nil +} + +func (x *GetMessageStatisticsReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type GetMessageStatisticsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PrivateMessageNum int32 `protobuf:"varint,1,opt,name=PrivateMessageNum,proto3" json:"PrivateMessageNum,omitempty"` + GroupMessageNum int32 `protobuf:"varint,2,opt,name=GroupMessageNum,proto3" json:"GroupMessageNum,omitempty"` + PrivateMessageNumList []*DateNumList `protobuf:"bytes,3,rep,name=PrivateMessageNumList,proto3" json:"PrivateMessageNumList,omitempty"` + GroupMessageNumList []*DateNumList `protobuf:"bytes,4,rep,name=GroupMessageNumList,proto3" json:"GroupMessageNumList,omitempty"` +} + +func (x *GetMessageStatisticsResp) Reset() { + *x = GetMessageStatisticsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMessageStatisticsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMessageStatisticsResp) ProtoMessage() {} + +func (x *GetMessageStatisticsResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMessageStatisticsResp.ProtoReflect.Descriptor instead. +func (*GetMessageStatisticsResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{9} +} + +func (x *GetMessageStatisticsResp) GetPrivateMessageNum() int32 { + if x != nil { + return x.PrivateMessageNum + } + return 0 +} + +func (x *GetMessageStatisticsResp) GetGroupMessageNum() int32 { + if x != nil { + return x.GroupMessageNum + } + return 0 +} + +func (x *GetMessageStatisticsResp) GetPrivateMessageNumList() []*DateNumList { + if x != nil { + return x.PrivateMessageNumList + } + return nil +} + +func (x *GetMessageStatisticsResp) GetGroupMessageNumList() []*DateNumList { + if x != nil { + return x.GroupMessageNumList + } + return nil +} + +type GetGroupStatisticsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatisticsReq *StatisticsReq `protobuf:"bytes,1,opt,name=StatisticsReq,proto3" json:"StatisticsReq,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *GetGroupStatisticsReq) Reset() { + *x = GetGroupStatisticsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetGroupStatisticsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetGroupStatisticsReq) ProtoMessage() {} + +func (x *GetGroupStatisticsReq) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetGroupStatisticsReq.ProtoReflect.Descriptor instead. +func (*GetGroupStatisticsReq) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{10} +} + +func (x *GetGroupStatisticsReq) GetStatisticsReq() *StatisticsReq { + if x != nil { + return x.StatisticsReq + } + return nil +} + +func (x *GetGroupStatisticsReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type GetGroupStatisticsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IncreaseGroupNum int32 `protobuf:"varint,1,opt,name=IncreaseGroupNum,proto3" json:"IncreaseGroupNum,omitempty"` + TotalGroupNum int32 `protobuf:"varint,2,opt,name=TotalGroupNum,proto3" json:"TotalGroupNum,omitempty"` + IncreaseGroupNumList []*DateNumList `protobuf:"bytes,3,rep,name=IncreaseGroupNumList,proto3" json:"IncreaseGroupNumList,omitempty"` + TotalGroupNumList []*DateNumList `protobuf:"bytes,4,rep,name=TotalGroupNumList,proto3" json:"TotalGroupNumList,omitempty"` +} + +func (x *GetGroupStatisticsResp) Reset() { + *x = GetGroupStatisticsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetGroupStatisticsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetGroupStatisticsResp) ProtoMessage() {} + +func (x *GetGroupStatisticsResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetGroupStatisticsResp.ProtoReflect.Descriptor instead. +func (*GetGroupStatisticsResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{11} +} + +func (x *GetGroupStatisticsResp) GetIncreaseGroupNum() int32 { + if x != nil { + return x.IncreaseGroupNum + } + return 0 +} + +func (x *GetGroupStatisticsResp) GetTotalGroupNum() int32 { + if x != nil { + return x.TotalGroupNum + } + return 0 +} + +func (x *GetGroupStatisticsResp) GetIncreaseGroupNumList() []*DateNumList { + if x != nil { + return x.IncreaseGroupNumList + } + return nil +} + +func (x *GetGroupStatisticsResp) GetTotalGroupNumList() []*DateNumList { + if x != nil { + return x.TotalGroupNumList + } + return nil +} + +type GetUserStatisticsReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StatisticsReq *StatisticsReq `protobuf:"bytes,1,opt,name=StatisticsReq,proto3" json:"StatisticsReq,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID,proto3" json:"OperationID,omitempty"` +} + +func (x *GetUserStatisticsReq) Reset() { + *x = GetUserStatisticsReq{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserStatisticsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserStatisticsReq) ProtoMessage() {} + +func (x *GetUserStatisticsReq) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserStatisticsReq.ProtoReflect.Descriptor instead. +func (*GetUserStatisticsReq) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{12} +} + +func (x *GetUserStatisticsReq) GetStatisticsReq() *StatisticsReq { + if x != nil { + return x.StatisticsReq + } + return nil +} + +func (x *GetUserStatisticsReq) GetOperationID() string { + if x != nil { + return x.OperationID + } + return "" +} + +type GetUserStatisticsResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IncreaseUserNum int32 `protobuf:"varint,1,opt,name=IncreaseUserNum,proto3" json:"IncreaseUserNum,omitempty"` + ActiveUserNum int32 `protobuf:"varint,2,opt,name=ActiveUserNum,proto3" json:"ActiveUserNum,omitempty"` + TotalUserNum int32 `protobuf:"varint,3,opt,name=TotalUserNum,proto3" json:"TotalUserNum,omitempty"` + IncreaseUserNumList []*DateNumList `protobuf:"bytes,4,rep,name=IncreaseUserNumList,proto3" json:"IncreaseUserNumList,omitempty"` + ActiveUserNumList []*DateNumList `protobuf:"bytes,5,rep,name=ActiveUserNumList,proto3" json:"ActiveUserNumList,omitempty"` + TotalUserNumList []*DateNumList `protobuf:"bytes,6,rep,name=TotalUserNumList,proto3" json:"TotalUserNumList,omitempty"` +} + +func (x *GetUserStatisticsResp) Reset() { + *x = GetUserStatisticsResp{} + if protoimpl.UnsafeEnabled { + mi := &file_statistics_statistics_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserStatisticsResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserStatisticsResp) ProtoMessage() {} + +func (x *GetUserStatisticsResp) ProtoReflect() protoreflect.Message { + mi := &file_statistics_statistics_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserStatisticsResp.ProtoReflect.Descriptor instead. +func (*GetUserStatisticsResp) Descriptor() ([]byte, []int) { + return file_statistics_statistics_proto_rawDescGZIP(), []int{13} +} + +func (x *GetUserStatisticsResp) GetIncreaseUserNum() int32 { + if x != nil { + return x.IncreaseUserNum + } + return 0 +} + +func (x *GetUserStatisticsResp) GetActiveUserNum() int32 { + if x != nil { + return x.ActiveUserNum + } + return 0 +} + +func (x *GetUserStatisticsResp) GetTotalUserNum() int32 { + if x != nil { + return x.TotalUserNum + } + return 0 +} + +func (x *GetUserStatisticsResp) GetIncreaseUserNumList() []*DateNumList { + if x != nil { + return x.IncreaseUserNumList + } + return nil +} + +func (x *GetUserStatisticsResp) GetActiveUserNumList() []*DateNumList { + if x != nil { + return x.ActiveUserNumList + } + return nil +} + +func (x *GetUserStatisticsResp) GetTotalUserNumList() []*DateNumList { + if x != nil { + return x.TotalUserNumList + } + return nil +} + +var File_statistics_statistics_proto protoreflect.FileDescriptor + +var file_statistics_statistics_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2f, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x33, 0x0a, 0x0d, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, + 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x75, + 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x71, 0x52, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x5e, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x4e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x4e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x22, 0x3f, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2a, 0x0a, 0x05, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x52, + 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x22, 0x76, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0d, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x52, 0x0d, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x63, + 0x0a, 0x09, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x75, + 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x4e, 0x75, 0x6d, 0x22, 0x43, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2d, 0x0a, 0x06, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x52, 0x06, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x33, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x65, + 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x44, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4e, + 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x4e, 0x75, 0x6d, 0x22, 0x7c, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x52, 0x0d, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x8c, 0x02, 0x0a, 0x18, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2c, 0x0a, 0x11, 0x50, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x11, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x28, 0x0a, 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, + 0x12, 0x4d, 0x0a, 0x15, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, + 0x65, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x15, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x49, 0x0a, 0x13, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, + 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x4e, 0x75, + 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x13, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x7a, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, + 0x63, 0x73, 0x52, 0x65, 0x71, 0x52, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0xfe, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x2a, 0x0a, 0x10, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x49, 0x6e, 0x63, + 0x72, 0x65, 0x61, 0x73, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x12, 0x24, 0x0a, + 0x0d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4e, 0x75, 0x6d, 0x12, 0x4b, 0x0a, 0x14, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x44, + 0x61, 0x74, 0x65, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x14, 0x49, 0x6e, 0x63, 0x72, + 0x65, 0x61, 0x73, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x45, 0x0a, 0x11, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x75, + 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x4e, 0x75, 0x6d, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x11, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x79, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x12, + 0x3f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, + 0x71, 0x52, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, + 0x12, 0x20, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x44, 0x22, 0xe2, 0x02, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x28, 0x0a, 0x0f, + 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x12, 0x24, 0x0a, 0x0d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x12, 0x22, 0x0a, 0x0c, + 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0c, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, + 0x12, 0x49, 0x0a, 0x13, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x4e, + 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x13, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x11, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x75, 0x6d, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x43, 0x0a, 0x10, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4e, + 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x4e, 0x75, + 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x10, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, + 0x4e, 0x75, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x32, 0xbf, 0x03, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x12, 0x4c, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x1c, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, + 0x1d, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4f, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x12, 0x1d, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, + 0x1e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x61, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x23, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5b, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x21, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x58, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x12, 0x20, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x42, 0x19, 0x5a, 0x17, 0x2e, 0x2f, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_statistics_statistics_proto_rawDescOnce sync.Once + file_statistics_statistics_proto_rawDescData = file_statistics_statistics_proto_rawDesc +) + +func file_statistics_statistics_proto_rawDescGZIP() []byte { + file_statistics_statistics_proto_rawDescOnce.Do(func() { + file_statistics_statistics_proto_rawDescData = protoimpl.X.CompressGZIP(file_statistics_statistics_proto_rawDescData) + }) + return file_statistics_statistics_proto_rawDescData +} + +var file_statistics_statistics_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_statistics_statistics_proto_goTypes = []interface{}{ + (*StatisticsReq)(nil), // 0: statistics.StatisticsReq + (*GetActiveUserReq)(nil), // 1: statistics.GetActiveUserReq + (*UserResp)(nil), // 2: statistics.UserResp + (*GetActiveUserResp)(nil), // 3: statistics.GetActiveUserResp + (*GetActiveGroupReq)(nil), // 4: statistics.GetActiveGroupReq + (*GroupResp)(nil), // 5: statistics.GroupResp + (*GetActiveGroupResp)(nil), // 6: statistics.GetActiveGroupResp + (*DateNumList)(nil), // 7: statistics.DateNumList + (*GetMessageStatisticsReq)(nil), // 8: statistics.GetMessageStatisticsReq + (*GetMessageStatisticsResp)(nil), // 9: statistics.GetMessageStatisticsResp + (*GetGroupStatisticsReq)(nil), // 10: statistics.GetGroupStatisticsReq + (*GetGroupStatisticsResp)(nil), // 11: statistics.GetGroupStatisticsResp + (*GetUserStatisticsReq)(nil), // 12: statistics.GetUserStatisticsReq + (*GetUserStatisticsResp)(nil), // 13: statistics.GetUserStatisticsResp +} +var file_statistics_statistics_proto_depIdxs = []int32{ + 0, // 0: statistics.GetActiveUserReq.StatisticsReq:type_name -> statistics.StatisticsReq + 2, // 1: statistics.GetActiveUserResp.Users:type_name -> statistics.UserResp + 0, // 2: statistics.GetActiveGroupReq.StatisticsReq:type_name -> statistics.StatisticsReq + 5, // 3: statistics.GetActiveGroupResp.Groups:type_name -> statistics.GroupResp + 0, // 4: statistics.GetMessageStatisticsReq.StatisticsReq:type_name -> statistics.StatisticsReq + 7, // 5: statistics.GetMessageStatisticsResp.PrivateMessageNumList:type_name -> statistics.DateNumList + 7, // 6: statistics.GetMessageStatisticsResp.GroupMessageNumList:type_name -> statistics.DateNumList + 0, // 7: statistics.GetGroupStatisticsReq.StatisticsReq:type_name -> statistics.StatisticsReq + 7, // 8: statistics.GetGroupStatisticsResp.IncreaseGroupNumList:type_name -> statistics.DateNumList + 7, // 9: statistics.GetGroupStatisticsResp.TotalGroupNumList:type_name -> statistics.DateNumList + 0, // 10: statistics.GetUserStatisticsReq.StatisticsReq:type_name -> statistics.StatisticsReq + 7, // 11: statistics.GetUserStatisticsResp.IncreaseUserNumList:type_name -> statistics.DateNumList + 7, // 12: statistics.GetUserStatisticsResp.ActiveUserNumList:type_name -> statistics.DateNumList + 7, // 13: statistics.GetUserStatisticsResp.TotalUserNumList:type_name -> statistics.DateNumList + 1, // 14: statistics.user.GetActiveUser:input_type -> statistics.GetActiveUserReq + 4, // 15: statistics.user.GetActiveGroup:input_type -> statistics.GetActiveGroupReq + 8, // 16: statistics.user.GetMessageStatistics:input_type -> statistics.GetMessageStatisticsReq + 10, // 17: statistics.user.GetGroupStatistics:input_type -> statistics.GetGroupStatisticsReq + 12, // 18: statistics.user.GetUserStatistics:input_type -> statistics.GetUserStatisticsReq + 3, // 19: statistics.user.GetActiveUser:output_type -> statistics.GetActiveUserResp + 6, // 20: statistics.user.GetActiveGroup:output_type -> statistics.GetActiveGroupResp + 9, // 21: statistics.user.GetMessageStatistics:output_type -> statistics.GetMessageStatisticsResp + 11, // 22: statistics.user.GetGroupStatistics:output_type -> statistics.GetGroupStatisticsResp + 13, // 23: statistics.user.GetUserStatistics:output_type -> statistics.GetUserStatisticsResp + 19, // [19:24] is the sub-list for method output_type + 14, // [14:19] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_statistics_statistics_proto_init() } +func file_statistics_statistics_proto_init() { + if File_statistics_statistics_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_statistics_statistics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StatisticsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetActiveUserReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetActiveUserResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetActiveGroupReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetActiveGroupResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DateNumList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMessageStatisticsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMessageStatisticsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetGroupStatisticsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetGroupStatisticsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserStatisticsReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_statistics_statistics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserStatisticsResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_statistics_statistics_proto_rawDesc, + NumEnums: 0, + NumMessages: 14, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_statistics_statistics_proto_goTypes, + DependencyIndexes: file_statistics_statistics_proto_depIdxs, + MessageInfos: file_statistics_statistics_proto_msgTypes, + }.Build() + File_statistics_statistics_proto = out.File + file_statistics_statistics_proto_rawDesc = nil + file_statistics_statistics_proto_goTypes = nil + file_statistics_statistics_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// UserClient is the client API for User service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type UserClient interface { + GetActiveUser(ctx context.Context, in *GetActiveUserReq, opts ...grpc.CallOption) (*GetActiveUserResp, error) + GetActiveGroup(ctx context.Context, in *GetActiveGroupReq, opts ...grpc.CallOption) (*GetActiveGroupResp, error) + GetMessageStatistics(ctx context.Context, in *GetMessageStatisticsReq, opts ...grpc.CallOption) (*GetMessageStatisticsResp, error) + GetGroupStatistics(ctx context.Context, in *GetGroupStatisticsReq, opts ...grpc.CallOption) (*GetGroupStatisticsResp, error) + GetUserStatistics(ctx context.Context, in *GetUserStatisticsReq, opts ...grpc.CallOption) (*GetUserStatisticsResp, error) +} + +type userClient struct { + cc grpc.ClientConnInterface +} + +func NewUserClient(cc grpc.ClientConnInterface) UserClient { + return &userClient{cc} +} + +func (c *userClient) GetActiveUser(ctx context.Context, in *GetActiveUserReq, opts ...grpc.CallOption) (*GetActiveUserResp, error) { + out := new(GetActiveUserResp) + err := c.cc.Invoke(ctx, "/statistics.user/GetActiveUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetActiveGroup(ctx context.Context, in *GetActiveGroupReq, opts ...grpc.CallOption) (*GetActiveGroupResp, error) { + out := new(GetActiveGroupResp) + err := c.cc.Invoke(ctx, "/statistics.user/GetActiveGroup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetMessageStatistics(ctx context.Context, in *GetMessageStatisticsReq, opts ...grpc.CallOption) (*GetMessageStatisticsResp, error) { + out := new(GetMessageStatisticsResp) + err := c.cc.Invoke(ctx, "/statistics.user/GetMessageStatistics", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetGroupStatistics(ctx context.Context, in *GetGroupStatisticsReq, opts ...grpc.CallOption) (*GetGroupStatisticsResp, error) { + out := new(GetGroupStatisticsResp) + err := c.cc.Invoke(ctx, "/statistics.user/GetGroupStatistics", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetUserStatistics(ctx context.Context, in *GetUserStatisticsReq, opts ...grpc.CallOption) (*GetUserStatisticsResp, error) { + out := new(GetUserStatisticsResp) + err := c.cc.Invoke(ctx, "/statistics.user/GetUserStatistics", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServer is the server API for User service. +type UserServer interface { + GetActiveUser(context.Context, *GetActiveUserReq) (*GetActiveUserResp, error) + GetActiveGroup(context.Context, *GetActiveGroupReq) (*GetActiveGroupResp, error) + GetMessageStatistics(context.Context, *GetMessageStatisticsReq) (*GetMessageStatisticsResp, error) + GetGroupStatistics(context.Context, *GetGroupStatisticsReq) (*GetGroupStatisticsResp, error) + GetUserStatistics(context.Context, *GetUserStatisticsReq) (*GetUserStatisticsResp, error) +} + +// UnimplementedUserServer can be embedded to have forward compatible implementations. +type UnimplementedUserServer struct { +} + +func (*UnimplementedUserServer) GetActiveUser(context.Context, *GetActiveUserReq) (*GetActiveUserResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetActiveUser not implemented") +} +func (*UnimplementedUserServer) GetActiveGroup(context.Context, *GetActiveGroupReq) (*GetActiveGroupResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetActiveGroup not implemented") +} +func (*UnimplementedUserServer) GetMessageStatistics(context.Context, *GetMessageStatisticsReq) (*GetMessageStatisticsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMessageStatistics not implemented") +} +func (*UnimplementedUserServer) GetGroupStatistics(context.Context, *GetGroupStatisticsReq) (*GetGroupStatisticsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetGroupStatistics not implemented") +} +func (*UnimplementedUserServer) GetUserStatistics(context.Context, *GetUserStatisticsReq) (*GetUserStatisticsResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserStatistics not implemented") +} + +func RegisterUserServer(s *grpc.Server, srv UserServer) { + s.RegisterService(&_User_serviceDesc, srv) +} + +func _User_GetActiveUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetActiveUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetActiveUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/statistics.user/GetActiveUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetActiveUser(ctx, req.(*GetActiveUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetActiveGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetActiveGroupReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetActiveGroup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/statistics.user/GetActiveGroup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetActiveGroup(ctx, req.(*GetActiveGroupReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetMessageStatistics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetMessageStatisticsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetMessageStatistics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/statistics.user/GetMessageStatistics", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetMessageStatistics(ctx, req.(*GetMessageStatisticsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetGroupStatistics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGroupStatisticsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetGroupStatistics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/statistics.user/GetGroupStatistics", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetGroupStatistics(ctx, req.(*GetGroupStatisticsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetUserStatistics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserStatisticsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetUserStatistics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/statistics.user/GetUserStatistics", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetUserStatistics(ctx, req.(*GetUserStatisticsReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _User_serviceDesc = grpc.ServiceDesc{ + ServiceName: "statistics.user", + HandlerType: (*UserServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetActiveUser", + Handler: _User_GetActiveUser_Handler, + }, + { + MethodName: "GetActiveGroup", + Handler: _User_GetActiveGroup_Handler, + }, + { + MethodName: "GetMessageStatistics", + Handler: _User_GetMessageStatistics_Handler, + }, + { + MethodName: "GetGroupStatistics", + Handler: _User_GetGroupStatistics_Handler, + }, + { + MethodName: "GetUserStatistics", + Handler: _User_GetUserStatistics_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "statistics/statistics.proto", +} diff --git a/pkg/proto/statistics/statistics.proto b/pkg/proto/statistics/statistics.proto new file mode 100644 index 000000000..3c72e4bc5 --- /dev/null +++ b/pkg/proto/statistics/statistics.proto @@ -0,0 +1,93 @@ +syntax = "proto3"; +// import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./statistics;statistics"; +package statistics; + +message StatisticsReq { + string from = 1; + string to = 2; +} + +message GetActiveUserReq{ + StatisticsReq StatisticsReq = 1; + string OperationID = 2; +} + +message UserResp{ + string NickName = 1; + string UserId = 2; + int32 MessageNum = 3; +} + +message GetActiveUserResp { + repeated UserResp Users = 1; +} + +message GetActiveGroupReq{ + StatisticsReq StatisticsReq = 1; + string OperationID = 2; +} + +message GroupResp { + string GroupName = 1; + string GroupId = 2; + int32 MessageNum = 3; +} + +message GetActiveGroupResp { + repeated GroupResp Groups = 1; +} + +message DateNumList { + string Date = 1; + int32 Num = 2; +} + + +message GetMessageStatisticsReq { + StatisticsReq StatisticsReq = 1; + string OperationID = 2; +} + + +message GetMessageStatisticsResp { + int32 PrivateMessageNum = 1; + int32 GroupMessageNum = 2; + repeated DateNumList PrivateMessageNumList = 3; + repeated DateNumList GroupMessageNumList = 4; +} + +message GetGroupStatisticsReq { + StatisticsReq StatisticsReq = 1; + string OperationID = 2; +} + + +message GetGroupStatisticsResp { + int32 IncreaseGroupNum = 1; + int32 TotalGroupNum = 2; + repeated DateNumList IncreaseGroupNumList = 3; + repeated DateNumList TotalGroupNumList = 4; +} + +message GetUserStatisticsReq { + StatisticsReq StatisticsReq = 1; + string OperationID = 2; +} + +message GetUserStatisticsResp { + int32 IncreaseUserNum = 1; + int32 ActiveUserNum = 2; + int32 TotalUserNum = 3; + repeated DateNumList IncreaseUserNumList = 4; + repeated DateNumList ActiveUserNumList = 5; + repeated DateNumList TotalUserNumList = 6; +} + +service user { + rpc GetActiveUser(GetActiveUserReq) returns(GetActiveUserResp); + rpc GetActiveGroup(GetActiveGroupReq) returns(GetActiveGroupResp); + rpc GetMessageStatistics(GetMessageStatisticsReq) returns(GetMessageStatisticsResp); + rpc GetGroupStatistics(GetGroupStatisticsReq) returns(GetGroupStatisticsResp); + rpc GetUserStatistics(GetUserStatisticsReq) returns(GetUserStatisticsResp); +} \ No newline at end of file diff --git a/pkg/proto/user/user.pb.go b/pkg/proto/user/user.pb.go new file mode 100644 index 000000000..1c8b88653 --- /dev/null +++ b/pkg/proto/user/user.pb.go @@ -0,0 +1,3505 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: user/user.proto + +package user // import "./user" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import sdk_ws "Open_IM/pkg/proto/sdk_ws" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CommonResp struct { + ErrCode int32 `protobuf:"varint,1,opt,name=errCode" json:"errCode,omitempty"` + ErrMsg string `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommonResp) Reset() { *m = CommonResp{} } +func (m *CommonResp) String() string { return proto.CompactTextString(m) } +func (*CommonResp) ProtoMessage() {} +func (*CommonResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{0} +} +func (m *CommonResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommonResp.Unmarshal(m, b) +} +func (m *CommonResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommonResp.Marshal(b, m, deterministic) +} +func (dst *CommonResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommonResp.Merge(dst, src) +} +func (m *CommonResp) XXX_Size() int { + return xxx_messageInfo_CommonResp.Size(m) +} +func (m *CommonResp) XXX_DiscardUnknown() { + xxx_messageInfo_CommonResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CommonResp proto.InternalMessageInfo + +func (m *CommonResp) GetErrCode() int32 { + if m != nil { + return m.ErrCode + } + return 0 +} + +func (m *CommonResp) GetErrMsg() string { + if m != nil { + return m.ErrMsg + } + return "" +} + +type DeleteUsersReq struct { + DeleteUserIDList []string `protobuf:"bytes,2,rep,name=DeleteUserIDList" json:"DeleteUserIDList,omitempty"` + OpUserID string `protobuf:"bytes,3,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteUsersReq) Reset() { *m = DeleteUsersReq{} } +func (m *DeleteUsersReq) String() string { return proto.CompactTextString(m) } +func (*DeleteUsersReq) ProtoMessage() {} +func (*DeleteUsersReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{1} +} +func (m *DeleteUsersReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteUsersReq.Unmarshal(m, b) +} +func (m *DeleteUsersReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteUsersReq.Marshal(b, m, deterministic) +} +func (dst *DeleteUsersReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteUsersReq.Merge(dst, src) +} +func (m *DeleteUsersReq) XXX_Size() int { + return xxx_messageInfo_DeleteUsersReq.Size(m) +} +func (m *DeleteUsersReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteUsersReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteUsersReq proto.InternalMessageInfo + +func (m *DeleteUsersReq) GetDeleteUserIDList() []string { + if m != nil { + return m.DeleteUserIDList + } + return nil +} + +func (m *DeleteUsersReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *DeleteUsersReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type DeleteUsersResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + FailedUserIDList []string `protobuf:"bytes,2,rep,name=FailedUserIDList" json:"FailedUserIDList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteUsersResp) Reset() { *m = DeleteUsersResp{} } +func (m *DeleteUsersResp) String() string { return proto.CompactTextString(m) } +func (*DeleteUsersResp) ProtoMessage() {} +func (*DeleteUsersResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{2} +} +func (m *DeleteUsersResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteUsersResp.Unmarshal(m, b) +} +func (m *DeleteUsersResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteUsersResp.Marshal(b, m, deterministic) +} +func (dst *DeleteUsersResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteUsersResp.Merge(dst, src) +} +func (m *DeleteUsersResp) XXX_Size() int { + return xxx_messageInfo_DeleteUsersResp.Size(m) +} +func (m *DeleteUsersResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteUsersResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteUsersResp proto.InternalMessageInfo + +func (m *DeleteUsersResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *DeleteUsersResp) GetFailedUserIDList() []string { + if m != nil { + return m.FailedUserIDList + } + return nil +} + +type GetAllUserIDReq struct { + OpUserID string `protobuf:"bytes,1,opt,name=opUserID" json:"opUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAllUserIDReq) Reset() { *m = GetAllUserIDReq{} } +func (m *GetAllUserIDReq) String() string { return proto.CompactTextString(m) } +func (*GetAllUserIDReq) ProtoMessage() {} +func (*GetAllUserIDReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{3} +} +func (m *GetAllUserIDReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAllUserIDReq.Unmarshal(m, b) +} +func (m *GetAllUserIDReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAllUserIDReq.Marshal(b, m, deterministic) +} +func (dst *GetAllUserIDReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAllUserIDReq.Merge(dst, src) +} +func (m *GetAllUserIDReq) XXX_Size() int { + return xxx_messageInfo_GetAllUserIDReq.Size(m) +} +func (m *GetAllUserIDReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetAllUserIDReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAllUserIDReq proto.InternalMessageInfo + +func (m *GetAllUserIDReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetAllUserIDReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetAllUserIDResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + UserIDList []string `protobuf:"bytes,2,rep,name=UserIDList" json:"UserIDList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAllUserIDResp) Reset() { *m = GetAllUserIDResp{} } +func (m *GetAllUserIDResp) String() string { return proto.CompactTextString(m) } +func (*GetAllUserIDResp) ProtoMessage() {} +func (*GetAllUserIDResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{4} +} +func (m *GetAllUserIDResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAllUserIDResp.Unmarshal(m, b) +} +func (m *GetAllUserIDResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAllUserIDResp.Marshal(b, m, deterministic) +} +func (dst *GetAllUserIDResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAllUserIDResp.Merge(dst, src) +} +func (m *GetAllUserIDResp) XXX_Size() int { + return xxx_messageInfo_GetAllUserIDResp.Size(m) +} +func (m *GetAllUserIDResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetAllUserIDResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAllUserIDResp proto.InternalMessageInfo + +func (m *GetAllUserIDResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetAllUserIDResp) GetUserIDList() []string { + if m != nil { + return m.UserIDList + } + return nil +} + +type AccountCheckReq struct { + CheckUserIDList []string `protobuf:"bytes,1,rep,name=CheckUserIDList" json:"CheckUserIDList,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AccountCheckReq) Reset() { *m = AccountCheckReq{} } +func (m *AccountCheckReq) String() string { return proto.CompactTextString(m) } +func (*AccountCheckReq) ProtoMessage() {} +func (*AccountCheckReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{5} +} +func (m *AccountCheckReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AccountCheckReq.Unmarshal(m, b) +} +func (m *AccountCheckReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AccountCheckReq.Marshal(b, m, deterministic) +} +func (dst *AccountCheckReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountCheckReq.Merge(dst, src) +} +func (m *AccountCheckReq) XXX_Size() int { + return xxx_messageInfo_AccountCheckReq.Size(m) +} +func (m *AccountCheckReq) XXX_DiscardUnknown() { + xxx_messageInfo_AccountCheckReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountCheckReq proto.InternalMessageInfo + +func (m *AccountCheckReq) GetCheckUserIDList() []string { + if m != nil { + return m.CheckUserIDList + } + return nil +} + +func (m *AccountCheckReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *AccountCheckReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type AccountCheckResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + ResultList []*AccountCheckResp_SingleUserStatus `protobuf:"bytes,2,rep,name=ResultList" json:"ResultList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AccountCheckResp) Reset() { *m = AccountCheckResp{} } +func (m *AccountCheckResp) String() string { return proto.CompactTextString(m) } +func (*AccountCheckResp) ProtoMessage() {} +func (*AccountCheckResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{6} +} +func (m *AccountCheckResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AccountCheckResp.Unmarshal(m, b) +} +func (m *AccountCheckResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AccountCheckResp.Marshal(b, m, deterministic) +} +func (dst *AccountCheckResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountCheckResp.Merge(dst, src) +} +func (m *AccountCheckResp) XXX_Size() int { + return xxx_messageInfo_AccountCheckResp.Size(m) +} +func (m *AccountCheckResp) XXX_DiscardUnknown() { + xxx_messageInfo_AccountCheckResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountCheckResp proto.InternalMessageInfo + +func (m *AccountCheckResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *AccountCheckResp) GetResultList() []*AccountCheckResp_SingleUserStatus { + if m != nil { + return m.ResultList + } + return nil +} + +type AccountCheckResp_SingleUserStatus struct { + UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"` + AccountStatus string `protobuf:"bytes,2,opt,name=accountStatus" json:"accountStatus,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AccountCheckResp_SingleUserStatus) Reset() { *m = AccountCheckResp_SingleUserStatus{} } +func (m *AccountCheckResp_SingleUserStatus) String() string { return proto.CompactTextString(m) } +func (*AccountCheckResp_SingleUserStatus) ProtoMessage() {} +func (*AccountCheckResp_SingleUserStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{6, 0} +} +func (m *AccountCheckResp_SingleUserStatus) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AccountCheckResp_SingleUserStatus.Unmarshal(m, b) +} +func (m *AccountCheckResp_SingleUserStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AccountCheckResp_SingleUserStatus.Marshal(b, m, deterministic) +} +func (dst *AccountCheckResp_SingleUserStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountCheckResp_SingleUserStatus.Merge(dst, src) +} +func (m *AccountCheckResp_SingleUserStatus) XXX_Size() int { + return xxx_messageInfo_AccountCheckResp_SingleUserStatus.Size(m) +} +func (m *AccountCheckResp_SingleUserStatus) XXX_DiscardUnknown() { + xxx_messageInfo_AccountCheckResp_SingleUserStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountCheckResp_SingleUserStatus proto.InternalMessageInfo + +func (m *AccountCheckResp_SingleUserStatus) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *AccountCheckResp_SingleUserStatus) GetAccountStatus() string { + if m != nil { + return m.AccountStatus + } + return "" +} + +type GetUserInfoReq struct { + UserIDList []string `protobuf:"bytes,1,rep,name=userIDList" json:"userIDList,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserInfoReq) Reset() { *m = GetUserInfoReq{} } +func (m *GetUserInfoReq) String() string { return proto.CompactTextString(m) } +func (*GetUserInfoReq) ProtoMessage() {} +func (*GetUserInfoReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{7} +} +func (m *GetUserInfoReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserInfoReq.Unmarshal(m, b) +} +func (m *GetUserInfoReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserInfoReq.Marshal(b, m, deterministic) +} +func (dst *GetUserInfoReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserInfoReq.Merge(dst, src) +} +func (m *GetUserInfoReq) XXX_Size() int { + return xxx_messageInfo_GetUserInfoReq.Size(m) +} +func (m *GetUserInfoReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserInfoReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserInfoReq proto.InternalMessageInfo + +func (m *GetUserInfoReq) GetUserIDList() []string { + if m != nil { + return m.UserIDList + } + return nil +} + +func (m *GetUserInfoReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *GetUserInfoReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUserInfoResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + UserInfoList []*sdk_ws.UserInfo `protobuf:"bytes,3,rep,name=UserInfoList" json:"UserInfoList,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserInfoResp) Reset() { *m = GetUserInfoResp{} } +func (m *GetUserInfoResp) String() string { return proto.CompactTextString(m) } +func (*GetUserInfoResp) ProtoMessage() {} +func (*GetUserInfoResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{8} +} +func (m *GetUserInfoResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserInfoResp.Unmarshal(m, b) +} +func (m *GetUserInfoResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserInfoResp.Marshal(b, m, deterministic) +} +func (dst *GetUserInfoResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserInfoResp.Merge(dst, src) +} +func (m *GetUserInfoResp) XXX_Size() int { + return xxx_messageInfo_GetUserInfoResp.Size(m) +} +func (m *GetUserInfoResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserInfoResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserInfoResp proto.InternalMessageInfo + +func (m *GetUserInfoResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserInfoResp) GetUserInfoList() []*sdk_ws.UserInfo { + if m != nil { + return m.UserInfoList + } + return nil +} + +type UpdateUserInfoReq struct { + UserInfo *sdk_ws.UserInfo `protobuf:"bytes,1,opt,name=UserInfo" json:"UserInfo,omitempty"` + OpUserID string `protobuf:"bytes,2,opt,name=OpUserID" json:"OpUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=operationID" json:"operationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateUserInfoReq) Reset() { *m = UpdateUserInfoReq{} } +func (m *UpdateUserInfoReq) String() string { return proto.CompactTextString(m) } +func (*UpdateUserInfoReq) ProtoMessage() {} +func (*UpdateUserInfoReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{9} +} +func (m *UpdateUserInfoReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateUserInfoReq.Unmarshal(m, b) +} +func (m *UpdateUserInfoReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateUserInfoReq.Marshal(b, m, deterministic) +} +func (dst *UpdateUserInfoReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateUserInfoReq.Merge(dst, src) +} +func (m *UpdateUserInfoReq) XXX_Size() int { + return xxx_messageInfo_UpdateUserInfoReq.Size(m) +} +func (m *UpdateUserInfoReq) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateUserInfoReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateUserInfoReq proto.InternalMessageInfo + +func (m *UpdateUserInfoReq) GetUserInfo() *sdk_ws.UserInfo { + if m != nil { + return m.UserInfo + } + return nil +} + +func (m *UpdateUserInfoReq) GetOpUserID() string { + if m != nil { + return m.OpUserID + } + return "" +} + +func (m *UpdateUserInfoReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type UpdateUserInfoResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateUserInfoResp) Reset() { *m = UpdateUserInfoResp{} } +func (m *UpdateUserInfoResp) String() string { return proto.CompactTextString(m) } +func (*UpdateUserInfoResp) ProtoMessage() {} +func (*UpdateUserInfoResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{10} +} +func (m *UpdateUserInfoResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateUserInfoResp.Unmarshal(m, b) +} +func (m *UpdateUserInfoResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateUserInfoResp.Marshal(b, m, deterministic) +} +func (dst *UpdateUserInfoResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateUserInfoResp.Merge(dst, src) +} +func (m *UpdateUserInfoResp) XXX_Size() int { + return xxx_messageInfo_UpdateUserInfoResp.Size(m) +} +func (m *UpdateUserInfoResp) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateUserInfoResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateUserInfoResp proto.InternalMessageInfo + +func (m *UpdateUserInfoResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type Conversation struct { + OwnerUserID string `protobuf:"bytes,1,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + ConversationID string `protobuf:"bytes,2,opt,name=ConversationID" json:"ConversationID,omitempty"` + RecvMsgOpt int32 `protobuf:"varint,3,opt,name=RecvMsgOpt" json:"RecvMsgOpt,omitempty"` + ConversationType int32 `protobuf:"varint,4,opt,name=ConversationType" json:"ConversationType,omitempty"` + UserID string `protobuf:"bytes,5,opt,name=UserID" json:"UserID,omitempty"` + GroupID string `protobuf:"bytes,6,opt,name=GroupID" json:"GroupID,omitempty"` + UnreadCount int32 `protobuf:"varint,7,opt,name=UnreadCount" json:"UnreadCount,omitempty"` + DraftTextTime int64 `protobuf:"varint,8,opt,name=DraftTextTime" json:"DraftTextTime,omitempty"` + IsPinned bool `protobuf:"varint,9,opt,name=IsPinned" json:"IsPinned,omitempty"` + AttachedInfo string `protobuf:"bytes,10,opt,name=AttachedInfo" json:"AttachedInfo,omitempty"` + IsPrivateChat bool `protobuf:"varint,11,opt,name=IsPrivateChat" json:"IsPrivateChat,omitempty"` + Ex string `protobuf:"bytes,12,opt,name=Ex" json:"Ex,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Conversation) Reset() { *m = Conversation{} } +func (m *Conversation) String() string { return proto.CompactTextString(m) } +func (*Conversation) ProtoMessage() {} +func (*Conversation) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{11} +} +func (m *Conversation) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Conversation.Unmarshal(m, b) +} +func (m *Conversation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Conversation.Marshal(b, m, deterministic) +} +func (dst *Conversation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Conversation.Merge(dst, src) +} +func (m *Conversation) XXX_Size() int { + return xxx_messageInfo_Conversation.Size(m) +} +func (m *Conversation) XXX_DiscardUnknown() { + xxx_messageInfo_Conversation.DiscardUnknown(m) +} + +var xxx_messageInfo_Conversation proto.InternalMessageInfo + +func (m *Conversation) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *Conversation) GetConversationID() string { + if m != nil { + return m.ConversationID + } + return "" +} + +func (m *Conversation) GetRecvMsgOpt() int32 { + if m != nil { + return m.RecvMsgOpt + } + return 0 +} + +func (m *Conversation) GetConversationType() int32 { + if m != nil { + return m.ConversationType + } + return 0 +} + +func (m *Conversation) GetUserID() string { + if m != nil { + return m.UserID + } + return "" +} + +func (m *Conversation) GetGroupID() string { + if m != nil { + return m.GroupID + } + return "" +} + +func (m *Conversation) GetUnreadCount() int32 { + if m != nil { + return m.UnreadCount + } + return 0 +} + +func (m *Conversation) GetDraftTextTime() int64 { + if m != nil { + return m.DraftTextTime + } + return 0 +} + +func (m *Conversation) GetIsPinned() bool { + if m != nil { + return m.IsPinned + } + return false +} + +func (m *Conversation) GetAttachedInfo() string { + if m != nil { + return m.AttachedInfo + } + return "" +} + +func (m *Conversation) GetIsPrivateChat() bool { + if m != nil { + return m.IsPrivateChat + } + return false +} + +func (m *Conversation) GetEx() string { + if m != nil { + return m.Ex + } + return "" +} + +type SetConversationReq struct { + Conversation *Conversation `protobuf:"bytes,1,opt,name=Conversation" json:"Conversation,omitempty"` + NotificationType int32 `protobuf:"varint,2,opt,name=notificationType" json:"notificationType,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetConversationReq) Reset() { *m = SetConversationReq{} } +func (m *SetConversationReq) String() string { return proto.CompactTextString(m) } +func (*SetConversationReq) ProtoMessage() {} +func (*SetConversationReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{12} +} +func (m *SetConversationReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetConversationReq.Unmarshal(m, b) +} +func (m *SetConversationReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetConversationReq.Marshal(b, m, deterministic) +} +func (dst *SetConversationReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetConversationReq.Merge(dst, src) +} +func (m *SetConversationReq) XXX_Size() int { + return xxx_messageInfo_SetConversationReq.Size(m) +} +func (m *SetConversationReq) XXX_DiscardUnknown() { + xxx_messageInfo_SetConversationReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SetConversationReq proto.InternalMessageInfo + +func (m *SetConversationReq) GetConversation() *Conversation { + if m != nil { + return m.Conversation + } + return nil +} + +func (m *SetConversationReq) GetNotificationType() int32 { + if m != nil { + return m.NotificationType + } + return 0 +} + +func (m *SetConversationReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type SetConversationResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetConversationResp) Reset() { *m = SetConversationResp{} } +func (m *SetConversationResp) String() string { return proto.CompactTextString(m) } +func (*SetConversationResp) ProtoMessage() {} +func (*SetConversationResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{13} +} +func (m *SetConversationResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetConversationResp.Unmarshal(m, b) +} +func (m *SetConversationResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetConversationResp.Marshal(b, m, deterministic) +} +func (dst *SetConversationResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetConversationResp.Merge(dst, src) +} +func (m *SetConversationResp) XXX_Size() int { + return xxx_messageInfo_SetConversationResp.Size(m) +} +func (m *SetConversationResp) XXX_DiscardUnknown() { + xxx_messageInfo_SetConversationResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SetConversationResp proto.InternalMessageInfo + +func (m *SetConversationResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type SetRecvMsgOptReq struct { + OwnerUserID string `protobuf:"bytes,1,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + ConversationID string `protobuf:"bytes,2,opt,name=ConversationID" json:"ConversationID,omitempty"` + RecvMsgOpt int32 `protobuf:"varint,3,opt,name=RecvMsgOpt" json:"RecvMsgOpt,omitempty"` + NotificationType int32 `protobuf:"varint,4,opt,name=notificationType" json:"notificationType,omitempty"` + OperationID string `protobuf:"bytes,5,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetRecvMsgOptReq) Reset() { *m = SetRecvMsgOptReq{} } +func (m *SetRecvMsgOptReq) String() string { return proto.CompactTextString(m) } +func (*SetRecvMsgOptReq) ProtoMessage() {} +func (*SetRecvMsgOptReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{14} +} +func (m *SetRecvMsgOptReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetRecvMsgOptReq.Unmarshal(m, b) +} +func (m *SetRecvMsgOptReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetRecvMsgOptReq.Marshal(b, m, deterministic) +} +func (dst *SetRecvMsgOptReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetRecvMsgOptReq.Merge(dst, src) +} +func (m *SetRecvMsgOptReq) XXX_Size() int { + return xxx_messageInfo_SetRecvMsgOptReq.Size(m) +} +func (m *SetRecvMsgOptReq) XXX_DiscardUnknown() { + xxx_messageInfo_SetRecvMsgOptReq.DiscardUnknown(m) +} + +var xxx_messageInfo_SetRecvMsgOptReq proto.InternalMessageInfo + +func (m *SetRecvMsgOptReq) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *SetRecvMsgOptReq) GetConversationID() string { + if m != nil { + return m.ConversationID + } + return "" +} + +func (m *SetRecvMsgOptReq) GetRecvMsgOpt() int32 { + if m != nil { + return m.RecvMsgOpt + } + return 0 +} + +func (m *SetRecvMsgOptReq) GetNotificationType() int32 { + if m != nil { + return m.NotificationType + } + return 0 +} + +func (m *SetRecvMsgOptReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type SetRecvMsgOptResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetRecvMsgOptResp) Reset() { *m = SetRecvMsgOptResp{} } +func (m *SetRecvMsgOptResp) String() string { return proto.CompactTextString(m) } +func (*SetRecvMsgOptResp) ProtoMessage() {} +func (*SetRecvMsgOptResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{15} +} +func (m *SetRecvMsgOptResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetRecvMsgOptResp.Unmarshal(m, b) +} +func (m *SetRecvMsgOptResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetRecvMsgOptResp.Marshal(b, m, deterministic) +} +func (dst *SetRecvMsgOptResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetRecvMsgOptResp.Merge(dst, src) +} +func (m *SetRecvMsgOptResp) XXX_Size() int { + return xxx_messageInfo_SetRecvMsgOptResp.Size(m) +} +func (m *SetRecvMsgOptResp) XXX_DiscardUnknown() { + xxx_messageInfo_SetRecvMsgOptResp.DiscardUnknown(m) +} + +var xxx_messageInfo_SetRecvMsgOptResp proto.InternalMessageInfo + +func (m *SetRecvMsgOptResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetConversationReq struct { + ConversationID string `protobuf:"bytes,1,opt,name=ConversationID" json:"ConversationID,omitempty"` + OwnerUserID string `protobuf:"bytes,2,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetConversationReq) Reset() { *m = GetConversationReq{} } +func (m *GetConversationReq) String() string { return proto.CompactTextString(m) } +func (*GetConversationReq) ProtoMessage() {} +func (*GetConversationReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{16} +} +func (m *GetConversationReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetConversationReq.Unmarshal(m, b) +} +func (m *GetConversationReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetConversationReq.Marshal(b, m, deterministic) +} +func (dst *GetConversationReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetConversationReq.Merge(dst, src) +} +func (m *GetConversationReq) XXX_Size() int { + return xxx_messageInfo_GetConversationReq.Size(m) +} +func (m *GetConversationReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetConversationReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetConversationReq proto.InternalMessageInfo + +func (m *GetConversationReq) GetConversationID() string { + if m != nil { + return m.ConversationID + } + return "" +} + +func (m *GetConversationReq) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *GetConversationReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetConversationResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Conversation *Conversation `protobuf:"bytes,2,opt,name=Conversation" json:"Conversation,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetConversationResp) Reset() { *m = GetConversationResp{} } +func (m *GetConversationResp) String() string { return proto.CompactTextString(m) } +func (*GetConversationResp) ProtoMessage() {} +func (*GetConversationResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{17} +} +func (m *GetConversationResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetConversationResp.Unmarshal(m, b) +} +func (m *GetConversationResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetConversationResp.Marshal(b, m, deterministic) +} +func (dst *GetConversationResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetConversationResp.Merge(dst, src) +} +func (m *GetConversationResp) XXX_Size() int { + return xxx_messageInfo_GetConversationResp.Size(m) +} +func (m *GetConversationResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetConversationResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetConversationResp proto.InternalMessageInfo + +func (m *GetConversationResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetConversationResp) GetConversation() *Conversation { + if m != nil { + return m.Conversation + } + return nil +} + +type GetConversationsReq struct { + OwnerUserID string `protobuf:"bytes,1,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + ConversationIDs []string `protobuf:"bytes,2,rep,name=ConversationIDs" json:"ConversationIDs,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetConversationsReq) Reset() { *m = GetConversationsReq{} } +func (m *GetConversationsReq) String() string { return proto.CompactTextString(m) } +func (*GetConversationsReq) ProtoMessage() {} +func (*GetConversationsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{18} +} +func (m *GetConversationsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetConversationsReq.Unmarshal(m, b) +} +func (m *GetConversationsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetConversationsReq.Marshal(b, m, deterministic) +} +func (dst *GetConversationsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetConversationsReq.Merge(dst, src) +} +func (m *GetConversationsReq) XXX_Size() int { + return xxx_messageInfo_GetConversationsReq.Size(m) +} +func (m *GetConversationsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetConversationsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetConversationsReq proto.InternalMessageInfo + +func (m *GetConversationsReq) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *GetConversationsReq) GetConversationIDs() []string { + if m != nil { + return m.ConversationIDs + } + return nil +} + +func (m *GetConversationsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetConversationsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Conversations []*Conversation `protobuf:"bytes,2,rep,name=Conversations" json:"Conversations,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetConversationsResp) Reset() { *m = GetConversationsResp{} } +func (m *GetConversationsResp) String() string { return proto.CompactTextString(m) } +func (*GetConversationsResp) ProtoMessage() {} +func (*GetConversationsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{19} +} +func (m *GetConversationsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetConversationsResp.Unmarshal(m, b) +} +func (m *GetConversationsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetConversationsResp.Marshal(b, m, deterministic) +} +func (dst *GetConversationsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetConversationsResp.Merge(dst, src) +} +func (m *GetConversationsResp) XXX_Size() int { + return xxx_messageInfo_GetConversationsResp.Size(m) +} +func (m *GetConversationsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetConversationsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetConversationsResp proto.InternalMessageInfo + +func (m *GetConversationsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetConversationsResp) GetConversations() []*Conversation { + if m != nil { + return m.Conversations + } + return nil +} + +type GetAllConversationsReq struct { + OwnerUserID string `protobuf:"bytes,1,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAllConversationsReq) Reset() { *m = GetAllConversationsReq{} } +func (m *GetAllConversationsReq) String() string { return proto.CompactTextString(m) } +func (*GetAllConversationsReq) ProtoMessage() {} +func (*GetAllConversationsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{20} +} +func (m *GetAllConversationsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAllConversationsReq.Unmarshal(m, b) +} +func (m *GetAllConversationsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAllConversationsReq.Marshal(b, m, deterministic) +} +func (dst *GetAllConversationsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAllConversationsReq.Merge(dst, src) +} +func (m *GetAllConversationsReq) XXX_Size() int { + return xxx_messageInfo_GetAllConversationsReq.Size(m) +} +func (m *GetAllConversationsReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetAllConversationsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAllConversationsReq proto.InternalMessageInfo + +func (m *GetAllConversationsReq) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *GetAllConversationsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetAllConversationsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Conversations []*Conversation `protobuf:"bytes,2,rep,name=Conversations" json:"Conversations,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAllConversationsResp) Reset() { *m = GetAllConversationsResp{} } +func (m *GetAllConversationsResp) String() string { return proto.CompactTextString(m) } +func (*GetAllConversationsResp) ProtoMessage() {} +func (*GetAllConversationsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{21} +} +func (m *GetAllConversationsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAllConversationsResp.Unmarshal(m, b) +} +func (m *GetAllConversationsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAllConversationsResp.Marshal(b, m, deterministic) +} +func (dst *GetAllConversationsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAllConversationsResp.Merge(dst, src) +} +func (m *GetAllConversationsResp) XXX_Size() int { + return xxx_messageInfo_GetAllConversationsResp.Size(m) +} +func (m *GetAllConversationsResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetAllConversationsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAllConversationsResp proto.InternalMessageInfo + +func (m *GetAllConversationsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetAllConversationsResp) GetConversations() []*Conversation { + if m != nil { + return m.Conversations + } + return nil +} + +type BatchSetConversationsReq struct { + Conversations []*Conversation `protobuf:"bytes,1,rep,name=Conversations" json:"Conversations,omitempty"` + OwnerUserID string `protobuf:"bytes,2,opt,name=OwnerUserID" json:"OwnerUserID,omitempty"` + NotificationType int32 `protobuf:"varint,3,opt,name=notificationType" json:"notificationType,omitempty"` + OperationID string `protobuf:"bytes,4,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BatchSetConversationsReq) Reset() { *m = BatchSetConversationsReq{} } +func (m *BatchSetConversationsReq) String() string { return proto.CompactTextString(m) } +func (*BatchSetConversationsReq) ProtoMessage() {} +func (*BatchSetConversationsReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{22} +} +func (m *BatchSetConversationsReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BatchSetConversationsReq.Unmarshal(m, b) +} +func (m *BatchSetConversationsReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BatchSetConversationsReq.Marshal(b, m, deterministic) +} +func (dst *BatchSetConversationsReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_BatchSetConversationsReq.Merge(dst, src) +} +func (m *BatchSetConversationsReq) XXX_Size() int { + return xxx_messageInfo_BatchSetConversationsReq.Size(m) +} +func (m *BatchSetConversationsReq) XXX_DiscardUnknown() { + xxx_messageInfo_BatchSetConversationsReq.DiscardUnknown(m) +} + +var xxx_messageInfo_BatchSetConversationsReq proto.InternalMessageInfo + +func (m *BatchSetConversationsReq) GetConversations() []*Conversation { + if m != nil { + return m.Conversations + } + return nil +} + +func (m *BatchSetConversationsReq) GetOwnerUserID() string { + if m != nil { + return m.OwnerUserID + } + return "" +} + +func (m *BatchSetConversationsReq) GetNotificationType() int32 { + if m != nil { + return m.NotificationType + } + return 0 +} + +func (m *BatchSetConversationsReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type BatchSetConversationsResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + Success []string `protobuf:"bytes,2,rep,name=Success" json:"Success,omitempty"` + Failed []string `protobuf:"bytes,3,rep,name=Failed" json:"Failed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BatchSetConversationsResp) Reset() { *m = BatchSetConversationsResp{} } +func (m *BatchSetConversationsResp) String() string { return proto.CompactTextString(m) } +func (*BatchSetConversationsResp) ProtoMessage() {} +func (*BatchSetConversationsResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{23} +} +func (m *BatchSetConversationsResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BatchSetConversationsResp.Unmarshal(m, b) +} +func (m *BatchSetConversationsResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BatchSetConversationsResp.Marshal(b, m, deterministic) +} +func (dst *BatchSetConversationsResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_BatchSetConversationsResp.Merge(dst, src) +} +func (m *BatchSetConversationsResp) XXX_Size() int { + return xxx_messageInfo_BatchSetConversationsResp.Size(m) +} +func (m *BatchSetConversationsResp) XXX_DiscardUnknown() { + xxx_messageInfo_BatchSetConversationsResp.DiscardUnknown(m) +} + +var xxx_messageInfo_BatchSetConversationsResp proto.InternalMessageInfo + +func (m *BatchSetConversationsResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *BatchSetConversationsResp) GetSuccess() []string { + if m != nil { + return m.Success + } + return nil +} + +func (m *BatchSetConversationsResp) GetFailed() []string { + if m != nil { + return m.Failed + } + return nil +} + +type ResignUserReq struct { + UserId string `protobuf:"bytes,1,opt,name=UserId" json:"UserId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResignUserReq) Reset() { *m = ResignUserReq{} } +func (m *ResignUserReq) String() string { return proto.CompactTextString(m) } +func (*ResignUserReq) ProtoMessage() {} +func (*ResignUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{24} +} +func (m *ResignUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResignUserReq.Unmarshal(m, b) +} +func (m *ResignUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResignUserReq.Marshal(b, m, deterministic) +} +func (dst *ResignUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResignUserReq.Merge(dst, src) +} +func (m *ResignUserReq) XXX_Size() int { + return xxx_messageInfo_ResignUserReq.Size(m) +} +func (m *ResignUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_ResignUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_ResignUserReq proto.InternalMessageInfo + +func (m *ResignUserReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *ResignUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type ResignUserResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=commonResp" json:"commonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResignUserResp) Reset() { *m = ResignUserResp{} } +func (m *ResignUserResp) String() string { return proto.CompactTextString(m) } +func (*ResignUserResp) ProtoMessage() {} +func (*ResignUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{25} +} +func (m *ResignUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResignUserResp.Unmarshal(m, b) +} +func (m *ResignUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResignUserResp.Marshal(b, m, deterministic) +} +func (dst *ResignUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResignUserResp.Merge(dst, src) +} +func (m *ResignUserResp) XXX_Size() int { + return xxx_messageInfo_ResignUserResp.Size(m) +} +func (m *ResignUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_ResignUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_ResignUserResp proto.InternalMessageInfo + +func (m *ResignUserResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetUserByIdReq struct { + UserId string `protobuf:"bytes,1,opt,name=UserId" json:"UserId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserByIdReq) Reset() { *m = GetUserByIdReq{} } +func (m *GetUserByIdReq) String() string { return proto.CompactTextString(m) } +func (*GetUserByIdReq) ProtoMessage() {} +func (*GetUserByIdReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{26} +} +func (m *GetUserByIdReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserByIdReq.Unmarshal(m, b) +} +func (m *GetUserByIdReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserByIdReq.Marshal(b, m, deterministic) +} +func (dst *GetUserByIdReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserByIdReq.Merge(dst, src) +} +func (m *GetUserByIdReq) XXX_Size() int { + return xxx_messageInfo_GetUserByIdReq.Size(m) +} +func (m *GetUserByIdReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserByIdReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserByIdReq proto.InternalMessageInfo + +func (m *GetUserByIdReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *GetUserByIdReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type User struct { + ProfilePhoto string `protobuf:"bytes,1,opt,name=ProfilePhoto" json:"ProfilePhoto,omitempty"` + Nickname string `protobuf:"bytes,2,opt,name=Nickname" json:"Nickname,omitempty"` + UserId string `protobuf:"bytes,3,opt,name=UserId" json:"UserId,omitempty"` + CreateTime string `protobuf:"bytes,4,opt,name=CreateTime" json:"CreateTime,omitempty"` + IsBlock bool `protobuf:"varint,5,opt,name=IsBlock" json:"IsBlock,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *User) Reset() { *m = User{} } +func (m *User) String() string { return proto.CompactTextString(m) } +func (*User) ProtoMessage() {} +func (*User) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{27} +} +func (m *User) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_User.Unmarshal(m, b) +} +func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_User.Marshal(b, m, deterministic) +} +func (dst *User) XXX_Merge(src proto.Message) { + xxx_messageInfo_User.Merge(dst, src) +} +func (m *User) XXX_Size() int { + return xxx_messageInfo_User.Size(m) +} +func (m *User) XXX_DiscardUnknown() { + xxx_messageInfo_User.DiscardUnknown(m) +} + +var xxx_messageInfo_User proto.InternalMessageInfo + +func (m *User) GetProfilePhoto() string { + if m != nil { + return m.ProfilePhoto + } + return "" +} + +func (m *User) GetNickname() string { + if m != nil { + return m.Nickname + } + return "" +} + +func (m *User) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *User) GetCreateTime() string { + if m != nil { + return m.CreateTime + } + return "" +} + +func (m *User) GetIsBlock() bool { + if m != nil { + return m.IsBlock + } + return false +} + +type GetUserByIdResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + User *User `protobuf:"bytes,2,opt,name=user" json:"user,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUserByIdResp) Reset() { *m = GetUserByIdResp{} } +func (m *GetUserByIdResp) String() string { return proto.CompactTextString(m) } +func (*GetUserByIdResp) ProtoMessage() {} +func (*GetUserByIdResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{28} +} +func (m *GetUserByIdResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUserByIdResp.Unmarshal(m, b) +} +func (m *GetUserByIdResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUserByIdResp.Marshal(b, m, deterministic) +} +func (dst *GetUserByIdResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUserByIdResp.Merge(dst, src) +} +func (m *GetUserByIdResp) XXX_Size() int { + return xxx_messageInfo_GetUserByIdResp.Size(m) +} +func (m *GetUserByIdResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUserByIdResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUserByIdResp proto.InternalMessageInfo + +func (m *GetUserByIdResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUserByIdResp) GetUser() *User { + if m != nil { + return m.User + } + return nil +} + +type GetUsersByNameReq struct { + UserName string `protobuf:"bytes,1,opt,name=UserName" json:"UserName,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersByNameReq) Reset() { *m = GetUsersByNameReq{} } +func (m *GetUsersByNameReq) String() string { return proto.CompactTextString(m) } +func (*GetUsersByNameReq) ProtoMessage() {} +func (*GetUsersByNameReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{29} +} +func (m *GetUsersByNameReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersByNameReq.Unmarshal(m, b) +} +func (m *GetUsersByNameReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersByNameReq.Marshal(b, m, deterministic) +} +func (dst *GetUsersByNameReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersByNameReq.Merge(dst, src) +} +func (m *GetUsersByNameReq) XXX_Size() int { + return xxx_messageInfo_GetUsersByNameReq.Size(m) +} +func (m *GetUsersByNameReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersByNameReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersByNameReq proto.InternalMessageInfo + +func (m *GetUsersByNameReq) GetUserName() string { + if m != nil { + return m.UserName + } + return "" +} + +func (m *GetUsersByNameReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetUsersByNameReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetUsersByNameResp struct { + Users []*User `protobuf:"bytes,1,rep,name=users" json:"users,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + UserNums int32 `protobuf:"varint,3,opt,name=UserNums" json:"UserNums,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersByNameResp) Reset() { *m = GetUsersByNameResp{} } +func (m *GetUsersByNameResp) String() string { return proto.CompactTextString(m) } +func (*GetUsersByNameResp) ProtoMessage() {} +func (*GetUsersByNameResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{30} +} +func (m *GetUsersByNameResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersByNameResp.Unmarshal(m, b) +} +func (m *GetUsersByNameResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersByNameResp.Marshal(b, m, deterministic) +} +func (dst *GetUsersByNameResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersByNameResp.Merge(dst, src) +} +func (m *GetUsersByNameResp) XXX_Size() int { + return xxx_messageInfo_GetUsersByNameResp.Size(m) +} +func (m *GetUsersByNameResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersByNameResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersByNameResp proto.InternalMessageInfo + +func (m *GetUsersByNameResp) GetUsers() []*User { + if m != nil { + return m.Users + } + return nil +} + +func (m *GetUsersByNameResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetUsersByNameResp) GetUserNums() int32 { + if m != nil { + return m.UserNums + } + return 0 +} + +type AlterUserReq struct { + UserId string `protobuf:"bytes,1,opt,name=UserId" json:"UserId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + PhoneNumber int64 `protobuf:"varint,3,opt,name=PhoneNumber" json:"PhoneNumber,omitempty"` + Nickname string `protobuf:"bytes,4,opt,name=Nickname" json:"Nickname,omitempty"` + Email string `protobuf:"bytes,5,opt,name=Email" json:"Email,omitempty"` + OpUserId string `protobuf:"bytes,6,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AlterUserReq) Reset() { *m = AlterUserReq{} } +func (m *AlterUserReq) String() string { return proto.CompactTextString(m) } +func (*AlterUserReq) ProtoMessage() {} +func (*AlterUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{31} +} +func (m *AlterUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AlterUserReq.Unmarshal(m, b) +} +func (m *AlterUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AlterUserReq.Marshal(b, m, deterministic) +} +func (dst *AlterUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AlterUserReq.Merge(dst, src) +} +func (m *AlterUserReq) XXX_Size() int { + return xxx_messageInfo_AlterUserReq.Size(m) +} +func (m *AlterUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_AlterUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AlterUserReq proto.InternalMessageInfo + +func (m *AlterUserReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *AlterUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *AlterUserReq) GetPhoneNumber() int64 { + if m != nil { + return m.PhoneNumber + } + return 0 +} + +func (m *AlterUserReq) GetNickname() string { + if m != nil { + return m.Nickname + } + return "" +} + +func (m *AlterUserReq) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *AlterUserReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type AlterUserResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AlterUserResp) Reset() { *m = AlterUserResp{} } +func (m *AlterUserResp) String() string { return proto.CompactTextString(m) } +func (*AlterUserResp) ProtoMessage() {} +func (*AlterUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{32} +} +func (m *AlterUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AlterUserResp.Unmarshal(m, b) +} +func (m *AlterUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AlterUserResp.Marshal(b, m, deterministic) +} +func (dst *AlterUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AlterUserResp.Merge(dst, src) +} +func (m *AlterUserResp) XXX_Size() int { + return xxx_messageInfo_AlterUserResp.Size(m) +} +func (m *AlterUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_AlterUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AlterUserResp proto.InternalMessageInfo + +func (m *AlterUserResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetUsersReq struct { + OperationID string `protobuf:"bytes,1,opt,name=OperationID" json:"OperationID,omitempty"` + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,2,opt,name=Pagination" json:"Pagination,omitempty"` + UserName string `protobuf:"bytes,3,opt,name=UserName" json:"UserName,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersReq) Reset() { *m = GetUsersReq{} } +func (m *GetUsersReq) String() string { return proto.CompactTextString(m) } +func (*GetUsersReq) ProtoMessage() {} +func (*GetUsersReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{33} +} +func (m *GetUsersReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersReq.Unmarshal(m, b) +} +func (m *GetUsersReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersReq.Marshal(b, m, deterministic) +} +func (dst *GetUsersReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersReq.Merge(dst, src) +} +func (m *GetUsersReq) XXX_Size() int { + return xxx_messageInfo_GetUsersReq.Size(m) +} +func (m *GetUsersReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersReq proto.InternalMessageInfo + +func (m *GetUsersReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetUsersReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetUsersReq) GetUserName() string { + if m != nil { + return m.UserName + } + return "" +} + +type GetUsersResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + User []*User `protobuf:"bytes,2,rep,name=user" json:"user,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + UserNums int32 `protobuf:"varint,4,opt,name=UserNums" json:"UserNums,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetUsersResp) Reset() { *m = GetUsersResp{} } +func (m *GetUsersResp) String() string { return proto.CompactTextString(m) } +func (*GetUsersResp) ProtoMessage() {} +func (*GetUsersResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{34} +} +func (m *GetUsersResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetUsersResp.Unmarshal(m, b) +} +func (m *GetUsersResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetUsersResp.Marshal(b, m, deterministic) +} +func (dst *GetUsersResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetUsersResp.Merge(dst, src) +} +func (m *GetUsersResp) XXX_Size() int { + return xxx_messageInfo_GetUsersResp.Size(m) +} +func (m *GetUsersResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetUsersResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetUsersResp proto.InternalMessageInfo + +func (m *GetUsersResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetUsersResp) GetUser() []*User { + if m != nil { + return m.User + } + return nil +} + +func (m *GetUsersResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetUsersResp) GetUserNums() int32 { + if m != nil { + return m.UserNums + } + return 0 +} + +type AddUserReq struct { + OperationID string `protobuf:"bytes,1,opt,name=OperationID" json:"OperationID,omitempty"` + PhoneNumber string `protobuf:"bytes,2,opt,name=PhoneNumber" json:"PhoneNumber,omitempty"` + UserId string `protobuf:"bytes,3,opt,name=UserId" json:"UserId,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` + OpUserId string `protobuf:"bytes,5,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddUserReq) Reset() { *m = AddUserReq{} } +func (m *AddUserReq) String() string { return proto.CompactTextString(m) } +func (*AddUserReq) ProtoMessage() {} +func (*AddUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{35} +} +func (m *AddUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddUserReq.Unmarshal(m, b) +} +func (m *AddUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddUserReq.Marshal(b, m, deterministic) +} +func (dst *AddUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddUserReq.Merge(dst, src) +} +func (m *AddUserReq) XXX_Size() int { + return xxx_messageInfo_AddUserReq.Size(m) +} +func (m *AddUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_AddUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_AddUserReq proto.InternalMessageInfo + +func (m *AddUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *AddUserReq) GetPhoneNumber() string { + if m != nil { + return m.PhoneNumber + } + return "" +} + +func (m *AddUserReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *AddUserReq) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *AddUserReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type AddUserResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddUserResp) Reset() { *m = AddUserResp{} } +func (m *AddUserResp) String() string { return proto.CompactTextString(m) } +func (*AddUserResp) ProtoMessage() {} +func (*AddUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{36} +} +func (m *AddUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddUserResp.Unmarshal(m, b) +} +func (m *AddUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddUserResp.Marshal(b, m, deterministic) +} +func (dst *AddUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddUserResp.Merge(dst, src) +} +func (m *AddUserResp) XXX_Size() int { + return xxx_messageInfo_AddUserResp.Size(m) +} +func (m *AddUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_AddUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_AddUserResp proto.InternalMessageInfo + +func (m *AddUserResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type BlockUserReq struct { + UserId string `protobuf:"bytes,1,opt,name=UserId" json:"UserId,omitempty"` + EndDisableTime string `protobuf:"bytes,2,opt,name=EndDisableTime" json:"EndDisableTime,omitempty"` + OperationID string `protobuf:"bytes,3,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserId string `protobuf:"bytes,4,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlockUserReq) Reset() { *m = BlockUserReq{} } +func (m *BlockUserReq) String() string { return proto.CompactTextString(m) } +func (*BlockUserReq) ProtoMessage() {} +func (*BlockUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{37} +} +func (m *BlockUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BlockUserReq.Unmarshal(m, b) +} +func (m *BlockUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BlockUserReq.Marshal(b, m, deterministic) +} +func (dst *BlockUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockUserReq.Merge(dst, src) +} +func (m *BlockUserReq) XXX_Size() int { + return xxx_messageInfo_BlockUserReq.Size(m) +} +func (m *BlockUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_BlockUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockUserReq proto.InternalMessageInfo + +func (m *BlockUserReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *BlockUserReq) GetEndDisableTime() string { + if m != nil { + return m.EndDisableTime + } + return "" +} + +func (m *BlockUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *BlockUserReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type BlockUserResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlockUserResp) Reset() { *m = BlockUserResp{} } +func (m *BlockUserResp) String() string { return proto.CompactTextString(m) } +func (*BlockUserResp) ProtoMessage() {} +func (*BlockUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{38} +} +func (m *BlockUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BlockUserResp.Unmarshal(m, b) +} +func (m *BlockUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BlockUserResp.Marshal(b, m, deterministic) +} +func (dst *BlockUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockUserResp.Merge(dst, src) +} +func (m *BlockUserResp) XXX_Size() int { + return xxx_messageInfo_BlockUserResp.Size(m) +} +func (m *BlockUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_BlockUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockUserResp proto.InternalMessageInfo + +func (m *BlockUserResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type UnBlockUserReq struct { + UserId string `protobuf:"bytes,1,opt,name=UserId" json:"UserId,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserId string `protobuf:"bytes,3,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UnBlockUserReq) Reset() { *m = UnBlockUserReq{} } +func (m *UnBlockUserReq) String() string { return proto.CompactTextString(m) } +func (*UnBlockUserReq) ProtoMessage() {} +func (*UnBlockUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{39} +} +func (m *UnBlockUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UnBlockUserReq.Unmarshal(m, b) +} +func (m *UnBlockUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UnBlockUserReq.Marshal(b, m, deterministic) +} +func (dst *UnBlockUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnBlockUserReq.Merge(dst, src) +} +func (m *UnBlockUserReq) XXX_Size() int { + return xxx_messageInfo_UnBlockUserReq.Size(m) +} +func (m *UnBlockUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_UnBlockUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UnBlockUserReq proto.InternalMessageInfo + +func (m *UnBlockUserReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *UnBlockUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *UnBlockUserReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type UnBlockUserResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UnBlockUserResp) Reset() { *m = UnBlockUserResp{} } +func (m *UnBlockUserResp) String() string { return proto.CompactTextString(m) } +func (*UnBlockUserResp) ProtoMessage() {} +func (*UnBlockUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{40} +} +func (m *UnBlockUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UnBlockUserResp.Unmarshal(m, b) +} +func (m *UnBlockUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UnBlockUserResp.Marshal(b, m, deterministic) +} +func (dst *UnBlockUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnBlockUserResp.Merge(dst, src) +} +func (m *UnBlockUserResp) XXX_Size() int { + return xxx_messageInfo_UnBlockUserResp.Size(m) +} +func (m *UnBlockUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_UnBlockUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_UnBlockUserResp proto.InternalMessageInfo + +func (m *UnBlockUserResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +type GetBlockUsersReq struct { + Pagination *sdk_ws.RequestPagination `protobuf:"bytes,1,opt,name=Pagination" json:"Pagination,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + BlockUserNum int32 `protobuf:"varint,3,opt,name=BlockUserNum" json:"BlockUserNum,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetBlockUsersReq) Reset() { *m = GetBlockUsersReq{} } +func (m *GetBlockUsersReq) String() string { return proto.CompactTextString(m) } +func (*GetBlockUsersReq) ProtoMessage() {} +func (*GetBlockUsersReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{41} +} +func (m *GetBlockUsersReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetBlockUsersReq.Unmarshal(m, b) +} +func (m *GetBlockUsersReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetBlockUsersReq.Marshal(b, m, deterministic) +} +func (dst *GetBlockUsersReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetBlockUsersReq.Merge(dst, src) +} +func (m *GetBlockUsersReq) XXX_Size() int { + return xxx_messageInfo_GetBlockUsersReq.Size(m) +} +func (m *GetBlockUsersReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetBlockUsersReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetBlockUsersReq proto.InternalMessageInfo + +func (m *GetBlockUsersReq) GetPagination() *sdk_ws.RequestPagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetBlockUsersReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *GetBlockUsersReq) GetBlockUserNum() int32 { + if m != nil { + return m.BlockUserNum + } + return 0 +} + +type BlockUser struct { + User *User `protobuf:"bytes,1,opt,name=User" json:"User,omitempty"` + BeginDisableTime string `protobuf:"bytes,2,opt,name=BeginDisableTime" json:"BeginDisableTime,omitempty"` + EndDisableTime string `protobuf:"bytes,3,opt,name=EndDisableTime" json:"EndDisableTime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlockUser) Reset() { *m = BlockUser{} } +func (m *BlockUser) String() string { return proto.CompactTextString(m) } +func (*BlockUser) ProtoMessage() {} +func (*BlockUser) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{42} +} +func (m *BlockUser) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BlockUser.Unmarshal(m, b) +} +func (m *BlockUser) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BlockUser.Marshal(b, m, deterministic) +} +func (dst *BlockUser) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockUser.Merge(dst, src) +} +func (m *BlockUser) XXX_Size() int { + return xxx_messageInfo_BlockUser.Size(m) +} +func (m *BlockUser) XXX_DiscardUnknown() { + xxx_messageInfo_BlockUser.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockUser proto.InternalMessageInfo + +func (m *BlockUser) GetUser() *User { + if m != nil { + return m.User + } + return nil +} + +func (m *BlockUser) GetBeginDisableTime() string { + if m != nil { + return m.BeginDisableTime + } + return "" +} + +func (m *BlockUser) GetEndDisableTime() string { + if m != nil { + return m.EndDisableTime + } + return "" +} + +type GetBlockUsersResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + BlockUsers []*BlockUser `protobuf:"bytes,2,rep,name=BlockUsers" json:"BlockUsers,omitempty"` + Pagination *sdk_ws.ResponsePagination `protobuf:"bytes,3,opt,name=Pagination" json:"Pagination,omitempty"` + UserNums int32 `protobuf:"varint,4,opt,name=UserNums" json:"UserNums,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetBlockUsersResp) Reset() { *m = GetBlockUsersResp{} } +func (m *GetBlockUsersResp) String() string { return proto.CompactTextString(m) } +func (*GetBlockUsersResp) ProtoMessage() {} +func (*GetBlockUsersResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{43} +} +func (m *GetBlockUsersResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetBlockUsersResp.Unmarshal(m, b) +} +func (m *GetBlockUsersResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetBlockUsersResp.Marshal(b, m, deterministic) +} +func (dst *GetBlockUsersResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetBlockUsersResp.Merge(dst, src) +} +func (m *GetBlockUsersResp) XXX_Size() int { + return xxx_messageInfo_GetBlockUsersResp.Size(m) +} +func (m *GetBlockUsersResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetBlockUsersResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetBlockUsersResp proto.InternalMessageInfo + +func (m *GetBlockUsersResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func (m *GetBlockUsersResp) GetBlockUsers() []*BlockUser { + if m != nil { + return m.BlockUsers + } + return nil +} + +func (m *GetBlockUsersResp) GetPagination() *sdk_ws.ResponsePagination { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *GetBlockUsersResp) GetUserNums() int32 { + if m != nil { + return m.UserNums + } + return 0 +} + +type GetBlockUserByIdReq struct { + UserId string `protobuf:"bytes,1,opt,name=User_id,json=UserId" json:"User_id,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetBlockUserByIdReq) Reset() { *m = GetBlockUserByIdReq{} } +func (m *GetBlockUserByIdReq) String() string { return proto.CompactTextString(m) } +func (*GetBlockUserByIdReq) ProtoMessage() {} +func (*GetBlockUserByIdReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{44} +} +func (m *GetBlockUserByIdReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetBlockUserByIdReq.Unmarshal(m, b) +} +func (m *GetBlockUserByIdReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetBlockUserByIdReq.Marshal(b, m, deterministic) +} +func (dst *GetBlockUserByIdReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetBlockUserByIdReq.Merge(dst, src) +} +func (m *GetBlockUserByIdReq) XXX_Size() int { + return xxx_messageInfo_GetBlockUserByIdReq.Size(m) +} +func (m *GetBlockUserByIdReq) XXX_DiscardUnknown() { + xxx_messageInfo_GetBlockUserByIdReq.DiscardUnknown(m) +} + +var xxx_messageInfo_GetBlockUserByIdReq proto.InternalMessageInfo + +func (m *GetBlockUserByIdReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *GetBlockUserByIdReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +type GetBlockUserByIdResp struct { + BlockUser *BlockUser `protobuf:"bytes,2,opt,name=BlockUser" json:"BlockUser,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetBlockUserByIdResp) Reset() { *m = GetBlockUserByIdResp{} } +func (m *GetBlockUserByIdResp) String() string { return proto.CompactTextString(m) } +func (*GetBlockUserByIdResp) ProtoMessage() {} +func (*GetBlockUserByIdResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{45} +} +func (m *GetBlockUserByIdResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetBlockUserByIdResp.Unmarshal(m, b) +} +func (m *GetBlockUserByIdResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetBlockUserByIdResp.Marshal(b, m, deterministic) +} +func (dst *GetBlockUserByIdResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetBlockUserByIdResp.Merge(dst, src) +} +func (m *GetBlockUserByIdResp) XXX_Size() int { + return xxx_messageInfo_GetBlockUserByIdResp.Size(m) +} +func (m *GetBlockUserByIdResp) XXX_DiscardUnknown() { + xxx_messageInfo_GetBlockUserByIdResp.DiscardUnknown(m) +} + +var xxx_messageInfo_GetBlockUserByIdResp proto.InternalMessageInfo + +func (m *GetBlockUserByIdResp) GetBlockUser() *BlockUser { + if m != nil { + return m.BlockUser + } + return nil +} + +type DeleteUserReq struct { + UserId string `protobuf:"bytes,1,opt,name=User_id,json=UserId" json:"User_id,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=OperationID" json:"OperationID,omitempty"` + OpUserId string `protobuf:"bytes,3,opt,name=OpUserId" json:"OpUserId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteUserReq) Reset() { *m = DeleteUserReq{} } +func (m *DeleteUserReq) String() string { return proto.CompactTextString(m) } +func (*DeleteUserReq) ProtoMessage() {} +func (*DeleteUserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{46} +} +func (m *DeleteUserReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteUserReq.Unmarshal(m, b) +} +func (m *DeleteUserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteUserReq.Marshal(b, m, deterministic) +} +func (dst *DeleteUserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteUserReq.Merge(dst, src) +} +func (m *DeleteUserReq) XXX_Size() int { + return xxx_messageInfo_DeleteUserReq.Size(m) +} +func (m *DeleteUserReq) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteUserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteUserReq proto.InternalMessageInfo + +func (m *DeleteUserReq) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *DeleteUserReq) GetOperationID() string { + if m != nil { + return m.OperationID + } + return "" +} + +func (m *DeleteUserReq) GetOpUserId() string { + if m != nil { + return m.OpUserId + } + return "" +} + +type DeleteUserResp struct { + CommonResp *CommonResp `protobuf:"bytes,1,opt,name=CommonResp" json:"CommonResp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteUserResp) Reset() { *m = DeleteUserResp{} } +func (m *DeleteUserResp) String() string { return proto.CompactTextString(m) } +func (*DeleteUserResp) ProtoMessage() {} +func (*DeleteUserResp) Descriptor() ([]byte, []int) { + return fileDescriptor_user_6133bd34462fbb1a, []int{47} +} +func (m *DeleteUserResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteUserResp.Unmarshal(m, b) +} +func (m *DeleteUserResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteUserResp.Marshal(b, m, deterministic) +} +func (dst *DeleteUserResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteUserResp.Merge(dst, src) +} +func (m *DeleteUserResp) XXX_Size() int { + return xxx_messageInfo_DeleteUserResp.Size(m) +} +func (m *DeleteUserResp) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteUserResp.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteUserResp proto.InternalMessageInfo + +func (m *DeleteUserResp) GetCommonResp() *CommonResp { + if m != nil { + return m.CommonResp + } + return nil +} + +func init() { + proto.RegisterType((*CommonResp)(nil), "user.CommonResp") + proto.RegisterType((*DeleteUsersReq)(nil), "user.DeleteUsersReq") + proto.RegisterType((*DeleteUsersResp)(nil), "user.DeleteUsersResp") + proto.RegisterType((*GetAllUserIDReq)(nil), "user.GetAllUserIDReq") + proto.RegisterType((*GetAllUserIDResp)(nil), "user.GetAllUserIDResp") + proto.RegisterType((*AccountCheckReq)(nil), "user.AccountCheckReq") + proto.RegisterType((*AccountCheckResp)(nil), "user.AccountCheckResp") + proto.RegisterType((*AccountCheckResp_SingleUserStatus)(nil), "user.AccountCheckResp.SingleUserStatus") + proto.RegisterType((*GetUserInfoReq)(nil), "user.GetUserInfoReq") + proto.RegisterType((*GetUserInfoResp)(nil), "user.GetUserInfoResp") + proto.RegisterType((*UpdateUserInfoReq)(nil), "user.UpdateUserInfoReq") + proto.RegisterType((*UpdateUserInfoResp)(nil), "user.UpdateUserInfoResp") + proto.RegisterType((*Conversation)(nil), "user.Conversation") + proto.RegisterType((*SetConversationReq)(nil), "user.SetConversationReq") + proto.RegisterType((*SetConversationResp)(nil), "user.SetConversationResp") + proto.RegisterType((*SetRecvMsgOptReq)(nil), "user.SetRecvMsgOptReq") + proto.RegisterType((*SetRecvMsgOptResp)(nil), "user.SetRecvMsgOptResp") + proto.RegisterType((*GetConversationReq)(nil), "user.GetConversationReq") + proto.RegisterType((*GetConversationResp)(nil), "user.GetConversationResp") + proto.RegisterType((*GetConversationsReq)(nil), "user.GetConversationsReq") + proto.RegisterType((*GetConversationsResp)(nil), "user.GetConversationsResp") + proto.RegisterType((*GetAllConversationsReq)(nil), "user.GetAllConversationsReq") + proto.RegisterType((*GetAllConversationsResp)(nil), "user.GetAllConversationsResp") + proto.RegisterType((*BatchSetConversationsReq)(nil), "user.BatchSetConversationsReq") + proto.RegisterType((*BatchSetConversationsResp)(nil), "user.BatchSetConversationsResp") + proto.RegisterType((*ResignUserReq)(nil), "user.ResignUserReq") + proto.RegisterType((*ResignUserResp)(nil), "user.ResignUserResp") + proto.RegisterType((*GetUserByIdReq)(nil), "user.GetUserByIdReq") + proto.RegisterType((*User)(nil), "user.User") + proto.RegisterType((*GetUserByIdResp)(nil), "user.GetUserByIdResp") + proto.RegisterType((*GetUsersByNameReq)(nil), "user.GetUsersByNameReq") + proto.RegisterType((*GetUsersByNameResp)(nil), "user.GetUsersByNameResp") + proto.RegisterType((*AlterUserReq)(nil), "user.AlterUserReq") + proto.RegisterType((*AlterUserResp)(nil), "user.AlterUserResp") + proto.RegisterType((*GetUsersReq)(nil), "user.GetUsersReq") + proto.RegisterType((*GetUsersResp)(nil), "user.GetUsersResp") + proto.RegisterType((*AddUserReq)(nil), "user.AddUserReq") + proto.RegisterType((*AddUserResp)(nil), "user.AddUserResp") + proto.RegisterType((*BlockUserReq)(nil), "user.BlockUserReq") + proto.RegisterType((*BlockUserResp)(nil), "user.BlockUserResp") + proto.RegisterType((*UnBlockUserReq)(nil), "user.UnBlockUserReq") + proto.RegisterType((*UnBlockUserResp)(nil), "user.UnBlockUserResp") + proto.RegisterType((*GetBlockUsersReq)(nil), "user.GetBlockUsersReq") + proto.RegisterType((*BlockUser)(nil), "user.BlockUser") + proto.RegisterType((*GetBlockUsersResp)(nil), "user.GetBlockUsersResp") + proto.RegisterType((*GetBlockUserByIdReq)(nil), "user.GetBlockUserByIdReq") + proto.RegisterType((*GetBlockUserByIdResp)(nil), "user.GetBlockUserByIdResp") + proto.RegisterType((*DeleteUserReq)(nil), "user.DeleteUserReq") + proto.RegisterType((*DeleteUserResp)(nil), "user.DeleteUserResp") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for User service + +type UserClient interface { + GetUserInfo(ctx context.Context, in *GetUserInfoReq, opts ...grpc.CallOption) (*GetUserInfoResp, error) + UpdateUserInfo(ctx context.Context, in *UpdateUserInfoReq, opts ...grpc.CallOption) (*UpdateUserInfoResp, error) + DeleteUsers(ctx context.Context, in *DeleteUsersReq, opts ...grpc.CallOption) (*DeleteUsersResp, error) + GetAllUserID(ctx context.Context, in *GetAllUserIDReq, opts ...grpc.CallOption) (*GetAllUserIDResp, error) + AccountCheck(ctx context.Context, in *AccountCheckReq, opts ...grpc.CallOption) (*AccountCheckResp, error) + GetConversation(ctx context.Context, in *GetConversationReq, opts ...grpc.CallOption) (*GetConversationResp, error) + GetAllConversations(ctx context.Context, in *GetAllConversationsReq, opts ...grpc.CallOption) (*GetAllConversationsResp, error) + GetConversations(ctx context.Context, in *GetConversationsReq, opts ...grpc.CallOption) (*GetConversationsResp, error) + BatchSetConversations(ctx context.Context, in *BatchSetConversationsReq, opts ...grpc.CallOption) (*BatchSetConversationsResp, error) + SetConversation(ctx context.Context, in *SetConversationReq, opts ...grpc.CallOption) (*SetConversationResp, error) + SetRecvMsgOpt(ctx context.Context, in *SetRecvMsgOptReq, opts ...grpc.CallOption) (*SetRecvMsgOptResp, error) + GetUserById(ctx context.Context, in *GetUserByIdReq, opts ...grpc.CallOption) (*GetUserByIdResp, error) + GetUsersByName(ctx context.Context, in *GetUsersByNameReq, opts ...grpc.CallOption) (*GetUsersByNameResp, error) + ResignUser(ctx context.Context, in *ResignUserReq, opts ...grpc.CallOption) (*ResignUserResp, error) + AlterUser(ctx context.Context, in *AlterUserReq, opts ...grpc.CallOption) (*AlterUserResp, error) + GetUsers(ctx context.Context, in *GetUsersReq, opts ...grpc.CallOption) (*GetUsersResp, error) + AddUser(ctx context.Context, in *AddUserReq, opts ...grpc.CallOption) (*AddUserResp, error) + BlockUser(ctx context.Context, in *BlockUserReq, opts ...grpc.CallOption) (*BlockUserResp, error) + UnBlockUser(ctx context.Context, in *UnBlockUserReq, opts ...grpc.CallOption) (*UnBlockUserResp, error) + GetBlockUsers(ctx context.Context, in *GetBlockUsersReq, opts ...grpc.CallOption) (*GetBlockUsersResp, error) + GetBlockUserById(ctx context.Context, in *GetBlockUserByIdReq, opts ...grpc.CallOption) (*GetBlockUserByIdResp, error) + DeleteUser(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserResp, error) +} + +type userClient struct { + cc *grpc.ClientConn +} + +func NewUserClient(cc *grpc.ClientConn) UserClient { + return &userClient{cc} +} + +func (c *userClient) GetUserInfo(ctx context.Context, in *GetUserInfoReq, opts ...grpc.CallOption) (*GetUserInfoResp, error) { + out := new(GetUserInfoResp) + err := grpc.Invoke(ctx, "/user.user/GetUserInfo", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) UpdateUserInfo(ctx context.Context, in *UpdateUserInfoReq, opts ...grpc.CallOption) (*UpdateUserInfoResp, error) { + out := new(UpdateUserInfoResp) + err := grpc.Invoke(ctx, "/user.user/UpdateUserInfo", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) DeleteUsers(ctx context.Context, in *DeleteUsersReq, opts ...grpc.CallOption) (*DeleteUsersResp, error) { + out := new(DeleteUsersResp) + err := grpc.Invoke(ctx, "/user.user/DeleteUsers", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetAllUserID(ctx context.Context, in *GetAllUserIDReq, opts ...grpc.CallOption) (*GetAllUserIDResp, error) { + out := new(GetAllUserIDResp) + err := grpc.Invoke(ctx, "/user.user/GetAllUserID", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) AccountCheck(ctx context.Context, in *AccountCheckReq, opts ...grpc.CallOption) (*AccountCheckResp, error) { + out := new(AccountCheckResp) + err := grpc.Invoke(ctx, "/user.user/AccountCheck", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetConversation(ctx context.Context, in *GetConversationReq, opts ...grpc.CallOption) (*GetConversationResp, error) { + out := new(GetConversationResp) + err := grpc.Invoke(ctx, "/user.user/GetConversation", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetAllConversations(ctx context.Context, in *GetAllConversationsReq, opts ...grpc.CallOption) (*GetAllConversationsResp, error) { + out := new(GetAllConversationsResp) + err := grpc.Invoke(ctx, "/user.user/GetAllConversations", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetConversations(ctx context.Context, in *GetConversationsReq, opts ...grpc.CallOption) (*GetConversationsResp, error) { + out := new(GetConversationsResp) + err := grpc.Invoke(ctx, "/user.user/GetConversations", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) BatchSetConversations(ctx context.Context, in *BatchSetConversationsReq, opts ...grpc.CallOption) (*BatchSetConversationsResp, error) { + out := new(BatchSetConversationsResp) + err := grpc.Invoke(ctx, "/user.user/BatchSetConversations", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) SetConversation(ctx context.Context, in *SetConversationReq, opts ...grpc.CallOption) (*SetConversationResp, error) { + out := new(SetConversationResp) + err := grpc.Invoke(ctx, "/user.user/SetConversation", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) SetRecvMsgOpt(ctx context.Context, in *SetRecvMsgOptReq, opts ...grpc.CallOption) (*SetRecvMsgOptResp, error) { + out := new(SetRecvMsgOptResp) + err := grpc.Invoke(ctx, "/user.user/SetRecvMsgOpt", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetUserById(ctx context.Context, in *GetUserByIdReq, opts ...grpc.CallOption) (*GetUserByIdResp, error) { + out := new(GetUserByIdResp) + err := grpc.Invoke(ctx, "/user.user/GetUserById", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetUsersByName(ctx context.Context, in *GetUsersByNameReq, opts ...grpc.CallOption) (*GetUsersByNameResp, error) { + out := new(GetUsersByNameResp) + err := grpc.Invoke(ctx, "/user.user/GetUsersByName", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) ResignUser(ctx context.Context, in *ResignUserReq, opts ...grpc.CallOption) (*ResignUserResp, error) { + out := new(ResignUserResp) + err := grpc.Invoke(ctx, "/user.user/ResignUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) AlterUser(ctx context.Context, in *AlterUserReq, opts ...grpc.CallOption) (*AlterUserResp, error) { + out := new(AlterUserResp) + err := grpc.Invoke(ctx, "/user.user/AlterUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetUsers(ctx context.Context, in *GetUsersReq, opts ...grpc.CallOption) (*GetUsersResp, error) { + out := new(GetUsersResp) + err := grpc.Invoke(ctx, "/user.user/GetUsers", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) AddUser(ctx context.Context, in *AddUserReq, opts ...grpc.CallOption) (*AddUserResp, error) { + out := new(AddUserResp) + err := grpc.Invoke(ctx, "/user.user/AddUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) BlockUser(ctx context.Context, in *BlockUserReq, opts ...grpc.CallOption) (*BlockUserResp, error) { + out := new(BlockUserResp) + err := grpc.Invoke(ctx, "/user.user/BlockUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) UnBlockUser(ctx context.Context, in *UnBlockUserReq, opts ...grpc.CallOption) (*UnBlockUserResp, error) { + out := new(UnBlockUserResp) + err := grpc.Invoke(ctx, "/user.user/UnBlockUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetBlockUsers(ctx context.Context, in *GetBlockUsersReq, opts ...grpc.CallOption) (*GetBlockUsersResp, error) { + out := new(GetBlockUsersResp) + err := grpc.Invoke(ctx, "/user.user/GetBlockUsers", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) GetBlockUserById(ctx context.Context, in *GetBlockUserByIdReq, opts ...grpc.CallOption) (*GetBlockUserByIdResp, error) { + out := new(GetBlockUserByIdResp) + err := grpc.Invoke(ctx, "/user.user/GetBlockUserById", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) DeleteUser(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserResp, error) { + out := new(DeleteUserResp) + err := grpc.Invoke(ctx, "/user.user/DeleteUser", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for User service + +type UserServer interface { + GetUserInfo(context.Context, *GetUserInfoReq) (*GetUserInfoResp, error) + UpdateUserInfo(context.Context, *UpdateUserInfoReq) (*UpdateUserInfoResp, error) + DeleteUsers(context.Context, *DeleteUsersReq) (*DeleteUsersResp, error) + GetAllUserID(context.Context, *GetAllUserIDReq) (*GetAllUserIDResp, error) + AccountCheck(context.Context, *AccountCheckReq) (*AccountCheckResp, error) + GetConversation(context.Context, *GetConversationReq) (*GetConversationResp, error) + GetAllConversations(context.Context, *GetAllConversationsReq) (*GetAllConversationsResp, error) + GetConversations(context.Context, *GetConversationsReq) (*GetConversationsResp, error) + BatchSetConversations(context.Context, *BatchSetConversationsReq) (*BatchSetConversationsResp, error) + SetConversation(context.Context, *SetConversationReq) (*SetConversationResp, error) + SetRecvMsgOpt(context.Context, *SetRecvMsgOptReq) (*SetRecvMsgOptResp, error) + GetUserById(context.Context, *GetUserByIdReq) (*GetUserByIdResp, error) + GetUsersByName(context.Context, *GetUsersByNameReq) (*GetUsersByNameResp, error) + ResignUser(context.Context, *ResignUserReq) (*ResignUserResp, error) + AlterUser(context.Context, *AlterUserReq) (*AlterUserResp, error) + GetUsers(context.Context, *GetUsersReq) (*GetUsersResp, error) + AddUser(context.Context, *AddUserReq) (*AddUserResp, error) + BlockUser(context.Context, *BlockUserReq) (*BlockUserResp, error) + UnBlockUser(context.Context, *UnBlockUserReq) (*UnBlockUserResp, error) + GetBlockUsers(context.Context, *GetBlockUsersReq) (*GetBlockUsersResp, error) + GetBlockUserById(context.Context, *GetBlockUserByIdReq) (*GetBlockUserByIdResp, error) + DeleteUser(context.Context, *DeleteUserReq) (*DeleteUserResp, error) +} + +func RegisterUserServer(s *grpc.Server, srv UserServer) { + s.RegisterService(&_User_serviceDesc, srv) +} + +func _User_GetUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetUserInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetUserInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetUserInfo(ctx, req.(*GetUserInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_UpdateUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserInfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).UpdateUserInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/UpdateUserInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).UpdateUserInfo(ctx, req.(*UpdateUserInfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_DeleteUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUsersReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).DeleteUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/DeleteUsers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).DeleteUsers(ctx, req.(*DeleteUsersReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetAllUserID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllUserIDReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetAllUserID(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetAllUserID", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetAllUserID(ctx, req.(*GetAllUserIDReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_AccountCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountCheckReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).AccountCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/AccountCheck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).AccountCheck(ctx, req.(*AccountCheckReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetConversation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetConversationReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetConversation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetConversation", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetConversation(ctx, req.(*GetConversationReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetAllConversations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllConversationsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetAllConversations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetAllConversations", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetAllConversations(ctx, req.(*GetAllConversationsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetConversations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetConversationsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetConversations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetConversations", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetConversations(ctx, req.(*GetConversationsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_BatchSetConversations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchSetConversationsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).BatchSetConversations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/BatchSetConversations", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).BatchSetConversations(ctx, req.(*BatchSetConversationsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_SetConversation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetConversationReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).SetConversation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/SetConversation", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).SetConversation(ctx, req.(*SetConversationReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_SetRecvMsgOpt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetRecvMsgOptReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).SetRecvMsgOpt(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/SetRecvMsgOpt", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).SetRecvMsgOpt(ctx, req.(*SetRecvMsgOptReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetUserById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserByIdReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetUserById(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetUserById", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetUserById(ctx, req.(*GetUserByIdReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetUsersByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUsersByNameReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetUsersByName(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetUsersByName", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetUsersByName(ctx, req.(*GetUsersByNameReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_ResignUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResignUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).ResignUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/ResignUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).ResignUser(ctx, req.(*ResignUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_AlterUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AlterUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).AlterUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/AlterUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).AlterUser(ctx, req.(*AlterUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUsersReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetUsers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetUsers(ctx, req.(*GetUsersReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_AddUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).AddUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/AddUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).AddUser(ctx, req.(*AddUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_BlockUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BlockUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).BlockUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/BlockUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).BlockUser(ctx, req.(*BlockUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_UnBlockUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnBlockUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).UnBlockUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/UnBlockUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).UnBlockUser(ctx, req.(*UnBlockUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetBlockUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBlockUsersReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetBlockUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetBlockUsers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetBlockUsers(ctx, req.(*GetBlockUsersReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_GetBlockUserById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBlockUserByIdReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).GetBlockUserById(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/GetBlockUserById", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).GetBlockUserById(ctx, req.(*GetBlockUserByIdReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).DeleteUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.user/DeleteUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).DeleteUser(ctx, req.(*DeleteUserReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _User_serviceDesc = grpc.ServiceDesc{ + ServiceName: "user.user", + HandlerType: (*UserServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetUserInfo", + Handler: _User_GetUserInfo_Handler, + }, + { + MethodName: "UpdateUserInfo", + Handler: _User_UpdateUserInfo_Handler, + }, + { + MethodName: "DeleteUsers", + Handler: _User_DeleteUsers_Handler, + }, + { + MethodName: "GetAllUserID", + Handler: _User_GetAllUserID_Handler, + }, + { + MethodName: "AccountCheck", + Handler: _User_AccountCheck_Handler, + }, + { + MethodName: "GetConversation", + Handler: _User_GetConversation_Handler, + }, + { + MethodName: "GetAllConversations", + Handler: _User_GetAllConversations_Handler, + }, + { + MethodName: "GetConversations", + Handler: _User_GetConversations_Handler, + }, + { + MethodName: "BatchSetConversations", + Handler: _User_BatchSetConversations_Handler, + }, + { + MethodName: "SetConversation", + Handler: _User_SetConversation_Handler, + }, + { + MethodName: "SetRecvMsgOpt", + Handler: _User_SetRecvMsgOpt_Handler, + }, + { + MethodName: "GetUserById", + Handler: _User_GetUserById_Handler, + }, + { + MethodName: "GetUsersByName", + Handler: _User_GetUsersByName_Handler, + }, + { + MethodName: "ResignUser", + Handler: _User_ResignUser_Handler, + }, + { + MethodName: "AlterUser", + Handler: _User_AlterUser_Handler, + }, + { + MethodName: "GetUsers", + Handler: _User_GetUsers_Handler, + }, + { + MethodName: "AddUser", + Handler: _User_AddUser_Handler, + }, + { + MethodName: "BlockUser", + Handler: _User_BlockUser_Handler, + }, + { + MethodName: "UnBlockUser", + Handler: _User_UnBlockUser_Handler, + }, + { + MethodName: "GetBlockUsers", + Handler: _User_GetBlockUsers_Handler, + }, + { + MethodName: "GetBlockUserById", + Handler: _User_GetBlockUserById_Handler, + }, + { + MethodName: "DeleteUser", + Handler: _User_DeleteUser_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "user/user.proto", +} + +func init() { proto.RegisterFile("user/user.proto", fileDescriptor_user_6133bd34462fbb1a) } + +var fileDescriptor_user_6133bd34462fbb1a = []byte{ + // 1835 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x5f, 0x6f, 0xdc, 0xc6, + 0x11, 0x07, 0xef, 0x8f, 0x25, 0xcd, 0xe9, 0x4e, 0xa7, 0x95, 0x2c, 0xd1, 0x6c, 0xab, 0xaa, 0x84, + 0xeb, 0x0a, 0x02, 0x2a, 0xb5, 0x6e, 0x51, 0x17, 0x2e, 0x5a, 0x5b, 0x77, 0x92, 0x85, 0x2b, 0x62, + 0xe9, 0xc0, 0xb3, 0x80, 0x20, 0x08, 0x20, 0xd0, 0x77, 0x2b, 0x89, 0xd0, 0x1d, 0x49, 0x73, 0x79, + 0xb2, 0x95, 0x17, 0x07, 0xf9, 0xf3, 0x12, 0xe4, 0x25, 0x40, 0x00, 0x3b, 0x79, 0xc8, 0xe7, 0xc8, + 0x7b, 0xf2, 0x94, 0x6f, 0x90, 0xa7, 0x7c, 0x95, 0x60, 0x97, 0x4b, 0x72, 0x77, 0x49, 0x49, 0x17, + 0x4a, 0xf0, 0x8b, 0xad, 0x9d, 0xdd, 0x1d, 0xfe, 0x66, 0xe6, 0x37, 0xb3, 0xb3, 0x7b, 0x30, 0x37, + 0x26, 0x38, 0xd8, 0xa4, 0xff, 0x6c, 0xf8, 0x81, 0x17, 0x7a, 0xa8, 0x42, 0xff, 0x36, 0xfe, 0xb4, + 0xef, 0x63, 0xf7, 0xb0, 0xf3, 0x74, 0xd3, 0x3f, 0x3d, 0xde, 0x64, 0x13, 0x9b, 0x64, 0x70, 0x7a, + 0xf8, 0x92, 0x6c, 0xbe, 0x24, 0xd1, 0x42, 0xf3, 0x7f, 0x00, 0x6d, 0x6f, 0x34, 0xf2, 0x5c, 0x0b, + 0x13, 0x1f, 0xe9, 0x30, 0x85, 0x83, 0xa0, 0xed, 0x0d, 0xb0, 0xae, 0xad, 0x6a, 0x6b, 0x55, 0x2b, + 0x1e, 0xa2, 0x25, 0xb8, 0x85, 0x83, 0xe0, 0x29, 0x39, 0xd6, 0x4b, 0xab, 0xda, 0xda, 0x8c, 0xc5, + 0x47, 0xe6, 0x47, 0xd0, 0xd8, 0xc6, 0x43, 0x1c, 0xe2, 0x03, 0x82, 0x03, 0x62, 0xe1, 0x17, 0x68, + 0x1d, 0x9a, 0xa9, 0xa4, 0xb3, 0xfd, 0x9e, 0x43, 0x42, 0xbd, 0xb4, 0x5a, 0x5e, 0x9b, 0xb1, 0x32, + 0x72, 0x64, 0xc0, 0xf4, 0xbe, 0x1f, 0x8d, 0xf5, 0x32, 0xd3, 0x9b, 0x8c, 0xd1, 0x2a, 0xd4, 0xf6, + 0x7d, 0x1c, 0xd8, 0xa1, 0xe3, 0xb9, 0x9d, 0x6d, 0xbd, 0xc2, 0xa6, 0x45, 0x91, 0xe9, 0xc1, 0x9c, + 0xf4, 0x6d, 0xe2, 0xa3, 0xbf, 0x89, 0xe6, 0x30, 0x1b, 0x6a, 0xf7, 0x9b, 0x1b, 0xcc, 0x31, 0xa9, + 0xdc, 0x12, 0x4d, 0x5e, 0x87, 0xe6, 0x13, 0xdb, 0x19, 0xe2, 0x41, 0x16, 0xae, 0x2a, 0x37, 0xf7, + 0x61, 0x6e, 0x17, 0x87, 0x5b, 0xc3, 0x61, 0x24, 0xa3, 0xd6, 0x1a, 0x30, 0xed, 0xc5, 0x16, 0x68, + 0x91, 0x05, 0x9e, 0x60, 0x81, 0x27, 0x58, 0x10, 0x39, 0x4e, 0x14, 0x99, 0x03, 0x68, 0xca, 0x0a, + 0x0b, 0x99, 0xb0, 0x02, 0x90, 0x01, 0x2f, 0x48, 0xcc, 0x73, 0x98, 0xdb, 0xea, 0xf7, 0xbd, 0xb1, + 0x1b, 0xb6, 0x4f, 0x70, 0xff, 0x94, 0xc2, 0x5e, 0x83, 0x39, 0xf6, 0xb7, 0xb0, 0x4f, 0x63, 0xfb, + 0x54, 0xb1, 0x14, 0xa2, 0xd2, 0xe5, 0x21, 0x2a, 0x67, 0x43, 0xf4, 0x8b, 0x06, 0x4d, 0xf9, 0xdb, + 0x91, 0x85, 0xfd, 0x09, 0x2c, 0x4c, 0xd7, 0xa0, 0x5d, 0x00, 0x0b, 0x93, 0xf1, 0x30, 0x4c, 0x2c, + 0xac, 0xdd, 0xff, 0x4b, 0xb4, 0x43, 0xd5, 0xbe, 0xd1, 0x73, 0xdc, 0xe3, 0x21, 0xa3, 0x44, 0x2f, + 0xb4, 0xc3, 0x31, 0xb1, 0x84, 0xad, 0x46, 0x17, 0x9a, 0xea, 0x3c, 0xa5, 0xf6, 0x58, 0x0c, 0x20, + 0x1f, 0xa1, 0xbb, 0x50, 0xb7, 0x23, 0xe5, 0xd1, 0x42, 0x6e, 0xbe, 0x2c, 0x34, 0x5d, 0x68, 0xec, + 0xe2, 0x90, 0x39, 0xc4, 0x3d, 0xf2, 0xa8, 0x6f, 0x57, 0x00, 0xc6, 0xaa, 0x5b, 0x05, 0xc9, 0x35, + 0x3d, 0xfa, 0x99, 0xc6, 0x48, 0x98, 0x7e, 0xb0, 0x90, 0x43, 0x1f, 0xc1, 0x6c, 0xac, 0x81, 0xa1, + 0x2c, 0x33, 0x97, 0xfe, 0x6e, 0x83, 0xe0, 0xe0, 0x0c, 0x07, 0x87, 0xb6, 0xef, 0x1c, 0xfa, 0x76, + 0x60, 0x8f, 0xc8, 0x46, 0xf2, 0x21, 0x69, 0x83, 0xf9, 0x85, 0x06, 0xf3, 0x07, 0xfe, 0xc0, 0xe6, + 0xe9, 0xcc, 0x4d, 0x7f, 0x00, 0xd3, 0xf1, 0x90, 0xc3, 0xb8, 0x54, 0x65, 0xb2, 0xf8, 0x2a, 0x9f, + 0x78, 0x59, 0x9f, 0x88, 0x69, 0xf4, 0x04, 0x90, 0x8a, 0xa5, 0x88, 0x57, 0xcc, 0xaf, 0xcb, 0x30, + 0xdb, 0xf6, 0xdc, 0x33, 0x1c, 0x10, 0xa6, 0x9a, 0x85, 0xe3, 0xa5, 0x8b, 0x03, 0x29, 0xc1, 0x45, + 0x11, 0xba, 0x07, 0x0d, 0x71, 0x47, 0x02, 0x5f, 0x91, 0x52, 0x52, 0x58, 0xb8, 0x7f, 0xf6, 0x94, + 0x1c, 0xef, 0xfb, 0x21, 0xb3, 0xa1, 0x6a, 0x09, 0x12, 0x5a, 0x86, 0xc4, 0x1d, 0xcf, 0xce, 0x7d, + 0xcc, 0x4a, 0x5e, 0xd5, 0xca, 0xc8, 0x29, 0x61, 0x39, 0xa0, 0x6a, 0x44, 0x58, 0x8e, 0x45, 0x87, + 0xa9, 0xdd, 0xc0, 0x1b, 0xfb, 0x9d, 0x6d, 0xfd, 0x16, 0x9b, 0x88, 0x87, 0xd4, 0x8e, 0x03, 0x37, + 0xc0, 0xf6, 0xa0, 0x4d, 0x99, 0xab, 0x4f, 0x31, 0xc5, 0xa2, 0x88, 0x92, 0x7d, 0x3b, 0xb0, 0x8f, + 0xc2, 0x67, 0xf8, 0x55, 0xf8, 0xcc, 0x19, 0x61, 0x7d, 0x7a, 0x55, 0x5b, 0x2b, 0x5b, 0xb2, 0x90, + 0x86, 0xa9, 0x43, 0xba, 0x8e, 0xeb, 0xe2, 0x81, 0x3e, 0xb3, 0xaa, 0xad, 0x4d, 0x5b, 0xc9, 0x18, + 0x99, 0x30, 0xbb, 0x15, 0x86, 0x76, 0xff, 0x04, 0x0f, 0x58, 0xfc, 0x81, 0x41, 0x90, 0x64, 0xf4, + 0x2b, 0x1d, 0xd2, 0x0d, 0x9c, 0x33, 0x3b, 0xc4, 0xed, 0x13, 0x3b, 0xd4, 0x6b, 0x4c, 0x89, 0x2c, + 0x44, 0x0d, 0x28, 0xed, 0xbc, 0xd2, 0x67, 0xd9, 0xfe, 0xd2, 0xce, 0x2b, 0xf3, 0x5b, 0x0d, 0x50, + 0x0f, 0x87, 0xa2, 0x1f, 0x28, 0xd9, 0xfe, 0x25, 0x07, 0x8b, 0x47, 0x18, 0xc5, 0x11, 0x16, 0x16, + 0xcb, 0x41, 0x5d, 0x87, 0xa6, 0xeb, 0x85, 0xce, 0x91, 0xd3, 0x4f, 0x5d, 0x5d, 0x8a, 0x5c, 0xad, + 0xca, 0x27, 0xc8, 0xc7, 0x5d, 0x58, 0xc8, 0x60, 0x2b, 0x44, 0xbe, 0x9f, 0x34, 0x68, 0xf6, 0x70, + 0x98, 0x72, 0x82, 0xda, 0xf8, 0x4e, 0x09, 0x98, 0xf1, 0x4a, 0x65, 0x32, 0xaf, 0x54, 0xb3, 0x5e, + 0xd9, 0x81, 0x79, 0xc5, 0x96, 0x42, 0x3e, 0xf9, 0x58, 0x03, 0xb4, 0x9b, 0x8d, 0x7c, 0xd6, 0x66, + 0x2d, 0xd7, 0x66, 0xc5, 0x7b, 0xa5, 0xac, 0xf7, 0xae, 0x8e, 0xef, 0x6b, 0x58, 0xd8, 0xbd, 0x89, + 0xf8, 0x66, 0xe8, 0x5a, 0x9a, 0x8c, 0xae, 0xe6, 0xa7, 0x5a, 0x06, 0x01, 0x99, 0x8c, 0x1a, 0xf4, + 0x90, 0x97, 0x1c, 0x42, 0x78, 0x73, 0xa0, 0x8a, 0x27, 0x70, 0xc3, 0x27, 0x1a, 0x2c, 0x66, 0x51, + 0x14, 0x72, 0xc4, 0xbf, 0xa1, 0x2e, 0xa9, 0xe1, 0xe7, 0x79, 0x9e, 0x27, 0xe4, 0x85, 0xe6, 0x87, + 0xb0, 0x14, 0xb5, 0x4b, 0x05, 0x9c, 0xa1, 0x98, 0x58, 0xca, 0x9a, 0xf8, 0xb9, 0x06, 0xcb, 0xb9, + 0xea, 0xdf, 0xb1, 0x95, 0x3f, 0x6a, 0xa0, 0xb7, 0xec, 0xb0, 0x7f, 0xd2, 0xcb, 0x89, 0x7a, 0x46, + 0xad, 0x36, 0xa1, 0xda, 0x09, 0x92, 0x21, 0xaf, 0x04, 0x94, 0x27, 0x2b, 0x01, 0x95, 0xbc, 0xc4, + 0xb9, 0x73, 0x81, 0x15, 0x85, 0xfc, 0xa9, 0xc3, 0x54, 0x6f, 0xdc, 0xef, 0x63, 0x12, 0x93, 0x38, + 0x1e, 0xd2, 0xe3, 0x30, 0xea, 0xd4, 0x59, 0x17, 0x33, 0x63, 0xf1, 0x91, 0xd9, 0x81, 0xba, 0x85, + 0x89, 0x73, 0xec, 0x52, 0xf3, 0xa8, 0xef, 0xe2, 0x73, 0x73, 0x10, 0x37, 0x7a, 0xd1, 0x68, 0x02, + 0x6a, 0xb4, 0xa0, 0x21, 0xaa, 0x2a, 0x54, 0xcb, 0xfe, 0x9f, 0x34, 0x8a, 0xad, 0xf3, 0xce, 0xe0, + 0x7a, 0x78, 0xde, 0x6a, 0x50, 0xa1, 0x8b, 0xe9, 0xa1, 0xdb, 0x0d, 0xbc, 0x23, 0x67, 0x88, 0xbb, + 0x27, 0x5e, 0xe8, 0x71, 0x45, 0x92, 0x8c, 0x1e, 0xda, 0x7b, 0x4e, 0xff, 0xd4, 0xb5, 0x47, 0x38, + 0xee, 0xad, 0xe2, 0xb1, 0x00, 0xa1, 0x2c, 0x41, 0x58, 0x01, 0x68, 0x07, 0xd8, 0x0e, 0x31, 0xeb, + 0x05, 0xa2, 0xe8, 0x0a, 0x12, 0x1a, 0x8d, 0x0e, 0x69, 0x0d, 0xbd, 0xfe, 0x29, 0xab, 0xfe, 0xd3, + 0x56, 0x3c, 0x34, 0xfb, 0x49, 0x7b, 0x1a, 0x99, 0x59, 0xf0, 0x46, 0xc3, 0x2e, 0xb0, 0xbc, 0x46, + 0x42, 0xb4, 0x96, 0xf9, 0x9e, 0xc9, 0xcd, 0x37, 0x1a, 0xcc, 0xf3, 0xaf, 0x90, 0xd6, 0xf9, 0x9e, + 0x3d, 0xc2, 0xfc, 0x2e, 0x46, 0x25, 0x74, 0x18, 0xdf, 0xc5, 0xe2, 0x31, 0xda, 0x06, 0xe8, 0xda, + 0xc7, 0x8e, 0x2b, 0xd6, 0xde, 0xbb, 0x39, 0xbd, 0xa9, 0x85, 0x5f, 0x8c, 0x31, 0x09, 0xd3, 0xb5, + 0x96, 0xb0, 0x6f, 0x82, 0x3a, 0xf9, 0x4d, 0x74, 0x62, 0x49, 0xc8, 0x88, 0x8f, 0x56, 0xa1, 0x4a, + 0x81, 0xc7, 0xe9, 0x2a, 0x5a, 0x14, 0x4d, 0xa0, 0x9d, 0x1c, 0x80, 0x7f, 0xce, 0x05, 0x48, 0x7c, + 0xcf, 0x25, 0xf8, 0x02, 0x84, 0xb1, 0x0f, 0xc6, 0x23, 0xc2, 0x73, 0x37, 0x19, 0x9b, 0xdf, 0x6b, + 0x30, 0xbb, 0x35, 0x0c, 0xa3, 0x7c, 0xbf, 0x16, 0x01, 0xe9, 0x8a, 0xee, 0x89, 0xe7, 0xe2, 0xbd, + 0xf1, 0xe8, 0x39, 0x0e, 0xd8, 0x97, 0xca, 0x96, 0x28, 0x92, 0x58, 0x57, 0x51, 0x58, 0xb7, 0x08, + 0xd5, 0x9d, 0x91, 0xed, 0x0c, 0x79, 0xe7, 0x10, 0x0d, 0x84, 0x3b, 0xc0, 0x80, 0xf7, 0xaf, 0xc9, + 0xd8, 0xdc, 0x82, 0xba, 0x80, 0xbc, 0x08, 0xa7, 0xcc, 0xaf, 0x34, 0xa8, 0xc5, 0x91, 0x89, 0x8f, + 0x0c, 0xc1, 0x48, 0x2d, 0x6b, 0xe4, 0xcd, 0x70, 0x46, 0x64, 0x65, 0x59, 0x66, 0xa5, 0xf9, 0x83, + 0x06, 0xb3, 0x29, 0xa6, 0x6b, 0xa6, 0x4a, 0x39, 0x2f, 0x55, 0x14, 0x5e, 0x95, 0x6f, 0x82, 0x57, + 0x15, 0x85, 0x57, 0x6f, 0x35, 0x80, 0xad, 0xc1, 0x20, 0x66, 0xd5, 0xd5, 0x8e, 0x55, 0xd8, 0xc3, + 0xf9, 0x25, 0xb2, 0xe7, 0xa2, 0xba, 0x84, 0xa0, 0x22, 0x30, 0x8a, 0xfd, 0x2d, 0xf1, 0xa6, 0xaa, + 0xf0, 0xe6, 0x11, 0xd4, 0x12, 0x64, 0x85, 0x58, 0xf3, 0xa5, 0x06, 0xb3, 0xac, 0xb0, 0x5d, 0x95, + 0x33, 0xf7, 0xa0, 0xb1, 0xe3, 0x0e, 0xb6, 0x1d, 0x62, 0x3f, 0x1f, 0x46, 0x55, 0x93, 0xf7, 0xe1, + 0xb2, 0xf4, 0xea, 0x12, 0x22, 0xd9, 0x53, 0xc9, 0xe6, 0x81, 0x80, 0xa6, 0x90, 0x45, 0x47, 0xd0, + 0x38, 0x70, 0x27, 0x32, 0xe9, 0xea, 0x32, 0x20, 0x42, 0x2d, 0x2b, 0x50, 0xdb, 0x30, 0x27, 0x7d, + 0xa7, 0x10, 0xd8, 0xef, 0x34, 0xf6, 0x42, 0x96, 0xa8, 0x61, 0x99, 0x2b, 0xe7, 0xa5, 0x76, 0x33, + 0xb5, 0x3c, 0xc7, 0x3a, 0x53, 0x08, 0xfd, 0xde, 0x78, 0xc4, 0xeb, 0xa9, 0x24, 0x33, 0x5f, 0xc3, + 0x4c, 0x32, 0xa6, 0xb9, 0x48, 0xff, 0xe7, 0x90, 0xa4, 0x5c, 0x64, 0xf3, 0xeb, 0xd0, 0x6c, 0xe1, + 0x63, 0xc7, 0xcd, 0xb2, 0x24, 0x23, 0xcf, 0xe1, 0x53, 0x39, 0x8f, 0x4f, 0xe6, 0xcf, 0xd1, 0x51, + 0x28, 0x7a, 0xa8, 0x50, 0x1d, 0xd9, 0x04, 0x48, 0x75, 0xf0, 0x6a, 0x32, 0x17, 0xed, 0x48, 0x83, + 0x28, 0x2c, 0x79, 0x17, 0x85, 0xa5, 0xcb, 0x6e, 0x3e, 0xc9, 0x37, 0xe3, 0xbe, 0x69, 0x19, 0xa6, + 0xe8, 0xf0, 0xd0, 0xf9, 0xed, 0x8d, 0xd3, 0x0e, 0xbb, 0xc5, 0x28, 0x1a, 0x89, 0x8f, 0xfe, 0x2a, + 0x84, 0x91, 0x57, 0xfa, 0x8c, 0xf1, 0xe9, 0x0a, 0xf3, 0x08, 0xea, 0xe9, 0xcb, 0xf3, 0xf5, 0x20, + 0x5d, 0x9a, 0x43, 0x2d, 0xf1, 0x75, 0xbd, 0x58, 0x60, 0xef, 0xbf, 0xa9, 0x45, 0x27, 0x04, 0x7a, + 0x98, 0x9c, 0x7f, 0xec, 0x2d, 0x66, 0x31, 0xda, 0x25, 0x3f, 0x5e, 0x1a, 0xb7, 0x73, 0xa4, 0xc4, + 0x47, 0x6d, 0x68, 0xc8, 0x2f, 0x6c, 0x68, 0x99, 0xb3, 0x5b, 0x7d, 0x03, 0x34, 0xf4, 0xfc, 0x09, + 0xe2, 0x53, 0x00, 0xc2, 0x7b, 0x7d, 0x0c, 0x40, 0xfe, 0xf9, 0x20, 0x06, 0xa0, 0x3e, 0xec, 0xff, + 0x97, 0x1d, 0x94, 0xc9, 0x4b, 0x39, 0x4a, 0x71, 0x8a, 0xcf, 0xf1, 0xc6, 0x52, 0x9e, 0x38, 0xda, + 0x2e, 0x3e, 0x14, 0xc7, 0xdb, 0x95, 0x67, 0xf1, 0x78, 0x7b, 0xe6, 0xc5, 0xfa, 0x09, 0x6b, 0x6a, + 0xa5, 0x57, 0x24, 0x3d, 0xf9, 0x92, 0xf2, 0x3a, 0x61, 0xdc, 0xb9, 0x60, 0x86, 0xf8, 0xc8, 0x62, + 0x84, 0x56, 0x6f, 0x98, 0xe8, 0xf7, 0x22, 0x6a, 0xf5, 0xca, 0x67, 0xfc, 0xe1, 0x92, 0x59, 0xe2, + 0xa3, 0x0e, 0xab, 0x90, 0xb2, 0xc2, 0x7c, 0x08, 0x4c, 0x9b, 0x71, 0xd1, 0x14, 0xf1, 0xd1, 0xfb, + 0x70, 0x3b, 0xf7, 0xca, 0x86, 0x56, 0x78, 0x2e, 0x5c, 0x70, 0x2b, 0x35, 0xfe, 0x78, 0xe9, 0x7c, + 0xe4, 0xc0, 0x5e, 0xbe, 0x03, 0x7b, 0x17, 0x3a, 0x30, 0xef, 0x59, 0xed, 0x31, 0xd4, 0xa5, 0x77, + 0x25, 0xb4, 0x94, 0xac, 0x95, 0x1e, 0xce, 0x8c, 0xe5, 0x5c, 0x79, 0x44, 0x42, 0xe1, 0x7e, 0xa2, + 0x64, 0x01, 0xaf, 0x30, 0x4a, 0x16, 0x24, 0x55, 0xa2, 0x9d, 0x5c, 0xe1, 0x78, 0x6f, 0x1f, 0x67, + 0x41, 0xe6, 0x2e, 0x62, 0xe8, 0xf9, 0x13, 0xc4, 0x47, 0x0f, 0xd8, 0x6f, 0x19, 0xfc, 0x2e, 0x89, + 0x16, 0xa2, 0x75, 0xd2, 0x45, 0xd5, 0x58, 0xcc, 0x0a, 0x89, 0x8f, 0xfe, 0x09, 0x33, 0x49, 0x0f, + 0x8c, 0xf8, 0x85, 0x5f, 0x6c, 0xe7, 0x8d, 0x85, 0x8c, 0x8c, 0xf8, 0xe8, 0xef, 0x30, 0x1d, 0x83, + 0x40, 0xf3, 0x32, 0x28, 0xba, 0x07, 0xa9, 0x22, 0xe2, 0xa3, 0x0d, 0x98, 0xe2, 0x4d, 0x13, 0xe2, + 0xa5, 0x25, 0xed, 0xee, 0x8c, 0x79, 0x45, 0x12, 0x01, 0x4b, 0xcf, 0x40, 0xa4, 0x96, 0xcd, 0x14, + 0x98, 0xdc, 0x0c, 0x3c, 0x84, 0x9a, 0xd0, 0x1f, 0xc4, 0x81, 0x90, 0x5b, 0x93, 0x38, 0x10, 0x6a, + 0x23, 0xf1, 0x18, 0xea, 0xd2, 0x99, 0x87, 0xd2, 0xbc, 0x97, 0x5a, 0x05, 0x63, 0x39, 0x57, 0x9e, + 0x64, 0x8d, 0x74, 0x10, 0x08, 0x59, 0xa3, 0x1e, 0x39, 0x42, 0xd6, 0x64, 0xcf, 0x8e, 0x07, 0x00, + 0x69, 0xb5, 0x8a, 0x03, 0x2a, 0x1d, 0x0f, 0xc6, 0x62, 0x56, 0x48, 0xfc, 0x56, 0xfd, 0x83, 0xda, + 0x06, 0xfb, 0xd1, 0xf6, 0x3f, 0xf4, 0x9f, 0xe7, 0xb7, 0xd8, 0x2f, 0xb2, 0xff, 0xf8, 0x35, 0x00, + 0x00, 0xff, 0xff, 0x10, 0x04, 0x45, 0x5d, 0xcd, 0x1d, 0x00, 0x00, +} diff --git a/pkg/proto/user/user.proto b/pkg/proto/user/user.proto new file mode 100644 index 000000000..c6dad658c --- /dev/null +++ b/pkg/proto/user/user.proto @@ -0,0 +1,316 @@ +syntax = "proto3"; +import "Open_IM/pkg/proto/sdk_ws/ws.proto"; +option go_package = "./user;user"; +package user; + +message CommonResp{ + int32 errCode = 1; + string errMsg = 2; +} + +message DeleteUsersReq{ + repeated string DeleteUserIDList = 2; + string OpUserID = 3; + string OperationID = 4; +} + +message DeleteUsersResp{ + CommonResp CommonResp = 1; + repeated string FailedUserIDList = 2; +} + + +message GetAllUserIDReq{ + string opUserID = 1; + string operationID = 2; +} +message GetAllUserIDResp{ + CommonResp CommonResp = 1; + repeated string UserIDList = 2; +} + + +message AccountCheckReq{ + repeated string CheckUserIDList = 1; + string OpUserID = 2; + string OperationID = 3; + +} +message AccountCheckResp{ + CommonResp commonResp = 1; + message SingleUserStatus { + string userID = 1; + string accountStatus = 2; + } + repeated SingleUserStatus ResultList = 2; +} + + +message GetUserInfoReq{ + repeated string userIDList = 1; + string OpUserID = 2; + string OperationID = 3; +} +message GetUserInfoResp{ + CommonResp commonResp = 1; + repeated server_api_params.UserInfo UserInfoList = 3; +} + + + +message UpdateUserInfoReq{ + server_api_params.UserInfo UserInfo = 1; + string OpUserID = 2; + string operationID = 3; +} +message UpdateUserInfoResp{ + CommonResp commonResp = 1; +} + +message Conversation{ + string OwnerUserID = 1; + string ConversationID = 2; + int32 RecvMsgOpt = 3; + int32 ConversationType = 4; + string UserID = 5; + string GroupID = 6; + int32 UnreadCount = 7; + int64 DraftTextTime = 8; + bool IsPinned = 9; + string AttachedInfo = 10; + bool IsPrivateChat = 11; + string Ex = 12; +} + +message SetConversationReq{ + Conversation Conversation = 1; + int32 notificationType = 2; + string OperationID = 3; +} + +message SetConversationResp{ + CommonResp commonResp = 1; +} + +message SetRecvMsgOptReq { + string OwnerUserID = 1; + string ConversationID = 2; + int32 RecvMsgOpt = 3; + int32 notificationType = 4; + string OperationID = 5; +} + +message SetRecvMsgOptResp { + CommonResp commonResp = 1; +} + +message GetConversationReq{ + string ConversationID = 1; + string OwnerUserID = 2; + string OperationID = 3; +} + +message GetConversationResp{ + CommonResp commonResp = 1; + Conversation Conversation = 2; +} + +message GetConversationsReq{ + string OwnerUserID = 1; + repeated string ConversationIDs = 2; + string OperationID = 3; +} + +message GetConversationsResp{ + CommonResp commonResp = 1; + repeated Conversation Conversations = 2; +} + +message GetAllConversationsReq{ + string OwnerUserID = 1; + string OperationID = 2; +} + +message GetAllConversationsResp{ + CommonResp commonResp = 1; + repeated Conversation Conversations = 2; +} + +message BatchSetConversationsReq{ + repeated Conversation Conversations = 1; + string OwnerUserID = 2; + int32 notificationType = 3; + string OperationID = 4; +} + +message BatchSetConversationsResp{ + CommonResp commonResp = 1; + repeated string Success = 2; + repeated string Failed = 3; +} + +message ResignUserReq{ + string UserId = 1; + string OperationID = 2; +} + +message ResignUserResp{ + CommonResp commonResp = 1; +} + +message GetUserByIdReq{ + string UserId = 1; + string OperationID = 2; +} + +message User{ + string ProfilePhoto = 1; + string Nickname = 2; + string UserId = 3; + string CreateTime = 4; + bool IsBlock = 5; +} + +message GetUserByIdResp{ + CommonResp CommonResp = 1; + User user = 2; +} + +message GetUsersByNameReq { + string UserName = 1; + server_api_params.RequestPagination Pagination =2; + string OperationID = 3; +} + +message GetUsersByNameResp { + repeated User users = 1; + server_api_params.ResponsePagination Pagination = 2; + int32 UserNums = 3; +} + +message AlterUserReq{ + string UserId = 1; + string OperationID = 2; + int64 PhoneNumber = 3; + string Nickname = 4; + string Email = 5; + string OpUserId = 6; +} + +message AlterUserResp{ + CommonResp CommonResp = 1; +} + +message GetUsersReq { + string OperationID = 1; + server_api_params.RequestPagination Pagination = 2; + string UserName = 3; +} + +message GetUsersResp{ + CommonResp CommonResp = 1; + repeated User user = 2; + server_api_params.ResponsePagination Pagination = 3; + int32 UserNums = 4; +} + +message AddUserReq{ + string OperationID = 1; + string PhoneNumber = 2; + string UserId = 3; + string name = 4; + string OpUserId = 5; +} + +message AddUserResp{ + CommonResp CommonResp = 1; +} + + +message BlockUserReq{ + string UserId = 1; + string EndDisableTime = 2; + string OperationID = 3; + string OpUserId = 4; +} + +message BlockUserResp{ + CommonResp CommonResp = 1; +} + +message UnBlockUserReq{ + string UserId = 1; + string OperationID = 2; + string OpUserId = 3; +} + +message UnBlockUserResp{ + CommonResp CommonResp = 1; +} + +message GetBlockUsersReq{ + server_api_params.RequestPagination Pagination =1; + string OperationID = 2; + int32 BlockUserNum = 3; +} + +message BlockUser { + User User = 1; + string BeginDisableTime = 2; + string EndDisableTime = 3; +} + +message GetBlockUsersResp{ + CommonResp CommonResp = 1; + repeated BlockUser BlockUsers = 2; + server_api_params.ResponsePagination Pagination = 3; + int32 UserNums = 4; +} + +message GetBlockUserByIdReq { + string User_id = 1; + string OperationID = 2; +} + +message GetBlockUserByIdResp { + BlockUser BlockUser = 2; +} + +message DeleteUserReq { + string User_id = 1; + string OperationID = 2; + string OpUserId = 3; +} + +message DeleteUserResp { + CommonResp CommonResp = 1; +} + + + +service user { + rpc GetUserInfo(GetUserInfoReq) returns(GetUserInfoResp); + rpc UpdateUserInfo(UpdateUserInfoReq) returns(UpdateUserInfoResp); + rpc DeleteUsers(DeleteUsersReq)returns(DeleteUsersResp); + rpc GetAllUserID(GetAllUserIDReq)returns(GetAllUserIDResp); + + rpc AccountCheck(AccountCheckReq)returns(AccountCheckResp); + rpc GetConversation(GetConversationReq)returns(GetConversationResp); + rpc GetAllConversations(GetAllConversationsReq)returns(GetAllConversationsResp); + rpc GetConversations(GetConversationsReq)returns(GetConversationsResp); + rpc BatchSetConversations(BatchSetConversationsReq)returns(BatchSetConversationsResp); + rpc SetConversation(SetConversationReq)returns(SetConversationResp); + rpc SetRecvMsgOpt(SetRecvMsgOptReq)returns(SetRecvMsgOptResp); + + rpc GetUserById(GetUserByIdReq) returns (GetUserByIdResp); + rpc GetUsersByName(GetUsersByNameReq) returns (GetUsersByNameResp); + rpc ResignUser(ResignUserReq) returns (ResignUserResp); + rpc AlterUser(AlterUserReq) returns (AlterUserResp); + rpc GetUsers(GetUsersReq) returns (GetUsersResp); + rpc AddUser(AddUserReq) returns (AddUserResp); + rpc BlockUser(BlockUserReq) returns (BlockUserResp); + rpc UnBlockUser(UnBlockUserReq) returns (UnBlockUserResp); + rpc GetBlockUsers(GetBlockUsersReq) returns (GetBlockUsersResp); + rpc GetBlockUserById(GetBlockUserByIdReq) returns (GetBlockUserByIdResp); + rpc DeleteUser(DeleteUserReq) returns (DeleteUserResp); +} diff --git a/pkg/statistics/statistics.go b/pkg/statistics/statistics.go new file mode 100644 index 000000000..bea4479bd --- /dev/null +++ b/pkg/statistics/statistics.go @@ -0,0 +1,32 @@ +package statistics + +import ( + "Open_IM/pkg/common/log" + "time" +) + +type Statistics struct { + Count *uint64 + ModuleName string + PrintArgs string + SleepTime int +} + +func (s *Statistics) output() { + t := time.NewTicker(time.Duration(s.SleepTime) * time.Second) + defer t.Stop() + var sum uint64 + for { + sum = *s.Count + select { + case <-t.C: + } + log.NewWarn("", " system stat ", s.ModuleName, s.PrintArgs, *s.Count-sum, "total:", *s.Count) + } +} + +func NewStatistics(count *uint64, moduleName, printArgs string, sleepTime int) *Statistics { + p := &Statistics{Count: count, ModuleName: moduleName, SleepTime: sleepTime, PrintArgs: printArgs} + go p.output() + return p +} diff --git a/pkg/utils/cors_middleware.go b/pkg/utils/cors_middleware.go new file mode 100644 index 000000000..6809d786d --- /dev/null +++ b/pkg/utils/cors_middleware.go @@ -0,0 +1,24 @@ +package utils + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func CorsHandler() gin.HandlerFunc { + return func(context *gin.Context) { + context.Writer.Header().Set("Access-Control-Allow-Origin", "*") + context.Header("Access-Control-Allow-Methods", "*") + context.Header("Access-Control-Allow-Headers", "*") + context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析 + context.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒 + context.Header("Access-Control-Allow-Credentials", "false") // 跨域请求是否需要带cookie信息 默认设置为true + context.Header("content-type", "application/json") // 设置返回格式是json + //Release all option pre-requests + if context.Request.Method == http.MethodOptions { + context.JSON(http.StatusOK, "Options Request!") + } + context.Next() + } +} diff --git a/pkg/utils/file.go b/pkg/utils/file.go new file mode 100644 index 000000000..e46050516 --- /dev/null +++ b/pkg/utils/file.go @@ -0,0 +1,39 @@ +package utils + +import ( + "Open_IM/pkg/common/constant" + "fmt" + "math/rand" + "os" + "path" + "time" +) + +// Determine whether the given path is a folder +func IsDir(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return s.IsDir() +} + +// Determine whether the given path is a file +func IsFile(path string) bool { + return !IsDir(path) +} + +// Create a directory +func MkDir(path string) error { + return os.MkdirAll(path, os.ModePerm) +} + +func GetNewFileNameAndContentType(fileName string, fileType int) (string, string) { + suffix := path.Ext(fileName) + newName := fmt.Sprintf("%d-%d%s", time.Now().UnixNano(), rand.Int(), fileName) + contentType := "" + if fileType == constant.ImageType { + contentType = "image/" + suffix[1:] + } + return newName, contentType +} diff --git a/pkg/utils/get_server_ip.go b/pkg/utils/get_server_ip.go new file mode 100644 index 000000000..239c75a19 --- /dev/null +++ b/pkg/utils/get_server_ip.go @@ -0,0 +1,26 @@ +package utils + +import ( + "Open_IM/pkg/common/config" + "net" +) + +var ServerIP = "" + +func init() { + //fixme In the configuration file, ip takes precedence, if not, get the valid network card ip of the machine + if config.Config.ServerIP != "" { + ServerIP = config.Config.ServerIP + return + } + + // see https://gist.github.com/jniltinho/9787946#gistcomment-3019898 + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + panic(err.Error()) + } + + defer conn.Close() + localAddr := conn.LocalAddr().(*net.UDPAddr) + ServerIP = localAddr.IP.String() +} diff --git a/pkg/utils/image.go b/pkg/utils/image.go new file mode 100644 index 000000000..393136e63 --- /dev/null +++ b/pkg/utils/image.go @@ -0,0 +1,56 @@ +package utils + +import ( + "errors" + "github.com/nfnt/resize" + "golang.org/x/image/bmp" + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + "os" +) + +func GenSmallImage(src, dst string) error { + fIn, _ := os.Open(src) + defer fIn.Close() + + fOut, _ := os.Create(dst) + defer fOut.Close() + + if err := scale(fIn, fOut, 0, 0, 0); err != nil { + return err + } + return nil +} + +func scale(in io.Reader, out io.Writer, width, height, quality int) error { + origin, fm, err := image.Decode(in) + if err != nil { + return err + } + if width == 0 || height == 0 { + width = origin.Bounds().Max.X / 2 + height = origin.Bounds().Max.Y / 2 + } + if quality == 0 { + quality = 25 + } + canvas := resize.Thumbnail(uint(width), uint(height), origin, resize.Lanczos3) + + switch fm { + case "jpeg": + return jpeg.Encode(out, canvas, &jpeg.Options{quality}) + case "png": + return png.Encode(out, canvas) + case "gif": + return gif.Encode(out, canvas, &gif.Options{}) + case "bmp": + return bmp.Encode(out, canvas) + default: + return errors.New("ERROR FORMAT") + } + + return nil +} diff --git a/pkg/utils/map.go b/pkg/utils/map.go new file mode 100644 index 000000000..fc24cc87d --- /dev/null +++ b/pkg/utils/map.go @@ -0,0 +1,129 @@ +package utils + +import ( + "encoding/json" + "sync" +) + +type Map struct { + sync.RWMutex + m map[interface{}]interface{} +} + +func (m *Map) init() { + if m.m == nil { + m.m = make(map[interface{}]interface{}) + } +} + +func (m *Map) UnsafeGet(key interface{}) interface{} { + if m.m == nil { + return nil + } else { + return m.m[key] + } +} + +func (m *Map) Get(key interface{}) interface{} { + m.RLock() + defer m.RUnlock() + return m.UnsafeGet(key) +} + +func (m *Map) UnsafeSet(key interface{}, value interface{}) { + m.init() + m.m[key] = value +} + +func (m *Map) Set(key interface{}, value interface{}) { + m.Lock() + defer m.Unlock() + m.UnsafeSet(key, value) +} + +func (m *Map) TestAndSet(key interface{}, value interface{}) interface{} { + m.Lock() + defer m.Unlock() + + m.init() + + if v, ok := m.m[key]; ok { + return v + } else { + m.m[key] = value + return nil + } +} + +func (m *Map) UnsafeDel(key interface{}) { + m.init() + delete(m.m, key) +} + +func (m *Map) Del(key interface{}) { + m.Lock() + defer m.Unlock() + m.UnsafeDel(key) +} + +func (m *Map) UnsafeLen() int { + if m.m == nil { + return 0 + } else { + return len(m.m) + } +} + +func (m *Map) Len() int { + m.RLock() + defer m.RUnlock() + return m.UnsafeLen() +} + +func (m *Map) UnsafeRange(f func(interface{}, interface{})) { + if m.m == nil { + return + } + for k, v := range m.m { + f(k, v) + } +} + +func (m *Map) RLockRange(f func(interface{}, interface{})) { + m.RLock() + defer m.RUnlock() + m.UnsafeRange(f) +} + +func (m *Map) LockRange(f func(interface{}, interface{})) { + m.Lock() + defer m.Unlock() + m.UnsafeRange(f) +} + +func MapToJsonString(param map[string]interface{}) string { + dataType, _ := json.Marshal(param) + dataString := string(dataType) + return dataString +} +func MapIntToJsonString(param map[string]int32) string { + dataType, _ := json.Marshal(param) + dataString := string(dataType) + return dataString +} +func JsonStringToMap(str string) (tempMap map[string]int32) { + _ = json.Unmarshal([]byte(str), &tempMap) + return tempMap +} +func GetSwitchFromOptions(Options map[string]bool, key string) (result bool) { + if flag, ok := Options[key]; !ok || flag { + return true + } + return false +} +func SetSwitchFromOptions(options map[string]bool, key string, value bool) { + if options == nil { + options = make(map[string]bool, 5) + } + options[key] = value +} diff --git a/pkg/utils/md5.go b/pkg/utils/md5.go new file mode 100644 index 000000000..8e3531668 --- /dev/null +++ b/pkg/utils/md5.go @@ -0,0 +1,13 @@ +package utils + +import ( + "crypto/md5" + "encoding/hex" +) + +func Md5(s string) string { + h := md5.New() + h.Write([]byte(s)) + cipher := h.Sum(nil) + return hex.EncodeToString(cipher) +} diff --git a/pkg/utils/strings.go b/pkg/utils/strings.go new file mode 100644 index 000000000..49d883f7c --- /dev/null +++ b/pkg/utils/strings.go @@ -0,0 +1,96 @@ +/* +** description(""). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/4/8 15:09). + */ +package utils + +import ( + "Open_IM/pkg/common/constant" + "encoding/json" + "math/rand" + "strconv" +) + +func IntToString(i int) string { + return strconv.FormatInt(int64(i), 10) +} + +func StringToInt(i string) int { + j, _ := strconv.Atoi(i) + return j +} +func StringToInt64(i string) int64 { + j, _ := strconv.ParseInt(i, 10, 64) + return j +} +func StringToInt32(i string) int32 { + j, _ := strconv.ParseInt(i, 10, 64) + return int32(j) +} +func Int32ToString(i int32) string { + return strconv.FormatInt(int64(i), 10) +} + +//judge a string whether in the string list +func IsContain(target string, List []string) bool { + for _, element := range List { + + if target == element { + return true + } + } + return false +} +func IsContainInt32(target int32, List []int32) bool { + for _, element := range List { + if target == element { + return true + } + } + return false +} + +func InterfaceArrayToStringArray(data []interface{}) (i []string) { + for _, param := range data { + i = append(i, param.(string)) + } + return i +} +func StructToJsonString(param interface{}) string { + dataType, _ := json.Marshal(param) + dataString := string(dataType) + return dataString +} + +func StructToJsonBytes(param interface{}) []byte { + dataType, _ := json.Marshal(param) + return dataType +} + +//The incoming parameter must be a pointer +func JsonStringToStruct(s string, args interface{}) error { + err := json.Unmarshal([]byte(s), args) + return err +} + +func GetMsgID(sendID string) string { + t := int64ToString(GetCurrentTimestampByNano()) + return Md5(t + sendID + int64ToString(rand.Int63n(GetCurrentTimestampByNano()))) +} +func GetConversationIDBySessionType(sourceID string, sessionType int) string { + switch sessionType { + case constant.SingleChatType: + return "single_" + sourceID + case constant.GroupChatType: + return "group_" + sourceID + } + return "" +} +func int64ToString(i int64) string { + return strconv.FormatInt(i, 10) +} +func Int64ToString(i int64) string { + return strconv.FormatInt(i, 10) +} diff --git a/pkg/utils/time_format.go b/pkg/utils/time_format.go new file mode 100644 index 000000000..c8f6e21fa --- /dev/null +++ b/pkg/utils/time_format.go @@ -0,0 +1,85 @@ +/* +** description(""). +** copyright('tuoyun,www.tuoyun.net'). +** author("fg,Gordon@tuoyun.net"). +** time(2021/2/22 11:52). + */ +package utils + +import ( + "strconv" + "time" +) + +const ( + TimeOffset = 8 * 3600 //8 hour offset + HalfOffset = 12 * 3600 //Half-day hourly offset +) + +//Get the current timestamp by Second +func GetCurrentTimestampBySecond() int64 { + return time.Now().Unix() +} + +//Convert timestamp to time.Time type +func UnixSecondToTime(second int64) time.Time { + return time.Unix(second, 0) +} + +//Convert nano timestamp to time.Time type +func UnixNanoSecondToTime(nanoSecond int64) time.Time { + return time.Unix(0, nanoSecond) +} +func UnixMillSecondToTime(millSecond int64) time.Time { + return time.Unix(0, millSecond*1e6) +} + +//Get the current timestamp by Nano +func GetCurrentTimestampByNano() int64 { + return time.Now().UnixNano() +} + +//Get the current timestamp by Mill +func GetCurrentTimestampByMill() int64 { + return time.Now().UnixNano() / 1e6 +} + +//Get the timestamp at 0 o'clock of the day +func GetCurDayZeroTimestamp() int64 { + timeStr := time.Now().Format("2006-01-02") + t, _ := time.Parse("2006-01-02", timeStr) + return t.Unix() - TimeOffset +} + +//Get the timestamp at 12 o'clock on the day +func GetCurDayHalfTimestamp() int64 { + return GetCurDayZeroTimestamp() + HalfOffset + +} + +//Get the formatted time at 0 o'clock of the day, the format is "2006-01-02_00-00-00" +func GetCurDayZeroTimeFormat() string { + return time.Unix(GetCurDayZeroTimestamp(), 0).Format("2006-01-02_15-04-05") +} + +//Get the formatted time at 12 o'clock of the day, the format is "2006-01-02_12-00-00" +func GetCurDayHalfTimeFormat() string { + return time.Unix(GetCurDayZeroTimestamp()+HalfOffset, 0).Format("2006-01-02_15-04-05") +} +func GetTimeStampByFormat(datetime string) string { + timeLayout := "2006-01-02 15:04:05" + loc, _ := time.LoadLocation("Local") + tmp, _ := time.ParseInLocation(timeLayout, datetime, loc) + timestamp := tmp.Unix() + return strconv.FormatInt(timestamp, 10) +} + +func TimeStringFormatTimeUnix(timeFormat string, timeSrc string) int64 { + tm, _ := time.Parse(timeFormat, timeSrc) + return tm.Unix() +} + +func TimeStringToTime(timeString string) (time.Time, error) { + t, err := time.Parse("2006-01-02", timeString) + return t, err +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go new file mode 100644 index 000000000..8f0b52d72 --- /dev/null +++ b/pkg/utils/utils.go @@ -0,0 +1,95 @@ +package utils + +import ( + "github.com/jinzhu/copier" + "github.com/pkg/errors" + "math/rand" + "runtime" + "strconv" + "strings" + "time" +) + +// copy a by b b->a +func CopyStructFields(a interface{}, b interface{}, fields ...string) (err error) { + return copier.Copy(a, b) +} + +func Wrap(err error, message string) error { + return errors.Wrap(err, "==> "+printCallerNameAndLine()+message) +} + +func WithMessage(err error, message string) error { + return errors.WithMessage(err, "==> "+printCallerNameAndLine()+message) +} + +func printCallerNameAndLine() string { + pc, _, line, _ := runtime.Caller(2) + return runtime.FuncForPC(pc).Name() + "()@" + strconv.Itoa(line) + ": " +} + +func GetSelfFuncName() string { + pc, _, _, _ := runtime.Caller(1) + return cleanUpFuncName(runtime.FuncForPC(pc).Name()) +} +func cleanUpFuncName(funcName string) string { + end := strings.LastIndex(funcName, ".") + if end == -1 { + return "" + } + return funcName[end+1:] +} + +//Get the intersection of two slices +func Intersect(slice1, slice2 []uint32) []uint32 { + m := make(map[uint32]bool) + n := make([]uint32, 0) + for _, v := range slice1 { + m[v] = true + } + for _, v := range slice2 { + flag, _ := m[v] + if flag { + n = append(n, v) + } + } + return n +} + +//Get the diff of two slices +func Difference(slice1, slice2 []uint32) []uint32 { + m := make(map[uint32]bool) + n := make([]uint32, 0) + inter := Intersect(slice1, slice2) + for _, v := range inter { + m[v] = true + } + for _, v := range slice1 { + if !m[v] { + n = append(n, v) + } + } + + for _, v := range slice2 { + if !m[v] { + n = append(n, v) + } + } + return n +} +func OperationIDGenerator() string { + return strconv.FormatInt(time.Now().UnixNano()+int64(rand.Uint32()), 10) +} + +func RemoveRepeatedStringInList(slc []string) []string { + var result []string + tempMap := map[string]byte{} + for _, e := range slc { + l := len(tempMap) + tempMap[e] = 0 + if len(tempMap) != l { + result = append(result, e) + } + } + return result +} diff --git a/script/build_all_service.sh b/script/build_all_service.sh new file mode 100644 index 000000000..0d9814bec --- /dev/null +++ b/script/build_all_service.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh + +bin_dir="../bin" +logs_dir="../logs" +sdk_db_dir="../db/sdk/" +#Automatically created when there is no bin, logs folder +if [ ! -d $bin_dir ]; then + mkdir -p $bin_dir +fi +if [ ! -d $logs_dir ]; then + mkdir -p $logs_dir +fi +if [ ! -d $sdk_db_dir ]; then + mkdir -p $sdk_db_dir +fi + +#begin path +begin_path=$PWD + +for ((i = 0; i < ${#service_source_root[*]}; i++)); do + cd $begin_path + service_path=${service_source_root[$i]} + cd $service_path + make install + if [ $? -ne 0 ]; then + echo -e "${RED_PREFIX}${service_names[$i]} build failed ${COLOR_SUFFIX}\n" + exit -1 + else + echo -e "${GREEN_PREFIX}${service_names[$i]} successfully be built ${COLOR_SUFFIX}\n" + fi +done +echo -e ${YELLOW_PREFIX}"all services build success"${COLOR_SUFFIX} diff --git a/script/build_images.sh b/script/build_images.sh new file mode 100644 index 000000000..ad37e24e4 --- /dev/null +++ b/script/build_images.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +image=openim/open_im_server:v1.0.5 +rm Open-IM-Server -rf +git clone https://github.com/OpenIMSDK/Open-IM-Server.git --recursive +cd Open-IM-Server +git checkout tuoyun +cd cmd/Open-IM-SDK-Core/ +git checkout tuoyun +cd ../../ +docker build -t $image . -f deploy.Dockerfile +docker push $image \ No newline at end of file diff --git a/script/check_all.sh b/script/check_all.sh new file mode 100644 index 000000000..c434c65d2 --- /dev/null +++ b/script/check_all.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh +service_port_name=( + openImCmsApiPort + openImApiPort + openImUserPort + openImFriendPort + openImOfflineMessagePort + openImOnlineRelayPort + openImGroupPort + openImAuthPort + openImPushPort + openImWsPort + openImSdkWsPort + openImDemoPort + openImAdminCmsPort + openImMessageCmsPort + openImStatisticsPort + openImOfficePort + openImOrganizationPort +) +switch=$(cat $config_path | grep demoswitch |awk -F '[:]' '{print $NF}') +for i in ${service_port_name[*]}; do + if [ ${switch} != "true" ]; then + if [ ${i} == "openImDemoPort"]; then + continue + fi + fi + list=$(cat $config_path | grep -w ${i} | awk -F '[:]' '{print $NF}') + list_to_string $list + for j in ${ports_array}; do + port=$(netstat -netulp | grep ./open_im | awk '{print $4}' | grep -w ${j} | awk -F '[:]' '{print $NF}') + if [[ ${port} -ne ${j} ]]; then + echo -e ${YELLOW_PREFIX}${i}${COLOR_SUFFIX}${RED_PREFIX}" service does not start normally,not initiated port is "${COLOR_SUFFIX}${YELLOW_PREFIX}${j}${COLOR_SUFFIX} + echo -e ${RED_PREFIX}"please check ../logs/openIM.log "${COLOR_SUFFIX} + exit -1 + else + echo -e ${j}${GREEN_PREFIX}" port has been listening,belongs service is "${i}${COLOR_SUFFIX} + fi + done +done + +#Check launched service process +check=$(ps aux | grep -w ./${msg_transfer_name} | grep -v grep | wc -l) +if [ $check -eq ${msg_transfer_service_num} ]; then + echo -e ${GREEN_PREFIX}"none port has been listening,belongs service is openImMsgTransfer"${COLOR_SUFFIX} +else + echo -e ${RED_PREFIX}"openImMsgTransfer service does not start normally, num err"${COLOR_SUFFIX} + echo -e ${RED_PREFIX}"please check ../logs/openIM.log "${COLOR_SUFFIX} + exit -1 +fi + + +#check=$(ps aux | grep -w ./${timer_task_name} | grep -v grep | wc -l) +#if [ $check -ge 1 ]; then +# echo -e ${GREEN_PREFIX}"none port has been listening,belongs service is openImMsgTimer"${COLOR_SUFFIX} +#else +# echo -e ${RED_PREFIX}"openImMsgTimer service does not start normally"${COLOR_SUFFIX} +# echo -e ${RED_PREFIX}"please check ../logs/openIM.log "${COLOR_SUFFIX} +# exit -1 +#fi + +echo -e ${YELLOW_PREFIX}"all services launch success"${COLOR_SUFFIX} diff --git a/script/demo_svr_start.sh b/script/demo_svr_start.sh new file mode 100644 index 000000000..85b36ab25 --- /dev/null +++ b/script/demo_svr_start.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +#Include shell font styles and some basic information +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh +switch=$(cat $config_path | grep demoswitch |awk -F '[:]' '{print $NF}') +if [ ${switch} != "true" ]; then + echo -e ${YELLOW_PREFIX}" demo service switch is false not start demo "${COLOR_SUFFIX} + exit 0 +fi +list1=$(cat $config_path | grep openImDemoPort | awk -F '[:]' '{print $NF}') +list_to_string $list1 +api_ports=($ports_array) + +#Check if the service exists +#If it is exists,kill this process +check=$(ps aux | grep -w ./${demo_server_name} | grep -v grep | wc -l) +if [ $check -ge 1 ]; then + oldPid=$(ps aux | grep -w ./${demo_server_name} | grep -v grep | awk '{print $2}') + kill -9 $oldPid +fi +#Waiting port recycling +sleep 1 +cd ${demo_server_binary_root} + +for ((i = 0; i < ${#api_ports[@]}; i++)); do + nohup ./${demo_server_name} -port ${api_ports[$i]} >>../logs/openIM.log 2>&1 & +done + +sleep 3 +#Check launched service process +check=$(ps aux | grep -w ./${demo_server_name} | grep -v grep | wc -l) +if [ $check -ge 1 ]; then + newPid=$(ps aux | grep -w ./${demo_server_name} | grep -v grep | awk '{print $2}') + ports=$(netstat -netulp | grep -w ${newPid} | awk '{print $4}' | awk -F '[:]' '{print $NF}') + allPorts="" + + for i in $ports; do + allPorts=${allPorts}"$i " + done + echo -e ${SKY_BLUE_PREFIX}"SERVICE START SUCCESS "${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"SERVICE_NAME: "${COLOR_SUFFIX}${YELLOW_PREFIX}${demo_server_name}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"PID: "${COLOR_SUFFIX}${YELLOW_PREFIX}${newPid}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"LISTENING_PORT: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allPorts}${COLOR_SUFFIX} +else + echo -e ${YELLOW_PREFIX}${demo_server_name}${COLOR_SUFFIX}${RED_PREFIX}"SERVICE START ERROR, PLEASE CHECK openIM.log"${COLOR_SUFFIX} +fi \ No newline at end of file diff --git a/script/docker_check_service.sh b/script/docker_check_service.sh new file mode 100644 index 000000000..6236712ba --- /dev/null +++ b/script/docker_check_service.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +echo "docker-compose ps..........................." +docker-compose ps + +echo "check OpenIM, waiting 30s...................." +sleep 30 + +echo "check OpenIM................................" +./check_all.sh + + diff --git a/script/docker_start_all.sh b/script/docker_start_all.sh new file mode 100644 index 000000000..42ee81992 --- /dev/null +++ b/script/docker_start_all.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +#fixme This script is the total startup script +#fixme The full name of the shell script that needs to be started is placed in the need_to_start_server_shell array + +#fixme Put the shell script name here +need_to_start_server_shell=( + start_rpc_service.sh + msg_gateway_start.sh + push_start.sh + msg_transfer_start.sh + sdk_svr_start.sh + demo_svr_start.sh +) + +#fixme The 10 second delay to start the project is for the docker-compose one-click to start openIM when the infrastructure dependencies are not started + +sleep 10 +time=`date +"%Y-%m-%d %H:%M:%S"` +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========server start time:${time}===========">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +for i in ${need_to_start_server_shell[*]}; do + chmod +x $i + ./$i +done + +sleep 15 + +#fixme prevents the openIM service exit after execution in the docker container +tail -f /dev/null diff --git a/script/env_check.sh b/script/env_check.sh new file mode 100644 index 000000000..2d81390f7 --- /dev/null +++ b/script/env_check.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +source ./style_info.cfg + +echo -e "check login user........................................" +user=`whoami` +if [ $user == "root" ] ; then + echo -e ${GREEN_PREFIX} "ok: login user is root" ${COLOR_SUFFIX} +else + echo -e ${RED_PREFIX}"Warning: The current user is not root "${COLOR_SUFFIX} +fi + + + +echo -e "check docker............................................" +docker_running=`systemctl status docker | grep running | grep active | wc -l` + +docker_version=`docker-compose -v; docker -v` + +if [ $docker_running -gt 0 ]; then + echo -e ${GREEN_PREFIX} "ok: docker is running" ${COLOR_SUFFIX} + echo -e ${GREEN_PREFIX} $docker_version ${COLOR_SUFFIX} + +else + echo -e ${RED_PREFIX}"docker not running"${COLOR_SUFFIX} +fi + + +echo -e "check environment......................................." +SYSTEM=`uname -s` +if [ $SYSTEM != "Linux" ] ; then + echo -e ${RED_PREFIX}"Warning: Currently only Linux is supported"${COLOR_SUFFIX} +else + echo -e ${GREEN_PREFIX} "ok: system is linux"${COLOR_SUFFIX} +fi + +echo -e "check memory............................................" +available=`free -m | grep Mem | awk '{print $NF}'` +if [ $available -lt 2000 ] ; then + echo -e ${RED_PREFIX}"Warning: Your memory not enough, available is: " "$available"m${COLOR_SUFFIX}"\c" + echo -e ${RED_PREFIX}", must be greater than 2000m"${COLOR_SUFFIX} +else + echo -e ${GREEN_PREFIX} "ok: available memory is: "$available"m${COLOR_SUFFIX}" +fi diff --git a/script/function.sh b/script/function.sh new file mode 100644 index 000000000..97f19187a --- /dev/null +++ b/script/function.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +#input:[10023,2323,3434] +#output:10023 2323 3434 +list_to_string(){ +ports_list=$* +sub_s1=`echo $ports_list | sed 's/ //g'` +sub_s2=${sub_s1//,/ } +sub_s3=${sub_s2#*[} +sub_s4=${sub_s3%]*} +ports_array=$sub_s4 +} +remove_space(){ + value=$* + result=`echo $value | sed 's/ //g'` +} \ No newline at end of file diff --git a/script/msg_gateway_start.sh b/script/msg_gateway_start.sh new file mode 100644 index 000000000..7c107f16a --- /dev/null +++ b/script/msg_gateway_start.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +#Include shell font styles and some basic information +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh +ulimit -n 200000 + +list1=$(cat $config_path | grep openImOnlineRelayPort | awk -F '[:]' '{print $NF}') +list2=$(cat $config_path | grep openImWsPort | awk -F '[:]' '{print $NF}') +list_to_string $list1 +rpc_ports=($ports_array) +list_to_string $list2 +ws_ports=($ports_array) +if [ ${#rpc_ports[@]} -ne ${#ws_ports[@]} ]; then + + echo -e ${RED_PREFIX}"ws_ports does not match push_rpc_ports in quantity!!!"${COLOR_SUFFIX} + exit -1 + +fi +#Check if the service exists +#If it is exists,kill this process +check=$(ps aux | grep -w ./${msg_gateway_name} | grep -v grep | wc -l) +if [ $check -ge 1 ]; then + oldPid=$(ps aux | grep -w ./${msg_gateway_name} | grep -v grep | awk '{print $2}') + kill -9 ${oldPid} +fi +#Waiting port recycling +sleep 1 +cd ${msg_gateway_binary_root} +for ((i = 0; i < ${#ws_ports[@]}; i++)); do + nohup ./${msg_gateway_name} -rpc_port ${rpc_ports[$i]} -ws_port ${ws_ports[$i]} >>../logs/openIM.log 2>&1 & +done + +#Check launched service process +sleep 3 +check=$(ps aux | grep -w ./${msg_gateway_name} | grep -v grep | wc -l) +allPorts="" +if [ $check -ge 1 ]; then + allNewPid=$(ps aux | grep -w ./${msg_gateway_name} | grep -v grep | awk '{print $2}') + for i in $allNewPid; do + ports=$(netstat -netulp | grep -w ${i} | awk '{print $4}' | awk -F '[:]' '{print $NF}') + allPorts=${allPorts}"$ports " + done + echo -e ${SKY_BLUE_PREFIX}"SERVICE START SUCCESS"${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"SERVICE_NAME: "${COLOR_SUFFIX}${YELLOW_PREFIX}${msg_gateway_name}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"PID: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allNewPid}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"LISTENING_PORT: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allPorts}${COLOR_SUFFIX} +else + echo -e ${YELLOW_PREFIX}${msg_gateway_name}${COLOR_SUFFIX}${RED_PREFIX}"SERVICE START ERROR, PLEASE CHECK openIM.log"${COLOR_SUFFIX} +fi diff --git a/script/msg_transfer_start.sh b/script/msg_transfer_start.sh new file mode 100644 index 000000000..4d7fb96cd --- /dev/null +++ b/script/msg_transfer_start.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +#Include shell font styles and some basic information +source ./style_info.cfg +source ./path_info.cfg + + + +#Check if the service exists +#If it is exists,kill this process +check=`ps aux | grep -w ./${msg_transfer_name} | grep -v grep| wc -l` +if [ $check -ge 1 ] +then +oldPid=`ps aux | grep -w ./${msg_transfer_name} | grep -v grep|awk '{print $2}'` + kill -9 $oldPid +fi +#Waiting port recycling +sleep 1 + +cd ${msg_transfer_binary_root} +for ((i = 0; i < ${msg_transfer_service_num}; i++)); do + nohup ./${msg_transfer_name} >>../logs/openIM.log 2>&1 & +done + +#Check launched service process +check=`ps aux | grep -w ./${msg_transfer_name} | grep -v grep| wc -l` +if [ $check -ge 1 ] +then +newPid=`ps aux | grep -w ./${msg_transfer_name} | grep -v grep|awk '{print $2}'` +allPorts="" + echo -e ${SKY_BLUE_PREFIX}"SERVICE START SUCCESS "${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"SERVICE_NAME: "${COLOR_SUFFIX}${YELLOW_PREFIX}${msg_transfer_name}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"PID: "${COLOR_SUFFIX}${YELLOW_PREFIX}${newPid}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"LISTENING_PORT: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allPorts}${COLOR_SUFFIX} +else + echo -e ${YELLOW_PREFIX}${msg_transfer_name}${COLOR_SUFFIX}${RED_PREFIX}"SERVICE START ERROR, PLEASE CHECK openIM.log"${COLOR_SUFFIX} +fi diff --git a/script/mysql_database_init.sh b/script/mysql_database_init.sh new file mode 100644 index 000000000..2a5135e8e --- /dev/null +++ b/script/mysql_database_init.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh + +#define database attributes +address=$(cat $config_path | grep -w dbMysqlAddress) +list_to_string ${address} +hostAndPort=($ports_array) +DATABASE_HOST=$(echo $hostAndPort | awk -F '[:]' '{print $1}') +DATABASE_PORT=$(echo $hostAndPort | awk -F '[:]' '{print $NF}') +DATABASE_USERNAME=$(cat $config_path | grep -w dbMysqlUserName | awk -F '[:]' '{print $NF}') +DATABASE_PWD=`eval echo $(cat $config_path | grep -w dbMysqlPassword | awk -F '[:]' '{print $NF}')` +DATABASE_NAME=$(cat $config_path | grep -w dbMysqlDatabaseName | awk -F '[:]' '{print $NF}') +SQL_FILE="../config/mysql_sql_file/openIM.sql" + + +create_data_sql="create database IF NOT EXISTS $DATABASE_NAME" +set_character_code_sql="alter database $DATABASE_NAME character set utf8mb4 collate utf8mb4_general_ci" + +echo -e "${SKY_BLUE_PREFIX}start to create database.....$COLOR_SUFFIX" +mysql -h $DATABASE_HOST -P $DATABASE_PORT -u $DATABASE_USERNAME -p$DATABASE_PWD -e "$create_data_sql" + +if [ $? -eq 0 ]; then + echo -e "${SKY_BLUE_PREFIX}create database ${DATABASE_NAME} successfully$COLOR_SUFFIX" + mysql -h $DATABASE_HOST -P $DATABASE_PORT -u $DATABASE_USERNAME -p$DATABASE_PWD -e "$set_character_code_sql" +else + echo -e "${RED_PREFIX}create database failed or exists the database$COLOR_SUFFIX\n" +fi + +echo -e "${SKY_BLUE_PREFIX}start to source openIM.sql .....$COLOR_SUFFIX" +mysql -h $DATABASE_HOST -P $DATABASE_PORT -u $DATABASE_USERNAME -p$DATABASE_PWD -D $DATABASE_NAME <$SQL_FILE +if [ $? -eq 0 ]; then + echo -e "${SKY_BLUE_PREFIX}source openIM.sql successfully$COLOR_SUFFIX" +else + echo -e "${RED_PREFIX}source openIM.sql failed$COLOR_SUFFIX\n" +fi diff --git a/script/path_info.cfg b/script/path_info.cfg new file mode 100644 index 000000000..b50fc18fb --- /dev/null +++ b/script/path_info.cfg @@ -0,0 +1,84 @@ +#Don't put the space between "=" +msg_gateway_name="open_im_msg_gateway" +msg_gateway_binary_root="../bin/" +msg_gateway_source_root="../cmd/open_im_msg_gateway/" + +msg_name="open_im_msg" +msg_binary_root="../bin/" +msg_source_root="../cmd/rpc/open_im_msg/" + +push_name="open_im_push" +push_binary_root="../bin/" +push_source_root="../cmd/open_im_push/" + + + +msg_transfer_name="open_im_msg_transfer" +msg_transfer_binary_root="../bin/" +msg_transfer_source_root="../cmd/open_im_msg_transfer/" +msg_transfer_service_num=2 + + +timer_task_name="open_im_timer_task" +timer_task_binary_root="../bin/" +timer_task_source_root="../cmd/open_im_timer_task/" + +sdk_server_name="open_im_sdk_server" +sdk_server_binary_root="../bin/" +sdk_server_source_root="../cmd/Open-IM-SDK-Core/" + +demo_server_name="open_im_demo" +demo_server_binary_root="../bin/" +demo_server_source_root="../cmd/open_im_demo/" + + +#Global configuration file default dir +config_path="../config/config.yaml" + +#servicefile dir path +service_source_root=( + #api service file + ../cmd/open_im_api/ + ../cmd/open_im_cms_api/ + #rpc service file + ../cmd/rpc/open_im_user/ + ../cmd/rpc/open_im_friend/ + ../cmd/rpc/open_im_group/ + ../cmd/rpc/open_im_auth/ + ../cmd/rpc/open_im_admin_cms/ + ../cmd/rpc/open_im_message_cms/ + ../cmd/rpc/open_im_statistics/ + ../cmd/rpc/open_im_office/ + ../cmd/rpc/open_im_organization/ + ${msg_gateway_source_root} + ${msg_transfer_source_root} + ${msg_source_root} + ${push_source_root} + ${sdk_server_source_root} + ${demo_server_source_root} +) +#service filename +service_names=( + #api service filename + open_im_api + open_im_cms_api + #rpc service filename + open_im_user + open_im_friend + open_im_group + open_im_auth + open_im_admin_cms + open_im_message_cms + open_im_statistics + open_im_office + open_im_organization + ${msg_gateway_name} + ${msg_transfer_name} + ${msg_name} + ${push_name} + ${sdk_server_name} + ${demo_server_name} +) + + + diff --git a/script/push_start.sh b/script/push_start.sh new file mode 100644 index 000000000..8b2a47896 --- /dev/null +++ b/script/push_start.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +#Include shell font styles and some basic information +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh + + + +list1=$(cat $config_path | grep openImPushPort | awk -F '[:]' '{print $NF}') +list_to_string $list1 +rpc_ports=($ports_array) + +#Check if the service exists +#If it is exists,kill this process +check=$(ps aux | grep -w ./${push_name} | grep -v grep | wc -l) +if [ $check -ge 1 ]; then + oldPid=$(ps aux | grep -w ./${push_name} | grep -v grep | awk '{print $2}') + kill -9 $oldPid +fi +#Waiting port recycling +sleep 1 +cd ${push_binary_root} + +for ((i = 0; i < ${#rpc_ports[@]}; i++)); do + nohup ./${push_name} -port ${rpc_ports[$i]} >>../logs/openIM.log 2>&1 & +done + +sleep 3 +#Check launched service process +check=$(ps aux | grep -w ./${push_name} | grep -v grep | wc -l) +if [ $check -ge 1 ]; then + newPid=$(ps aux | grep -w ./${push_name} | grep -v grep | awk '{print $2}') + ports=$(netstat -netulp | grep -w ${newPid} | awk '{print $4}' | awk -F '[:]' '{print $NF}') + allPorts="" + + for i in $ports; do + allPorts=${allPorts}"$i " + done + echo -e ${SKY_BLUE_PREFIX}"SERVICE START SUCCESS "${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"SERVICE_NAME: "${COLOR_SUFFIX}${YELLOW_PREFIX}${push_name}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"PID: "${COLOR_SUFFIX}${YELLOW_PREFIX}${newPid}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"LISTENING_PORT: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allPorts}${COLOR_SUFFIX} +else + echo -e ${YELLOW_PREFIX}${push_name}${COLOR_SUFFIX}${RED_PREFIX}"SERVICE START ERROR, PLEASE CHECK openIM.log"${COLOR_SUFFIX} +fi diff --git a/script/sdk_svr_start.sh b/script/sdk_svr_start.sh new file mode 100644 index 000000000..5f47228dc --- /dev/null +++ b/script/sdk_svr_start.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +#Include shell font styles and some basic information +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh +list1=$(cat $config_path | grep openImApiPort | awk -F '[:]' '{print $NF}') +list2=$(cat $config_path | grep openImWsPort | awk -F '[:]' '{print $NF}') +list3=$(cat $config_path | grep openImSdkWsPort | awk -F '[:]' '{print $NF}') +logLevel=$(cat $config_path | grep remainLogLevel | awk -F '[:]' '{print $NF}') +list_to_string $list1 +api_ports=($ports_array) +list_to_string $list2 +ws_ports=($ports_array) +list_to_string $list3 +sdk_ws_ports=($ports_array) +list_to_string $list4 + + + +#Check if the service exists +#If it is exists,kill this process +check=$(ps aux | grep -w ./${sdk_server_name} | grep -v grep | wc -l) +if [ $check -ge 1 ]; then + oldPid=$(ps aux | grep -w ./${sdk_server_name} | grep -v grep | awk '{print $2}') + kill -9 ${oldPid} +fi +#Waiting port recycling +sleep 1 +cd ${sdk_server_binary_root} + nohup ./${sdk_server_name} -openIM_api_port ${api_ports[0]} -openIM_ws_port ${ws_ports[0]} -sdk_ws_port ${sdk_ws_ports[0]} -openIM_log_level ${logLevel} >>../logs/openIM.log 2>&1 & + +#Check launched service process +sleep 3 +check=$(ps aux | grep -w ./${sdk_server_name} | grep -v grep | wc -l) +allPorts="" +if [ $check -ge 1 ]; then + allNewPid=$(ps aux | grep -w ./${sdk_server_name} | grep -v grep | awk '{print $2}') + for i in $allNewPid; do + ports=$(netstat -netulp | grep -w ${i} | awk '{print $4}' | awk -F '[:]' '{print $NF}') + allPorts=${allPorts}"$ports " + done + echo -e ${SKY_BLUE_PREFIX}"SERVICE START SUCCESS "${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"SERVICE_NAME: "${COLOR_SUFFIX}${YELLOW_PREFIX}${sdk_server_name}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"PID: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allNewPid}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"LISTENING_PORT: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allPorts}${COLOR_SUFFIX} +else + echo -e ${YELLOW_PREFIX}${sdk_server_name}${COLOR_SUFFIX}${RED_PREFIX}"SERVICE START ERROR PLEASE CHECK openIM.log"${COLOR_SUFFIX} +fi diff --git a/script/start_all.sh b/script/start_all.sh new file mode 100644 index 000000000..bf7170d68 --- /dev/null +++ b/script/start_all.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +#fixme This script is the total startup script +#fixme The full name of the shell script that needs to be started is placed in the need_to_start_server_shell array + +#fixme Put the shell script name here +need_to_start_server_shell=( + start_rpc_service.sh + msg_gateway_start.sh + push_start.sh + msg_transfer_start.sh + sdk_svr_start.sh + demo_svr_start.sh +) +time=`date +"%Y-%m-%d %H:%M:%S"` +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========server start time:${time}===========">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & +echo "==========================================================">>../logs/openIM.log 2>&1 & + +for i in ${need_to_start_server_shell[*]}; do + chmod +x $i + ./$i + if [ $? -ne 0 ]; then + exit -1 + fi +done diff --git a/script/start_rpc_service.sh b/script/start_rpc_service.sh new file mode 100644 index 000000000..20e7991b4 --- /dev/null +++ b/script/start_rpc_service.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +source ./style_info.cfg +source ./path_info.cfg +source ./function.sh + +#service filename +service_filename=( + #api + open_im_api + open_im_cms_api + #rpc + open_im_user + open_im_friend + open_im_group + open_im_auth + open_im_admin_cms + open_im_message_cms + open_im_statistics + ${msg_name} + open_im_office + open_im_organization +) + +#service config port name +service_port_name=( + #api port name + openImApiPort + openImCmsApiPort + #rpc port name + openImUserPort + openImFriendPort + openImGroupPort + openImAuthPort + openImAdminCmsPort + openImMessageCmsPort + openImStatisticsPort + openImOfflineMessagePort + openImOfficePort + openImOrganizationPort +) + +for ((i = 0; i < ${#service_filename[*]}; i++)); do + #Check whether the service exists + service_name="ps -aux |grep -w ${service_filename[$i]} |grep -v grep" + count="${service_name}| wc -l" + + if [ $(eval ${count}) -gt 0 ]; then + pid="${service_name}| awk '{print \$2}'" + echo "${service_filename[$i]} service has been started,pid:$(eval $pid)" + echo "killing the service ${service_filename[$i]} pid:$(eval $pid)" + #kill the service that existed + kill -9 $(eval $pid) + sleep 0.5 + fi + cd ../bin + #Get the rpc port in the configuration file + portList=$(cat $config_path | grep ${service_port_name[$i]} | awk -F '[:]' '{print $NF}') + list_to_string ${portList} + #Start related rpc services based on the number of ports + for j in ${ports_array}; do + #Start the service in the background + # ./${service_filename[$i]} -port $j & + nohup ./${service_filename[$i]} -port $j >>../logs/openIM.log 2>&1 & + sleep 1 + pid="netstat -ntlp|grep $j |awk '{printf \$7}'|cut -d/ -f1" + echo -e "${GREEN_PREFIX}${service_filename[$i]} start success,port number:$j pid:$(eval $pid)$COLOR_SUFFIX" + done +done diff --git a/script/stop_all.sh b/script/stop_all.sh new file mode 100644 index 000000000..2e1e119c1 --- /dev/null +++ b/script/stop_all.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +#fixme This script is to stop the service + +source ./style_info.cfg +source ./path_info.cfg + + +for i in ${service_names[*]}; do + #Check whether the service exists + name="ps -aux |grep -w $i |grep -v grep" + count="${name}| wc -l" + if [ $(eval ${count}) -gt 0 ]; then + pid="${name}| awk '{print \$2}'" + echo -e "${SKY_BLUE_PREFIX}Killing service:$i pid:$(eval $pid)${COLOR_SUFFIX}" + #kill the service that existed + kill -9 $(eval $pid) + echo -e "${SKY_BLUE_PREFIX}service:$i was killed ${COLOR_SUFFIX}" + fi +done diff --git a/script/style_info.cfg b/script/style_info.cfg new file mode 100644 index 000000000..ff28dcb88 --- /dev/null +++ b/script/style_info.cfg @@ -0,0 +1,9 @@ +#Shell font formatting information +COLOR_SUFFIX="\033[0m" +BLACK_PREFIX="\033[30m" +RED_PREFIX="\033[31m" +GREEN_PREFIX="\033[32m" +YELLOW_PREFIX="\033[33m" +BLUE_PREFIX="\033[34m" +PURPLE_PREFIX="\033[35m" +SKY_BLUE_PREFIX="\033[36m" diff --git a/script/timer_start.sh b/script/timer_start.sh new file mode 100644 index 000000000..7e2791f11 --- /dev/null +++ b/script/timer_start.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +#Include shell font styles and some basic information +source ./style_info.cfg +source ./path_info.cfg + + + +#Check if the service exists +#If it is exists,kill this process +check=`ps aux | grep -w ./${timer_task_name} | grep -v grep| wc -l` +if [ $check -ge 1 ] +then +oldPid=`ps aux | grep -w ./${timer_task_name} | grep -v grep|awk '{print $2}'` + kill -9 $oldPid +fi +#Waiting port recycling +sleep 1 + +cd ${timer_task_binary_root} +nohup ./${timer_task_name} >>../logs/openIM.log 2>&1 & + + +#Check launched service process +check=`ps aux | grep -w ./${timer_task_name} | grep -v grep| wc -l` +if [ $check -ge 1 ] +then +newPid=`ps aux | grep -w ./${timer_task_name} | grep -v grep|awk '{print $2}'` +allPorts="" + echo -e ${SKY_BLUE_PREFIX}"SERVICE START SUCCESS "${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"SERVICE_NAME: "${COLOR_SUFFIX}${YELLOW_PREFIX}${timer_task_name}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"PID: "${COLOR_SUFFIX}${YELLOW_PREFIX}${newPid}${COLOR_SUFFIX} + echo -e ${SKY_BLUE_PREFIX}"LISTENING_PORT: "${COLOR_SUFFIX}${YELLOW_PREFIX}${allPorts}${COLOR_SUFFIX} +else + echo -e ${YELLOW_PREFIX}${timer_task_name}${COLOR_SUFFIX}${RED_PREFIX}"SERVICE START ERROR, PLEASE CHECK openIM.log"${COLOR_SUFFIX} +fi