### 界面 (Interface) 纯命令行界面实现,程序界面分为三大块: * 聊天区 -- 左上角最大的一块 -- 显示聊天记录的区域。 * 输入区 -- 左下角稍小的一块 -- 用户输入区域。 * 状态区 -- 右侧一列-- 显示使用 `/list`命令的输出。 * 当在一个聊天组中,默认显示当前聊天组用户列表 (需要包括用户的名称、用户的在线状态) (效果等效于 `/list -s`)。 三个区域之间应当需要分别刷新 TUI 使用 *Textual* 库 实现, 优先实现基本界面, 进阶的界面如果有时间继续完善 ##### 聊天区 自己的消息需要使用特殊的颜色标明, 每条信息应该带有发送者昵称, 发送时间例如: ``` Alice >hello Bob!🥰 ``` 格式类似于此, 非常需要优化 ##### 输入区 普通的输入 ##### 状态区 以比较优雅的方式输出列表 ------ ### 命令 (Commands) 进入系统是默认进入一个空的界面,但是输入框是可以输入的,然后可以在输入框中输入 `/{cmd}` 来执行各种操作,具体如下: * `/?` * 列出所有可用的命令选项。 * `/help {options}` * 列出 `{option}` 命令的用法。例如 `/help send_files {文件路径}` : 将 `{文件路径}` 这个文件通过ftp发送。 (备注:FTP描述将更新为服务器中转)。 * `/login` * 进入登录状态,在状态列显示提示输入用户名/ID的提示,然后可以在输入框中输入用户名。用户名输入完毕后,状态列显示输入密码的提示,然后在输入框中输入密码。登录成功后在状态列打印登录成功,然后默认进入公频聊天。 (密码输入时应在界面上做掩码处理)。 * `/signin` * 进入注册状态。类似登录的流程走一遍注册的流程。 (密码输入时应在界面上做掩码处理)。 * `/info` * 在状态列显示当前的用户信息: 用户名(唯一),ID(自动分配),状态,已经加入的聊天组数量(私聊也算聊天组, 不过可以分开打印, 比如说总数x, 私聊y, 群聊x-y),当前系统存在的聊天组总数,当前系统存在的用户总数,当前系统在线的用户总数。 * `/list {options}` * `-u` : 在状态列显示所有的用户 (需要包括用户的名称, ID, 用户的在线状态)。 * `-s`: 在状态列显示**当前聊天组**的所有用户 (需要包括用户的名称, 用户的在线状态)。 * `-c` : 在状态列显示所有**本用户已经加入的聊天组**。 * `-g` : 在状态列显示所有的**用户列表长度>2**的聊天组 (也就是群聊而非私聊)。 * `-f` : 在状态列显示该聊天记录中所有的文件 (准确说是文件传输记录)。 * `/create_chat {chat_name} {users...}` * 创建一个聊天组, 该聊天组的 *别名* 是 `{chat_name}` , 初始成员为 `{users...}` (users为可变长参数)。将`users...` 加入到该聊天组的用户列表中。 * `/enter_chat {chat_name}` * 可以进入一个 *别名* 为 `{chat_name}` 的聊天组 **如果本用户存在于这个聊天组的用户列表中** (默认存在的公频的名称为: `public`)。 * `/join_chat {chat_name}` * 加入到一个 *别名* 为 `{chat_name}` 的聊天组中, **将本用户加入到这个聊天组的用户列表中**。 * `/send_files {file_path...}` * 将本机的 `{file_path}` 文件通过**服务器中转**传输到当前聊天组。`file_path`是可变长参数。 * `/recv_files {options}` * `-n {file_identifier}`: 接收该聊天组中标识为 `{file_identifier}` 的文件 (文件名或文件ID)。`file_identifier`是可变长参数。 * `-l`: 列出当前聊天记录中可供下载的文件。 * `-a`: 接收当前聊天记录中所有可供下载的文件。 * `/exit` * 退出系统, 将状态更新为离线。 ------ ### 功能细节 (Functional Details) #### 1. 安全性 (Security) * **数据传输**:除密码外,其他数据将以明文方式在客户端和服务器之间传输。 * **密码存储**:用户密码在注册时,服务器端将使用某种加密方式进行处理后存储在SQLite数据库中。登录验证时,对用户输入的密码进行同样的处理再进行比对。 #### 2. 数据库 (SQLite) 将使用 **SQLite** 数据库存储所有持久化数据,包括用户信息、聊天组信息、消息记录和文件元数据。数据库文件将部署在服务器端。 **初步表结构设想**: * `users` * `id` (INTEGER, PRIMARY KEY, AUTOINCREMENT) * `username` (TEXT, UNIQUE, NOT NULL) * `password_hash` (TEXT, NOT NULL) * `is_online` (INTEGER, DEFAULT 0) -- 0 for offline, 1 for online * `chat_groups` * `id` (INTEGER, PRIMARY KEY, AUTOINCREMENT) * `name` (TEXT, UNIQUE, NOT NULL) -- 聊天组别名 * `is_private_chat` (INTEGER, DEFAULT 0) -- 1表示私聊 (成员数为2),0表示群聊 * `created_at` (TIMESTAMP, DEFAULT CURRENT_TIMESTAMP) * `group_members` * `group_id` (INTEGER, FOREIGN KEY (`chat_groups.id`)) * `user_id` (INTEGER, FOREIGN KEY (`users.id`)) * PRIMARY KEY (`group_id`, `user_id`) * `messages` * `id` (INTEGER, PRIMARY KEY, AUTOINCREMENT) * `group_id` (INTEGER, FOREIGN KEY (`chat_groups.id`)) * `sender_id` (INTEGER, FOREIGN KEY (`users.id`)) * `content` (TEXT) -- 文本消息内容或文件传输的描述性信息 * `message_type` (TEXT, DEFAULT 'text') -- 'text', 'file_notification', 'system_message' * `timestamp` (TIMESTAMP, DEFAULT CURRENT_TIMESTAMP) * `files_metadata` (用于追踪文件信息) * `id` (INTEGER, PRIMARY KEY, AUTOINCREMENT) * `original_filename` (TEXT, NOT NULL) * `server_filepath` (TEXT, NOT NULL, UNIQUE) -- 文件在服务器上的存储路径 * `uploader_id` (INTEGER, FOREIGN KEY (`users.id`)) * `chat_group_id` (INTEGER, FOREIGN KEY (`chat_groups.id`)) * `upload_timestamp` (TIMESTAMP, DEFAULT CURRENT_TIMESTAMP) * `message_id` (INTEGER, FOREIGN KEY (`messages.id`), NULLABLE) -- 关联到通知此文件的消息 #### 3. 聊天记录 (Chat History) * 全部聊天内容(文本消息和文件传输记录)将存储在服务器端的SQLite数据库中。 * 客户端登录时,可从服务器拉取其参与的聊天组的最新消息,实现漫游。 * 客户端本地可缓存一部分聊天记录,以提高显示速度和支持离线查看(可选功能)。 #### 4. 用户状态 (User Status) * 用户登录聊天室即向服务器发送上线信息,服务器更新数据库中用户状态为在线。 * 用户退出程序 (`/exit`) 或连接意外断开,服务器将其状态更新为离线。 * 服务器端存储的用户状态发生改变时,应通知相关客户端(例如同一聊天组内的用户)更新其本地显示的用户状态。 #### 5. 聊天 (Chat) * 所有聊天(包括私聊和群聊)均视为一个“聊天组”。私聊是成员数量为2的特殊聊天组。 * 默认存在一个名为 `public` 的公频聊天组,所有用户均可加入和发言。 * AI (glm-4-flash) 集成 * AI 用户可作为系统内的一个特殊用户。 * **私聊**:用户与AI私聊时,客户端将用户消息发送至服务器。服务器识别目标为AI后,将当前对话上下文作为prompt,通过API请求智谱服务。收到智谱的响应后,服务器将此响应作为AI的消息发送回给用户。 * **群聊**:群聊消息中若包含 `@AI`,服务器将截取该消息作为prompt,并结合聊天组的上下文信息,请求智谱服务。AI的回复将作为一条新消息发送到该群聊中。 #### 6. 收发文件 (File Transfer - Server Mediated) * 发送文件 (`/send_files {file_path...}`) 1. 客户端用户输入命令,指定本地文件路径。 2. 客户端将文件数据块通过socket连接发送给服务器。 3. 服务器接收文件,将其存储在预定义的服务器文件存储区 (例如,按聊天组ID或日期分子文件夹)。 4. 服务器在 `files_metadata` 表中记录文件元数据(原文件名、服务器路径、上传者、所属聊天组等)。 5. 服务器在对应的聊天组的 `messages` 表中插入一条类型为 `file_notification` 的消息,内容可包含文件名、大小、上传者等信息,并关联到`files_metadata`的记录。 6. 服务器将此文件通知消息广播给聊天组内所有在线成员。 * 接收文件 (`/recv_files`) 1. 用户通过 `/list -f` 或 `/recv_files -l` 查看当前聊天组的文件列表 (从服务器查询 `files_metadata` 或 `messages` 中类型为 `file_notification` 的记录)。 2. 用户输入 `/recv_files -n {file_identifier}` (file_identifier 可以是文件名或列表中的编号/ID)。 3. 客户端向服务器发起文件下载请求,指明所需文件。 4. 服务器根据请求,从其存储区读取文件数据,并通过socket连接将文件数据块发送给客户端。 5. 客户端接收文件数据,将其保存在用户指定的本地文件夹(例如,用户个人文件夹下的 `received_files/`)。 6. 客户端在界面提示用户文件接收成功及存储路径。 * `/recv_files -a` 将触发对当前聊天组内所有可下载文件的下载流程。 ------ ### 代码结构 (Code Structure) 建议采用模块化的代码结构,将客户端和服务器端分离,并进一步细化内部模块。 **我不清楚这样是否是最佳的方式, 非常需要优化 ** ``` chat_project/ ├── client/ │ ├── __init__.py │ ├── main_client.py # 客户端主入口,初始化并运行AppController │ ├── app_controller.py # NEW: 客户端应用逻辑控制器 (协调TUI和后端服务) │ ├── tui/ # NEW: TUI相关模块目录 │ │ ├── __init__.py │ │ ├── app_tui.py # Textual TUI应用定义 (原tui_app.py) │ │ └── widgets/ # (Optional) 自定义Textual小部件 │ ├── network/ │ │ ├── __init__.py │ │ ├── client_service.py # 封装网络通信,收发和解析协议消息 (原network_client.py) │ │ └── message_handler.py # NEW: 处理从服务器接收到的各类消息/事件 │ ├── services/ # NEW: 客户端本地服务 │ │ ├── __init__.py │ │ ├── command_processor.py # 解析用户输入命令并分发 (原command_parser.py) │ │ └── file_transfer_client.py # 客户端文件传输逻辑 │ └── config_client.py # 客户端配置 │ ├── server/ │ ├── __init__.py │ ├── main_server.py # 服务器主入口,启动监听服务 │ ├── core/ # NEW: 服务器核心业务逻辑 │ │ ├── __init__.py │ │ ├── client_session.py # 管理单个客户端的会话和状态 (原client_handler.py) │ │ ├── request_dispatcher.py # NEW: 接收原始请求,根据协议分发到各服务处理 │ │ └── broadcast_service.py # NEW: 负责向客户端广播消息(如用户状态、群消息) │ ├── services/ # NEW: 服务器各功能模块/服务 │ │ ├── __init__.py │ │ ├── auth_service.py # 用户认证服务 (原auth.py) │ │ ├── chat_service.py # 聊天逻辑服务 (原chat_manager.py) │ │ ├── file_service.py # 文件处理服务 (原file_transfer_server.py) │ │ ├── user_service.py # NEW: 用户信息管理,状态更新等 │ │ └── ai_service.py # AI集成服务 (原ai_integration.py) │ ├── data_access/ # NEW: 数据访问层 │ │ ├── __init__.py | | ├──models.py # 数据模型定义 | | ├──init_db.py # 数据库初始化脚本 │ │ └── database_manager.py # SQLite数据库交互封装 (原database.py) │ └── config_server.py # 服务器配置 │ ├── common/ │ ├── __init__.py │ ├── protocol.py # 通信协议定义 (消息类型、命令码、数据结构) │ ├── dto.py # NEW: Data Transfer Objects (可选,用于规范数据结构) │ └── utils.py # 通用工具函数 │ ├── storage/ # 服务器文件存储 (运行时创建) │ ├── chat.db # SQLite数据库文件 │ └── uploaded_files/ | ├── docs/ # 文档 │ ├── api.md │ └── setup.md │ ├── requirements.txt └── README.md ``` **模块职责简述**: * client/ * `client_main.py`: 启动TUI,初始化网络连接。 * `tui_app.py`: 使用Textual构建和管理所有TUI组件、布局、用户输入处理和界面更新。 * `network_client.py`: 负责与服务器建立socket连接,发送格式化请求,接收并初步解析服务器响应。 * `command_parser.py`: 解析在TUI输入框中键入的 `/` 命令,并将其转换为内部动作或网络请求。 * `file_transfer_client.py`: 实现文件上传的读取、分块、发送,以及文件下载的接收、写入。 * server/ * `server_main.py`: 启动socket服务器,监听连接,为每个连接创建`client_handler`实例。 * `client_handler.py`: 线程/异步任务,处理来自特定客户端的所有请求,调用其他模块功能。 * `database.py`: 封装所有SQL语句和数据库交互,提供高级接口给其他服务模块。 * `auth.py`: 处理 `/login` 和 `/signin` 请求,密码验证和哈希。 * `chat_manager.py`: 处理消息广播、聊天室创建/加入、用户列表等。 * `file_transfer_server.py`: 接收上传的文件并保存,提供文件下载。 * `ai_integration.py`: 调用智谱AI API。 * common/ * `protocol.py`: 定义消息的结构(例如,使用JSON),命令代码,状态码等,确保客户端和服务器理解对方。 * **storage/**: 服务器实际存储用户上传文件的地方,应在`.gitignore`中排除。 #### 关键模块职责调整与新增模块说明 ##### 客户端 (Client) 1. **`main_client.py`**: * 职责:程序入口。初始化配置、`AppController`,并启动 `AppController`。 2. **`app_controller.py` (新增/核心协调器)**: * 职责:作为TUI与客户端后端服务(网络、文件处理等)之间的桥梁。 * 接收来自 `tui.app_tui` 的用户操作(如发送消息、输入命令)。 * 调用 `services.command_processor` 处理命令。 * 调用 `network.client_service` 发送网络请求。 * 接收来自 `network.message_handler` 的服务器推送数据,并更新TUI显示。 * 管理客户端的整体状态(如当前聊天组、用户信息)。 3. **`tui/app_tui.py`**: * 职责:纯粹的界面展示和用户输入捕获(使用Textual)。 * 将用户输入(如聊天内容、命令)传递给 `AppController`。 * 提供方法供 `AppController` 更新界面(如显示新消息、更新状态栏)。 * 自身不包含复杂的应用逻辑。 4. **`network/client_service.py`**: * 职责:管理与服务器的socket连接,使用 `common.protocol` 序列化和反序列化消息,发送请求,启动一个后台线程/任务来持续监听服务器消息。 * 收到服务器消息后,交给 `network.message_handler` 处理。 5. **`network/message_handler.py` (新增)**: * 职责:根据从服务器收到的消息类型 (定义在 `common.protocol`),进行初步解析和分类。 * 调用 `AppController` 中相应的方法来处理这些消息(例如,新消息到达、用户状态更新、文件通知等),以便更新TUI或客户端状态。 6. **`services/command_processor.py`**: * 职责:解析用户在TUI输入框中输入的命令,验证命令格式和参数。 * 调用 `AppController` 或直接调用 `network.client_service` (对于需要网络请求的命令) 或其他客户端服务。 ##### 服务器 (Server) 1. **`main_server.py`**: * 职责:程序入口。初始化配置、数据库连接(通过`data_access.database_manager`)、启动socket监听。 * 接受新的客户端连接,为每个连接创建一个 `core.client_session` 实例来处理。 2. **`core/client_session.py`**: * 职责:管理单个客户端连接的整个生命周期(从未认证到已认证,再到断开)。 * 接收该客户端发送的原始数据,将其传递给 `core.request_dispatcher`。 * 持有客户端的会话状态(如用户ID、当前所在聊天组等)。 * 负责将需要单播给该客户端的响应(通过 `common.protocol` 格式化后)发送回去。 3. **`core/request_dispatcher.py` (新增)**: * 职责:接收来自 `client_session` 的原始客户端请求数据。 * 根据 `common.protocol` 解析请求类型和内容。 * 根据请求类型,调用相应的业务服务模块(如 `services.auth_service`、`services.chat_service` 等)来处理请求。 * 收集业务服务的处理结果,准备响应数据。 4. **`core/broadcast_service.py` (新增)**: * 职责:提供广播消息的能力。例如,当一条群消息产生时,`chat_service` 会调用它,由它负责将消息推送给群内所有在线的 `client_session`。 * 管理所有活跃的 `client_session` 列表或按聊天组分类。 5. **`services/\*_service.py` (原 `\*.py` 移入并统一命名)**: * 例如:`auth_service.py`, `chat_service.py`, `file_service.py`, `user_service.py`, `ai_service.py`。 * 职责:封装具体的业务逻辑。例如,`auth_service` 处理登录注册;`chat_service` 处理消息存储、群组创建加入等。 * 这些服务会调用 `data_access.database_manager` 进行数据库操作。 * 它们是无状态的(或仅依赖传入的参数和数据库状态),易于测试。 6. **`data_access/database_manager.py`**: * 职责:封装所有与SQLite数据库的交互。提供清晰的CRUD(创建、读取、更新、删除)接口供上层服务调用。 * 例如,`get_user_by_username()`, `save_message()`, `create_chat_group()`。 * 所有SQL语句都应在此模块内。 ##### 公共模块 (Common) 1. **`protocol.py`**: * 职责:**极其重要**。定义客户端和服务器之间所有消息的格式、类型标识、命令代码、状态码等。建议使用JSON作为消息体格式,并在此定义清晰的结构。 * 例如,可以定义消息类型常量 `MSG_TYPE_TEXT`, `MSG_TYPE_LOGIN_REQ`, `MSG_TYPE_LOGIN_RESP` 等。 2. **`dto.py` (Data Transfer Objects - 可选但推荐)**: * 职责:定义用于在不同层或模块之间传递数据的简单对象(例如使用 `dataclasses`)。这比直接使用字典更清晰,也更利于类型检查和代码提示。 * 例如,`UserData(id, username, is_online)`, `MessageData(sender, content, timestamp)`。 * `protocol.py` 中定义的消息体结构可以直接映射到这些DTO