sorarebuddy/cmd/common/init.go
2024-05-23 08:18:54 +04:00

229 lines
6.9 KiB
Go

package common
import (
"context"
"fmt"
"os"
"runtime"
"strings"
"time"
"git.lehouerou.net/laurent/sorare"
"git.lehouerou.net/laurent/sorare/graphql"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/stdlib"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/extra/bundebug"
)
func InitParams(cmd *cobra.Command) {
cobra.OnInitialize(InitLog)
viper.AutomaticEnv()
viper.SetEnvPrefix("sorare")
cmd.PersistentFlags().BoolP("verbose", "v", false, "Verbose output")
_ = viper.BindPFlag("verbose", cmd.PersistentFlags().Lookup("verbose"))
viper.SetDefault("verbose", false)
cmd.PersistentFlags().String("jwttoken", "", "Sorare JWT Token")
_ = viper.BindPFlag("jwttoken", cmd.PersistentFlags().Lookup("jwttoken"))
viper.SetDefault("jwttoken", "")
cmd.PersistentFlags().String("jwtaudience", "", "Sorare JWT Audience")
_ = viper.BindPFlag("jwtaudience", cmd.PersistentFlags().Lookup("jwtaudience"))
viper.SetDefault("jwtaudience", "")
cmd.PersistentFlags().String("email", "", "Sorare Email")
_ = viper.BindPFlag("email", cmd.PersistentFlags().Lookup("email"))
viper.SetDefault("email", "")
cmd.PersistentFlags().String("password", "", "Sorare Password")
_ = viper.BindPFlag("password", cmd.PersistentFlags().Lookup("password"))
viper.SetDefault("password", "")
cmd.PersistentFlags().String("otp", "", "Sorare OTP")
_ = viper.BindPFlag("otp", cmd.PersistentFlags().Lookup("otp"))
viper.SetDefault("otp", "")
cmd.PersistentFlags().String("dbhost", "", "Database Host")
_ = viper.BindPFlag("dbhost", cmd.PersistentFlags().Lookup("dbhost"))
viper.SetDefault("dbhost", "192.168.1.250")
cmd.PersistentFlags().String("dbport", "", "Database Port")
_ = viper.BindPFlag("dbport", cmd.PersistentFlags().Lookup("dbport"))
viper.SetDefault("dbport", "5436")
cmd.PersistentFlags().String("dbuser", "", "Database User")
_ = viper.BindPFlag("dbuser", cmd.PersistentFlags().Lookup("dbuser"))
viper.SetDefault("dbuser", "sorare")
cmd.PersistentFlags().String("dbpass", "", "Database Password")
_ = viper.BindPFlag("dbpass", cmd.PersistentFlags().Lookup("dbpass"))
viper.SetDefault("dbpass", "sorare")
cmd.PersistentFlags().String("dbname", "", "Database Name")
_ = viper.BindPFlag("dbname", cmd.PersistentFlags().Lookup("dbname"))
viper.SetDefault("dbname", "sorare")
cmd.PersistentFlags().String("privatekey", "", "Sorare Private Key")
_ = viper.BindPFlag("privatekey", cmd.PersistentFlags().Lookup("privatekey"))
viper.SetDefault("privatekey", "")
cmd.PersistentFlags().Bool("tracedb", false, "Trace Database Queries")
_ = viper.BindPFlag("tracedb", cmd.PersistentFlags().Lookup("tracedb"))
viper.SetDefault("tracedb", false)
cmd.PersistentFlags().Bool("tracesorare", false, "Trace Sorare API Calls")
_ = viper.BindPFlag("tracesorare", cmd.PersistentFlags().Lookup("tracesorare"))
viper.SetDefault("tracesorare", false)
cmd.PersistentFlags().String("cryptkey", "", "Crypt Key")
_ = viper.BindPFlag("cryptkey", cmd.PersistentFlags().Lookup("cryptkey"))
viper.SetDefault("cryptkey", "")
cmd.PersistentFlags().String("jwtkey", "", "JWT Key")
_ = viper.BindPFlag("jwtkey", cmd.PersistentFlags().Lookup("jwtkey"))
viper.SetDefault("jwtkey", "")
}
func InitLog() {
log.Logger = zerolog.New(zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: "2006-01-02 | 15:04:05.000",
FormatLevel: func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("| %-6s|", i))
},
FormatFieldName: func(i interface{}) string {
return fmt.Sprintf("%s:", i)
},
FormatFieldValue: func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("%s", i))
},
}).With().Timestamp().Logger()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMicro
zerolog.SetGlobalLevel(zerolog.InfoLevel)
verbose := viper.GetBool("verbose")
if verbose {
log.Info().Msg("Verbose output enabled")
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
}
func InitSorare(ctx context.Context) (*sorare.Sorare, error) {
audience := viper.GetString("jwtaudience")
if audience == "" {
return nil, errors.New("jwtaudience is required")
}
jwttoken := viper.GetString("jwttoken")
s := sorare.New()
tracesorare := viper.GetBool("tracesorare")
if tracesorare {
s.Debug()
}
if jwttoken != "" {
s.SetJWTToken(graphql.JwtToken{
Token: jwttoken,
ExpiredAt: time.Time{},
}, audience)
} else {
email := viper.GetString("email")
password := viper.GetString("password")
otp := viper.GetString("otp")
err := s.Authenticate(ctx, email, password, audience, otp)
if err != nil {
return nil, errors.Wrap(err, "authenticating to sorare")
}
log.Info().Msgf("authentication to sorare successful. new token: %s", s.GetCurrentToken().Token)
}
cu, err := s.Users.CurrentUser.Get(ctx, graphql.EmptyParams{})
if err != nil {
return nil, errors.Wrap(err, "getting current user")
}
log.Info().Msgf("authenticated on Sorare as %s (%s)", cu.Nickname, cu.Profile.ClubName)
return s, nil
}
func InitDb(ctx context.Context) (*bun.DB, error) {
host := viper.GetString("dbhost")
if host == "" {
return nil, errors.New("dbhost is required")
}
port := viper.GetString("dbport")
if port == "" {
return nil, errors.New("dbport is required")
}
user := viper.GetString("dbuser")
if user == "" {
return nil, errors.New("dbuser is required")
}
password := viper.GetString("dbpass")
if password == "" {
return nil, errors.New("dbpass is required")
}
dbname := viper.GetString("dbname")
if dbname == "" {
return nil, errors.New("dbname is required")
}
maxOpenConns := 4 * runtime.GOMAXPROCS(0)
pgxconfig, err := pgx.ParseConfig(
fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", user, password, host, port, dbname),
)
if err != nil {
return nil, errors.Wrap(err, "parsing pgx config")
}
sqldb := stdlib.OpenDB(*pgxconfig)
db := bun.NewDB(sqldb, pgdialect.New())
db.SetMaxOpenConns(maxOpenConns)
tracedb := viper.GetBool("tracedb")
if tracedb {
db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
}
// Test the connection
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.DB.PingContext(ctx); err != nil {
return nil, errors.Wrap(err, "pinging database")
}
log.Info().Msgf("connected to database %s@%s:%s/%s", user, host, port, dbname)
return db, nil
}
type contextKey string
const (
SorareContextKey contextKey = "sorare"
DbContextKey contextKey = "db"
)
func CmdPreRunE(cmd *cobra.Command, _ []string) error {
s, err := InitSorare(cmd.Context())
if err != nil {
return errors.Wrap(err, "initializing sorare client")
}
cmd.SetContext(context.WithValue(cmd.Context(), SorareContextKey, s))
db, err := InitDb(cmd.Context())
if err != nil {
return errors.Wrap(err, "initializing database")
}
cmd.SetContext(context.WithValue(cmd.Context(), DbContextKey, db))
return nil
}