strimertul/twitch/api.go

116 lines
2.7 KiB
Go

package twitch
import (
"fmt"
"time"
"github.com/nicklaw5/helix/v2"
"git.sr.ht/~ashkeel/strimertul/database"
)
func GetConfig(db database.Database) (Config, error) {
var config Config
if err := db.GetJSON(ConfigKey, &config); err != nil {
return Config{}, fmt.Errorf("failed to get twitch config: %w", err)
}
return config, nil
}
type AuthResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
Scope []string `json:"scope"`
Time time.Time
}
func GetUserClient(db database.Database, keyPath string, forceRefresh bool) (*helix.Client, error) {
var authResp AuthResponse
if err := db.GetJSON(keyPath, &authResp); err != nil {
return nil, err
}
// Handle token expiration
if forceRefresh || time.Now().After(authResp.Time.Add(time.Duration(authResp.ExpiresIn)*time.Second)) {
// Refresh tokens
api, err := GetHelixAPI(db, "")
if err != nil {
return nil, err
}
refreshed, err := api.RefreshUserAccessToken(authResp.RefreshToken)
if err != nil {
return nil, err
}
authResp.AccessToken = refreshed.Data.AccessToken
authResp.RefreshToken = refreshed.Data.RefreshToken
authResp.Time = time.Now().Add(time.Duration(refreshed.Data.ExpiresIn) * time.Second)
// Save new token pair
err = db.PutJSON(keyPath, authResp)
if err != nil {
return nil, err
}
}
return GetHelixAPI(db, authResp.AccessToken)
}
func GetHelixAPI(db database.Database, userToken string) (*helix.Client, error) {
config, err := GetConfig(db)
if err != nil {
return nil, err
}
// If a user token is provided, create a user client
if userToken != "" {
return helix.NewClient(&helix.Options{
ClientID: config.APIClientID,
ClientSecret: config.APIClientSecret,
UserAccessToken: userToken,
})
}
// If no user token is provided, create an app client
baseurl, err := baseURL(db)
if err != nil {
return nil, err
}
redirectURI := getRedirectURI(baseurl)
// Create Twitch client
api, err := helix.NewClient(&helix.Options{
ClientID: config.APIClientID,
ClientSecret: config.APIClientSecret,
RedirectURI: redirectURI,
})
if err != nil {
return nil, err
}
// Get access token
resp, err := api.RequestAppAccessToken([]string{"user:read:email"})
if err != nil {
return nil, err
}
// Set the access token on the client
api.SetAppAccessToken(resp.Data.AccessToken)
return api, nil
}
func baseURL(db database.Database) (string, error) {
var severConfig struct {
Bind string `json:"bind"`
}
err := db.GetJSON("http/config", &severConfig)
return severConfig.Bind, err
}
func getRedirectURI(baseurl string) string {
return fmt.Sprintf("http://%s/twitch/callback", baseurl)
}