Delete xray directory

This commit is contained in:
civisrom 2025-02-04 14:35:39 +03:00 committed by GitHub
parent 325bd1e203
commit 561248d5e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 0 additions and 703 deletions

View file

@ -1,256 +0,0 @@
package xray
import (
"context"
"encoding/json"
"fmt"
"regexp"
"time"
"x-ui/logger"
"x-ui/util/common"
"github.com/xtls/xray-core/app/proxyman/command"
statsService "github.com/xtls/xray-core/app/stats/command"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/trojan"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vmess"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
type XrayAPI struct {
HandlerServiceClient *command.HandlerServiceClient
StatsServiceClient *statsService.StatsServiceClient
grpcClient *grpc.ClientConn
isConnected bool
}
func (x *XrayAPI) Init(apiPort int) error {
if apiPort <= 0 {
return fmt.Errorf("invalid Xray API port: %d", apiPort)
}
addr := fmt.Sprintf("127.0.0.1:%d", apiPort)
conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return fmt.Errorf("failed to connect to Xray API: %w", err)
}
x.grpcClient = conn
x.isConnected = true
hsClient := command.NewHandlerServiceClient(conn)
ssClient := statsService.NewStatsServiceClient(conn)
x.HandlerServiceClient = &hsClient
x.StatsServiceClient = &ssClient
return nil
}
func (x *XrayAPI) Close() {
if x.grpcClient != nil {
x.grpcClient.Close()
}
x.HandlerServiceClient = nil
x.StatsServiceClient = nil
x.isConnected = false
}
func (x *XrayAPI) AddInbound(inbound []byte) error {
client := *x.HandlerServiceClient
conf := new(conf.InboundDetourConfig)
err := json.Unmarshal(inbound, conf)
if err != nil {
logger.Debug("Failed to unmarshal inbound:", err)
return err
}
config, err := conf.Build()
if err != nil {
logger.Debug("Failed to build inbound Detur:", err)
return err
}
inboundConfig := command.AddInboundRequest{Inbound: config}
_, err = client.AddInbound(context.Background(), &inboundConfig)
return err
}
func (x *XrayAPI) DelInbound(tag string) error {
client := *x.HandlerServiceClient
_, err := client.RemoveInbound(context.Background(), &command.RemoveInboundRequest{
Tag: tag,
})
return err
}
func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]interface{}) error {
var account *serial.TypedMessage
switch Protocol {
case "vmess":
account = serial.ToTypedMessage(&vmess.Account{
Id: user["id"].(string),
})
case "vless":
account = serial.ToTypedMessage(&vless.Account{
Id: user["id"].(string),
Flow: user["flow"].(string),
})
case "trojan":
account = serial.ToTypedMessage(&trojan.Account{
Password: user["password"].(string),
})
case "shadowsocks":
var ssCipherType shadowsocks.CipherType
switch user["cipher"].(string) {
case "aes-128-gcm":
ssCipherType = shadowsocks.CipherType_AES_128_GCM
case "aes-256-gcm":
ssCipherType = shadowsocks.CipherType_AES_256_GCM
case "chacha20-poly1305", "chacha20-ietf-poly1305":
ssCipherType = shadowsocks.CipherType_CHACHA20_POLY1305
case "xchacha20-poly1305", "xchacha20-ietf-poly1305":
ssCipherType = shadowsocks.CipherType_XCHACHA20_POLY1305
default:
ssCipherType = shadowsocks.CipherType_NONE
}
if ssCipherType != shadowsocks.CipherType_NONE {
account = serial.ToTypedMessage(&shadowsocks.Account{
Password: user["password"].(string),
CipherType: ssCipherType,
})
} else {
account = serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
Key: user["password"].(string),
Email: user["email"].(string),
})
}
default:
return nil
}
client := *x.HandlerServiceClient
_, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Email: user["email"].(string),
Account: account,
},
}),
})
return err
}
func (x *XrayAPI) RemoveUser(inboundTag, email string) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
op := &command.RemoveUserOperation{Email: email}
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(op),
}
_, err := (*x.HandlerServiceClient).AlterInbound(ctx, req)
if err != nil {
return fmt.Errorf("failed to remove user: %w", err)
}
return nil
}
func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
if x.grpcClient == nil {
return nil, nil, common.NewError("xray api is not initialized")
}
trafficRegex := regexp.MustCompile(`(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)`)
clientTrafficRegex := regexp.MustCompile(`user>>>([^>]+)>>>traffic>>>(downlink|uplink)`)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
if x.StatsServiceClient == nil {
return nil, nil, common.NewError("xray StatusServiceClient is not initialized")
}
resp, err := (*x.StatsServiceClient).QueryStats(ctx, &statsService.QueryStatsRequest{Reset_: reset})
if err != nil {
logger.Debug("Failed to query Xray stats:", err)
return nil, nil, err
}
tagTrafficMap := make(map[string]*Traffic)
emailTrafficMap := make(map[string]*ClientTraffic)
for _, stat := range resp.GetStat() {
if matches := trafficRegex.FindStringSubmatch(stat.Name); len(matches) == 4 {
processTraffic(matches, stat.Value, tagTrafficMap)
} else if matches := clientTrafficRegex.FindStringSubmatch(stat.Name); len(matches) == 3 {
processClientTraffic(matches, stat.Value, emailTrafficMap)
}
}
return mapToSlice(tagTrafficMap), mapToSlice(emailTrafficMap), nil
}
func processTraffic(matches []string, value int64, trafficMap map[string]*Traffic) {
isInbound := matches[1] == "inbound"
tag := matches[2]
isDown := matches[3] == "downlink"
if tag == "api" {
return
}
traffic, ok := trafficMap[tag]
if !ok {
traffic = &Traffic{
IsInbound: isInbound,
IsOutbound: !isInbound,
Tag: tag,
}
trafficMap[tag] = traffic
}
if isDown {
traffic.Down = value
} else {
traffic.Up = value
}
}
func processClientTraffic(matches []string, value int64, clientTrafficMap map[string]*ClientTraffic) {
email := matches[1]
isDown := matches[2] == "downlink"
traffic, ok := clientTrafficMap[email]
if !ok {
traffic = &ClientTraffic{Email: email}
clientTrafficMap[email] = traffic
}
if isDown {
traffic.Down = value
} else {
traffic.Up = value
}
}
func mapToSlice[T any](m map[string]*T) []*T {
result := make([]*T, 0, len(m))
for _, v := range m {
result = append(result, v)
}
return result
}

