【work记录:c++web聊天服务器】修复多个客户端登录重复的bug|更新单个客户端退出功能|调整好友列表和群聊列表的代码

日期:2025.4.21

学习内容:

  • 整理前端代码
  • 修复多个客户端登录重复的bug
  • 更新单个客户端退出功能
  • 更新好友列表与群聊列表的交互按钮
  • 调整好友列表和群聊列表的代码

个人总结:

整理前端代码:

是这样的,之前对于这些东西完全不太怎么了解,让AI直接跑出来,自己做一些简单的修改操作,但是现在实在是不行了。

我的脑子看到这几百行的代码就已经要废掉了,感觉功能什么的,已经完全加不下去了,于是决定整理一下。

大概就是长这个样子,其实就和之前写C++后端的时候差不太多,果然大家都是差不多的。

然后这里js的文件夹里面都是对于index.html的文件:

  • handler.js:做接受消息处理器的,主要功能实现在这里面
  • config.js:目前有点鸡肋,放一些消息的定义
  • websocket.js:把websocket的一些操作封装了起来,我们以后调用ws.send的时候都是默认发送JSON文件了。
  • main.js: 所有的入口,做一些客户端的操作的功能

更新了mudule模块

将原本的main.js里的sendMessage的模块挪到了一个mudule文件夹下,在websocket类里修改了两个函数,send和sendByJson函数。

前者是直接用来发送数据,后者是发送json数据用的。

修复bug

真的,卡了我好久,结果一个很简单的sessionStorage就解决了。

问题是这样的:因为我用了localStorage,导致我如果浏览器连续开两个客户端,第二个客户端在刷新的时候就会读取到最新的客户登录的信息,然后我问了弱智AI,

AI给了我个弱智回复,然后我竟然一开始还不带脑子照着那个去实现了半天,大概的意思就是实现两个localStorage,一个存储当前活跃用户信息,一个就像是map一样去实现,结果我发现还是不行,然后又开了个新窗口问AI,AI告诉我有sessionStorage这个东西的存在,也就是说可以不用存储到本地上,而是存储到当前的标签页上,于是就非常丝滑的解决了这个问题。

日期:2025.4.22

个人总结:

更新退出功能

之前一直懒,写了一个把所有客户端强制退出,方便服务器这边做一些测试之类的,但是现在既然写了一个前端,那么就完善一下退出功能。

左下角这里加了一个退出按钮,当点击退出按钮的时候,将向服务端发送一个退出的消息,接收到了退出允许的消息的话,就会与服务端断开连接,同时跳转到登录页面。

export function logout() {
    
  // 构造消息对象
  const message = {
    msgid: 17,
    user_id: parseInt(storedUser.id)
  };
  
  // 发送到服务器
  ws.sendByJson(message);
}

main.js:

// 执行 退出登录 功能, 当点击按钮的时候
const logoutButton = document.getElementById("logout-btn");
logoutButton.addEventListener("click", logout);

同时服务端那边也做了一些更新:


void ChatService::CloseUser(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
	int user_id = js["user_id"].get<int>();
	auto it = _conn_mp.find(user_id);
	if (it != _conn_mp.end())
	{
		auto session = it->second;

		json response;
		response["user_id"] = user_id;
		response["msgid"] = CLOSE_USER_MSG_ACK;
		response["uid"] = session.getUid();
		Send(conn, response.dump());

		_conn_mp.erase(it);

		User user;
		user.SetID(user_id);
		_user_modle.UpdateState(user, "offline");
		_redis.UnSubscribe(user.GetID());
	}
}

其实就是一些很弱智的操作了,没有什么高端的,纯纯苦力,活成了java的样子。

更新好友列表与群聊列表的交互按钮

具体看图,现在左边这两个按钮可以点击了,点击之后会切换到对应的好友列表和群聊列表。(讲真的这一块好恶心)我果然还是不喜欢前端。

另外我突然意识到了一个bug:

关于我右边的聊天窗口,原来是没有与点击好友关联的。也就是说其实现在更像是一个聊天室项目了。。。

所以后续要补的bug之一,就是要完善好这个聊天窗口,阿巴阿巴业务好恶心。更多的内容到调整好友列表和群聊列表的代码去讲了。

调整好友列表和群聊列表的代码

首先先看handler的改动:

