state

package
v1.3.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2020 License: ISC Imports: 9 Imported by: 21

Documentation

Overview

Package state provides interfaces for a local or remote state, as well as abstractions around the REST API and Gateway events.

Index

Constants

This section is empty.

Variables

View Source
var (
	MaxFetchMembers uint = 1000
	MaxFetchGuilds  uint = 10
)
View Source
var ErrNotImplemented = errors.New("state is not implemented")
View Source
var ErrStoreNotFound = errors.New("item not found in store")

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.

Functions

func DiffMessage added in v0.6.2

func DiffMessage(src discord.Message, dst *discord.Message)

DiffMessage fills non-empty fields from src to dst.

Types

type DefaultStore

type DefaultStore struct {
	DefaultStoreOptions
	// contains filtered or unexported fields
}

func NewDefaultStore

func NewDefaultStore(opts *DefaultStoreOptions) *DefaultStore

func (*DefaultStore) Channel

func (s *DefaultStore) Channel(id discord.ChannelID) (*discord.Channel, error)

func (*DefaultStore) ChannelRemove

func (s *DefaultStore) ChannelRemove(channel discord.Channel) error

func (*DefaultStore) ChannelSet

func (s *DefaultStore) ChannelSet(channel discord.Channel) error

func (*DefaultStore) Channels

func (s *DefaultStore) Channels(guildID discord.GuildID) ([]discord.Channel, error)

func (*DefaultStore) CreatePrivateChannel added in v0.3.0

func (s *DefaultStore) CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error)

CreatePrivateChannel searches in the cache for a private channel. It makes no API calls.

func (*DefaultStore) Emoji

func (s *DefaultStore) Emoji(guildID discord.GuildID, emojiID discord.EmojiID) (*discord.Emoji, error)

func (*DefaultStore) EmojiSet

func (s *DefaultStore) EmojiSet(guildID discord.GuildID, emojis []discord.Emoji) error

func (*DefaultStore) Emojis

func (s *DefaultStore) Emojis(guildID discord.GuildID) ([]discord.Emoji, error)

func (*DefaultStore) Guild

func (s *DefaultStore) Guild(id discord.GuildID) (*discord.Guild, error)

func (*DefaultStore) GuildRemove

func (s *DefaultStore) GuildRemove(id discord.GuildID) error

func (*DefaultStore) GuildSet

func (s *DefaultStore) GuildSet(guild discord.Guild) error

func (*DefaultStore) Guilds

func (s *DefaultStore) Guilds() ([]discord.Guild, error)

func (*DefaultStore) MaxMessages added in v0.0.3

func (s *DefaultStore) MaxMessages() int

func (*DefaultStore) Me added in v0.1.2

func (s *DefaultStore) Me() (*discord.User, error)

func (*DefaultStore) Member

func (s *DefaultStore) Member(
	guildID discord.GuildID, userID discord.UserID) (*discord.Member, error)

func (*DefaultStore) MemberRemove

func (s *DefaultStore) MemberRemove(guildID discord.GuildID, userID discord.UserID) error

func (*DefaultStore) MemberSet

func (s *DefaultStore) MemberSet(guildID discord.GuildID, member discord.Member) error

func (*DefaultStore) Members

func (s *DefaultStore) Members(guildID discord.GuildID) ([]discord.Member, error)

func (*DefaultStore) Message

func (s *DefaultStore) Message(
	channelID discord.ChannelID, messageID discord.MessageID) (*discord.Message, error)

func (*DefaultStore) MessageRemove

func (s *DefaultStore) MessageRemove(
	channelID discord.ChannelID, messageID discord.MessageID) error

func (*DefaultStore) MessageSet

func (s *DefaultStore) MessageSet(message discord.Message) error

func (*DefaultStore) Messages

func (s *DefaultStore) Messages(channelID discord.ChannelID) ([]discord.Message, error)

func (*DefaultStore) MyselfSet added in v0.1.2

func (s *DefaultStore) MyselfSet(me discord.User) error

func (*DefaultStore) Presence

