Files
my-chat_-server/gateway/source/gateway_server.hpp
2025-10-13 18:34:48 +08:00

1421 lines
85 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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>;
GatewayServer(
int websocket_port,
int http_port,
const std::shared_ptr<sw::redis::Redis> &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<Session>(redis_client)),
_redis_status(std::make_shared<Status>(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<Connection>()){
_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<GetUserInfoRsp> _GetUserInfo(const std::string &rid, const std::string &uid) {
GetUserInfoReq req;
auto rsp = std::make_shared<GetUserInfoRsp>();
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<GetUserInfoRsp>();
}
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<GetUserInfoRsp>();
}
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 &reg_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<ServiceManager>();
_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<Discovery>(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<GatewayServer>(
_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<sw::redis::Redis> _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;
};
}