110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package dmapi
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
type token string
|
|
|
|
const sessionIDKey token = "session-id"
|
|
|
|
// Token session ID.
|
|
// > Every request (except "login") requires the presence of the Auth-Sid variable ("Session ID"),
|
|
// > which is returned by the "login" request (login). An active session will expire after some inactivity period (default: 1 hour).
|
|
// https://joker.com/faq/content/22/12/en/commonalities-for-all-requests.html
|
|
type Token struct {
|
|
SessionID string
|
|
ExpireAt time.Time
|
|
}
|
|
|
|
// login performs a log in to Joker's DMAPI.
|
|
func (c *Client) login(ctx context.Context) (*Response, error) {
|
|
var values url.Values
|
|
switch {
|
|
case c.username != "" && c.password != "":
|
|
values = url.Values{
|
|
"username": {c.username},
|
|
"password": {c.password},
|
|
}
|
|
case c.apiKey != "":
|
|
values = url.Values{"api-key": {c.apiKey}}
|
|
default:
|
|
return nil, errors.New("no username and password or api-key")
|
|
}
|
|
|
|
response, err := c.postRequest(ctx, "login", values)
|
|
if err != nil {
|
|
return response, err
|
|
}
|
|
|
|
if response == nil {
|
|
return nil, errors.New("login returned nil response")
|
|
}
|
|
|
|
if response.AuthSid == "" {
|
|
return response, errors.New("login did not return valid Auth-Sid")
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// Logout closes authenticated session with Joker's DMAPI.
|
|
func (c *Client) Logout(ctx context.Context) (*Response, error) {
|
|
if c.token == nil {
|
|
return nil, errors.New("already logged out")
|
|
}
|
|
|
|
response, err := c.postRequest(ctx, "logout", url.Values{})
|
|
|
|
c.muToken.Lock()
|
|
c.token = nil
|
|
c.muToken.Unlock()
|
|
|
|
if err != nil {
|
|
return response, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (c *Client) CreateAuthenticatedContext(ctx context.Context) (context.Context, error) {
|
|
c.muToken.Lock()
|
|
defer c.muToken.Unlock()
|
|
|
|
if c.token != nil && time.Now().UTC().Before(c.token.ExpireAt) {
|
|
return context.WithValue(ctx, sessionIDKey, c.token.SessionID), nil
|
|
}
|
|
|
|
response, err := c.login(ctx)
|
|
if err != nil {
|
|
return nil, formatResponseError(response, err)
|
|
}
|
|
|
|
c.token = &Token{
|
|
SessionID: response.AuthSid,
|
|
ExpireAt: time.Now().UTC().Add(1 * time.Hour),
|
|
}
|
|
|
|
return context.WithValue(ctx, sessionIDKey, response.AuthSid), nil
|
|
}
|
|
|
|
func getSessionID(ctx context.Context) string {
|
|
tok, ok := ctx.Value(sessionIDKey).(string)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
return tok
|
|
}
|
|
|
|
// formatResponseError formats error with optional details from DMAPI response.
|
|
func formatResponseError(response *Response, err error) error {
|
|
if response != nil {
|
|
return fmt.Errorf("joker: DMAPI error: %w Response: %v", err, response.Headers)
|
|
}
|
|
return fmt.Errorf("joker: DMAPI error: %w", err)
|
|
}
|