connector: fix UserLogin lifecycle during provisioning
Bridge provisioning would crash because we wouldn't thread the necessary database models through.
This commit is contained in:
@@ -33,10 +33,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DiscordClient struct {
|
type DiscordClient struct {
|
||||||
connector *DiscordConnector
|
connector *DiscordConnector
|
||||||
usersFromReady map[string]*discordgo.User
|
usersFromReady map[string]*discordgo.User
|
||||||
UserLogin *bridgev2.UserLogin
|
UserLogin *bridgev2.UserLogin
|
||||||
Session *discordgo.Session
|
Session *discordgo.Session
|
||||||
|
hasBegunSyncing bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DiscordConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error {
|
func (d *DiscordConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error {
|
||||||
@@ -116,23 +117,6 @@ func (cl *DiscordClient) connect(ctx context.Context) error {
|
|||||||
user := cl.Session.State.User
|
user := cl.Session.State.User
|
||||||
log.Info().Str("user_id", user.ID).Str("user_username", user.Username).Msg("Connected to Discord")
|
log.Info().Str("user_id", user.ID).Str("user_username", user.Username).Msg("Connected to Discord")
|
||||||
|
|
||||||
if cl.UserLogin != nil {
|
|
||||||
// Feels a bit hacky to check for this here, but it should be true when
|
|
||||||
// logging in initially. The UserLogin is only ever created if we know
|
|
||||||
// that we connected successfully. We _do_ know that by now here, but we're
|
|
||||||
// not tasked with creating the UserLogin; the login code is. Alas.
|
|
||||||
|
|
||||||
// FIXME(skip): Avatar.
|
|
||||||
cl.UserLogin.RemoteProfile = status.RemoteProfile{
|
|
||||||
Email: user.Email,
|
|
||||||
Phone: user.Phone,
|
|
||||||
Name: user.String(),
|
|
||||||
}
|
|
||||||
if err := cl.UserLogin.Save(ctx); err != nil {
|
|
||||||
log.Err(err).Msg("Couldn't save UserLogin after connecting")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stash all of the users we received in READY so we can perform quick lookups
|
// Stash all of the users we received in READY so we can perform quick lookups
|
||||||
// keyed by user ID.
|
// keyed by user ID.
|
||||||
cl.usersFromReady = make(map[string]*discordgo.User)
|
cl.usersFromReady = make(map[string]*discordgo.User)
|
||||||
@@ -140,7 +124,11 @@ func (cl *DiscordClient) connect(ctx context.Context) error {
|
|||||||
cl.usersFromReady[user.ID] = user
|
cl.usersFromReady[user.ID] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
go cl.syncChannels(ctx)
|
// We won't have a UserLogin during provisioning, because the UserLogin can
|
||||||
|
// only be properly constructed once we know what the Discord user ID is
|
||||||
|
// (i.e. we have returned from this function). Thus, rely on the login
|
||||||
|
// process calling this method manually.
|
||||||
|
cl.BeginSyncingIfUserLoginPresent(ctx)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -160,6 +148,33 @@ func (d *DiscordClient) LogoutRemote(ctx context.Context) {
|
|||||||
d.Disconnect()
|
d.Disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cl *DiscordClient) BeginSyncingIfUserLoginPresent(ctx context.Context) {
|
||||||
|
if cl.UserLogin == nil {
|
||||||
|
cl.connector.bridge.Log.Warn().Msg("Not syncing just yet as we don't have a UserLogin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cl.hasBegunSyncing {
|
||||||
|
cl.connector.bridge.Log.Warn().Msg("Not beginning sync more than once")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cl.hasBegunSyncing = true
|
||||||
|
|
||||||
|
log := cl.UserLogin.Log
|
||||||
|
user := cl.Session.State.User
|
||||||
|
|
||||||
|
// FIXME(skip): Avatar.
|
||||||
|
cl.UserLogin.RemoteProfile = status.RemoteProfile{
|
||||||
|
Email: user.Email,
|
||||||
|
Phone: user.Phone,
|
||||||
|
Name: user.String(),
|
||||||
|
}
|
||||||
|
if err := cl.UserLogin.Save(ctx); err != nil {
|
||||||
|
log.Err(err).Msg("Couldn't save UserLogin after connecting")
|
||||||
|
}
|
||||||
|
|
||||||
|
go cl.syncChannels(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DiscordClient) syncChannels(ctx context.Context) {
|
func (d *DiscordClient) syncChannels(ctx context.Context) {
|
||||||
for _, dm := range d.Session.State.PrivateChannels {
|
for _, dm := range d.Session.State.PrivateChannels {
|
||||||
d.UserLogin.Log.Debug().Str("channel_id", dm.ID).Msg("Syncing private channel")
|
d.UserLogin.Log.Debug().Str("channel_id", dm.ID).Msg("Syncing private channel")
|
||||||
|
|||||||
@@ -48,13 +48,14 @@ func (d *DiscordConnector) CreateLogin(ctx context.Context, user *bridgev2.User,
|
|||||||
return nil, fmt.Errorf("unknown login flow ID")
|
return nil, fmt.Errorf("unknown login flow ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &DiscordLogin{User: user}, nil
|
return &DiscordLogin{connector: d, User: user}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiscordLogin struct {
|
type DiscordLogin struct {
|
||||||
User *bridgev2.User
|
connector *DiscordConnector
|
||||||
Token string
|
User *bridgev2.User
|
||||||
Session *discordgo.Session
|
Token string
|
||||||
|
Session *discordgo.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ bridgev2.LoginProcessUserInput = (*DiscordLogin)(nil)
|
var _ bridgev2.LoginProcessUserInput = (*DiscordLogin)(nil)
|
||||||
@@ -104,7 +105,8 @@ func (dl *DiscordLogin) SubmitUserInput(ctx context.Context, input map[string]st
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := DiscordClient{
|
client := DiscordClient{
|
||||||
Session: session,
|
connector: dl.connector,
|
||||||
|
Session: session,
|
||||||
}
|
}
|
||||||
err = client.connect(ctx)
|
err = client.connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -123,9 +125,14 @@ func (dl *DiscordLogin) SubmitUserInput(ctx context.Context, input map[string]st
|
|||||||
HeartbeatSession: session.HeartbeatSession,
|
HeartbeatSession: session.HeartbeatSession,
|
||||||
},
|
},
|
||||||
}, &bridgev2.NewLoginParams{
|
}, &bridgev2.NewLoginParams{
|
||||||
// We already have a Session; call this instead of the connector's main LoadUserLogin method and thread the Session through.
|
// We already have a Session; let's call this instead of the connector's
|
||||||
|
// main LoadUserLogin method, and thread the Session through.
|
||||||
LoadUserLogin: func(ctx context.Context, login *bridgev2.UserLogin) error {
|
LoadUserLogin: func(ctx context.Context, login *bridgev2.UserLogin) error {
|
||||||
login.Client = &client
|
login.Client = &client
|
||||||
|
client.UserLogin = login
|
||||||
|
|
||||||
|
// Only now that we have a UserLogin can we begin syncing.
|
||||||
|
client.BeginSyncingIfUserLoginPresent(ctx)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
DeleteOnConflict: true,
|
DeleteOnConflict: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user