add http and websocket

This commit is contained in:
xyz
2025-06-10 20:17:39 +08:00
parent 030b5d6101
commit 68cd53a80c
23 changed files with 650 additions and 171 deletions

View File

@ -9,20 +9,27 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) 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) set(QT_VERSION_MAJOR 6)
# proto文件
file(GLOB PB_FILES file(GLOB PB_FILES
proto/*.proto proto/*.proto
) )
file(GLOB_RECURSE PROJECT_SOURCES
*.cpp # 源文件
*.h file(GLOB PROJECT_SOURCES
model/*.h model/*.cpp
network/*.h network/*.cpp
*.h *.cpp
*.ui *.ui
*.qrc *.qrc
) )
@ -48,14 +55,9 @@ else()
endif() endif()
endif() endif()
target_link_libraries(ClientChat PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) # 链接动态库
target_link_libraries(ClientChat PRIVATE
if(${QT_VERSION_MAJOR} EQUAL 6) Qt${QT_VERSION_MAJOR}::Widgets
qt_finalize_executable(ClientChat) Qt6::Network
endif() Qt6::WebSockets
include(GNUInstallDirs)
install(TARGETS ClientChat
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
) )

View File

@ -4,32 +4,20 @@
Microservices instant messaging platform. Microservices instant messaging platform.
#### 软件架构 #### 软件架构
软件架构说明
#### 安装教程 #### 安装教程
1. Win + R 输入cmd打开终端 1. Win + R 输入cmd打开终端
2. cmake -B build && cd build 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/)

View File

@ -1,4 +1,4 @@
#include "SelfInfoWidget.h" #include "selfinfowidget.h"
SelfInfoWidget::SelfInfoWidget(QWidget *parent) SelfInfoWidget::SelfInfoWidget(QWidget *parent)
: QDialog(parent) : QDialog(parent)

View File

@ -1,10 +1,12 @@
#ifndef DEBUG_H #ifndef DEBUG_H
#define DEBUG_H #define DEBUG_H
#define TEST_UI 0 #define TEST_UI 1
#define TEST_SKIP_LOGIN 1 #define TEST_SKIP_LOGIN 1
#define TEST_NETWORK 1
#define TEST_GROUP_SESSION_DETAIL 1 #define TEST_GROUP_SESSION_DETAIL 1
#endif // DEBUG_H #endif // DEBUG_H

View File

@ -4,6 +4,7 @@
#include "model/data.h" #include "model/data.h"
#include "loginwidget.h" #include "loginwidget.h"
#include "model/datacenter.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -11,12 +12,30 @@ int main(int argc, char *argv[])
qputenv("QT_QPA_PLATFORM", "windows:darkmode=0"); 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 #if TEST_SKIP_LOGIN
QPalette palette; QPalette palette;
palette.setColor(QPalette::WindowText, Qt::black);// 窗口文字颜色 palette.setColor(QPalette::WindowText, Qt::black);// 窗口文字颜色
QApplication::setPalette(palette); QApplication::setPalette(palette);
//mychat的主窗口
MainWidget* w = MainWidget::getInstance(); MainWidget* w = MainWidget::getInstance();
w->show(); w->show();
#else #else
@ -24,9 +43,5 @@ int main(int argc, char *argv[])
loginWidget->show(); loginWidget->show();
#endif #endif
LOG() << "Hello";
/*MainWidget* w = MainWidget::getInstance();
w->show();*/
return a.exec(); return a.exec();
} }

View File

@ -219,6 +219,8 @@ void MainWidget::initRightWindow()
void MainWidget::initSignalSlot() void MainWidget::initSignalSlot()
{ {
model::DataCenter* dataCenter = model::DataCenter::getInstance();
///////////////////////////////////// /////////////////////////////////////
//连接信号槽,处理标签页切换 //连接信号槽,处理标签页切换
///////////////////////////////////// /////////////////////////////////////
@ -278,6 +280,12 @@ void MainWidget::initSignalSlot()
searchEdit->setText(""); searchEdit->setText("");
addFriendDialog->exec(); addFriendDialog->exec();
}); });
/////////////////////////////////////
// 获取个人的信息
/////////////////////////////////////
//dataCenter
} }
void MainWidget::switchTabToSession() void MainWidget::switchTabToSession()

View File

@ -9,10 +9,11 @@
#include "debug.h" #include "debug.h"
#include "messageeditarea.h" #include "messageeditarea.h"
#include "messageshowarea.h" #include "messageshowarea.h"
#include "SelfInfoWidget.h" #include "selfinfowidget.h"
#include "sessionfriendarea.h" #include "sessionfriendarea.h"
#include "groupsessiondetailwidget.h" #include "groupsessiondetailwidget.h"
#include "addfrienddialog.h" #include "addfrienddialog.h"
#include "model/datacenter.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui {

