Files
softplayer-backend/main.go
2026-04-26 21:06:33 +02:00

160 lines
4.9 KiB
Go

package main
import (
"context"
"database/sql"
"errors"
"fmt"
"net"
"os"
v1 "gitea.badhouseplants.net/softplayer/softplayer-backend/api/v1"
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/email"
"gitea.badhouseplants.net/softplayer/softplayer-backend/internal/tools/logger"
"gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts/v1"
applications_proto "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/applications/v1"
email_proto "gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/email/v1"
"gitea.badhouseplants.net/softplayer/softplayer-go-proto/pkg/environments/v1"
"github.com/alecthomas/kong"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
_ "github.com/lib/pq"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
ctrl "sigs.k8s.io/controller-runtime"
)
type Serve struct {
Port int64 `short:"p" env:"SOFTPLAYER_PORT" default:"4020"`
Host string `env:"SOFTPLAYER_HOST" default:"0.0.0.0"`
HashCost int16 `env:"SOFTPLAYER_HASH_COST" default:"1"`
Reflection bool `env:"SOFTPLAYER_REFLECTION" default:"false"`
DevMode bool `env:"SOFTPLAYER_DEV_MODE" default:"false"`
SmtpHost string `env:"SOFTPLAYER_SMTP_HOST"`
SmtpPort string `env:"SOFTPLAYER_SMTP_PORT" default:"587"`
SmtpFrom string `env:"SOFTPLAYER_SMTP_FROM" default:"overlord@badhouseplants.net"`
SmtpPassword string `env:"SOFTPLAYER_SMTP_PASSWORD"`
DownloadDir string `env:"SOFTPLAYER_DOWNLOAD_DIR" default:"/tmp/softplayer"`
DBConnectionString string `env:"SOFTPLAYER_DB_CONNECTION_STRING"`
}
var CLI struct {
Serve Serve `cmd:"" help:"Start the grpc server"`
}
func main() {
kongCtx := kong.Parse(&CLI)
ctx := logger.NewLogger(context.Background(), "info")
switch kongCtx.Command() {
case "serve":
if err := server(ctx, CLI.Serve); err != nil {
panic(err)
}
default:
panic(kongCtx.Command())
}
}
func migrateDB(ctx context.Context, db *sql.DB) error {
log := logger.FromContext(ctx)
log.Info("Starting a database migration driver")
driver, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
log.Error(err, "Couldn't start a database migration driver")
return err
}
log.Info("Preparing database migrations")
m, err := migrate.NewWithDatabaseInstance(
"file://migrations",
"postgres", driver)
if err != nil {
log.Error(err, "Couldn't perform database migrations")
return err
}
log.Info("Starting database migrations")
err = m.Up() // or m.Steps(2) if you want to explicitly set the number of migrations to r
if err != nil {
if errors.Is(err, migrate.ErrNoChange) {
log.Info("Database is already up-to-date")
} else {
log.Error(err, "Couldn't migrate the database")
return err
}
}
return nil
}
func server(ctx context.Context, params Serve) error {
// Make sure the download dir exists
log := logger.FromContext(ctx)
if err := os.MkdirAll(params.DownloadDir, 0o777); err != nil {
log.Error(err, "Coulnd't create a download dir")
return err
}
// Init a logger
log.Info("Starting a kubernetes manager")
controller, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
if err != nil {
log.Error(err, "Coulnd't start a kube manager")
return err
}
// TODO: Handle the error
go func() {
if err := controller.Start(ctx); err != nil {
panic(err)
}
}()
log.Info("Opening a database connection")
db, err := sql.Open("postgres", "postgres://softplayer:qwertyu9@localhost:30432/softplayer?sslmode=disable")
if err != nil {
log.Error(err, "Couldn't start a database driver")
return err
}
if err := migrateDB(ctx, db); err != nil {
log.Error(err, "Error occured while executing migrations")
return err
}
emailConfig := email.EmailConf{
From: params.SmtpFrom,
Password: params.SmtpPassword,
SmtpHost: params.SmtpHost,
SmtpPort: params.SmtpPort,
}
address := fmt.Sprintf("%s:%d", params.Host, params.Port)
lis, err := net.Listen("tcp", address)
if err != nil {
return err
}
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(grpc_zap.UnaryServerInterceptor(logger.SetupLogger("info"))),
grpc.StreamInterceptor(grpc_zap.StreamServerInterceptor(logger.SetupLogger("info"))),
)
if params.Reflection {
reflection.Register(grpcServer)
}
environments.RegisterEnvironmentsServer(grpcServer, v1.NewapiGrpcImpl(controller, log))
accounts.RegisterAccountsServer(grpcServer, v1.NewAccountRPCImpl(db, params.HashCost, &emailConfig, params.DevMode))
email_proto.RegisterEmailValidationServer(grpcServer, v1.InitEmailServer(controller, &emailConfig, params.DevMode))
applications_proto.RegisterApplicationsServer(grpcServer, v1.NewApplicationsGrpcImpl(controller, log))
if err := grpcServer.Serve(lis); err != nil {
return err
}
return nil
}