259 lines
5.3 KiB
Go
259 lines
5.3 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/cchat-discord/internal/funcutil"
|
|
"github.com/diamondburned/cchat-discord/internal/segments/mention"
|
|
"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
|
|
detach 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.detach = funcutil.JoinCancels(
|
|
state.AddHandler(r.onGuildUpdate),
|
|
state.AddHandler(r.onMemberUpdate),
|
|
state.AddHandler(r.onMemberRemove),
|
|
state.AddHandler(r.onChannelUpdate),
|
|
state.AddHandler(r.onChannelDelete),
|
|
state.AddHandler(r.onGuildMembersChunk),
|
|
// TODO: *gateway.GuildMemberListUpdate
|
|
)
|
|
|
|
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 := mention.NewGuildText(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(mention.NewGuildText(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) {
|
|
// Not sure what to do.
|
|
}
|
|
|
|
func (r *Repository) onMemberUpdate(ev *gateway.GuildMemberUpdateEvent) {
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
|
|
if r.stopped {
|
|
return
|
|
}
|
|
|
|
guild, _ := r.stores.guilds[ev.GuildID]
|
|
member, ok := guild.members[ev.User.ID]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
rich := mention.NewMemberText(r.state, ev.GuildID, ev.User.ID)
|
|
|
|
for labeler := range member {
|
|
labeler.SetLabel(rich)
|
|
}
|
|
}
|
|
|
|
func (r *Repository) onGuildMembersChunk(chunk *gateway.GuildMembersChunkEvent) {
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
|
|
if r.stopped {
|
|
return
|
|
}
|
|
|
|
guild, ok := r.stores.guilds[chunk.GuildID]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
for _, member := range chunk.Members {
|
|
m, ok := guild.members[member.User.ID]
|
|
if ok {
|
|
rich := mention.NewMemberText(r.state, chunk.GuildID, member.User.ID)
|
|
|
|
for labeler := range m {
|
|
labeler.SetLabel(rich)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// AddMemberLabel adds a label to display the given member live. If the given
|
|
// guildID is not valid, then AddPresenceLabel will be called. Refer to
|
|
// Repository for more documentation.
|
|
func (r *Repository) AddMemberLabel(
|
|
guildID discord.GuildID, userID discord.UserID, l cchat.LabelContainer) func() {
|
|
|
|
if !guildID.IsValid() {
|
|
return r.AddPresenceLabel(userID, l)
|
|
}
|
|
|
|
l.SetLabel(mention.NewMemberText(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) onChannelDelete(ev *gateway.ChannelDeleteEvent) {
|
|
// Not sure what to do.
|
|
}
|
|
|
|
func (r *Repository) onChannelUpdate(ev *gateway.ChannelUpdateEvent) {
|
|
r.mutex.Lock()
|
|
defer r.mutex.Unlock()
|
|
|
|
if r.stopped {
|
|
return
|
|
}
|
|
|
|
channel, ok := r.stores.channels[ev.ID]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
rich := mention.NewChannelText(r.state, ev.ID)
|
|
|
|
for labeler := range channel {
|
|
labeler.SetLabel(rich)
|
|
}
|
|
}
|
|
|
|
// 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(mention.NewChannelText(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
|
|
}
|
|
}
|
|
|
|
func (r *Repository) AddPresenceLabel(uID discord.UserID, l cchat.LabelContainer) func() {
|
|
// TODO: Presence update events
|
|
// TODO: user fallbacks
|
|
panic("Implement me")
|
|
return nil
|
|
}
|
|
|
|
// Stop detaches all handlers.
|
|
func (r *Repository) Stop() {
|
|
r.mutex.Lock()
|
|
r.stopped = true
|
|
r.mutex.Unlock()
|
|
|
|
r.detach()
|
|
}
|