2020-09-08 04:44:09 +00:00
|
|
|
package session
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-03-13 11:49:23 +00:00
|
|
|
"time"
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2020-12-20 05:44:26 +00:00
|
|
|
"github.com/diamondburned/arikawa/v2/gateway"
|
|
|
|
"github.com/diamondburned/arikawa/v2/session"
|
2020-09-08 04:44:09 +00:00
|
|
|
"github.com/diamondburned/cchat"
|
|
|
|
"github.com/diamondburned/cchat-discord/internal/discord/folder"
|
|
|
|
"github.com/diamondburned/cchat-discord/internal/discord/guild"
|
2020-12-17 08:01:58 +00:00
|
|
|
"github.com/diamondburned/cchat-discord/internal/discord/private"
|
2021-03-13 11:49:23 +00:00
|
|
|
"github.com/diamondburned/cchat-discord/internal/discord/shared/state"
|
|
|
|
"github.com/diamondburned/cchat-discord/internal/funcutil"
|
|
|
|
"github.com/diamondburned/cchat-discord/internal/segments/mention"
|
2020-09-08 04:44:09 +00:00
|
|
|
"github.com/diamondburned/cchat/text"
|
2020-10-07 01:53:15 +00:00
|
|
|
"github.com/diamondburned/cchat/utils/empty"
|
2020-12-20 05:44:26 +00:00
|
|
|
"github.com/diamondburned/ningen/v2"
|
2020-09-08 04:44:09 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
2020-10-07 01:53:15 +00:00
|
|
|
var ErrMFA = session.ErrMFA
|
|
|
|
|
2020-09-08 04:44:09 +00:00
|
|
|
type Session struct {
|
2020-10-14 20:22:11 +00:00
|
|
|
empty.Session
|
2020-12-17 08:01:58 +00:00
|
|
|
private cchat.Server
|
|
|
|
state *state.Instance
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 01:53:15 +00:00
|
|
|
func NewFromInstance(i *state.Instance) (cchat.Session, error) {
|
2020-12-17 08:01:58 +00:00
|
|
|
priv, err := private.New(i)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "failed to make main private server")
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Session{
|
|
|
|
private: priv,
|
|
|
|
state: i,
|
|
|
|
}, nil
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) ID() cchat.ID {
|
2020-12-17 08:01:58 +00:00
|
|
|
return s.state.UserID.String()
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
func (s *Session) Name(ctx context.Context, l cchat.LabelContainer) (func(), error) {
|
2020-12-20 05:44:26 +00:00
|
|
|
u, err := s.state.Cabinet.Me()
|
2020-09-08 04:44:09 +00:00
|
|
|
if err != nil {
|
2021-03-13 11:49:23 +00:00
|
|
|
l.SetLabel(text.Plain("<@" + s.state.UserID.String() + ">"))
|
|
|
|
} else {
|
|
|
|
user := mention.NewUser(*u)
|
|
|
|
user.WithState(s.state.State)
|
|
|
|
user.Prefetch()
|
|
|
|
|
|
|
|
rich := text.Plain(user.DisplayName())
|
|
|
|
rich.Segments = []text.Segment{
|
|
|
|
mention.Segment{
|
|
|
|
End: len(rich.Content),
|
|
|
|
User: user,
|
|
|
|
},
|
|
|
|
}
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
l.SetLabel(rich)
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
// TODO.
|
|
|
|
return func() {}, nil
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) Disconnect() error {
|
2021-03-13 11:49:23 +00:00
|
|
|
return s.state.CloseGracefully()
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
2020-12-17 08:01:58 +00:00
|
|
|
func (s *Session) AsSessionSaver() cchat.SessionSaver { return s.state }
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
func (s *Session) Servers(container cchat.ServersContainer) (func(), error) {
|
|
|
|
if err := s.servers(container); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
retryFn := func() {
|
|
|
|
// We should set up a back-off here.
|
|
|
|
for s.servers(container) != nil {
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
}
|
|
|
|
}
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
stop := funcutil.JoinCancels(
|
|
|
|
// Reset the entire container when the session is closed.
|
|
|
|
s.state.AddHandler(func(*session.Closed) {
|
|
|
|
container.SetServers(nil)
|
|
|
|
}),
|
|
|
|
|
|
|
|
// Set the entire container again once reconnected.
|
|
|
|
s.state.AddHandler(func(*ningen.Connected) {
|
|
|
|
retryFn()
|
|
|
|
}),
|
|
|
|
|
|
|
|
// Update the entire container when we update the guild list. Blame
|
|
|
|
// Discord on this one.
|
|
|
|
s.state.AddHandler(func(update *gateway.UserSettingsUpdateEvent) {
|
|
|
|
if update.GuildFolders != nil || update.GuildPositions != nil {
|
|
|
|
retryFn()
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
|
|
|
|
return stop, nil
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) servers(container cchat.ServersContainer) error {
|
2020-12-20 05:44:26 +00:00
|
|
|
ready := s.state.Ready()
|
2020-12-17 08:01:58 +00:00
|
|
|
|
2020-09-08 04:44:09 +00:00
|
|
|
// If the user has guild folders:
|
2021-03-13 08:21:12 +00:00
|
|
|
if len(ready.UserSettings.GuildFolders) > 0 {
|
2020-09-08 04:44:09 +00:00
|
|
|
// TODO: account for missing guilds.
|
2020-12-20 05:44:26 +00:00
|
|
|
toplevels := make([]cchat.Server, 1, len(ready.UserSettings.GuildFolders)+1)
|
2020-12-17 08:01:58 +00:00
|
|
|
toplevels[0] = s.private
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2020-12-20 05:44:26 +00:00
|
|
|
for _, guildFolder := range ready.UserSettings.GuildFolders {
|
2020-09-08 04:44:09 +00:00
|
|
|
// TODO: correct.
|
2021-03-13 11:49:23 +00:00
|
|
|
// TODO: correct how? What did I mean by this?
|
2020-09-08 04:44:09 +00:00
|
|
|
switch {
|
2020-10-14 20:22:11 +00:00
|
|
|
case guildFolder.ID != 0:
|
2020-09-08 04:44:09 +00:00
|
|
|
fallthrough
|
|
|
|
case len(guildFolder.GuildIDs) > 1:
|
2020-12-17 08:01:58 +00:00
|
|
|
toplevels = append(toplevels, folder.New(s.state, guildFolder))
|
2020-09-08 04:44:09 +00:00
|
|
|
|
|
|
|
case len(guildFolder.GuildIDs) == 1:
|
2020-12-17 08:01:58 +00:00
|
|
|
g, err := guild.NewFromID(s.state, guildFolder.GuildIDs[0])
|
2020-09-08 04:44:09 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
toplevels = append(toplevels, g)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
container.SetServers(toplevels)
|
2021-03-13 08:21:12 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-09-08 04:44:09 +00:00
|
|
|
|
|
|
|
// If the user doesn't have guild folders but has sorted their guilds
|
|
|
|
// before:
|
2021-03-13 08:21:12 +00:00
|
|
|
if len(ready.UserSettings.GuildPositions) > 0 {
|
2020-12-20 05:44:26 +00:00
|
|
|
guilds := make([]cchat.Server, 1, len(ready.UserSettings.GuildPositions)+1)
|
2020-12-17 08:01:58 +00:00
|
|
|
guilds[0] = s.private
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2020-12-20 05:44:26 +00:00
|
|
|
for _, id := range ready.UserSettings.GuildPositions {
|
2020-12-17 08:01:58 +00:00
|
|
|
g, err := guild.NewFromID(s.state, id)
|
2020-09-08 04:44:09 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
guilds = append(guilds, g)
|
|
|
|
}
|
|
|
|
|
|
|
|
container.SetServers(guilds)
|
2021-03-13 08:21:12 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-09-08 04:44:09 +00:00
|
|
|
|
|
|
|
// None of the above:
|
2021-03-13 08:21:12 +00:00
|
|
|
g, err := s.state.Guilds()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-17 08:01:58 +00:00
|
|
|
|
2021-03-13 08:21:12 +00:00
|
|
|
servers := make([]cchat.Server, len(g)+1)
|
|
|
|
servers[0] = s.private
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2021-03-13 08:21:12 +00:00
|
|
|
for i := range g {
|
|
|
|
servers[i+1] = guild.New(s.state, &g[i])
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-13 08:21:12 +00:00
|
|
|
container.SetServers(servers)
|
2020-09-08 04:44:09 +00:00
|
|
|
return nil
|
|
|
|
}
|