135 lines
4.3 KiB
Go
135 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"3588AdminBackend/internal/api"
|
|
"3588AdminBackend/internal/config"
|
|
"3588AdminBackend/internal/service"
|
|
"3588AdminBackend/internal/storage"
|
|
"3588AdminBackend/internal/web"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/go-chi/cors"
|
|
)
|
|
|
|
func main() {
|
|
cfgPath := "managerd.json"
|
|
if len(os.Args) > 1 {
|
|
cfgPath = os.Args[1]
|
|
}
|
|
|
|
cfg, err := config.LoadConfig(cfgPath)
|
|
if err != nil {
|
|
log.Fatalf("failed to load config: %v", err)
|
|
}
|
|
|
|
// Initialize Services
|
|
agentClient := service.NewAgentClient(cfg)
|
|
regSvc := service.NewRegistryService(cfg, agentClient)
|
|
discoSvc := service.NewDiscoveryService(cfg, regSvc)
|
|
store, err := storage.OpenSQLite(cfg.DBPathOrDefault())
|
|
if err != nil {
|
|
log.Fatalf("failed to open storage: %v", err)
|
|
}
|
|
defer store.Close()
|
|
taskRepo := storage.NewTasksRepo(store.DB())
|
|
assetsRepo := storage.NewAssetsRepo(store.DB())
|
|
if imported, err := service.ImportStandardTemplatesFromDir(assetsRepo, filepath.Join("templates", "standard_templates")); err != nil {
|
|
log.Fatalf("import standard templates: %v", err)
|
|
} else if imported > 0 {
|
|
log.Printf("imported %d standard templates", imported)
|
|
}
|
|
stateRepo := storage.NewDeviceConfigStateRepo(store.DB())
|
|
auditRepo := storage.NewAuditLogsRepo(store.DB())
|
|
taskSvc := service.NewTaskService(cfg, agentClient, regSvc, taskRepo)
|
|
taskSvc.SetDeviceConfigStateRepo(stateRepo)
|
|
taskSvc.SetAuditLogRepo(auditRepo)
|
|
if err := taskSvc.LoadPersistedTasks(); err != nil {
|
|
log.Printf("load persisted tasks: %v", err)
|
|
}
|
|
tplSvc := service.NewTemplateService(cfg)
|
|
h := api.NewHandler(discoSvc, regSvc, agentClient, taskSvc, tplSvc)
|
|
|
|
r := chi.NewRouter()
|
|
r.Use(middleware.Logger)
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(cors.Handler(cors.Options{
|
|
AllowedOrigins: []string{"http://localhost:5173", "http://127.0.0.1:5173"},
|
|
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
|
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-RK-Token", "X-Model-Sha256"},
|
|
MaxAge: 300,
|
|
}))
|
|
|
|
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("ok"))
|
|
})
|
|
r.Get("/openapi.json", api.OpenAPI)
|
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, "/ui", http.StatusFound)
|
|
})
|
|
|
|
ui, err := web.NewUI(discoSvc, regSvc, agentClient, taskSvc, tplSvc, service.NewConfigPreviewService(cfg, assetsRepo))
|
|
if err != nil {
|
|
log.Fatalf("failed to init ui: %v", err)
|
|
}
|
|
ui.SetStateRepo(stateRepo)
|
|
ui.SetAuditRepo(auditRepo)
|
|
ui.SetDBPath(cfg.DBPathOrDefault())
|
|
uiRouter, err := ui.Routes()
|
|
if err != nil {
|
|
log.Fatalf("failed to init ui routes: %v", err)
|
|
}
|
|
r.Mount("/ui", http.StripPrefix("/ui", uiRouter))
|
|
|
|
// API Routes
|
|
r.Route("/api", func(r chi.Router) {
|
|
r.Post("/discovery/search", h.Search)
|
|
r.Get("/devices", h.ListDevices)
|
|
r.Post("/devices", h.CreateDevice)
|
|
r.Get("/devices/{id}", h.GetDevice)
|
|
|
|
// Proxy routes for device actions
|
|
r.Get("/devices/{id}/info", h.ProxyAgent)
|
|
r.Get("/devices/{id}/config/status", h.ProxyAgent)
|
|
r.Put("/devices/{id}/config/candidate", h.ProxyAgent)
|
|
r.Post("/devices/{id}/config/candidate/apply", h.ProxyAgent)
|
|
r.Post("/devices/{id}/reload", h.ProxyAgent)
|
|
r.Post("/devices/{id}/rollback", h.ProxyAgent)
|
|
r.Get("/devices/{id}/graphs", h.ProxyAgent)
|
|
r.Get("/devices/{id}/graphs/{name}", h.ProxyAgent)
|
|
r.Get("/devices/{id}/logs", h.ProxyAgent)
|
|
r.Post("/devices/{id}/config/apply", h.ProxyAgent)
|
|
r.Get("/devices/{id}/models", h.ProxyAgent)
|
|
r.Post("/devices/{id}/media-server/start", h.ProxyAgent)
|
|
r.Post("/devices/{id}/media-server/restart", h.ProxyAgent)
|
|
r.Post("/devices/{id}/media-server/stop", h.ProxyAgent)
|
|
r.Get("/devices/{id}/media-server/status", h.ProxyAgent)
|
|
|
|
// Generic passthrough for device agent /v1/* (covers config/ui/*, face-gallery, etc.)
|
|
r.Handle("/devices/{id}/v1/*", http.HandlerFunc(h.ProxyAgentV1))
|
|
|
|
// Task routes
|
|
r.Post("/tasks", h.CreateTask)
|
|
r.Get("/tasks", h.ListTasks)
|
|
r.Get("/tasks/{id}/events", h.TaskEvents)
|
|
|
|
// Template routes
|
|
r.Get("/templates", h.ListTemplates)
|
|
r.Get("/templates/{name}", h.GetTemplate)
|
|
|
|
// Model routes
|
|
r.Post("/devices/{id}/models/upload", h.UploadModel)
|
|
})
|
|
|
|
fmt.Printf("Starting managerd on %s\n", cfg.Listen)
|
|
if err := http.ListenAndServe(cfg.Listen, r); err != nil {
|
|
log.Fatalf("failed to start server: %v", err)
|
|
}
|
|
}
|