package main import ( "context" "flag" "log" "net/http" "os" "os/signal" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/httplog" "golang.org/x/sync/errgroup" badger "github.com/dgraph-io/badger/v3" "go.neonxp.dev/djson/internal/config" "go.neonxp.dev/djson/internal/core" "go.neonxp.dev/djson/internal/events" "go.neonxp.dev/djson/internal/handler" "go.neonxp.dev/djson/internal/logger" ) var configFile = flag.String("config", "/etc/djson/config.json", "Path to config file") func main() { flag.Parse() ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) defer cancel() cfg, err := config.Parse(*configFile) if err != nil { panic(err) } baseLogger := httplog.NewLogger("djson", httplog.Options{ JSON: true, LogLevel: cfg.Log.Level, }) appLogger := logger.Logger{ Logger: baseLogger, } dbOpts := badger.DefaultOptions(cfg.DB) dbOpts.Logger = appLogger db, err := badger.Open(dbOpts) if err != nil { log.Fatal(err) } defer db.Close() eventsDispatcher := events.New() // Tree core core := core.New(db) if err := core.Init(ctx); err != nil { log.Fatal(err) } // Tree HTTP wrapper treeHandler := handler.New(core, eventsDispatcher) // HTTP router r := chi.NewRouter() r.Use(httplog.RequestLogger(appLogger.Logger)) r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Recoverer) r.Get("/health", treeHandler.Hearthbeat) r.Route("/tree", treeHandler.HandleCRUD) r.Route("/events", treeHandler.HandleEvents) server := &http.Server{ Addr: cfg.Listen, Handler: r, } eg, ctx := errgroup.WithContext(ctx) eg.Go(func() error { appLogger.Info().Str("server listen", cfg.Listen).Send() if err := server.ListenAndServe(); err != http.ErrServerClosed { return err } return nil }) eg.Go(func() error { <-ctx.Done() db.Close() return server.Close() }) if err := eg.Wait(); err != nil { panic(err) } }