func (s *DefaultStore) Presence(
	guildID discord.GuildID, userID discord.UserID) (*discord.Presence, error)

func (*DefaultStore) PresenceRemove

func (s *DefaultStore) PresenceRemove(guildID discord.GuildID, userID discord.UserID) error

func (*DefaultStore) PresenceSet

func (s *DefaultStore) PresenceSet(guildID discord.GuildID, presence discord.Presence) error

func (*DefaultStore) Presences

func (s *DefaultStore) Presences(guildID discord.GuildID) ([]discord.Presence, error)

func (*DefaultStore) PrivateChannels

func (s *DefaultStore) PrivateChannels() ([]discord.Channel, error)

PrivateChannels returns a list of Direct Message channels randomly ordered.

func (*DefaultStore) Reset

func (s *DefaultStore) Reset() error

func (*DefaultStore) Role

func (s *DefaultStore) Role(guildID discord.GuildID, roleID discord.RoleID) (*discord.Role, error)

func (*DefaultStore) RoleRemove

func (s *DefaultStore) RoleRemove(guildID discord.GuildID, roleID discord.RoleID) error

func (*DefaultStore) RoleSet

func (s *DefaultStore) RoleSet(guildID discord.GuildID, role discord.Role) error

func (*DefaultStore) Roles

func (s *DefaultStore) Roles(guildID discord.GuildID) ([]discord.Role, error)

func (*DefaultStore) VoiceState added in v0.4.1

func (s *DefaultStore) VoiceState(
	guildID discord.GuildID, userID discord.UserID) (*discord.VoiceState, error)

func (*DefaultStore) VoiceStateRemove added in v0.4.1

func (s *DefaultStore) VoiceStateRemove(guildID discord.GuildID, userID discord.UserID) error

func (*DefaultStore) VoiceStateSet added in v0.4.1

func (s *DefaultStore) VoiceStateSet(guildID discord.GuildID, voiceState discord.VoiceState) error

func (*DefaultStore) VoiceStates added in v0.4.1

func (s *DefaultStore) VoiceStates(guildID discord.GuildID) ([]discord.VoiceState, error)

type DefaultStoreOptions

type DefaultStoreOptions struct {
	MaxMessages uint // default 50
}

type GuildAvailableEvent added in v0.9.3

type GuildAvailableEvent struct {
	*gateway.GuildCreateEvent
}

GuildAvailableEvent gets fired when a guild becomes available again, after being previously declared unavailable through a GuildUnavailableEvent. This event will not be fired for guilds that were already unavailable when connecting to the gateway.

type GuildJoinEvent added in v0.9.3

type GuildJoinEvent struct {
	*gateway.GuildCreateEvent
}

GuildJoinEvent gets fired if the bot/user joins a guild.

type GuildLeaveEvent added in v0.9.3

type GuildLeaveEvent struct {
	*gateway.GuildDeleteEvent
}

GuildLeaveEvent gets fired if the bot/user left a guild, was removed or the owner deleted the guild.

type GuildReadyEvent added in v0.9.3

type GuildReadyEvent struct {
	*gateway.GuildCreateEvent
}

GuildReady gets fired for every guild the bot/user is in, as found in the Ready event.

Guilds that are unavailable when connecting, will not trigger a GuildReadyEvent, until they become available again.

type GuildUnavailableEvent added in v0.9.3

type GuildUnavailableEvent struct {
	*gateway.GuildDeleteEvent
}

GuildUnavailableEvent gets fired if a guild becomes unavailable.

type NoopStore added in v0.1.5

type NoopStore struct{}

NoopStore could be embedded by other structs for partial state implementation. All Getters will return ErrNotImplemented, and all Setters will return no error.

func (NoopStore) Channel added in v0.1.5

func (NoopStore) ChannelRemove added in v0.1.5

func (NoopStore) ChannelRemove(discord.Channel) error

func (NoopStore) ChannelSet added in v0.1.5

func (NoopStore) ChannelSet(discord.Channel) error

func (NoopStore) Channels added in v0.1.5

func (NoopStore) Channels(discord.GuildID) ([]discord.Channel, error)

