Refactor main to use Cobra command line framework and package restructure

Reorganized the Go package structure, moving the main package to 'cmd'. Upgraded the flag library to Cobra for better management of CLI commands. This included moving the X25519 key generation from a flag to its own standalone Cobra command, which improves user interaction and code modularity. This structural change will benefit future additions and code maintainability.
This commit is contained in:
Senis John 2023-10-14 10:50:50 +08:00
parent edf02307ad
commit b1bfd04895
No known key found for this signature in database
GPG Key ID: 845E9E4727C3E1A4
21 changed files with 158 additions and 103 deletions

View File

@ -122,12 +122,12 @@ jobs:
- name: Build XrayR
run: |
mkdir -p build_assets
go build -v -o build_assets/XrayR -trimpath -ldflags "-s -w -buildid=" ./main
go build -v -o build_assets/XrayR -trimpath -ldflags "-s -w -buildid="
- name: Build Mips softfloat XrayR
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
run: |
GOMIPS=softfloat go build -v -o build_assets/XrayR_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
GOMIPS=softfloat go build -v -o build_assets/XrayR_softfloat -trimpath -ldflags "-s -w -buildid="
- name: Rename Windows XrayR
if: matrix.goos == 'windows'
run: |
@ -143,12 +143,12 @@ jobs:
command: |
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
cp ${GITHUB_WORKSPACE}/main/dns.json ./build_assets/dns.json
cp ${GITHUB_WORKSPACE}/main/route.json ./build_assets/route.json
cp ${GITHUB_WORKSPACE}/main/custom_outbound.json ./build_assets/custom_outbound.json
cp ${GITHUB_WORKSPACE}/main/custom_inbound.json ./build_assets/custom_inbound.json
cp ${GITHUB_WORKSPACE}/main/rulelist ./build_assets/rulelist
cp ${GITHUB_WORKSPACE}/main/config.yml.example ./build_assets/config.yml
cp ${GITHUB_WORKSPACE}/release/config/dns.json ./build_assets/dns.json
cp ${GITHUB_WORKSPACE}/release/config/route.json ./build_assets/route.json
cp ${GITHUB_WORKSPACE}/release/config/custom_outbound.json ./build_assets/custom_outbound.json
cp ${GITHUB_WORKSPACE}/release/config/custom_inbound.json ./build_assets/custom_inbound.json
cp ${GITHUB_WORKSPACE}/release/config/rulelist ./build_assets/rulelist
cp ${GITHUB_WORKSPACE}/release/config/config.yml.example ./build_assets/config.yml
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do

38
.gitignore vendored
View File

