diff options
Diffstat (limited to 'backend/cmd/main.go')
-rw-r--r-- | backend/cmd/main.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/backend/cmd/main.go b/backend/cmd/main.go new file mode 100644 index 0000000..8040560 --- /dev/null +++ b/backend/cmd/main.go @@ -0,0 +1,159 @@ +package main + +import ( + "context" + "fmt" + "log" + "log/slog" + "net/http" + "os" + "os/signal" + "time" + + "ibd-trader/internal/analyzer/openai" + auth2 "ibd-trader/internal/auth" + "ibd-trader/internal/config" + "ibd-trader/internal/database" + "ibd-trader/internal/ibd" + "ibd-trader/internal/keys" + "ibd-trader/internal/leader/election" + "ibd-trader/internal/leader/manager" + "ibd-trader/internal/server2" + "ibd-trader/internal/worker" + + "github.com/lmittmann/tint" + "github.com/redis/go-redis/v9" +) + +func main() { + // Load the config + cfg, err := config.New() + if err != nil { + log.Fatal("Unable to load config: ", err) + } + + // Setup slog + var level slog.Level + if err = level.UnmarshalText([]byte(cfg.Log.Level)); err != nil { + log.Fatal("Unable to parse log level: ", err) + } + var logger *slog.Logger + opts := &tint.Options{ + AddSource: cfg.Log.AddSource, + Level: level, + NoColor: !cfg.Log.Color, + } + logger = slog.New(tint.NewHandler(os.Stdout, opts)) + slog.SetDefault(logger) + + logger.Info( + "Starting IBD Trader...", + "logger.level", level, + ) + + // Connect to the database + db, err := connectDB(logger, cfg) + defer db.Close() + if err != nil { + log.Fatal("Unable to connect to database: ", err) + } + + // Connect to redis + redisClient := redis.NewClient(&redis.Options{ + Addr: cfg.Redis.Addr, + Password: cfg.Redis.Password, + }) + defer redisClient.Close() + + // Setup auth + auth, err := auth2.New(cfg) + if err != nil { + log.Fatal("Unable to setup auth: ", err) + } + _ = auth + + // Setup IBD client + client, err := ibd.NewClient(http.DefaultClient, cfg.IBD.APIKey, db, cfg.IBD.ProxyURL) + if err != nil { + log.Fatal("Unable to setup IBD client: ", err) + } + + // Setup analyzer + analyzer := openai.NewAnalyzer(openai.WithDefaultConfig(cfg.Analyzer.OpenAI.APIKey)) + _ = analyzer + + // Setup context w/ signal handling + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + + //// Start the server + //go func() { + // if err := server.StartServer(ctx, cfg, logger, db, auth, client, redisClient); err != nil { + // log.Fatal("Unable to start server: ", err) + // } + // // Cancel the context when the server stops + // cancel() + //}() + + // Start the gRPC server + go func() { + server, err := server2.New(ctx, cfg.Server.Port, db, redisClient) + if err != nil { + log.Fatal("Unable to create gRPC server: ", err) + } + if err := server.Serve(ctx); err != nil { + slog.ErrorContext(ctx, "Unable to start gRPC server", "error", err) + } + // Cancel the context when the server stops + cancel() + }() + + // Start the worker + go func() { + err := worker.StartWorker( + ctx, + client, + redisClient, + db, + analyzer, + ) + if err != nil { + log.Fatal("Unable to start worker: ", err) + } + // Cancel the context when the worker stops + cancel() + }() + + // Start leader election + election.RunOrDie( + ctx, + redisClient, + func(ctx context.Context) { + m, err := manager.New(ctx, cfg, redisClient, db, client) + if err != nil { + logger.Error("Unable to create manager", "error", err) + return + } + if err = m.Run(ctx); err != nil { + logger.Error("Manager exited with error", "error", err) + } + }, + ) +} + +func connectDB(logger *slog.Logger, cfg *config.Config) (database.Database, error) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + kms, err := keys.NewGoogleKMS(ctx) + if err != nil { + return nil, fmt.Errorf("unable to create Google KMS Client: %w", err) + } + + db, err := database.New(ctx, logger, cfg.DB.URL, kms, cfg.KMS.GCP.String()) + if err != nil { + return nil, err + } + + return db, nil +} |