| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | package service | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2024-03-10 21:31:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	"x-ui/logger" | 
					
						
							|  |  |  | 	"x-ui/xray" | 
					
						
							| 
									
										
										
										
											2023-02-18 12:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	"go.uber.org/atomic" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 21:31:24 +00:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	p                 *xray.Process | 
					
						
							|  |  |  | 	lock              sync.Mutex | 
					
						
							|  |  |  | 	isNeedXrayRestart atomic.Bool | 
					
						
							|  |  |  | 	result            string | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | type XrayService struct { | 
					
						
							|  |  |  | 	inboundService InboundService | 
					
						
							|  |  |  | 	settingService SettingService | 
					
						
							| 
									
										
										
										
											2023-06-04 21:02:19 +00:00
										 |  |  | 	xrayAPI        xray.XrayAPI | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) IsXrayRunning() bool { | 
					
						
							|  |  |  | 	return p != nil && p.IsRunning() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) GetXrayErr() error { | 
					
						
							|  |  |  | 	if p == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return p.GetErr() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) GetXrayResult() string { | 
					
						
							|  |  |  | 	if result != "" { | 
					
						
							|  |  |  | 		return result | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if s.IsXrayRunning() { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if p == nil { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	result = p.GetResult() | 
					
						
							|  |  |  | 	return result | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) GetXrayVersion() string { | 
					
						
							|  |  |  | 	if p == nil { | 
					
						
							|  |  |  | 		return "Unknown" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return p.GetVersion() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-02-18 12:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | func RemoveIndex(s []interface{}, index int) []interface{} { | 
					
						
							|  |  |  | 	return append(s[:index], s[index+1:]...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) GetXrayConfig() (*xray.Config, error) { | 
					
						
							|  |  |  | 	templateConfig, err := s.settingService.GetXrayConfigTemplate() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xrayConfig := &xray.Config{} | 
					
						
							|  |  |  | 	err = json.Unmarshal([]byte(templateConfig), xrayConfig) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:49:51 +00:00
										 |  |  | 	s.inboundService.AddTraffic(nil, nil) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	inbounds, err := s.inboundService.GetAllInbounds() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, inbound := range inbounds { | 
					
						
							|  |  |  | 		if !inbound.Enable { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// get settings clients
 | 
					
						
							|  |  |  | 		settings := map[string]interface{}{} | 
					
						
							|  |  |  | 		json.Unmarshal([]byte(inbound.Settings), &settings) | 
					
						
							| 
									
										
										
										
											2023-02-18 12:37:32 +00:00
										 |  |  | 		clients, ok := settings["clients"].([]interface{}) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 		if ok { | 
					
						
							|  |  |  | 			// check users active or not
 | 
					
						
							|  |  |  | 			clientStats := inbound.ClientStats | 
					
						
							|  |  |  | 			for _, clientTraffic := range clientStats { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  | 				indexDecrease := 0 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 				for index, client := range clients { | 
					
						
							|  |  |  | 					c := client.(map[string]interface{}) | 
					
						
							|  |  |  | 					if c["email"] == clientTraffic.Email { | 
					
						
							| 
									
										
										
										
											2023-02-18 12:37:32 +00:00
										 |  |  | 						if !clientTraffic.Enable { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  | 							clients = RemoveIndex(clients, index-indexDecrease) | 
					
						
							|  |  |  | 							indexDecrease++ | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 							logger.Infof("Remove Inbound User %s due to expiration or traffic limit", c["email"]) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// clear client config for additional parameters
 | 
					
						
							|  |  |  | 			var final_clients []interface{} | 
					
						
							|  |  |  | 			for _, client := range clients { | 
					
						
							|  |  |  | 				c := client.(map[string]interface{}) | 
					
						
							|  |  |  | 				if c["enable"] != nil { | 
					
						
							|  |  |  | 					if enable, ok := c["enable"].(bool); ok && !enable { | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for key := range c { | 
					
						
							| 
									
										
										
										
											2023-07-27 08:28:12 +00:00
										 |  |  | 					if key != "email" && key != "id" && key != "password" && key != "flow" && key != "method" { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  | 						delete(c, key) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2023-04-25 18:13:29 +00:00
										 |  |  | 					if c["flow"] == "xtls-rprx-vision-udp443" { | 
					
						
							|  |  |  | 						c["flow"] = "xtls-rprx-vision" | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				final_clients = append(final_clients, interface{}(c)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			settings["clients"] = final_clients | 
					
						
							| 
									
										
										
										
											2023-04-24 10:43:25 +00:00
										 |  |  | 			modifiedSettings, err := json.MarshalIndent(settings, "", "  ") | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-02-18 12:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 			inbound.Settings = string(modifiedSettings) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-08 16:21:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  | 		if len(inbound.StreamSettings) > 0 { | 
					
						
							|  |  |  | 			// Unmarshal stream JSON
 | 
					
						
							|  |  |  | 			var stream map[string]interface{} | 
					
						
							|  |  |  | 			json.Unmarshal([]byte(inbound.StreamSettings), &stream) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Remove the "settings" field under "tlsSettings" and "realitySettings"
 | 
					
						
							|  |  |  | 			tlsSettings, ok1 := stream["tlsSettings"].(map[string]interface{}) | 
					
						
							|  |  |  | 			realitySettings, ok2 := stream["realitySettings"].(map[string]interface{}) | 
					
						
							|  |  |  | 			if ok1 || ok2 { | 
					
						
							|  |  |  | 				if ok1 { | 
					
						
							|  |  |  | 					delete(tlsSettings, "settings") | 
					
						
							|  |  |  | 				} else if ok2 { | 
					
						
							|  |  |  | 					delete(realitySettings, "settings") | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-12-08 16:21:43 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			delete(stream, "externalProxy") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 16:21:43 +00:00
										 |  |  | 			newStream, err := json.MarshalIndent(stream, "", "  ") | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			inbound.StreamSettings = string(newStream) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 		inboundConfig := inbound.GenXrayInboundConfig() | 
					
						
							|  |  |  | 		xrayConfig.InboundConfigs = append(xrayConfig.InboundConfigs, *inboundConfig) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return xrayConfig, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, error) { | 
					
						
							|  |  |  | 	if !s.IsXrayRunning() { | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 		err := errors.New("xray is not running") | 
					
						
							|  |  |  | 		logger.Debug("Attempted to fetch Xray traffic, but Xray is not running:", err) | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 	apiPort := p.GetAPIPort() | 
					
						
							|  |  |  | 	s.xrayAPI.Init(apiPort) | 
					
						
							| 
									
										
										
										
											2023-06-04 21:02:19 +00:00
										 |  |  | 	defer s.xrayAPI.Close() | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	traffic, clientTraffic, err := s.xrayAPI.GetTraffic(true) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		logger.Debug("Failed to fetch Xray traffic:", err) | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return traffic, clientTraffic, nil | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) RestartXray(isForce bool) error { | 
					
						
							|  |  |  | 	lock.Lock() | 
					
						
							|  |  |  | 	defer lock.Unlock() | 
					
						
							|  |  |  | 	logger.Debug("restart xray, force:", isForce) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xrayConfig, err := s.GetXrayConfig() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-01 15:07:56 +00:00
										 |  |  | 	if s.IsXrayRunning() { | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 		if !isForce && p.GetConfig().Equals(xrayConfig) { | 
					
						
							| 
									
										
										
										
											2023-06-04 21:02:19 +00:00
										 |  |  | 			logger.Debug("It does not need to restart xray") | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		p.Stop() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = xray.NewProcess(xrayConfig) | 
					
						
							|  |  |  | 	result = "" | 
					
						
							| 
									
										
										
										
											2023-06-04 21:02:19 +00:00
										 |  |  | 	err = p.Start() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) StopXray() error { | 
					
						
							|  |  |  | 	lock.Lock() | 
					
						
							|  |  |  | 	defer lock.Unlock() | 
					
						
							| 
									
										
										
										
											2024-07-08 21:08:00 +00:00
										 |  |  | 	logger.Debug("Attempting to stop Xray...") | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | 	if s.IsXrayRunning() { | 
					
						
							|  |  |  | 		return p.Stop() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return errors.New("xray is not running") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) SetToNeedRestart() { | 
					
						
							|  |  |  | 	isNeedXrayRestart.Store(true) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *XrayService) IsNeedRestartAndSetFalse() bool { | 
					
						
							| 
									
										
										
										
											2023-03-17 16:07:49 +00:00
										 |  |  | 	return isNeedXrayRestart.CompareAndSwap(true, false) | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | } |