feat: add WebSocket endpoint and ConnectionManager setup

Add WebSocket infrastructure to main server:
- Import sync package for ConnectionManager
- Create and start ConnectionManager with cleanup task
- Initialize WSHandler with auth dependencies
- Add /ws/sync WebSocket endpoint
- Update handler initialization to pass ConnectionManager

The WebSocket endpoint at /ws/sync enables real-time progress
updates across all connected clients (web, mobile, devices).
This commit is contained in:
2026-01-30 21:48:21 -05:00
parent 885cbd5d47
commit d77585a6f5
+12 -3
View File
@@ -6,6 +6,7 @@ import (
"bookmann/internal/handlers" "bookmann/internal/handlers"
"bookmann/internal/middleware" "bookmann/internal/middleware"
ratelimit "bookmann/internal/middleware" ratelimit "bookmann/internal/middleware"
"bookmann/internal/sync"
"bookmann/templates" "bookmann/templates"
"bytes" "bytes"
"context" "context"
@@ -50,10 +51,15 @@ func main() {
authHandler := handlers.NewAuthHandler(queries, cfg.JWTSecret, loginAttemptTracker) authHandler := handlers.NewAuthHandler(queries, cfg.JWTSecret, loginAttemptTracker)
libraryHandler := handlers.NewLibraryHandler(queries) libraryHandler := handlers.NewLibraryHandler(queries)
deviceHandler := handlers.NewDeviceHandler(queries, cfg.JWTSecret, cfg) deviceHandler := handlers.NewDeviceHandler(queries, cfg.JWTSecret, cfg)
koreaderHandler := handlers.NewKOReaderHandler(queries)
deviceAuthMiddleware := middleware.NewDeviceAuthMiddleware(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() e := echo.New()
// Set up validator // Set up validator
@@ -117,7 +123,7 @@ func main() {
protected := e.Group("/api", jwtMiddleware) protected := e.Group("/api", jwtMiddleware)
// Setup ebook handler routes first (so we can use it for library scan) // 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) // Public library types endpoint (no authentication required)
e.GET("/api/libraries/types", libraryHandler.GetLibraryTypes) e.GET("/api/libraries/types", libraryHandler.GetLibraryTypes)
@@ -196,6 +202,9 @@ func main() {
devices.DELETE("/:id", deviceHandler.DeleteDevice) devices.DELETE("/:id", deviceHandler.DeleteDevice)
devices.GET("/pending", deviceHandler.ListPendingRegistrations) devices.GET("/pending", deviceHandler.ListPendingRegistrations)
// WebSocket endpoint for real-time sync
e.GET("/ws/sync", wsHandler.HandleWebSocket)
// Static files // Static files
e.Static("/static", "web/static") e.Static("/static", "web/static")