View file

@ -1,13 +0,0 @@
package xray
type ClientTraffic struct {
Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
InboundId int `json:"inboundId" form:"inboundId"`
Enable bool `json:"enable" form:"enable"`
Email string `json:"email" form:"email" gorm:"unique"`
Up int64 `json:"up" form:"up"`
Down int64 `json:"down" form:"down"`
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
Total int64 `json:"total" form:"total"`
Reset int `json:"reset" form:"reset" gorm:"default:0"`
}

View file

@ -1,65 +0,0 @@
package xray
import (
"bytes"
"x-ui/util/json_util"
)
type Config struct {
LogConfig json_util.RawMessage `json:"log"`
RouterConfig json_util.RawMessage `json:"routing"`
DNSConfig json_util.RawMessage `json:"dns"`
InboundConfigs []InboundConfig `json:"inbounds"`
OutboundConfigs json_util.RawMessage `json:"outbounds"`
Transport json_util.RawMessage `json:"transport"`
Policy json_util.RawMessage `json:"policy"`
API json_util.RawMessage `json:"api"`
Stats json_util.RawMessage `json:"stats"`
Reverse json_util.RawMessage `json:"reverse"`
FakeDNS json_util.RawMessage `json:"fakedns"`
Observatory json_util.RawMessage `json:"observatory"`
BurstObservatory json_util.RawMessage `json:"burstObservatory"`
}
func (c *Config) Equals(other *Config) bool {
if len(c.InboundConfigs) != len(other.InboundConfigs) {
return false
}
for i, inbound := range c.InboundConfigs {
if !inbound.Equals(&other.InboundConfigs[i]) {
return false
}
}
if !bytes.Equal(c.LogConfig, other.LogConfig) {
return false
}
if !bytes.Equal(c.RouterConfig, other.RouterConfig) {
return false
}
if !bytes.Equal(c.DNSConfig, other.DNSConfig) {
return false
}
if !bytes.Equal(c.OutboundConfigs, other.OutboundConfigs) {
return false
}
if !bytes.Equal(c.Transport, other.Transport) {
return false
}
if !bytes.Equal(c.Policy, other.Policy) {
return false
}
if !bytes.Equal(c.API, other.API) {
return false
}
if !bytes.Equal(c.Stats, other.Stats) {
return false
}
if !bytes.Equal(c.Reverse, other.Reverse) {
return false
}
if !bytes.Equal(c.FakeDNS, other.FakeDNS) {
return false
}
return true
}

