package main import ( "context" "flag" "fmt" "os" "os/signal" "strings" logger "git.site.quack-lab.dev/dave/cylogger" "github.com/fasthttp/router" "github.com/joho/godotenv" "github.com/valyala/fasthttp" ) type Options struct { ClientID string RedirectURI string Scopes []string DBPath string } var options Options func main() { flag.Parse() logger.InitFlag() logger.Info("Starting Eve PI") var err error options, err = LoadOptions() if err != nil { logger.Error("Failed to load options %v", err) return } // Create SSO instance sso, err := NewSSO( options.ClientID, options.RedirectURI, options.Scopes, ) if err != nil { logger.Error("Failed to create SSO instance %v", err) return } // Setup fasthttp router r := router.New() // Configure SSO to use existing fasthttp router sso.SetRouter(r) // Add your own routes r.GET("/", func(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusOK) ctx.WriteString("EVE PI Server Running") }) r.GET("/login/{character}", func(ctx *fasthttp.RequestCtx) { charName := ctx.UserValue("character") charNameStr, ok := charName.(string) if !ok || charNameStr == "" { ctx.SetStatusCode(fasthttp.StatusBadRequest) ctx.WriteString("Missing character parameter") return } logger.Info("Login requested for character %s", charNameStr) // Trigger the auth flow (will register callback if needed) token, err := sso.GetToken(context.Background(), charNameStr) if err != nil { logger.Error("Failed to authenticate character %s: %v", charNameStr, err) ctx.SetStatusCode(fasthttp.StatusInternalServerError) ctx.WriteString("Authentication failed") return } logger.Info("Successfully authenticated character %s", charNameStr) ctx.SetContentType("text/plain") ctx.SetStatusCode(fasthttp.StatusOK) ctx.WriteString("Authenticated! Access token: " + token) }) logger.Info("Starting web server on :3000") go func() { if err := fasthttp.ListenAndServe(":3000", r.Handler); err != nil { logger.Error("Server failed: %v", err) } }() // Listen for SIGINT and gracefully shut down the server sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt) <-sigCh logger.Info("SIGINT received, shutting down web server gracefully...") logger.Info("Web server shut down cleanly") } func LoadOptions() (Options, error) { // Load environment variables strictly from .env file (fail if there's an error loading) if err := godotenv.Load(); err != nil { return Options{}, fmt.Errorf("error loading .env file: %w", err) } clientID := os.Getenv("ESI_CLIENT_ID") if clientID == "" { return Options{}, fmt.Errorf("ESI_CLIENT_ID is required in .env file") } redirectURI := os.Getenv("ESI_REDIRECT_URI") if redirectURI == "" { return Options{}, fmt.Errorf("ESI_REDIRECT_URI is required in .env file") } rawScopes := os.Getenv("ESI_SCOPES") if rawScopes == "" { return Options{}, fmt.Errorf("ESI_SCOPES is required in .env file") } scopes := strings.Fields(rawScopes) dbPath := os.Getenv("DB_PATH") if dbPath == "" { return Options{}, fmt.Errorf("DB_PATH is required in .env file") } return Options{ ClientID: clientID, RedirectURI: redirectURI, Scopes: scopes, DBPath: dbPath, }, nil }