func (NoopStore) CreatePrivateChannel added in v0.3.0

func (NoopStore) CreatePrivateChannel(discord.UserID) (*discord.Channel, error)

func (NoopStore) Emoji added in v0.1.5

func (NoopStore) EmojiSet added in v0.1.5

func (NoopStore) EmojiSet(discord.GuildID, []discord.Emoji) error

func (NoopStore) Emojis added in v0.1.5

func (NoopStore) Emojis(discord.GuildID) ([]discord.Emoji, error)

func (NoopStore) Guild added in v0.1.5

func (NoopStore) GuildRemove added in v0.1.5

func (NoopStore) GuildRemove(discord.GuildID) error

func (NoopStore) GuildSet added in v0.1.5

func (NoopStore) GuildSet(discord.Guild) error

func (NoopStore) Guilds added in v0.1.5

func (NoopStore) Guilds() ([]discord.Guild, error)

func (NoopStore) MaxMessages added in v0.1.5

func (NoopStore) MaxMessages() int

MaxMessages will always return 100 messages, so the API can fetch that many.

func (NoopStore) Me added in v0.1.5

func (NoopStore) Me() (*discord.User, error)

func (NoopStore) Member added in v0.1.5

func (NoopStore) MemberRemove added in v0.1.5

func (NoopStore) MemberRemove(discord.GuildID, discord.UserID) error

func (NoopStore) MemberSet added in v0.1.5

func (NoopStore) Members added in v0.1.5

func (NoopStore) Members(discord.GuildID) ([]discord.Member, error)

func (NoopStore) Message added in v0.1.5

func (NoopStore) MessageRemove added in v0.1.5

func (NoopStore) MessageSet added in v0.1.5

func (NoopStore) MessageSet(discord.Message) error

func (NoopStore) Messages added in v0.1.5

func (NoopStore) MyselfSet added in v0.1.5

func (NoopStore) MyselfSet(discord.User) error

func (NoopStore) Presence added in v0.1.5

func (NoopStore) PresenceRemove added in v0.1.5

func (NoopStore) PresenceRemove(discord.GuildID, discord.UserID) error

func (NoopStore) PresenceSet added in v0.1.5

func (NoopStore) Presences added in v0.1.5

func (NoopStore) Presences(discord.GuildID) ([]discord.Presence, error)

func (NoopStore) PrivateChannels added in v0.1.5

func (NoopStore) PrivateChannels() ([]discord.Channel, error)

func (NoopStore) Reset added in v0.1.5

func (NoopStore) Reset() error

func (NoopStore) Role added in v0.1.5

func (NoopStore) RoleRemove added in v0.1.5

func (NoopStore) RoleSet added in v0.1.5

func (NoopStore) Roles added in v0.1.5

func (NoopStore) Roles(discord.GuildID) ([]discord.Role, error)

func (NoopStore) VoiceState added in v0.4.1

func (NoopStore) VoiceStateRemove added in v0.4.1

func (NoopStore) VoiceStateRemove(discord.GuildID, discord.UserID) error

func (NoopStore) VoiceStateSet added in v0.4.1

func (NoopStore) VoiceStateSet(discord.GuildID, discord.VoiceState) error

func (NoopStore) VoiceStates added in v0.4.1

func (NoopStore) VoiceStates(discord.GuildID) ([]discord.VoiceState, error)

type State

type State struct {
	*session.Session
	Store

	// Ready is not updated by the state.
	Ready gateway.ReadyEvent

	// StateLog logs all errors that come from the state cache. This includes
	// not found errors. Defaults to a no-op, as state errors aren't that
	// important.
	StateLog func(error)

	// PreHandler is the manual hook that is executed before the State handler
	// is. This should only be used for low-level operations.
	// It's recommended to set Synchronous to true if you mutate the events.
	PreHandler *handler.Handler // default nil

	// Command handler with inherited methods. Ran after PreHandler. You should
	// most of the time use this instead of Session's, to avoid race conditions
	// with the State.
	*handler.Handler
	// contains filtered or unexported fields
}

