123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- package service
- import (
- "encoding/json"
- "errors"
- "sync"
- "x-ui/logger"
- "x-ui/xray"
- "go.uber.org/atomic"
- )
- var (
- p *xray.Process
- lock sync.Mutex
- isNeedXrayRestart atomic.Bool
- result string
- )
- type XrayService struct {
- inboundService InboundService
- settingService SettingService
- xrayAPI xray.XrayAPI
- }
- 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()
- }
- 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
- }
- s.inboundService.AddTraffic(nil, nil)
- 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)
- clients, ok := settings["clients"].([]interface{})
- if ok {
- // check users active or not
- clientStats := inbound.ClientStats
- for _, clientTraffic := range clientStats {
- indexDecrease := 0
- for index, client := range clients {
- c := client.(map[string]interface{})
- if c["email"] == clientTraffic.Email {
- if !clientTraffic.Enable {
- clients = RemoveIndex(clients, index-indexDecrease)
- indexDecrease++
- logger.Infof("Remove Inbound User %s due to expiration or traffic limit", c["email"])
- }
- }
- }
- }
- // 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 {
- if key != "email" && key != "id" && key != "password" && key != "flow" && key != "method" {
- delete(c, key)
- }
- if c["flow"] == "xtls-rprx-vision-udp443" {
- c["flow"] = "xtls-rprx-vision"
- }
- }
- final_clients = append(final_clients, interface{}(c))
- }
- settings["clients"] = final_clients
- modifiedSettings, err := json.MarshalIndent(settings, "", " ")
- if err != nil {
- return nil, err
- }
- inbound.Settings = string(modifiedSettings)
- }
- 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")
- }
- }
- delete(stream, "externalProxy")
- newStream, err := json.MarshalIndent(stream, "", " ")
- if err != nil {
- return nil, err
- }
- inbound.StreamSettings = string(newStream)
- }
- inboundConfig := inbound.GenXrayInboundConfig()
- xrayConfig.InboundConfigs = append(xrayConfig.InboundConfigs, *inboundConfig)
- }
- return xrayConfig, nil
- }
- func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, error) {
- if !s.IsXrayRunning() {
- err := errors.New("xray is not running")
- logger.Debug("Attempted to fetch Xray traffic, but Xray is not running:", err)
- return nil, nil, err
- }
- apiPort := p.GetAPIPort()
- s.xrayAPI.Init(apiPort)
- defer s.xrayAPI.Close()
- 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
- }
- 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
- }
- if s.IsXrayRunning() {
- if !isForce && p.GetConfig().Equals(xrayConfig) {
- logger.Debug("It does not need to restart xray")
- return nil
- }
- p.Stop()
- }
- p = xray.NewProcess(xrayConfig)
- result = ""
- err = p.Start()
- if err != nil {
- return err
- }
- return nil
- }
- func (s *XrayService) StopXray() error {
- lock.Lock()
- defer lock.Unlock()
- logger.Debug("Attempting to stop Xray...")
- 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 {
- return isNeedXrayRestart.CompareAndSwap(true, false)
- }
|