backend/pkg/library/centrifugo/centrifugo.go

188 lines
5.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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)
}