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.
1074 lines
38 KiB
Go
1074 lines
38 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"super-frpc/postLog"
|
|
"time"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
type InstanceInfo struct {
|
|
Name string `json:"name"`
|
|
ServerAddr string `json:"serverAddr"`
|
|
ServerPort string `json:"serverPort"`
|
|
AuthMethod string `json:"auth_method"`
|
|
RunUser string `json:"runUser"`
|
|
Additional map[string]interface{} `json:"additionalProperties"`
|
|
}
|
|
|
|
type FrpcProxyInfo struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
LocalIP string `json:"local_ip"`
|
|
LocalPort string `json:"local_port"`
|
|
RemotePort string `json:"remote_port"`
|
|
}
|
|
|
|
type CreateInstanceRequest struct {
|
|
InstanceInfo InstanceInfo `json:"instanceInfo"`
|
|
BootAtStart bool `json:"bootAtStart"`
|
|
RunUser string `json:"runUser"`
|
|
Additional map[string]interface{} `json:"additionalProperties"`
|
|
}
|
|
|
|
type FrpcConfig struct {
|
|
Common map[string]interface{} `toml:"common"`
|
|
Proxies []map[string]interface{} `toml:"proxies"`
|
|
Additional map[string]interface{} `toml:"-"`
|
|
}
|
|
|
|
var frpcDB *sql.DB
|
|
|
|
func CloseFrpcDatabase() error {
|
|
if frpcDB != nil {
|
|
return frpcDB.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func CreateInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[CreateInstanceHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
bootAtStart := false
|
|
if bas, ok := reqMap["bootAtStart"]; ok {
|
|
switch v := bas.(type) {
|
|
case bool:
|
|
bootAtStart = v
|
|
case string:
|
|
if v == "true" {
|
|
bootAtStart = true
|
|
}
|
|
}
|
|
}
|
|
|
|
instanceInfoMap, ok := reqMap["instanceInfo"].(map[string]interface{})
|
|
if !ok {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceInfo format")
|
|
return
|
|
}
|
|
|
|
instanceInfo := InstanceInfo{
|
|
Name: getStringFromMap(instanceInfoMap, "name"),
|
|
ServerAddr: getStringFromMap(instanceInfoMap, "serverAddr"),
|
|
ServerPort: getStringFromMap(instanceInfoMap, "serverPort"),
|
|
AuthMethod: getStringFromMap(instanceInfoMap, "auth_method"),
|
|
RunUser: getStringFromMap(reqMap, "runUser"),
|
|
}
|
|
|
|
if additional, ok := reqMap["additionalProperties"].(map[string]interface{}); ok {
|
|
instanceInfo.Additional = additional
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusUnauthorized, err.Error())
|
|
return
|
|
}
|
|
|
|
req := CreateInstanceRequest{
|
|
InstanceInfo: instanceInfo,
|
|
BootAtStart: bootAtStart,
|
|
RunUser: instanceInfo.RunUser,
|
|
Additional: instanceInfo.Additional,
|
|
}
|
|
|
|
if err := CheckPermission(userID, "superuser", "admin"); err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to check permission: %v", err))
|
|
SendErrorResponse(w, http.StatusForbidden, err.Error())
|
|
return
|
|
}
|
|
|
|
if req.InstanceInfo.Name == "" || req.InstanceInfo.ServerAddr == "" ||
|
|
req.InstanceInfo.ServerPort == "" || req.InstanceInfo.AuthMethod == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Missing required fields in instanceInfo")
|
|
return
|
|
}
|
|
|
|
runUser := req.RunUser
|
|
if runUser == "" {
|
|
runUser = "root"
|
|
}
|
|
|
|
user, err := GetUserByID(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
configDir, err := GetConfigDir()
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to get config directory: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get config directory")
|
|
return
|
|
}
|
|
|
|
configFileName := fmt.Sprintf("superfrpc_%s_%s.toml", user.Username, req.InstanceInfo.Name)
|
|
configPath := filepath.Join(configDir, configFileName)
|
|
|
|
configContent := generateFrpcConfig(req.InstanceInfo)
|
|
if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to create config file %s: %v", configPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to create config file")
|
|
return
|
|
}
|
|
|
|
instance := FrpcInstance{
|
|
UserID: userID,
|
|
Name: req.InstanceInfo.Name,
|
|
ServerAddr: req.InstanceInfo.ServerAddr,
|
|
ServerPort: req.InstanceInfo.ServerPort,
|
|
AuthMethod: req.InstanceInfo.AuthMethod,
|
|
BootAtStart: req.BootAtStart,
|
|
RunUser: runUser,
|
|
ConfigPath: configPath,
|
|
}
|
|
|
|
if err := DBAddFrpcInstance(instance); err != nil {
|
|
os.Remove(configPath)
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to save instance %s to database: %v", req.InstanceInfo.Name, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to save instance to database")
|
|
return
|
|
}
|
|
|
|
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)
|
|
os.Remove(configPath)
|
|
postLog.Error(fmt.Sprintf("[CreateInstanceHandler] Failed to create boot service for instance %s: %v", req.InstanceInfo.Name, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to create boot service")
|
|
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{}{
|
|
"name": req.InstanceInfo.Name,
|
|
"configPath": configPath,
|
|
"bootAtStart": req.BootAtStart,
|
|
})
|
|
postLog.Info(fmt.Sprintf("[CreateInstanceHandler] Instance %s created successfully: configPath=%s, bootAtStart=%v, runUser=%s, additionalProperties=%v", req.InstanceInfo.Name, configPath, req.BootAtStart, runUser, req.Additional))
|
|
}
|
|
|
|
func DeleteInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceIDStr := getStringFromMap(reqMap, "instanceID")
|
|
if instanceIDStr == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
|
if err != nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusUnauthorized, err.Error())
|
|
return
|
|
}
|
|
|
|
if err := CheckPermission(userID, "superuser", "admin"); err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to check permission: %v", err))
|
|
SendErrorResponse(w, http.StatusForbidden, err.Error())
|
|
return
|
|
}
|
|
|
|
user, err := GetUserByID(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
var instance FrpcInstance
|
|
instance, err = DBQueryFrpcInstanceByID(instanceID)
|
|
if err == sql.ErrNoRows {
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] User %d tried to delete a not existed instance: %d", userID, instanceID))
|
|
return
|
|
}
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
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))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to remove boot service")
|
|
return
|
|
}
|
|
|
|
if _, err := os.Stat(instance.ConfigPath); err == nil {
|
|
if err := os.Remove(instance.ConfigPath); err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to remove config file %s: %v", instance.ConfigPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to remove config file")
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := DBRemoveFrpcInstanceByID(instanceID); err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteInstanceHandler] Failed to delete instance %d from database: %v", instanceID, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to delete instance from database")
|
|
return
|
|
}
|
|
|
|
SendSuccessResponse(w, "Instance deleted successfully", map[string]interface{}{
|
|
"id": instanceID,
|
|
})
|
|
postLog.Info(fmt.Sprintf("[DeleteInstanceHandler] Instance %d deleted successfully", instanceID))
|
|
}
|
|
|
|
func ModifyInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Invalid request method: %s", r.Method))
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceIDStr := getStringFromMap(reqMap, "instanceID")
|
|
if instanceIDStr == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
|
if err != nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
|
return
|
|
}
|
|
|
|
modifyType := getStringFromMap(reqMap, "type")
|
|
if modifyType == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "type is required")
|
|
return
|
|
}
|
|
|
|
if modifyType != "configFile" && modifyType != "systemConfig" {
|
|
SendErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("Unknown modify type %s", modifyType))
|
|
return
|
|
}
|
|
|
|
modifiedData, ok := reqMap["modifiedData"].(map[string]interface{})
|
|
if !ok || modifiedData == nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "modifiedData is required and must be an object")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusUnauthorized, err.Error())
|
|
return
|
|
}
|
|
|
|
if err := CheckPermission(userID, "superuser", "admin"); err != nil {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Failed to check permission: %v", err))
|
|
SendErrorResponse(w, http.StatusForbidden, err.Error())
|
|
return
|
|
}
|
|
|
|
instance, err := DBQueryFrpcInstanceByID(instanceID)
|
|
if err == sql.ErrNoRows {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] User %d tried to modify a not existed instance: %d", userID, instanceID))
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
return
|
|
}
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] User %d does not have permission to modify instance %d", userID, instanceID))
|
|
SendErrorResponse(w, http.StatusForbidden, "Permission denied")
|
|
return
|
|
}
|
|
|
|
user, err := GetUserByID(instance.UserID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
if modifyType == "configFile" {
|
|
handleConfigFileModify(w, instance, modifiedData, user.Username)
|
|
} else {
|
|
handleSystemConfigModify(w, r, instance, modifiedData, user)
|
|
}
|
|
}
|
|
|
|
func handleConfigFileModify(w http.ResponseWriter, instance FrpcInstance, modifiedData map[string]interface{}, username string) {
|
|
configPath := instance.ConfigPath
|
|
|
|
configContent, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleConfigFileModify] Failed to read config file %s: %v", configPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
|
|
return
|
|
}
|
|
|
|
updatedConfig, err := updateCommonSection(string(configContent), modifiedData)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleConfigFileModify] Failed to update common section: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to update config file")
|
|
return
|
|
}
|
|
|
|
if err := os.WriteFile(configPath, []byte(updatedConfig), 0644); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleConfigFileModify] Failed to write config file %s: %v", configPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
|
|
return
|
|
}
|
|
|
|
if v, ok := modifiedData["server_addr"].(string); ok && v != "" {
|
|
instance.ServerAddr = v
|
|
}
|
|
if v, ok := modifiedData["server_port"].(string); ok && v != "" {
|
|
instance.ServerPort = v
|
|
}
|
|
if v, ok := modifiedData["auth_method"].(string); ok && v != "" {
|
|
instance.AuthMethod = v
|
|
}
|
|
|
|
if err := DBUpdateFrpcInstance(instance); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleConfigFileModify] Failed to update instance in database: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to update instance in database")
|
|
return
|
|
}
|
|
|
|
SendSuccessResponse(w, "Config file modified successfully", map[string]interface{}{
|
|
"instanceName": instance.Name,
|
|
"instanceID": instance.ID,
|
|
"configPath": configPath,
|
|
})
|
|
postLog.Info(fmt.Sprintf("[handleConfigFileModify] Config file for instance %s modified successfully", instance.Name))
|
|
}
|
|
|
|
func updateCommonSection(configContent string, modifiedData map[string]interface{}) (string, error) {
|
|
var config FrpcConfig
|
|
if _, err := toml.Decode(configContent, &config); err != nil {
|
|
return "", fmt.Errorf("failed to parse config: %w", err)
|
|
}
|
|
|
|
for key, value := range modifiedData {
|
|
config.Common[key] = value
|
|
}
|
|
|
|
var buf strings.Builder
|
|
if err := toml.NewEncoder(&buf).Encode(config); err != nil {
|
|
return "", fmt.Errorf("failed to write config: %w", err)
|
|
}
|
|
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance FrpcInstance, modifiedData map[string]interface{}, user *User) {
|
|
newName := instance.Name
|
|
newRunUser := instance.RunUser
|
|
newBootAtStart := instance.BootAtStart
|
|
var bootServiceError string
|
|
|
|
if v, ok := modifiedData["name"].(string); ok && v != "" {
|
|
newName = v
|
|
}
|
|
if v, ok := modifiedData["runUser"].(string); ok {
|
|
newRunUser = v
|
|
}
|
|
if v, ok := modifiedData["bootAtStart"].(bool); ok {
|
|
newBootAtStart = v
|
|
}
|
|
|
|
oldConfigPath := instance.ConfigPath
|
|
var newConfigPath string
|
|
|
|
if newName != instance.Name || newRunUser != instance.RunUser {
|
|
configDir, err := GetConfigDir()
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to get config directory: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get config directory")
|
|
return
|
|
}
|
|
|
|
newConfigFileName := fmt.Sprintf("superfrpc_%s_%s.toml", user.Username, newName)
|
|
newConfigPath = filepath.Join(configDir, newConfigFileName)
|
|
|
|
if oldConfigPath != newConfigPath {
|
|
if _, err := os.Stat(oldConfigPath); err == nil {
|
|
if err := os.Rename(oldConfigPath, newConfigPath); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to rename config file %s to %s: %v", oldConfigPath, newConfigPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to rename config file")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
newConfigPath = oldConfigPath
|
|
}
|
|
|
|
instance.RunUser = newRunUser
|
|
instance.BootAtStart = newBootAtStart
|
|
instance.ConfigPath = newConfigPath
|
|
// Update instance new name will be processed in boot service creation or removal
|
|
|
|
if err := DBUpdateFrpcInstance(instance); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to update instance in database: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to update instance in database")
|
|
return
|
|
}
|
|
|
|
if newBootAtStart {
|
|
if err := removeBootAtStart(user.Username, instance.Name); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot at start: %v", err))
|
|
bootServiceError = fmt.Sprintf("Failed to remove boot at start: %v", err)
|
|
}
|
|
instance.Name = newName
|
|
if err := setBootAtStart(user.Username, newName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to set boot at start: %v", err))
|
|
if bootServiceError != "" {
|
|
bootServiceError += "; "
|
|
}
|
|
bootServiceError += fmt.Sprintf("Failed to set boot at start: %v", err)
|
|
}
|
|
} else {
|
|
if err := removeBootAtStart(user.Username, instance.Name); err != nil {
|
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot at start: %v", err))
|
|
bootServiceError = fmt.Sprintf("Failed to remove boot at start: %v", err)
|
|
}
|
|
instance.Name = newName
|
|
}
|
|
instance.Name = newName
|
|
|
|
data := map[string]interface{}{
|
|
"instanceName": newName,
|
|
"instanceID": instance.ID,
|
|
"configPath": newConfigPath,
|
|
"bootAtStart": newBootAtStart,
|
|
"runUser": newRunUser,
|
|
}
|
|
if bootServiceError != "" {
|
|
data["bootServiceError"] = bootServiceError
|
|
}
|
|
SendSuccessResponse(w, "System config modified successfully", data)
|
|
}
|
|
|
|
func generateFrpcConfig(info InstanceInfo) string {
|
|
config := FrpcConfig{
|
|
Common: make(map[string]interface{}),
|
|
}
|
|
|
|
config.Common["server_addr"] = info.ServerAddr
|
|
config.Common["server_port"] = info.ServerPort
|
|
config.Common["auth_method"] = info.AuthMethod
|
|
|
|
for key, value := range info.Additional {
|
|
config.Common[key] = value
|
|
}
|
|
|
|
var buf strings.Builder
|
|
if err := toml.NewEncoder(&buf).Encode(config); err != nil {
|
|
return ""
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
func GetUserInstances(userID int) ([]FrpcInstance, error) {
|
|
rows, err := frpcDB.Query(`
|
|
SELECT id, userID, name, serverAddr, serverPort, auth_method, bootAtStart, runUser, configPath, createdAt
|
|
FROM frpcInstances WHERE userID = ?
|
|
`, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var instances []FrpcInstance
|
|
for rows.Next() {
|
|
var instance FrpcInstance
|
|
var createdAtStr string
|
|
if err := rows.Scan(
|
|
&instance.ID, &instance.UserID, &instance.Name, &instance.ServerAddr, &instance.ServerPort,
|
|
&instance.AuthMethod, &instance.BootAtStart, &instance.RunUser, &instance.ConfigPath, &createdAtStr,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
instance.CreatedAt, _ = time.Parse(time.RFC3339, createdAtStr)
|
|
instances = append(instances, instance)
|
|
}
|
|
|
|
return instances, nil
|
|
}
|
|
|
|
func getStringFromMap(m map[string]interface{}, key string) string {
|
|
if v, ok := m[key].(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func ListInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[ListInstancesHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ListInstancesHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
userType, err := GetUserType(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ListInstancesHandler] Failed to get user type: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
|
|
return
|
|
}
|
|
|
|
instances, err := GetUserInstances(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ListInstancesHandler] Failed to get user instances: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get instances")
|
|
return
|
|
}
|
|
|
|
instanceList := make([]map[string]interface{}, len(instances))
|
|
for i, inst := range instances {
|
|
instanceData := map[string]interface{}{
|
|
"instanceID": inst.ID,
|
|
"name": inst.Name,
|
|
"bootAtStart": inst.BootAtStart,
|
|
"runUser": inst.RunUser,
|
|
"configPath": inst.ConfigPath,
|
|
"createdAt": inst.CreatedAt,
|
|
"createdBy": inst.CreatedBy,
|
|
}
|
|
|
|
if userType == "admin" || userType == "superuser" {
|
|
instanceData["serverAddr"] = inst.ServerAddr
|
|
instanceData["serverPort"] = inst.ServerPort
|
|
instanceData["auth_method"] = inst.AuthMethod
|
|
}
|
|
|
|
instanceList[i] = instanceData
|
|
}
|
|
|
|
SendSuccessResponse(w, "Instances retrieved successfully", instanceList)
|
|
postLog.Info(fmt.Sprintf("[ListInstancesHandler] Retrieved %d instances for user %d (type: %s)", len(instances), userID, userType))
|
|
}
|
|
|
|
func StartInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[StartInstanceHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceIDStr := getStringFromMap(reqMap, "instanceID")
|
|
if instanceIDStr == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
|
if err != nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
userType, err := GetUserType(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to get user type: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
|
|
return
|
|
}
|
|
if userType != "admin" && userType != "superuser" {
|
|
SendErrorResponse(w, http.StatusForbidden, "Permission Denied")
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Permission Denied for user %d (type: %s)", userID, userType))
|
|
return
|
|
}
|
|
|
|
instance, err := DBQueryFrpcInstanceByID(instanceID)
|
|
if err == sql.ErrNoRows {
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] User %d tried to start a not existed instance: %d", userID, instanceID))
|
|
return
|
|
}
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
SendErrorResponse(w, http.StatusForbidden, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] User %d tried to start instance %d that does not belong to them", userID, instanceID))
|
|
return
|
|
}
|
|
|
|
user, err := GetUserByID(instance.UserID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
initType := GetInitSystem()
|
|
serviceName := fmt.Sprintf("superfrpc_%s_%s", user.Username, instance.Name)
|
|
|
|
switch initType {
|
|
case "windows":
|
|
if err := StartWindowsService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to start Windows service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to start Windows service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[StartInstanceHandler] Windows service %s started successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance started successfully", nil)
|
|
|
|
case "systemd":
|
|
if err := StartSystemdService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to start systemd service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to start systemd service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[StartInstanceHandler] Systemd service %s started successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance started successfully", nil)
|
|
|
|
case "init.d":
|
|
if err := StartInitDService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Failed to start init.d service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to start init.d service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[StartInstanceHandler] Init.d service %s started successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance started successfully", nil)
|
|
|
|
default:
|
|
postLog.Error(fmt.Sprintf("[StartInstanceHandler] Unsupported init system: %s", initType))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Unsupported init system: %s", initType))
|
|
return
|
|
}
|
|
}
|
|
|
|
func StopInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[StopInstanceHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceIDStr := getStringFromMap(reqMap, "instanceID")
|
|
if instanceIDStr == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
|
if err != nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
userType, err := GetUserType(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to get user type: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
|
|
return
|
|
}
|
|
if userType != "admin" && userType != "superuser" {
|
|
SendErrorResponse(w, http.StatusForbidden, "Permission Denied")
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Permission Denied for user %d (type: %s)", userID, userType))
|
|
return
|
|
}
|
|
|
|
instance, err := DBQueryFrpcInstanceByID(instanceID)
|
|
if err == sql.ErrNoRows {
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] User %d tried to stop a not existed instance: %d", userID, instanceID))
|
|
return
|
|
}
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
SendErrorResponse(w, http.StatusForbidden, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] User %d tried to stop instance %d that does not belong to them", userID, instanceID))
|
|
return
|
|
}
|
|
|
|
user, err := GetUserByID(instance.UserID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
initType := GetInitSystem()
|
|
serviceName := fmt.Sprintf("superfrpc_%s_%s", user.Username, instance.Name)
|
|
|
|
switch initType {
|
|
case "windows":
|
|
if err := StopWindowsService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to stop Windows service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to stop Windows service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[StopInstanceHandler] Windows service %s stopped successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance stopped successfully", nil)
|
|
|
|
case "systemd":
|
|
if err := StopSystemdService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to stop systemd service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to stop systemd service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[StopInstanceHandler] Systemd service %s stopped successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance stopped successfully", nil)
|
|
|
|
case "init.d":
|
|
if err := StopInitDService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Failed to stop init.d service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to stop init.d service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[StopInstanceHandler] Init.d service %s stopped successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance stopped successfully", nil)
|
|
|
|
default:
|
|
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Unsupported init system: %s", initType))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Unsupported init system: %s", initType))
|
|
return
|
|
}
|
|
}
|
|
|
|
func RestartInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[RestartInstanceHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceIDStr := getStringFromMap(reqMap, "instanceID")
|
|
if instanceIDStr == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
|
if err != nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
userType, err := GetUserType(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to get user type: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
|
|
return
|
|
}
|
|
if userType != "admin" && userType != "superuser" {
|
|
SendErrorResponse(w, http.StatusForbidden, "Permission Denied")
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Permission Denied for user %d (type: %s)", userID, userType))
|
|
return
|
|
}
|
|
|
|
instance, err := DBQueryFrpcInstanceByID(instanceID)
|
|
if err == sql.ErrNoRows {
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] User %d tried to restart a not existed instance: %d", userID, instanceID))
|
|
return
|
|
}
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
SendErrorResponse(w, http.StatusForbidden, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] User %d tried to restart instance %d that does not belong to them", userID, instanceID))
|
|
return
|
|
}
|
|
|
|
user, err := GetUserByID(instance.UserID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
initType := GetInitSystem()
|
|
serviceName := fmt.Sprintf("superfrpc_%s_%s", user.Username, instance.Name)
|
|
|
|
switch initType {
|
|
case "windows":
|
|
if err := RestartWindowsService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to restart Windows service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to restart Windows service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[RestartInstanceHandler] Windows service %s restarted successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance restarted successfully", nil)
|
|
|
|
case "systemd":
|
|
if err := RestartSystemdService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to restart systemd service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to restart systemd service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[RestartInstanceHandler] Systemd service %s restarted successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance restarted successfully", nil)
|
|
|
|
case "init.d":
|
|
if err := RestartInitDService(serviceName); err != nil {
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Failed to restart init.d service %s: %v", serviceName, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Failed to restart init.d service: %v", err))
|
|
return
|
|
}
|
|
postLog.Info(fmt.Sprintf("[RestartInstanceHandler] Init.d service %s restarted successfully", serviceName))
|
|
SendSuccessResponse(w, "Instance restarted successfully", nil)
|
|
|
|
default:
|
|
postLog.Error(fmt.Sprintf("[RestartInstanceHandler] Unsupported init system: %s", initType))
|
|
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Unsupported init system: %s", initType))
|
|
return
|
|
}
|
|
}
|
|
|
|
func GetInstanceStatusHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[GetInstanceStatusHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
queryParams := r.URL.Query()
|
|
instanceIDStr := queryParams.Get("instanceID")
|
|
if instanceIDStr == "" {
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
|
if err != nil {
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[GetInstanceStatusHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
instance, err := DBQueryFrpcInstanceByID(instanceID)
|
|
if err == sql.ErrNoRows {
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[GetInstanceStatusHandler] User %d tried to get status of a not existed instance: %d", userID, instanceID))
|
|
return
|
|
}
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[GetInstanceStatusHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
SendErrorResponse(w, http.StatusForbidden, "Instance not found")
|
|
postLog.Error(fmt.Sprintf("[GetInstanceStatusHandler] User %d tried to get status of instance %d that does not belong to them", userID, instanceID))
|
|
return
|
|
}
|
|
|
|
user, err := GetUserByID(instance.UserID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[GetInstanceStatusHandler] Failed to get user info: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user info")
|
|
return
|
|
}
|
|
|
|
initType := GetInitSystem()
|
|
|
|
serviceName := fmt.Sprintf("superfrpc_%s_%s", user.Username, instance.Name)
|
|
|
|
responseData := map[string]interface{}{
|
|
"name": instance.Name,
|
|
"initSystem": initType,
|
|
"serviceName": serviceName,
|
|
"isRunning": false,
|
|
}
|
|
|
|
isRunning := IsInstanceRunning(instance.Name)
|
|
responseData["isRunning"] = isRunning
|
|
|
|
SendSuccessResponse(w, "Instance status retrieved successfully", responseData)
|
|
postLog.Info(fmt.Sprintf("[GetInstanceStatusHandler] Retrieved status for instance %d (name: %s), isRunning: %v", instanceID, instance.Name, isRunning))
|
|
}
|