State is the cache to store events coming from Discord as well as data from API calls.

Store

The state basically provides abstractions on top of the API and the state storage (Store). The state storage is effectively a set of interfaces which allow arbitrary backends to be implemented.

The default storage backend is a typical in-memory structure consisting of maps and slices. Custom backend implementations could embed this storage backend as an in-memory fallback. A good example of this would be embedding the default store for messages only, while handling everything else in Redis.

The package also provides a no-op store (NoopStore) that implementations could embed. This no-op store will always return an error, which makes the state fetch information from the API. The setters are all no-ops, so the fetched data won't be updated.

Handler

The state uses its own handler over session's to make all handlers run after the state updates itself. A PreHandler is exposed in any case the user needs the handlers to run before the state updates itself. Refer to that field's documentation.

The state also provides extra events and overrides to make up for Discord's inconsistencies in data. The following are known instances of such.

The Guild Create event is split up to make the state's Guild Available, Guild Ready and Guild Join events. Refer to these events' documentations for more information.

The Message Create and Message Update events with the Member field provided will have the User field copied from Author. This is because the User field will be empty, while the Member structure expects it to be there.

func New

func New(token string) (*State, error)

New creates a new state.

func NewFromSession

func NewFromSession(s *session.Session, store Store) (*State, error)

NewFromSession never returns an error. This API is kept for backwards compatibility.

func NewWithIntents added in v0.10.0

func NewWithIntents(token string, intents ...gateway.Intents) (*State, error)

NewWithIntents creates a new state with the given gateway intents. For more information, refer to gateway.Intents.

func NewWithStore

func NewWithStore(token string, store Store) (*State, error)

func (*State) AuthorColor added in v0.0.7

func (s *State) AuthorColor(message *gateway.MessageCreateEvent) (discord.Color, error)

func (*State) AuthorDisplayName added in v0.0.7

func (s *State) AuthorDisplayName(message *gateway.MessageCreateEvent) string

func (*State) Channel

func (s *State) Channel(id discord.ChannelID) (*discord.Channel, error)

func (*State) Channels

func (s *State) Channels(guildID discord.GuildID) ([]discord.Channel, error)

func (*State) CreatePrivateChannel added in v0.3.0

func (s *State) CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error)

func (*State) Emoji

func (s *State) Emoji(
	guildID discord.GuildID, emojiID discord.EmojiID) (*discord.Emoji, error)

func (*State) Emojis

func (s *State) Emojis(guildID discord.GuildID) ([]discord.Emoji, error)

func (*State) Guild

func (s *State) Guild(id discord.GuildID) (*discord.Guild, error)

func (*State) Guilds

func (s *State) Guilds() ([]discord.Guild, error)

Guilds will only fill a maximum of 100 guilds from the API.

func (*State) Me added in v0.1.2

func (s *State) Me() (*discord.User, error)

func (*State) Member

func (s *State) Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error)

func (*State) MemberColor added in v0.0.7

func (s *State) MemberColor(guildID discord.GuildID, userID discord.UserID) (discord.Color, error)

func (*State) MemberDisplayName added in v0.0.7

func (s *State) MemberDisplayName(guildID discord.GuildID, userID discord.UserID) (string, error)

func (*State) Members

func (s *State) Members(guildID discord.GuildID) ([]discord.Member, error)

func (*State) Message

func (s *State) Message(
	channelID discord.ChannelID, messageID discord.MessageID) (*discord.Message, error)

func (*State) Messages

func (s *State) Messages(channelID discord.ChannelID) ([]discord.Message, error)

Messages fetches maximum 100 messages from the API, if it has to. There is no limit if it's from the State storage.

func (*State) Permissions

func (s *State) Permissions(
	channelID discord.ChannelID, userID discord.UserID) (discord.Permissions, error)

func (*State) Presence

func (s *State) Presence(
	guildID discord.GuildID, userID discord.UserID) (*discord.Presence, error)

Presence checks the state for user presences. If no guildID is given, it will look for the presence in all guilds.

