package main import ( "context" "database/sql" "log" "net/http" "os" "os/signal" "syscall" "time" httpin "github.com/example/storage-appliance/internal/http" "github.com/example/storage-appliance/internal/infra/sqlite/db" "github.com/example/storage-appliance/internal/service/mock" _ "github.com/glebarez/sqlite" "github.com/go-chi/chi/v5" "github.com/google/uuid" ) func main() { ctx := context.Background() // Connect simple sqlite DB (file) dsn := "file:appliance.db?_foreign_keys=on" sqldb, err := sql.Open("sqlite", dsn) if err != nil { log.Fatalf("open db: %v", err) } defer sqldb.Close() // Run migrations and seed admin if err := db.MigrateAndSeed(ctx, sqldb); err != nil { log.Fatalf("migrate: %v", err) } r := chi.NewRouter() uuidMiddleware := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rid := uuid.New().String() rw := w r = r.WithContext(context.WithValue(r.Context(), httpin.ContextKeyRequestID, rid)) rw.Header().Set("X-Request-Id", rid) next.ServeHTTP(rw, r) }) } // Attach router and app dependencies // wire mocks for now; replace with real adapters in infra diskSvc := &mock.MockDiskService{} zfsSvc := &mock.MockZFSService{} jobRunner := &mock.MockJobRunner{} app := &httpin.App{ DB: sqldb, DiskSvc: diskSvc, ZFSSvc: zfsSvc, JobRunner: jobRunner, HTTPClient: &http.Client{}, } r.Use(uuidMiddleware) httpin.RegisterRoutes(r, app) srv := &http.Server{ Addr: ":8080", Handler: r, } // graceful shutdown go func() { log.Printf("Starting server on %s", srv.Addr) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("server error: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop ctxShut, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() if err := srv.Shutdown(ctxShut); err != nil { log.Fatalf("server shutdown failed: %v", err) } log.Println("server stopped") }