前情回顾
前面我们实现了聊天资源的下载和上传,以及异步通知断点下载等功能。
今天主要实现登录后聊天信息的加载,之前把文本信息的加载实现了,现在需要实现用户登录后图片信息的加载。
这个功能做完,聊天的基本功能就都收尾了,有意思的是好像一个圆圈,我们又回到了最初的原点,从登录逻辑出发,补充聊天资源加载
登录流程回顾

点击登录按钮后,通过HttpMgr发送登录请求
1 | void LoginDialog::on_login_btn_clicked() |
HttpMgr内部封装了PostHttpReq接口,这是异步http请求,会提前构造好一个reply,以及注册一个回调函数,将来GateServer将登录信息返回后会出发这个回调函数
1 | void HttpMgr::PostHttpReq(QUrl url, QJsonObject json, ReqId req_id, Modules mod) |
我们查看下GateServer的处理流程
1 | bool LogicSystem::HandlePost(std::string path, std::shared_ptr<HttpConnection> con) { |
服务器会根据客户端传递的url进行分析,然后去_post_handlers中根据path查找并调用回调函数
回调函数在LogicSystem中提前注册到_post_handlers中
1 | void LogicSystem::RegPost(std::string url, HttpHandler handler) { |
在构造函数中调用RegPost注册消息
1 | //用户登录逻辑 |
所以GateServer会触发上面的lambda表达式处理
在lambda表达式中调用GRPC连接池,向StatusServer发送请求,获取可用的聊天服务器地址,将聊天服务器地址返回给GateServer,GateServer再将地址返回给客户端, rpc封装
1 | GetChatServerRsp StatusGrpcClient::GetChatServer(int uid) |
客户端收到GateServer回复后,客户端会根据消息ID为ReqId::ID_LOGIN_USER发送sig_http_finish信号通知
该信号连接了
1 | HttpMgr::HttpMgr() |
分别对应三个请求的处理
1 | void HttpMgr::slot_http_finish(ReqId id, QString res, ErrorCodes err, Modules mod) |
对于登录请求,主要逻辑在sig_login_mod_finish信号发出看,该信号在LoginDialog中连接
1 | //连接登录回包信号 |
进而出发槽函数
1 | void LoginDialog::slot_login_mod_finish(ReqId id, QString res, ErrorCodes err) |
槽函数中根据id获取提前注册好的回调函数
1 | _handlers[id](jsonDoc.object()); |
之前的注册逻辑
1 | void LoginDialog::initHttpHandlers() |
所以当消息到来时会出发上面的lambda表达式,进而发出sig_connect_tcp信号, 该信号链接槽函数slot_tcp_connect
1 | //连接tcp连接请求的信号和槽函数 |
槽函数内根据host地址链接指定的tcpserver
1 | void TcpMgr::slot_tcp_connect(std::shared_ptr<ServerInfo> si) |
_socket 是QTcpSocket类型,发出连接请求后,如果和服务器建立好连接后,会触发链接成功的回调, 在TcpMgr的构造函数中提前注册了消息和回调函数
1 | TcpMgr::TcpMgr():_host(""),_port(0),_b_recv_pending(false),_message_id(0),_message_len(0),_bytes_sent(0),_pending(false) |
当客户端和服务器建立连接后,会出发下面的lambda表达式
1 | QObject::connect(&_socket, &QTcpSocket::connected, this, [&]() { |
从而发出sig_con_success信号, 信号连接了槽函数slot_tcp_con_finish
1 | //连接tcp管理者发出的连接成功信号 |
槽函数里链接资源服务器
1 | void LoginDialog::slot_tcp_con_finish(bool bsuccess) |
该信号连接了槽函数
1 | //连接tcp连接资源服务器请求的信号和槽函数 |
链接资源服务器的逻辑和之前链接ChatServer类似
1 | void FileTcpMgr::slot_tcp_connect(std::shared_ptr<ServerInfo> si) |
当客户端链接资源服务器成功了,就会出发lambda表达式
1 | QObject::connect(&_socket, &QTcpSocket::connected, this, [&]() { |
信号sig_con_success和槽函数链接
1 | connect(FileTcpMgr::GetInstance().get(), &FileTcpMgr::sig_con_success, this, &LoginDialog::slot_res_con_finish); |
进而触发这个函数,内部发送登录请求给ChatServer
1 | void LoginDialog::slot_res_con_finish(bool bsuccess) |
这里略去ChatServer的处理,客户端收到ID_CHAT_LOGIN_RSP回复后,出发lambda表达式
1 | _handlers.insert(ID_CHAT_LOGIN_RSP, [this](ReqId id, int len, QByteArray data){ |
将用户信息,以及好友列表,申请列表等数据组织好后存储UserMgr中,然后发送信号sig_swich_chatdlg跳转到登录界面
链接信号
1 | //连接创建聊天界面信号 |
跳转逻辑
1 |
|
至此完成登录界面加载以及聊天记录加载,聊天记录加载具体流程看下面
加载聊天记录
其中加载聊天记录核心逻辑
1 | void ChatDialog::loadChatList() |
发送ID_LOAD_CHAT_THREAD_REQ逻辑给ChatServer,略去服务器处理流程,客户端会受到会话列表的回复数据
1 | _handlers.insert(ID_LOAD_CHAT_THREAD_RSP, [this](ReqId id, int len, QByteArray data) { |
解析会话列表,按照会话id请求每个会话具体内容
1 | void ChatDialog::slot_load_chat_thread(bool load_more, int last_thread_id, |
如果load_more为true,说明有会话没加载完,需要继续加载,等到所有会话信息加载成功后,load_more为false,则将当前会话的消息列表添加到聊天界面。如果会话列表加载完成了,则继续加载会话内部的多个消息。
1 | void ChatDialog::loadChatMsg() { |
回包消息处理
1 | _handlers.insert(ID_LOAD_CHAT_MSG_RSP, [this](ReqId id, int len, QByteArray data) { |
这里加载了thread会话信息,以及每个会话的消息列表,如果消息列表没有加载完全,则继续发送信号sig_load_chat_msg信号继续加载消息。
最终在此处将所有会话的所有消息加载完成
1 | void ChatDialog::slot_load_chat_msg(int thread_id, int msg_id, bool load_more, |
资源消息加载
核心的资源消息加载是在ID_LOAD_CHAT_MSG_RSP回报的逻辑里
1 | _handlers.insert(ID_LOAD_CHAT_MSG_RSP, [this](ReqId id, int len, QByteArray data) { |
核心逻辑是这部分
1 |
|