package main import ( "fmt" "log/slog" "net/http" "time" ) type Route struct { Path string Handler http.HandlerFunc } type BackgroundTask struct { Handler func() Interval time.Duration } type App struct { Routes []Route BackgroundTasks []BackgroundTask StaticRoot string } func LoggingMiddleware(f http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() f(w, r) slog.Info(fmt.Sprintf("%s - %s (%dms)", r.Method, r.URL, time.Now().Sub(start).Milliseconds())) } } func (a App) Start(addr string) { for _, route := range a.Routes { http.HandleFunc(route.Path, LoggingMiddleware(route.Handler)) } if a.StaticRoot != "" { http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(a.StaticRoot)))) } for _, task := range a.BackgroundTasks { go func() { for { task.Handler() time.Sleep(task.Interval) } }() } http.ListenAndServe(addr, nil) } func (a *App) AddRoute(path string, handler http.HandlerFunc) { a.Routes = append(a.Routes, Route{Path: path, Handler: handler}) } func NewApp(routes map[string]http.HandlerFunc, backgroundTasks []BackgroundTask, staticRoot string) *App { app := App{StaticRoot: staticRoot, BackgroundTasks: backgroundTasks} for route, handler := range routes { app.AddRoute(route, handler) } return &app }