# im **Repository Path**: vipkwds/im ## Basic Information - **Project Name**: im - **Description**: 基于 `ws` WebSocket 高可用库构建的完整可生产 IM 系统,支持单聊、群聊、完整客服系统 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-22 - **Last Updated**: 2026-06-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # IM System - 完整即时通讯系统 基于 `ws` WebSocket 高可用库构建的完整可生产 IM 系统,支持单聊、群聊、完整客服系统。 ## 功能特性 - **单聊/群聊**:支持文本、图片、语音、文件等多种消息类型 - **完整客服系统**:排队、分配、满意度评价、工单管理 - **MySQL 持久化存储**:完整的关系型数据库支持 - **用户在线状态**:在线/离开/忙碌/离线状态管理 - **已读未读状态**:消息送达/已读状态追踪 - **多端同步**:支持用户多设备消息同步 - **离线推送**:预留 JPush/个推接口 ## 项目结构 ``` im/ ├── user/ # 用户在线状态管理 │ ├── presence.go # 用户状态定义 │ └── manager.go # 状态管理器 ├── conversation/ # 会话管理 │ ├── types.go # 会话基础类型 │ ├── single.go # 单聊会话 │ ├── group.go # 群聊会话 │ ├── customer.go # 客服会话 │ └── manager.go # 会话管理器 ├── message/ # 消息管理 │ ├── types.go # 消息类型定义 │ ├── storage.go # 存储接口 │ ├── mysql/storage.go # MySQL实现 │ └── manager.go # 消息管理器 ├── customer/ # 客服系统 │ ├── queue.go # 优先级排队队列 │ ├── agent.go # 坐席管理 │ ├── department.go # 部门管理 │ ├── ticket.go # 工单系统 │ ├── satisfaction.go # 满意度评价 │ └── manager.go # 统一管理器 ├── router/ # 消息路由 │ ├── router.go # 路由核心 │ └── handlers.go # Action处理器 ├── sync/ # 多端同步 │ └── sync.go # 同步管理器 ├── push/ # 离线推送 │ └── pusher.go # 推送接口 ├── ws/ # WebSocket层 │ ├── session.go # 会话管理 │ ├── handler.go # 消息处理 │ └── server.go # 服务端 ├── examples/ # 示例代码 │ ├── server/main.go # 服务端示例 │ └── client/main.go # 客户端示例 ├── go.mod └── README.md ``` ## 快速开始 ### 1. 初始化项目 ```go package main import ( "gitee.com/vipkwds/im/customer" "gitee.com/vipkwds/im/conversation" "gitee.com/vipkwds/im/message" "gitee.com/vipkwds/im/push" "gitee.com/vipkwds/im/router" "gitee.com/vipkwds/im/sync" "gitee.com/vipkwds/im/user" ) func main() { // 初始化各管理器 userMgr := user.NewManager() convMgr := conversation.NewManager() msgMgr := message.NewManager(nil) // 传入 MySQL storage customerMgr := customer.NewManager() syncMgr := sync.NewManager() pusher := push.NewDefaultPusher() // 或 push.NewJPusher(appKey, masterSecret) // 创建路由 r := router.NewRouter(userMgr, convMgr, msgMgr, customerMgr, syncMgr, pusher) } ``` ### 2. 消息发送 ```go // 发送文本消息 msg, err := msgMgr.Send(ctx, convID, fromID, toID, []byte("Hello!"), message.ContentTypeText) // 发送图片消息 msg, err := msgMgr.Send(ctx, convID, fromID, toID, []byte(imageData), message.ContentTypeImage) ``` ### 3. 会话管理 ```go // 获取或创建单聊会话 conv := convMgr.GetOrCreateSingleConversation(userID1, userID2) // 创建群聊 members := []string{"user1", "user2", "user3"} groupConv := convMgr.CreateGroupConversation("群名", ownerID, members) // 创建客服会话 customerConv := convMgr.CreateCustomerConversation(visitorID, departmentID) ``` ## 用户状态管理 (user/) ### 状态类型 ```go const ( PresenceOnline Presence = iota // 在线 PresenceAway // 离开 PresenceBusy // 忙碌 PresenceOffline // 离线 ) ``` ### 使用示例 ```go // 注册用户会话 session := user.NewUserSession("user_123", "device_001", 1) userMgr.RegisterSession(session) // 更新状态 userMgr.UpdatePresence("user_123", user.PresenceBusy) // 检查用户是否在线 if userMgr.IsUserOnline("user_123") { // 用户在线 } // 获取用户所有会话 sessions := userMgr.GetUserSessions("user_123") ``` ## 会话管理 (conversation/) ### 会话类型 ```go const ( ConversationTypeSingle ConversationType = iota // 单聊 ConversationTypeGroup // 群聊 ConversationTypeCustomer // 客服 ) ``` ### 单聊使用 ```go // 创建单聊 conv := convMgr.CreateSingleConversation("user_A", "user_B") // 获取或创建(如果已存在则返回) conv = convMgr.GetOrCreateSingleConversation("user_A", "user_B") // 获取两个用户间的单聊 conv, ok := convMgr.GetSingleConversation("user_A", "user_B") // 获取用户的所有会话 convs := convMgr.GetUserConversations("user_A") ``` ### 群聊使用 ```go // 创建群聊 group := convMgr.CreateGroupConversation("技术交流群", ownerID, []string{"user1", "user2", "user3"}) // 添加/移除成员 group.AddParticipant("user4") group.RemoveParticipant("user2") // 检查用户是否为管理员 if group.IsAdmin("user1") { // 是管理员 } ``` ### 客服会话使用 ```go // 创建客服会话 customerConv := convMgr.CreateCustomerConversation(visitorID, departmentID) // 分配坐席 customerConv.AssignAgent(agentID) // 转接会话 customerConv.Transfer(newAgentID, "用户要求转接") // 关闭会话 customerConv.Close() // 关联工单 customerConv.SetTicketID(ticketID) ``` ## 消息管理 (message/) ### 消息类型 ```go const ( ContentTypeText ContentType = iota + 1 // 文本 ContentTypeImage // 图片 ContentTypeVoice // 语音 ContentTypeFile // 文件 ContentTypeVideo // 视频 ContentTypeLocation // 位置 ContentTypeCard // 名片 ) ``` ### 消息状态 ```go const ( MessageStatusSending MessageStatus = iota // 发送中 MessageStatusSent // 已发送 MessageStatusDelivered // 已送达 MessageStatusRead // 已读 ) ``` ### 使用示例 ```go // 发送消息 msg, err := msgMgr.Send(ctx, convID, fromID, toID, []byte("内容"), message.ContentTypeText) // 获取消息 msg, err := msgMgr.GetByID("msg_id") // 分页获取会话消息 messages, err := msgMgr.GetByConv(convID, 50, 0) // limit, offset // 标记已读 err = msgMgr.MarkRead(convID, userID, msgID) // 获取未读消息 unreadMsgs, err := msgMgr.GetUnread(convID, userID) // 撤回消息(仅发送者,5分钟内) err = msgMgr.Recall(ctx, msgID, userID) ``` ### MySQL 存储配置 ```go import "gitee.com/vipkwds/im/message/mysql" db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/im") storage := mysql.NewStorage(db) msgMgr := message.NewManager(storage) ``` ## 客服系统 (customer/) ### 客服排队队列 ```go // 创建部门队列 queue := customer.NewDepartmentQueue() // 访客加入队列 entry := queue.Enqueue(visitorID, departmentID, priority) // priority 越高越优先 // 获取排队位置 position := queue.GetPosition(visitorID, departmentID) // 获取部门等待人数 length := queue.QueueLength(departmentID) // 移除访客(分配给坐席后) queue.Dequeue(departmentID) ``` ### 坐席管理 ```go // 创建坐席 agent := customerMgr.CreateAgent("客服小王", departmentID) // 坐席状态 agent.SetOnline() // 上线 agent.SetBusy(convID) // 忙碌(带会话ID) agent.SetOffline() // 下线 // 接待会话 agent.AcceptConversation(convID) // 结束会话 agent.FinishConversation() // 自动变为在线 // 检查是否可用 if agent.IsAvailable() { // 可接单 } // 获取可用坐席 agent, ok := customerMgr.GetAvailableAgent(departmentID) ``` ### 工单系统 ```go // 创建工单 ticket := customerMgr.CreateTicket(visitorID, departmentID, "问题标题", "问题描述") // 分配坐席 ticket.AssignAgent(agentID) // 更新优先级 ticket.SetPriority(1) // 解决工单 ticket.Resolve() // 关闭工单 ticket.Close() // 重新打开 ticket.Reopen() ``` ### 满意度评价 ```go // 创建评价 rating, err := customerMgr.CreateSatisfactionRating( ticketID, 5, // 1-5星 []string{"态度好", "回复快"}, "非常满意,服务周到" ) // 获取评价 rating, ok := customerMgr.GetRating(ticketID) // 获取平均分 avg := satisfactionMgr.GetAverageRating() // 获取评分分布 dist := satisfactionMgr.GetRatingDistribution() // map[1]:2 map[2]:3 map[3]:5 map[4]:10 map[5]:80 ``` ## 消息路由 (router/) ### 支持的 Action | Action | 说明 | 数据结构 | |--------|------|---------| | `send_message` | 发送消息 | `{to_id, content, content_type, conv_id}` | | `read_message` | 标记已读 | `{conv_id, msg_id}` | | `typing` | 正在输入 | `{conv_id, to_id}` | | `presence_update` | 状态更新 | `{presence}` | | `sync_messages` | 同步消息 | `{conv_id, since}` | | `customer_queue` | 加入排队 | `{department_id, priority}` | | `customer_accept` | 客服接单 | `{visitor_id}` | | `customer_transfer` | 转接会话 | `{conv_id, to_agent_id, reason}` | | `ticket_create` | 创建工单 | `{conv_id, department_id, title, content}` | | `satisfaction_rate` | 满意度评价 | `{ticket_id, rating, tags, comment}` | ### 使用示例 ```go // 创建路由 r := router.NewRouter(userMgr, convMgr, msgMgr, customerMgr, syncMgr, pusher) // 处理请求 req := &router.Request{ Action: router.ActionSendMessage, UserID: "user_123", Data: json.RawMessage(`{"to_id":"user_456","content":"Hello"}`), } resp, err := r.Handle(ctx, req) ``` ## 多端同步 (sync/) ```go // 注册设备 syncMgr.RegisterDevice(userID, deviceID, "ios") // 同步消息到用户所有设备 err := syncMgr.SyncMessage(ctx, userID, msg) // 获取离线消息 offlineMsgs := syncMgr.GetOfflineMessages(userID) // 设置当前设备 syncMgr.SetCurrentDevice(userID, deviceID) // 更新设备最后活跃时间 syncMgr.UpdateDeviceLastSeen(userID, deviceID) ``` ## 离线推送 (push/) ```go // 默认实现(无操作) pusher := push.NewDefaultPusher() // JPush 实现(需配置) pusher := push.NewJPusher(appKey, masterSecret) // 个推实现(需配置) pusher := push.NewGTPusher(appID, appKey, masterSecret) // 发送推送 err := pusher.Push(ctx, userID, msg) // 设置角标 err := pusher.SetBadge(ctx, userID, 5) ``` ## 数据库表结构 ```sql -- 用户表 CREATE TABLE users ( id VARCHAR(64) PRIMARY KEY, nickname VARCHAR(128), avatar VARCHAR(256), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 会话表 CREATE TABLE conversations ( id VARCHAR(64) PRIMARY KEY, type TINYINT NOT NULL, owner_id VARCHAR(64), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_owner (owner_id) ); -- 会话参与者 CREATE TABLE conversation_participants ( conv_id VARCHAR(64), user_id VARCHAR(64), PRIMARY KEY (conv_id, user_id) ); -- 消息表 CREATE TABLE messages ( id VARCHAR(64) PRIMARY KEY, conv_id VARCHAR(64) NOT NULL, from_id VARCHAR(64) NOT NULL, to_id VARCHAR(64) NOT NULL, content_type TINYINT, content MEDIUMBLOB, seq BIGINT, status TINYINT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_conv (conv_id, created_at), INDEX idx_seq (seq) ); -- 消息已读状态 CREATE TABLE message_reads ( conv_id VARCHAR(64), user_id VARCHAR(64), msg_id VARCHAR(64), read_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (conv_id, user_id, msg_id) ); -- 客服坐席 CREATE TABLE customer_agents ( id VARCHAR(64) PRIMARY KEY, name VARCHAR(128), department_id VARCHAR(64), status TINYINT DEFAULT 0, today_count INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 客服部门 CREATE TABLE customer_departments ( id VARCHAR(64) PRIMARY KEY, name VARCHAR(128), parent_id VARCHAR(64) ); -- 客服排队 CREATE TABLE customer_queue ( id VARCHAR(64) PRIMARY KEY, visitor_id VARCHAR(64), department_id VARCHAR(64), wait_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, priority INT DEFAULT 0 ); -- 工单 CREATE TABLE customer_tickets ( id VARCHAR(64) PRIMARY KEY, conv_id VARCHAR(64), visitor_id VARCHAR(64), agent_id VARCHAR(64), status TINYINT DEFAULT 0, priority INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, resolved_at TIMESTAMP NULL ); -- 满意度评价 CREATE TABLE customer_satisfactions ( id VARCHAR(64) PRIMARY KEY, ticket_id VARCHAR(64), rating TINYINT, tags VARCHAR(512), comment TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` ## WebSocket 消息协议 ### 请求格式 ```json { "action": "send_message", "session_id": 12345, "user_id": "user_123", "data": { "to_id": "user_456", "content": "Hello!", "content_type": 1, "conv_id": "" } } ``` ### 响应格式 ```json { "action": "send_message", "code": 200, "message": "", "data": { "id": "msg_123456", "conv_id": "conv_single_user123_user456", "from_id": "user_123", "to_id": "user_456", "content": "Hello!", "content_type": 1, "seq": 1, "status": 2, "timestamp": "2024-01-01T12:00:00Z" } } ``` ## 验证 ```bash # 编译检查 go build ./... # 代码检查 go vet ./... # 格式化 go fmt ./... # 运行测试 go test ./... # 模块验证 go mod verify ``` ## 依赖 - Go 1.21+ - github.com/gorilla/websocket v1.5.1 ## 许可 MIT License