diff --git a/README_RU.md b/README_RU.md
index d86840b8..fde21707 100644
--- a/README_RU.md
+++ b/README_RU.md
@@ -1,4 +1,4 @@
-# Xray Checker
+# Singbox Checker
[](https://github.com/kutovoys/xray-checker/releases/latest)
[](https://github.com/kutovoys/xray-checker/actions/workflows/build-publish.yml)
@@ -8,7 +8,7 @@
[](https://github.com/kutovoys/xray-checker/blob/main/README_RU.md)
[](https://github.com/kutovoys/xray-checker/blob/main/README.md)
-Xray Checker - ΡΡΠΎ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ Π΄Π»Ρ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π° Π΄ΠΎΡΡΡΠΏΠ½ΠΎΡΡΠΈ ΠΏΡΠΎΠΊΡΠΈ-ΡΠ΅ΡΠ²Π΅ΡΠΎΠ² Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΎΠΉ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»ΠΎΠ² VLESS, VMess, Trojan ΠΈ Shadowsocks. ΠΠ½ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΅ΡΡΠΈΡΡΠ΅Ρ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ ΡΠ΅ΡΠ΅Π· Xray Core ΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠ΅ΡΡΠΈΠΊΠΈ Π΄Π»Ρ Prometheus, Π° ΡΠ°ΠΊΠΆΠ΅ API-ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΡ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ ΡΠΈΡΡΠ΅ΠΌΠ°ΠΌΠΈ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π°.
+Singbox Checker - ΡΡΠΎ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ Π΄Π»Ρ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π° Π΄ΠΎΡΡΡΠΏΠ½ΠΎΡΡΠΈ ΠΏΡΠΎΠΊΡΠΈ-ΡΠ΅ΡΠ²Π΅ΡΠΎΠ² Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΎΠΉ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»ΠΎΠ² VLESS, VMess, Trojan ΠΈ Shadowsocks. ΠΠ½ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ΅ΡΡΠΈΡΡΠ΅Ρ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ ΡΠ΅ΡΠ΅Π· Singbox ΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠ΅ΡΡΠΈΠΊΠΈ Π΄Π»Ρ Prometheus, Π° ΡΠ°ΠΊΠΆΠ΅ API-ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΡ Π΄Π»Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΠΈ Ρ ΡΠΈΡΡΠ΅ΠΌΠ°ΠΌΠΈ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π°.

@@ -68,7 +68,7 @@ services:
## π€ Π£ΡΠ°ΡΡΠΈΠ΅ Π² ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅
-ΠΡ ΡΠ°Π΄Ρ Π»ΡΠ±ΠΎΠΌΡ Π²ΠΊΠ»Π°Π΄Ρ Π² ΡΠ°Π·Π²ΠΈΡΠΈΠ΅ Xray Checker! ΠΡΠ»ΠΈ Π²Ρ Ρ
ΠΎΡΠΈΡΠ΅ ΠΏΠΎΠΌΠΎΡΡ:
+ΠΡ ΡΠ°Π΄Ρ Π»ΡΠ±ΠΎΠΌΡ Π²ΠΊΠ»Π°Π΄Ρ Π² ΡΠ°Π·Π²ΠΈΡΠΈΠ΅ Singbox Checker! ΠΡΠ»ΠΈ Π²Ρ Ρ
ΠΎΡΠΈΡΠ΅ ΠΏΠΎΠΌΠΎΡΡ:
1. Π‘Π΄Π΅Π»Π°ΠΉΡΠ΅ ΡΠΎΡΠΊ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΡ
2. Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ Π²Π΅ΡΠΊΡ Π΄Π»Ρ Π²Π°ΡΠΈΡ
ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
@@ -78,7 +78,7 @@ services:
ΠΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ ΠΎ ΡΠΎΠΌ, ΠΊΠ°ΠΊ Π²Π½Π΅ΡΡΠΈ ΡΠ²ΠΎΠΉ Π²ΠΊΠ»Π°Π΄, ΡΠΈΡΠ°ΠΉΡΠ΅ Π² [ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²Π΅ Π΄Π»Ρ ΠΊΠΎΠ½ΡΡΠΈΠ±ΡΡΡΠΎΡΠΎΠ²](https://xray-checker.kutovoy.dev/ru/contributing/development-guide).
-Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ Π²ΡΠ΅ΠΌ ΠΊΠΎΠ½ΡΡΠΈΠ±ΡΡΡΠΎΡΠ°ΠΌ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎΠΌΠΎΠ³Π»ΠΈ ΡΠ»ΡΡΡΠΈΡΡ Xray Checker:
+Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ Π²ΡΠ΅ΠΌ ΠΊΠΎΠ½ΡΡΠΈΠ±ΡΡΡΠΎΡΠ°ΠΌ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎΠΌΠΎΠ³Π»ΠΈ ΡΠ»ΡΡΡΠΈΡΡ Singbox Checker:
diff --git a/config/config.go b/config/config.go
index 4ac1d247..a5acb245 100644
--- a/config/config.go
+++ b/config/config.go
@@ -10,8 +10,8 @@ var CLIConfig CLI
func Parse(version string) {
ctx := kong.Parse(&CLIConfig,
- kong.Name("xray-checker"),
- kong.Description("Xray Checker: A Prometheus exporter for monitoring Xray proxies"),
+ kong.Name("singbox-checker"),
+ kong.Description("Singbox Checker: A Prometheus exporter for monitoring Singbox proxies"),
kong.Vars{
"version": version,
},
@@ -35,9 +35,9 @@ type CLI struct {
SimulateLatency bool `name:"simulate-latency" help:"Whether to add latency to the response" default:"true" env:"SIMULATE_LATENCY"`
} `embed:"" prefix:""`
- Xray struct {
- StartPort int `name:"xray-start-port" help:"Start port for proxy configuration" default:"10000" env:"XRAY_START_PORT"`
- LogLevel string `name:"xray-log-level" help:"Xray log level (debug|info|warning|error|none)" default:"none" env:"XRAY_LOG_LEVEL"`
+ Singbox struct {
+ StartPort int `name:"singbox-start-port" help:"Start port for proxy configuration" default:"10000" env:"SINGBOX_START_PORT"`
+ LogLevel string `name:"singbox-log-level" help:"Singbox log level (debug|info|warning|error|none)" default:"none" env:"SINGBOX_LOG_LEVEL"`
} `embed:"" prefix:""`
Metrics struct {
@@ -48,7 +48,7 @@ type CLI struct {
Password string `name:"metrics-password" help:"Password for metrics if protected by basic auth" default:"MetricsVeryHardPassword" env:"METRICS_PASSWORD"`
Instance string `name:"metrics-instance" help:"Instance label for metrics" default:"" env:"METRICS_INSTANCE"`
PushURL string `name:"metrics-push-url" help:"Prometheus pushgateway URL (e.g. https://user:pass@host:port)" default:"" env:"METRICS_PUSH_URL"`
- BasePath string `name:"metrics-base-path" help:"URL path to metrics (e.g. /xray/metrics)" default:"" env:"METRICS_BASE_PATH"`
+ BasePath string `name:"metrics-base-path" help:"URL path to metrics (e.g. /singbox/metrics)" default:"" env:"METRICS_BASE_PATH"`
} `embed:"" prefix:""`
Version VersionFlag `name:"version" help:"Print version information and quit"`
@@ -60,9 +60,9 @@ type VersionFlag string
func (v VersionFlag) Decode(ctx *kong.DecodeContext) error { return nil }
func (v VersionFlag) IsBool() bool { return true }
func (v VersionFlag) BeforeApply(app *kong.Kong, vars kong.Vars) error {
- fmt.Println("Xray Checker: A Prometheus exporter for monitoring Xray proxies")
+ fmt.Println("Singbox Checker: A Prometheus exporter for monitoring Singbox proxies")
fmt.Printf("Version:\t %s\n", vars["version"])
- fmt.Printf("GitHub: https://github.com/kutovoys/xray-checker\n")
+ fmt.Printf("GitHub: https://github.com/kutovoys/singbox-checker\n")
app.Exit(0)
return nil
}
diff --git a/main.go b/main.go
index 48311523..2e8d5b72 100644
--- a/main.go
+++ b/main.go
@@ -9,9 +9,9 @@ import (
"xray-checker/config"
"xray-checker/metrics"
"xray-checker/runner"
+ singbox "xray-checker/singbox"
"xray-checker/subscription"
"xray-checker/web"
- "xray-checker/xray"
"github.com/go-co-op/gocron"
"github.com/prometheus/client_golang/prometheus"
@@ -24,22 +24,22 @@ var (
func main() {
config.Parse(version)
- log.Printf("Xray Checker %s starting...\n", version)
+ log.Printf("Singbox Checker %s starting...\n", version)
- configFile := "xray_config.json"
+ configFile := "singbox_config.json"
proxyConfigs, err := subscription.InitializeConfiguration(configFile)
if err != nil {
log.Fatalf("Error initializing configuration: %v", err)
}
- xrayRunner := runner.NewXrayRunner(configFile)
- if err := xrayRunner.Start(); err != nil {
- log.Fatalf("Error starting Xray: %v", err)
+ singboxRunner := runner.NewSingboxRunner(configFile)
+ if err := singboxRunner.Start(); err != nil {
+ log.Fatalf("Error starting Singbox: %v", err)
}
defer func() {
- if err := xrayRunner.Stop(); err != nil {
- log.Printf("Error stopping Xray: %v", err)
+ if err := singboxRunner.Stop(); err != nil {
+ log.Printf("Error stopping Singbox: %v", err)
}
}()
@@ -51,7 +51,7 @@ func main() {
proxyChecker := checker.NewProxyChecker(
*proxyConfigs,
- config.CLIConfig.Xray.StartPort,
+ config.CLIConfig.Singbox.StartPort,
config.CLIConfig.Proxy.IpCheckUrl,
config.CLIConfig.Proxy.Timeout,
config.CLIConfig.Proxy.StatusCheckUrl,
@@ -92,8 +92,8 @@ func main() {
newConfigs, err := subscription.ReadFromSource(config.CLIConfig.Subscription.URL)
if err != nil {
log.Printf("Error checking subscription updates: %v", err)
- } else if !xray.IsConfigsEqual(*proxyConfigs, newConfigs) {
- if err := xray.UpdateConfiguration(newConfigs, proxyConfigs, xrayRunner, proxyChecker); err != nil {
+ } else if !singbox.IsConfigsEqual(*proxyConfigs, newConfigs) {
+ if err := singbox.UpdateConfiguration(newConfigs, proxyConfigs, singboxRunner, proxyChecker); err != nil {
log.Printf("Error updating configuration: %v", err)
}
}
@@ -120,7 +120,7 @@ func main() {
protectedHandler.Handle("/", web.IndexHandler(version, proxyChecker))
protectedHandler.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
- web.RegisterConfigEndpoints(*proxyConfigs, proxyChecker, config.CLIConfig.Xray.StartPort)
+ web.RegisterConfigEndpoints(*proxyConfigs, proxyChecker, config.CLIConfig.Singbox.StartPort)
protectedHandler.Handle("/config/", web.ConfigStatusHandler(proxyChecker))
if config.CLIConfig.Metrics.Protected {
diff --git a/runner/singbox.go b/runner/singbox.go
new file mode 100644
index 00000000..79333e1e
--- /dev/null
+++ b/runner/singbox.go
@@ -0,0 +1,51 @@
+package runner
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+)
+
+type SingboxRunner struct {
+ cmd *exec.Cmd
+ configFile string
+}
+
+func NewSingboxRunner(configFile string) *SingboxRunner {
+ return &SingboxRunner{configFile: configFile}
+}
+
+func (r *SingboxRunner) Start() error {
+ r.cmd = exec.Command("sing-box", "run", "-c", r.configFile)
+ r.cmd.Stdout = os.Stdout
+ r.cmd.Stderr = os.Stderr
+
+ if err := r.cmd.Start(); err != nil {
+ return fmt.Errorf("error starting sing-box: %v", err)
+ }
+
+ go func() {
+ _ = r.cmd.Wait()
+ r.cmd = nil
+ }()
+
+ log.Println("sing-box started successfully")
+ return nil
+}
+
+func (r *SingboxRunner) Stop() error {
+ if r.cmd != nil && r.cmd.Process != nil {
+ if err := r.cmd.Process.Signal(os.Interrupt); err != nil {
+ return fmt.Errorf("error stopping sing-box: %v", err)
+ }
+ _, _ = r.cmd.Process.Wait()
+ r.cmd = nil
+ log.Println("sing-box stopped successfully")
+ }
+ return nil
+}
+
+func (r *SingboxRunner) IsRunning() bool {
+ return r.cmd != nil && r.cmd.ProcessState == nil
+}
diff --git a/xray/xray.go b/singbox/singbox.go
similarity index 74%
rename from xray/xray.go
rename to singbox/singbox.go
index 0b30b296..ab4027e3 100644
--- a/xray/xray.go
+++ b/singbox/singbox.go
@@ -1,4 +1,4 @@
-package xray
+package singbox
import (
"bytes"
@@ -15,20 +15,20 @@ import (
)
type TemplateData struct {
- Proxies []*models.ProxyConfig
- StartPort int
- XrayLogLevel string
+ Proxies []*models.ProxyConfig
+ StartPort int
+ LogLevel string
}
-func generateConfig(proxies []*models.ProxyConfig, startPort int, xrayLogLevel string) ([]byte, error) {
+func generateConfig(proxies []*models.ProxyConfig, startPort int, logLevel string) ([]byte, error) {
if len(proxies) == 0 {
return nil, fmt.Errorf("no valid proxy configurations found")
}
data := TemplateData{
- Proxies: proxies,
- StartPort: startPort,
- XrayLogLevel: xrayLogLevel,
+ Proxies: proxies,
+ StartPort: startPort,
+ LogLevel: logLevel,
}
funcMap := template.FuncMap{
@@ -42,9 +42,9 @@ func generateConfig(proxies []*models.ProxyConfig, startPort int, xrayLogLevel s
},
}
- tmpl, err := template.New("xray.json.tmpl").
+ tmpl, err := template.New("singbox.json.tmpl").
Funcs(funcMap).
- ParseFS(templates, "templates/xray.json.tmpl")
+ ParseFS(templates, "templates/singbox.json.tmpl")
if err != nil {
return nil, fmt.Errorf("error parsing template: %v", err)
}
@@ -80,8 +80,8 @@ func PrepareProxyConfigs(proxies []*models.ProxyConfig) {
}
}
-func GenerateAndSaveConfig(proxies []*models.ProxyConfig, startPort int, filename string, xrayLogLevel string) error {
- configBytes, err := generateConfig(proxies, startPort, xrayLogLevel)
+func GenerateAndSaveConfig(proxies []*models.ProxyConfig, startPort int, filename string, logLevel string) error {
+ configBytes, err := generateConfig(proxies, startPort, logLevel)
if err != nil {
return fmt.Errorf("error generating config: %v", err)
}
@@ -94,30 +94,30 @@ func GenerateAndSaveConfig(proxies []*models.ProxyConfig, startPort int, filenam
}
func UpdateConfiguration(newConfigs []*models.ProxyConfig, currentConfigs *[]*models.ProxyConfig,
- xrayRunner *runner.XrayRunner, proxyChecker *checker.ProxyChecker) error {
+ singboxRunner *runner.SingboxRunner, proxyChecker *checker.ProxyChecker) error {
log.Println("Found changes in subscription, updating configuration...")
PrepareProxyConfigs(newConfigs)
- configFile := "xray_config.json"
- if err := GenerateAndSaveConfig(newConfigs, config.CLIConfig.Xray.StartPort, configFile, config.CLIConfig.Xray.LogLevel); err != nil {
- return fmt.Errorf("error generating new Xray config: %v", err)
+ configFile := "singbox_config.json"
+ if err := GenerateAndSaveConfig(newConfigs, config.CLIConfig.Singbox.StartPort, configFile, config.CLIConfig.Singbox.LogLevel); err != nil {
+ return fmt.Errorf("error generating new Singbox config: %v", err)
}
- if err := xrayRunner.Stop(); err != nil {
- return fmt.Errorf("error stopping Xray: %v", err)
+ if err := singboxRunner.Stop(); err != nil {
+ return fmt.Errorf("error stopping Singbox: %v", err)
}
- if err := xrayRunner.Start(); err != nil {
- return fmt.Errorf("error starting Xray with new config: %v", err)
+ if err := singboxRunner.Start(); err != nil {
+ return fmt.Errorf("error starting Singbox with new config: %v", err)
}
proxyChecker.UpdateProxies(newConfigs)
*currentConfigs = newConfigs
- web.RegisterConfigEndpoints(newConfigs, proxyChecker, config.CLIConfig.Xray.StartPort)
+ web.RegisterConfigEndpoints(newConfigs, proxyChecker, config.CLIConfig.Singbox.StartPort)
log.Println("Configuration updated successfully")
return nil
diff --git a/singbox/template.go b/singbox/template.go
new file mode 100644
index 00000000..6dceaa35
--- /dev/null
+++ b/singbox/template.go
@@ -0,0 +1,6 @@
+package singbox
+
+import "embed"
+
+//go:embed templates/singbox.json.tmpl
+var templates embed.FS
diff --git a/xray/templates/xray.json.tmpl b/singbox/templates/singbox.json.tmpl
similarity index 99%
rename from xray/templates/xray.json.tmpl
rename to singbox/templates/singbox.json.tmpl
index 20618fad..899dcb15 100644
--- a/xray/templates/xray.json.tmpl
+++ b/singbox/templates/singbox.json.tmpl
@@ -1,7 +1,7 @@
{{/* Base template structure */}}
{
"log": {
- "loglevel": "{{.XrayLogLevel}}"
+ "loglevel": "{{.LogLevel}}"
},
"inbounds": [
{{- range $index, $proxy := .Proxies }}
diff --git a/subscription/subscription.go b/subscription/subscription.go
index 6464fa1e..a12f2ed8 100644
--- a/subscription/subscription.go
+++ b/subscription/subscription.go
@@ -14,8 +14,8 @@ import (
"xray-checker/config"
"xray-checker/models"
"xray-checker/parser"
+ singbox "xray-checker/singbox"
"xray-checker/utils"
- "xray-checker/xray"
)
func InitializeConfiguration(configFile string) (*[]*models.ProxyConfig, error) {
@@ -25,9 +25,9 @@ func InitializeConfiguration(configFile string) (*[]*models.ProxyConfig, error)
}
proxyConfigs := &configs
- xray.PrepareProxyConfigs(*proxyConfigs)
- if err := xray.GenerateAndSaveConfig(*proxyConfigs, config.CLIConfig.Xray.StartPort, configFile, config.CLIConfig.Xray.LogLevel); err != nil {
- return nil, fmt.Errorf("error generating Xray config: %v", err)
+ singbox.PrepareProxyConfigs(*proxyConfigs)
+ if err := singbox.GenerateAndSaveConfig(*proxyConfigs, config.CLIConfig.Singbox.StartPort, configFile, config.CLIConfig.Singbox.LogLevel); err != nil {
+ return nil, fmt.Errorf("error generating Singbox config: %v", err)
}
return proxyConfigs, nil
diff --git a/web/handlers.go b/web/handlers.go
index 35eacebf..5c007ae3 100644
--- a/web/handlers.go
+++ b/web/handlers.go
@@ -28,7 +28,7 @@ func IndexHandler(version string, proxyChecker *checker.ProxyChecker) http.Handl
return
}
- RegisterConfigEndpoints(proxyChecker.GetProxies(), proxyChecker, config.CLIConfig.Xray.StartPort)
+ RegisterConfigEndpoints(proxyChecker.GetProxies(), proxyChecker, config.CLIConfig.Singbox.StartPort)
data := PageData{
Version: version,
@@ -42,7 +42,7 @@ func IndexHandler(version string, proxyChecker *checker.ProxyChecker) http.Handl
Timeout: config.CLIConfig.Proxy.Timeout,
SubscriptionUpdate: config.CLIConfig.Subscription.Update,
SubscriptionUpdateInterval: config.CLIConfig.Subscription.UpdateInterval,
- StartPort: config.CLIConfig.Xray.StartPort,
+ StartPort: config.CLIConfig.Singbox.StartPort,
Instance: config.CLIConfig.Metrics.Instance,
PushUrl: metrics.GetPushURL(config.CLIConfig.Metrics.PushURL),
Endpoints: registeredEndpoints,
diff --git a/xray/template.go b/xray/template.go
deleted file mode 100644
index 13fd52e4..00000000
--- a/xray/template.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package xray
-
-import "embed"
-
-//go:embed templates/xray.json.tmpl
-var templates embed.FS