Skip to content

elel-code/chatview

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ChatView — 端到端即时通讯系统

ChatView 是一个基于 Ed25519 公钥体系的即时通讯应用,使用 Go 实现,gRPC (HTTP/2 over TCP) 通信,支持多端同时在线。

组件 技术栈 存储
Server Go + gRPC PostgreSQL
Client Go + Fyne (跨平台桌面 GUI) SQLite
Proto protobuf

核心特性

  • Ed25519 公钥身份 — 用户以公钥为唯一标识,私钥用 PIN 加密存储在本地,永不离开客户端
  • Challenge-Response 认证 — 服务端生成随机挑战,客户端本地签名验证,零知识证明
  • 幂等消息发送 — 每条消息携带 UUIDv7 作为幂等键,配合 PostgreSQL serialization failure 自动重试,保证 exactly-once 语义
  • 离线 Outbox — 网络中断时消息进入本地 SQLite 队列,后台 worker 自动重试发送
  • 实时事件推送 — 服务端 Hub 维护发布/订阅通道,客户端通过 gRPC server-streaming 订阅新消息、好友状态变更、强制下线等事件
  • 结构化并发 — 全链路 context 树管理 goroutine 生命周期,登出时级联取消所有后台任务,无泄漏
  • 管理员面板 — 用户管理(封禁/解封)、系统广播、统计数据面板
  • 多端在线 — 同一公钥可注册多个客户端连接,消息推送到所有在线终端

项目结构

chatview/
├── proto/                          # protobuf 协议定义
│   └── chatview/
│       ├── common/types.proto      # 通用类型(枚举、消息体)
│       ├── auth.proto              # 认证协议
│       ├── chat.proto              # 聊天协议(好友、消息、历史、已读)
│       ├── events.proto            # 事件流(新消息、好友状态、强制下线)
│       └── admin.proto             # 管理员协议
├── api/                            # Go module(生成 + 手写代码)
│   ├── go.mod
│   └── gen/chatview/               # protoc 生成代码(.pb.go, _grpc.pb.go)
├── server/                         # 服务端
│   ├── cmd/server/main.go          # 入口
│   ├── config.example.yaml         # 示例配置
│   ├── configuration.md            # 配置文档
│   ├── migrations/                 # PostgreSQL DDL 迁移
│   └── internal/
│       ├── account/                # 账户类型定义
│       ├── auth/                   # Ed25519 加密工具
│       ├── config/                 # 配置加载
│       ├── contextx/               # Context Principal 注入
│       ├── db/                     # PostgreSQL 数据层
│       ├── eventhub/               # 事件总线(发布/订阅)
│       ├── interceptor/            # gRPC 拦截器(认证/权限/日志)
│       └── service/                # gRPC 服务实现
├── client/                         # 桌面客户端
│   ├── cmd/client/main.go          # 入口
│   ├── client.example.yaml         # 示例配置
│   ├── configuration.md            # 配置文档
│   └── internal/
│       ├── config/                 # 配置加载
│       ├── core/                   # 业务编排(接口 + 实现)
│       ├── domain/                 # 纯数据类型
│       ├── identity/               # Ed25519 密钥管理(PIN 加密)
│       ├── rpcclient/              # gRPC 传输适配
│       ├── storage/                # SQLite 本地缓存 + outbox
│       └── ui/                     # Fyne 桌面 UI
├── scripts/gen-proto               # Proto 代码生成脚本
└── tools/protoc-*/                 # protoc 工具链(本地目录,由 gitignore 排除)

快速开始

前置条件

  • Go 1.21+
  • PostgreSQL(服务端需要)
  • protoc(可选,仅修改 proto 时需要)

1. 启动服务端

cd server

# 创建数据库
createdb chatview

# 使用示例配置启动
go run ./cmd/server -config config.example.yaml

服务端默认监听 :50051,需要先修改 config.example.yaml 中的 db_dsn 为你的 PostgreSQL 连接串。

2. 启动客户端

cd client

# 连接本地服务端
go run ./cmd/client

