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  }