feat(service): add auto-start management for services

Implement setBootAtStart and removeBootAtStart functions to handle service auto-start configuration separately from service creation/removal. Update handlers to use these new functions for better control of boot behavior. The changes support Windows, systemd and init.d systems.
This commit is contained in:
2026-03-25 11:05:17 +08:00
parent 3a00f5d6a5
commit da729b44ff
2 changed files with 83 additions and 17 deletions
+16 -12
View File
@@ -180,7 +180,6 @@ func CreateInstanceHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if req.BootAtStart {
if err := createBootService(user.Username, req.InstanceInfo.Name, configPath, runUser); err != nil { if err := createBootService(user.Username, req.InstanceInfo.Name, configPath, runUser); err != nil {
frpcDB.Exec("DELETE FROM frpcInstances WHERE userID = ? AND name = ?", userID, req.InstanceInfo.Name) frpcDB.Exec("DELETE FROM frpcInstances WHERE userID = ? AND name = ?", userID, req.InstanceInfo.Name)
os.Remove(configPath) os.Remove(configPath)
@@ -188,6 +187,13 @@ func CreateInstanceHandler(w http.ResponseWriter, r *http.Request) {
SendErrorResponse(w, http.StatusInternalServerError, "Failed to create boot service") SendErrorResponse(w, http.StatusInternalServerError, "Failed to create boot service")
return return
} }
if req.BootAtStart {
if err := setBootAtStart(user.Username, req.InstanceInfo.Name); err != nil {
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to set boot at start for instance %s: %v", req.InstanceInfo.Name, err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to set boot at start")
return
}
} }
SendSuccessResponse(w, "Instance created successfully", map[string]interface{}{ SendSuccessResponse(w, "Instance created successfully", map[string]interface{}{
@@ -264,13 +270,11 @@ func DeleteInstanceHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if instance.BootAtStart {
if err := removeBootService(user.Username, instance.Name); err != nil { if err := removeBootService(user.Username, instance.Name); err != nil {
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to remove boot service for instance %s: %v", instance.Name, err)) postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to remove boot service for instance %s: %v", instance.Name, err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to remove boot service") SendErrorResponse(w, http.StatusInternalServerError, "Failed to remove boot service")
return return
} }
}
if _, err := os.Stat(instance.ConfigPath); err == nil { if _, err := os.Stat(instance.ConfigPath); err == nil {
if err := os.Remove(instance.ConfigPath); err != nil { if err := os.Remove(instance.ConfigPath); err != nil {
@@ -508,22 +512,22 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F
} }
if newBootAtStart { if newBootAtStart {
if err := removeBootService(user.Username, instance.Name); err != nil { if err := removeBootAtStart(user.Username, instance.Name); err != nil {
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot service: %v", err)) postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot at start: %v", err))
bootServiceError = fmt.Sprintf("Failed to remove boot service: %v", err) bootServiceError = fmt.Sprintf("Failed to remove boot at start: %v", err)
} }
instance.Name = newName instance.Name = newName
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil { if err := setBootAtStart(user.Username, newName); err != nil {
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create boot service: %v", err)) postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to set boot at start: %v", err))
if bootServiceError != "" { if bootServiceError != "" {
bootServiceError += "; " bootServiceError += "; "
} }
bootServiceError += fmt.Sprintf("Failed to create boot service: %v", err) bootServiceError += fmt.Sprintf("Failed to set boot at start: %v", err)
} }
} else { } else {
if err := removeBootService(user.Username, instance.Name); err != nil { if err := removeBootAtStart(user.Username, instance.Name); err != nil {
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot service: %v", err)) postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot at start: %v", err))
bootServiceError = fmt.Sprintf("Failed to remove boot service: %v", err) bootServiceError = fmt.Sprintf("Failed to remove boot at start: %v", err)
} }
instance.Name = newName instance.Name = newName
} }
+62
View File
@@ -249,6 +249,68 @@ func createWindowsBootService(username, instanceName, configPath string) error {
return nil return nil
} }
func setBootAtStart(username, instanceName string) error {
initType := GetInitSystem()
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
switch initType {
case "windows":
cmd := exec.Command("sc", "config", serviceName, "start=", "auto")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to set Windows service %s to auto-start: %s, output: %s", serviceName, err, output)
}
return nil
case "systemd":
cmd := exec.Command("systemctl", "enable", serviceName)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to enable systemd service %s: %s, output: %s", serviceName, err, output)
}
return nil
case "init.d":
cmd := exec.Command("update-rc.d", serviceName, "enable")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to enable init.d service %s: %s, output: %s", serviceName, err, output)
}
return nil
default:
return fmt.Errorf("unsupported init system: %s", initType)
}
}
func removeBootAtStart(username, instanceName string) error {
initType := GetInitSystem()
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
switch initType{
case "windows":
cmd := exec.Command("sc", "config", serviceName, "start=", "disabled")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to set Windows service %s to disabled-start: %s, output: %s", serviceName, err, output)
}
return nil
case "systemd":
cmd := exec.Command("systemctl", "disable", serviceName)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to disable systemd service %s: %s, output: %s", serviceName, err, output)
}
return nil
case "init.d":
cmd := exec.Command("update-rc.d", serviceName, "disable")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to disable init.d service %s: %s, output: %s", serviceName, err, output)
}
return nil
default:
return fmt.Errorf("unsupported init system: %s", initType)
}
}
func removeBootService(username, instanceName string) error { func removeBootService(username, instanceName string) error {
initType := GetInitSystem() initType := GetInitSystem()