Files
x-ui/web/service/xray.go
SudoSpace 0c9816b7ba Bug Fix
Bug fix, can't connect after change transmission type from tcp to other types

If flow is not equal to "" in transmit except tcp, connection will not be made. This problem occurs when we change the transmission from tcp to another type. Also, if tcp itself is alone and without tls and reality, flow must be empty in it.
2023-07-08 19:52:35 +03:30

206 lines
4.4 KiB
Go

package service
import (
"encoding/json"
"errors"
"sync"
"x-ui/logger"
"x-ui/xray"
"go.uber.org/atomic"
)
var p *xray.Process
var lock sync.Mutex
var isNeedXrayRestart atomic.Bool
var 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.DisableInvalidClients()
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.Info("Remove Inbound User", c["email"], "due the expire or traffic limit")
}
}
}
}
// clear client config for additional parameters
var final_clients []interface{}
// detect inbound transmission type
var stream map[string]interface{}
json.Unmarshal([]byte(inbound.StreamSettings), &stream)
network, _ := stream["network"].(string)
security, _ := stream["security"].(string)
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" {
delete(c, key)
}
if c["flow"] == "xtls-rprx-vision-udp443" {
c["flow"] = "xtls-rprx-vision"
}
if network != "tcp" || !(security == "tls" || security == "reality") {
c["flow"] = ""
}
}
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)
}
inboundConfig := inbound.GenXrayInboundConfig()
xrayConfig.InboundConfigs = append(xrayConfig.InboundConfigs, *inboundConfig)
}
return xrayConfig, nil
}
func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic, error) {
if !s.IsXrayRunning() {
return nil, nil, errors.New("xray is not running")
}
s.xrayAPI.Init(p.GetAPIPort())
defer s.xrayAPI.Close()
return s.xrayAPI.GetTraffic(true)
}
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 p != nil && p.IsRunning() {
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("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)
}