func (*State) PrivateChannels added in v0.3.0

func (s *State) PrivateChannels() ([]discord.Channel, error)

func (*State) Role

func (s *State) Role(guildID discord.GuildID, roleID discord.RoleID) (*discord.Role, error)

func (*State) Roles

func (s *State) Roles(guildID discord.GuildID) ([]discord.Role, error)

func (*State) WithContext added in v0.6.0

func (s *State) WithContext(ctx context.Context) *State

WithContext returns a shallow copy of State with the context replaced in the API client. All methods called on the State will use this given context. This method is thread-safe.

type Store

type Store interface {
	StoreGetter
	StoreModifier
}

Store is the state storage. It should handle mutex itself, and it should only concern itself with the local state.

type StoreGetter

type StoreGetter interface {
	Me() (*discord.User, error)

	// Channel should check for both DM and guild channels.
	Channel(id discord.ChannelID) (*discord.Channel, error)
	Channels(guildID discord.GuildID) ([]discord.Channel, error)

	// same API as (*api.Client)
	CreatePrivateChannel(recipient discord.UserID) (*discord.Channel, error)
	PrivateChannels() ([]discord.Channel, error)

	Emoji(guildID discord.GuildID, emojiID discord.EmojiID) (*discord.Emoji, error)
	Emojis(guildID discord.GuildID) ([]discord.Emoji, error)

	Guild(id discord.GuildID) (*discord.Guild, error)
	Guilds() ([]discord.Guild, error)

	Member(guildID discord.GuildID, userID discord.UserID) (*discord.Member, error)
	Members(guildID discord.GuildID) ([]discord.Member, error)

	Message(channelID discord.ChannelID, messageID discord.MessageID) (*discord.Message, error)
	// Messages should return messages ordered from latest to earliest.
	Messages(channelID discord.ChannelID) ([]discord.Message, error)
	MaxMessages() int // used to know if the state is filled or not.

	// These don't get fetched from the API, it's Gateway only.
	Presence(guildID discord.GuildID, userID discord.UserID) (*discord.Presence, error)
	Presences(guildID discord.GuildID) ([]discord.Presence, error)

	Role(guildID discord.GuildID, roleID discord.RoleID) (*discord.Role, error)
	Roles(guildID discord.GuildID) ([]discord.Role, error)

	VoiceState(guildID discord.GuildID, userID discord.UserID) (*discord.VoiceState, error)
	VoiceStates(guildID discord.GuildID) ([]discord.VoiceState, error)
}

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.

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.

These methods should not care about returning slices in order, unless explicitly stated against.

type StoreModifier

type StoreModifier interface {
	MyselfSet(me discord.User) error

	// ChannelSet should switch on Type to know if it's a private channel or
	// not.
	ChannelSet(discord.Channel) error
	ChannelRemove(discord.Channel) error

	// EmojiSet should delete all old emojis before setting new ones.
	EmojiSet(guildID discord.GuildID, emojis []discord.Emoji) error

	GuildSet(discord.Guild) error
	GuildRemove(id discord.GuildID) error

	MemberSet(guildID discord.GuildID, member discord.Member) error
	MemberRemove(guildID discord.GuildID, userID discord.UserID) error

	// MessageSet should prepend messages into the slice, the latest being in
	// front.
	MessageSet(discord.Message) error
	MessageRemove(channelID discord.ChannelID, messageID discord.MessageID) error

	PresenceSet(guildID discord.GuildID, presence discord.Presence) error
	PresenceRemove(guildID discord.GuildID, userID discord.UserID) error

	RoleSet(guildID discord.GuildID, role discord.Role) error
	RoleRemove(guildID discord.GuildID, roleID discord.RoleID) error

	VoiceStateSet(guildID discord.GuildID, voiceState discord.VoiceState) error
	VoiceStateRemove(guildID discord.GuildID, userID discord.UserID) error
}

type StoreResetter added in v1.2.0

type StoreResetter interface {
	// Reset resets the store to a new valid instance.
	Reset() error
}

StoreResetter is used by the state to reset the store on every Ready event.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL