mirror of
https://gitee.com/Zhaoxin59/my-chat_-client.git
synced 2026-02-14 00:51:48 +08:00
refactor: 大规模调整项目目录结构,将ChatClient和ChatServer整合为Monorepo结构,并分为两个独立文件夹:chatclient/ 和 chatserver/。更新了ChatClient的CMakeLists.txt配置以适配新结构。
This commit is contained in:
318
ChatClient/include/model/data.h
Normal file
318
ChatClient/include/model/data.h
Normal 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
|
||||
Reference in New Issue
Block a user