98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
"xboard-go/internal/database"
|
|
)
|
|
|
|
const deviceStateTTL = 10 * time.Minute
|
|
|
|
type userDevicesSnapshot map[string][]string
|
|
|
|
func SaveUserNodeDevices(userID, nodeID int, ips []string) error {
|
|
unique := make([]string, 0, len(ips))
|
|
seen := make(map[string]struct{})
|
|
for _, ip := range ips {
|
|
trimmed := strings.TrimSpace(ip)
|
|
if trimmed == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[trimmed]; ok {
|
|
continue
|
|
}
|
|
seen[trimmed] = struct{}{}
|
|
unique = append(unique, trimmed)
|
|
}
|
|
sort.Strings(unique)
|
|
|
|
return database.CacheSet(deviceStateKey(userID, nodeID), unique, deviceStateTTL)
|
|
}
|
|
|
|
func GetUsersDevices(userIDs []int) map[int][]string {
|
|
result := make(map[int][]string, len(userIDs))
|
|
|
|
for _, userID := range userIDs {
|
|
snapshot, ok := database.CacheGetJSON[userDevicesSnapshot](deviceStateUserIndexKey(userID))
|
|
if !ok {
|
|
result[userID] = []string{}
|
|
continue
|
|
}
|
|
|
|
merged := make([]string, 0)
|
|
seen := make(map[string]struct{})
|
|
for _, ips := range snapshot {
|
|
for _, ip := range ips {
|
|
if _, exists := seen[ip]; exists {
|
|
continue
|
|
}
|
|
seen[ip] = struct{}{}
|
|
merged = append(merged, ip)
|
|
}
|
|
}
|
|
sort.Strings(merged)
|
|
result[userID] = merged
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func SetDevices(userID, nodeID int, ips []string) error {
|
|
if err := SaveUserNodeDevices(userID, nodeID, ips); err != nil {
|
|
return err
|
|
}
|
|
|
|
indexKey := deviceStateUserIndexKey(userID)
|
|
indexSnapshot, _ := database.CacheGetJSON[userDevicesSnapshot](indexKey)
|
|
indexSnapshot[fmt.Sprintf("%d", nodeID)] = normalizeIPs(ips)
|
|
return database.CacheSet(indexKey, indexSnapshot, deviceStateTTL)
|
|
}
|
|
|
|
func normalizeIPs(ips []string) []string {
|
|
seen := make(map[string]struct{})
|
|
result := make([]string, 0, len(ips))
|
|
for _, ip := range ips {
|
|
ip = strings.TrimSpace(ip)
|
|
if ip == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[ip]; ok {
|
|
continue
|
|
}
|
|
seen[ip] = struct{}{}
|
|
result = append(result, ip)
|
|
}
|
|
sort.Strings(result)
|
|
return result
|
|
}
|
|
|
|
func deviceStateKey(userID, nodeID int) string {
|
|
return fmt.Sprintf("device_state:user:%d:node:%d", userID, nodeID)
|
|
}
|
|
|
|
func deviceStateUserIndexKey(userID int) string {
|
|
return fmt.Sprintf("device_state:user:%d:index", userID)
|
|
}
|