@ -1,18 +1,20 @@
main/main
main/XrayR
main/XrayR*
main/mytest
main/access.logo
main/error.log
api/chooseparser.go.bak
common/Inboundbuilder/.lego/
common/legocmd/.lego/
.vscode/launch.json
main/.lego
main/cert
main/config.yml
./vscode
.idea/*
.DS_Store
*.bak
go.work*
.idea
*.iml
out
gen
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
go.work
main
XrayR
XrayR*
access.log
error.log
.lego
cert
config.yml

View File

@ -4,7 +4,7 @@ WORKDIR /app
COPY . .
ENV CGO_ENABLED=0
RUN go mod download
RUN go build -v -o XrayR -trimpath -ldflags "-s -w -buildid=" ./main
RUN go build -v -o XrayR -trimpath -ldflags "-s -w -buildid="
# Release
FROM alpine

View File

@ -1,7 +1,6 @@
package main
package cmd
import (
"flag"
"fmt"
"log"
"os"
@ -13,37 +12,37 @@ import (
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/XrayR-project/XrayR/common"
"github.com/XrayR-project/XrayR/panel"
)
var (
configFile = flag.String("config", "", "Config file for XrayR.")
printVersion = flag.Bool("version", false, "show version")
x25519 = flag.Bool("x25519", false, "Generate key pair for x25519 key exchange")
cfgFile string
rootCmd = &cobra.Command{
Use: "XrayR",
Run: func(cmd *cobra.Command, args []string) {
if err := run(); err != nil {
log.Fatal(err)
}
},
}
)
var (
version = "0.9.1"
codename = "XrayR"
intro = "A Xray backend that supports many panels"
)
func showVersion() {
fmt.Printf("%s %s (%s) \n", codename, version, intro)
func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "Config file for XrayR.")
}
func getConfig() *viper.Viper {
config := viper.New()
// Set custom path and name
if *configFile != "" {
configName := path.Base(*configFile)
configFileExt := path.Ext(*configFile)
if cfgFile != "" {
configName := path.Base(cfgFile)
configFileExt := path.Ext(cfgFile)
configNameOnly := strings.TrimSuffix(configName, configFileExt)
configPath := path.Dir(*configFile)
configPath := path.Dir(cfgFile)
config.SetConfigName(configNameOnly)
config.SetConfigType(strings.TrimPrefix(configFileExt, "."))
config.AddConfigPath(configPath)
@ -67,21 +66,13 @@ func getConfig() *viper.Viper {
return config
}
func main() {
flag.Parse()
func run() error {
showVersion()
if *printVersion {
return
}
if *x25519 {
common.X25519()
return
}
config := getConfig()
panelConfig := &panel.Config{}
if err := config.Unmarshal(panelConfig); err != nil {
log.Panicf("Parse config file %v failed: %s \n", configFile, err)
return fmt.Errorf("Parse config file %v failed: %s \n", cfgFile, err)
}
p := panel.New(panelConfig)
lastTime := time.Now()
@ -94,7 +85,7 @@ func main() {
// Delete old instance and trigger GC
runtime.GC()
if err := config.Unmarshal(panelConfig); err != nil {
log.Panicf("Parse config file %v failed: %s \n", configFile, err)
log.Panicf("Parse config file %v failed: %s \n", cfgFile, err)
}
p.Start()
lastTime = time.Now()
@ -106,9 +97,13 @@ func main() {
// Explicitly triggering GC to remove garbage from config loading.
runtime.GC()
// Running backend
{
osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM)
<-osSignals
}
osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, os.Kill, syscall.SIGTERM)
<-osSignals
return nil
}
func Execute() error {
return rootCmd.Execute()
}

27
cmd/version.go Normal file
View File

@ -0,0 +1,27 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
version = "0.9.1"
codename = "XrayR"
intro = "A Xray backend that supports many panels"
)
func init() {
rootCmd.AddCommand(&cobra.Command{
Use: "version",
Short: "Print current version of XrayR",
Run: func(cmd *cobra.Command, args []string) {
showVersion()
},
})
}
func showVersion() {
fmt.Printf("%s %s (%s) \n", codename, version, intro)
}

48
cmd/x25519.go Normal file
View File

@ -0,0 +1,48 @@
package cmd
import (
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/spf13/cobra"
"golang.org/x/crypto/curve25519"
)
func init() {
rootCmd.AddCommand(&cobra.Command{
Use: "x25519",
Short: "Generate key pair for x25519 key exchange",
Run: func(cmd *cobra.Command, args []string) {
if err := x25519(); err != nil {
fmt.Println(err)
}
},
})
}
func x25519() error {
var publicKey []byte
privateKey := make([]byte, curve25519.ScalarSize)
if _, err := rand.Read(privateKey); err != nil {
return err
}
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
privateKey[0] &= 248
privateKey[31] &= 127
privateKey[31] |= 64
publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint)
if err != nil {
return err
}
output := fmt.Sprintf("Private key: %v\nPublic key: %v",
base64.RawURLEncoding.EncodeToString(privateKey),
base64.RawURLEncoding.EncodeToString(publicKey))
fmt.Println(output)
return nil
}

View File

@ -1,36 +1,2 @@
// Package common contains common utilities that are shared among other packages.
package common
import (
"crypto/rand"
"encoding/base64"
"fmt"
"golang.org/x/crypto/curve25519"
)
func X25519() {
var publicKey []byte
privateKey := make([]byte, curve25519.ScalarSize)
if _, err := rand.Read(privateKey); err != nil {
fmt.Println(err)
return
}
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
privateKey[0] &= 248
privateKey[31] &= 127
privateKey[31] |= 64
publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint)
if err != nil {
fmt.Println(err)
return
}
output := fmt.Sprintf("Private key: %v\nPublic key: %v",
base64.RawURLEncoding.EncodeToString(privateKey),
base64.RawURLEncoding.EncodeToString(publicKey))
fmt.Println(output)
}

2
go.mod
View File

@ -21,6 +21,7 @@ require (
github.com/sagernet/sing v0.2.13
github.com/sagernet/sing-shadowsocks v0.2.5
github.com/shirou/gopsutil/v3 v3.23.9
github.com/spf13/cobra v1.1.1
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
github.com/xtls/xray-core v1.8.4
@ -112,6 +113,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect

2
go.sum
View File

@ -468,6 +468,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df h1:MZf03xP9WdakyXhOWuAD5uPK3wHh96wCsqe3hCMKh8E=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768PWHfGFm0HH8FnbtU=
github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
@ -834,6 +835,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=

13
main.go Normal file
View File

@ -0,0 +1,13 @@
package main
import (
"log"
"github.com/XrayR-project/XrayR/cmd"
)
func main() {
if err := cmd.Execute(); err != nil {
log.Fatal(err)
}
}

View File

@ -23,7 +23,7 @@ import (
"github.com/XrayR-project/XrayR/api/proxypanel"
"github.com/XrayR-project/XrayR/api/sspanel"
"github.com/XrayR-project/XrayR/api/v2raysocks"
_ "github.com/XrayR-project/XrayR/main/distro/all"
_ "github.com/XrayR-project/XrayR/cmd/distro/all"
"github.com/XrayR-project/XrayR/service"
"github.com/XrayR-project/XrayR/service/controller"
)

View File

@ -56,11 +56,11 @@ Nodes:
EnableREALITY: false # Enable REALITY
REALITYConfigs:
Show: true # Show REALITY debug
Dest: www.smzdm.com:443 # Required, Same as fallback
Dest: www.amazon.com:443 # Required, Same as fallback
ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable
ServerNames: # Required, list of available serverNames for the client, * wildcard is not supported at the moment.
- www.smzdm.com
PrivateKey: YOUR_PRIVATE_KEY # Required, execute './XrayR -x25519' to generate.
- www.amazon.com
PrivateKey: YOUR_PRIVATE_KEY # Required, execute './XrayR x25519' to generate.
MinClientVer: # Optional, minimum version of Xray client, format is x.y.z.
MaxClientVer: # Optional, maximum version of Xray client, format is x.y.z.
MaxTimeDiff: 0 # Optional, maximum allowed time difference, unit is in milliseconds.
@ -119,11 +119,11 @@ Nodes:
# EnableREALITY: true # Enable REALITY
# REALITYConfigs:
# Show: true # Show REALITY debug
# Dest: www.smzdm.com:443 # Required, Same as fallback
# Dest: www.amazon.com:443 # Required, Same as fallback
# ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable
# ServerNames: # Required, list of available serverNames for the client, * wildcard is not supported at the moment.
# - www.smzdm.com
# PrivateKey: YOUR_PRIVATE_KEY # Required, execute './xray x25519' to generate.
# - www.amazon.com
# PrivateKey: YOUR_PRIVATE_KEY # Required, execute './XrayR x25519' to generate.
# MinClientVer: # Optional, minimum version of Xray client, format is x.y.z.
# MaxClientVer: # Optional, maximum version of Xray client, format is x.y.z.
# MaxTimeDiff: 0 # Optional, maximum allowed time difference, unit is in milliseconds.

View File

@ -13,8 +13,8 @@ import (
"github.com/XrayR-project/XrayR/api"
"github.com/XrayR-project/XrayR/api/sspanel"
_ "github.com/XrayR-project/XrayR/cmd/distro/all"
"github.com/XrayR-project/XrayR/common/mylego"
_ "github.com/XrayR-project/XrayR/main/distro/all"
. "github.com/XrayR-project/XrayR/service/controller"
)