View file

@ -1,46 +0,0 @@
package xray
import (
"bytes"
"x-ui/util/json_util"
)
type InboundConfig struct {
Listen json_util.RawMessage `json:"listen"` // listen cannot be an empty string
Port int `json:"port"`
Protocol string `json:"protocol"`
Settings json_util.RawMessage `json:"settings"`
StreamSettings json_util.RawMessage `json:"streamSettings"`
Tag string `json:"tag"`
Sniffing json_util.RawMessage `json:"sniffing"`
Allocate json_util.RawMessage `json:"allocate"`
}
func (c *InboundConfig) Equals(other *InboundConfig) bool {
if !bytes.Equal(c.Listen, other.Listen) {
return false
}
if c.Port != other.Port {
return false
}
if c.Protocol != other.Protocol {
return false
}
if !bytes.Equal(c.Settings, other.Settings) {
return false
}
if !bytes.Equal(c.StreamSettings, other.StreamSettings) {
return false
}
if c.Tag != other.Tag {
return false
}
if !bytes.Equal(c.Sniffing, other.Sniffing) {
return false
}
if !bytes.Equal(c.Allocate, other.Allocate) {
return false
}
return true
}

View file

@ -1,66 +0,0 @@
package xray
import (
"regexp"
"strings"
"x-ui/logger"
)
func NewLogWriter() *LogWriter {
return &LogWriter{}
}
type LogWriter struct {
lastLine string
}
func (lw *LogWriter) Write(m []byte) (n int, err error) {
crashRegex := regexp.MustCompile(`(?i)(panic|exception|stack trace|fatal error)`)
// Convert the data to a string
message := strings.TrimSpace(string(m))
// Check if the message contains a crash
if crashRegex.MatchString(message) {
logger.Debug("Core crash detected:\n", message)
lw.lastLine = message
err1 := writeCrachReport(m)
if err1 != nil {
logger.Error("Unable to write crash report:", err1)
}
return len(m), nil
}
regex := regexp.MustCompile(`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[([^\]]+)\] (.+)$`)
messages := strings.Split(message, "\n")
for _, msg := range messages {
matches := regex.FindStringSubmatch(msg)
if len(matches) > 3 {
level := matches[2]
msgBody := matches[3]
// Map the level to the appropriate logger function
switch level {
case "Debug":
logger.Debug("XRAY: " + msgBody)
case "Info":
logger.Info("XRAY: " + msgBody)
case "Warning":
logger.Warning("XRAY: " + msgBody)
case "Error":
logger.Error("XRAY: " + msgBody)
default:
logger.Debug("XRAY: " + msg)
}
lw.lastLine = ""
} else if msg != "" {
logger.Debug("XRAY: " + msg)
lw.lastLine = msg
}
}
return len(m), nil
}

View file

