cchat-discord/internal/discord/state/labels/labels.go

179 lines
3.8 KiB
Go

package labels
import (
"sync"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/gateway"
"github.com/diamondburned/cchat"
"github.com/diamondburned/ningen/v2"
)
// Repository is a repository containing LabelContainers. It watches for update
// events from the gateway.
//
// If a labeler that is already registered were to be added again, then the
// adder function will do nothing and will return a callback that does nothing.
type Repository struct {
state *ningen.State
detachs []func()
stopped bool
mutex sync.Mutex
stores labelContainers
}
// NewRepository creates a new repository.
func NewRepository(state *ningen.State) *Repository {
r := Repository{
state: state,
stores: newLabelContainers(),
}
r.detachs = []func(){
state.AddHandler(r.onGuildUpdate),
state.AddHandler(r.onMemberUpdate),
state.AddHandler(r.onMemberRemove),
state.AddHandler(r.onChannelUpdate),
state.AddHandler(r.onChannelDelete),
}
return &r
}
func (r *Repository) onGuildUpdate(ev *gateway.GuildUpdateEvent) {
r.mutex.Lock()
defer r.mutex.Unlock()
if r.stopped {
return
}
guild, ok := r.stores.guilds[ev.ID]
if !ok {
return
}
rich := labelGuild(r.state, ev.ID)
for labeler := range guild.guild {
labeler.SetLabel(rich)
}
}
// AddGuildLabel adds a label to display the given guild ID. Refer to Repository
// for more documentation.
func (r *Repository) AddGuildLabel(guildID discord.GuildID, l cchat.LabelContainer) func() {
l.SetLabel(labelGuild(r.state, guildID))
r.mutex.Lock()
defer r.mutex.Unlock()
guild, _ := r.stores.guilds[guildID]
guild.guild.Add(l)
r.stores.guilds[guildID] = guild
return func() {
r.mutex.Lock()
defer r.mutex.Unlock()
guild, _ := r.stores.guilds[guildID]
guild.guild.Remove(l)
if guild.IsEmpty() {
delete(r.stores.guilds, guildID)
return
}
r.stores.guilds[guildID] = guild
}
}
func (r *Repository) onMemberRemove(ev *gateway.GuildMemberRemoveEvent) {}
func (r *Repository) onMemberUpdate(ev *gateway.GuildMemberUpdateEvent) {}
// AddMemberLabel adds a label to display the given member live. Refer to
// Repository for more documentation.
func (r *Repository) AddMemberLabel(
guildID discord.GuildID, userID discord.UserID, l cchat.LabelContainer) func() {
l.SetLabel(labelMember(r.state, guildID, userID))
r.mutex.Lock()
defer r.mutex.Unlock()
guild, _ := r.stores.guilds[guildID]
llist := guild.members[userID]
llist.Add(l)
if guild.members == nil {
guild.members = make(map[discord.UserID]labelerList, 1)
}
guild.members[userID] = llist
r.stores.guilds[guildID] = guild
return func() {
r.mutex.Lock()
defer r.mutex.Unlock()
guild, _ := r.stores.guilds[guildID]
llist := guild.members[userID]
llist.Remove(l)
if guild.IsEmpty() {
delete(r.stores.guilds, guildID)
return
}
guild.members[userID] = llist
r.stores.guilds[guildID] = guild
}
}
func (r *Repository) onChannelUpdate(ev *gateway.ChannelUpdateEvent) {}
func (r *Repository) onChannelDelete(ev *gateway.ChannelDeleteEvent) {}
// AddChannelLabel adds a label to display the given channel live. Refer to
// Repository for more documentation.
func (r *Repository) AddChannelLabel(chID discord.ChannelID, l cchat.LabelContainer) func() {
l.SetLabel(labelChannel(r.state, chID))
r.mutex.Lock()
defer r.mutex.Unlock()
llist := r.stores.channels[chID]
llist.Add(l)
r.stores.channels[chID] = llist
return func() {
r.mutex.Lock()
defer r.mutex.Unlock()
llist := r.stores.channels[chID]
llist.Remove(l)
if len(llist) == 0 {
delete(r.stores.channels, chID)
return
}
r.stores.channels[chID] = llist
}
}
// Stop detaches all handlers.
func (r *Repository) Stop() {
r.mutex.Lock()
defer r.mutex.Unlock()
r.stopped = true
for _, detach := range r.detachs {
detach()
}
}