feat(frpAct): add Windows/Systemd/Init.d service boot control. BUT WINDOWS STILL HAS BUGS AND LINUX HAS NOT BEEN TESTED.
This commit is contained in:
282
docs/api.md
282
docs/api.md
@@ -492,21 +492,36 @@ X-Timestamp: 1704067200000
|
|||||||
**Request Body:**
|
**Request Body:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"instanceName": "my_frpc"
|
"instanceID": "1"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| Header | Type | Required | Description |
|
||||||
|
|--------|------|----------|-------------|
|
||||||
|
| X-Token | string | Yes | Authentication token |
|
||||||
|
| X-Timestamp | int64 | Yes | Client timestamp in milliseconds |
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| instanceID | string | Yes | Instance ID (the ID of the frpc instance) |
|
||||||
|
|
||||||
**Response:**
|
**Response:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "instance deleted successfully",
|
"message": "instance deleted successfully",
|
||||||
"data": {
|
"data": {
|
||||||
|
"instanceID": 1,
|
||||||
"name": "my_frpc"
|
"name": "my_frpc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| instanceID | int | Instance ID |
|
||||||
|
| name | string | Name of the deleted frpc instance |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Modify frpc Instance
|
## Modify frpc Instance
|
||||||
@@ -532,7 +547,6 @@ Modify fields in the `[common]` section of the frpc configuration file. Only `[c
|
|||||||
**Request Body:**
|
**Request Body:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"instanceName": "my_frpc",
|
|
||||||
"instanceID": "1",
|
"instanceID": "1",
|
||||||
"type": "configFile",
|
"type": "configFile",
|
||||||
"modifiedData": {
|
"modifiedData": {
|
||||||
@@ -546,8 +560,7 @@ Modify fields in the `[common]` section of the frpc configuration file. Only `[c
|
|||||||
|
|
||||||
| Field | Type | Required | Description |
|
| Field | Type | Required | Description |
|
||||||
|-------|------|----------|-------------|
|
|-------|------|----------|-------------|
|
||||||
| instanceName | string | Yes | Current instance name |
|
| instanceID | string | Yes | Instance ID (the ID of the frpc instance) |
|
||||||
| instanceID | string | Yes | Instance ID |
|
|
||||||
| type | string | Yes | Modification type: `configFile` or `systemConfig` |
|
| type | string | Yes | Modification type: `configFile` or `systemConfig` |
|
||||||
| modifiedData | object | Yes | Key-value pairs of fields to modify in `[common]` section |
|
| modifiedData | object | Yes | Key-value pairs of fields to modify in `[common]` section |
|
||||||
|
|
||||||
@@ -557,7 +570,6 @@ Modify fields in the `[common]` section of the frpc configuration file. Only `[c
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "Config file modified successfully",
|
"message": "Config file modified successfully",
|
||||||
"data": {
|
"data": {
|
||||||
"instanceName": "my_frpc",
|
|
||||||
"instanceID": 1,
|
"instanceID": 1,
|
||||||
"configPath": "./configs/superfrpc_user_my_frpc.toml"
|
"configPath": "./configs/superfrpc_user_my_frpc.toml"
|
||||||
}
|
}
|
||||||
@@ -571,7 +583,6 @@ Modify system-level settings such as instance name, boot-at-start configuration,
|
|||||||
**Request Body:**
|
**Request Body:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"instanceName": "my_frpc",
|
|
||||||
"instanceID": "1",
|
"instanceID": "1",
|
||||||
"type": "systemConfig",
|
"type": "systemConfig",
|
||||||
"modifiedData": {
|
"modifiedData": {
|
||||||
@@ -584,8 +595,7 @@ Modify system-level settings such as instance name, boot-at-start configuration,
|
|||||||
|
|
||||||
| Field | Type | Required | Description |
|
| Field | Type | Required | Description |
|
||||||
|-------|------|----------|-------------|
|
|-------|------|----------|-------------|
|
||||||
| instanceName | string | Yes | Current instance name |
|
| instanceID | string | Yes | Instance ID (the ID of the frpc instance) |
|
||||||
| instanceID | string | Yes | Instance ID |
|
|
||||||
| type | string | Yes | Modification type: `configFile` or `systemConfig` |
|
| type | string | Yes | Modification type: `configFile` or `systemConfig` |
|
||||||
| modifiedData.name | string | No | New instance name (renames config file if changed) |
|
| modifiedData.name | string | No | New instance name (renames config file if changed) |
|
||||||
| modifiedData.bootAtStart | bool | No | Auto-start on system boot |
|
| modifiedData.bootAtStart | bool | No | Auto-start on system boot |
|
||||||
@@ -597,7 +607,6 @@ Modify system-level settings such as instance name, boot-at-start configuration,
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "System config modified successfully",
|
"message": "System config modified successfully",
|
||||||
"data": {
|
"data": {
|
||||||
"instanceName": "new_frpc_name",
|
|
||||||
"instanceID": 1,
|
"instanceID": 1,
|
||||||
"configPath": "./configs/superfrpc_user_new_frpc_name.toml",
|
"configPath": "./configs/superfrpc_user_new_frpc_name.toml",
|
||||||
"bootAtStart": true,
|
"bootAtStart": true,
|
||||||
@@ -635,6 +644,255 @@ Modify system-level settings such as instance name, boot-at-start configuration,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Start frpc Instance
|
||||||
|
|
||||||
|
**Endpoint:** `/frpcAct/instanceMgr/start`
|
||||||
|
**Method:** POST
|
||||||
|
**Content-Type:** application/json
|
||||||
|
**Auth Required:** Yes (token)
|
||||||
|
**Permission Level:** Admin
|
||||||
|
|
||||||
|
Start a frpc instance. The instance can be started as a background process on Windows (hidden window) or as a systemd/init.d service on Linux.
|
||||||
|
|
||||||
|
**Request Headers:**
|
||||||
|
```
|
||||||
|
X-Token: your_token
|
||||||
|
X-Timestamp: 1704067200000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"instanceID": "1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Header | Type | Required | Description |
|
||||||
|
|--------|------|----------|-------------|
|
||||||
|
| X-Token | string | Yes | Authentication token |
|
||||||
|
| X-Timestamp | int64 | Yes | Client timestamp in milliseconds |
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| instanceID | string | Yes | ID of the instance to start |
|
||||||
|
|
||||||
|
**Response (Windows):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance started successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (Linux systemd):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance started successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (Linux init.d):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance started successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stop frpc Instance
|
||||||
|
|
||||||
|
**Endpoint:** `/frpcAct/instanceMgr/stop`
|
||||||
|
**Method:** POST
|
||||||
|
**Content-Type:** application/json
|
||||||
|
**Auth Required:** Yes (token)
|
||||||
|
**Permission Level:** Admin
|
||||||
|
|
||||||
|
Stop a running frpc instance. On Windows, this stops the frpc process. On Linux, this stops the systemd/init.d service.
|
||||||
|
|
||||||
|
**Request Headers:**
|
||||||
|
```
|
||||||
|
X-Token: your_token
|
||||||
|
X-Timestamp: 1704067200000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"instanceID": "1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Header | Type | Required | Description |
|
||||||
|
|--------|------|----------|-------------|
|
||||||
|
| X-Token | string | Yes | Authentication token |
|
||||||
|
| X-Timestamp | int64 | Yes | Client timestamp in milliseconds |
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| instanceID | string | Yes | ID of the instance to stop |
|
||||||
|
|
||||||
|
**Response (Windows):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance stopped successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (Linux systemd):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance stopped successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (Linux init.d):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance stopped successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Restart frpc Instance
|
||||||
|
|
||||||
|
**Endpoint:** `/frpcAct/instanceMgr/restart`
|
||||||
|
**Method:** POST
|
||||||
|
**Content-Type:** application/json
|
||||||
|
**Auth Required:** Yes (token)
|
||||||
|
**Permission Level:** Admin
|
||||||
|
|
||||||
|
Restart a frpc instance. This stops and then starts the instance again.
|
||||||
|
|
||||||
|
**Request Headers:**
|
||||||
|
```
|
||||||
|
X-Token: your_token
|
||||||
|
X-Timestamp: 1704067200000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"instanceID": "1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Header | Type | Required | Description |
|
||||||
|
|--------|------|----------|-------------|
|
||||||
|
| X-Token | string | Yes | Authentication token |
|
||||||
|
| X-Timestamp | int64 | Yes | Client timestamp in milliseconds |
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| instanceID | string | Yes | ID of the instance to restart |
|
||||||
|
|
||||||
|
**Response (Windows):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance restarted successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (Linux systemd):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance restarted successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (Linux init.d):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance restarted successfully",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Get frpc Instance Status
|
||||||
|
|
||||||
|
**Endpoint:** `/frpcAct/instanceMgr/status`
|
||||||
|
**Method:** GET
|
||||||
|
**Auth Required:** Yes (token)
|
||||||
|
**Permission Level:** Visitor
|
||||||
|
|
||||||
|
Check the running status of a frpc instance.
|
||||||
|
|
||||||
|
**Request Headers:**
|
||||||
|
```
|
||||||
|
X-Token: your_token
|
||||||
|
X-Timestamp: 1704067200000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
```
|
||||||
|
instanceID=1
|
||||||
|
```
|
||||||
|
|
||||||
|
| Header | Type | Required | Description |
|
||||||
|
|--------|------|----------|-------------|
|
||||||
|
| X-Token | string | Yes | Authentication token |
|
||||||
|
| X-Timestamp | int64 | Yes | Client timestamp in milliseconds |
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
|-----------|------|----------|-------------|
|
||||||
|
| instanceID | string | Yes | ID of the instance to check |
|
||||||
|
|
||||||
|
**Response (running):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance status retrieved successfully",
|
||||||
|
"data": {
|
||||||
|
"name": "my_frpc",
|
||||||
|
"initSystem": "systemd",
|
||||||
|
"serviceName": "superfrpc_admin_my_frpc",
|
||||||
|
"isRunning": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (stopped):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Instance status retrieved successfully",
|
||||||
|
"data": {
|
||||||
|
"name": "my_frpc",
|
||||||
|
"initSystem": "systemd",
|
||||||
|
"serviceName": "superfrpc_admin_my_frpc",
|
||||||
|
"isRunning": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| name | string | Name of the frpc instance |
|
||||||
|
| initSystem | string | Operating system init system: "windows", "systemd", or "init.d" |
|
||||||
|
| serviceName | string | Service name (Linux only) |
|
||||||
|
| isRunning | boolean | Instance running status: true (running) or false (stopped) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Create Proxy
|
## Create Proxy
|
||||||
|
|
||||||
**Endpoint:** `/frpcAct/proxyMgr/create`
|
**Endpoint:** `/frpcAct/proxyMgr/create`
|
||||||
@@ -685,7 +943,6 @@ X-Timestamp: 1704067200000
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "Proxy created successfully",
|
"message": "Proxy created successfully",
|
||||||
"data": {
|
"data": {
|
||||||
"instanceName": "my_frpc",
|
|
||||||
"instanceID": 1,
|
"instanceID": 1,
|
||||||
"configPath": "./configs/superfrpc_user_my_frpc.toml",
|
"configPath": "./configs/superfrpc_user_my_frpc.toml",
|
||||||
"proxyName": "ssh_proxy"
|
"proxyName": "ssh_proxy"
|
||||||
@@ -695,7 +952,6 @@ X-Timestamp: 1704067200000
|
|||||||
|
|
||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
|-------|------|-------------|
|
|-------|------|-------------|
|
||||||
| instanceName | string | Name of the frpc instance |
|
|
||||||
| instanceID | int | Instance ID |
|
| instanceID | int | Instance ID |
|
||||||
| configPath | string | Path to the configuration file |
|
| configPath | string | Path to the configuration file |
|
||||||
| proxyName | string | Name of the created proxy |
|
| proxyName | string | Name of the created proxy |
|
||||||
@@ -761,7 +1017,6 @@ X-Timestamp: 1704067200000
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "Proxy deleted successfully",
|
"message": "Proxy deleted successfully",
|
||||||
"data": {
|
"data": {
|
||||||
"instanceName": "my_frpc",
|
|
||||||
"instanceID": 1,
|
"instanceID": 1,
|
||||||
"configPath": "./configs/superfrpc_user_my_frpc.toml",
|
"configPath": "./configs/superfrpc_user_my_frpc.toml",
|
||||||
"proxyName": "ssh_proxy"
|
"proxyName": "ssh_proxy"
|
||||||
@@ -771,7 +1026,6 @@ X-Timestamp: 1704067200000
|
|||||||
|
|
||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
|-------|------|-------------|
|
|-------|------|-------------|
|
||||||
| instanceName | string | Name of the frpc instance |
|
|
||||||
| instanceID | int | Instance ID |
|
| instanceID | int | Instance ID |
|
||||||
| configPath | string | Path to the configuration file |
|
| configPath | string | Path to the configuration file |
|
||||||
| proxyName | string | Name of the deleted proxy |
|
| proxyName | string | Name of the deleted proxy |
|
||||||
@@ -820,7 +1074,6 @@ X-Timestamp: 1704067200000
|
|||||||
"message": "Proxies listed successfully",
|
"message": "Proxies listed successfully",
|
||||||
"data": {
|
"data": {
|
||||||
"instanceID": 1,
|
"instanceID": 1,
|
||||||
"instanceName": "my_frpc",
|
|
||||||
"proxyCount": 2,
|
"proxyCount": 2,
|
||||||
"proxies": [
|
"proxies": [
|
||||||
{
|
{
|
||||||
@@ -845,7 +1098,6 @@ X-Timestamp: 1704067200000
|
|||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
|-------|------|-------------|
|
|-------|------|-------------|
|
||||||
| instanceID | int | Instance ID |
|
| instanceID | int | Instance ID |
|
||||||
| instanceName | string | Name of the frpc instance |
|
|
||||||
| proxyCount | int | Number of proxies |
|
| proxyCount | int | Number of proxies |
|
||||||
| proxies | array | List of proxy configurations |
|
| proxies | array | List of proxy configurations |
|
||||||
|
|
||||||
|
|||||||
479
frpAct.go
479
frpAct.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"super-frpc/postLog"
|
"super-frpc/postLog"
|
||||||
"time"
|
"time"
|
||||||
@@ -307,15 +308,15 @@ func ModifyInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceName := getStringFromMap(reqMap, "instanceName")
|
instanceIDStr := getStringFromMap(reqMap, "instanceID")
|
||||||
if instanceName == "" {
|
if instanceIDStr == "" {
|
||||||
SendErrorResponse(w, http.StatusBadRequest, "instanceName is required")
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceID := getStringFromMap(reqMap, "instanceID")
|
instanceID, err := strconv.Atoi(instanceIDStr)
|
||||||
if instanceID == "" {
|
if err != nil {
|
||||||
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,16 +350,9 @@ func ModifyInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := GetUserByID(userID)
|
instance, err := DBQueryFrpcInstanceByID(instanceID)
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
instance, err := DBQueryFrpcInstance(userID, instanceName)
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] User %d tried to modify a not existed instance: %s", userID, instanceName))
|
postLog.Error(fmt.Sprintf("[ModifyInstanceHandler] User %d tried to modify a not existed instance: %d", userID, instanceID))
|
||||||
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -368,8 +362,16 @@ func ModifyInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if fmt.Sprintf("%d", instance.ID) != instanceID {
|
if instance.UserID != userID {
|
||||||
SendErrorResponse(w, http.StatusBadRequest, "instanceID does not match instanceName")
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,7 +451,6 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F
|
|||||||
newName := instance.Name
|
newName := instance.Name
|
||||||
newRunUser := instance.RunUser
|
newRunUser := instance.RunUser
|
||||||
newBootAtStart := instance.BootAtStart
|
newBootAtStart := instance.BootAtStart
|
||||||
oldBootAtStart := instance.BootAtStart
|
|
||||||
var bootServiceError string
|
var bootServiceError string
|
||||||
|
|
||||||
if v, ok := modifiedData["name"].(string); ok && v != "" {
|
if v, ok := modifiedData["name"].(string); ok && v != "" {
|
||||||
@@ -489,10 +490,10 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F
|
|||||||
newConfigPath = oldConfigPath
|
newConfigPath = oldConfigPath
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.Name = newName
|
|
||||||
instance.RunUser = newRunUser
|
instance.RunUser = newRunUser
|
||||||
instance.BootAtStart = newBootAtStart
|
instance.BootAtStart = newBootAtStart
|
||||||
instance.ConfigPath = newConfigPath
|
instance.ConfigPath = newConfigPath
|
||||||
|
// Update instance new name will be processed in boot service creation or removal
|
||||||
|
|
||||||
if err := DBUpdateFrpcInstance(instance); err != nil {
|
if err := DBUpdateFrpcInstance(instance); err != nil {
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to update instance in database: %v", err))
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to update instance in database: %v", err))
|
||||||
@@ -500,29 +501,27 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldBootAtStart && !newBootAtStart {
|
if newBootAtStart {
|
||||||
if err := removeBootService(user.Username, instance.Name); err != nil {
|
if err := removeBootService(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 service: %v", err))
|
||||||
bootServiceError = fmt.Sprintf("Failed to remove boot service: %v", err)
|
bootServiceError = fmt.Sprintf("Failed to remove boot service: %v", err)
|
||||||
}
|
}
|
||||||
} else if !oldBootAtStart && newBootAtStart {
|
instance.Name = newName
|
||||||
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil {
|
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil {
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create boot service: %v", err))
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create boot service: %v", err))
|
||||||
bootServiceError = fmt.Sprintf("Failed to create boot service: %v", err)
|
|
||||||
}
|
|
||||||
} else if oldBootAtStart && newBootAtStart && (instance.Name != newName || instance.RunUser != newRunUser) {
|
|
||||||
if err := removeBootService(user.Username, instance.Name); err != nil {
|
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove old boot service: %v", err))
|
|
||||||
bootServiceError = fmt.Sprintf("Failed to remove old boot service: %v", err)
|
|
||||||
}
|
|
||||||
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil {
|
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create new boot service: %v", err))
|
|
||||||
if bootServiceError != "" {
|
if bootServiceError != "" {
|
||||||
bootServiceError += "; "
|
bootServiceError += "; "
|
||||||
}
|
}
|
||||||
bootServiceError += fmt.Sprintf("Failed to create new boot service: %v", err)
|
bootServiceError += fmt.Sprintf("Failed to create boot service: %v", err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if err := removeBootService(user.Username, instance.Name); err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot service: %v", err))
|
||||||
|
bootServiceError = fmt.Sprintf("Failed to remove boot service: %v", err)
|
||||||
|
}
|
||||||
|
instance.Name = newName
|
||||||
}
|
}
|
||||||
|
instance.Name = newName
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"instanceName": newName,
|
"instanceName": newName,
|
||||||
@@ -644,3 +643,421 @@ func ListInstancesHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
SendSuccessResponse(w, "Instances retrieved successfully", instanceList)
|
SendSuccessResponse(w, "Instances retrieved successfully", instanceList)
|
||||||
postLog.Info(fmt.Sprintf("[ListInstancesHandler] Retrieved %d instances for user %d (type: %s)", len(instances), userID, userType))
|
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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -122,12 +122,11 @@ func CreateProxyHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SendSuccessResponse(w, "Proxy created successfully", map[string]interface{}{
|
SendSuccessResponse(w, "Proxy created successfully", map[string]interface{}{
|
||||||
"instanceName": instance.Name,
|
"instanceID": instance.ID,
|
||||||
"instanceID": instance.ID,
|
"configPath": instance.ConfigPath,
|
||||||
"configPath": instance.ConfigPath,
|
"proxyName": proxyInfo.Name,
|
||||||
"proxyName": proxyInfo.Name,
|
|
||||||
})
|
})
|
||||||
postLog.Info(fmt.Sprintf("[CreateProxyHandler] Proxy %s created successfully for instance %s", proxyInfo.Name, instance.Name))
|
postLog.Info(fmt.Sprintf("[CreateProxyHandler] Proxy %s created successfully for instance %d", proxyInfo.Name, instance.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func addFrpcProxy(configContent string, info FrpcProxyInfo) (string, error) {
|
func addFrpcProxy(configContent string, info FrpcProxyInfo) (string, error) {
|
||||||
@@ -137,8 +136,8 @@ func addFrpcProxy(configContent string, info FrpcProxyInfo) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proxy := map[string]interface{}{
|
proxy := map[string]interface{}{
|
||||||
"name": info.Name,
|
"name": info.Name,
|
||||||
"type": info.Type,
|
"type": info.Type,
|
||||||
"localIP": info.LocalIP,
|
"localIP": info.LocalIP,
|
||||||
"localPort": info.LocalPort,
|
"localPort": info.LocalPort,
|
||||||
"remotePort": info.RemotePort,
|
"remotePort": info.RemotePort,
|
||||||
@@ -243,12 +242,11 @@ func DeleteProxyHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SendSuccessResponse(w, "Proxy deleted successfully", map[string]interface{}{
|
SendSuccessResponse(w, "Proxy deleted successfully", map[string]interface{}{
|
||||||
"instanceName": instance.Name,
|
"instanceID": instance.ID,
|
||||||
"instanceID": instance.ID,
|
"configPath": instance.ConfigPath,
|
||||||
"configPath": instance.ConfigPath,
|
"proxyName": proxyName,
|
||||||
"proxyName": proxyName,
|
|
||||||
})
|
})
|
||||||
postLog.Info(fmt.Sprintf("[DeleteProxyHandler] Proxy %s deleted successfully from instance %s", proxyName, instance.Name))
|
postLog.Info(fmt.Sprintf("[DeleteProxyHandler] Proxy %s deleted successfully from instance %d", proxyName, instance.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeFrpcProxy(configContent string, proxyName string) (string, error) {
|
func removeFrpcProxy(configContent string, proxyName string) (string, error) {
|
||||||
@@ -335,20 +333,19 @@ func ListProxiesHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
proxyList := make([]map[string]interface{}, len(config.Proxies))
|
proxyList := make([]map[string]interface{}, len(config.Proxies))
|
||||||
for i, proxy := range config.Proxies {
|
for i, proxy := range config.Proxies {
|
||||||
proxyData := map[string]interface{}{
|
proxyData := map[string]interface{}{
|
||||||
"name": proxy["name"],
|
"name": proxy["name"],
|
||||||
"type": proxy["type"],
|
"type": proxy["type"],
|
||||||
"localIP": proxy["localIP"],
|
"localIP": proxy["localIP"],
|
||||||
"localPort": proxy["localPort"],
|
"localPort": proxy["localPort"],
|
||||||
"remotePort": proxy["remotePort"],
|
"remotePort": proxy["remotePort"],
|
||||||
}
|
}
|
||||||
proxyList[i] = proxyData
|
proxyList[i] = proxyData
|
||||||
}
|
}
|
||||||
|
|
||||||
SendSuccessResponse(w, "Proxies listed successfully", map[string]interface{}{
|
SendSuccessResponse(w, "Proxies listed successfully", map[string]interface{}{
|
||||||
"instanceID": instance.ID,
|
"instanceID": instance.ID,
|
||||||
"instanceName": instance.Name,
|
"proxyCount": len(proxyList),
|
||||||
"proxyCount": len(proxyList),
|
"proxies": proxyList,
|
||||||
"proxies": proxyList,
|
|
||||||
})
|
})
|
||||||
postLog.Info(fmt.Sprintf("[ListProxiesHandler] Retrieved %d proxies for instance %s", len(proxyList), instance.Name))
|
postLog.Info(fmt.Sprintf("[ListProxiesHandler] Retrieved %d proxies for instance %d", len(proxyList), instance.ID))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,16 @@ type Response struct {
|
|||||||
Data interface{} `json:"data,omitempty"`
|
Data interface{} `json:"data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendErrorResponse(w http.ResponseWriter, statusCode int, message string) {
|
func SendErrorResponse(w http.ResponseWriter, statusCode int, message string, data ...interface{}) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(statusCode)
|
w.WriteHeader(statusCode)
|
||||||
resp := Response{
|
resp := Response{
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: message,
|
Message: message,
|
||||||
}
|
}
|
||||||
|
if len(data) > 0 {
|
||||||
|
resp.Data = data[0]
|
||||||
|
}
|
||||||
jsonResp, err := json.Marshal(resp)
|
jsonResp, err := json.Marshal(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
postLog.Error(fmt.Sprintf("Failed to marshal error response: %v", err))
|
postLog.Error(fmt.Sprintf("Failed to marshal error response: %v", err))
|
||||||
|
|||||||
275
os.go
275
os.go
@@ -7,9 +7,9 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"super-frpc/postLog"
|
"super-frpc/postLog"
|
||||||
|
|
||||||
"golang.org/x/sys/windows/registry"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetConfigDir() (string, error) {
|
func GetConfigDir() (string, error) {
|
||||||
@@ -30,7 +30,7 @@ func GetFrpcPath() (string, error) {
|
|||||||
return config.FrpcPath, nil
|
return config.FrpcPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func detectInitSystem() string {
|
func GetInitSystem() string {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
return "windows"
|
return "windows"
|
||||||
}
|
}
|
||||||
@@ -46,9 +46,9 @@ func detectInitSystem() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createBootService(username, instanceName, configPath, runUser string) error {
|
func createBootService(username, instanceName, configPath, runUser string) error {
|
||||||
initSystem := detectInitSystem()
|
initType := GetInitSystem()
|
||||||
|
|
||||||
switch initSystem {
|
switch initType {
|
||||||
case "systemd":
|
case "systemd":
|
||||||
return createSystemdService(username, instanceName, configPath, runUser)
|
return createSystemdService(username, instanceName, configPath, runUser)
|
||||||
case "init.d":
|
case "init.d":
|
||||||
@@ -240,25 +240,22 @@ func createWindowsBootService(username, instanceName, configPath string) error {
|
|||||||
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
||||||
command := fmt.Sprintf("\"%s\" -c \"%s\"", frpcPath, configPath)
|
command := fmt.Sprintf("\"%s\" -c \"%s\"", frpcPath, configPath)
|
||||||
|
|
||||||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, registry.WRITE|registry.WOW64_64KEY)
|
cmd := exec.Command("sc", "create", serviceName, "binPath=", command, "start=", "auto")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
postLog.Debug(fmt.Sprintf("[createWindowsBootService] Sc create output: %s", output))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open registry key: %w", err)
|
return fmt.Errorf("failed to create Windows service: %s, output: %s", err, output)
|
||||||
}
|
|
||||||
defer key.Close()
|
|
||||||
|
|
||||||
if err := key.SetStringValue(serviceName, command); err != nil {
|
|
||||||
return fmt.Errorf("failed to set registry value: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeBootService(username, instanceName string) error {
|
func removeBootService(username, instanceName string) error {
|
||||||
initSystem := detectInitSystem()
|
initType := GetInitSystem()
|
||||||
|
|
||||||
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
||||||
|
|
||||||
switch initSystem {
|
switch initType {
|
||||||
case "systemd":
|
case "systemd":
|
||||||
cmd := exec.Command("systemctl", "disable", serviceName)
|
cmd := exec.Command("systemctl", "disable", serviceName)
|
||||||
cmd.CombinedOutput()
|
cmd.CombinedOutput()
|
||||||
@@ -277,18 +274,250 @@ func removeBootService(username, instanceName string) error {
|
|||||||
os.Remove(servicePath)
|
os.Remove(servicePath)
|
||||||
|
|
||||||
case "windows":
|
case "windows":
|
||||||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, registry.WRITE|registry.WOW64_64KEY)
|
cmd := exec.Command("sc", "delete", serviceName)
|
||||||
if err != nil {
|
postLog.Debug(fmt.Sprintf("[removeBootService] Sc delete command: %s", cmd.String()))
|
||||||
postLog.Error(fmt.Sprintf("[removeBootService] Failed to open registry key: %v", err))
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
} else {
|
postLog.Error(fmt.Sprintf("[removeBootService] Failed to delete Windows service: %s, output: %s", err, output))
|
||||||
defer key.Close()
|
|
||||||
if err := key.DeleteValue(serviceName); err != nil {
|
|
||||||
postLog.Error(fmt.Sprintf("[removeBootService] Failed to delete registry value: %v", err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
postLog.Error(fmt.Sprintf("[removeBootService] Unsupported init system: %s", initSystem))
|
postLog.Error(fmt.Sprintf("[removeBootService] Unsupported init system: %s", initType))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsInstanceRunning(instanceName string) bool {
|
||||||
|
initType := GetInitSystem()
|
||||||
|
switch initType {
|
||||||
|
case "windows":
|
||||||
|
cmd := exec.Command("sc", "query", instanceName)
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
postLog.Debug(fmt.Sprintf("[IsInstanceRunning] Sc query output: %s", output))
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[IsInstanceRunning] Failed to check Windows service status: %s, output: %s", err, output))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStr := string(output)
|
||||||
|
if strings.Contains(outputStr, "RUNNING") {
|
||||||
|
postLog.Info(fmt.Sprintf("[IsInstanceRunning] Windows service %s is running", instanceName))
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
postLog.Info(fmt.Sprintf("[IsInstanceRunning] Windows service %s is stopped", instanceName))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
case "systemd":
|
||||||
|
cmd := exec.Command("systemctl", "is-active", instanceName)
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[IsInstanceRunning] Failed to check systemd service status: %s, output: %s", err, output))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
status := strings.TrimSpace(string(output))
|
||||||
|
if status == "active" {
|
||||||
|
postLog.Info(fmt.Sprintf("[IsInstanceRunning] Systemd service %s is running", instanceName))
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
postLog.Info(fmt.Sprintf("[IsInstanceRunning] Systemd service %s is stopped", instanceName))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
case "init.d":
|
||||||
|
servicePath := fmt.Sprintf("/etc/init.d/%s", instanceName)
|
||||||
|
if _, err := os.Stat(servicePath); err != nil {
|
||||||
|
postLog.Info(fmt.Sprintf("[IsInstanceRunning] Init.d service %s not found", instanceName))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(servicePath, "status")
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[IsInstanceRunning] Failed to check init.d service status: %s, output: %s", err, output))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStr := strings.TrimSpace(string(output))
|
||||||
|
if strings.Contains(outputStr, "is running") {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
postLog.Error(fmt.Sprintf("[IsInstanceRunning] Unsupported init system: %s", initType))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInstancePid(instanceName string) int {
|
||||||
|
initType := GetInitSystem()
|
||||||
|
switch initType {
|
||||||
|
case "windows":
|
||||||
|
cmd := exec.Command("sc", "query", instanceName, "info")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[GetInstancePid] Failed to get Windows service info: %s, output: %s", err, output))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
outputStr := string(output)
|
||||||
|
lines := strings.Split(outputStr, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.Contains(line, "PID") {
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
pidStr := strings.TrimSpace(parts[1])
|
||||||
|
pid, err := strconv.Atoi(pidStr)
|
||||||
|
if err == nil {
|
||||||
|
return pid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
case "systemd":
|
||||||
|
cmd := exec.Command("systemctl", "show", instanceName, "--property", "MainPID")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[GetInstancePid] Failed to get PID from systemd: %s, output: %s", err, output))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
outputStr := strings.TrimSpace(string(output))
|
||||||
|
parts := strings.Split(outputStr, "=")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
pidStr := strings.TrimSpace(parts[1])
|
||||||
|
if pidStr != "" && pidStr != "0" {
|
||||||
|
pid, err := strconv.Atoi(pidStr)
|
||||||
|
if err == nil {
|
||||||
|
return pid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
case "init.d":
|
||||||
|
servicePath := fmt.Sprintf("/etc/init.d/%s", instanceName)
|
||||||
|
if _, err := os.Stat(servicePath); err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[GetInstancePid] Init.d service %s not found", instanceName))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
cmd := exec.Command(servicePath, "status")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[GetInstancePid] Failed to get init.d service status: %s, output: %s", err, output))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
outputStr := strings.TrimSpace(string(output))
|
||||||
|
if strings.Contains(outputStr, "is running") {
|
||||||
|
if strings.Contains(outputStr, "pid") {
|
||||||
|
parts := strings.Split(outputStr, "pid")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
pidStr := strings.TrimSpace(strings.Split(parts[1], ")")[0])
|
||||||
|
pid, err := strconv.Atoi(pidStr)
|
||||||
|
if err == nil {
|
||||||
|
return pid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pidFile := fmt.Sprintf("/var/run/%s.pid", instanceName)
|
||||||
|
if content, err := os.ReadFile(pidFile); err == nil {
|
||||||
|
pidStr := strings.TrimSpace(string(content))
|
||||||
|
pid, err := strconv.Atoi(pidStr)
|
||||||
|
if err == nil {
|
||||||
|
return pid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
default:
|
||||||
|
postLog.Error(fmt.Sprintf("[GetInstancePid] Unsupported init system: %s", initType))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartWindowsService(instanceName string) error {
|
||||||
|
cmd := exec.Command("sc", "start", instanceName)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start Windows service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartSystemdService(instanceName string) error {
|
||||||
|
cmd := exec.Command("systemctl", "start", instanceName)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start systemd service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartInitDService(instanceName string) error {
|
||||||
|
servicePath := fmt.Sprintf("/etc/init.d/%s", instanceName)
|
||||||
|
cmd := exec.Command(servicePath, "start")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start init.d service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StopWindowsService(instanceName string) error {
|
||||||
|
cmd := exec.Command("sc", "stop", instanceName)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to stop Windows service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StopSystemdService(instanceName string) error {
|
||||||
|
cmd := exec.Command("systemctl", "stop", instanceName)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to stop systemd service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StopInitDService(instanceName string) error {
|
||||||
|
servicePath := fmt.Sprintf("/etc/init.d/%s", instanceName)
|
||||||
|
cmd := exec.Command(servicePath, "stop")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to stop init.d service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestartWindowsService(instanceName string) error {
|
||||||
|
cmd := exec.Command("sc", "restart", instanceName)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to restart Windows service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestartSystemdService(instanceName string) error {
|
||||||
|
cmd := exec.Command("systemctl", "restart", instanceName)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to restart systemd service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestartInitDService(instanceName string) error {
|
||||||
|
servicePath := fmt.Sprintf("/etc/init.d/%s", instanceName)
|
||||||
|
cmd := exec.Command(servicePath, "restart")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to restart init.d service %s: %s, output: %s", instanceName, err, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ func setupRoutes() {
|
|||||||
http.HandleFunc("/frpcAct/instanceMgr/delete", DeleteInstanceHandler)
|
http.HandleFunc("/frpcAct/instanceMgr/delete", DeleteInstanceHandler)
|
||||||
http.HandleFunc("/frpcAct/instanceMgr/modify", ModifyInstanceHandler)
|
http.HandleFunc("/frpcAct/instanceMgr/modify", ModifyInstanceHandler)
|
||||||
http.HandleFunc("/frpcAct/instanceMgr/list", ListInstancesHandler)
|
http.HandleFunc("/frpcAct/instanceMgr/list", ListInstancesHandler)
|
||||||
|
http.HandleFunc("/frpcAct/instanceMgr/start", StartInstanceHandler)
|
||||||
|
http.HandleFunc("/frpcAct/instanceMgr/stop", StopInstanceHandler)
|
||||||
|
http.HandleFunc("/frpcAct/instanceMgr/restart", RestartInstanceHandler)
|
||||||
|
http.HandleFunc("/frpcAct/instanceMgr/status", GetInstanceStatusHandler)
|
||||||
http.HandleFunc("/frpcAct/proxyMgr/create", CreateProxyHandler)
|
http.HandleFunc("/frpcAct/proxyMgr/create", CreateProxyHandler)
|
||||||
http.HandleFunc("/frpcAct/proxyMgr/delete", DeleteProxyHandler)
|
http.HandleFunc("/frpcAct/proxyMgr/delete", DeleteProxyHandler)
|
||||||
http.HandleFunc("/frpcAct/proxyMgr/list", ListProxiesHandler)
|
http.HandleFunc("/frpcAct/proxyMgr/list", ListProxiesHandler)
|
||||||
|
|||||||
Reference in New Issue
Block a user