add manage command

This commit is contained in:
yuzuki999
2023-05-24 10:26:14 +08:00
parent c8429ab428
commit 73342652fe
12 changed files with 487 additions and 106 deletions

109
cmd/action_linux.go Normal file
View File

@@ -0,0 +1,109 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"time"
)
var (
startCommand = cobra.Command{
Use: "start",
Short: "Start V2bX service",
Run: startHandle,
}
stopCommand = cobra.Command{
Use: "stop",
Short: "Stop V2bX service",
Run: stopHandle,
}
restartCommand = cobra.Command{
Use: "restart",
Short: "Restart V2bX service",
Run: restartHandle,
}
logCommand = cobra.Command{
Use: "log",
Short: "Output V2bX log",
Run: func(_ *cobra.Command, _ []string) {
execCommandStd("journalctl", "-u", "V2bX.service", "-e", "--no-pager", "-f")
},
}
)
func init() {
command.AddCommand(&startCommand)
command.AddCommand(&stopCommand)
command.AddCommand(&restartCommand)
command.AddCommand(&logCommand)
}
func startHandle(_ *cobra.Command, _ []string) {
r, err := checkRunning()
if err != nil {
fmt.Println(Err("check status error: ", err))
fmt.Println(Err("V2bX启动失败"))
return
}
if r {
fmt.Println(Ok("V2bX已运行无需再次启动如需重启请选择重启"))
}
_, err = execCommand("systemctl start V2bX.service")
if err != nil {
fmt.Println(Err("exec start cmd error: ", err))
fmt.Println(Err("V2bX启动失败"))
return
}
time.Sleep(time.Second * 3)
r, err = checkRunning()
if err != nil {
fmt.Println(Err("check status error: ", err))
fmt.Println(Err("V2bX启动失败"))
}
if !r {
fmt.Println(Err("V2bX可能启动失败请稍后使用 V2bX log 查看日志信息"))
return
}
fmt.Println(Ok("V2bX 启动成功,请使用 V2bX log 查看运行日志"))
}
func stopHandle(_ *cobra.Command, _ []string) {
_, err := execCommand("systemctl stop V2bX.service")
if err != nil {
fmt.Println(Err("exec stop cmd error: ", err))
fmt.Println(Err("V2bX停止失败"))
return
}
time.Sleep(2 * time.Second)
r, err := checkRunning()
if err != nil {
fmt.Println(Err("check status error:", err))
fmt.Println(Err("V2bX停止失败"))
return
}
if r {
fmt.Println(Err("V2bX停止失败可能是因为停止时间超过了两秒请稍后查看日志信息"))
return
}
fmt.Println(Ok("V2bX 停止成功"))
}
func restartHandle(_ *cobra.Command, _ []string) {
_, err := execCommand("systemctl restart V2bX.service")
if err != nil {
fmt.Println(Err("exec restart cmd error: ", err))
fmt.Println(Err("V2bX重启失败"))
return
}
r, err := checkRunning()
if err != nil {
fmt.Println(Err("check status error: ", err))
fmt.Println(Err("V2bX重启失败"))
return
}
if !r {
fmt.Println(Err("V2bX可能启动失败请稍后使用 V2bX log 查看日志信息"))
return
}
fmt.Println(Ok("V2bX重启成功"))
}

34
cmd/cmd.go Normal file
View File

@@ -0,0 +1,34 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"log"
)
var (
version = "TempVersion" //use ldflags replace
codename = "V2bX"
intro = "A V2board backend based on Xray-core"
)
func showVersion() {
fmt.Printf("%s %s (%s) \n", codename, version, intro)
// Warning
fmt.Println(Warn("This version need V2board version >= 1.7.0."))
fmt.Println(Warn("This version changed config file. Please check config file before running."))
}
var command = &cobra.Command{
Use: "V2bX",
PreRun: func(_ *cobra.Command, _ []string) {
showVersion()
},
}
func Run() {
err := command.Execute()
if err != nil {
log.Println("execute failed, error:", err)
}
}

33
cmd/common.go Normal file
View File

@@ -0,0 +1,33 @@
package cmd
import (
"fmt"
"strings"
)
const (
red = "\033[0;31m"
green = "\033[0;32m"
yellow = "\033[0;33m"
plain = "\033[0m"
)
func checkRunning() (bool, error) {
o, err := execCommand("systemctl status V2bX | grep Active")
if err != nil {
return false, err
}
return strings.Contains(o, "running"), nil
}
func Err(msg ...any) string {
return red + fmt.Sprint(msg...) + plain
}
func Ok(msg ...any) string {
return green + fmt.Sprint(msg...) + plain
}
func Warn(msg ...any) string {
return yellow + fmt.Sprint(msg...) + plain
}

11
cmd/common_test.go Normal file
View File

@@ -0,0 +1,11 @@
package cmd
import "testing"
func TestExecCommand(t *testing.T) {
t.Log(execCommand("echo test"))
}
func Test_printFailed(t *testing.T) {
t.Log(Err("test"))
}

25
cmd/exec.go Normal file
View File

