package main import ( "context" "database/sql" "flag" "log" "log/slog" "net/http" "os" "time" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/transport" _ "github.com/mattn/go-sqlite3" ) type service_mode string const ( API_MODE = "api" DISCORD_BOT_MODE = "discord" TG_BOT_MODE = "tg" ) type config struct { mode service_mode port string db struct { dsn string maxOpenConns int maxIdleConns int maxIdleTime string } } type application struct { cfg config foundryApp *foundry.FoundryApi slogger *slog.Logger logger *log.Logger } func openDB(cfg config) (*sql.DB, error) { db, err := sql.Open("sqlite3", cfg.db.dsn) if err != nil { return nil, err } db.SetMaxIdleConns(cfg.db.maxIdleConns) db.SetMaxOpenConns(cfg.db.maxOpenConns) duration, err := time.ParseDuration(cfg.db.maxIdleTime) if err != nil { return nil, err } db.SetConnMaxIdleTime(duration) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err = db.PingContext(ctx) if err != nil { return nil, err } return db, nil } // TODO: change default values func (app *application) parseFlags() *requests.FoundryHttpRequest { flag.StringVar(&app.cfg.port, "port", ":9090", "Service port") flag.StringVar(&app.cfg.db.dsn, "db-dsn", "file:db/default.db?cache=shared", "PostgreSQL DSN") flag.IntVar(&app.cfg.db.maxOpenConns, "db-max-open-conns", 25, "PostgreSQL max open connections") flag.IntVar(&app.cfg.db.maxIdleConns, "db-max-idle-conns", 25, "PostgreSQL max idle connections") flag.StringVar(&app.cfg.db.maxIdleTime, "db-max-idle-time", "15m", "PostgreSQL max connection idle time") var mode string flag.StringVar(&mode, "service_mode", "api", "Type of service mode(api|discord|tg)") foundryHttpData := requests.FoundryHttpRequest{SessionID: ""} flag.StringVar(&foundryHttpData.Host, "foundry_host", "127.0.0.1", "Address to connect to Foundry") flag.StringVar(&foundryHttpData.Password, "foundry_pass", "", "Password to connect to Foundry") var logLevelStr string flag.StringVar(&logLevelStr, "log_level", "info", "Password to connect to Foundry(debug|info|warn|error)") flag.Parse() app.cfg.mode = service_mode(mode) // app.foundryApp.SetConfig(&foundryConfig) logLevel, ok := StringToLogLevel[logLevelStr] if !ok { logLevel = slog.LevelInfo } app.slogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel})) if !ok { app.slogger.Warn("Wrong log level. Started with log_level=info", "received", logLevelStr) } return &foundryHttpData } // TODO: Handle application exit if wrong data func (app *application) StartListenFoundry() { var err error for { err = app.foundryApp.ConnectToWebSocket() if err != nil { app.slogger.Error("Error raised", "err", err.Error()) return } } } func main() { app := application{foundryApp: &foundry.FoundryApi{}} foundryHttpData := app.parseFlags() app.slogger.Info("", "dsn", app.cfg.db.dsn) db, err := openDB(app.cfg) if err != nil { app.slogger.Error("Error when opening database connection", "err", err) return } defer db.Close() app.slogger.Info("Database connection pool established") app.foundryApp.Transport = transport.NewFoundryTransport(db, app.slogger, foundryHttpData) go app.StartListenFoundry() errLog := slog.NewLogLogger(app.slogger.Handler(), slog.LevelError) server := &http.Server{ Addr: app.cfg.port, Handler: app.routes(), ErrorLog: errLog, // TLSConfig: tlsConfig, IdleTimeout: time.Minute, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } switch app.cfg.mode { case API_MODE: app.slogger.Info("Server is started", "port", app.cfg.port) server.ListenAndServe() case DISCORD_BOT_MODE: app.slogger.Warn("TODO: implement this mode") case TG_BOT_MODE: app.slogger.Warn("TODO: implement this mode") default: app.slogger.Error("Wrong Mode. Should be one of: 'api', 'discord', 'tg'", "mode", app.cfg.mode) } }