2020-11-30 00:57:58 +00:00
|
|
|
package defaultstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2021-11-03 22:16:02 +00:00
|
|
|
"fmt"
|
2020-11-30 00:57:58 +00:00
|
|
|
"sync"
|
|
|
|
|
2021-06-02 02:53:19 +00:00
|
|
|
"github.com/diamondburned/arikawa/v3/discord"
|
|
|
|
"github.com/diamondburned/arikawa/v3/state/store"
|
2020-11-30 00:57:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Channel struct {
|
|
|
|
mut sync.RWMutex
|
|
|
|
|
|
|
|
// Channel references must be protected under the same mutex.
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
channels map[discord.ChannelID]discord.Channel
|
|
|
|
privates map[discord.UserID]discord.ChannelID
|
|
|
|
guildChs map[discord.GuildID][]discord.ChannelID
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ store.ChannelStore = (*Channel)(nil)
|
|
|
|
|
|
|
|
func NewChannel() *Channel {
|
|
|
|
return &Channel{
|
2021-11-03 22:16:02 +00:00
|
|
|
channels: map[discord.ChannelID]discord.Channel{},
|
|
|
|
privates: map[discord.UserID]discord.ChannelID{},
|
|
|
|
guildChs: map[discord.GuildID][]discord.ChannelID{},
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Channel) Reset() error {
|
|
|
|
s.mut.Lock()
|
|
|
|
defer s.mut.Unlock()
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
s.channels = map[discord.ChannelID]discord.Channel{}
|
|
|
|
s.privates = map[discord.UserID]discord.ChannelID{}
|
|
|
|
s.guildChs = map[discord.GuildID][]discord.ChannelID{}
|
2020-11-30 00:57:58 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Channel) Channel(id discord.ChannelID) (*discord.Channel, error) {
|
|
|
|
s.mut.RLock()
|
|
|
|
defer s.mut.RUnlock()
|
|
|
|
|
|
|
|
ch, ok := s.channels[id]
|
|
|
|
if !ok {
|
|
|
|
return nil, store.ErrNotFound
|
|
|
|
}
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
return &ch, nil
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Channel) CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error) {
|
|
|
|
s.mut.RLock()
|
|
|
|
defer s.mut.RUnlock()
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
id, ok := s.privates[recipient]
|
2020-11-30 00:57:58 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, store.ErrNotFound
|
|
|
|
}
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
cpy := s.channels[id]
|
2020-11-30 00:57:58 +00:00
|
|
|
return &cpy, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Channels returns a list of Guild channels randomly ordered.
|
|
|
|
func (s *Channel) Channels(guildID discord.GuildID) ([]discord.Channel, error) {
|
|
|
|
s.mut.RLock()
|
|
|
|
defer s.mut.RUnlock()
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
chIDs, ok := s.guildChs[guildID]
|
2020-11-30 00:57:58 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, store.ErrNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reading chRefs is also covered by the global mutex.
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
var channels = make([]discord.Channel, 0, len(chIDs))
|
|
|
|
for _, chID := range chIDs {
|
|
|
|
ch, ok := s.channels[chID]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
channels = append(channels, ch)
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return channels, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrivateChannels returns a list of Direct Message channels randomly ordered.
|
|
|
|
func (s *Channel) PrivateChannels() ([]discord.Channel, error) {
|
|
|
|
s.mut.RLock()
|
|
|
|
defer s.mut.RUnlock()
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
groupDMs := s.guildChs[0]
|
|
|
|
|
|
|
|
if len(s.privates) == 0 && len(groupDMs) == 0 {
|
2020-11-30 00:57:58 +00:00
|
|
|
return nil, store.ErrNotFound
|
|
|
|
}
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
var channels = make([]discord.Channel, 0, len(s.privates)+len(groupDMs))
|
|
|
|
for _, chID := range s.privates {
|
|
|
|
if ch, ok := s.channels[chID]; ok {
|
|
|
|
channels = append(channels, ch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, chID := range groupDMs {
|
|
|
|
if ch, ok := s.channels[chID]; ok {
|
|
|
|
channels = append(channels, ch)
|
|
|
|
}
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return channels, nil
|
|
|
|
}
|
|
|
|
|
2020-12-19 06:18:04 +00:00
|
|
|
// ChannelSet sets the Direct Message or Guild channel into the state.
|
2021-11-03 22:16:02 +00:00
|
|
|
func (s *Channel) ChannelSet(channel *discord.Channel, update bool) error {
|
|
|
|
cpy := *channel
|
|
|
|
|
2020-11-30 00:57:58 +00:00
|
|
|
s.mut.Lock()
|
|
|
|
defer s.mut.Unlock()
|
|
|
|
|
|
|
|
// Update the reference if we can.
|
2021-11-03 22:16:02 +00:00
|
|
|
s.channels[channel.ID] = cpy
|
2020-11-30 00:57:58 +00:00
|
|
|
|
2020-12-19 06:18:04 +00:00
|
|
|
switch channel.Type {
|
|
|
|
case discord.DirectMessage:
|
|
|
|
// Safety bound check.
|
|
|
|
if len(channel.DMRecipients) != 1 {
|
2021-11-03 22:16:02 +00:00
|
|
|
return fmt.Errorf("DirectMessage channel %d doesn't have 1 recipient", channel.ID)
|
2020-12-19 06:18:04 +00:00
|
|
|
}
|
2021-11-03 22:16:02 +00:00
|
|
|
s.privates[channel.DMRecipients[0].ID] = channel.ID
|
|
|
|
return nil
|
2020-12-19 06:18:04 +00:00
|
|
|
case discord.GroupDM:
|
2021-11-03 22:16:02 +00:00
|
|
|
s.guildChs[0] = addChannelID(s.guildChs[0], channel.ID)
|
2020-11-30 00:57:58 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-19 06:18:04 +00:00
|
|
|
// Ensure that if the channel is not a DM or group DM channel, then it must
|
|
|
|
// have a valid guild ID.
|
2020-11-30 00:57:58 +00:00
|
|
|
if !channel.GuildID.IsValid() {
|
|
|
|
return errors.New("invalid guildID for guild channel")
|
|
|
|
}
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
s.guildChs[channel.GuildID] = addChannelID(s.guildChs[channel.GuildID], channel.ID)
|
2020-11-30 00:57:58 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
func (s *Channel) ChannelRemove(channel *discord.Channel) error {
|
2020-11-30 00:57:58 +00:00
|
|
|
s.mut.Lock()
|
|
|
|
defer s.mut.Unlock()
|
|
|
|
|
2020-12-19 06:18:04 +00:00
|
|
|
// Wipe the channel off the channel ID index.
|
2020-11-30 00:57:58 +00:00
|
|
|
delete(s.channels, channel.ID)
|
|
|
|
|
2020-12-19 06:18:04 +00:00
|
|
|
// Wipe the channel off the DM recipient index, if available.
|
|
|
|
switch channel.Type {
|
|
|
|
case discord.DirectMessage:
|
|
|
|
// Safety bound check.
|
|
|
|
if len(channel.DMRecipients) != 1 {
|
2021-11-03 22:16:02 +00:00
|
|
|
return fmt.Errorf("DirectMessage channel %d doesn't have 1 recipient", channel.ID)
|
2020-12-19 06:18:04 +00:00
|
|
|
}
|
2020-11-30 00:57:58 +00:00
|
|
|
delete(s.privates, channel.DMRecipients[0].ID)
|
2021-11-03 22:16:02 +00:00
|
|
|
return nil
|
2020-12-19 06:18:04 +00:00
|
|
|
case discord.GroupDM:
|
2021-11-03 22:16:02 +00:00
|
|
|
s.guildChs[0] = removeChannelID(s.guildChs[0], channel.ID)
|
2020-11-30 00:57:58 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
s.guildChs[channel.GuildID] = removeChannelID(s.guildChs[channel.GuildID], channel.ID)
|
|
|
|
return nil
|
|
|
|
}
|
2020-11-30 00:57:58 +00:00
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
func addChannelID(channels []discord.ChannelID, id discord.ChannelID) []discord.ChannelID {
|
|
|
|
for _, ch := range channels {
|
|
|
|
if ch == id {
|
|
|
|
return channels
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
|
|
|
}
|
2021-11-03 22:16:02 +00:00
|
|
|
if channels == nil {
|
|
|
|
channels = make([]discord.ChannelID, 0, 5)
|
|
|
|
}
|
|
|
|
return append(channels, id)
|
2020-11-30 00:57:58 +00:00
|
|
|
}
|
2020-12-19 06:18:04 +00:00
|
|
|
|
2021-11-03 22:16:02 +00:00
|
|
|
// removeChannelID removes the given channel with the index from the given
|
2020-12-19 06:18:04 +00:00
|
|
|
// channels slice in an unordered fashion.
|
2021-11-03 22:16:02 +00:00
|
|
|
func removeChannelID(channels []discord.ChannelID, id discord.ChannelID) []discord.ChannelID {
|
|
|
|
for i, ch := range channels {
|
|
|
|
if ch == id {
|
|
|
|
// Move the last channel to the current channel, then slice the last
|
|
|
|
// channel off.
|
|
|
|
channels[i] = channels[len(channels)-1]
|
|
|
|
channels = channels[:len(channels)-1]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2020-12-19 06:18:04 +00:00
|
|
|
return channels
|
|
|
|
}
|