shard: Separate state's cabinet, fix return bugs

This commit makes it so that all sharded state.State instances will have
its own cabinet store on construction. This ensures that when a State is
reconnected, a Ready event won't wipe the cabinet for all other states.

This commit also fixes a bug with the Shard() and FromGuildID() getters.
This commit is contained in:
diamondburned 2021-10-31 13:10:34 -07:00
parent e8131db8df
commit 7f4daccd2d
No known key found for this signature in database
GPG Key ID: D78C4471CE776659
4 changed files with 9 additions and 27 deletions

View File

@ -155,7 +155,7 @@ func (m *Manager) Shard(ix int) Shard {
return nil
}
return m.shards[ix]
return m.shards[ix].Shard
}
// FromGuildID returns the Shard and the shard ID for the guild with the given
@ -165,7 +165,7 @@ func (m *Manager) FromGuildID(guildID discord.GuildID) (shard Shard, ix int) {
defer m.mutex.RUnlock()
ix = int(uint64(guildID>>22) % uint64(len(m.shards)))
return m.shards[ix], ix
return m.shards[ix].Shard, ix
}
// ForEach calls the given function on each shard from first to last. The caller

View File

@ -38,7 +38,7 @@ func NewGatewayShard(m *Manager, id *gateway.Identifier) *gateway.Gateway {
// ShardState wraps around the Gateway interface to provide additional state.
type ShardState struct {
Shard
Shard Shard
// This is a bit wasteful: 2 constant pointers are stored here, and they
// waste GC cycles. This is unavoidable, however, since the API has to take
// in a pointer to Identifier, not IdentifyData. This is to ensure rescales
@ -55,7 +55,7 @@ func (state ShardState) ShardID() int {
// OpenShards opens the gateways of the given list of shard states.
func OpenShards(ctx context.Context, shards []ShardState) error {
for i, shard := range shards {
if err := shard.Open(ctx); err != nil {
if err := shard.Shard.Open(ctx); err != nil {
CloseShards(shards)
return errors.Wrapf(err, "failed to open shard %d/%d", i, len(shards)-1)
}
@ -73,7 +73,7 @@ func CloseShards(shards []ShardState) error {
for i, gw := range shards {
if gw.Opened {
if err := gw.Close(); err != nil {
if err := gw.Shard.Close(); err != nil {
lastError = err
}

View File

@ -30,7 +30,6 @@ type Closed struct {
}
// NewShardFunc creates a shard constructor for a session.
// Accessing any shard and adding a handler will add a handler for all shards.
func NewShardFunc(f func(m *shard.Manager, s *Session)) shard.NewShardFunc {
return func(m *shard.Manager, id *gateway.Identifier) (shard.Shard, error) {
s := NewCustomShard(m, id)

View File

@ -22,29 +22,12 @@ var (
MaxFetchGuilds uint = 100
)
// NewShardFunc creates a shard constructor that shares the same handler. The
// given opts function is called everytime the State is created. If it doesn't
// set a cabinet into the state, then a shared default cabinet is set instead.
// NewShardFunc creates a shard constructor with its own state registry and
// handlers. The given opts function is called everytime the State is created.
// The user should initialize handlers and intents in the opts function.
func NewShardFunc(opts func(*shard.Manager, *State)) shard.NewShardFunc {
var once sync.Once
var cab *store.Cabinet
return func(m *shard.Manager, id *gateway.Identifier) (shard.Shard, error) {
state := NewFromSession(session.NewCustomShard(m, id), nil)
if opts != nil {
opts(m, state)
}
if state.Cabinet == nil {
// Create the cabinet once; use sync.Once so the constructor can be
// concurrently safe.
once.Do(func() { cab = defaultstore.New() })
state.Cabinet = cab
}
return state, nil
return NewFromSession(session.NewCustomShard(m, id), defaultstore.New()), nil
}
}