2026-01-05 21:12:53 +00:00
|
|
|
// Package main is the entry point for the 3x-ui node service (worker).
|
|
|
|
|
// This service runs XRAY Core and provides a REST API for the master panel to manage it.
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"flag"
|
2026-01-12 02:01:31 +00:00
|
|
|
"fmt"
|
2026-01-05 21:12:53 +00:00
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"os/signal"
|
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/logger"
|
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/node/api"
|
2026-01-12 02:01:31 +00:00
|
|
|
nodeConfig "github.com/mhsanaei/3x-ui/v2/node/config"
|
|
|
|
|
nodeLogs "github.com/mhsanaei/3x-ui/v2/node/logs"
|
2026-01-05 21:12:53 +00:00
|
|
|
"github.com/mhsanaei/3x-ui/v2/node/xray"
|
|
|
|
|
"github.com/op/go-logging"
|
|
|
|
|
)
|
|
|
|
|
|
2026-01-12 02:01:31 +00:00
|
|
|
|
2026-01-05 21:12:53 +00:00
|
|
|
func main() {
|
|
|
|
|
var port int
|
|
|
|
|
var apiKey string
|
|
|
|
|
flag.IntVar(&port, "port", 8080, "API server port")
|
2026-01-12 02:01:31 +00:00
|
|
|
flag.StringVar(&apiKey, "api-key", "", "API key for authentication (optional, can be set via registration)")
|
2026-01-05 21:12:53 +00:00
|
|
|
flag.Parse()
|
|
|
|
|
|
2026-01-12 02:01:31 +00:00
|
|
|
logger.InitLogger(logging.INFO)
|
|
|
|
|
|
|
|
|
|
// Initialize node configuration system
|
|
|
|
|
// Try to find config directory (same as XRAY config)
|
|
|
|
|
configDirs := []string{"bin", "config", ".", "/app/bin", "/app/config"}
|
|
|
|
|
var configDir string
|
|
|
|
|
for _, dir := range configDirs {
|
|
|
|
|
if _, err := os.Stat(dir); err == nil {
|
|
|
|
|
configDir = dir
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if configDir == "" {
|
|
|
|
|
configDir = "." // Fallback
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := nodeConfig.InitConfig(configDir); err != nil {
|
|
|
|
|
log.Fatalf("Failed to initialize node config: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get API key from (in order of priority):
|
|
|
|
|
// 1. Command line flag
|
|
|
|
|
// 2. Environment variable (for backward compatibility)
|
|
|
|
|
// 3. Saved config file (from registration)
|
2026-01-05 21:12:53 +00:00
|
|
|
if apiKey == "" {
|
|
|
|
|
apiKey = os.Getenv("NODE_API_KEY")
|
|
|
|
|
}
|
2026-01-12 02:01:31 +00:00
|
|
|
if apiKey == "" {
|
|
|
|
|
// Try to load from saved config
|
|
|
|
|
savedConfig := nodeConfig.GetConfig()
|
|
|
|
|
if savedConfig.ApiKey != "" {
|
|
|
|
|
apiKey = savedConfig.ApiKey
|
|
|
|
|
log.Printf("Using API key from saved configuration")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-05 21:12:53 +00:00
|
|
|
|
2026-01-12 02:01:31 +00:00
|
|
|
// If still no API key, node can start but will need registration
|
2026-01-05 21:12:53 +00:00
|
|
|
if apiKey == "" {
|
2026-01-12 02:01:31 +00:00
|
|
|
log.Printf("WARNING: No API key found. Node will need to be registered via /api/v1/register endpoint")
|
|
|
|
|
log.Printf("You can set NODE_API_KEY environment variable or use -api-key flag for immediate use")
|
|
|
|
|
// Use a temporary key that will be replaced during registration
|
|
|
|
|
apiKey = "temp-unregistered"
|
2026-01-05 21:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-12 02:01:31 +00:00
|
|
|
// Initialize log pusher if panel URL is configured
|
|
|
|
|
// Get node address from saved config or environment variable
|
|
|
|
|
savedConfig := nodeConfig.GetConfig()
|
|
|
|
|
nodeAddress := savedConfig.NodeAddress
|
|
|
|
|
if nodeAddress == "" {
|
|
|
|
|
nodeAddress = os.Getenv("NODE_ADDRESS")
|
|
|
|
|
}
|
|
|
|
|
if nodeAddress == "" {
|
|
|
|
|
// Default to localhost with the port (panel will match by port if address doesn't match exactly)
|
|
|
|
|
nodeAddress = fmt.Sprintf("http://127.0.0.1:%d", port)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get panel URL from saved config or environment variable
|
|
|
|
|
panelURL := savedConfig.PanelURL
|
|
|
|
|
if panelURL == "" {
|
|
|
|
|
panelURL = os.Getenv("PANEL_URL")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeLogs.InitLogPusher(nodeAddress)
|
|
|
|
|
if panelURL != "" {
|
|
|
|
|
nodeLogs.SetPanelURL(panelURL)
|
|
|
|
|
}
|
|
|
|
|
// Connect log pusher to logger
|
|
|
|
|
logger.SetLogPusher(nodeLogs.PushLog)
|
2026-01-05 21:12:53 +00:00
|
|
|
|
|
|
|
|
xrayManager := xray.NewManager()
|
|
|
|
|
server := api.NewServer(port, apiKey, xrayManager)
|
|
|
|
|
|
|
|
|
|
log.Printf("Starting 3x-ui Node Service on port %d", port)
|
|
|
|
|
if err := server.Start(); err != nil {
|
|
|
|
|
log.Fatalf("Failed to start server: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
|
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
|
<-sigCh
|
|
|
|
|
|
|
|
|
|
log.Println("Shutting down...")
|
|
|
|
|
xrayManager.Stop()
|
|
|
|
|
server.Stop()
|
|
|
|
|
log.Println("Shutdown complete")
|
|
|
|
|
}
|