mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-10-31 04:12:51 +00:00 
			
		
		
		
	Delete process.go
This commit is contained in:
		
							parent
							
								
									4fb060d25e
								
							
						
					
					
						commit
						05bb5ca217
					
				
					 1 changed files with 0 additions and 318 deletions
				
			
		
							
								
								
									
										318
									
								
								xray/process.go
									
									
									
									
									
								
							
							
						
						
									
										318
									
								
								xray/process.go
									
									
									
									
									
								
							|  | @ -1,318 +0,0 @@ | |||
| package xray | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/fs" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"x-ui/config" | ||||
| 	"x-ui/util/common" | ||||
| 
 | ||||
| 	"github.com/Workiva/go-datastructures/queue" | ||||
| 	statsservice "github.com/xtls/xray-core/app/stats/command" | ||||
| 	"google.golang.org/grpc" | ||||
| ) | ||||
| 
 | ||||
| var trafficRegex = regexp.MustCompile("(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)") | ||||
| var ClientTrafficRegex = regexp.MustCompile("(user)>>>([^>]+)>>>traffic>>>(downlink|uplink)") | ||||
| 
 | ||||
| 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 GetBlockedIPsPath() string { | ||||
| 	return config.GetBinFolderPath() + "/blockedIPs" | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| 	config  *Config | ||||
| 	lines   *queue.Queue | ||||
| 	exitErr error | ||||
| } | ||||
| 
 | ||||
| func newProcess(config *Config) *process { | ||||
| 	return &process{ | ||||
| 		version: "Unknown", | ||||
| 		config:  config, | ||||
| 		lines:   queue.New(100), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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 p.lines.Empty() && p.exitErr != nil { | ||||
| 		return p.exitErr.Error() | ||||
| 	} | ||||
| 	items, _ := p.lines.TakeUntil(func(item interface{}) bool { | ||||
| 		return true | ||||
| 	}) | ||||
| 	lines := make([]string, 0, len(items)) | ||||
| 	for _, item := range items { | ||||
| 		lines = append(lines, item.(string)) | ||||
| 	} | ||||
| 	return strings.Join(lines, "\n") | ||||
| } | ||||
| 
 | ||||
| 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) 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 { | ||||
| 			p.exitErr = err | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	data, err := json.MarshalIndent(p.config, "", "  ") | ||||
| 	if err != nil { | ||||
| 		return common.NewErrorf("Failed to generate xray configuration file: %v", 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, "-restrictedIPsPath", GetBlockedIPsPath()) | ||||
| 	p.cmd = cmd | ||||
| 
 | ||||
| 	stdReader, err := cmd.StdoutPipe() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	errReader, err := cmd.StderrPipe() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	go func() { | ||||
| 		defer func() { | ||||
| 			common.Recover("") | ||||
| 			stdReader.Close() | ||||
| 		}() | ||||
| 		reader := bufio.NewReaderSize(stdReader, 8192) | ||||
| 		for { | ||||
| 			line, _, err := reader.ReadLine() | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			if p.lines.Len() >= 100 { | ||||
| 				p.lines.Get(1) | ||||
| 			} | ||||
| 			p.lines.Put(string(line)) | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	go func() { | ||||
| 		defer func() { | ||||
| 			common.Recover("") | ||||
| 			errReader.Close() | ||||
| 		}() | ||||
| 		reader := bufio.NewReaderSize(errReader, 8192) | ||||
| 		for { | ||||
| 			line, _, err := reader.ReadLine() | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			if p.lines.Len() >= 100 { | ||||
| 				p.lines.Get(1) | ||||
| 			} | ||||
| 			p.lines.Put(string(line)) | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	go func() { | ||||
| 		err := cmd.Run() | ||||
| 		if err != nil { | ||||
| 			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.Kill() | ||||
| } | ||||
| 
 | ||||
| func (p *process) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) { | ||||
| 	if p.apiPort == 0 { | ||||
| 		return nil, nil, common.NewError("xray api port wrong:", p.apiPort) | ||||
| 	} | ||||
| 	conn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%v", p.apiPort), grpc.WithInsecure()) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	defer conn.Close() | ||||
| 
 | ||||
| 	client := statsservice.NewStatsServiceClient(conn) | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) | ||||
| 	defer cancel() | ||||
| 	request := &statsservice.QueryStatsRequest{ | ||||
| 		Reset_: reset, | ||||
| 	} | ||||
| 	resp, err := client.QueryStats(ctx, request) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	tagTrafficMap := map[string]*Traffic{} | ||||
| 	emailTrafficMap := map[string]*ClientTraffic{} | ||||
| 
 | ||||
| 	clientTraffics := make([]*ClientTraffic, 0) | ||||
| 	traffics := make([]*Traffic, 0) | ||||
| 	for _, stat := range resp.GetStat() { | ||||
| 		matchs := trafficRegex.FindStringSubmatch(stat.Name) | ||||
| 		if len(matchs) < 3 { | ||||
| 
 | ||||
| 			matchs := ClientTrafficRegex.FindStringSubmatch(stat.Name) | ||||
| 			if len(matchs) < 3 { | ||||
| 				continue | ||||
| 			} else { | ||||
| 
 | ||||
| 				isUser := matchs[1] == "user" | ||||
| 				email := matchs[2] | ||||
| 				isDown := matchs[3] == "downlink" | ||||
| 				if !isUser { | ||||
| 					continue | ||||
| 				} | ||||
| 				traffic, ok := emailTrafficMap[email] | ||||
| 				if !ok { | ||||
| 					traffic = &ClientTraffic{ | ||||
| 						Email: email, | ||||
| 					} | ||||
| 					emailTrafficMap[email] = traffic | ||||
| 					clientTraffics = append(clientTraffics, traffic) | ||||
| 				} | ||||
| 				if isDown { | ||||
| 					traffic.Down = stat.Value | ||||
| 				} else { | ||||
| 					traffic.Up = stat.Value | ||||
| 				} | ||||
| 
 | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		isInbound := matchs[1] == "inbound" | ||||
| 		tag := matchs[2] | ||||
| 		isDown := matchs[3] == "downlink" | ||||
| 		if tag == "api" { | ||||
| 			continue | ||||
| 		} | ||||
| 		traffic, ok := tagTrafficMap[tag] | ||||
| 		if !ok { | ||||
| 			traffic = &Traffic{ | ||||
| 				IsInbound: isInbound, | ||||
| 				Tag:       tag, | ||||
| 			} | ||||
| 			tagTrafficMap[tag] = traffic | ||||
| 			traffics = append(traffics, traffic) | ||||
| 		} | ||||
| 		if isDown { | ||||
| 			traffic.Down = stat.Value | ||||
| 		} else { | ||||
| 			traffic.Up = stat.Value | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return traffics, clientTraffics, nil | ||||
| } | ||||
		Loading…
	
		Reference in a new issue
	
	 Peyman
						Peyman