XrayR/panel/panel.go
Senis 115d7bad6f
Replace standard log package with logrus
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.
2023-12-28 13:40:31 +08:00

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
}