2020-09-08 04:44:09 +00:00
|
|
|
// Package state provides a shared state instance for other packages to use.
|
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-03-13 11:49:23 +00:00
|
|
|
"log"
|
2020-09-08 04:44:09 +00:00
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
"github.com/diamondburned/arikawa/utils/httputil/httpdriver"
|
2020-12-20 05:44:26 +00:00
|
|
|
"github.com/diamondburned/arikawa/v2/discord"
|
|
|
|
"github.com/diamondburned/arikawa/v2/session"
|
|
|
|
"github.com/diamondburned/arikawa/v2/state"
|
|
|
|
"github.com/diamondburned/arikawa/v2/state/store/defaultstore"
|
2020-10-07 01:53:15 +00:00
|
|
|
"github.com/diamondburned/cchat"
|
2021-03-13 08:21:12 +00:00
|
|
|
"github.com/diamondburned/cchat-discord/internal/discord/state/labels"
|
2020-12-19 05:46:12 +00:00
|
|
|
"github.com/diamondburned/cchat-discord/internal/discord/state/nonce"
|
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"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Instance struct {
|
|
|
|
*ningen.State
|
2020-12-19 05:46:12 +00:00
|
|
|
Nonces *nonce.Map
|
2021-03-13 08:21:12 +00:00
|
|
|
Labels *labels.Repository
|
2020-12-19 05:46:12 +00:00
|
|
|
|
2020-12-20 05:44:26 +00:00
|
|
|
// UserID is a constant user ID of the current user. It is guaranteed to be
|
|
|
|
// valid.
|
2020-09-08 04:44:09 +00:00
|
|
|
UserID discord.UserID
|
|
|
|
}
|
|
|
|
|
2020-12-19 05:46:12 +00:00
|
|
|
var _ cchat.SessionSaver = (*Instance)(nil)
|
2020-10-07 01:53:15 +00:00
|
|
|
|
|
|
|
// ErrInvalidSession is returned if SessionRestore is given a bad session.
|
|
|
|
var ErrInvalidSession = errors.New("invalid session")
|
|
|
|
|
|
|
|
func NewFromData(data map[string]string) (*Instance, error) {
|
|
|
|
tk, ok := data["token"]
|
|
|
|
if !ok {
|
|
|
|
return nil, ErrInvalidSession
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewFromToken(tk)
|
|
|
|
}
|
|
|
|
|
2020-09-08 04:44:09 +00:00
|
|
|
func NewFromToken(token string) (*Instance, error) {
|
|
|
|
s, err := state.New(token)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return New(s)
|
|
|
|
}
|
|
|
|
|
2020-10-07 01:53:15 +00:00
|
|
|
func Login(email, password, mfa string) (*Instance, error) {
|
|
|
|
session, err := session.Login(email, password, mfa)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-20 05:44:26 +00:00
|
|
|
cabinet := defaultstore.New()
|
|
|
|
cabinet.MessageStore = defaultstore.NewMessage(50)
|
|
|
|
|
|
|
|
return New(state.NewFromSession(session, cabinet))
|
2020-10-07 01:53:15 +00:00
|
|
|
}
|
|
|
|
|
2020-09-08 04:44:09 +00:00
|
|
|
func New(s *state.State) (*Instance, error) {
|
|
|
|
n, err := ningen.FromState(s)
|
|
|
|
if err != nil {
|
2020-12-19 05:46:12 +00:00
|
|
|
return nil, errors.Wrap(err, "failed to create a state wrapper")
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-13 11:49:23 +00:00
|
|
|
n.Client.OnRequest = append(n.Client.OnRequest,
|
|
|
|
func(r httpdriver.Request) error {
|
|
|
|
log.Println("[Discord] Request", r.GetPath())
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
)
|
2020-09-08 04:44:09 +00:00
|
|
|
|
|
|
|
if err := n.Open(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-20 05:44:26 +00:00
|
|
|
// Prefetch user.
|
|
|
|
u, err := s.Me()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "failed to get current user")
|
|
|
|
}
|
|
|
|
|
2020-09-08 04:44:09 +00:00
|
|
|
return &Instance{
|
|
|
|
UserID: u.ID,
|
|
|
|
State: n,
|
2020-12-19 05:46:12 +00:00
|
|
|
Nonces: new(nonce.Map),
|
2021-03-13 08:21:12 +00:00
|
|
|
Labels: labels.NewRepository(n),
|
2020-09-08 04:44:09 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-01-06 05:26:27 +00:00
|
|
|
// Permissions queries for the permission without hitting the REST API.
|
|
|
|
func (s *Instance) Permissions(
|
|
|
|
chID discord.ChannelID, uID discord.UserID) (discord.Permissions, error) {
|
|
|
|
|
|
|
|
return s.StateOnly().Permissions(chID, uID)
|
|
|
|
}
|
|
|
|
|
2021-03-13 08:21:12 +00:00
|
|
|
var deadCtx = expiredContext()
|
|
|
|
|
2020-09-08 04:44:09 +00:00
|
|
|
// StateOnly returns a shallow copy of *State with an already-expired context.
|
|
|
|
func (s *Instance) StateOnly() *state.State {
|
2021-03-13 08:21:12 +00:00
|
|
|
return s.WithContext(deadCtx)
|
2020-09-08 04:44:09 +00:00
|
|
|
}
|
2020-10-07 01:53:15 +00:00
|
|
|
|
|
|
|
func (s *Instance) SaveSession() map[string]string {
|
|
|
|
return map[string]string{
|
|
|
|
"token": s.Token,
|
|
|
|
}
|
|
|
|
}
|
2021-03-13 08:21:12 +00:00
|
|
|
|
|
|
|
func expiredContext() context.Context {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
return ctx
|
|
|
|
}
|