2020-01-18 07:07:52 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
|
|
|
|
"github.com/diamondburned/arikawa/discord"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Store is the state storage. It should handle mutex itself, and it should only
|
|
|
|
// concern itself with the local state.
|
2020-03-01 02:54:14 +00:00
|
|
|
type Store interface {
|
|
|
|
StoreGetter
|
|
|
|
StoreModifier
|
2020-01-18 07:07:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// All methods in StoreGetter will be wrapped by the State. If the State can't
|
|
|
|
// find anything in the storage, it will call the API itself and automatically
|
|
|
|
// add what's missing into the storage.
|
2020-01-20 09:42:03 +00:00
|
|
|
//
|
|
|
|
// Methods that return with a slice should pay attention to race conditions that
|
|
|
|
// would mutate the underlying slice (and as a result the returned slice as
|
|
|
|
// well). The best way to avoid this is to copy the whole slice, like
|
|
|
|
// DefaultStore does.
|
2020-07-28 19:00:01 +00:00
|
|
|
//
|
|
|
|
// These methods should not care about returning slices in order, unless
|
|
|
|
// explicitly stated against.
|
2020-03-01 02:54:14 +00:00
|
|
|
type StoreGetter interface {
|
|
|
|
Me() (*discord.User, error)
|
|
|
|
|
2020-03-11 03:44:35 +00:00
|
|
|
// Channel should check for both DM and guild channels.
|
2020-07-21 20:27:59 +00:00
|
|
|
Channel(id discord.ChannelID) (*discord.Channel, error)
|
|
|
|
Channels(guildID discord.GuildID) ([]discord.Channel, error)
|
2020-04-08 02:33:56 +00:00
|
|
|
|
|
|
|
// same API as (*api.Client)
|
2020-07-21 20:27:59 +00:00
|
|
|
CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
PrivateChannels() ([]discord.Channel, error)
|
|
|
|
|
2020-07-21 20:27:59 +00:00
|
|
|
Emoji(guildID discord.GuildID, emojiID discord.EmojiID) (*discord.Emoji, error)
|
|
|
|
Emojis(guildID discord.GuildID) ([]discord.Emoji, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-21 20:27:59 +00:00
|
|
|
Guild(id discord.GuildID) (*discord.Guild, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
Guilds() ([]discord.Guild, error)
|
|
|
|
|
2020-07-21 20:27:59 +00:00
|
|
|
Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error)
|
|
|
|
Members(guildID discord.GuildID) ([]discord.Member, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-21 20:27:59 +00:00
|
|
|
Message(channelID discord.ChannelID, messageID discord.MessageID) (*discord.Message, error)
|
2020-05-16 20:04:54 +00:00
|
|
|
// Messages should return messages ordered from latest to earliest.
|
2020-07-21 20:27:59 +00:00
|
|
|
Messages(channelID discord.ChannelID) ([]discord.Message, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
MaxMessages() int // used to know if the state is filled or not.
|
|
|
|
|
|
|
|
// These don't get fetched from the API, it's Gateway only.
|
2020-07-21 20:27:59 +00:00
|
|
|
Presence(guildID discord.GuildID, userID discord.UserID) (*discord.Presence, error)
|
|
|
|
Presences(guildID discord.GuildID) ([]discord.Presence, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-21 20:27:59 +00:00
|
|
|
Role(guildID discord.GuildID, roleID discord.RoleID) (*discord.Role, error)
|
|
|
|
Roles(guildID discord.GuildID) ([]discord.Role, error)
|
2020-04-19 02:22:49 +00:00
|
|
|
|
2020-07-21 20:27:59 +00:00
|
|
|
VoiceState(guildID discord.GuildID, userID discord.UserID) (*discord.VoiceState, error)
|
|
|
|
VoiceStates(guildID discord.GuildID) ([]discord.VoiceState, error)
|
2020-03-01 02:54:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type StoreModifier interface {
|
2020-07-28 19:00:01 +00:00
|
|
|
MyselfSet(me discord.User) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
|
|
|
// ChannelSet should switch on Type to know if it's a private channel or
|
|
|
|
// not.
|
2020-07-28 19:00:01 +00:00
|
|
|
ChannelSet(discord.Channel) error
|
|
|
|
ChannelRemove(discord.Channel) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-03-01 03:09:03 +00:00
|
|
|
// EmojiSet should delete all old emojis before setting new ones.
|
2020-07-21 20:27:59 +00:00
|
|
|
EmojiSet(guildID discord.GuildID, emojis []discord.Emoji) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-28 19:00:01 +00:00
|
|
|
GuildSet(discord.Guild) error
|
2020-07-21 20:27:59 +00:00
|
|
|
GuildRemove(id discord.GuildID) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-28 19:00:01 +00:00
|
|
|
MemberSet(guildID discord.GuildID, member discord.Member) error
|
2020-07-21 20:27:59 +00:00
|
|
|
MemberRemove(guildID discord.GuildID, userID discord.UserID) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-05-16 20:04:54 +00:00
|
|
|
// MessageSet should prepend messages into the slice, the latest being in
|
|
|
|
// front.
|
2020-07-28 19:00:01 +00:00
|
|
|
MessageSet(discord.Message) error
|
2020-07-21 20:27:59 +00:00
|
|
|
MessageRemove(channelID discord.ChannelID, messageID discord.MessageID) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-28 19:00:01 +00:00
|
|
|
PresenceSet(guildID discord.GuildID, presence discord.Presence) error
|
2020-07-21 20:27:59 +00:00
|
|
|
PresenceRemove(guildID discord.GuildID, userID discord.UserID) error
|
2020-03-01 02:54:14 +00:00
|
|
|
|
2020-07-28 19:00:01 +00:00
|
|
|
RoleSet(guildID discord.GuildID, role discord.Role) error
|
2020-07-21 20:27:59 +00:00
|
|
|
RoleRemove(guildID discord.GuildID, roleID discord.RoleID) error
|
2020-04-19 02:22:49 +00:00
|
|
|
|
2020-07-28 19:00:01 +00:00
|
|
|
VoiceStateSet(guildID discord.GuildID, voiceState discord.VoiceState) error
|
2020-07-21 20:27:59 +00:00
|
|
|
VoiceStateRemove(guildID discord.GuildID, userID discord.UserID) error
|
2020-03-01 02:54:14 +00:00
|
|
|
}
|
2020-01-18 07:07:52 +00:00
|
|
|
|
2020-08-18 17:20:48 +00:00
|
|
|
// StoreResetter is used by the state to reset the store on every Ready event.
|
|
|
|
type StoreResetter interface {
|
|
|
|
// Reset resets the store to a new valid instance.
|
|
|
|
Reset() error
|
|
|
|
}
|
|
|
|
|
2020-01-18 07:07:52 +00:00
|
|
|
// ErrStoreNotFound is an error that a store can use to return when something
|
|
|
|
// isn't in the storage. There is no strict restrictions on what uses this (the
|
|
|
|
// default one does, though), so be advised.
|
|
|
|
var ErrStoreNotFound = errors.New("item not found in store")
|
2020-05-06 03:26:05 +00:00
|
|
|
|
|
|
|
// DiffMessage fills non-empty fields from src to dst.
|
|
|
|
func DiffMessage(src discord.Message, dst *discord.Message) {
|
|
|
|
// Thanks, Discord.
|
|
|
|
if src.Content != "" {
|
|
|
|
dst.Content = src.Content
|
|
|
|
}
|
2020-07-29 20:10:17 +00:00
|
|
|
if src.EditedTimestamp.IsValid() {
|
2020-05-06 03:26:05 +00:00
|
|
|
dst.EditedTimestamp = src.EditedTimestamp
|
|
|
|
}
|
|
|
|
if src.Mentions != nil {
|
|
|
|
dst.Mentions = src.Mentions
|
|
|
|
}
|
|
|
|
if src.Embeds != nil {
|
|
|
|
dst.Embeds = src.Embeds
|
|
|
|
}
|
|
|
|
if src.Attachments != nil {
|
|
|
|
dst.Attachments = src.Attachments
|
|
|
|
}
|
2020-07-29 20:10:17 +00:00
|
|
|
if src.Timestamp.IsValid() {
|
2020-05-06 03:26:05 +00:00
|
|
|
dst.Timestamp = src.Timestamp
|
|
|
|
}
|
2020-07-29 20:10:17 +00:00
|
|
|
if src.Author.ID.IsValid() {
|
2020-05-06 03:26:05 +00:00
|
|
|
dst.Author = src.Author
|
|
|
|
}
|
|
|
|
if src.Reactions != nil {
|
|
|
|
dst.Reactions = src.Reactions
|
|
|
|
}
|
|
|
|
}
|