mirror of
https://github.com/XrayR-project/XrayR.git
synced 2025-06-08 05:19:54 +00:00

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.
252 lines
7.8 KiB
Go
252 lines
7.8 KiB
Go
package panel
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/XrayR-project/XrayR/api/gov2panel"
|
|
"github.com/XrayR-project/XrayR/api/newV2board"
|
|
"github.com/XrayR-project/XrayR/app/mydispatcher"
|
|
|
|
"dario.cat/mergo"
|
|
"github.com/r3labs/diff/v2"
|
|
"github.com/xtls/xray-core/app/proxyman"
|
|
"github.com/xtls/xray-core/app/stats"
|
|
"github.com/xtls/xray-core/common/serial"
|
|
"github.com/xtls/xray-core/core"
|
|
"github.com/xtls/xray-core/infra/conf"
|
|
|
|
"github.com/XrayR-project/XrayR/api"
|
|
"github.com/XrayR-project/XrayR/api/pmpanel"
|
|
"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/cmd/distro/all"
|
|
"github.com/XrayR-project/XrayR/service"
|
|
"github.com/XrayR-project/XrayR/service/controller"
|
|
)
|
|
|
|
// Panel Structure
|
|
type Panel struct {
|
|
access sync.Mutex
|
|
panelConfig *Config
|
|
Server *core.Instance
|
|
Service []service.Service
|
|
Running bool
|
|
}
|
|
|
|
func New(panelConfig *Config) *Panel {
|
|
p := &Panel{panelConfig: panelConfig}
|
|
return p
|
|
}
|
|
|
|
func (p *Panel) loadCore(panelConfig *Config) *core.Instance {
|
|
// Log Config
|
|
coreLogConfig := &conf.LogConfig{}
|
|
logConfig := getDefaultLogConfig()
|
|
if panelConfig.LogConfig != nil {
|
|
if _, err := diff.Merge(logConfig, panelConfig.LogConfig, logConfig); err != nil {
|
|
log.Panicf("Read Log config failed: %s", err)
|
|
}
|
|
}
|
|
coreLogConfig.LogLevel = logConfig.Level
|
|
coreLogConfig.AccessLog = logConfig.AccessPath
|
|
coreLogConfig.ErrorLog = logConfig.ErrorPath
|
|
|
|
// DNS config
|
|
coreDnsConfig := &conf.DNSConfig{}
|
|
if panelConfig.DnsConfigPath != "" {
|
|
if data, err := os.ReadFile(panelConfig.DnsConfigPath); err != nil {
|
|
log.Panicf("Failed to read DNS config file at: %s", panelConfig.DnsConfigPath)
|
|
} else {
|
|
if err = json.Unmarshal(data, coreDnsConfig); err != nil {
|
|
log.Panicf("Failed to unmarshal DNS config: %s", panelConfig.DnsConfigPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
// init controller's DNS config
|
|
// for _, config := range p.panelConfig.NodesConfig {
|
|
// config.ControllerConfig.DNSConfig = coreDnsConfig
|
|
// }
|
|
|
|
dnsConfig, err := coreDnsConfig.Build()
|
|
if err != nil {
|
|
log.Panicf("Failed to understand DNS config, Please check: https://xtls.github.io/config/dns.html for help: %s", err)
|
|
}
|
|
|
|
// Routing config
|
|
coreRouterConfig := &conf.RouterConfig{}
|
|
if panelConfig.RouteConfigPath != "" {
|
|
if data, err := os.ReadFile(panelConfig.RouteConfigPath); err != nil {
|
|
log.Panicf("Failed to read Routing config file at: %s", panelConfig.RouteConfigPath)
|
|
} else {
|
|
if err = json.Unmarshal(data, coreRouterConfig); err != nil {
|
|
log.Panicf("Failed to unmarshal Routing config: %s", panelConfig.RouteConfigPath)
|
|
}
|
|
}
|
|
}
|
|
routeConfig, err := coreRouterConfig.Build()
|
|
if err != nil {
|
|
log.Panicf("Failed to understand Routing config Please check: https://xtls.github.io/config/routing.html for help: %s", err)
|
|
}
|
|
// Custom Inbound config
|
|
var coreCustomInboundConfig []conf.InboundDetourConfig
|
|
if panelConfig.InboundConfigPath != "" {
|
|
if data, err := os.ReadFile(panelConfig.InboundConfigPath); err != nil {
|
|
log.Panicf("Failed to read Custom Inbound config file at: %s", panelConfig.OutboundConfigPath)
|
|
} else {
|
|
if err = json.Unmarshal(data, &coreCustomInboundConfig); err != nil {
|
|
log.Panicf("Failed to unmarshal Custom Inbound config: %s", panelConfig.OutboundConfigPath)
|
|
}
|
|
}
|
|
}
|
|
var inBoundConfig []*core.InboundHandlerConfig
|
|
for _, config := range coreCustomInboundConfig {
|
|
oc, err := config.Build()
|
|
if err != nil {
|
|
log.Panicf("Failed to understand Inbound config, Please check: https://xtls.github.io/config/inbound.html for help: %s", err)
|
|
}
|
|
inBoundConfig = append(inBoundConfig, oc)
|
|
}
|
|
// Custom Outbound config
|
|
var coreCustomOutboundConfig []conf.OutboundDetourConfig
|
|
if panelConfig.OutboundConfigPath != "" {
|
|
if data, err := os.ReadFile(panelConfig.OutboundConfigPath); err != nil {
|
|
log.Panicf("Failed to read Custom Outbound config file at: %s", panelConfig.OutboundConfigPath)
|
|
} else {
|
|
if err = json.Unmarshal(data, &coreCustomOutboundConfig); err != nil {
|
|
log.Panicf("Failed to unmarshal Custom Outbound config: %s", panelConfig.OutboundConfigPath)
|
|
}
|
|
}
|
|
}
|
|
var outBoundConfig []*core.OutboundHandlerConfig
|
|
for _, config := range coreCustomOutboundConfig {
|
|
oc, err := config.Build()
|
|
if err != nil {
|
|
log.Panicf("Failed to understand Outbound config, Please check: https://xtls.github.io/config/outbound.html for help: %s", err)
|
|
}
|
|
outBoundConfig = append(outBoundConfig, oc)
|
|
}
|
|
// Policy config
|
|
levelPolicyConfig := parseConnectionConfig(panelConfig.ConnectionConfig)
|
|
corePolicyConfig := &conf.PolicyConfig{}
|
|
corePolicyConfig.Levels = map[uint32]*conf.Policy{0: levelPolicyConfig}
|
|
policyConfig, _ := corePolicyConfig.Build()
|
|
// Build Core Config
|
|
config := &core.Config{
|
|
App: []*serial.TypedMessage{
|
|
serial.ToTypedMessage(coreLogConfig.Build()),
|
|
serial.ToTypedMessage(&mydispatcher.Config{}),
|
|
serial.ToTypedMessage(&stats.Config{}),
|
|
serial.ToTypedMessage(&proxyman.InboundConfig{}),
|
|
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
|
|
serial.ToTypedMessage(policyConfig),
|
|
serial.ToTypedMessage(dnsConfig),
|
|
serial.ToTypedMessage(routeConfig),
|
|
},
|
|
Inbound: inBoundConfig,
|
|
Outbound: outBoundConfig,
|
|
}
|
|
server, err := core.New(config)
|
|
if err != nil {
|
|
log.Panicf("failed to create instance: %s", err)
|
|
}
|
|
log.Printf("Xray Core Version: %s", core.Version())
|
|
|
|
return server
|
|
}
|
|
|
|
// Start the panel
|
|
func (p *Panel) Start() {
|
|
p.access.Lock()
|
|
defer p.access.Unlock()
|
|
log.Print("Start the panel..")
|
|
// Load Core
|
|
server := p.loadCore(p.panelConfig)
|
|
if err := server.Start(); err != nil {
|
|
log.Panicf("Failed to start instance: %s", err)
|
|
}
|
|
p.Server = server
|
|
|
|
// Load Nodes config
|
|
for _, nodeConfig := range p.panelConfig.NodesConfig {
|
|
var apiClient api.API
|
|
switch nodeConfig.PanelType {
|
|
case "SSpanel":
|
|
apiClient = sspanel.New(nodeConfig.ApiConfig)
|
|
case "NewV2board":
|
|
apiClient = newV2board.New(nodeConfig.ApiConfig)
|
|
case "PMpanel":
|
|
apiClient = pmpanel.New(nodeConfig.ApiConfig)
|
|
case "Proxypanel":
|
|
apiClient = proxypanel.New(nodeConfig.ApiConfig)
|
|
case "V2RaySocks":
|
|
apiClient = v2raysocks.New(nodeConfig.ApiConfig)
|
|
case "GoV2Panel":
|
|
apiClient = gov2panel.New(nodeConfig.ApiConfig)
|
|
default:
|
|
log.Panicf("Unsupport panel type: %s", nodeConfig.PanelType)
|
|
}
|
|
var controllerService service.Service
|
|
// Register controller service
|
|
controllerConfig := getDefaultControllerConfig()
|
|
if nodeConfig.ControllerConfig != nil {
|
|
if err := mergo.Merge(controllerConfig, nodeConfig.ControllerConfig, mergo.WithOverride); err != nil {
|
|
log.Panicf("Read Controller Config Failed")
|
|
}
|
|
}
|
|
controllerService = controller.New(server, apiClient, controllerConfig, nodeConfig.PanelType)
|
|
p.Service = append(p.Service, controllerService)
|
|
|
|
}
|
|
|
|
// Start all the service
|
|
for _, s := range p.Service {
|
|
err := s.Start()
|
|
if err != nil {
|
|
log.Panicf("Panel Start fialed: %s", err)
|
|
}
|
|
}
|
|
p.Running = true
|
|
return
|
|
}
|
|
|
|
// Close the panel
|
|
func (p *Panel) Close() {
|
|
p.access.Lock()
|
|
defer p.access.Unlock()
|
|
for _, s := range p.Service {
|
|
err := s.Close()
|
|
if err != nil {
|
|
log.Panicf("Panel Close fialed: %s", err)
|
|
}
|
|
}
|
|
p.Service = nil
|
|
p.Server.Close()
|
|
p.Running = false
|
|
return
|
|
}
|
|
|
|
func parseConnectionConfig(c *ConnectionConfig) (policy *conf.Policy) {
|
|
connectionConfig := getDefaultConnectionConfig()
|
|
if c != nil {
|
|
if _, err := diff.Merge(connectionConfig, c, connectionConfig); err != nil {
|
|
log.Panicf("Read ConnectionConfig failed: %s", err)
|
|
}
|
|
}
|
|
policy = &conf.Policy{
|
|
StatsUserUplink: true,
|
|
StatsUserDownlink: true,
|
|
Handshake: &connectionConfig.Handshake,
|
|
ConnectionIdle: &connectionConfig.ConnIdle,
|
|
UplinkOnly: &connectionConfig.UplinkOnly,
|
|
DownlinkOnly: &connectionConfig.DownlinkOnly,
|
|
BufferSize: &connectionConfig.BufferSize,
|
|
}
|
|
|
|
return
|
|
}
|