diff --git a/cmd/server/main.go b/cmd/server/main.go index 26067b1..6f12037 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -6,6 +6,7 @@ import ( "bookmann/internal/handlers" "bookmann/internal/middleware" ratelimit "bookmann/internal/middleware" + "bookmann/internal/sync" "bookmann/templates" "bytes" "context" @@ -50,10 +51,15 @@ func main() { authHandler := handlers.NewAuthHandler(queries, cfg.JWTSecret, loginAttemptTracker) libraryHandler := handlers.NewLibraryHandler(queries) deviceHandler := handlers.NewDeviceHandler(queries, cfg.JWTSecret, cfg) - koreaderHandler := handlers.NewKOReaderHandler(queries) - deviceAuthMiddleware := middleware.NewDeviceAuthMiddleware(queries) + // Create WebSocket connection manager + connManager := sync.NewConnectionManager() + connManager.StartCleanupTask() + + koreaderHandler := handlers.NewKOReaderHandler(queries, connManager) + wsHandler := handlers.NewWSHandler(queries, connManager, cfg.JWTSecret, deviceAuthMiddleware) + e := echo.New() // Set up validator @@ -117,7 +123,7 @@ func main() { protected := e.Group("/api", jwtMiddleware) // Setup ebook handler routes first (so we can use it for library scan) - h := handlers.SetupRoutes(protected, queries) + h := handlers.SetupRoutes(protected, queries, connManager) // Public library types endpoint (no authentication required) e.GET("/api/libraries/types", libraryHandler.GetLibraryTypes) @@ -196,6 +202,9 @@ func main() { devices.DELETE("/:id", deviceHandler.DeleteDevice) devices.GET("/pending", deviceHandler.ListPendingRegistrations) + // WebSocket endpoint for real-time sync + e.GET("/ws/sync", wsHandler.HandleWebSocket) + // Static files e.Static("/static", "web/static")