From 68cd53a80cd5a62d9c7c961b4279fb9df62bee37 Mon Sep 17 00:00:00 2001 From: xyz <2050965275@qq.com> Date: Tue, 10 Jun 2025 20:17:39 +0800 Subject: [PATCH] add http and websocket --- CMakeLists.txt | 40 ++--- README.md | 14 +- SelfInfoWidget.cpp | 2 +- debug.h | 4 +- main.cpp | 23 ++- mainwidget.cpp | 8 + mainwidget.h | 3 +- model/data.h | 8 + model/datacenter.cpp | 143 +++++++++++++++++- model/datacenter.h | 74 +++++++-- network/netclient.cpp | 121 +++++++++++++++ network/netclient.h | 59 ++++++++ proto/base.proto | 40 +++-- proto/file.proto | 17 ++- proto/friend.proto | 26 ++-- proto/gateway.proto | 34 ++++- .../{message.proto => message_storage.proto} | 7 + proto/message_transmit.proto | 39 +++++ proto/notify.proto | 43 ++++++ proto/speech.proto | 23 --- proto/speech_recognition.proto | 28 ++++ proto/transmite.proto | 32 ---- proto/user.proto | 33 ++-- 23 files changed, 650 insertions(+), 171 deletions(-) create mode 100644 network/netclient.cpp create mode 100644 network/netclient.h rename proto/{message.proto => message_storage.proto} (77%) create mode 100644 proto/message_transmit.proto create mode 100644 proto/notify.proto delete mode 100644 proto/speech.proto create mode 100644 proto/speech_recognition.proto delete mode 100644 proto/transmite.proto diff --git a/CMakeLists.txt b/CMakeLists.txt index c2622d2..7683d68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,20 +9,27 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# set(CMAKE_PREFIX_PATH C:/src/vcpkg/installed/x64-windows) -# 查找Qt版本 -find_package(Qt6 COMPONENTS Protobuf Widgets QUIET) +# 查找模块 +find_package(Qt6 COMPONENTS +Protobuf +Widgets +Network +WebSockets +QUIET) + set(QT_VERSION_MAJOR 6) - - +# proto文件 file(GLOB PB_FILES proto/*.proto ) -file(GLOB_RECURSE PROJECT_SOURCES - *.cpp - *.h + +# 源文件 +file(GLOB PROJECT_SOURCES + model/*.h model/*.cpp + network/*.h network/*.cpp + *.h *.cpp *.ui *.qrc ) @@ -48,14 +55,9 @@ else() endif() endif() -target_link_libraries(ClientChat PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) - -if(${QT_VERSION_MAJOR} EQUAL 6) - qt_finalize_executable(ClientChat) -endif() - -include(GNUInstallDirs) -install(TARGETS ClientChat - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} -) +# 链接动态库 +target_link_libraries(ClientChat PRIVATE +Qt${QT_VERSION_MAJOR}::Widgets +Qt6::Network +Qt6::WebSockets +) \ No newline at end of file diff --git a/README.md b/README.md index 009c149..b41494e 100644 --- a/README.md +++ b/README.md @@ -4,32 +4,20 @@ Microservices instant messaging platform. #### 软件架构 -软件架构说明 #### 安装教程 1. Win + R 输入cmd打开终端 2. cmake -B build && cd build -3. make && make install +3. cmake build . #### 使用说明 -Freedom to explore. #### 参与贡献 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request #### 特技 -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/SelfInfoWidget.cpp b/SelfInfoWidget.cpp index 76ed7ff..d456a86 100644 --- a/SelfInfoWidget.cpp +++ b/SelfInfoWidget.cpp @@ -1,4 +1,4 @@ -#include "SelfInfoWidget.h" +#include "selfinfowidget.h" SelfInfoWidget::SelfInfoWidget(QWidget *parent) : QDialog(parent) diff --git a/debug.h b/debug.h index a80b297..7023aad 100644 --- a/debug.h +++ b/debug.h @@ -1,10 +1,12 @@ #ifndef DEBUG_H #define DEBUG_H -#define TEST_UI 0 +#define TEST_UI 1 #define TEST_SKIP_LOGIN 1 +#define TEST_NETWORK 1 + #define TEST_GROUP_SESSION_DETAIL 1 #endif // DEBUG_H diff --git a/main.cpp b/main.cpp index c5525d9..a0f5740 100644 --- a/main.cpp +++ b/main.cpp @@ -4,6 +4,7 @@ #include "model/data.h" #include "loginwidget.h" +#include "model/datacenter.h" int main(int argc, char *argv[]) { @@ -11,12 +12,30 @@ int main(int argc, char *argv[]) qputenv("QT_QPA_PLATFORM", "windows:darkmode=0"); + LOG() << "Hello"; + + //测试代码 + //DataCenter* dataCenter = model::DataCenter::getInstance(); + //dataCenter->initDataFile(); + //dataCenter->saveDataFile(); + +#if TEST_NETWORK + //开始执行network + LOG() << "start network"; + /*network::NetClient netClient(nullptr); + netClient.ping();*/ + + model::DataCenter* dataCenter = model::DataCenter::getInstance(); + dataCenter->ping(); +#endif + #if TEST_SKIP_LOGIN QPalette palette; palette.setColor(QPalette::WindowText, Qt::black);// 窗口文字颜色 QApplication::setPalette(palette); + //mychat的主窗口 MainWidget* w = MainWidget::getInstance(); w->show(); #else @@ -24,9 +43,5 @@ int main(int argc, char *argv[]) loginWidget->show(); #endif - LOG() << "Hello"; - - /*MainWidget* w = MainWidget::getInstance(); - w->show();*/ return a.exec(); } diff --git a/mainwidget.cpp b/mainwidget.cpp index f9778cd..102579f 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -219,6 +219,8 @@ void MainWidget::initRightWindow() void MainWidget::initSignalSlot() { + model::DataCenter* dataCenter = model::DataCenter::getInstance(); + ///////////////////////////////////// //连接信号槽,处理标签页切换 ///////////////////////////////////// @@ -278,6 +280,12 @@ void MainWidget::initSignalSlot() searchEdit->setText(""); addFriendDialog->exec(); }); + + ///////////////////////////////////// + // 获取个人的信息 + ///////////////////////////////////// + + //dataCenter } void MainWidget::switchTabToSession() diff --git a/mainwidget.h b/mainwidget.h index fc80017..be0821a 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -9,10 +9,11 @@ #include "debug.h" #include "messageeditarea.h" #include "messageshowarea.h" -#include "SelfInfoWidget.h" +#include "selfinfowidget.h" #include "sessionfriendarea.h" #include "groupsessiondetailwidget.h" #include "addfrienddialog.h" +#include "model/datacenter.h" QT_BEGIN_NAMESPACE namespace Ui { diff --git a/model/data.h b/model/data.h index 34d3fb0..27e1f50 100644 --- a/model/data.h +++ b/model/data.h @@ -9,6 +9,14 @@ #include #include "base.qpb.h" +#include "gateway.qpb.h" +#include "user.qpb.h" +#include "friend.qpb.h" +#include "file.qpb.h" +#include "notify.qpb.h" +#include "speech_recognition.qpb.h" +#include "message_storage.qpb.h" +#include "message_transmit.qpb.h" // 创建命名空间 namespace model { diff --git a/model/datacenter.cpp b/model/datacenter.cpp index 5c0a082..0831629 100644 --- a/model/datacenter.cpp +++ b/model/datacenter.cpp @@ -1,4 +1,4 @@ -#include "datacenter.h" +#include "datacenter.h" namespace model { @@ -9,11 +9,144 @@ namespace model if (instance == nullptr) { instance = new DataCenter(); } - return nullptr; + return instance; } - DataCenter::DataCenter() + DataCenter::~DataCenter() { - + //释放所有的成员 + //此处就不必判断nullptr,直接delete即可 + //c++标准中明确规定了,对nullptr进行delete是合法行为,不会有任何副作用 + delete myself; + delete friendList; + delete chatSessionList; + delete memberList; + delete applyList; + delete recentMessages; + delete unreadMessageCount; + delete searchUserResult; + delete searchMessageResult; } -} + + DataCenter::DataCenter() : netClient(this) + { + //此处只是把这几个hash类型的属性进行new出实例,其他的QList都暂时不实例化 + //主要是为了使用nullptr表示非法状态 + //对于hash来说,不关心整个的QHash是否是nullptr,而是关心某个key对应的value是否存在 + //通过key是否存在,也能表示该值是否有效 + recentMessages = new QHash>(); + memberList = new QHash>(); + unreadMessageCount = new QHash(); + + //加载数据 + loadDataFile(); + } + + void DataCenter::initDataFile() + { + //构造出文件的路径,使用appData存储文件 + QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + QString filePath = basePath + "/ChatClient.json"; + + QDir dir; + if (!dir.exists(basePath)) { + //没有则进行目录的创建 + dir.mkpath(basePath); + } + + //构造好文件的路径之后,把文件创建出来 + //写的方式打开,并且写入初始内容 + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + LOG() << "initDataFile open file failed!!!" << file.errorString(); + file.close(); + return; + } + //打开成功,写入初始内容 + QString data = "{\n\n}"; + file.write(data.toUtf8()); + file.close(); + } + + void DataCenter::saveDataFile() + { + QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + QString filePath = basePath + "/ChatClient.json"; + + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + LOG() << "saveDataFile open file failed!!!" << file.errorString(); + file.close(); + return; + } + + //按照json格式进行数据的写入 + //这个对象可以当作map一样来使用 + QJsonObject jsonObj; + jsonObj["loginSessionId"] = loginSessionId; + + QJsonObject jsonUnread; + for (auto it = unreadMessageCount->begin(); it != unreadMessageCount->end(); ++it) { + //注意此处的qt迭代器使用和stl有区别(不是使用first和second) + jsonUnread[it.key()] = it.value(); + } + jsonObj["unread"] = jsonUnread; + + //把json写入文件 + QJsonDocument jsonDoc(jsonObj); + QString s = jsonDoc.toJson(); + file.write(s.toUtf8()); + + //关闭文件 + file.close(); + } + + //加载文件,在DataCenter实例化就应该执行的 + void DataCenter::loadDataFile() + { + //确保加载之前就针对文件进行初始化操作 + QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + QString filePath = basePath + "/ChatClient.json"; + + //判定文件是否存在,不存在则初始化,并创建出空空白的json文件 + QFileInfo fileInfo(filePath); + if (!fileInfo.exists()) { + initDataFile(); + } + + //按读方式打开文件 + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + LOG() << "loadDataFile open file failed!!!" << file.errorString(); + return; + } + + //读取文件内容,解析为 JSON对象 + QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll()); + if (jsonDoc.isNull()) { + LOG() << "loadDataFile parsing the json file failed!!!"; + file.close(); + return; + } + + QJsonObject jsonObj = jsonDoc.object(); + this->loginSessionId = jsonObj["loginSessionId"].toString(); + + + this->unreadMessageCount->clear(); + QJsonObject jsonUnread = jsonObj["unread"].toObject(); + for (auto it = jsonUnread.begin(); it != jsonUnread.end(); ++it) { + this->unreadMessageCount->insert(it.key(), it.value().toInt()); + } + + file.close(); + } + + void DataCenter::getMyselfAsync() + { + //DataCenter 只是负责“处理数据”, + //而真正负责网络进行通信,需要通过NetClient + netClient.getMyself(loginSessionId); + } + +} //end namespace model diff --git a/model/datacenter.h b/model/datacenter.h index f7434c9..6e0a774 100644 --- a/model/datacenter.h +++ b/model/datacenter.h @@ -1,8 +1,12 @@ -#pragma once +#pragma once #include +#include +#include +#include #include "data.h" +#include "../network/netclient.h" namespace model { @@ -13,12 +17,13 @@ namespace model public: static DataCenter* getInstance(); + ~DataCenter(); /// - /// ĺ͡ + /// 计算两个整数的和。 /// - /// һ - /// ڶ - /// a + b Ľ + /// 第一个加数 + /// 第二个加数 + /// 返回 a + b 的结果 /*int add(int a, int b) { return a + b; }*/ @@ -28,29 +33,70 @@ namespace model static DataCenter* instance; - //гDataCenterҪ֯ + //列出DataCenter中要组织管理的所有数据 - //ǰͻ˵¼Ӧĵ¼ỰId + //当前客户端登录到服务器对应的登录会话Id QString loginSessionId; - //ǰûϢ + //当前的用户信息 UserInfo* myself = nullptr; - //б - QList* firendList = nullptr; + //好友列表 + QList* friendList = nullptr; - //Ựб + //会话列表 QList* chatSessionList = nullptr; - //¼ǰѡеĻỰĸ + //记录当前选中的会话是哪个 QString currentChatSession = ""; - //¼ÿỰУЩԱ + //记录每个会话中,都有哪些成员 QHash>* memberList = nullptr;//unordered_map - //ĺб + //待处理的好友申请列表 QList* applyList = nullptr; + //每个会话最近消息的列表,key为chatSessionId,value为消息列表 + QHash>* recentMessages = nullptr; + + //存储每个会话,表示未读消息的数量 + QHash* unreadMessageCount = nullptr; + + // 用户的好友搜索结果 + QList* searchUserResult = nullptr; + + //保存一个历史消息搜索结果 + QList* searchMessageResult = nullptr; + + //短信(邮箱)验证码的验证Id + QString currentVerifyCodeId = ""; + + //让dataCenter持有Netclient实例 + network::NetClient netClient; + + public: + /// + /// 初始化数据文件 + /// + void initDataFile(); + + //存储数据到文件中 + void saveDataFile(); + + //从数据文件中加载数据到内存 + void loadDataFile(); + + //获取到当前的登录会话Id + const QString& getLoginSessionId() const{ + return loginSessionId; + } + + //验证网络的连通性 + void ping() { netClient.ping(); } + + //通过网络获取到用户的个人信息 + void getMyselfAsync(); + signals: }; } //end namespace model diff --git a/network/netclient.cpp b/network/netclient.cpp new file mode 100644 index 0000000..6f70e69 --- /dev/null +++ b/network/netclient.cpp @@ -0,0 +1,121 @@ +#include "netclient.h" +#include "../model/datacenter.h" +using namespace model; + +namespace network { + NetClient::NetClient(model::DataCenter* dataCenter) + :dataCenter(dataCenter) + { + initWebSocket(); + } + + void NetClient::ping() + { + QNetworkRequest httpReq; + httpReq.setUrl(QUrl(HTTP_URL + "/ping")); + + QNetworkReply* httpResp = httpClient.get(httpReq); + connect(httpResp, &QNetworkReply::finished, this, [=]() { + //到这里面,说明响应已经回了 + if (httpResp->error() != QNetworkReply::NoError) { + //请求失败 + LOG() << "HTTP请求失败!!!" << httpResp->errorString(); + httpResp->deleteLater(); + return; + } + //获取到响应的body + QByteArray body = httpResp->readAll(); + LOG() << "响应的内容: " << body; + httpResp->deleteLater(); + }); + } + + void NetClient::initWebSocket() + { + //准备好所需要的信号槽 + connect(&websocketClient, &QWebSocket::connected, this, [=]() { + LOG() << "webSocket 连接成功"; + //连接成功之后,进行发送身份认证 + sendAuth(); + }); + + connect(&websocketClient, &QWebSocket::disconnected, this, [=]() { + LOG() << "webSocket 连接断开"; + }); + + connect(&websocketClient, &QWebSocket::textMessageReceived, this, [=](const QString& message) { + LOG() << "webSocket 收到文本消息 " << message; + }); + + connect(&websocketClient, &QWebSocket::binaryMessageReceived, this, [=](const QByteArray& byteArray) { + LOG() << "webSocket 收到二进制的消息" << byteArray.length(); + //TODO + }); + + //和服务器真正建立连接 + websocketClient.open(WEBSOCKET_URL); + } + + void NetClient::sendAuth() + { + bite_im::ClientAuthenticationReq req; + req.setRequestId(makeRequestId()); + req.setSessionId(dataCenter->getLoginSessionId()); + QByteArray body = req.serialize(&serializer); + websocketClient.sendBinaryMessage(body); + LOG() << "[WS身份认证] requestId= " << req.requestId() << ",loginSessionId= " << req.sessionId(); + + } + + QString NetClient::makeRequestId() + { + //基本的要求,确保每个请求的Id都是不重复的(唯一的) + //通过UUID实现上述的效果 + return "R" + QUuid::createUuid().toString().sliced(25, 12); + } + + //在这个函数内部,完成具体的网络通信即可 + void NetClient::getMyself(const QString& loginSessionId) + { + //构造出HTTP请求body部分 + bite_im::GetUserInfoReq req; + req.setRequestId(makeRequestId()); + req.setSessionId(loginSessionId); + QByteArray body = req.serialize(&serializer); + LOG() << "获取个人信息: requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId; + + //构造出HTTP请求 + QNetworkRequest httpReq; + httpReq.setUrl(QUrl(HTTP_URL + "/service/user/get_user_info")); + httpReq.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf"); + + //发起HTTP请求 + QNetworkReply* httpResp = httpClient.post(httpReq, body); + + //通过信号槽,获取到当前的响应 + connect(httpResp, &QNetworkReply::finished, this, [=]() { + if (httpResp->error() != QNetworkReply::NoError) { + //说明HTTP请求出错了, + LOG() << "HTTP error: " << httpResp->errorString(); + httpResp->deleteLater(); + return; + } + //说明拿到了body + QByteArray respBody = httpResp->readAll(); + + //针对body进行反序列化,解析成对象 + bite_im::GetUserInfoRsp respObj; + respObj.deserialize(&serializer, respBody); + + //判定一下业务上是否出错 + if (!respObj.success()) { + LOG() << "requestId= " << respObj.requestId() << ", errmsg=" << respObj.errmsg(); + httpResp->deleteLater(); + return; + } + + //继续处理后续的业务逻辑 + + }); + } +} //end namespace network \ No newline at end of file diff --git a/network/netclient.h b/network/netclient.h new file mode 100644 index 0000000..d05bac1 --- /dev/null +++ b/network/netclient.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "../model/data.h" + +//此处为了避免“循环包含”的问题,就需要使用前置声明的方法 +// 代替包含头文件 +namespace model { + class DataCenter; +} //end namespace model + +class model::DataCenter; + +namespace network { + class NetClient : public QObject + { + Q_OBJECT + + private: + //定义重要的常量,ip暂时使用本地的回环ip,端口号暂定的8000和8001 + const QString HTTP_URL = "http://127.0.0.1:8000"; + const QString WEBSOCKET_URL = "ws://127.0.0.1:8001/ws"; + + public: + NetClient(model::DataCenter* dataCenter); + + //验证网络的联通性 + void ping(); + + //初始化websocket + void initWebSocket(); + + //发送身份认证请求 + void sendAuth(); + + //生成请求的Id + static QString makeRequestId(); + + void getMyself(const QString& loginSessionId); + private: + model::DataCenter* dataCenter; + + //http客户端 + QNetworkAccessManager httpClient; + + //websocket客户端 + QWebSocket websocketClient; + + //序列化器 + QProtobufSerializer serializer; + signals: + }; +} //end namespace network diff --git a/proto/base.proto b/proto/base.proto index 79f9b1d..37579d8 100644 --- a/proto/base.proto +++ b/proto/base.proto @@ -1,5 +1,6 @@ syntax = "proto3"; package bite_im; + option cc_generic_services = true; //用户信息结构 @@ -13,14 +14,11 @@ message UserInfo { //聊天会话信息 message ChatSessionInfo { - //群聊会话不需要设置,单聊会话设置为对方用户ID - optional string single_chat_friend_id = 1; + optional string single_chat_friend_id = 1;//群聊会话不需要设置,单聊会话设置为对方ID string chat_session_id = 2; //会话ID string chat_session_name = 3;//会话名称git - //会话上一条消息,新建的会话没有最新消息 - optional MessageInfo prev_message = 4; - //会话头像 --群聊会话不需要,直接由前端固定渲染,单聊就是对方的头像 - optional bytes avatar = 5; + optional MessageInfo prev_message = 4;//会话上一条消息,新建的会话没有最新消息 + optional bytes avatar = 5;//会话头像 --群聊会话不需要,直接由前端固定渲染,单聊就是对方的头像 } //消息类型 @@ -34,23 +32,18 @@ message StringMessageInfo { string content = 1;//文字聊天内容 } message ImageMessageInfo { - //图片文件id,客户端发送的时候不用设置,由transmit服务器进行设置后交给storage的时候设置 - optional string file_id = 1; - //图片数据,在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候需要原样转发 - optional bytes image_content = 2; + optional string file_id = 1;//图片文件id,客户端发送的时候不用设置,由transmit服务器进行设置后交给storage的时候设置 + optional bytes image_content = 2;//图片数据,在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候需要原样转发 } message FileMessageInfo { optional string file_id = 1;//文件id,客户端发送的时候不用设置 - optional int64 file_size = 2;//文件大小 - optional string file_name = 3;//文件名称 - //文件数据,在ES中存储消息的时候只要id和元信息,不要文件数据, 服务端转发的时候也不需要填充 - optional bytes file_contents = 4; + int64 file_size = 2;//文件大小 + string file_name = 3;//文件名称 + optional bytes file_contents = 4;//文件数据,在ES中存储消息的时候只要id和元信息,不要文件数据, 服务端转发的时候也不需要填充 } message SpeechMessageInfo { - //语音文件id,客户端发送的时候不用设置 - optional string file_id = 1; - //文件数据,在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候也不需要填充 - optional bytes file_contents = 2; + optional string file_id = 1;//语音文件id,客户端发送的时候不用设置 + optional bytes file_contents = 2;//文件数据,在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候也不需要填充 } message MessageContent { MessageType message_type = 1; //消息类型 @@ -70,13 +63,18 @@ message MessageInfo { MessageContent message = 5; } +message Message { + string request_id = 1; + MessageInfo message = 2; +} + message FileDownloadData { string file_id = 1; bytes file_content = 2; } message FileUploadData { - string file_name = 1; //文件名称 - int64 file_size = 2; //文件大小 - bytes file_content = 3; //文件数据 + string file_name = 1; + int64 file_size = 2; + bytes file_content = 3; } \ No newline at end of file diff --git a/proto/file.proto b/proto/file.proto index 1a9a33d..8a74476 100644 --- a/proto/file.proto +++ b/proto/file.proto @@ -1,9 +1,16 @@ +/* + 文件操作服务器的子服务注册信息: /service/file/instance_id + 服务名称:/service/file + 实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID + 当服务发现的时候,通过 /service/file 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了 +*/ syntax = "proto3"; package bite_im; import "base.proto"; option cc_generic_services = true; + message GetSingleFileReq { string request_id = 1; string file_id = 2; @@ -14,7 +21,7 @@ message GetSingleFileRsp { string request_id = 1; bool success = 2; string errmsg = 3; - optional FileDownloadData file_data = 4; + FileDownloadData file_data = 4; } message GetMultiFileReq { @@ -27,11 +34,11 @@ message GetMultiFileRsp { string request_id = 1; bool success = 2; string errmsg = 3; - map file_data = 4;//文件ID与文件数据的映射map + repeated FileDownloadData file_data = 4; } message PutSingleFileReq { - string request_id = 1; //请求ID,作为处理流程唯一标识 + string request_id = 1; optional string user_id = 2; optional string session_id = 3; FileUploadData file_data = 4; @@ -40,7 +47,7 @@ message PutSingleFileRsp { string request_id = 1; bool success = 2; string errmsg = 3; - FileMessageInfo file_info = 4; //返回了文件组织的元信息 + FileMessageInfo file_info = 4; } message PutMultiFileReq { @@ -61,4 +68,4 @@ service FileService { rpc GetMultiFile(GetMultiFileReq) returns (GetMultiFileRsp); rpc PutSingleFile(PutSingleFileReq) returns (PutSingleFileRsp); rpc PutMultiFile(PutMultiFileReq) returns (PutMultiFileRsp); -} \ No newline at end of file +} diff --git a/proto/friend.proto b/proto/friend.proto index edd3309..d28c237 100644 --- a/proto/friend.proto +++ b/proto/friend.proto @@ -1,30 +1,37 @@ +/* + 好友操作服务器的子服务注册信息: /service/friend/instance_id + 服务名称:/service/friend + 实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID + 当服务发现的时候,通过 /service/friend 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了 +*/ syntax = "proto3"; package bite_im; import "base.proto"; option cc_generic_services = true; + //-------------------------------------- //好友列表获取 message GetFriendListReq { - string request_id = 1; // 请求标识ID - optional string user_id = 2; // 当前请求的发起者用户ID - optional string session_id = 3; //登录会话ID--用于网关进行身份识别--其他子服务用不到 + string request_id = 1; + optional string user_id = 2; + optional string session_id = 3; } message GetFriendListRsp { string request_id = 1; bool success = 2; string errmsg = 3; - repeated UserInfo friend_list = 4; //要返回的用户信息 + repeated UserInfo friend_list = 4; } //-------------------------------------- //好友删除 message FriendRemoveReq { string request_id = 1; - optional string user_id = 2; //当前用户ID + optional string user_id = 2; optional string session_id = 3; - string peer_id = 4; //要删除的好友ID + string peer_id = 4; } message FriendRemoveRsp { string request_id = 1; @@ -53,15 +60,14 @@ message FriendAddProcessReq { bool agree = 3;//是否同意好友申请 string apply_user_id = 4; //申请人的用户id optional string session_id = 5; - optional string user_id = 6; // 被申请人 + optional string user_id = 6; } // +++++++++++++++++++++++++++++++++ message FriendAddProcessRsp { string request_id = 1; bool success = 2; string errmsg = 3; - // 同意后会创建会话,向网关返回会话信息,用于通知双方会话的建立,这个字段客户端不需要关注 - optional string new_session_id = 4; + optional string new_session_id = 4; // 同意后会创建会话,向网关返回会话信息,用于通知双方会话的建立,这个字段客户端不需要关注 } //-------------------------------------- //获取待处理的,申请自己好友的信息列表 @@ -72,7 +78,7 @@ message GetPendingFriendEventListReq { } message FriendEvent { - optional string event_id = 1; + string event_id = 1; UserInfo sender = 3; } message GetPendingFriendEventListRsp { diff --git a/proto/gateway.proto b/proto/gateway.proto index 4fa312f..1074e15 100644 --- a/proto/gateway.proto +++ b/proto/gateway.proto @@ -1,11 +1,39 @@ syntax = "proto3"; package bite_im; option cc_generic_services = true; - +/* + 消息推送使用websocket长连接进行 + websocket长连接转换请求:ws://host:ip/ws + 长连建立以后,需要客户端给服务器发送一个身份验证信息 +*/ message ClientAuthenticationReq { string request_id = 1; - string session_id = 2; // 用于向服务器表明当前长连接客户端的身份 + string session_id = 2; } +message ClientAuthenticationRsp { + string request_id = 1; + bool success = 2; + string errmsg = 3; +} + +//通信接口统一采用POST请求实现,正文采用protobuf协议进行组织 +/* + HTTP HEADER: + POST /service/xxxxx + Content-Type: application/x-protobuf + Content-Length: 123 + + xxxxxx + + ------------------------------------------------------- + + HTTP/1.1 200 OK + Content-Type: application/x-protobuf + Content-Length: 123 + + xxxxxxxxxx +*/ + //在客户端与网关服务器的通信中,使用HTTP协议进行通信 // 通信时采用POST请求作为请求方法 @@ -50,4 +78,4 @@ message ClientAuthenticationReq { 语音转文字 /service/speech/recognition } -*/ \ No newline at end of file +*/ diff --git a/proto/message.proto b/proto/message_storage.proto similarity index 77% rename from proto/message.proto rename to proto/message_storage.proto index 4d13a7d..121086e 100644 --- a/proto/message.proto +++ b/proto/message_storage.proto @@ -1,3 +1,9 @@ +/* + 消息存储服务器的子服务注册信息: /service/message_storage/instance_id + 服务名称:/service/message_storage + 实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID + 当服务发现的时候,通过 /service/message_storage 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了 +*/ syntax = "proto3"; package bite_im; import "base.proto"; @@ -52,4 +58,5 @@ service MsgStorageService { rpc GetHistoryMsg(GetHistoryMsgReq) returns (GetHistoryMsgRsp); rpc GetRecentMsg(GetRecentMsgReq) returns (GetRecentMsgRsp); rpc MsgSearch(MsgSearchReq) returns (MsgSearchRsp); + } \ No newline at end of file diff --git a/proto/message_transmit.proto b/proto/message_transmit.proto new file mode 100644 index 0000000..2762058 --- /dev/null +++ b/proto/message_transmit.proto @@ -0,0 +1,39 @@ +/* + 消息转发服务器的子服务注册信息: /service/message_transmit/instance_id + 服务名称:/service/message_transmit + 实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID + 当服务发现的时候,通过 /service/message_transmit 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了 +*/ +//消息转发服务器接口 +syntax = "proto3"; +package bite_im; +import "base.proto"; + +option cc_generic_services = true; + +//这个用于和网关进行通信 +message NewMessageReq { + string request_id = 1; + optional string user_id = 2; + optional string session_id = 3; + string chat_session_id = 4; + MessageContent message = 5; +} +message NewMessageRsp { + string request_id = 1; + bool success = 2; + string errmsg = 3; +} + +//这个用于内部的通信,生成完整的消息信息,并获取消息的转发人员列表 +message GetTransmitTargetRsp { + string request_id = 1; + bool success = 2; + string errmsg = 3; + MessageInfo message = 4; + repeated string target_id_list = 5; +} + +service MsgTransmitService { + rpc GetTransmitTarget(NewMessageReq) returns (GetTransmitTargetRsp); +} \ No newline at end of file diff --git a/proto/notify.proto b/proto/notify.proto new file mode 100644 index 0000000..737aed9 --- /dev/null +++ b/proto/notify.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; +package bite_im; +import "base.proto"; + +option cc_generic_services = true; + +enum NotifyType { + FRIEND_ADD_APPLY_NOTIFY = 0; + FRIEND_ADD_PROCESS_NOTIFY = 1; + CHAT_SESSION_CREATE_NOTIFY = 2; + CHAT_MESSAGE_NOTIFY = 3; + FRIEND_REMOVE_NOTIFY = 4; +} + +message NotifyFriendAddApply { + UserInfo user_info = 1; //申请人信息 +} +message NotifyFriendAddProcess { + bool agree = 1; + UserInfo user_info = 2; //处理人信息 +} +message NotifyFriendRemove { + string user_id = 1; //删除自己的用户ID +} +message NotifyNewChatSession { + ChatSessionInfo chat_session_info = 1; //新建会话信息 +} +message NotifyNewMessage { + MessageInfo message_info = 1; //新消息 +} + + +message NotifyMessage { + optional string notify_event_id = 1;//通知事件操作id(有则填无则忽略) + NotifyType notify_type = 2;//通知事件类型 + oneof notify_remarks { //事件备注信息 + NotifyFriendAddApply friend_add_apply = 3; + NotifyFriendAddProcess friend_process_result = 4; + NotifyFriendRemove friend_remove = 7; + NotifyNewChatSession new_chat_session_info = 5;//会话信息 + NotifyNewMessage new_message_info = 6;//消息信息 + } +} \ No newline at end of file diff --git a/proto/speech.proto b/proto/speech.proto deleted file mode 100644 index df26bbd..0000000 --- a/proto/speech.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; -package bite_im; - -option cc_generic_services = true; - -message SpeechRecognitionReq { - string request_id = 1; //请求ID - bytes speech_content = 2; //语音数据 - optional string user_id = 3; //用户ID - optional string session_id = 4; //登录会话ID -- 网关进行身份鉴权 -} - -message SpeechRecognitionRsp { - string request_id = 1; //请求ID - bool success = 2; //请求处理结果标志 - optional string errmsg = 3; //失败原因 - optional string recognition_result = 4; //识别后的文字数据 -} - -//语音识别Rpc服务及接口的定义 -service SpeechService { - rpc SpeechRecognition(SpeechRecognitionReq) returns (SpeechRecognitionRsp); -} \ No newline at end of file diff --git a/proto/speech_recognition.proto b/proto/speech_recognition.proto new file mode 100644 index 0000000..570ab2a --- /dev/null +++ b/proto/speech_recognition.proto @@ -0,0 +1,28 @@ +/* + 语音识别服务器的子服务注册信息: /service/speech/instance_id + 服务名称:/service/speech + 实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID + 当服务发现的时候,通过 /service/speech 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了 +*/ +syntax = "proto3"; +package bite_im; + +option cc_generic_services = true; + +message SpeechRecognitionReq { + string request_id = 1; + bytes speech_content = 2; + optional string user_id = 3; + optional string session_id = 4; +} + +message SpeechRecognitionRsp { + string request_id = 1; + bool success = 2; + string errmsg = 3; + string recognition_result = 4; +} + +service SpeechService { + rpc SpeechRecognition(SpeechRecognitionReq) returns (SpeechRecognitionRsp); +} \ No newline at end of file diff --git a/proto/transmite.proto b/proto/transmite.proto deleted file mode 100644 index 2546d3b..0000000 --- a/proto/transmite.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; -package bite_im; -import "base.proto"; - -option cc_generic_services = true; - -//这个用于和网关进行通信 -message NewMessageReq { - string request_id = 1; //请求ID -- 全链路唯一标识 - optional string user_id = 2; - optional string session_id = 3;//客户端身份识别信息 -- 这就是消息发送者 - string chat_session_id = 4; //聊天会话ID -- 标识了当前消息属于哪个会话,应该转发给谁 - MessageContent message = 5; // 消息内容--消息类型+内容 -} -message NewMessageRsp { - string request_id = 1; - bool success = 2; - string errmsg = 3; -} - -//这个用于内部的通信,生成完整的消息信息,并获取消息的转发人员列表 -message GetTransmitTargetRsp { - string request_id = 1; - bool success = 2; - string errmsg = 3; - MessageInfo message = 4; // 组织好的消息结构 -- - repeated string target_id_list = 5; //消息的转发目标列表 -} - -service MsgTransmitService { - rpc GetTransmitTarget(NewMessageReq) returns (GetTransmitTargetRsp); -} \ No newline at end of file diff --git a/proto/user.proto b/proto/user.proto index 6a2548a..0ddca3b 100644 --- a/proto/user.proto +++ b/proto/user.proto @@ -1,6 +1,13 @@ +/* + 用户操作服务器的子服务注册信息: /service/user/instance_id + 服务名称:/service/user + 实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID + 当服务发现的时候,通过 /service/user 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了 +*/ syntax = "proto3"; package bite_im; import "base.proto"; + option cc_generic_services = true; //---------------------------- @@ -9,8 +16,8 @@ message UserRegisterReq { string request_id = 1; string nickname = 2; string password = 3; - optional string verify_code_id = 4; //目前客户端实现了本地验证,该字段没用了 - optional string verify_code = 5;//目前客户端实现了本地验证,该字段没用了 + string verify_code_id = 4; + string verify_code = 5; } message UserRegisterRsp { string request_id = 1; @@ -23,8 +30,8 @@ message UserLoginReq { string request_id = 1; string nickname = 2; string password = 3; - optional string verify_code_id = 4; - optional string verify_code = 5; + string verify_code_id = 4; + string verify_code = 5; } message UserLoginRsp { string request_id = 1; @@ -76,8 +83,8 @@ message PhoneLoginRsp { //其他个人/好友信息的获取在好友操作中完成 message GetUserInfoReq { string request_id = 1; - optional string user_id = 2; // 这个字段是网关进行身份鉴权之后填入的字段 - optional string session_id = 3; // 进行客户端身份识别的关键字段 + optional string user_id = 2; + optional string session_id = 3; } message GetUserInfoRsp { string request_id = 1; @@ -85,17 +92,6 @@ message GetUserInfoRsp { string errmsg = 3; UserInfo user_info = 4; } -//内部接口 -message GetMultiUserInfoReq { - string request_id = 1; - repeated string users_id = 2; -} -message GetMultiUserInfoRsp { - string request_id = 1; - bool success = 2; - string errmsg = 3; - map users_info = 4; -} //---------------------------- //用户头像修改 message SetUserAvatarReq { @@ -158,9 +154,8 @@ service UserService { rpc PhoneRegister(PhoneRegisterReq) returns (PhoneRegisterRsp); rpc PhoneLogin(PhoneLoginReq) returns (PhoneLoginRsp); rpc GetUserInfo(GetUserInfoReq) returns (GetUserInfoRsp); - rpc GetMultiUserInfo(GetMultiUserInfoReq) returns (GetMultiUserInfoRsp); rpc SetUserAvatar(SetUserAvatarReq) returns (SetUserAvatarRsp); rpc SetUserNickname(SetUserNicknameReq) returns (SetUserNicknameRsp); rpc SetUserDescription(SetUserDescriptionReq) returns (SetUserDescriptionRsp); rpc SetUserPhoneNumber(SetUserPhoneNumberReq) returns (SetUserPhoneNumberRsp); -} \ No newline at end of file +}