15: (data) => {
         // 1. 解析数据
    const parsedFriends = data.friends.map(friendStr => JSON.parse(friendStr));
    const parsedGroups = data.groups.map(friendStr => JSON.parse(friendStr));
    
    // 2. 更新存储(重要!)
    parsedFriends.forEach(friend => {
      appState.friends.set(friend.id, friend);
    });
    parsedGroups.forEach(group => {
      appState.groups.set(group.id, group);
    });
    // 3. 如果当前显示的是好友列表
    if (appState.currentView === 'friends') {
      friendListView.handle();
    }
    else {
	// 3. 如果当前显示的是群聊列表
      GroupListView.handle();
    }
    },

这里之前是写了一坨,现在我们写了一个关于friendListView的类,然后把那些渲染之类的操作放到了类里面,现在这里做一些存储数据的功能。

存储数据:这里简单提一下,之前我们是直接获取到了parsedFriends,然后直接对他进行解析,对于解析的内容直接呈现到了web上,所以我们并没有存储数据到浏览器里,也就是说我们如果后续做了一些页面切换(虽然我们并不会那样做)的操作,那我们这个页面回来的时候是不会有好友列表的,因为我们都没有存储起来呀!

所以这里关于申请自身状态的函数,做的改动就是把解析的数据存储起来,然后对于当前选择的数据分类讨论去渲染,渲染也是在各自的类里就去封装好的。

然后这里两个类长得极像,我并不想把他们融合成一个,然后通过type去分开区别,觉得这样其实更直观一些,于是就直接开了两个类。

import {appState} from './main.js'
export class FriendListHandler {
    constructor(containerId, onFriendSelected) {
      this.container = document.getElementById(containerId);
      // 好友选中回调函数
      this.onFriendSelected = onFriendSelected;
    }
  
    // 核心消息处理方法
    handle() {
      if (appState.currentView === 'friends') {
        this._renderList(Array.from(appState.friends.values()));
      }     
      this._bindItemClickEvents();
    }
  
    // 渲染好友列表(私有方法)
  _renderList(friends) {
    // console.log("解析了");
      this.container.innerHTML = friends.map(friend => `
        <div class="list-item" 
             data-id="${friend.id}" 
             data-name="${friend.name}"
             data-state="${friend.state}">
          <div>
            <div>${friend.name}</div>
            <div style="color: #666; font-size: 0.9em">
              ${this._getStateText(friend.state)}
            </div>
          </div>
          <div class="status-indicator ${friend.state === 'online' ? 'online' : ''}"></div>
        </div>
      `).join('');
    }
  
    // 获取状态文本(私有方法)
    _getStateText(state) {
      return state === 'online' ? '在线' : '离线';
    }
  
    // 绑定点击事件(私有方法)
    _bindItemClickEvents() {
      this.container.querySelectorAll('.list-item').forEach(item => {
        item.addEventListener('click', () => {
          // 清除所有激活状态
          this._clearActiveStates();
          // 设置当前激活项
          item.classList.add('active');
          // 触发回调
          this.onFriendSelected({
            id: item.dataset.id,
            name: item.dataset.name,
            state: item.dataset.state
          });
        });
      });
    }
  
    // 清除激活状态(私有方法)
    _clearActiveStates() {
      this.container.querySelectorAll('.list-item').forEach(item => {
        item.classList.remove('active');
      });
    }
  }

这里的注释其实写的也算是比较详细了,不得不说AI挺好的 (不知道刚才谁骂了sbAI

另外说一句题外话:如果我现在还想要一些新功能,例如之前提到的申请好友之类的,我觉得对我更大的挑战在于是前端的实现,就像今天和昨天,其实基本上我都是在前端上花费了很多的时间,所以我觉得应该刨去一些那些功能,实现一些关键的内容,这样我才说不定可以赶上下个月中旬之前完成。

所以现在主要是打算实现好web的基本功能,然后去好好搞后端。

来总结一下目前的bug:

  • 没有区分好友或者群聊的聊天窗口
  • 聊天窗口并不会收缩,如果聊天消息多会直接伸长。
  • 没有实现群聊聊天功能(web)
  • 状态没有自动刷新

功能方面所欠缺的:

  • 离线消息
  • 历史消息
posted @ 2025-04-22 16:17  AdviseDY  阅读(19)  评论(0)    收藏  举报