@@ -0,0 +1,25 @@
package cmd
import (
"errors"
"os"
"os/exec"
)
func execCommand(cmd string) (string, error) {
e := exec.Command("bash", "-c", cmd)
out, err := e.CombinedOutput()
if errors.Unwrap(err) == exec.ErrNotFound {
e = exec.Command("sh", "-c", cmd)
out, err = e.CombinedOutput()
}
return string(out), err
}
func execCommandStd(name string, args ...string) {
e := exec.Command(name, args...)
e.Stdout = os.Stdout
e.Stdin = os.Stdin
e.Stderr = os.Stderr
_ = e.Run()
}

59
cmd/install_linux.go Normal file
View File

@@ -0,0 +1,59 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
"strings"
)
var targetVersion string
var (
updateCommand = cobra.Command{
Use: "update",
Short: "Update V2bX version",
Run: func(_ *cobra.Command, _ []string) {
c := execCommandStd("bash",
"<(curl -Ls https://raw.githubusercontents.com/Yuzuki616/V2bX-script/master/install.sh)",
targetVersion)
},
Args: cobra.NoArgs,
}
uninstallCommand = cobra.Command{
Use: "uninstall",
Short: "Uninstall V2bX",
Run: uninstallHandle,
}
)
func init() {
updateCommand.PersistentFlags().StringVar(&targetVersion, "version", "", "update target version")
command.AddCommand(&updateCommand)
command.AddCommand(&uninstallCommand)
}
func uninstallHandle(_ *cobra.Command, _ []string) {
var yes string
fmt.Println(Warn("确定要卸载 V2bX 吗?(Y/n)"))
fmt.Scan(&yes)
if strings.ToLower(yes) != "y" {
fmt.Println("已取消卸载")
}
_, err := execCommand("systemctl stop V2bX&&systemctl disable V2bX")
if err != nil {
fmt.Println(Err("exec cmd error: ", err))
fmt.Println(Err("卸载失败"))
return
}
_ = os.RemoveAll("/etc/systemd/system/V2bX.service")
_ = os.RemoveAll("/etc/V2bX/")
_ = os.RemoveAll("/usr/local/V2bX/")
_, err = execCommand("systemctl daemon-reload&&systemctl reset-failed")
if err != nil {
fmt.Println(Err("exec cmd error: ", err))
fmt.Println(Err("卸载失败"))
return
}
fmt.Println(Ok("卸载成功"))
}

83
cmd/server.go Normal file
View File

@@ -0,0 +1,83 @@
package cmd
import (
"github.com/Yuzuki616/V2bX/conf"
"github.com/Yuzuki616/V2bX/core"
"github.com/Yuzuki616/V2bX/limiter"
"github.com/Yuzuki616/V2bX/node"
"github.com/spf13/cobra"
"log"
"os"
"os/signal"
"runtime"
"syscall"
)
var (
config string
watch bool
)
var serverCommand = cobra.Command{
Use: "server",
Short: "Run V2bX server",
Run: serverHandle,
Args: cobra.NoArgs,
}
func init() {
serverCommand.PersistentFlags().
StringVarP(&config, "config", "c",
"/etc/V2bX/config.yml", "config file path")
serverCommand.PersistentFlags().
BoolVarP(&watch, "watch", "w",
true, "watch file path change")
command.AddCommand(&serverCommand)
}
func serverHandle(_ *cobra.Command, _ []string) {
c := conf.New()
err := c.LoadFromPath(config)
if err != nil {
log.Fatalf("can't unmarshal config file: %s \n", err)
}
limiter.Init()
log.Println("Start V2bX...")
x := core.New(c)
err = x.Start()
if err != nil {
log.Fatalf("Start xray-core error: %s", err)
}
defer x.Close()
nodes := node.New()
err = nodes.Start(c.NodesConfig, x)
if err != nil {
log.Fatalf("Run nodes error: %s", err)
return
}
if watch {
err = c.Watch(config, func() {
nodes.Close()
err = x.Restart(c)
if err != nil {
log.Fatalf("Failed to restart xray-core: %s", err)
}
err = nodes.Start(c.NodesConfig, x)
if err != nil {
log.Fatalf("run nodes error: %s", err)
}
runtime.GC()
})
if err != nil {
log.Fatalf("watch config file error: %s", err)
}
}
// clear memory
runtime.GC()
// wait exit signal
{
osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
<-osSignals
}
}

7
cmd/server_test.go Normal file
View File

@@ -0,0 +1,7 @@
package cmd
import "testing"
func TestRun(t *testing.T) {
Run()
}

38
cmd/synctime.go Normal file
View File

@@ -0,0 +1,38 @@
package cmd
import (
"fmt"
"github.com/beevik/ntp"
"github.com/sagernet/sing-box/common/settings"
"github.com/spf13/cobra"
)
var ntpServer string
var commandSyncTime = &cobra.Command{
Use: "synctime",
Short: "Sync time from ntp server",
Args: cobra.NoArgs,
Run: synctimeHandle,
}
func init() {
commandSyncTime.Flags().StringVar(&ntpServer, "server", "time.apple.com", "ntp server")
command.AddCommand(commandSyncTime)
}
func synctimeHandle(_ *cobra.Command, _ []string) {
t, err := ntp.Time(ntpServer)
if err != nil {
fmt.Println(Err("get time from server error: ", err))
fmt.Println(Err("同步时间失败"))
return
}
err = settings.SetSystemTime(t)
if err != nil {
fmt.Println(Err("set system time error: ", err))
fmt.Println(Err("同步时间失败"))
return
}
fmt.Println(Ok("同步时间成功"))
}