package server import ( "fmt" "net/http" "path" "time" "github.com/sirupsen/logrus" "reichard.io/aethera/internal/api" "reichard.io/aethera/internal/store" ) func StartServer(settingsStore store.Store, dataDir, listenAddress string, listenPort int) { mux := http.NewServeMux() // Create API Instance - use settingsStore as the unified store for both settings and chat logger := logrus.New() api := api.New(settingsStore, dataDir, logger) feFS := http.FileServer(http.Dir("../frontend/public/")) mux.Handle("GET /", feFS) // Serve UI Pages pagesFS := http.FileServer(http.Dir("../frontend/public/pages/")) mux.Handle("GET /pages/", http.StripPrefix("/pages/", pagesFS)) // Serve Generated Data genFS := http.FileServer(http.Dir(path.Join(dataDir, "generated"))) mux.Handle("GET /generated/", http.StripPrefix("/generated/", genFS)) // Register API Routes mux.HandleFunc("POST /api/images", api.PostImage) mux.HandleFunc("GET /api/settings", api.GetSettings) mux.HandleFunc("POST /api/settings", api.PostSettings) mux.HandleFunc("GET /api/models", api.GetModels) mux.HandleFunc("GET /api/images", api.GetImages) mux.HandleFunc("DELETE /api/images/{filename}", api.DeleteImage) // Register Chat Management Routes mux.HandleFunc("GET /api/chats", api.GetChats) mux.HandleFunc("POST /api/chats", api.PostChat) mux.HandleFunc("GET /api/chats/{chatId}", api.GetChat) mux.HandleFunc("POST /api/chats/{chatId}", api.PostChatMessage) mux.HandleFunc("DELETE /api/chats/{chatId}", api.DeleteChat) // Wrap Logging wrappedMux := loggingMiddleware(mux) logrus.Infof("Starting server on %s:%d with data directory: %s", listenAddress, listenPort, dataDir) logrus.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", listenAddress, listenPort), wrappedMux)) } // loggingMiddleware wraps an http.Handler and logs requests func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := &responseWriterWrapper{ResponseWriter: w} next.ServeHTTP(ww, r) logrus.WithFields(logrus.Fields{ "datetime": start.UTC().Format(time.RFC3339), "method": r.Method, "path": r.URL.Path, "remote": r.RemoteAddr, "status": ww.getStatusCode(), "latency": time.Since(start), }).Infof("%s %s", r.Method, r.URL.Path) }) } // responseWriterWrapper wraps http.ResponseWriter to capture status code type responseWriterWrapper struct { http.ResponseWriter statusCode int } func (w *responseWriterWrapper) Flush() { if f, ok := w.ResponseWriter.(http.Flusher); ok { f.Flush() } } func (rw *responseWriterWrapper) getStatusCode() int { if rw.statusCode == 0 { return 200 } return rw.statusCode } func (rw *responseWriterWrapper) WriteHeader(code int) { if code > 0 { rw.statusCode = code } rw.ResponseWriter.WriteHeader(code) }