package chat import ( "encoding/json" "log/slog" "os" "path/filepath" "sync" "github.com/ayn2op/discordo/internal/consts" "github.com/diamondburned/arikawa/v3/discord" ) type guildState struct { ExpandedGuilds map[discord.GuildID]bool `json:"expanded_guilds"` ExpandedChannels map[discord.ChannelID]bool `json:"expanded_channels,omitempty"` mu sync.RWMutex } var stateFilePath = filepath.Join(consts.CacheDir(), "state.json") func loadGuildState() *guildState { gs := &guildState{ ExpandedGuilds: make(map[discord.GuildID]bool), ExpandedChannels: make(map[discord.ChannelID]bool), } data, err := os.ReadFile(stateFilePath) if err != nil { return gs } if err := json.Unmarshal(data, gs); err != nil { slog.Warn("failed to parse guild state", "err", err) return &guildState{ ExpandedGuilds: make(map[discord.GuildID]bool), ExpandedChannels: make(map[discord.ChannelID]bool), } } if gs.ExpandedGuilds == nil { gs.ExpandedGuilds = make(map[discord.GuildID]bool) } if gs.ExpandedChannels == nil { gs.ExpandedChannels = make(map[discord.ChannelID]bool) } return gs } func (gs *guildState) save() { gs.mu.Lock() defer gs.mu.Unlock() atomicSaveJSON(stateFilePath, gs) } func (gs *guildState) setExpanded(id discord.GuildID, expanded bool) { gs.mu.Lock() if expanded { gs.ExpandedGuilds[id] = true } else { delete(gs.ExpandedGuilds, id) } gs.mu.Unlock() gs.save() } func (gs *guildState) isExpanded(id discord.GuildID) bool { gs.mu.RLock() defer gs.mu.RUnlock() return gs.ExpandedGuilds[id] } func (gs *guildState) setChannelExpanded(id discord.ChannelID, expanded bool) { gs.mu.Lock() if expanded { gs.ExpandedChannels[id] = true } else { delete(gs.ExpandedChannels, id) } gs.mu.Unlock() gs.save() } func (gs *guildState) isChannelExpanded(id discord.ChannelID, defaultExpanded bool) bool { gs.mu.RLock() defer gs.mu.RUnlock() if v, ok := gs.ExpandedChannels[id]; ok { return v } return defaultExpanded }