diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index ee55d599..a391a031 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -235,6 +235,18 @@ func registerRoutes(r *gin.Engine, h *handler.Handlers, s *service.Services, rep c.JSON(http.StatusOK, gin.H{"status": "ok"}) }) + // Setup status endpoint (always returns needs_setup: false in normal mode) + // This is used by the frontend to detect when the service has restarted after setup + r.GET("/setup/status", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "code": 0, + "data": gin.H{ + "needs_setup": false, + "step": "completed", + }, + }) + }) + // API v1 v1 := r.Group("/api/v1") { diff --git a/backend/internal/setup/handler.go b/backend/internal/setup/handler.go index 5565539d..a8e73a03 100644 --- a/backend/internal/setup/handler.go +++ b/backend/internal/setup/handler.go @@ -2,11 +2,15 @@ package setup import ( "fmt" + "log" "net/http" "net/mail" + "os/exec" "regexp" + "runtime" "strings" "sync" + "time" "sub2api/internal/pkg/response" @@ -337,8 +341,41 @@ func install(c *gin.Context) { return } + // Schedule service restart in background after sending response + // This ensures the client receives the success response before the service restarts + go func() { + // Wait a moment to ensure the response is sent + time.Sleep(500 * time.Millisecond) + triggerServiceRestart() + }() + response.Success(c, gin.H{ - "message": "Installation completed successfully", + "message": "Installation completed successfully. Service will restart automatically.", "restart": true, }) } + +// triggerServiceRestart attempts to restart the service via systemd +// This is called after setup completes to switch from setup mode to normal mode +func triggerServiceRestart() { + if runtime.GOOS != "linux" { + log.Println("Service restart: not on Linux, manual restart required") + return + } + + log.Println("Setup completed, triggering service restart...") + + // Try direct systemctl first (works if running as root or with proper permissions) + cmd := exec.Command("systemctl", "restart", "sub2api") + if err := cmd.Run(); err != nil { + // Try with sudo (requires NOPASSWD sudoers entry) + sudoCmd := exec.Command("sudo", "systemctl", "restart", "sub2api") + if sudoErr := sudoCmd.Run(); sudoErr != nil { + log.Printf("Service restart failed: %v (sudo also failed: %v)", err, sudoErr) + log.Println("Please restart the service manually: sudo systemctl restart sub2api") + return + } + } + + log.Println("Service restart initiated successfully") +} diff --git a/backend/internal/web/embed.go b/backend/internal/web/embed.go index 93cfe763..da5ba167 100644 --- a/backend/internal/web/embed.go +++ b/backend/internal/web/embed.go @@ -10,7 +10,7 @@ import ( "github.com/gin-gonic/gin" ) -//go:embed dist/* +//go:embed all:dist var frontendFS embed.FS // ServeEmbeddedFrontend returns a Gin handler that serves embedded frontend assets diff --git a/frontend/src/views/setup/SetupWizardView.vue b/frontend/src/views/setup/SetupWizardView.vue index 4d63118e..ee7bb640 100644 --- a/frontend/src/views/setup/SetupWizardView.vue +++ b/frontend/src/views/setup/SetupWizardView.vue @@ -214,12 +214,18 @@