refactor(service): move boot service functions to os.go
Extract service management functions from frpAct.go to new os.go file for better code organization and maintainability. Also update README.md to document supported platforms.
This commit is contained in:
241
frpAct.go
241
frpAct.go
@@ -3,12 +3,10 @@ package main
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"super-frpc/postLog"
|
||||
@@ -679,245 +677,6 @@ func addFrpcProxy(info FrpcProxyInfo) string {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func GetConfigDir() (string, error) {
|
||||
config, err := GetConfig()
|
||||
if err != nil {
|
||||
postLog.Error(fmt.Sprintf("[GetConfigDir] Failed to get config: %v", err))
|
||||
return "", err
|
||||
}
|
||||
return config.InstancePath, nil
|
||||
}
|
||||
|
||||
func GetFrpcPath() (string, error) {
|
||||
config, err := GetConfig()
|
||||
if err != nil {
|
||||
postLog.Error(fmt.Sprintf("[GetFrpcPath] Failed to get config: %v", err))
|
||||
return "", err
|
||||
}
|
||||
return config.FrpcPath, nil
|
||||
}
|
||||
|
||||
func detectInitSystem() string {
|
||||
if _, err := os.Stat("/run/systemd/system"); err == nil {
|
||||
return "systemd"
|
||||
}
|
||||
if _, err := os.Stat("/etc/init.d"); err == nil {
|
||||
return "init.d"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func createBootService(username, instanceName, configPath, runUser string) error {
|
||||
initSystem := detectInitSystem()
|
||||
|
||||
switch initSystem {
|
||||
case "systemd":
|
||||
return createSystemdService(username, instanceName, configPath, runUser)
|
||||
case "init.d":
|
||||
return createInitDService(username, instanceName, configPath, runUser)
|
||||
default:
|
||||
return errors.New("unsupported init system")
|
||||
}
|
||||
}
|
||||
|
||||
func createSystemdService(username, instanceName, configPath, runUser string) error {
|
||||
frpcPath, err := GetFrpcPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
||||
serviceContent := fmt.Sprintf(`[Unit]
|
||||
Description=superfrpc_%s_%s
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=%s -c %s
|
||||
User=%s
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`, username, instanceName, frpcPath, configPath, runUser)
|
||||
|
||||
servicePath := filepath.Join("/etc/systemd/system", serviceName+".service")
|
||||
if err := os.WriteFile(servicePath, []byte(serviceContent), 0644); err != nil {
|
||||
return fmt.Errorf("failed to create systemd service file: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command("systemctl", "enable", serviceName)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
os.Remove(servicePath)
|
||||
return fmt.Errorf("failed to enable service: %s, output: %s", err, output)
|
||||
}
|
||||
|
||||
cmd = exec.Command("systemctl", "daemon-reload")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to reload daemon: %s, output: %s", err, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createInitDService(username, instanceName, configPath, runUser string) error {
|
||||
frpcPath, err := GetFrpcPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
||||
|
||||
var serviceContent string
|
||||
runUserArg := ""
|
||||
if runUser != "" && runUser != "root" {
|
||||
runUserArg = runUser
|
||||
serviceContent = fmt.Sprintf(`#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: %s
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop: $network $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Description: superfrpc %s %s
|
||||
### END INIT INFO
|
||||
|
||||
NAME="%s"
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=%s
|
||||
DAEMON_ARGS="-c %s"
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
USER=%s
|
||||
|
||||
[ -x "$DAEMON" ] || exit 0
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $NAME: "
|
||||
start-stop-daemon -S -c $USER -b -m -p /var/run/$NAME.pid --start --exec $DAEMON -- $DAEMON_ARGS
|
||||
echo "$NAME."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $NAME: "
|
||||
start-stop-daemon -K -p /var/run/$NAME.pid
|
||||
rm -f /var/run/$NAME.pid
|
||||
echo "$NAME."
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
status)
|
||||
if [ -f /var/run/$NAME.pid ]; then
|
||||
echo "$NAME is running (pid $(cat /var/run/$NAME.pid))"
|
||||
else
|
||||
echo "$NAME is not running"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
`, serviceName, username, instanceName, serviceName, frpcPath, configPath, runUserArg)
|
||||
} else {
|
||||
serviceContent = fmt.Sprintf(`#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: %s
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop: $network $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Description: superfrpc %s %s
|
||||
### END INIT INFO
|
||||
|
||||
NAME="%s"
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=%s
|
||||
DAEMON_ARGS="-c %s"
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
[ -x "$DAEMON" ] || exit 0
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $NAME: "
|
||||
start-stop-daemon -S -b -m -p /var/run/$NAME.pid --start --exec $DAEMON -- $DAEMON_ARGS
|
||||
echo "$NAME."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $NAME: "
|
||||
start-stop-daemon -K -p /var/run/$NAME.pid
|
||||
rm -f /var/run/$NAME.pid
|
||||
echo "$NAME."
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
status)
|
||||
if [ -f /var/run/$NAME.pid ]; then
|
||||
echo "$NAME is running (pid $(cat /var/run/$NAME.pid))"
|
||||
else
|
||||
echo "$NAME is not running"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
`, serviceName, username, instanceName, serviceName, frpcPath, configPath)
|
||||
}
|
||||
|
||||
servicePath := filepath.Join("/etc/init.d", serviceName)
|
||||
if err := os.WriteFile(servicePath, []byte(serviceContent), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create init.d service file: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command("/etc/init.d", serviceName, "enable")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
os.Remove(servicePath)
|
||||
return fmt.Errorf("failed to enable service: %s, output: %s", err, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeBootService(username, instanceName string) error {
|
||||
initSystem := detectInitSystem()
|
||||
|
||||
serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName)
|
||||
|
||||
switch initSystem {
|
||||
case "systemd":
|
||||
cmd := exec.Command("systemctl", "disable", serviceName)
|
||||
cmd.CombinedOutput()
|
||||
|
||||
servicePath := filepath.Join("/etc/systemd/system", serviceName+".service")
|
||||
os.Remove(servicePath)
|
||||
|
||||
cmd = exec.Command("systemctl", "daemon-reload")
|
||||
cmd.CombinedOutput()
|
||||
|
||||
case "init.d":
|
||||
cmd := exec.Command("/etc/init.d", serviceName, "disable")
|
||||
cmd.CombinedOutput()
|
||||
|
||||
servicePath := filepath.Join("/etc/init.d", serviceName)
|
||||
os.Remove(servicePath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetUserInstances(userID int) ([]FrpcInstance, error) {
|
||||
rows, err := frpcDB.Query(`
|
||||
SELECT id, userID, name, serverAddr, serverPort, auth_method, bootAtStart, runUser, configPath, createdAt
|
||||
|
||||
Reference in New Issue
Block a user