View File

@ -9,6 +9,14 @@
#include <QUuid> #include <QUuid>
#include "base.qpb.h" #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 { namespace model {

View File

@ -1,4 +1,4 @@
#include "datacenter.h" #include "datacenter.h"
namespace model namespace model
{ {
@ -9,11 +9,144 @@ namespace model
if (instance == nullptr) { if (instance == nullptr) {
instance = new DataCenter(); 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<QString, QList<Message>>();
memberList = new QHash<QString, QList<UserInfo>>();
unreadMessageCount = new QHash<QString, int>();
//加载数据
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

View File

@ -1,8 +1,12 @@
#pragma once #pragma once
#include <QWidget> #include <QWidget>
#include <qstandardpaths.h>
#include <QDir>
#include <QJsonObject>
#include "data.h" #include "data.h"
#include "../network/netclient.h"
namespace model namespace model
{ {
@ -13,12 +17,13 @@ namespace model
public: public:
static DataCenter* getInstance(); static DataCenter* getInstance();
~DataCenter();
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĺ͡<EFBFBD> /// 计算两个整数的和。
/// </summary> /// </summary>
/// <param name="a"><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param> /// <param name="a">第一个加数</param>
/// <param name="b"><EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param> /// <param name="b">第二个加数</param>
/// <returns><EFBFBD><EFBFBD><EFBFBD><EFBFBD> a + b <EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD></returns> /// <returns>返回 a + b 的结果</returns>
/*int add(int a, int b) { /*int add(int a, int b) {
return a + b; return a + b;
}*/ }*/
@ -28,29 +33,70 @@ namespace model
static DataCenter* instance; static DataCenter* instance;
//<EFBFBD>г<EFBFBD>DataCenter<EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>֯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //列出DataCenter中要组织管理的所有数据
//<EFBFBD><EFBFBD>ǰ<EFBFBD>ͻ<EFBFBD><EFBFBD>˵<EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD>ĵ<EFBFBD>¼<EFBFBD>Id //当前客户端登录到服务器对应的登录会话Id
QString loginSessionId; QString loginSessionId;
//<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD>Ϣ //当前的用户信息
UserInfo* myself = nullptr; UserInfo* myself = nullptr;
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD> //好友列表
QList<UserInfo>* firendList = nullptr; QList<UserInfo>* friendList = nullptr;
//<EFBFBD><EFBFBD>б<EFBFBD> //会话列表
QList<ChatSessionInfo>* chatSessionList = nullptr; QList<ChatSessionInfo>* chatSessionList = nullptr;
//<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ǰѡ<EFBFBD>еĻỰ<EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD> //记录当前选中的会话是哪个
QString currentChatSession = ""; QString currentChatSession = "";
//<EFBFBD><EFBFBD>¼ÿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD><EFBFBD>Ա //记录每个会话中,都有哪些成员
QHash<QString, QList<UserInfo>>* memberList = nullptr;//unordered_map QHash<QString, QList<UserInfo>>* memberList = nullptr;//unordered_map
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD> //待处理的好友申请列表
QList<UserInfo>* applyList = nullptr; QList<UserInfo>* applyList = nullptr;
//每个会话最近消息的列表,key为chatSessionIdvalue为消息列表
QHash<QString, QList<Message>>* recentMessages = nullptr;
//存储每个会话,表示未读消息的数量
QHash<QString, int>* unreadMessageCount = nullptr;
// 用户的好友搜索结果
QList<UserInfo>* searchUserResult = nullptr;
//保存一个历史消息搜索结果
QList<Message>* searchMessageResult = nullptr;
//短信邮箱验证码的验证Id
QString currentVerifyCodeId = "";
//让dataCenter持有Netclient实例
network::NetClient netClient;
public:
/// <summary>
/// 初始化数据文件
/// </summary>
void initDataFile();
//存储数据到文件中
void saveDataFile();
//从数据文件中加载数据到内存
void loadDataFile();
//获取到当前的登录会话Id
const QString& getLoginSessionId() const{
return loginSessionId;
}
//验证网络的连通性
void ping() { netClient.ping(); }
//通过网络获取到用户的个人信息
void getMyselfAsync();
signals: signals:
}; };
} //end namespace model } //end namespace model

121
network/netclient.cpp Normal file
View File

@ -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

59
network/netclient.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
#include <QWebSocket>
#include <QProtobufSerializer>
#include <qnetworkreply.h>
#include <QUuid>
#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

View File

@ -1,5 +1,6 @@
syntax = "proto3"; syntax = "proto3";
package bite_im; package bite_im;
option cc_generic_services = true; option cc_generic_services = true;
//用户信息结构 //用户信息结构
@ -13,14 +14,11 @@ message UserInfo {
//聊天会话信息 //聊天会话信息
message ChatSessionInfo { message ChatSessionInfo {
//群聊会话不需要设置,单聊会话设置为对方用户ID optional string single_chat_friend_id = 1;//群聊会话不需要设置单聊会话设置为对方ID
optional string single_chat_friend_id = 1;
string chat_session_id = 2; //会话ID string chat_session_id = 2; //会话ID
string chat_session_name = 3;//会话名称git string chat_session_name = 3;//会话名称git
//会话上一条消息,新建的会话没有最新消息 optional MessageInfo prev_message = 4;//会话上一条消息,新建的会话没有最新消息
optional MessageInfo prev_message = 4; optional bytes avatar = 5;//会话头像 --群聊会话不需要,直接由前端固定渲染,单聊就是对方的头像
//会话头像 --群聊会话不需要,直接由前端固定渲染,单聊就是对方的头像
optional bytes avatar = 5;
} }
//消息类型 //消息类型
@ -34,23 +32,18 @@ message StringMessageInfo {
string content = 1;//文字聊天内容 string content = 1;//文字聊天内容
} }
message ImageMessageInfo { message ImageMessageInfo {
//图片文件id,客户端发送的时候不用设置由transmit服务器进行设置后交给storage的时候设置 optional string file_id = 1;//图片文件id,客户端发送的时候不用设置由transmit服务器进行设置后交给storage的时候设置
optional string file_id = 1; optional bytes image_content = 2;//图片数据在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候需要原样转发
//图片数据在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候需要原样转发
optional bytes image_content = 2;
} }
message FileMessageInfo { message FileMessageInfo {
optional string file_id = 1;//文件id,客户端发送的时候不用设置 optional string file_id = 1;//文件id,客户端发送的时候不用设置
optional int64 file_size = 2;//文件大小 int64 file_size = 2;//文件大小
optional string file_name = 3;//文件名称 string file_name = 3;//文件名称
//文件数据在ES中存储消息的时候只要id和元信息不要文件数据, 服务端转发的时候也不需要填充 optional bytes file_contents = 4;//文件数据在ES中存储消息的时候只要id和元信息不要文件数据, 服务端转发的时候也不需要填充
optional bytes file_contents = 4;
} }
message SpeechMessageInfo { message SpeechMessageInfo {
//语音文件id,客户端发送的时候不用设置 optional string file_id = 1;//语音文件id,客户端发送的时候不用设置
optional string file_id = 1; optional bytes file_contents = 2;//文件数据在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候也不需要填充
//文件数据在ES中存储消息的时候只要id不要文件数据, 服务端转发的时候也不需要填充
optional bytes file_contents = 2;
} }
message MessageContent { message MessageContent {
MessageType message_type = 1; //消息类型 MessageType message_type = 1; //消息类型
@ -70,13 +63,18 @@ message MessageInfo {
MessageContent message = 5; MessageContent message = 5;
} }
message Message {
string request_id = 1;
MessageInfo message = 2;
}
message FileDownloadData { message FileDownloadData {
string file_id = 1; string file_id = 1;
bytes file_content = 2; bytes file_content = 2;
} }
message FileUploadData { message FileUploadData {
string file_name = 1; //文件名称 string file_name = 1;
int64 file_size = 2; //文件大小 int64 file_size = 2;
bytes file_content = 3; //文件数据 bytes file_content = 3;
} }

View File

@ -1,9 +1,16 @@
/*
文件操作服务器的子服务注册信息: /service/file/instance_id
服务名称:/service/file
实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID
当服务发现的时候,通过 /service/file 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了
*/
syntax = "proto3"; syntax = "proto3";
package bite_im; package bite_im;
import "base.proto"; import "base.proto";
option cc_generic_services = true; option cc_generic_services = true;
message GetSingleFileReq { message GetSingleFileReq {
string request_id = 1; string request_id = 1;
string file_id = 2; string file_id = 2;
@ -14,7 +21,7 @@ message GetSingleFileRsp {
string request_id = 1; string request_id = 1;
bool success = 2; bool success = 2;
string errmsg = 3; string errmsg = 3;
optional FileDownloadData file_data = 4; FileDownloadData file_data = 4;
} }
message GetMultiFileReq { message GetMultiFileReq {
@ -27,11 +34,11 @@ message GetMultiFileRsp {
string request_id = 1; string request_id = 1;
bool success = 2; bool success = 2;
string errmsg = 3; string errmsg = 3;
map<string, FileDownloadData> file_data = 4;//文件ID与文件数据的映射map repeated FileDownloadData file_data = 4;
} }
message PutSingleFileReq { message PutSingleFileReq {
string request_id = 1; //请求ID作为处理流程唯一标识 string request_id = 1;
optional string user_id = 2; optional string user_id = 2;
optional string session_id = 3; optional string session_id = 3;
FileUploadData file_data = 4; FileUploadData file_data = 4;
@ -40,7 +47,7 @@ message PutSingleFileRsp {
string request_id = 1; string request_id = 1;
bool success = 2; bool success = 2;
string errmsg = 3; string errmsg = 3;
FileMessageInfo file_info = 4; //返回了文件组织的元信息 FileMessageInfo file_info = 4;
} }
message PutMultiFileReq { message PutMultiFileReq {

View File

@ -1,30 +1,37 @@
/*
好友操作服务器的子服务注册信息: /service/friend/instance_id
服务名称:/service/friend
实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID
当服务发现的时候,通过 /service/friend 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了
*/
syntax = "proto3"; syntax = "proto3";
package bite_im; package bite_im;
import "base.proto"; import "base.proto";
option cc_generic_services = true; option cc_generic_services = true;
//-------------------------------------- //--------------------------------------
//好友列表获取 //好友列表获取
message GetFriendListReq { message GetFriendListReq {
string request_id = 1; // 请求标识ID string request_id = 1;
optional string user_id = 2; // 当前请求的发起者用户ID optional string user_id = 2;
optional string session_id = 3; //登录会话ID--用于网关进行身份识别--其他子服务用不到 optional string session_id = 3;
} }
message GetFriendListRsp { message GetFriendListRsp {
string request_id = 1; string request_id = 1;
bool success = 2; bool success = 2;
string errmsg = 3; string errmsg = 3;
repeated UserInfo friend_list = 4; //要返回的用户信息 repeated UserInfo friend_list = 4;
} }
//-------------------------------------- //--------------------------------------
//好友删除 //好友删除
message FriendRemoveReq { message FriendRemoveReq {
string request_id = 1; string request_id = 1;
optional string user_id = 2; //当前用户ID optional string user_id = 2;
optional string session_id = 3; optional string session_id = 3;
string peer_id = 4; //要删除的好友ID string peer_id = 4;
} }
message FriendRemoveRsp { message FriendRemoveRsp {
string request_id = 1; string request_id = 1;
@ -53,15 +60,14 @@ message FriendAddProcessReq {
bool agree = 3;//是否同意好友申请 bool agree = 3;//是否同意好友申请
string apply_user_id = 4; //申请人的用户id string apply_user_id = 4; //申请人的用户id
optional string session_id = 5; optional string session_id = 5;
optional string user_id = 6; // 被申请人 optional string user_id = 6;
} }
// +++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++
message FriendAddProcessRsp { message FriendAddProcessRsp {
string request_id = 1; string request_id = 1;
bool success = 2; bool success = 2;
string errmsg = 3; string errmsg = 3;
// 同意后会创建会话,向网关返回会话信息,用于通知双方会话的建立,这个字段客户端不需要关注 optional string new_session_id = 4; // 同意后会创建会话,向网关返回会话信息,用于通知双方会话的建立,这个字段客户端不需要关注
optional string new_session_id = 4;
} }
//-------------------------------------- //--------------------------------------
//获取待处理的,申请自己好友的信息列表 //获取待处理的,申请自己好友的信息列表
@ -72,7 +78,7 @@ message GetPendingFriendEventListReq {
} }
message FriendEvent { message FriendEvent {
optional string event_id = 1; string event_id = 1;
UserInfo sender = 3; UserInfo sender = 3;
} }
message GetPendingFriendEventListRsp { message GetPendingFriendEventListRsp {

View File

@ -1,11 +1,39 @@
syntax = "proto3"; syntax = "proto3";
package bite_im; package bite_im;
option cc_generic_services = true; option cc_generic_services = true;
/*
消息推送使用websocket长连接进行
websocket长连接转换请求ws://host:ip/ws
长连建立以后,需要客户端给服务器发送一个身份验证信息
*/
message ClientAuthenticationReq { message ClientAuthenticationReq {
string request_id = 1; 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协议进行通信 //在客户端与网关服务器的通信中使用HTTP协议进行通信
// 通信时采用POST请求作为请求方法 // 通信时采用POST请求作为请求方法

View File

@ -1,3 +1,9 @@
/*
/service/message_storage/instance_id
/service/message_storage
ID: instance_id ID
/service/message_storage
*/
syntax = "proto3"; syntax = "proto3";
package bite_im; package bite_im;
import "base.proto"; import "base.proto";
@ -52,4 +58,5 @@ service MsgStorageService {
rpc GetHistoryMsg(GetHistoryMsgReq) returns (GetHistoryMsgRsp); rpc GetHistoryMsg(GetHistoryMsgReq) returns (GetHistoryMsgRsp);
rpc GetRecentMsg(GetRecentMsgReq) returns (GetRecentMsgRsp); rpc GetRecentMsg(GetRecentMsgReq) returns (GetRecentMsgRsp);
rpc MsgSearch(MsgSearchReq) returns (MsgSearchRsp); rpc MsgSearch(MsgSearchReq) returns (MsgSearchRsp);
} }

View File

@ -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);
}

43
proto/notify.proto Normal file
View File

@ -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;//消息信息
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1,6 +1,13 @@
/*
用户操作服务器的子服务注册信息: /service/user/instance_id
服务名称:/service/user
实例ID: instance_id 每个能够提供用户操作服务的子服务器唯一ID
当服务发现的时候,通过 /service/user 进行服务发现,就可以发现所有的能够提供用户操作的实例信息了
*/
syntax = "proto3"; syntax = "proto3";
package bite_im; package bite_im;
import "base.proto"; import "base.proto";
option cc_generic_services = true; option cc_generic_services = true;
//---------------------------- //----------------------------
@ -9,8 +16,8 @@ message UserRegisterReq {
string request_id = 1; string request_id = 1;
string nickname = 2; string nickname = 2;
string password = 3; string password = 3;
optional string verify_code_id = 4; //目前客户端实现了本地验证,该字段没用了 string verify_code_id = 4;
optional string verify_code = 5;//目前客户端实现了本地验证,该字段没用了 string verify_code = 5;
} }
message UserRegisterRsp { message UserRegisterRsp {
string request_id = 1; string request_id = 1;
@ -23,8 +30,8 @@ message UserLoginReq {
string request_id = 1; string request_id = 1;
string nickname = 2; string nickname = 2;
string password = 3; string password = 3;
optional string verify_code_id = 4; string verify_code_id = 4;
optional string verify_code = 5; string verify_code = 5;
} }
message UserLoginRsp { message UserLoginRsp {
string request_id = 1; string request_id = 1;
@ -76,8 +83,8 @@ message PhoneLoginRsp {
//其他个人/好友信息的获取在好友操作中完成 //其他个人/好友信息的获取在好友操作中完成
message GetUserInfoReq { message GetUserInfoReq {
string request_id = 1; string request_id = 1;
optional string user_id = 2; // 这个字段是网关进行身份鉴权之后填入的字段 optional string user_id = 2;
optional string session_id = 3; // 进行客户端身份识别的关键字段 optional string session_id = 3;
} }
message GetUserInfoRsp { message GetUserInfoRsp {
string request_id = 1; string request_id = 1;
@ -85,17 +92,6 @@ message GetUserInfoRsp {
string errmsg = 3; string errmsg = 3;
UserInfo user_info = 4; 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<string, UserInfo> users_info = 4;
}
//---------------------------- //----------------------------
//用户头像修改 //用户头像修改
message SetUserAvatarReq { message SetUserAvatarReq {
@ -158,7 +154,6 @@ service UserService {
rpc PhoneRegister(PhoneRegisterReq) returns (PhoneRegisterRsp); rpc PhoneRegister(PhoneRegisterReq) returns (PhoneRegisterRsp);
rpc PhoneLogin(PhoneLoginReq) returns (PhoneLoginRsp); rpc PhoneLogin(PhoneLoginReq) returns (PhoneLoginRsp);
rpc GetUserInfo(GetUserInfoReq) returns (GetUserInfoRsp); rpc GetUserInfo(GetUserInfoReq) returns (GetUserInfoRsp);
rpc GetMultiUserInfo(GetMultiUserInfoReq) returns (GetMultiUserInfoRsp);
rpc SetUserAvatar(SetUserAvatarReq) returns (SetUserAvatarRsp); rpc SetUserAvatar(SetUserAvatarReq) returns (SetUserAvatarRsp);
rpc SetUserNickname(SetUserNicknameReq) returns (SetUserNicknameRsp); rpc SetUserNickname(SetUserNicknameReq) returns (SetUserNicknameRsp);
rpc SetUserDescription(SetUserDescriptionReq) returns (SetUserDescriptionRsp); rpc SetUserDescription(SetUserDescriptionReq) returns (SetUserDescriptionRsp);