2022-11-30 10:51:24 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/bsm/redislock"
|
|
|
|
celo "github.com/grassrootseconomics/cic-celo-sdk"
|
|
|
|
"github.com/grassrootseconomics/cic-custodial/internal/keystore"
|
|
|
|
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
2023-02-03 10:29:27 +01:00
|
|
|
"github.com/grassrootseconomics/cic-custodial/internal/queries"
|
2023-02-09 12:23:37 +01:00
|
|
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
2022-11-30 10:51:24 +01:00
|
|
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
|
|
|
"github.com/grassrootseconomics/cic-custodial/pkg/logg"
|
|
|
|
"github.com/grassrootseconomics/cic-custodial/pkg/postgres"
|
|
|
|
"github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
2023-02-03 10:29:27 +01:00
|
|
|
"github.com/knadh/goyesql/v2"
|
2022-11-30 10:51:24 +01:00
|
|
|
"github.com/knadh/koanf"
|
|
|
|
"github.com/knadh/koanf/parsers/toml"
|
|
|
|
"github.com/knadh/koanf/providers/env"
|
|
|
|
"github.com/knadh/koanf/providers/file"
|
2023-02-09 12:23:37 +01:00
|
|
|
"github.com/nats-io/nats.go"
|
2022-11-30 10:51:24 +01:00
|
|
|
"github.com/zerodha/logf"
|
|
|
|
)
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load config file.
|
2022-11-30 10:51:24 +01:00
|
|
|
func initConfig(configFilePath string) *koanf.Koanf {
|
|
|
|
var (
|
|
|
|
ko = koanf.New(".")
|
|
|
|
)
|
|
|
|
|
|
|
|
confFile := file.Provider(configFilePath)
|
|
|
|
if err := ko.Load(confFile, toml.Parser()); err != nil {
|
2022-12-01 15:29:34 +01:00
|
|
|
lo.Fatal("Could not load config file", "error", err)
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := ko.Load(env.Provider("", ".", func(s string) string {
|
|
|
|
return strings.ReplaceAll(strings.ToLower(
|
|
|
|
strings.TrimPrefix(s, "")), "_", ".")
|
|
|
|
}), nil); err != nil {
|
2022-12-01 15:29:34 +01:00
|
|
|
lo.Fatal("Could not override config from env vars", "error", err)
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return ko
|
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load logger.
|
2022-12-01 15:29:34 +01:00
|
|
|
func initLogger(debug bool) logf.Logger {
|
|
|
|
loggOpts := logg.LoggOpts{
|
|
|
|
Color: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
if debug {
|
|
|
|
loggOpts.Caller = true
|
|
|
|
loggOpts.Debug = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return logg.NewLogg(loggOpts)
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load Celo chain provider.
|
|
|
|
func initCeloProvider() (*celo.Provider, error) {
|
2022-11-30 10:51:24 +01:00
|
|
|
providerOpts := celo.ProviderOpts{
|
|
|
|
RpcEndpoint: ko.MustString("chain.rpc_endpoint"),
|
|
|
|
}
|
|
|
|
|
|
|
|
if ko.Bool("chain.testnet") {
|
2023-02-12 10:50:43 +01:00
|
|
|
// Devnet = 1337
|
|
|
|
providerOpts.ChainId = 1337
|
2022-11-30 10:51:24 +01:00
|
|
|
} else {
|
|
|
|
providerOpts.ChainId = celo.MainnetChainId
|
|
|
|
}
|
|
|
|
|
|
|
|
provider, err := celo.NewProvider(providerOpts)
|
|
|
|
if err != nil {
|
2023-02-02 13:29:43 +01:00
|
|
|
return nil, err
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
return provider, nil
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load postgres pool.
|
|
|
|
func initPostgresPool() (*pgxpool.Pool, error) {
|
2022-11-30 10:51:24 +01:00
|
|
|
poolOpts := postgres.PostgresPoolOpts{
|
|
|
|
DSN: ko.MustString("postgres.dsn"),
|
|
|
|
}
|
|
|
|
|
|
|
|
pool, err := postgres.NewPostgresPool(poolOpts)
|
|
|
|
if err != nil {
|
2023-02-02 13:29:43 +01:00
|
|
|
return nil, err
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
return pool, nil
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load separate redis connection for the tasker on a reserved db namespace.
|
|
|
|
func initAsynqRedisPool() (*redis.RedisPool, error) {
|
2022-11-30 10:51:24 +01:00
|
|
|
poolOpts := redis.RedisPoolOpts{
|
|
|
|
DSN: ko.MustString("asynq.dsn"),
|
2023-02-03 10:29:27 +01:00
|
|
|
MinIdleConns: ko.MustInt("redis.min_idle_conn"),
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pool, err := redis.NewRedisPool(poolOpts)
|
|
|
|
if err != nil {
|
2023-02-02 13:29:43 +01:00
|
|
|
return nil, err
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
return pool, nil
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Common redis connection on a different db namespace from the takser.
|
|
|
|
func initCommonRedisPool() (*redis.RedisPool, error) {
|
2022-11-30 10:51:24 +01:00
|
|
|
poolOpts := redis.RedisPoolOpts{
|
|
|
|
DSN: ko.MustString("redis.dsn"),
|
2023-02-03 10:29:27 +01:00
|
|
|
MinIdleConns: ko.MustInt("redis.min_idle_conn"),
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pool, err := redis.NewRedisPool(poolOpts)
|
|
|
|
if err != nil {
|
2023-02-02 13:29:43 +01:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return pool, nil
|
|
|
|
}
|
|
|
|
|
2023-02-09 12:23:37 +01:00
|
|
|
// Load SQL statements into struct.
|
|
|
|
func initQueries(queriesPath string) (*queries.Queries, error) {
|
2023-02-03 10:29:27 +01:00
|
|
|
parsedQueries, err := goyesql.ParseFile(queriesFlag)
|
2023-02-02 13:29:43 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-03 10:29:27 +01:00
|
|
|
loadedQueries, err := queries.LoadQueries(parsedQueries)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-09 12:23:37 +01:00
|
|
|
return loadedQueries, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load postgres based keystore.
|
|
|
|
func initPostgresKeystore(postgresPool *pgxpool.Pool, queries *queries.Queries) (keystore.Keystore, error) {
|
2023-02-03 10:29:27 +01:00
|
|
|
keystore := keystore.NewPostgresKeytore(keystore.Opts{
|
|
|
|
PostgresPool: postgresPool,
|
2023-02-09 12:23:37 +01:00
|
|
|
Queries: queries,
|
2023-02-03 10:29:27 +01:00
|
|
|
})
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
return keystore, nil
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load redis backed noncestore.
|
|
|
|
func initRedisNoncestore(redisPool *redis.RedisPool, celoProvider *celo.Provider) nonce.Noncestore {
|
2022-11-30 10:51:24 +01:00
|
|
|
return nonce.NewRedisNoncestore(nonce.Opts{
|
2023-02-02 13:29:43 +01:00
|
|
|
RedisPool: redisPool,
|
|
|
|
CeloProvider: celoProvider,
|
2022-11-30 10:51:24 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load global lock provider.
|
|
|
|
func initLockProvider(redisPool redislock.RedisClient) *redislock.Client {
|
|
|
|
return redislock.New(redisPool)
|
2022-11-30 10:51:24 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:29:43 +01:00
|
|
|
// Load tasker client.
|
|
|
|
func initTaskerClient(redisPool *redis.RedisPool) *tasker.TaskerClient {
|
2022-11-30 10:51:24 +01:00
|
|
|
return tasker.NewTaskerClient(tasker.TaskerClientOpts{
|
2023-02-02 13:29:43 +01:00
|
|
|
RedisPool: redisPool,
|
|
|
|
TaskRetention: time.Duration(ko.MustInt64("asynq.task_retention_hrs")) * time.Hour,
|
2022-11-30 10:51:24 +01:00
|
|
|
})
|
|
|
|
}
|
2023-02-09 12:23:37 +01:00
|
|
|
|
|
|
|
// Load Postgres store
|
|
|
|
func initPostgresStore(postgresPool *pgxpool.Pool, queries *queries.Queries) store.Store {
|
|
|
|
return store.NewPostgresStore(store.Opts{
|
|
|
|
PostgresPool: postgresPool,
|
|
|
|
Queries: queries,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init JetStream context for tasker events.
|
|
|
|
func initJetStream() (nats.JetStreamContext, error) {
|
|
|
|
natsConn, err := nats.Connect(ko.MustString("jetstream.endpoint"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
js, err := natsConn.JetStream()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bootstrap stream if it does not exist
|
|
|
|
stream, _ := js.StreamInfo(ko.MustString("jetstream.stream_name"))
|
|
|
|
if stream == nil {
|
|
|
|
lo.Info("jetstream: bootstrapping stream")
|
|
|
|
_, err = js.AddStream(&nats.StreamConfig{
|
|
|
|
Name: ko.MustString("jetstream.stream_name"),
|
|
|
|
MaxAge: time.Duration(ko.MustInt("jetstream.persist_duration_hours")) * time.Hour,
|
|
|
|
Storage: nats.FileStorage,
|
|
|
|
Subjects: ko.MustStrings("jetstream.stream_subjects"),
|
|
|
|
Duplicates: time.Duration(ko.MustInt("jetstream.dedup_duration_hours")) * time.Hour,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return js, nil
|
|
|
|
}
|