100 lines
3.1 KiB
Go
100 lines
3.1 KiB
Go
package http
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/noderunners/nip05api/internal/audit"
|
|
"github.com/noderunners/nip05api/internal/config"
|
|
"github.com/noderunners/nip05api/internal/db"
|
|
"github.com/noderunners/nip05api/internal/dm"
|
|
"github.com/noderunners/nip05api/internal/http/docs"
|
|
"github.com/noderunners/nip05api/internal/http/handlers"
|
|
"github.com/noderunners/nip05api/internal/http/middleware"
|
|
"github.com/noderunners/nip05api/internal/invoice"
|
|
"github.com/noderunners/nip05api/internal/user"
|
|
"github.com/noderunners/nip05api/internal/webhook"
|
|
)
|
|
|
|
type Deps struct {
|
|
Cfg *config.Config
|
|
DB *db.DB
|
|
Users *user.Service
|
|
Invoices *invoice.Service
|
|
DMs *dm.Service
|
|
Hooks *webhook.Service
|
|
Audit *audit.Logger
|
|
Version string
|
|
}
|
|
|
|
func NewServer(d Deps) *http.Server {
|
|
r := chi.NewRouter()
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(middleware.RealIP)
|
|
r.Use(middleware.Logging)
|
|
r.Use(middleware.CORS)
|
|
r.Use(middleware.BodyLimit(1 << 20)) // 1 MiB max request body
|
|
r.Use(middleware.RateLimit(d.Cfg.RateLimitPerMin))
|
|
|
|
health := &handlers.Health{DB: d.DB, Version: d.Version}
|
|
nostrJSON := &handlers.NostrJSON{Users: d.Users, Relays: d.Cfg.Nostr.Relays}
|
|
pricing := &handlers.Pricing{
|
|
YearlySats: d.Cfg.Lightning.PriceYearlySats,
|
|
LifetimeSats: d.Cfg.Lightning.PriceLifetimeSats,
|
|
LightningEnabled: d.Cfg.Lightning.Enabled,
|
|
}
|
|
users := &handlers.Users{Users: d.Users, GraceDays: d.Cfg.Expiry.GraceDays}
|
|
usernames := &handlers.Usernames{Users: d.Users}
|
|
invoices := &handlers.Invoices{Service: d.Invoices, LightningEnabled: d.Cfg.Lightning.Enabled}
|
|
adminUsers := &handlers.AdminUsers{
|
|
Users: d.Users, DMs: d.DMs, Hooks: d.Hooks, Audit: d.Audit,
|
|
Domain: d.Cfg.Domain, Frontend: d.Cfg.FrontendURL,
|
|
}
|
|
adminExtend := &handlers.AdminExtend{
|
|
Users: d.Users, DMs: d.DMs, Hooks: d.Hooks, Audit: d.Audit,
|
|
Domain: d.Cfg.Domain, Frontend: d.Cfg.FrontendURL,
|
|
}
|
|
|
|
r.Get("/healthz", health.Handle)
|
|
r.Get("/.well-known/nostr.json", nostrJSON.Handle)
|
|
r.Get("/openapi.json", docs.ServeJSON)
|
|
r.Get("/docs", docs.ServeUI)
|
|
r.Get("/docs/", docs.ServeUI)
|
|
|
|
r.Route("/v1", func(r chi.Router) {
|
|
r.Get("/pricing", pricing.Handle)
|
|
r.Get("/users/{pubkey}", users.Get)
|
|
r.Get("/usernames/{name}/available", usernames.Available)
|
|
if d.Invoices != nil {
|
|
r.Post("/invoices", invoices.Create)
|
|
r.Get("/invoices/{payment_hash}", invoices.Get)
|
|
}
|
|
|
|
r.Route("/admin", func(r chi.Router) {
|
|
r.Use(middleware.AdminAuth(d.Cfg.AdminAPIKey))
|
|
r.Post("/users", adminUsers.Add)
|
|
r.Get("/users", adminUsers.List)
|
|
r.Put("/users/{pubkey}", adminUsers.Update)
|
|
r.Delete("/users/{pubkey}", adminUsers.Delete)
|
|
r.Post("/users/{pubkey}/extend", adminExtend.Handle)
|
|
})
|
|
})
|
|
|
|
return &http.Server{
|
|
Addr: d.Cfg.Addr(),
|
|
Handler: r,
|
|
ReadHeaderTimeout: 10 * time.Second,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
}
|
|
|
|
func Shutdown(ctx context.Context, srv *http.Server) error {
|
|
shutdownCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
defer cancel()
|
|
return srv.Shutdown(shutdownCtx)
|
|
}
|