mirror of
https://github.com/XrayR-project/XrayR.git
synced 2025-06-07 21:09:53 +00:00

The standard "log" package was replaced by the structured logger "github.com/sirupsen/logrus" for better log control in various files. This change will allow to tailor the logging information more precisely and make logs easier to read and analyze. All calls of standard log methods were replaced by their logrus counterparts.
253 lines
7.9 KiB
Go
253 lines
7.9 KiB
Go
package panel
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"sync"
|
|
|
|
"dario.cat/mergo"
|
|
"github.com/r3labs/diff/v2"
|
|
log "github.com/sirupsen/logrus"
|
|
"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/bunpanel"
|
|
"github.com/XrayR-project/XrayR/api/gov2panel"
|
|
"github.com/XrayR-project/XrayR/api/newV2board"
|
|
"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/app/mydispatcher"
|
|
_ "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)
|
|
}
|
|
|
|
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", "V2board":
|
|
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)
|
|
case "BunPanel":
|
|
apiClient = bunpanel.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
|
|
}
|