@ -1,248 +0,0 @@
package xray
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"runtime"
"syscall"
"time"
"x-ui/config"
"x-ui/logger"
"x-ui/util/common"
)
func GetBinaryName() string {
return fmt.Sprintf("xray-%s-%s", runtime.GOOS, runtime.GOARCH)
}
func GetBinaryPath() string {
return config.GetBinFolderPath() + "/" + GetBinaryName()
}
func GetConfigPath() string {
return config.GetBinFolderPath() + "/config.json"
}
func GetGeositePath() string {
return config.GetBinFolderPath() + "/geosite.dat"
}
func GetGeoipPath() string {
return config.GetBinFolderPath() + "/geoip.dat"
}
func GetIPLimitLogPath() string {
return config.GetLogFolder() + "/3xipl.log"
}
func GetIPLimitBannedLogPath() string {
return config.GetLogFolder() + "/3xipl-banned.log"
}
func GetIPLimitBannedPrevLogPath() string {
return config.GetLogFolder() + "/3xipl-banned.prev.log"
}
func GetAccessPersistentLogPath() string {
return config.GetLogFolder() + "/3xipl-ap.log"
}
func GetAccessPersistentPrevLogPath() string {
return config.GetLogFolder() + "/3xipl-ap.prev.log"
}
func GetAccessLogPath() (string, error) {
config, err := os.ReadFile(GetConfigPath())
if err != nil {
logger.Warningf("Failed to read configuration file: %s", err)
return "", err
}
jsonConfig := map[string]interface{}{}
err = json.Unmarshal([]byte(config), &jsonConfig)
if err != nil {
logger.Warningf("Failed to parse JSON configuration: %s", err)
return "", err
}
if jsonConfig["log"] != nil {
jsonLog := jsonConfig["log"].(map[string]interface{})
if jsonLog["access"] != nil {
accessLogPath := jsonLog["access"].(string)
return accessLogPath, nil
}
}
return "", err
}
func stopProcess(p *Process) {
p.Stop()
}
type Process struct {
*process
}
func NewProcess(xrayConfig *Config) *Process {
p := &Process{newProcess(xrayConfig)}
runtime.SetFinalizer(p, stopProcess)
return p
}
type process struct {
cmd *exec.Cmd
version string
apiPort int
onlineClients []string
config *Config
logWriter *LogWriter
exitErr error
startTime time.Time
}
func newProcess(config *Config) *process {
return &process{
version: "Unknown",
config: config,
logWriter: NewLogWriter(),
startTime: time.Now(),
}
}
func (p *process) IsRunning() bool {
if p.cmd == nil || p.cmd.Process == nil {
return false
}
if p.cmd.ProcessState == nil {
return true
}
return false
}
func (p *process) GetErr() error {
return p.exitErr
}
func (p *process) GetResult() string {
if len(p.logWriter.lastLine) == 0 && p.exitErr != nil {
return p.exitErr.Error()
}
return p.logWriter.lastLine
}
func (p *process) GetVersion() string {
return p.version
}
func (p *Process) GetAPIPort() int {
return p.apiPort
}
func (p *Process) GetConfig() *Config {
return p.config
}
func (p *Process) GetOnlineClients() []string {
return p.onlineClients
}
func (p *Process) SetOnlineClients(users []string) {
p.onlineClients = users
}
func (p *Process) GetUptime() uint64 {
return uint64(time.Since(p.startTime).Seconds())
}
func (p *process) refreshAPIPort() {
for _, inbound := range p.config.InboundConfigs {
if inbound.Tag == "api" {
p.apiPort = inbound.Port
break
}
}
}
func (p *process) refreshVersion() {
cmd := exec.Command(GetBinaryPath(), "-version")
data, err := cmd.Output()
if err != nil {
p.version = "Unknown"
} else {
datas := bytes.Split(data, []byte(" "))
if len(datas) <= 1 {
p.version = "Unknown"
} else {
p.version = string(datas[1])
}
}
}
func (p *process) Start() (err error) {
if p.IsRunning() {
return errors.New("xray is already running")
}
defer func() {
if err != nil {
logger.Error("Failure in running xray-core process: ", err)
p.exitErr = err
}
}()
data, err := json.MarshalIndent(p.config, "", " ")
if err != nil {
return common.NewErrorf("Failed to generate XRAY configuration files: %v", err)
}
err = os.MkdirAll(config.GetLogFolder(), 0o770)
if err != nil {
logger.Warningf("Failed to create log folder: %s", err)
}
configPath := GetConfigPath()
err = os.WriteFile(configPath, data, fs.ModePerm)
if err != nil {
return common.NewErrorf("Failed to write configuration file: %v", err)
}
cmd := exec.Command(GetBinaryPath(), "-c", configPath)
p.cmd = cmd
cmd.Stdout = p.logWriter
cmd.Stderr = p.logWriter
go func() {
err := cmd.Run()
if err != nil {
logger.Error("Failure in running xray-core:", err)
p.exitErr = err
}
}()
p.refreshVersion()
p.refreshAPIPort()
return nil
}
func (p *process) Stop() error {
if !p.IsRunning() {
return errors.New("xray is not running")
}
return p.cmd.Process.Signal(syscall.SIGTERM)
}
func writeCrachReport(m []byte) error {
crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log"
return os.WriteFile(crashReportPath, m, os.ModePerm)
}

View file

@ -1,9 +0,0 @@
package xray
type Traffic struct {
IsInbound bool
IsOutbound bool
Tag string
Up int64
Down int64
}