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,
|
|||
|
}
|
|||
|
}
|