Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168package cliutil
import ( "encoding/json" "fmt" "net/http" "os" "path/filepath" "strings" "time"
"github.com/bluesky-social/indigo/xrpc"
slogGorm "github.com/orandin/slog-gorm" "github.com/urfave/cli/v2" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm")
func NewHttpClient() *http.Client { return &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, ForceAttemptHTTP2: true, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, }, }}
func GetXrpcClient(cctx *cli.Context, authreq bool) (*xrpc.Client, error) { h := "http://localhost:4989" if pdsurl := cctx.String("pds-host"); pdsurl != "" { h = pdsurl }
auth, err := loadAuthFromEnv(cctx, authreq) if err != nil { return nil, fmt.Errorf("loading auth: %w", err) }
return &xrpc.Client{ Client: NewHttpClient(), Host: h, Auth: auth, }, nil}
func loadAuthFromEnv(cctx *cli.Context, req bool) (*xrpc.AuthInfo, error) { if a := cctx.String("auth"); a != "" { if ai, err := ReadAuth(a); err != nil && req { return nil, err } else { return ai, nil } }
val := os.Getenv("ATP_AUTH_FILE") if val == "" { if req { return nil, fmt.Errorf("no auth env present, ATP_AUTH_FILE not set") }
return nil, nil }
var auth xrpc.AuthInfo if err := json.Unmarshal([]byte(val), &auth); err != nil { return nil, err }
return &auth, nil}
func ReadAuth(fname string) (*xrpc.AuthInfo, error) { b, err := os.ReadFile(fname) if err != nil { return nil, err } var auth xrpc.AuthInfo if err := json.Unmarshal(b, &auth); err != nil { return nil, err }
return &auth, nil}
// Supports both previous "dbtype=" prefixed DSNs, and URI-style database config strings, for both sqlite and postgresql.//// Examples:// - "sqlite=dir/file.sqlite"// - "sqlite://file.sqlite"// - "postgres=host=localhost user=postgres password=password dbname=pdsdb port=5432 sslmode=disable"// - "postgresql://postgres:password@localhost:5432/pdsdb?sslmode=disable"func SetupDatabase(dburl string, maxConnections int) (*gorm.DB, error) { var dial gorm.Dialector // NOTE(bnewbold): might also handle file:// as sqlite, but let's keep it // explicit for now
isSqlite := false openConns := maxConnections if strings.HasPrefix(dburl, "sqlite://") { sqliteSuffix := dburl[len("sqlite://"):] // if this isn't ":memory:", ensure that directory exists (eg, if db // file is being initialized) if !strings.Contains(sqliteSuffix, ":?") { os.MkdirAll(filepath.Dir(sqliteSuffix), os.ModePerm) } dial = sqlite.Open(sqliteSuffix) openConns = 1 isSqlite = true } else if strings.HasPrefix(dburl, "sqlite=") { sqliteSuffix := dburl[len("sqlite="):] // if this isn't ":memory:", ensure that directory exists (eg, if db // file is being initialized) if !strings.Contains(sqliteSuffix, ":?") { os.MkdirAll(filepath.Dir(sqliteSuffix), os.ModePerm) } dial = sqlite.Open(sqliteSuffix) openConns = 1 isSqlite = true } else if strings.HasPrefix(dburl, "postgresql://") || strings.HasPrefix(dburl, "postgres://") { // can pass entire URL, with prefix, to gorm driver dial = postgres.Open(dburl) } else if strings.HasPrefix(dburl, "postgres=") { dsn := dburl[len("postgres="):] dial = postgres.Open(dsn) } else { // TODO(bnewbold): this might print password? return nil, fmt.Errorf("unsupported or unrecognized DATABASE_URL value: %s", dburl) }
gormLogger := slogGorm.New()
db, err := gorm.Open(dial, &gorm.Config{ SkipDefaultTransaction: true, TranslateError: true, Logger: gormLogger, }) if err != nil { return nil, err }
sqldb, err := db.DB() if err != nil { return nil, err }
sqldb.SetMaxIdleConns(80) sqldb.SetMaxOpenConns(openConns) sqldb.SetConnMaxIdleTime(time.Hour)
if isSqlite { // Set pragmas for sqlite if err := db.Exec("PRAGMA journal_mode=WAL;").Error; err != nil { return nil, err } if err := db.Exec("PRAGMA synchronous=normal;").Error; err != nil { return nil, err } }
return db, nil}