#include "data_redis.hpp" // redis数据管理客户端封装 #include "etcd.hpp" // 服务注册模块封装 #include "logger.hpp" // 日志模块封装 #include "channel.hpp" // 信道管理模块封装 #include "connection.hpp" #include "user.pb.h" // protobuf框架代码 #include "base.pb.h" // protobuf框架代码 #include "file.pb.h" // protobuf框架代码 #include "friend.pb.h" // protobuf框架代码 #include "gateway.pb.h" // protobuf框架代码 #include "message.pb.h" // protobuf框架代码 #include "speech.pb.h" // protobuf框架代码 #include "transmite.pb.h" // protobuf框架代码 #include "notify.pb.h" #include "httplib.h" namespace bite_im{ #define GET_PHONE_VERIFY_CODE "/service/user/get_phone_verify_code" #define USERNAME_REGISTER "/service/user/username_register" #define USERNAME_LOGIN "/service/user/username_login" #define PHONE_REGISTER "/service/user/phone_register" #define PHONE_LOGIN "/service/user/phone_login" #define GET_USERINFO "/service/user/get_user_info" #define SET_USER_AVATAR "/service/user/set_avatar" #define SET_USER_NICKNAME "/service/user/set_nickname" #define SET_USER_DESC "/service/user/set_description" #define SET_USER_PHONE "/service/user/set_phone" #define FRIEND_GET_LIST "/service/friend/get_friend_list" #define FRIEND_APPLY "/service/friend/add_friend_apply" #define FRIEND_APPLY_PROCESS "/service/friend/add_friend_process" #define FRIEND_REMOVE "/service/friend/remove_friend" #define FRIEND_SEARCH "/service/friend/search_friend" #define FRIEND_GET_PENDING_EV "/service/friend/get_pending_friend_events" #define CSS_GET_LIST "/service/friend/get_chat_session_list" #define CSS_CREATE "/service/friend/create_chat_session" #define CSS_GET_MEMBER "/service/friend/get_chat_session_member" #define MSG_GET_RANGE "/service/message_storage/get_history" #define MSG_GET_RECENT "/service/message_storage/get_recent" #define MSG_KEY_SEARCH "/service/message_storage/search_history" #define NEW_MESSAGE "/service/message_transmit/new_message" #define FILE_GET_SINGLE "/service/file/get_single_file" #define FILE_GET_MULTI "/service/file/get_multi_file" #define FILE_PUT_SINGLE "/service/file/put_single_file" #define FILE_PUT_MULTI "/service/file/put_multi_file" #define SPEECH_RECOGNITION "/service/speech/recognition" class GatewayServer { public: using ptr = std::shared_ptr; GatewayServer( int websocket_port, int http_port, const std::shared_ptr &redis_client, const ServiceManager::ptr &channels, const Discovery::ptr &service_discoverer, const std::string user_service_name, const std::string file_service_name, const std::string speech_service_name, const std::string message_service_name, const std::string transmite_service_name, const std::string friend_service_name) :_redis_session(std::make_shared(redis_client)), _redis_status(std::make_shared(redis_client)), _mm_channels(channels), _service_discoverer(service_discoverer), _user_service_name(user_service_name), _file_service_name(file_service_name), _speech_service_name(speech_service_name), _message_service_name(message_service_name), _transmite_service_name(transmite_service_name), _friend_service_name(friend_service_name), _connections(std::make_shared()){ _ws_server.set_access_channels(websocketpp::log::alevel::none); _ws_server.init_asio(); _ws_server.set_open_handler(std::bind(&GatewayServer::onOpen, this, std::placeholders::_1)); _ws_server.set_close_handler(std::bind(&GatewayServer::onClose, this, std::placeholders::_1)); auto wscb = std::bind(&GatewayServer::onMessage, this, std::placeholders::_1, std::placeholders::_2); _ws_server.set_message_handler(wscb); _ws_server.set_reuse_addr(true); _ws_server.listen(websocket_port); _ws_server.start_accept(); _http_server.Post(GET_PHONE_VERIFY_CODE , (httplib::Server::Handler)std::bind(&GatewayServer::GetPhoneVerifyCode , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(USERNAME_REGISTER , (httplib::Server::Handler)std::bind(&GatewayServer::UserRegister , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(USERNAME_LOGIN , (httplib::Server::Handler)std::bind(&GatewayServer::UserLogin , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(PHONE_REGISTER , (httplib::Server::Handler)std::bind(&GatewayServer::PhoneRegister , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(PHONE_LOGIN , (httplib::Server::Handler)std::bind(&GatewayServer::PhoneLogin , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(GET_USERINFO , (httplib::Server::Handler)std::bind(&GatewayServer::GetUserInfo , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(SET_USER_AVATAR , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserAvatar , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(SET_USER_NICKNAME , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserNickname , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(SET_USER_DESC , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserDescription , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(SET_USER_PHONE , (httplib::Server::Handler)std::bind(&GatewayServer::SetUserPhoneNumber , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FRIEND_GET_LIST , (httplib::Server::Handler)std::bind(&GatewayServer::GetFriendList , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FRIEND_APPLY , (httplib::Server::Handler)std::bind(&GatewayServer::FriendAdd , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FRIEND_APPLY_PROCESS , (httplib::Server::Handler)std::bind(&GatewayServer::FriendAddProcess , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FRIEND_REMOVE , (httplib::Server::Handler)std::bind(&GatewayServer::FriendRemove , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FRIEND_SEARCH , (httplib::Server::Handler)std::bind(&GatewayServer::FriendSearch , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FRIEND_GET_PENDING_EV , (httplib::Server::Handler)std::bind(&GatewayServer::GetPendingFriendEventList , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(CSS_GET_LIST , (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionList , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(CSS_CREATE , (httplib::Server::Handler)std::bind(&GatewayServer::ChatSessionCreate , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(CSS_GET_MEMBER , (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionMember , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(MSG_GET_RANGE , (httplib::Server::Handler)std::bind(&GatewayServer::GetHistoryMsg , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(MSG_GET_RECENT , (httplib::Server::Handler)std::bind(&GatewayServer::GetRecentMsg , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(MSG_KEY_SEARCH , (httplib::Server::Handler)std::bind(&GatewayServer::MsgSearch , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(NEW_MESSAGE , (httplib::Server::Handler)std::bind(&GatewayServer::NewMessage , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FILE_GET_SINGLE , (httplib::Server::Handler)std::bind(&GatewayServer::GetSingleFile , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FILE_GET_MULTI , (httplib::Server::Handler)std::bind(&GatewayServer::GetMultiFile , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FILE_PUT_SINGLE , (httplib::Server::Handler)std::bind(&GatewayServer::PutSingleFile , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(FILE_PUT_MULTI , (httplib::Server::Handler)std::bind(&GatewayServer::PutMultiFile , this, std::placeholders::_1, std::placeholders::_2)); _http_server.Post(SPEECH_RECOGNITION , (httplib::Server::Handler)std::bind(&GatewayServer::SpeechRecognition , this, std::placeholders::_1, std::placeholders::_2)); _http_thread = std::thread([this, http_port](){ _http_server.listen("0.0.0.0", http_port); }); _http_thread.detach(); } void start() { _ws_server.run(); } private: void onOpen(websocketpp::connection_hdl hdl) { LOG_DEBUG("websocket长连接建立成功 {}", (size_t)_ws_server.get_con_from_hdl(hdl).get()); } void onClose(websocketpp::connection_hdl hdl) { //长连接断开时做的清理工作 //0. 通过连接对象,获取对应的用户ID与登录会话ID auto conn = _ws_server.get_con_from_hdl(hdl); std::string uid, ssid; bool ret = _connections->client(conn, uid, ssid); if (ret == false) { LOG_WARN("长连接断开,未找到长连接对应的客户端信息!"); return ; } //1. 移除登录会话信息 _redis_session->remove(ssid); //2. 移除登录状态信息 _redis_status->remove(uid); //3. 移除长连接管理数据 _connections->remove(conn); LOG_DEBUG("{} {} {} 长连接断开,清理缓存数据!", ssid, uid, (size_t)conn.get()); } void keepAlive(server_t::connection_ptr conn) { if (!conn || conn->get_state() != websocketpp::session::state::value::open) { LOG_DEBUG("非正常连接状态,结束连接保活"); return; } conn->ping(""); _ws_server.set_timer(60000, std::bind(&GatewayServer::keepAlive, this, conn)); } void onMessage(websocketpp::connection_hdl hdl, server_t::message_ptr msg) { //收到第一条消息后,根据消息中的会话ID进行身份识别,将客户端长连接添加管理 //1. 取出长连接对应的连接对象 auto conn = _ws_server.get_con_from_hdl(hdl); //2. 针对消息内容进行反序列化 -- ClientAuthenticationReq -- 提取登录会话ID ClientAuthenticationReq request; bool ret = request.ParseFromString(msg->get_payload()); if (ret == false) { LOG_ERROR("长连接身份识别失败:正文反序列化失败!"); _ws_server.close(hdl, websocketpp::close::status::unsupported_data, "正文反序列化失败!"); return; } //3. 在会话信息缓存中,查找会话信息 std::string ssid = request.session_id(); auto uid = _redis_session->uid(ssid); //4. 会话信息不存在则关闭连接 if (!uid) { LOG_ERROR("长连接身份识别失败:未找到会话信息 {}!", ssid); _ws_server.close(hdl, websocketpp::close::status::unsupported_data, "未找到会话信息!"); return; } //5. 会话信息存在,则添加长连接管理 _connections->insert(conn, *uid, ssid); LOG_DEBUG("新增长连接管理:{}-{}-{}", ssid, *uid, (size_t)conn.get()); keepAlive(conn); } void GetPhoneVerifyCode(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 PhoneVerifyCodeReq req; PhoneVerifyCodeRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取短信验证码请求正文反序列化失败!"); return err_response("获取短信验证码请求正文反序列化失败!"); } //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetPhoneVerifyCode(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void UserRegister(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 UserRegisterReq req; UserRegisterRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户名注册请求正文反序列化失败!"); return err_response("用户名注册请求正文反序列化失败!"); } //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.UserRegister(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void UserLogin(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 UserLoginReq req; UserLoginRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户登录请求正文反序列化失败!"); return err_response("用户登录请求正文反序列化失败!"); } //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.UserLogin(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void PhoneRegister(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 PhoneRegisterReq req; PhoneRegisterRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("手机号注册请求正文反序列化失败!"); return err_response("手机号注册请求正文反序列化失败!"); } //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.PhoneRegister(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void PhoneLogin(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 PhoneLoginReq req; PhoneLoginRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("手机号登录请求正文反序列化失败!"); return err_response("手机号登录请求正文反序列化失败!"); } //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.PhoneLogin(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetUserInfo(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 GetUserInfoReq req; GetUserInfoRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取用户信息请求正文反序列化失败!"); return err_response("获取用户信息请求正文反序列化失败!"); } //2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetUserInfo(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void SetUserAvatar(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 SetUserAvatarReq req; SetUserAvatarRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户头像设置请求正文反序列化失败!"); return err_response("用户头像设置请求正文反序列化失败!"); } //2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.SetUserAvatar(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void SetUserNickname(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 SetUserNicknameReq req; SetUserNicknameRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户昵称设置请求正文反序列化失败!"); return err_response("用户昵称设置请求正文反序列化失败!"); } //2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.SetUserNickname(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void SetUserDescription(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 SetUserDescriptionReq req; SetUserDescriptionRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户签名设置请求正文反序列化失败!"); return err_response("用户签名设置请求正文反序列化失败!"); } //2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.SetUserDescription(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void SetUserPhoneNumber(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 SetUserPhoneNumberReq req; SetUserPhoneNumberRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户手机号设置请求正文反序列化失败!"); return err_response("用户手机号设置请求正文反序列化失败!"); } //2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.SetUserPhoneNumber(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return err_response("用户子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetFriendList(const httplib::Request &request, httplib::Response &response) { //1. 取出http请求正文,将正文进行反序列化 GetFriendListReq req; GetFriendListRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取好友列表请求正文反序列化失败!"); return err_response("获取好友列表请求正文反序列化失败!"); } //2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); //2. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetFriendList(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } //3. 得到用户子服务的响应后,将响应内容进行序列化作为http响应正文 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } std::shared_ptr _GetUserInfo(const std::string &rid, const std::string &uid) { GetUserInfoReq req; auto rsp = std::make_shared(); req.set_request_id(rid); req.set_user_id(uid); //2. 将请求转发给用户子服务进行业务处理 auto channel = _mm_channels->choose(_user_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return std::shared_ptr(); } bite_im::UserService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetUserInfo(&cntl, &req, rsp.get(), nullptr); if (cntl.Failed()) { LOG_ERROR("{} 用户子服务调用失败!", req.request_id()); return std::shared_ptr(); } return rsp; } void FriendAdd(const httplib::Request &request, httplib::Response &response) { // 好友申请的业务处理中,好友子服务其实只是在数据库创建了申请事件 // 网关需要做的事情:当好友子服务将业务处理完毕后,如果处理是成功的--需要通知被申请方 // 1. 正文的反序列化,提取关键要素:登录会话ID FriendAddReq req; FriendAddRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("申请好友请求正文反序列化失败!"); return err_response("申请好友请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.FriendAdd(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 4. 若业务处理成功 --- 且获取被申请方长连接成功,则向被申请放进行好友申请事件通知 auto conn = _connections->connection(req.respondent_id()); if (rsp.success() && conn) { LOG_DEBUG("找到被申请人 {} 长连接,对其进行好友申请通知", req.respondent_id()); auto user_rsp = _GetUserInfo(req.request_id(), *uid); if (!user_rsp) { LOG_ERROR("{} 获取当前客户端用户信息失败!", req.request_id()); return err_response("获取当前客户端用户信息失败!"); } NotifyMessage notify; notify.set_notify_type(NotifyType::FRIEND_ADD_APPLY_NOTIFY); notify.mutable_friend_add_apply()->mutable_user_info()->CopyFrom(user_rsp->user_info()); conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void FriendAddProcess(const httplib::Request &request, httplib::Response &response) { //好友申请的处理----- FriendAddProcessReq req; FriendAddProcessRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("好友申请处理请求正文反序列化失败!"); return err_response("好友申请处理请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.FriendAddProcess(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } if (rsp.success()) { auto process_user_rsp = _GetUserInfo(req.request_id(), *uid); if (!process_user_rsp) { LOG_ERROR("{} 获取用户信息失败!", req.request_id()); return err_response("获取用户信息失败!"); } auto apply_user_rsp = _GetUserInfo(req.request_id(), req.apply_user_id()); if (!process_user_rsp) { LOG_ERROR("{} 获取用户信息失败!", req.request_id()); return err_response("获取用户信息失败!"); } auto process_conn = _connections->connection(*uid); if (process_conn) LOG_DEBUG("找到处理人的长连接!"); else LOG_DEBUG("未找到处理人的长连接!"); auto apply_conn = _connections->connection(req.apply_user_id()); if (apply_conn) LOG_DEBUG("找到申请人的长连接!"); else LOG_DEBUG("未找到申请人的长连接!"); //4. 将处理结果给申请人进行通知 if (apply_conn) { NotifyMessage notify; notify.set_notify_type(NotifyType::FRIEND_ADD_PROCESS_NOTIFY); auto process_result = notify.mutable_friend_process_result(); process_result->mutable_user_info()->CopyFrom(process_user_rsp->user_info()); process_result->set_agree(req.agree()); apply_conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); LOG_DEBUG("对申请人进行申请处理结果通知!"); } //5. 若处理结果是同意 --- 会伴随着单聊会话的创建 -- 因此需要对双方进行会话创建的通知 if (req.agree() && apply_conn) { //对申请人的通知---会话信息就是处理人信息 NotifyMessage notify; notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY); auto chat_session = notify.mutable_new_chat_session_info(); chat_session->mutable_chat_session_info()->set_single_chat_friend_id(*uid); chat_session->mutable_chat_session_info()->set_chat_session_id(rsp.new_session_id()); chat_session->mutable_chat_session_info()->set_chat_session_name(process_user_rsp->user_info().nickname()); chat_session->mutable_chat_session_info()->set_avatar(process_user_rsp->user_info().avatar()); apply_conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); LOG_DEBUG("对申请人进行会话创建通知!"); } if (req.agree() && process_conn) { //对处理人的通知 --- 会话信息就是申请人信息 NotifyMessage notify; notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY); auto chat_session = notify.mutable_new_chat_session_info(); chat_session->mutable_chat_session_info()->set_single_chat_friend_id(req.apply_user_id()); chat_session->mutable_chat_session_info()->set_chat_session_id(rsp.new_session_id()); chat_session->mutable_chat_session_info()->set_chat_session_name(apply_user_rsp->user_info().nickname()); chat_session->mutable_chat_session_info()->set_avatar(apply_user_rsp->user_info().avatar()); process_conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); LOG_DEBUG("对处理人进行会话创建通知!"); } } //6. 对客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void FriendRemove(const httplib::Request &request, httplib::Response &response) { // 1. 正文的反序列化,提取关键要素:登录会话ID FriendRemoveReq req; FriendRemoveRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("删除好友请求正文反序列化失败!"); return err_response("删除好友请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.FriendRemove(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 4. 若业务处理成功 --- 且获取被申请方长连接成功,则向被申请放进行好友申请事件通知 auto conn = _connections->connection(req.peer_id()); if (rsp.success() && conn) { LOG_ERROR("对被删除人 {} 进行好友删除通知!", req.peer_id()); NotifyMessage notify; notify.set_notify_type(NotifyType::FRIEND_REMOVE_NOTIFY); notify.mutable_friend_remove()->set_user_id(*uid); conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void FriendSearch(const httplib::Request &request, httplib::Response &response) { FriendSearchReq req; FriendSearchRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("用户搜索请求正文反序列化失败!"); return err_response("用户搜索请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.FriendSearch(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetPendingFriendEventList(const httplib::Request &request, httplib::Response &response) { GetPendingFriendEventListReq req; GetPendingFriendEventListRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取待处理好友申请请求正文反序列化失败!"); return err_response("获取待处理好友申请请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetPendingFriendEventList(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetChatSessionList(const httplib::Request &request, httplib::Response &response) { GetChatSessionListReq req; GetChatSessionListRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取聊天会话列表请求正文反序列化失败!"); return err_response("获取聊天会话列表请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetChatSessionList(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetChatSessionMember(const httplib::Request &request, httplib::Response &response) { GetChatSessionMemberReq req; GetChatSessionMemberRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取聊天会话成员请求正文反序列化失败!"); return err_response("获取聊天会话成员请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetChatSessionMember(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void ChatSessionCreate(const httplib::Request &request, httplib::Response &response) { ChatSessionCreateReq req; ChatSessionCreateRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("创建聊天会话请求正文反序列化失败!"); return err_response("创建聊天会话请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_friend_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FriendService_Stub stub(channel.get()); brpc::Controller cntl; stub.ChatSessionCreate(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 好友子服务调用失败!", req.request_id()); return err_response("好友子服务调用失败!"); } // 4. 若业务处理成功 --- 且获取被申请方长连接成功,则向被申请放进行好友申请事件通知 if (rsp.success()){ for (int i = 0; i < req.member_id_list_size(); i++) { auto conn = _connections->connection(req.member_id_list(i)); if (!conn) { LOG_DEBUG("未找到群聊成员 {} 长连接", req.member_id_list(i)); continue; } NotifyMessage notify; notify.set_notify_type(NotifyType::CHAT_SESSION_CREATE_NOTIFY); auto chat_session = notify.mutable_new_chat_session_info(); chat_session->mutable_chat_session_info()->CopyFrom(rsp.chat_session_info()); conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); LOG_DEBUG("对群聊成员 {} 进行会话创建通知", req.member_id_list(i)); } } // 5. 向客户端进行响应 rsp.clear_chat_session_info(); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetHistoryMsg(const httplib::Request &request, httplib::Response &response) { GetHistoryMsgReq req; GetHistoryMsgRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取区间消息请求正文反序列化失败!"); return err_response("获取区间消息请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_message_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::MsgStorageService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetHistoryMsg(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 消息存储子服务调用失败!", req.request_id()); return err_response("消息存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetRecentMsg(const httplib::Request &request, httplib::Response &response) { GetRecentMsgReq req; GetRecentMsgRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("获取最近消息请求正文反序列化失败!"); return err_response("获取最近消息请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_message_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::MsgStorageService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetRecentMsg(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 消息存储子服务调用失败!", req.request_id()); return err_response("消息存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void MsgSearch(const httplib::Request &request, httplib::Response &response) { MsgSearchReq req; MsgSearchRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("消息搜索请求正文反序列化失败!"); return err_response("消息搜索请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_message_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::MsgStorageService_Stub stub(channel.get()); brpc::Controller cntl; stub.MsgSearch(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 消息存储子服务调用失败!", req.request_id()); return err_response("消息存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetSingleFile(const httplib::Request &request, httplib::Response &response) { GetSingleFileReq req; GetSingleFileRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("单文件下载请求正文反序列化失败!"); return err_response("单文件下载请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_file_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FileService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetSingleFile(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 文件存储子服务调用失败!", req.request_id()); return err_response("文件存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void GetMultiFile(const httplib::Request &request, httplib::Response &response) { GetMultiFileReq req; GetMultiFileRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("单文件下载请求正文反序列化失败!"); return err_response("单文件下载请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_file_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FileService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetMultiFile(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 文件存储子服务调用失败!", req.request_id()); return err_response("文件存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void PutSingleFile(const httplib::Request &request, httplib::Response &response) { PutSingleFileReq req; PutSingleFileRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("单文件上传请求正文反序列化失败!"); return err_response("单文件上传请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_file_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FileService_Stub stub(channel.get()); brpc::Controller cntl; stub.PutSingleFile(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 文件存储子服务调用失败!", req.request_id()); return err_response("文件存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void PutMultiFile(const httplib::Request &request, httplib::Response &response) { PutMultiFileReq req; PutMultiFileRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("批量文件上传请求正文反序列化失败!"); return err_response("批量文件上传请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_file_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::FileService_Stub stub(channel.get()); brpc::Controller cntl; stub.PutMultiFile(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 文件存储子服务调用失败!", req.request_id()); return err_response("文件存储子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void SpeechRecognition(const httplib::Request &request, httplib::Response &response) { LOG_DEBUG("收到语音转文字请求!"); SpeechRecognitionReq req; SpeechRecognitionRsp rsp; auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("语音识别请求正文反序列化失败!"); return err_response("语音识别请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_speech_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::SpeechService_Stub stub(channel.get()); brpc::Controller cntl; stub.SpeechRecognition(&cntl, &req, &rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 语音识别子服务调用失败!", req.request_id()); return err_response("语音识别子服务调用失败!"); } // 5. 向客户端进行响应 response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } void NewMessage(const httplib::Request &request, httplib::Response &response) { NewMessageReq req; NewMessageRsp rsp;//这是给客户端的响应 GetTransmitTargetRsp target_rsp;//这是请求子服务的响应 auto err_response = [&req, &rsp, &response](const std::string &errmsg) -> void { rsp.set_success(false); rsp.set_errmsg(errmsg); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); }; bool ret = req.ParseFromString(request.body); if (ret == false) { LOG_ERROR("新消息请求正文反序列化失败!"); return err_response("新消息请求正文反序列化失败!"); } // 2. 客户端身份识别与鉴权 std::string ssid = req.session_id(); auto uid = _redis_session->uid(ssid); if (!uid) { LOG_ERROR("{} 获取登录会话关联用户信息失败!", ssid); return err_response("获取登录会话关联用户信息失败!"); } req.set_user_id(*uid); // 3. 将请求转发给好友子服务进行业务处理 auto channel = _mm_channels->choose(_transmite_service_name); if (!channel) { LOG_ERROR("{} 未找到可提供业务处理的用户子服务节点!", req.request_id()); return err_response("未找到可提供业务处理的用户子服务节点!"); } bite_im::MsgTransmitService_Stub stub(channel.get()); brpc::Controller cntl; stub.GetTransmitTarget(&cntl, &req, &target_rsp, nullptr); if (cntl.Failed()) { LOG_ERROR("{} 消息转发子服务调用失败!", req.request_id()); return err_response("消息转发子服务调用失败!"); } // 4. 若业务处理成功 --- 且获取被申请方长连接成功,则向被申请放进行好友申请事件通知 if (target_rsp.success()){ for (int i = 0; i < target_rsp.target_id_list_size(); i++) { std::string notify_uid = target_rsp.target_id_list(i); if (notify_uid == *uid) continue; //不通知自己 auto conn = _connections->connection(notify_uid); if (!conn) { continue;} NotifyMessage notify; notify.set_notify_type(NotifyType::CHAT_MESSAGE_NOTIFY); auto msg_info = notify.mutable_new_message_info(); msg_info->mutable_message_info()->CopyFrom(target_rsp.message()); conn->send(notify.SerializeAsString(), websocketpp::frame::opcode::value::binary); } } // 5. 向客户端进行响应 rsp.set_request_id(req.request_id()); rsp.set_success(target_rsp.success()); rsp.set_errmsg(target_rsp.errmsg()); response.set_content(rsp.SerializeAsString(), "application/x-protbuf"); } private: Session::ptr _redis_session; Status::ptr _redis_status; std::string _user_service_name; std::string _file_service_name; std::string _speech_service_name; std::string _message_service_name; std::string _transmite_service_name; std::string _friend_service_name; ServiceManager::ptr _mm_channels; Discovery::ptr _service_discoverer; Connection::ptr _connections; server_t _ws_server; httplib::Server _http_server; std::thread _http_thread; }; class GatewayServerBuilder { public: //构造redis客户端对象 void make_redis_object(const std::string &host, int port, int db, bool keep_alive) { _redis_client = RedisClientFactory::create(host, port, db, keep_alive); } //用于构造服务发现客户端&信道管理对象 void make_discovery_object(const std::string ®_host, const std::string &base_service_name, const std::string &file_service_name, const std::string &speech_service_name, const std::string &message_service_name, const std::string &friend_service_name, const std::string &user_service_name, const std::string &transmite_service_name) { _file_service_name = file_service_name; _speech_service_name = speech_service_name; _message_service_name = message_service_name; _friend_service_name = friend_service_name; _user_service_name = user_service_name; _transmite_service_name = transmite_service_name; _mm_channels = std::make_shared(); _mm_channels->declared(file_service_name); _mm_channels->declared(speech_service_name); _mm_channels->declared(message_service_name); _mm_channels->declared(friend_service_name); _mm_channels->declared(user_service_name); _mm_channels->declared(transmite_service_name); auto put_cb = std::bind(&ServiceManager::onServiceOnline, _mm_channels.get(), std::placeholders::_1, std::placeholders::_2); auto del_cb = std::bind(&ServiceManager::onServiceOffline, _mm_channels.get(), std::placeholders::_1, std::placeholders::_2); _service_discoverer = std::make_shared(reg_host, base_service_name, put_cb, del_cb); } void make_server_object(int websocket_port, int http_port) { _websocket_port = websocket_port; _http_port = http_port; } //构造RPC服务器对象 GatewayServer::ptr build() { if (!_redis_client) { LOG_ERROR("还未初始化Redis客户端模块!"); abort(); } if (!_service_discoverer) { LOG_ERROR("还未初始化服务发现模块!"); abort(); } if (!_mm_channels) { LOG_ERROR("还未初始化信道管理模块!"); abort(); } GatewayServer::ptr server = std::make_shared( _websocket_port, _http_port, _redis_client, _mm_channels, _service_discoverer, _user_service_name, _file_service_name, _speech_service_name, _message_service_name, _transmite_service_name, _friend_service_name); return server; } private: int _websocket_port; int _http_port; std::shared_ptr _redis_client; std::string _file_service_name; std::string _speech_service_name; std::string _message_service_name; std::string _friend_service_name; std::string _user_service_name; std::string _transmite_service_name; ServiceManager::ptr _mm_channels; Discovery::ptr _service_discoverer; }; }