diff --git a/app.go b/app.go index 403e270422f26d61dcd91fe0d8cdc393d2728ddd..df0e0bc00b02fef6b8e5ef1c2107a68b1cb728d3 100644 --- a/app.go +++ b/app.go @@ -9,9 +9,10 @@ import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/limiter" + "github.com/syndtr/goleveldb/leveldb" ) -func serve(sig chan os.Signal) error { +func serve(sig chan os.Signal, db *leveldb.DB) error { app := fiber.New() // cors @@ -33,7 +34,7 @@ func serve(sig chan os.Signal) error { })) // /register - routeRegister(app) + routeRegister(app, db) // Graceful shutdown app.Use(func(c *fiber.Ctx) error { diff --git a/conf.go b/conf.go index c3833f8e2b28ba9a78a97cd44a83835cec966a8b..cb9cafb6c9df22993b66ac9dfe2e536b8e8346cd 100644 --- a/conf.go +++ b/conf.go @@ -1,11 +1,15 @@ package main -import "os" +import ( + "log" + "os" +) const ( dbPath uint8 = iota listenAddr allowedOrigins + verboseLogging confLen ) @@ -15,11 +19,14 @@ var confEnv = [confLen][2]string{ {"DB", "db"}, {"LISTEN_ADDR", "127.0.0.1:3000"}, {"ALLOWED_ORIGINS", "https://hizla.io"}, + {"VERBOSE", "1"}, } // resolved config values var conf [confLen]string +var verbose bool + func init() { for i := 0; i < int(confLen); i++ { if v, ok := os.LookupEnv(confEnv[i][0]); !ok { @@ -28,4 +35,13 @@ func init() { conf[i] = v } } + + switch conf[verboseLogging] { + case "0": + verbose = false + case "1": + verbose = true + default: + log.Printf("invalid verbose value %q", conf[verboseLogging]) + } } diff --git a/db.go b/db.go deleted file mode 100644 index 527af3ffa86668ee686985d66b4eaba4efe5ead5..0000000000000000000000000000000000000000 --- a/db.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "github.com/syndtr/goleveldb/leveldb" - "log" -) - -var db *leveldb.DB - -func InitDB(path string) error { - var err error - db, err = leveldb.OpenFile(path, nil) - if err != nil { - return err - } - return nil -} - -func CloseDB() { - if err := db.Close(); err != nil { - log.Printf("Warning: Failed to close LevelDB: %v", err) - } -} - -func SaveEmail(email string) error { - if err := db.Put([]byte(email), []byte("registered"), nil); err != nil { - log.Printf("Error saving email to LevelDB: %v", err) - return err - } - return nil -} - -func IsEmailRegistered(email string) (bool, error) { - _, err := db.Get([]byte(email), nil) - if err != nil { - if err == leveldb.ErrNotFound { - return false, nil - } - log.Printf("Error checking email registration: %v", err) - return false, err - } - return true, nil -} diff --git a/main.go b/main.go index 71568b38cac62ffa41087ed52a9fdbdd7593bb51..1f4cd6efd3d603ed5f3077b6c0b29fdbfd679bd4 100644 --- a/main.go +++ b/main.go @@ -5,20 +5,28 @@ import ( "os" "os/signal" "syscall" + + "github.com/syndtr/goleveldb/leveldb" ) func main() { + var db *leveldb.DB - if err := InitDB(conf[dbPath]); err != nil { - log.Fatalf("Failed to initialize LevelDB: %v", err) + if d, err := leveldb.OpenFile(conf[dbPath], nil); err != nil { + log.Fatalf("cannot open database %q: %v", conf[dbPath], err) + } else { + db = d } - - defer CloseDB() + defer func() { + if err := db.Close(); err != nil { + log.Printf("cannot close database %q: %v", conf[dbPath], err) + } + }() sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP) - if err := serve(sig); err != nil { + if err := serve(sig, db); err != nil { log.Printf("cannot serve: %v", err) } diff --git a/register.go b/register.go index afe37f52222b2282ae1662cd4c9173f128ef8104..38f846b80933dfd4718dca090482aa3b821d24c0 100644 --- a/register.go +++ b/register.go @@ -5,6 +5,7 @@ import ( "regexp" "github.com/gofiber/fiber/v2" + "github.com/syndtr/goleveldb/leveldb" ) var emailRegexp = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`) @@ -14,12 +15,14 @@ type registration struct { } // Waitlist registration route -func routeRegister(app *fiber.App) { +func routeRegister(app *fiber.App, db *leveldb.DB) { app.Post("/register", func(c *fiber.Ctx) error { req := new(registration) if err := c.BodyParser(req); err != nil { - log.Printf("Invalid request body: %v", err) + if verbose { + log.Printf("invalid request from %q: %v", c.IP(), err) + } return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ "message": "Invalid request", }) @@ -27,36 +30,38 @@ func routeRegister(app *fiber.App) { // Validate email format if !emailRegexp.MatchString(req.Email) { - log.Printf("Invalid email format: %s", req.Email) + if verbose { + log.Printf("invalid email from %q: %s", c.IP(), req.Email) + } return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ "message": "Invalid email format", }) } // Check if email is already registered - registered, err := IsEmailRegistered(req.Email) - if err != nil { - log.Printf("Error checking email registration: %v", err) + if ok, err := db.Has([]byte(req.Email), nil); err != nil { + log.Printf("cannot check for existence of email %q: %v", req.Email, err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "message": "Error checking registration status", }) - } - if registered { - log.Printf("Email already registered: %s", req.Email) + } else if ok { + if verbose { + log.Printf("duplicate email from %q: %s", c.IP(), req.Email) + } return c.Status(fiber.StatusConflict).JSON(fiber.Map{ "message": "Email already registered", }) } // Save the email to the waitlist - if err := SaveEmail(req.Email); err != nil { - log.Printf("Error registering email: %v", err) + if err := db.Put([]byte(req.Email), []byte{'x'}, nil); err != nil { + log.Printf("cannot register email %q: %v", req.Email, err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "message": "Error registering email", }) } - log.Printf("Email registered successfully: %s", req.Email) + log.Printf("registered email %q", req.Email) return c.JSON(fiber.Map{ "message": "Email registered successfully", })