mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-01-05 19:57:02 +00:00
State now handles MsgCreate's missing Member.User field, some bug fixes
This addresses discord/discord-api-docs#1440. State documentation has been added, which documents the store and handlers as well. Bug fixes include: - PreHandler being called after the state handler; it is now called before as documented. - Minor behavior changes regarding Guild Create events. Refer to State's documentation.
This commit is contained in:
parent
1373e42fe1
commit
88dd0f8995
|
@ -4,23 +4,14 @@ import (
|
|||
"github.com/diamondburned/arikawa/gateway"
|
||||
)
|
||||
|
||||
func (s *State) handleEvent(ev interface{}) {
|
||||
if s.PreHandler != nil {
|
||||
s.PreHandler.Call(ev)
|
||||
}
|
||||
s.Handler.Call(ev)
|
||||
}
|
||||
|
||||
func (s *State) handleReady(ev *gateway.ReadyEvent) {
|
||||
s.handleEvent(ev)
|
||||
|
||||
for _, g := range ev.Guilds {
|
||||
// store this so we know when we need to dispatch a belated
|
||||
// GuildReadyEvent
|
||||
if g.Unavailable {
|
||||
s.unreadyGuilds.Add(g.ID)
|
||||
} else {
|
||||
s.handleEvent(&GuildReadyEvent{
|
||||
s.Handler.Call(&GuildReadyEvent{
|
||||
GuildCreateEvent: &g,
|
||||
})
|
||||
}
|
||||
|
@ -28,47 +19,39 @@ func (s *State) handleReady(ev *gateway.ReadyEvent) {
|
|||
}
|
||||
|
||||
func (s *State) handleGuildCreate(ev *gateway.GuildCreateEvent) {
|
||||
// before we dispatch the specific events, we can already call the handlers
|
||||
// that subscribed to the generic version
|
||||
s.handleEvent(ev)
|
||||
|
||||
// this guild was unavailable, but has come back online
|
||||
if s.unavailableGuilds.Delete(ev.ID) {
|
||||
s.handleEvent(&GuildAvailableEvent{
|
||||
s.Handler.Call(&GuildAvailableEvent{
|
||||
GuildCreateEvent: ev,
|
||||
})
|
||||
|
||||
// the guild was already unavailable when connecting to the gateway
|
||||
// we can dispatch a belated GuildReadyEvent
|
||||
} else if s.unreadyGuilds.Delete(ev.ID) {
|
||||
s.handleEvent(&GuildReadyEvent{
|
||||
s.Handler.Call(&GuildReadyEvent{
|
||||
GuildCreateEvent: ev,
|
||||
})
|
||||
} else { // we don't know this guild, hence we just joined it
|
||||
s.handleEvent(&GuildJoinEvent{
|
||||
s.Handler.Call(&GuildJoinEvent{
|
||||
GuildCreateEvent: ev,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) handleGuildDelete(ev *gateway.GuildDeleteEvent) {
|
||||
// before we dispatch the specific events, we can already call the handlers
|
||||
// that subscribed to the generic version
|
||||
s.handleEvent(ev)
|
||||
|
||||
// store this so we can later dispatch a GuildAvailableEvent, once the
|
||||
// guild becomes available again.
|
||||
if ev.Unavailable {
|
||||
s.unavailableGuilds.Add(ev.ID)
|
||||
|
||||
s.handleEvent(&GuildUnavailableEvent{
|
||||
s.Handler.Call(&GuildUnavailableEvent{
|
||||
GuildDeleteEvent: ev,
|
||||
})
|
||||
} else {
|
||||
// it might have been unavailable before we left
|
||||
s.unavailableGuilds.Delete(ev.ID)
|
||||
|
||||
s.handleEvent(&GuildLeaveEvent{
|
||||
s.Handler.Call(&GuildLeaveEvent{
|
||||
GuildDeleteEvent: ev,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -20,6 +20,42 @@ var (
|
|||
MaxFetchGuilds uint = 100
|
||||
)
|
||||
|
||||
// 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.
|
||||
type State struct {
|
||||
*session.Session
|
||||
Store
|
||||
|
@ -41,7 +77,7 @@ type State struct {
|
|||
|
||||
// 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
|
||||
// with the State.
|
||||
*handler.Handler
|
||||
|
||||
unhooker func()
|
||||
|
|
|
@ -7,23 +7,42 @@ import (
|
|||
"github.com/diamondburned/arikawa/gateway"
|
||||
)
|
||||
|
||||
func (s *State) hookSession() error {
|
||||
s.unhooker = s.Session.AddHandler(func(iface interface{}) {
|
||||
s.onEvent(iface)
|
||||
func (s *State) hookSession() {
|
||||
s.unhooker = s.Session.AddHandler(func(event interface{}) {
|
||||
// Call the pre-handler before the state handler.
|
||||
if s.PreHandler != nil {
|
||||
s.PreHandler.Call(event)
|
||||
}
|
||||
|
||||
switch e := iface.(type) {
|
||||
// Run the state handler.
|
||||
s.onEvent(event)
|
||||
|
||||
// Always call the event on function exit. Extra events constructed by
|
||||
// handlers will be called before the main event, but that's fine.
|
||||
defer s.Handler.Call(event)
|
||||
|
||||
switch e := event.(type) {
|
||||
case *gateway.ReadyEvent:
|
||||
s.handleReady(e)
|
||||
return
|
||||
case *gateway.GuildCreateEvent:
|
||||
s.handleGuildCreate(e)
|
||||
return
|
||||
case *gateway.GuildDeleteEvent:
|
||||
s.handleGuildDelete(e)
|
||||
default:
|
||||
s.handleEvent(iface)
|
||||
return
|
||||
|
||||
// https://github.com/discord/discord-api-docs/commit/01665c4
|
||||
case *gateway.MessageCreateEvent:
|
||||
if e.Member != nil {
|
||||
e.Member.User = e.Author
|
||||
}
|
||||
case *gateway.MessageUpdateEvent:
|
||||
if e.Member != nil {
|
||||
e.Member.User = e.Author
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *State) onEvent(iface interface{}) {
|
||||
|
|
Loading…
Reference in a new issue