mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-23 19:03:11 +03:00
Add daemon support
This commit is contained in:
165
experimental/daemon/daemon.go
Executable file
165
experimental/daemon/daemon.go
Executable file
@@ -0,0 +1,165 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
|
||||
"github.com/kardianos/service"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultDaemonName = "sing-box-daemon"
|
||||
DefaultDaemonPort = 9091
|
||||
)
|
||||
|
||||
var defaultDaemonOptions = Options{
|
||||
Listen: "127.0.0.1",
|
||||
ListenPort: DefaultDaemonPort,
|
||||
WorkingDirectory: workingDirectory(),
|
||||
}
|
||||
|
||||
func workingDirectory() string {
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
return filepath.Join("/usr/local/lib", DefaultDaemonName)
|
||||
default:
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
return filepath.Join(configDir, DefaultDaemonName)
|
||||
} else {
|
||||
return DefaultDaemonName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const systemdScript = `[Unit]
|
||||
Description=sing-box service
|
||||
Documentation=https://sing-box.sagernet.org
|
||||
After=network.target nss-lookup.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
||||
WorkingDirectory={{.WorkingDirectory|cmdEscape}}
|
||||
Restart=on-failure
|
||||
RestartSec=10s
|
||||
LimitNOFILE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target`
|
||||
|
||||
type Daemon struct {
|
||||
service service.Service
|
||||
workingDirectory string
|
||||
executable string
|
||||
}
|
||||
|
||||
func New() (*Daemon, error) {
|
||||
daemonInterface := NewInterface(defaultDaemonOptions)
|
||||
executable := filepath.Join(defaultDaemonOptions.WorkingDirectory, "sing-box")
|
||||
if C.IsWindows {
|
||||
executable += ".exe"
|
||||
}
|
||||
daemonService, err := service.New(daemonInterface, &service.Config{
|
||||
Name: DefaultDaemonName,
|
||||
Description: "The universal proxy platform.",
|
||||
Arguments: []string{"daemon", "run"},
|
||||
Executable: executable,
|
||||
Option: service.KeyValue{
|
||||
"SystemdScript": systemdScript,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.New(strings.ToLower(err.Error()))
|
||||
}
|
||||
return &Daemon{
|
||||
service: daemonService,
|
||||
workingDirectory: defaultDaemonOptions.WorkingDirectory,
|
||||
executable: executable,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Daemon) Install() error {
|
||||
_, err := d.service.Status()
|
||||
if err != service.ErrNotInstalled {
|
||||
d.service.Stop()
|
||||
err = d.service.Uninstall()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
executablePath, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !rw.FileExists(d.workingDirectory) {
|
||||
err = os.MkdirAll(d.workingDirectory, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
outputFile, err := os.OpenFile(d.executable, os.O_CREATE|os.O_WRONLY, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inputFile, err := os.Open(executablePath)
|
||||
if err != nil {
|
||||
outputFile.Close()
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(outputFile, inputFile)
|
||||
inputFile.Close()
|
||||
outputFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = d.service.Install()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.service.Start()
|
||||
}
|
||||
|
||||
func (d *Daemon) Uninstall() error {
|
||||
_, err := d.service.Status()
|
||||
if err != service.ErrNotInstalled {
|
||||
d.service.Stop()
|
||||
err = d.service.Uninstall()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return os.RemoveAll(d.workingDirectory)
|
||||
}
|
||||
|
||||
func (d *Daemon) Run() error {
|
||||
d.chdir()
|
||||
return d.service.Run()
|
||||
}
|
||||
|
||||
func (d *Daemon) chdir() error {
|
||||
executable, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chdir(filepath.Dir(executable))
|
||||
}
|
||||
|
||||
func (d *Daemon) Start() error {
|
||||
return d.service.Start()
|
||||
}
|
||||
|
||||
func (d *Daemon) Stop() error {
|
||||
return d.service.Stop()
|
||||
}
|
||||
|
||||
func (d *Daemon) Restart() error {
|
||||
return d.service.Restart()
|
||||
}
|
||||
Reference in New Issue
Block a user