2023-02-09 22:18:06 +03:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"sync"
|
|
|
|
"x-ui/logger"
|
|
|
|
"x-ui/xray"
|
2023-02-18 15:37:32 +03:00
|
|
|
|
2023-02-09 22:18:06 +03:00
|
|
|
"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
|
2023-06-05 00:02:19 +03:00
|
|
|
xrayAPI xray.XrayAPI
|
2023-02-09 22:18:06 +03: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 15:37:32 +03:00
|
|
|
|
2023-02-09 22:18:06 +03: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 14:49:51 +03:00
|
|
|
s.inboundService.AddTraffic(nil, nil)
|
2023-02-09 22:18:06 +03: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 15:37:32 +03:00
|
|
|
clients, ok := settings["clients"].([]interface{})
|
2023-02-09 22:18:06 +03:00
|
|
|
if ok {
|
|
|
|
// check users active or not
|
|
|
|
clientStats := inbound.ClientStats
|
|
|
|
for _, clientTraffic := range clientStats {
|
2023-02-18 15:37:32 +03:00
|
|
|
|
2023-04-09 22:43:18 +03:00
|
|
|
indexDecrease := 0
|
2023-02-09 22:18:06 +03:00
|
|
|
for index, client := range clients {
|
|
|
|
c := client.(map[string]interface{})
|
|
|
|
if c["email"] == clientTraffic.Email {
|
2023-02-18 15:37:32 +03:00
|
|
|
if !clientTraffic.Enable {
|
2023-04-09 22:43:18 +03:00
|
|
|
clients = RemoveIndex(clients, index-indexDecrease)
|
|
|
|
indexDecrease++
|
2023-02-18 15:37:32 +03:00
|
|
|
logger.Info("Remove Inbound User", c["email"], "due the expire or traffic limit")
|
2023-02-09 22:18:06 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-04-09 22:43:18 +03: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 11:28:12 +03:00
|
|
|
if key != "email" && key != "id" && key != "password" && key != "flow" && key != "method" {
|
2023-04-09 22:43:18 +03:00
|
|
|
delete(c, key)
|
|
|
|
}
|
2023-04-25 21:13:29 +03:00
|
|
|
if c["flow"] == "xtls-rprx-vision-udp443" {
|
|
|
|
c["flow"] = "xtls-rprx-vision"
|
|
|
|
}
|
2023-04-09 22:43:18 +03:00
|
|
|
}
|
|
|
|
final_clients = append(final_clients, interface{}(c))
|
|
|
|
}
|
|
|
|
|
|
|
|
settings["clients"] = final_clients
|
2023-04-24 13:43:25 +03:00
|
|
|
modifiedSettings, err := json.MarshalIndent(settings, "", " ")
|
2023-02-09 22:18:06 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-18 15:37:32 +03:00
|
|
|
|
2023-02-09 22:18:06 +03:00
|
|
|
inbound.Settings = string(modifiedSettings)
|
|
|
|
}
|
2023-12-08 19:21:43 +03:00
|
|
|
|
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
newStream, err := json.MarshalIndent(stream, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
inbound.StreamSettings = string(newStream)
|
|
|
|
}
|
|
|
|
|
2023-02-09 22:18:06 +03: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() {
|
|
|
|
return nil, nil, errors.New("xray is not running")
|
|
|
|
}
|
2023-06-05 00:02:19 +03:00
|
|
|
s.xrayAPI.Init(p.GetAPIPort())
|
|
|
|
defer s.xrayAPI.Close()
|
|
|
|
return s.xrayAPI.GetTraffic(true)
|
2023-02-09 22:18:06 +03: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
|
|
|
|
}
|
|
|
|
|
|
|
|
if p != nil && p.IsRunning() {
|
|
|
|
if !isForce && p.GetConfig().Equals(xrayConfig) {
|
2023-06-05 00:02:19 +03:00
|
|
|
logger.Debug("It does not need to restart xray")
|
2023-02-09 22:18:06 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
p.Stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
p = xray.NewProcess(xrayConfig)
|
|
|
|
result = ""
|
2023-06-05 00:02:19 +03:00
|
|
|
err = p.Start()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2023-02-09 22:18:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-03-17 19:07:49 +03:00
|
|
|
return isNeedXrayRestart.CompareAndSwap(true, false)
|
2023-02-09 22:18:06 +03:00
|
|
|
}
|