1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-12-01 11:12:48 +00:00
arikawa/state/store_default.go

619 lines
10 KiB
Go

package state
import (
"sort"
"sync"
"github.com/diamondburned/arikawa/discord"
)
// TODO: make an ExpiryStore
type DefaultStore struct {
*DefaultStoreOptions
self discord.User
// includes normal and private
privates map[discord.Snowflake]*discord.Channel // channelID:channel
guilds map[discord.Snowflake]*discord.Guild // guildID:guild
messages map[discord.Snowflake][]discord.Message // channelID:messages
mut sync.Mutex
}
type DefaultStoreOptions struct {
MaxMessages uint // default 50
}
var _ Store = (*DefaultStore)(nil)
func NewDefaultStore(opts *DefaultStoreOptions) *DefaultStore {
if opts == nil {
opts = &DefaultStoreOptions{
MaxMessages: 50,
}
}
return &DefaultStore{
DefaultStoreOptions: opts,
privates: map[discord.Snowflake]*discord.Channel{},
guilds: map[discord.Snowflake]*discord.Guild{},
messages: map[discord.Snowflake][]discord.Message{},
}
}
func (s *DefaultStore) Reset() error {
s.mut.Lock()
defer s.mut.Unlock()
s.self = discord.User{}
s.privates = map[discord.Snowflake]*discord.Channel{}
s.guilds = map[discord.Snowflake]*discord.Guild{}
s.messages = map[discord.Snowflake][]discord.Message{}
return nil
}
////
func (s *DefaultStore) Self() (*discord.User, error) {
s.mut.Lock()
defer s.mut.Unlock()
if !s.self.ID.Valid() {
return nil, ErrStoreNotFound
}
return &s.self, nil
}
func (s *DefaultStore) SelfSet(me *discord.User) error {
s.mut.Lock()
s.self = *me
s.mut.Unlock()
return nil
}
////
func (s *DefaultStore) Channel(id discord.Snowflake) (*discord.Channel, error) {
s.mut.Lock()
defer s.mut.Unlock()
for _, g := range s.guilds {
for _, ch := range g.Channels {
if ch.ID == id {
return &ch, nil
}
}
}
return nil, ErrStoreNotFound
}
func (s *DefaultStore) Channels(
guildID discord.Snowflake) ([]discord.Channel, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
return gd.Channels, nil
}
func (s *DefaultStore) PrivateChannels() ([]discord.Channel, error) {
s.mut.Lock()
var chs = make([]discord.Channel, 0, len(s.privates))
for _, ch := range s.privates {
chs = append(chs, *ch)
}
s.mut.Unlock()
sort.Slice(chs, func(i, j int) bool {
// Latest first
return chs[i].LastMessageID > chs[j].LastMessageID
})
return chs, nil
}
func (s *DefaultStore) ChannelSet(channel *discord.Channel) error {
s.mut.Lock()
defer s.mut.Unlock()
switch channel.Type {
case discord.DirectMessage, discord.GroupDM:
s.privates[channel.ID] = channel
default:
gd, ok := s.guilds[channel.GuildID]
if !ok {
return ErrStoreNotFound
}
for i, ch := range gd.Channels {
if ch.ID == channel.ID {
// Found, just edit
gd.Channels[i] = *channel
return nil
}
}
gd.Channels = append(gd.Channels, *channel)
}
return nil
}
func (s *DefaultStore) ChannelRemove(channel *discord.Channel) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[channel.GuildID]
if !ok {
return ErrStoreNotFound
}
for i, ch := range gd.Channels {
if ch.ID == channel.ID {
gd.Channels = append(gd.Channels[:i], gd.Channels[i+1:]...)
return nil
}
}
return ErrStoreNotFound
}
////
func (s *DefaultStore) Emoji(
guildID, emojiID discord.Snowflake) (*discord.Emoji, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
for _, emoji := range gd.Emojis {
if emoji.ID == emojiID {
return &emoji, nil
}
}
return nil, ErrStoreNotFound
}
func (s *DefaultStore) Emojis(
guildID discord.Snowflake) ([]discord.Emoji, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
return gd.Emojis, nil
}
func (s *DefaultStore) EmojiSet(
guildID discord.Snowflake, emojis []discord.Emoji) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
filtered := emojis[:0]
Main:
for _, enew := range emojis {
// Try and see if this emoji is already in the slice
for i, emoji := range gd.Emojis {
if emoji.ID == enew.ID {
// If it is, we simply replace it
gd.Emojis[i] = enew
continue Main
}
}
// If not, we add it to the slice that's to be appended.
filtered = append(filtered, enew)
}
// Append the new emojis
gd.Emojis = append(gd.Emojis, filtered...)
return nil
}
////
func (s *DefaultStore) Guild(id discord.Snowflake) (*discord.Guild, error) {
s.mut.Lock()
defer s.mut.Unlock()
ch, ok := s.guilds[id]
if !ok {
return nil, ErrStoreNotFound
}
return ch, nil
}
func (s *DefaultStore) Guilds() ([]discord.Guild, error) {
s.mut.Lock()
var gs = make([]discord.Guild, 0, len(s.guilds))
for _, g := range s.guilds {
gs = append(gs, *g)
}
s.mut.Unlock()
sort.Slice(gs, func(i, j int) bool {
return gs[i].ID > gs[j].ID
})
return gs, nil
}
func (s *DefaultStore) GuildSet(g *discord.Guild) error {
s.mut.Lock()
defer s.mut.Unlock()
old := s.guilds[g.ID]
// Check the channels too
if len(old.Channels) == 0 {
return nil
}
if len(g.Channels) == 0 {
g.Channels = old.Channels
}
s.guilds[g.ID] = g
return nil
}
func (s *DefaultStore) GuildRemove(g *discord.Guild) error {
s.mut.Lock()
delete(s.guilds, g.ID)
s.mut.Unlock()
return nil
}
////
func (s *DefaultStore) Member(
guildID, userID discord.Snowflake) (*discord.Member, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
for _, member := range gd.Members {
if member.User.ID == userID {
return &member, nil
}
}
return nil, ErrStoreNotFound
}
func (s *DefaultStore) Members(
guildID discord.Snowflake) ([]discord.Member, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
return gd.Members, nil
}
func (s *DefaultStore) MemberSet(
guildID discord.Snowflake, member *discord.Member) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
// Try and see if this member is already in the slice
for i, m := range gd.Members {
if m.User.ID == member.User.ID {
// If it is, we simply replace it
gd.Members[i] = *member
return nil
}
}
// Append the new member
gd.Members = append(gd.Members, *member)
return nil
}
func (s *DefaultStore) MemberRemove(guildID, userID discord.Snowflake) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
// Try and see if this member is already in the slice
for i, m := range gd.Members {
if m.User.ID == userID {
gd.Members = append(gd.Members[:i], gd.Members[i+1:]...)
return nil
}
}
return ErrStoreNotFound
}
////
func (s *DefaultStore) Message(
channelID, messageID discord.Snowflake) (*discord.Message, error) {
s.mut.Lock()
defer s.mut.Unlock()
ms, ok := s.messages[channelID]
if !ok {
return nil, ErrStoreNotFound
}
for _, m := range ms {
if m.ID == messageID {
return &m, nil
}
}
return nil, ErrStoreNotFound
}
func (s *DefaultStore) Messages(
channelID discord.Snowflake) ([]discord.Message, error) {
s.mut.Lock()
defer s.mut.Unlock()
ms, ok := s.messages[channelID]
if !ok {
return nil, ErrStoreNotFound
}
return ms, nil
}
func (s *DefaultStore) MessageSet(message *discord.Message) error {
s.mut.Lock()
defer s.mut.Unlock()
ms, ok := s.messages[message.ChannelID]
if !ok {
ms = make([]discord.Message, 0, int(s.MaxMessages)+1)
}
// Append
ms = append(ms, *message)
// Sort (should be fast since it's presorted)
sort.Slice(ms, func(i, j int) bool {
return ms[i].ID > ms[j].ID
})
if len(ms) > int(s.MaxMessages) {
ms = ms[len(ms)-int(s.MaxMessages):]
}
return nil
}
func (s *DefaultStore) MessageRemove(message *discord.Message) error {
s.mut.Lock()
defer s.mut.Unlock()
ms, ok := s.messages[message.ChannelID]
if !ok {
return ErrStoreNotFound
}
for i, m := range ms {
if m.ID == message.ID {
ms = append(ms[:i], ms[i+1:]...)
s.messages[message.ChannelID] = ms
return nil
}
}
return ErrStoreNotFound
}
////
func (s *DefaultStore) Presence(
guildID, userID discord.Snowflake) (*discord.Presence, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
for _, p := range gd.Presences {
if p.User.ID == userID {
return &p, nil
}
}
return nil, ErrStoreNotFound
}
func (s *DefaultStore) Presences(
guildID discord.Snowflake) ([]discord.Presence, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
return gd.Presences, nil
}
func (s *DefaultStore) PresenceSet(
guildID discord.Snowflake, presence *discord.Presence) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
for i, p := range gd.Presences {
if p.User.ID == presence.User.ID {
gd.Presences[i] = *presence
return nil
}
}
gd.Presences = append(gd.Presences, *presence)
return nil
}
func (s *DefaultStore) PresenceRemove(guildID, userID discord.Snowflake) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
for i, p := range gd.Presences {
if p.User.ID == userID {
gd.Presences = append(gd.Presences[:i], gd.Presences[i+1:]...)
return nil
}
}
return ErrStoreNotFound
}
////
func (s *DefaultStore) Role(
guildID, roleID discord.Snowflake) (*discord.Role, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
for _, r := range gd.Roles {
if r.ID == roleID {
return &r, nil
}
}
return nil, ErrStoreNotFound
}
func (s *DefaultStore) Roles(
guildID discord.Snowflake) ([]discord.Role, error) {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return nil, ErrStoreNotFound
}
return gd.Roles, nil
}
func (s *DefaultStore) RoleSet(
guildID discord.Snowflake, role *discord.Role) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
for i, r := range gd.Roles {
if r.ID == role.ID {
gd.Roles[i] = *role
return nil
}
}
gd.Roles = append(gd.Roles, *role)
return nil
}
func (s *DefaultStore) RoleRemove(guildID, roleID discord.Snowflake) error {
s.mut.Lock()
defer s.mut.Unlock()
gd, ok := s.guilds[guildID]
if !ok {
return ErrStoreNotFound
}
for i, r := range gd.Roles {
if r.ID == roleID {
gd.Roles = append(gd.Roles[:i], gd.Roles[i+1:]...)
return nil
}
}
return ErrStoreNotFound
}