github.com/diamondburned/arikawa@v1.3.14/state/store.go (about) 1 package state 2 3 import ( 4 "errors" 5 6 "github.com/diamondburned/arikawa/discord" 7 ) 8 9 // Store is the state storage. It should handle mutex itself, and it should only 10 // concern itself with the local state. 11 type Store interface { 12 StoreGetter 13 StoreModifier 14 } 15 16 // All methods in StoreGetter will be wrapped by the State. If the State can't 17 // find anything in the storage, it will call the API itself and automatically 18 // add what's missing into the storage. 19 // 20 // Methods that return with a slice should pay attention to race conditions that 21 // would mutate the underlying slice (and as a result the returned slice as 22 // well). The best way to avoid this is to copy the whole slice, like 23 // DefaultStore does. 24 // 25 // These methods should not care about returning slices in order, unless 26 // explicitly stated against. 27 type StoreGetter interface { 28 Me() (*discord.User, error) 29 30 // Channel should check for both DM and guild channels. 31 Channel(id discord.ChannelID) (*discord.Channel, error) 32 Channels(guildID discord.GuildID) ([]discord.Channel, error) 33 34 // same API as (*api.Client) 35 CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error) 36 PrivateChannels() ([]discord.Channel, error) 37 38 Emoji(guildID discord.GuildID, emojiID discord.EmojiID) (*discord.Emoji, error) 39 Emojis(guildID discord.GuildID) ([]discord.Emoji, error) 40 41 Guild(id discord.GuildID) (*discord.Guild, error) 42 Guilds() ([]discord.Guild, error) 43 44 Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error) 45 Members(guildID discord.GuildID) ([]discord.Member, error) 46 47 Message(channelID discord.ChannelID, messageID discord.MessageID) (*discord.Message, error) 48 // Messages should return messages ordered from latest to earliest. 49 Messages(channelID discord.ChannelID) ([]discord.Message, error) 50 MaxMessages() int // used to know if the state is filled or not. 51 52 // These don't get fetched from the API, it's Gateway only. 53 Presence(guildID discord.GuildID, userID discord.UserID) (*discord.Presence, error) 54 Presences(guildID discord.GuildID) ([]discord.Presence, error) 55 56 Role(guildID discord.GuildID, roleID discord.RoleID) (*discord.Role, error) 57 Roles(guildID discord.GuildID) ([]discord.Role, error) 58 59 VoiceState(guildID discord.GuildID, userID discord.UserID) (*discord.VoiceState, error) 60 VoiceStates(guildID discord.GuildID) ([]discord.VoiceState, error) 61 } 62 63 type StoreModifier interface { 64 MyselfSet(me discord.User) error 65 66 // ChannelSet should switch on Type to know if it's a private channel or 67 // not. 68 ChannelSet(discord.Channel) error 69 ChannelRemove(discord.Channel) error 70 71 // EmojiSet should delete all old emojis before setting new ones. 72 EmojiSet(guildID discord.GuildID, emojis []discord.Emoji) error 73 74 GuildSet(discord.Guild) error 75 GuildRemove(id discord.GuildID) error 76 77 MemberSet(guildID discord.GuildID, member discord.Member) error 78 MemberRemove(guildID discord.GuildID, userID discord.UserID) error 79 80 // MessageSet should prepend messages into the slice, the latest being in 81 // front. 82 MessageSet(discord.Message) error 83 MessageRemove(channelID discord.ChannelID, messageID discord.MessageID) error 84 85 PresenceSet(guildID discord.GuildID, presence discord.Presence) error 86 PresenceRemove(guildID discord.GuildID, userID discord.UserID) error 87 88 RoleSet(guildID discord.GuildID, role discord.Role) error 89 RoleRemove(guildID discord.GuildID, roleID discord.RoleID) error 90 91 VoiceStateSet(guildID discord.GuildID, voiceState discord.VoiceState) error 92 VoiceStateRemove(guildID discord.GuildID, userID discord.UserID) error 93 } 94 95 // StoreResetter is used by the state to reset the store on every Ready event. 96 type StoreResetter interface { 97 // Reset resets the store to a new valid instance. 98 Reset() error 99 } 100 101 // ErrStoreNotFound is an error that a store can use to return when something 102 // isn't in the storage. There is no strict restrictions on what uses this (the 103 // default one does, though), so be advised. 104 var ErrStoreNotFound = errors.New("item not found in store") 105 106 // DiffMessage fills non-empty fields from src to dst. 107 func DiffMessage(src discord.Message, dst *discord.Message) { 108 // Thanks, Discord. 109 if src.Content != "" { 110 dst.Content = src.Content 111 } 112 if src.EditedTimestamp.IsValid() { 113 dst.EditedTimestamp = src.EditedTimestamp 114 } 115 if src.Mentions != nil { 116 dst.Mentions = src.Mentions 117 } 118 if src.Embeds != nil { 119 dst.Embeds = src.Embeds 120 } 121 if src.Attachments != nil { 122 dst.Attachments = src.Attachments 123 } 124 if src.Timestamp.IsValid() { 125 dst.Timestamp = src.Timestamp 126 } 127 if src.Author.ID.IsValid() { 128 dst.Author = src.Author 129 } 130 if src.Reactions != nil { 131 dst.Reactions = src.Reactions 132 } 133 }