// Package centrifugo 提供 Centrifugo 即時訊息服務的完整 Go 客戶端 // // 功能包含: // - HTTP API 客戶端(發布訊息、訂閱管理、在線狀態等) // - JWT Token 生成(連線認證、私有頻道訂閱) // - Token 黑名單管理(撤銷單一 Token、撤銷用戶所有 Token) // - 在線狀態追蹤(Redis 或記憶體存儲) // // 基本使用: // // // 創建服務實例 // svc := centrifugo.NewService(centrifugo.ServiceConfig{ // APIURL: "http://localhost:8000", // APIKey: "your-api-key", // TokenSecret: "your-jwt-secret", // Redis: redisClient, // 可選,用於黑名單和在線狀態 // }) // // // 發布訊息 // svc.Client().PublishJSON(ctx, "chat:room-1", data) // // // 生成 Token // token, _ := svc.Token().QuickConnectionToken("user-123") // // // 撤銷用戶所有 Token 並踢出 // svc.InvalidateUser(ctx, "user-123") package centrifugo import ( "context" "time" "github.com/zeromicro/go-zero/core/stores/redis" ) // Service Centrifugo 服務整合介面 // 提供 HTTP API、Token 生成、黑名單管理、在線狀態追蹤的統一入口 type Service struct { client *Client token *TokenGenerator blacklist *TokenBlacklist online *OnlineManager } // ServiceConfig 服務配置 type ServiceConfig struct { // APIURL Centrifugo HTTP API 地址(必填) APIURL string // APIKey Centrifugo API 密鑰(必填) APIKey string // TokenSecret JWT Token 簽名密鑰(必填) TokenSecret string // TokenExpire Token 過期時間(預設 1 小時) TokenExpire time.Duration // Redis 客戶端(可選,用於黑名單和在線狀態) Redis *redis.Redis // ClientConfig HTTP 客戶端配置(可選) ClientConfig *ClientConfig // OnlineTTL 在線狀態過期時間(預設 5 分鐘) OnlineTTL time.Duration // KeyPrefix Redis key 前綴(預設 "centrifugo:") KeyPrefix string } // NewService 創建 Centrifugo 服務實例 func NewService(cfg ServiceConfig) *Service { // 設定預設值 if cfg.TokenExpire == 0 { cfg.TokenExpire = time.Hour } if cfg.OnlineTTL == 0 { cfg.OnlineTTL = 5 * time.Minute } if cfg.KeyPrefix == "" { cfg.KeyPrefix = "centrifugo:" } // 創建 HTTP 客戶端 var client *Client if cfg.ClientConfig != nil { client = NewClientWithConfig(*cfg.ClientConfig) } else { client = NewClient(cfg.APIURL, cfg.APIKey) } // 創建 Token 生成器 token := NewTokenGeneratorWithConfig(TokenConfig{ Secret: cfg.TokenSecret, ExpireIn: cfg.TokenExpire, }) svc := &Service{ client: client, token: token, } // 如果有 Redis,創建黑名單管理器和在線狀態管理器 if cfg.Redis != nil { svc.blacklist = NewTokenBlacklistWithPrefix(cfg.Redis, cfg.KeyPrefix+"blacklist:") store := NewRedisOnlineStoreWithPrefix(cfg.Redis, cfg.KeyPrefix+"online:") svc.online = NewOnlineManagerWithTTL(client, store, cfg.OnlineTTL) } return svc } // Client 返回 HTTP API 客戶端 func (s *Service) Client() *Client { return s.client } // Token 返回 Token 生成器 func (s *Service) Token() *TokenGenerator { return s.token } // Blacklist 返回黑名單管理器(可能為 nil) func (s *Service) Blacklist() *TokenBlacklist { return s.blacklist } // Online 返回在線狀態管理器(可能為 nil) func (s *Service) Online() *OnlineManager { return s.online } // ==================== 便捷方法 ==================== // PublishJSON 發布 JSON 訊息到頻道 func (s *Service) PublishJSON(ctx context.Context, channel string, data interface{}) (*PublishResult, error) { return s.client.PublishJSON(ctx, channel, data) } // BroadcastJSON 批量發布 JSON 訊息到多個頻道 func (s *Service) BroadcastJSON(ctx context.Context, channels []string, data interface{}) error { return s.client.BroadcastJSON(ctx, channels, data) } // Disconnect 斷開用戶連線 func (s *Service) Disconnect(ctx context.Context, userID string) error { return s.client.Disconnect(ctx, userID) } // GenerateToken 快速生成連線 Token func (s *Service) GenerateToken(userID string) (string, error) { return s.token.QuickConnectionToken(userID) } // GenerateTokenWithInfo 生成帶用戶資訊的連線 Token func (s *Service) GenerateTokenWithInfo(userID string, info map[string]interface{}) (string, error) { return s.token.GenerateConnectionToken(ConnectionTokenOptions{ UserID: userID, Info: info, }) } // InvalidateUser 撤銷用戶所有 Token 並斷開連線 // 這是最常用的「踢人」方法,適用於: // - 用戶被封禁 // - 密碼變更 // - 用戶登出(全設備) func (s *Service) InvalidateUser(ctx context.Context, userID string) error { // 撤銷所有 Token if s.blacklist != nil { if err := s.blacklist.RevokeUserTokens(ctx, userID); err != nil { return err } } // 斷開連線 return s.client.Disconnect(ctx, userID) } // IsUserOnline 檢查用戶是否在線 func (s *Service) IsUserOnline(ctx context.Context, userID string) (bool, error) { if s.online == nil { return false, ErrOnlineStoreNotConfigured } return s.online.IsUserOnline(ctx, userID) } // GetUsersOnlineStatus 批量獲取用戶在線狀態 func (s *Service) GetUsersOnlineStatus(ctx context.Context, userIDs []string) (map[string]bool, error) { if s.online == nil { return nil, ErrOnlineStoreNotConfigured } return s.online.GetUsersOnlineStatus(ctx, userIDs) }