refactor: 大规模调整项目目录结构,将ChatClient和ChatServer整合为Monorepo结构,并分为两个独立文件夹:chatclient/ 和 chatserver/。更新了ChatClient的CMakeLists.txt配置以适配新结构。

This commit is contained in:
xyz
2025-09-16 19:47:22 +08:00
parent 89ff4fbac0
commit e7af9ad1d7
77 changed files with 146 additions and 168 deletions

View File

@ -0,0 +1,318 @@
#pragma once
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QIcon>
#include <QString>
#include <QUuid>
#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 {
///////////////////////////
//工具函数,后续很多模块可能会用到
///////////////////////////
//获取仅当前的源文件名
static inline QString getFileName(const QString& path) {
QFileInfo fileinfo(path);
return fileinfo.fileName();
}
//封装一个宏作为日志打印的方式
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))
#define LOG() qDebug().noquote() << TAG
//避免链接阶段出现“函数重定义的问题”
static inline QString formatTime(int64_t timestamp) {
//先把时间戳转换为datetime对象
QDateTime datetime = QDateTime::fromSecsSinceEpoch(timestamp);
//把datetime对象转化为格式化的时间
return datetime.toString("MM-dd HH:mm:ss");
}
//通过这个函数得到秒级别的时间
static inline int64_t getTime() {
return QDateTime::currentSecsSinceEpoch();
}
//根据QByteArray转换为QIcon
static inline QIcon makeIcon(const QByteArray& byteArray) {
//存储和操作图像数据的类
QPixmap pixmap;
pixmap.loadFromData(byteArray);
QIcon icon(pixmap);
return icon;
}
// 读写文件操作
// 从指定的文件中读取所有的二进制内容得到一个QByteArray
static inline QByteArray loadFileToByteArray(const QString& path) {
QFile file(path);
bool ok = file.open(QFile::ReadOnly);
if(!ok) {
qDebug() << "文件打开失败!!!";
return QByteArray();
}
QByteArray content = file.readAll();
file.close();
return content;
}
//将QByteArray的内容写入到某个指定的文件里
static inline void writeByteArrayToFile(const QString& path, const QByteArray& content) {
QFile file(path);
bool ok = file.open(QFile::WriteOnly);
if(!ok) {
qDebug() << "文件打开失败!!!";
return;
}
file.write(content);
file.flush();
file.close();
}
///////////////////////////
// 用户信息
///////////////////////////
class UserInfo {
public:
//初始化,避免一些随机值可能的负面影响
QString userId = ""; //用户编号
QString nickname = ""; //用户昵称
QString description = ""; //用户签名
QString phone = ""; //手机号码
QIcon avatar; //用户头像
//从protobuffer的UserInfo对象转换为当前代码的UserInfo对象
void load(const bite_im::UserInfo& userInfo) {
this->userId = userInfo.userId();
this->nickname = userInfo.nickname();
this->phone = userInfo.phone();
this->description = userInfo.description();
if (userInfo.avatar().isEmpty()) {
//使用默认的头像即可
this->avatar = QIcon(":resource/image/defaultAvatar.png");
}
else {
this->avatar = makeIcon(userInfo.avatar());
}
}
};
///////////////////////////
//消息信息
///////////////////////////
enum MessageType {
TEXT_TYPE, //文本消息
IMAGE_TYPE, //图片消息
FILE_TYPE, //文件消息
SPEECH_TYPE //语音消息
};
class Message {
public:
QString messageId = ""; //消息的编号
QString chatSessionId = ""; //消息所属会话的编号
QString time = ""; //消息的时间,通过格式化的方式来表示
MessageType messageType = TEXT_TYPE; //消息类型
UserInfo sender; //发送者信息
QByteArray content; //消息的正文内容
QString fileId = ""; //文件的身份标识,当为文件,图片,语音,视频有效,当为文本则为""
QString fileName = ""; //文件名称
static Message makeMessage(MessageType messageType, const QString& chatSessionId, const UserInfo& sender,
const QByteArray& content, const QString& extraInfo) {
if(messageType == TEXT_TYPE) {
return makeTextMessage(chatSessionId, sender, content);
} else if(messageType == IMAGE_TYPE) {
return makeImageMessage(chatSessionId, sender, content);
} else if(messageType == FILE_TYPE) {
return makeFileMessage(chatSessionId, sender, content, extraInfo);
} else if(messageType == SPEECH_TYPE) {
return makeSpeechMessage(chatSessionId, sender, content);
} else {
//触发了未知消息类型
return Message();
}
}
void load(const bite_im::MessageInfo& messageInfo) {
this->messageId = messageInfo.messageId();
this->chatSessionId = messageInfo.chatSessionId();
this->time = formatTime(messageInfo.timestamp());
this->sender.load(messageInfo.sender());
//设置消息的类型
auto type = messageInfo.message().messageType();
if (type == bite_im::MessageTypeGadget::MessageType::STRING) {
this->messageType = TEXT_TYPE;
this->content = messageInfo.message().stringMessage().content().toUtf8();
}
else if (type == bite_im::MessageTypeGadget::MessageType::IMAGE) {
this->messageType = IMAGE_TYPE;
if (messageInfo.message().imageMessage().hasImageContent()) {
this->content = messageInfo.message().imageMessage().imageContent();
}
if (messageInfo.message().imageMessage().hasFileId()) {
this->fileId = messageInfo.message().imageMessage().fileId();
}
}
else if (type == bite_im::MessageTypeGadget::MessageType::FILE) {
this->messageType = FILE_TYPE;
if (messageInfo.message().fileMessage().hasFileContents()) {
this->content = messageInfo.message().fileMessage().fileContents();
}
if (messageInfo.message().fileMessage().hasFileId()) {
this->fileId = messageInfo.message().fileMessage().fileId();
}
this->fileName = messageInfo.message().fileMessage().fileName();
}
else if (type == bite_im::MessageTypeGadget::MessageType::SPEECH) {
this->messageType = SPEECH_TYPE;
if (messageInfo.message().speechMessage().hasFileContents()) {
this->content = messageInfo.message().speechMessage().fileContents();
}
if (messageInfo.message().speechMessage().hasFileId()) {
this->fileId = messageInfo.message().speechMessage().fileId();
}
}
else {
// 错误的类型, 啥都不做了, 只是打印一个日志
LOG() << "非法的消息类型! type=" << type;
}
}
private:
static QString makeId() {
//Uuid这东西背后也是一套算法能够生成“全球唯一的身份标识”
//Qt对UUID也有封装
//{75eb37e5-5af5-4bfb-8d0e-5261038a9107}(16进制的整数)
return "M" + QUuid::createUuid().toString().mid(25, 12);
}
static Message makeTextMessage(const QString& chatSessionId,const UserInfo& sender, const QByteArray& content) {
Message message;
//此处需要确保生成的messageId是唯一的
message.messageId = makeId();
message.chatSessionId = chatSessionId;
message.sender = sender;
message.time = formatTime(getTime());
message.content = content;
message.messageType = TEXT_TYPE;
//对于文本消息来说,以下属性并不使用,所以设置为""
message.fileId = "";
message.fileName = "";
return message;
}
static Message makeImageMessage(const QString& chatSessionId,const UserInfo& sender, const QByteArray& content) {
Message message;
message.messageId = makeId();
message.chatSessionId = chatSessionId;
message.sender = sender;
message.time = formatTime(getTime());
message.content = content;
message.messageType = IMAGE_TYPE;
//后续使用时再进一步进行设置
message.fileId = "";
//此处并不使用,设置为""
message.fileName = "";
return message;
}
static Message makeFileMessage(const QString& chatSessionId,const UserInfo& sender, const QByteArray& content, const QString& fileName) {
Message message;
message.messageId = makeId();
message.chatSessionId = chatSessionId;
message.sender = sender;
message.time = formatTime(getTime());
message.content = content;
message.messageType = FILE_TYPE;
//后续使用时再进一步进行设置
message.fileId = "";
//此处并不使用,设置为""
message.fileName = fileName;
return message;
}
static Message makeSpeechMessage(const QString& chatSessionId,const UserInfo& sender, const QByteArray& content) {
Message message;
message.messageId = makeId();
message.chatSessionId = chatSessionId;
message.sender = sender;
message.time = formatTime(getTime());
message.content = content;
message.messageType = SPEECH_TYPE;
//后续使用时再进一步进行设置
message.fileId = "";
//此处并不使用,设置为""
message.fileName = "";
return message;
}
};
///////////////////////////
//会话信息
///////////////////////////
class ChatSessionInfo {
public:
QString chatSessionId = ""; //会话编号
QString chatSessionName = ""; //会话名字(单聊或群聊)
Message lastMessage; //表示会话的最新消息
QIcon avatar; //会话的头像(单聊或群聊)
QString userId = ""; //(单聊为对方的id群聊为"")
void load(const bite_im::ChatSessionInfo& chatSessionInfo) {
this->chatSessionId = chatSessionInfo.chatSessionId();
this->chatSessionName = chatSessionInfo.chatSessionName();
if (chatSessionInfo.hasSingleChatFriendId()) {
this->userId = chatSessionInfo.singleChatFriendId();
}
if (chatSessionInfo.hasPrevMessage()) {
lastMessage.load(chatSessionInfo.prevMessage());
}
if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty()) {
//如果有头像,则设置这个头像
this->avatar = makeIcon(chatSessionInfo.avatar());
}
else {
//如果没有,则会根据是单聊还是群聊,使用不同的默认头像
if (userId != "") {
//单聊
this->avatar = QIcon(":/resource/image/defaultAvatar.png");
}
else {
//群聊
this->avatar = QIcon(":/resource/image/groupAvatar.png");
}
}
}
};
} //end namespace model