# Wayland 下建议添加原生支持
go run -tags wayland ./cmd/client

首次启动会显示 PIN 输入界面,可选择创建新身份或导入已有 Ed25519 私钥。

3. 运行测试

cd server && go test ./...
cd client && go test ./...

4. 修改 Proto 后重新生成

./scripts/gen-proto

详见 PROTO_GUIDE.md


认证流程

客户端                                服务端
──────                                ──────
1. RequestChallenge(public_key)  →    生成随机 nonce,关联 public_key
2.                          ←    返回 challenge (bytes)
3. 用 Ed25519 私钥本地签名 challenge
   (私钥不发送给服务端)
4. Login(public_key, sig)     →     验证 Ed25519 签名
5.                          ←    返回 session_token + role

之后所有 RPC 在 gRPC metadata 中携带 authorization: Bearer <token>


消息发送流程

UI (sync.go)
  └→ Service.SendMessage(ctx, receiver, text)
       ├─ 生成 clientMessageID(UUIDv7,幂等键)
       ├─ 创建 pending 状态消息
       ├─ 在线 → gRPC SendMessage (带幂等键)
       └─ 离线 → 写入 SQLite outbox → 后台 worker 重试

服务端 (chat_send.go)
  1. 串行化重试(最多 3 次,处理 serialization failure)
  2. clientMessageID 去重检查
  3. 事务内:next_seq++ → INSERT message
  4. 事件推送 → Hub.Push(receiver, NewMessageEvent)
  5. 返回 messageId + serverSeq

事件流架构

服务端 Hub(map[pubKey]→[client channel])
  ├─ Register(pubKey, clientID, chan)
  ├─ Unregister(pubKey, clientID)
  ├─ Push(pubKey, event)        → 推送到指定用户的所有连接
  ├─ Broadcast(event)            → 推送到所有在线用户
  └─ PushAdmins(event)           → 仅推送给管理员

客户端 (events.go)
  └→ 通过 gRPC server-streaming 订阅事件流
       ├─ new_message      → 刷新消息列表 + 好友列表
       ├─ friend_status    → 刷新好友列表
       ├─ system_broadcast → 桌面通知
       ├─ force_offline    → 登出
       └─ admin_update     → 刷新管理员面板

结构化并发 — Context 树

全链路使用 Go context 管理 goroutine 生命周期:

startSessionContext()                     ← 根 context
  ├─ startOutboxWorker(ctx)               ← 离线消息发送
  ├─ watchEvents(ctx)                     ← 实时事件订阅
  ├─ startOutboxPoller(ctx)               ← 定期重试轮询
  └─ runSessionTask(snapshot)             ← UI 异步任务
       └─ snapshot.ctx + sessionVersion   ← 双重保护防竞态

服务端同理,Ctrl+Csignal.NotifyContext 取消 → 所有后台 goroutine 优雅退出。


配置参考

服务端 (server/config.example.yaml)

默认值 说明
listen_addr :50051 监听地址
db_dsn (必填) PostgreSQL DSN
session_ttl 24h 会话有效期
challenge_ttl 5m 登录挑战有效期
cleanup_interval 10m 过期会话清理间隔
admin_pub_key 初始管理员公钥

客户端 (client/client.example.yaml)

默认值 说明
data_dir 平台相关 本地数据目录
grpc_target 127.0.0.1:50051 服务端地址
grpc_tls 自动判断 是否启用 TLS
grpc_timeout 10s 单次 RPC 超时

详见 server/configuration.mdclient/configuration.md


阅读指引

推荐阅读顺序(从底层到上层,约 2 小时):

  1. 协议定义proto/chatview/ 下 5 个 .proto 文件
  2. 服务端server/internal/service/ 核心业务逻辑
  3. 客户端核心client/internal/core/ 业务编排
  4. 客户端传输与存储client/internal/rpcclient/ + client/internal/storage/
  5. 客户端 UIclient/internal/ui/

详细的代码阅读地图和技术要点解析见 CODE_GUIDE.md。Proto 代码生成见 PROTO_GUIDE.md

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors