mirror of
https://gitee.com/Zhaoxin59/my-chat_-client.git
synced 2026-02-13 16:41:48 +08:00
319 lines
11 KiB
C++
319 lines
11 KiB
C++
#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(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
|