105 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			105 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | package repository | |||
|  | 
 | |||
|  | import ( | |||
|  | 	"app-cloudep-permission-server/internal/domain/repository" | |||
|  | 	"code.30cm.net/digimon/library-go/utils/invited_code" | |||
|  | 	"context" | |||
|  | 	"fmt" | |||
|  | 	"github.com/zeromicro/go-zero/core/stores/redis" | |||
|  | ) | |||
|  | 
 | |||
|  | type MemberOnlineStatusRepositoryParam struct { | |||
|  | 	Store *redis.Redis `name:"redis"` | |||
|  | } | |||
|  | 
 | |||
|  | type memberOnlineStatusRepository struct { | |||
|  | 	store *redis.Redis | |||
|  | } | |||
|  | 
 | |||
|  | // 使用 UID 計算 Bitmap 的 offset
 | |||
|  | func (t *memberOnlineStatusRepository) uidToOffset(uid string) (int64, error) { | |||
|  | 	converter := invited_code.MustConverter(10, invited_code.DefaultCodeLen, invited_code.ConvertTable) | |||
|  | 
 | |||
|  | 	// 將 UID 轉換為整數型,並減去基礎 UID (1000000)
 | |||
|  | 	uidInt, err := converter.DecodeFromCode(uid) | |||
|  | 	if err != nil { | |||
|  | 		return 0, fmt.Errorf("invalid UID: %w", err) | |||
|  | 	} | |||
|  | 	// 以 1000000 作為基準
 | |||
|  | 	baseUID := invited_code.InitAutoId | |||
|  | 	if uidInt < int64(baseUID) { | |||
|  | 		return 0, fmt.Errorf("UID smaller than base: %d", baseUID) | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return uidInt - int64(baseUID), nil | |||
|  | } | |||
|  | 
 | |||
|  | func (t *memberOnlineStatusRepository) SetMemberOnline(ctx context.Context, uid string) (bool, error) { | |||
|  | 	offset, err := t.uidToOffset(uid) | |||
|  | 	if err != nil { | |||
|  | 		return false, err | |||
|  | 	} | |||
|  | 
 | |||
|  | 	// 使用 SET BIT 設置對應的位為 1
 | |||
|  | 	_, err = t.store.SetBit("member_status", offset, 1) | |||
|  | 	if err != nil { | |||
|  | 		return false, fmt.Errorf("failed to set member online: %w", err) | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return true, nil | |||
|  | } | |||
|  | 
 | |||
|  | func (t *memberOnlineStatusRepository) SetMemberOffline(ctx context.Context, uid string) (bool, error) { | |||
|  | 	offset, err := t.uidToOffset(uid) | |||
|  | 	if err != nil { | |||
|  | 		return false, err | |||
|  | 	} | |||
|  | 
 | |||
|  | 	// 使用 SET BIT 設置對應的位為 1
 | |||
|  | 	_, err = t.store.SetBit("member_status", offset, 0) | |||
|  | 	if err != nil { | |||
|  | 		return false, fmt.Errorf("failed to set member offline: %w", err) | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return true, nil | |||
|  | } | |||
|  | 
 | |||
|  | func (t *memberOnlineStatusRepository) IsMemberOnline(ctx context.Context, uid string) (bool, error) { | |||
|  | 	offset, err := t.uidToOffset(uid) | |||
|  | 	if err != nil { | |||
|  | 		return false, err | |||
|  | 	} | |||
|  | 
 | |||
|  | 	// 使用 GET BIT 獲取對應的位,1 表示在線,0 表示離線
 | |||
|  | 	status, err := t.store.GetBit("member_status", offset) | |||
|  | 	if err != nil { | |||
|  | 		return false, fmt.Errorf("failed to get member status: %w", err) | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return status == 1, nil | |||
|  | } | |||
|  | 
 | |||
|  | func (t *memberOnlineStatusRepository) QueryMemberOnlineList(ctx context.Context, uids []string) ([]repository.MemberOnlineStatusResp, error) { | |||
|  | 	statusMap := make([]repository.MemberOnlineStatusResp, 0, len(uids)) | |||
|  | 
 | |||
|  | 	// 遍歷所有用戶的 UID,查詢他們的在線狀態
 | |||
|  | 	for _, uid := range uids { | |||
|  | 		isOnline, err := t.IsMemberOnline(ctx, uid) | |||
|  | 		if err != nil { | |||
|  | 			return nil, fmt.Errorf("failed to query member status for UID %s: %w", uid, err) | |||
|  | 		} | |||
|  | 		statusMap = append(statusMap, repository.MemberOnlineStatusResp{ | |||
|  | 			UID:    uid, | |||
|  | 			Status: isOnline, | |||
|  | 		}) | |||
|  | 	} | |||
|  | 
 | |||
|  | 	return statusMap, nil | |||
|  | } | |||
|  | 
 | |||
|  | func NewMemberOnlineStatusRepository(param MemberOnlineStatusRepositoryParam) repository.MemberOnlineStatusRepository { | |||
|  | 	return &memberOnlineStatusRepository{ | |||
|  | 		store: param.Store, | |||
|  | 	} | |||
|  | } |