| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | package xray | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/fs" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"os/exec" | 
					
						
							|  |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2023-06-15 21:40:49 +00:00
										 |  |  | 	"syscall" | 
					
						
							| 
									
										
										
										
											2023-08-08 21:07:05 +00:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2023-08-08 18:51:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 19:40:01 +00:00
										 |  |  | 	"x-ui/config" | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 	"x-ui/logger" | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	"x-ui/util/common" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetBinaryName() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("xray-%s-%s", runtime.GOOS, runtime.GOARCH) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetBinaryPath() string { | 
					
						
							| 
									
										
										
										
											2023-04-13 19:40:01 +00:00
										 |  |  | 	return config.GetBinFolderPath() + "/" + GetBinaryName() | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetConfigPath() string { | 
					
						
							| 
									
										
										
										
											2023-04-13 19:40:01 +00:00
										 |  |  | 	return config.GetBinFolderPath() + "/config.json" | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetGeositePath() string { | 
					
						
							| 
									
										
										
										
											2023-04-13 19:40:01 +00:00
										 |  |  | 	return config.GetBinFolderPath() + "/geosite.dat" | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetGeoipPath() string { | 
					
						
							| 
									
										
										
										
											2023-04-13 19:40:01 +00:00
										 |  |  | 	return config.GetBinFolderPath() + "/geoip.dat" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | func GetIPLimitLogPath() string { | 
					
						
							|  |  |  | 	return config.GetLogFolder() + "/3xipl.log" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetIPLimitBannedLogPath() string { | 
					
						
							|  |  |  | 	return config.GetLogFolder() + "/3xipl-banned.log" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-01 15:07:56 +00:00
										 |  |  | func GetIPLimitBannedPrevLogPath() string { | 
					
						
							|  |  |  | 	return config.GetLogFolder() + "/3xipl-banned.prev.log" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | func GetAccessPersistentLogPath() string { | 
					
						
							| 
									
										
										
										
											2024-01-01 15:07:56 +00:00
										 |  |  | 	return config.GetLogFolder() + "/3xipl-ap.log" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetAccessPersistentPrevLogPath() string { | 
					
						
							|  |  |  | 	return config.GetLogFolder() + "/3xipl-ap.prev.log" | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-13 07:54:41 +00:00
										 |  |  | func GetAccessLogPath() (string, error) { | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 	config, err := os.ReadFile(GetConfigPath()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 		logger.Warningf("Failed to read configuration file: %s", err) | 
					
						
							| 
									
										
										
										
											2024-03-13 07:54:41 +00:00
										 |  |  | 		return "", err | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  | 	jsonConfig := map[string]any{} | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 	err = json.Unmarshal([]byte(config), &jsonConfig) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 		logger.Warningf("Failed to parse JSON configuration: %s", err) | 
					
						
							| 
									
										
										
										
											2024-03-13 07:54:41 +00:00
										 |  |  | 		return "", err | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if jsonConfig["log"] != nil { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  | 		jsonLog := jsonConfig["log"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 		if jsonLog["access"] != nil { | 
					
						
							|  |  |  | 			accessLogPath := jsonLog["access"].(string) | 
					
						
							| 
									
										
										
										
											2024-03-13 07:54:41 +00:00
										 |  |  | 			return accessLogPath, nil | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-13 07:54:41 +00:00
										 |  |  | 	return "", err | 
					
						
							| 
									
										
										
										
											2023-07-01 12:26:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 18:13:21 +00:00
										 |  |  | 	onlineClients []string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-08 21:07:05 +00:00
										 |  |  | 	config    *Config | 
					
						
							| 
									
										
										
										
											2023-12-10 12:07:50 +00:00
										 |  |  | 	logWriter *LogWriter | 
					
						
							| 
									
										
										
										
											2023-08-08 21:07:05 +00:00
										 |  |  | 	exitErr   error | 
					
						
							|  |  |  | 	startTime time.Time | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newProcess(config *Config) *process { | 
					
						
							|  |  |  | 	return &process{ | 
					
						
							| 
									
										
										
										
											2023-08-08 21:07:05 +00:00
										 |  |  | 		version:   "Unknown", | 
					
						
							|  |  |  | 		config:    config, | 
					
						
							| 
									
										
										
										
											2023-12-10 12:07:50 +00:00
										 |  |  | 		logWriter: NewLogWriter(), | 
					
						
							| 
									
										
										
										
											2023-08-08 21:07:05 +00:00
										 |  |  | 		startTime: time.Now(), | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 { | 
					
						
							| 
									
										
										
										
											2023-12-10 12:07:50 +00:00
										 |  |  | 	if len(p.logWriter.lastLine) == 0 && p.exitErr != nil { | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 		return p.exitErr.Error() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-12-10 12:07:50 +00:00
										 |  |  | 	return p.logWriter.lastLine | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *process) GetVersion() string { | 
					
						
							|  |  |  | 	return p.version | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Process) GetAPIPort() int { | 
					
						
							|  |  |  | 	return p.apiPort | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Process) GetConfig() *Config { | 
					
						
							|  |  |  | 	return p.config | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 18:13:21 +00:00
										 |  |  | func (p *Process) GetOnlineClients() []string { | 
					
						
							|  |  |  | 	return p.onlineClients | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Process) SetOnlineClients(users []string) { | 
					
						
							|  |  |  | 	p.onlineClients = users | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-08 21:07:05 +00:00
										 |  |  | func (p *Process) GetUptime() uint64 { | 
					
						
							|  |  |  | 	return uint64(time.Since(p.startTime).Seconds()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 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 { | 
					
						
							| 
									
										
										
										
											2024-04-01 07:50:34 +00:00
										 |  |  | 			logger.Error("Failure in running xray-core process: ", err) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 			p.exitErr = err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.MarshalIndent(p.config, "", "  ") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-04-01 07:50:34 +00:00
										 |  |  | 		return common.NewErrorf("Failed to generate XRAY configuration files: %v", err) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-10 21:31:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-13 07:54:41 +00:00
										 |  |  | 	err = os.MkdirAll(config.GetLogFolder(), 0o770) | 
					
						
							| 
									
										
										
										
											2024-03-05 13:39:20 +00:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 		logger.Warningf("Failed to create log folder: %s", err) | 
					
						
							| 
									
										
										
										
											2024-03-05 13:39:20 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	configPath := GetConfigPath() | 
					
						
							|  |  |  | 	err = os.WriteFile(configPath, data, fs.ModePerm) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2023-02-11 20:55:21 +00:00
										 |  |  | 		return common.NewErrorf("Failed to write configuration file: %v", err) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-27 07:36:27 +00:00
										 |  |  | 	cmd := exec.Command(GetBinaryPath(), "-c", configPath) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	p.cmd = cmd | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-10 12:07:50 +00:00
										 |  |  | 	cmd.Stdout = p.logWriter | 
					
						
							|  |  |  | 	cmd.Stderr = p.logWriter | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		err := cmd.Run() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 			logger.Error("Failure in running xray-core:", err) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 			p.exitErr = err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p.refreshVersion() | 
					
						
							|  |  |  | 	p.refreshAPIPort() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *process) Stop() error { | 
					
						
							|  |  |  | 	if !p.IsRunning() { | 
					
						
							|  |  |  | 		return errors.New("xray is not running") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-15 21:40:49 +00:00
										 |  |  | 	return p.cmd.Process.Signal(syscall.SIGTERM) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2024-11-21 13:55:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-03 22:07:24 +00:00
										 |  |  | func writeCrachReport(m []byte) error { | 
					
						
							| 
									
										
										
										
											2024-11-21 13:55:11 +00:00
										 |  |  | 	crashReportPath := config.GetBinFolderPath() + "/core_crash_" + time.Now().Format("20060102_150405") + ".log" | 
					
						
							| 
									
										
										
										
											2024-12-03 22:07:24 +00:00
										 |  |  | 	return os.WriteFile(crashReportPath, m, os.ModePerm) | 
					
						
							| 
									
										
										
										
											2024-11-21 13:55:11 +00:00
										 |  |  | } |