diff options
| author | MHSanaei <ho3ein.sanaei@gmail.com> | 2023-04-09 22:43:18 +0300 |
|---|---|---|
| committer | MHSanaei <ho3ein.sanaei@gmail.com> | 2023-04-09 22:43:18 +0300 |
| commit | e1da43053d23c995bcd6e7267cb20042398cd64f (patch) | |
| tree | 08c4c371ba070ef765ec2be83270ee6032e54774 /web/service | |
| parent | 3bb90cbf2463b31c6a921f7cd75cf32edd3a37f0 (diff) | |
alireza update pack
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
Diffstat (limited to 'web/service')
| -rw-r--r-- | web/service/inbound.go | 126 | ||||
| -rw-r--r-- | web/service/server.go | 4 | ||||
| -rw-r--r-- | web/service/setting.go | 36 | ||||
| -rw-r--r-- | web/service/sub.go | 505 | ||||
| -rw-r--r-- | web/service/tgbot.go | 32 | ||||
| -rw-r--r-- | web/service/xray.go | 27 |
6 files changed, 672 insertions, 58 deletions
diff --git a/web/service/inbound.go b/web/service/inbound.go index 9814b549..55d57997 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -394,11 +394,16 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e if len(traffics) == 0 { return nil } - db := database.GetDB() - dbInbound := db.Model(model.Inbound{}) + traffics, err = s.adjustTraffics(traffics) + if err != nil { + return err + } + + db := database.GetDB() db = db.Model(xray.ClientTraffic{}) tx := db.Begin() + defer func() { if err != nil { tx.Rollback() @@ -406,7 +411,20 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e tx.Commit() } }() + + err = tx.Save(traffics).Error + if err != nil { + logger.Warning("AddClientTraffic update data ", err) + } + + return nil +} + +func (s *InboundService) adjustTraffics(traffics []*xray.ClientTraffic) (full_traffics []*xray.ClientTraffic, err error) { + db := database.GetDB() + dbInbound := db.Model(model.Inbound{}) txInbound := dbInbound.Begin() + defer func() { if err != nil { txInbound.Rollback() @@ -415,22 +433,23 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e } }() - for _, traffic := range traffics { + for traffic_index, traffic := range traffics { inbound := &model.Inbound{} - client := &xray.ClientTraffic{} - err := tx.Where("email = ?", traffic.Email).First(client).Error + client_traffic := &xray.ClientTraffic{} + err := db.Model(xray.ClientTraffic{}).Where("email = ?", traffic.Email).First(client_traffic).Error if err != nil { if err == gorm.ErrRecordNotFound { logger.Warning(err, traffic.Email) } continue } + client_traffic.Up += traffic.Up + client_traffic.Down += traffic.Down - err = txInbound.Where("id=?", client.InboundId).First(inbound).Error + err = txInbound.Where("id=?", client_traffic.InboundId).First(inbound).Error if err != nil { if err == gorm.ErrRecordNotFound { logger.Warning(err, traffic.Email) - } continue } @@ -438,29 +457,35 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e settings := map[string][]model.Client{} json.Unmarshal([]byte(inbound.Settings), &settings) clients := settings["clients"] - for _, client := range clients { + needUpdate := false + for client_index, client := range clients { if traffic.Email == client.Email { - traffic.ExpiryTime = client.ExpiryTime - traffic.Total = client.TotalGB + if client.ExpiryTime < 0 { + clients[client_index].ExpiryTime = (time.Now().Unix() * 1000) - client.ExpiryTime + needUpdate = true + } + client_traffic.ExpiryTime = client.ExpiryTime + client_traffic.Total = client.TotalGB + break } } - if tx.Where("inbound_id = ? and email = ?", inbound.Id, traffic.Email). - UpdateColumns(map[string]interface{}{ - "enable": true, - "expiry_time": traffic.ExpiryTime, - "total": traffic.Total, - "up": gorm.Expr("up + ?", traffic.Up), - "down": gorm.Expr("down + ?", traffic.Down)}).RowsAffected == 0 { - err = tx.Create(traffic).Error - } - if err != nil { - logger.Warning("AddClientTraffic update data ", err) - continue + if needUpdate { + settings["clients"] = clients + modifiedSettings, err := json.MarshalIndent(settings, "", " ") + if err != nil { + return nil, err + } + + err = txInbound.Where("id=?", inbound.Id).Update("settings", string(modifiedSettings)).Error + if err != nil { + return nil, err + } } + traffics[traffic_index] = client_traffic } - return + return traffics, nil } func (s *InboundService) DisableInvalidInbounds() (int64, error) { @@ -545,11 +570,58 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) error { } return nil } -func (s *InboundService) GetClientTrafficTgBot(tguname string) (traffic []*xray.ClientTraffic, err error) { + +func (s *InboundService) ResetAllClientTraffics(id int) error { db := database.GetDB() - var traffics []*xray.ClientTraffic - err = db.Model(xray.ClientTraffic{}).Where("email like ?", "%@"+tguname).Find(&traffics).Error + result := db.Model(xray.ClientTraffic{}). + Where("inbound_id = ?", id). + Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0}) + + err := result.Error + + if err != nil { + return err + } + return nil +} + +func (s *InboundService) ResetAllTraffics() error { + db := database.GetDB() + + result := db.Model(model.Inbound{}). + Where("user_id > ?", 0). + Updates(map[string]interface{}{"up": 0, "down": 0}) + + err := result.Error + + if err != nil { + return err + } + return nil +} + +func (s *InboundService) GetClientTrafficTgBot(tguname string) ([]*xray.ClientTraffic, error) { + db := database.GetDB() + var inbounds []*model.Inbound + err := db.Model(model.Inbound{}).Where("settings like ?", fmt.Sprintf(`%%"tgId": "%s"%%`, tguname)).Find(&inbounds).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + var emails []string + for _, inbound := range inbounds { + clients, err := s.getClients(inbound) + if err != nil { + logger.Error("Unable to get clients from inbound") + } + for _, client := range clients { + if client.TgID == tguname { + emails = append(emails, client.Email) + } + } + } + var traffics []*xray.ClientTraffic + err = db.Model(xray.ClientTraffic{}).Where("email IN ?", emails).Find(&traffics).Error if err != nil { if err == gorm.ErrRecordNotFound { logger.Warning(err) @@ -643,4 +715,4 @@ func (s *InboundService) SearchInbounds(query string) ([]*model.Inbound, error) return nil, err } return inbounds, nil -}
\ No newline at end of file +} diff --git a/web/service/server.go b/web/service/server.go index 5e6065b5..91f9399a 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -327,11 +327,11 @@ func (s *ServerService) UpdateXray(version string) error { } -func (s *ServerService) GetLogs() ([]string, error) { +func (s *ServerService) GetLogs(count string) ([]string, error) { // Define the journalctl command and its arguments var cmdArgs []string if runtime.GOOS == "linux" { - cmdArgs = []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", "100"} + cmdArgs = []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", count} } else { return []string{"Unsupported operating system"}, nil } diff --git a/web/service/setting.go b/web/service/setting.go index c30bb929..ff22f847 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -28,14 +28,14 @@ var defaultValueMap = map[string]string{ "webKeyFile": "", "secret": random.Seq(32), "webBasePath": "/", + "expireDiff": "0", + "trafficDiff": "0", "timeLocation": "Asia/Tehran", "tgBotEnable": "false", "tgBotToken": "", "tgBotChatId": "", "tgRunTime": "@daily", "tgBotBackup": "false", - "tgExpireDiff": "0", - "tgTrafficDiff": "0", "tgCpu": "0", } @@ -238,22 +238,6 @@ func (s *SettingService) SetTgBotBackup(value bool) error { return s.setBool("tgBotBackup", value) } -func (s *SettingService) GetTgExpireDiff() (int, error) { - return s.getInt("tgExpireDiff") -} - -func (s *SettingService) SetTgExpireDiff(value int) error { - return s.setInt("tgExpireDiff", value) -} - -func (s *SettingService) GetTgTrafficDiff() (int, error) { - return s.getInt("tgTrafficDiff") -} - -func (s *SettingService) SetTgTrafficDiff(value int) error { - return s.setInt("tgTrafficDiff", value) -} - func (s *SettingService) GetTgCpu() (int, error) { return s.getInt("tgCpu") } @@ -278,6 +262,22 @@ func (s *SettingService) GetKeyFile() (string, error) { return s.getString("webKeyFile") } +func (s *SettingService) GetExpireDiff() (int, error) { + return s.getInt("expireDiff") +} + +func (s *SettingService) SetExpireDiff(value int) error { + return s.setInt("expireDiff", value) +} + +func (s *SettingService) GetTrafficDiff() (int, error) { + return s.getInt("trafficDiff") +} + +func (s *SettingService) SetgetTrafficDiff(value int) error { + return s.setInt("trafficDiff", value) +} + func (s *SettingService) GetSecret() ([]byte, error) { secret, err := s.getString("secret") if secret == defaultValueMap["secret"] { diff --git a/web/service/sub.go b/web/service/sub.go new file mode 100644 index 00000000..875a5b53 --- /dev/null +++ b/web/service/sub.go @@ -0,0 +1,505 @@ +package service + +import ( + "encoding/base64" + "fmt" + "net/url" + "strings" + "x-ui/database" + "x-ui/database/model" + "x-ui/logger" + + "github.com/goccy/go-json" + "gorm.io/gorm" +) + +type SubService struct { + address string + inboundService InboundService +} + +func (s *SubService) GetSubs(subId string, host string) ([]string, error) { + s.address = host + var result []string + inbounds, err := s.getInboundsBySubId(subId) + if err != nil { + return nil, err + } + for _, inbound := range inbounds { + clients, err := s.inboundService.getClients(inbound) + if err != nil { + logger.Error("SubService - GetSub: Unable to get clients from inbound") + } + if clients == nil { + continue + } + for _, client := range clients { + if client.SubID == subId { + link := s.getLink(inbound, client.Email) + result = append(result, link) + } + } + } + return result, nil +} + +func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) { + db := database.GetDB() + var inbounds []*model.Inbound + err := db.Model(model.Inbound{}).Where("settings like ?", fmt.Sprintf(`%%"subId": "%s"%%`, subId)).Find(&inbounds).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + return inbounds, nil +} + +func (s *SubService) getLink(inbound *model.Inbound, email string) string { + switch inbound.Protocol { + case "vmess": + return s.genVmessLink(inbound, email) + case "vless": + return s.genVlessLink(inbound, email) + case "trojan": + return s.genTrojanLink(inbound, email) + } + return "" +} + +func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string { + address := s.address + if inbound.Protocol != model.VMess { + return "" + } + var stream map[string]interface{} + json.Unmarshal([]byte(inbound.StreamSettings), &stream) + network, _ := stream["network"].(string) + typeStr := "none" + host := "" + path := "" + sni := "" + fp := "" + var alpn []string + allowInsecure := false + switch network { + case "tcp": + tcp, _ := stream["tcpSettings"].(map[string]interface{}) + header, _ := tcp["header"].(map[string]interface{}) + typeStr, _ = header["type"].(string) + if typeStr == "http" { + request := header["request"].(map[string]interface{}) + requestPath, _ := request["path"].([]interface{}) + path = requestPath[0].(string) + headers, _ := request["headers"].(map[string]interface{}) + host = searchHost(headers) + } + case "kcp": + kcp, _ := stream["kcpSettings"].(map[string]interface{}) + header, _ := kcp["header"].(map[string]interface{}) + typeStr, _ = header["type"].(string) + path, _ = kcp["seed"].(string) + case "ws": + ws, _ := stream["wsSettings"].(map[string]interface{}) + path = ws["path"].(string) + headers, _ := ws["headers"].(map[string]interface{}) + host = searchHost(headers) + case "http": + network = "h2" + http, _ := stream["httpSettings"].(map[string]interface{}) + path, _ = http["path"].(string) + host = searchHost(http) + case "quic": + quic, _ := stream["quicSettings"].(map[string]interface{}) + header := quic["header"].(map[string]interface{}) + typeStr, _ = header["type"].(string) + host, _ = quic["security"].(string) + path, _ = quic["key"].(string) + case "grpc": + grpc, _ := stream["grpcSettings"].(map[string]interface{}) + path = grpc["serviceName"].(string) + } + + security, _ := stream["security"].(string) + if security == "tls" { + tlsSetting, _ := stream["tlsSettings"].(map[string]interface{}) + alpns, _ := tlsSetting["alpn"].([]interface{}) + for _, a := range alpns { + alpn = append(alpn, a.(string)) + } + tlsSettings, _ := searchKey(tlsSetting, "settings") + if tlsSetting != nil { + if sniValue, ok := searchKey(tlsSettings, "serverName"); ok { + sni, _ = sniValue.(string) + } + if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { + fp, _ = fpValue.(string) + } + if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { + allowInsecure, _ = insecure.(bool) + } + } + serverName, _ := tlsSetting["serverName"].(string) + if serverName != "" { + address = serverName + } + } + + clients, _ := s.inboundService.getClients(inbound) + clientIndex := -1 + for i, client := range clients { + if client.Email == email { + clientIndex = i + break + } + } + + obj := map[string]interface{}{ + "v": "2", + "ps": email, + "add": address, + "port": inbound.Port, + "id": clients[clientIndex].ID, + "aid": clients[clientIndex].AlterIds, + "net": network, + "type": typeStr, + "host": host, + "path": path, + "tls": security, + "sni": sni, + "fp": fp, + "alpn": strings.Join(alpn, ","), + "allowInsecure": allowInsecure, + } + jsonStr, _ := json.MarshalIndent(obj, "", " ") + return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr) +} + +func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { + address := s.address + if inbound.Protocol != model.VLESS { + return "" + } + var stream map[string]interface{} + json.Unmarshal([]byte(inbound.StreamSettings), &stream) + clients, _ := s.inboundService.getClients(inbound) + clientIndex := -1 + for i, client := range clients { + if client.Email == email { + clientIndex = i + break + } + } + uuid := clients[clientIndex].ID + port := inbound.Port + streamNetwork := stream["network"].(string) + params := make(map[string]string) + params["type"] = streamNetwork + + switch streamNetwork { + case "tcp": + tcp, _ := stream["tcpSettings"].(map[string]interface{}) + header, _ := tcp["header"].(map[string]interface{}) + typeStr, _ := header["type"].(string) + if typeStr == "http" { + request := header["request"].(map[string]interface{}) + requestPath, _ := request["path"].([]interface{}) + params["path"] = requestPath[0].(string) + headers, _ := request["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + params["headerType"] = "http" + } + case "kcp": + kcp, _ := stream["kcpSettings"].(map[string]interface{}) + header, _ := kcp["header"].(map[string]interface{}) + params["headerType"] = header["type"].(string) + params["seed"] = kcp["seed"].(string) + case "ws": + ws, _ := stream["wsSettings"].(map[string]interface{}) + params["path"] = ws["path"].(string) + headers, _ := ws["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + case "http": + http, _ := stream["httpSettings"].(map[string]interface{}) + params["path"] = http["path"].(string) + params["host"] = searchHost(http) + case "quic": + quic, _ := stream["quicSettings"].(map[string]interface{}) + params["quicSecurity"] = quic["security"].(string) + params["key"] = quic["key"].(string) + header := quic["header"].(map[string]interface{}) + params["headerType"] = header["type"].(string) + case "grpc": + grpc, _ := stream["grpcSettings"].(map[string]interface{}) + params["serviceName"] = grpc["serviceName"].(string) + } + + security, _ := stream["security"].(string) + if security == "tls" { + params["security"] = "tls" + tlsSetting, _ := stream["tlsSettings"].(map[string]interface{}) + alpns, _ := tlsSetting["alpn"].([]interface{}) + var alpn []string + for _, a := range alpns { + alpn = append(alpn, a.(string)) + } + if len(alpn) > 0 { + params["alpn"] = strings.Join(alpn, ",") + } + tlsSettings, _ := searchKey(tlsSetting, "settings") + if tlsSetting != nil { + if sniValue, ok := searchKey(tlsSettings, "serverName"); ok { + params["sni"], _ = sniValue.(string) + } + if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { + params["fp"], _ = fpValue.(string) + } + if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { + if insecure.(bool) { + params["allowInsecure"] = "1" + } + } + } + + if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { + params["flow"] = clients[clientIndex].Flow + } + + serverName, _ := tlsSetting["serverName"].(string) + if serverName != "" { + address = serverName + } + } + + if security == "xtls" { + params["security"] = "xtls" + xtlsSetting, _ := stream["xtlsSettings"].(map[string]interface{}) + alpns, _ := xtlsSetting["alpn"].([]interface{}) + var alpn []string + for _, a := range alpns { + alpn = append(alpn, a.(string)) + } + if len(alpn) > 0 { + params["alpn"] = strings.Join(alpn, ",") + } + + xtlsSettings, _ := searchKey(xtlsSetting, "settings") + if xtlsSetting != nil { + if sniValue, ok := searchKey(xtlsSettings, "serverName"); ok { + params["sni"], _ = sniValue.(string) + } + if fpValue, ok := searchKey(xtlsSettings, "fingerprint"); ok { + params["fp"], _ = fpValue.(string) + } + if insecure, ok := searchKey(xtlsSettings, "allowInsecure"); ok { + if insecure.(bool) { + params["allowInsecure"] = "1" + } + } + } + + if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { + params["flow"] = clients[clientIndex].Flow + } + + serverName, _ := xtlsSetting["serverName"].(string) + if serverName != "" { + address = serverName + } + } + + link := fmt.Sprintf("vless://%s@%s:%d", uuid, address, port) + url, _ := url.Parse(link) + q := url.Query() + + for k, v := range params { + q.Add(k, v) + } + + // Set the new query values on the URL + url.RawQuery = q.Encode() + + url.Fragment = email + return url.String() +} + +func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string { + address := s.address + if inbound.Protocol != model.Trojan { + return "" + } + var stream map[string]interface{} + json.Unmarshal([]byte(inbound.StreamSettings), &stream) + clients, _ := s.inboundService.getClients(inbound) + clientIndex := -1 + for i, client := range clients { + if client.Email == email { + clientIndex = i + break + } + } + password := clients[clientIndex].Password + port := inbound.Port + streamNetwork := stream["network"].(string) + params := make(map[string]string) + params["type"] = streamNetwork + + switch streamNetwork { + case "tcp": + tcp, _ := stream["tcpSettings"].(map[string]interface{}) + header, _ := tcp["header"].(map[string]interface{}) + typeStr, _ := header["type"].(string) + if typeStr == "http" { + request := header["request"].(map[string]interface{}) + requestPath, _ := request["path"].([]interface{}) + params["path"] = requestPath[0].(string) + headers, _ := request["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + params["headerType"] = "http" + } + case "kcp": + kcp, _ := stream["kcpSettings"].(map[string]interface{}) + header, _ := kcp["header"].(map[string]interface{}) + params["headerType"] = header["type"].(string) + params["seed"] = kcp["seed"].(string) + case "ws": + ws, _ := stream["wsSettings"].(map[string]interface{}) + params["path"] = ws["path"].(string) + headers, _ := ws["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + case "http": + http, _ := stream["httpSettings"].(map[string]interface{}) + params["path"] = http["path"].(string) + params["host"] = searchHost(http) + case "quic": + quic, _ := stream["quicSettings"].(map[string]interface{}) + params["quicSecurity"] = quic["security"].(string) + params["key"] = quic["key"].(string) + header := quic["header"].(map[string]interface{}) + params["headerType"] = header["type"].(string) + case "grpc": + grpc, _ := stream["grpcSettings"].(map[string]interface{}) + params["serviceName"] = grpc["serviceName"].(string) + } + + security, _ := stream["security"].(string) + if security == "tls" { + params["security"] = "tls" + tlsSetting, _ := stream["tlsSettings"].(map[string]interface{}) + alpns, _ := tlsSetting["alpn"].([]interface{}) + var alpn []string + for _, a := range alpns { + alpn = append(alpn, a.(string)) + } + if len(alpn) > 0 { + params["alpn"] = strings.Join(alpn, ",") + } + tlsSettings, _ := searchKey(tlsSetting, "settings") + if tlsSetting != nil { + if sniValue, ok := searchKey(tlsSettings, "serverName"); ok { + params["sni"], _ = sniValue.(string) + } + if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { + params["fp"], _ = fpValue.(string) + } + if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { + if insecure.(bool) { + params["allowInsecure"] = "1" + } + } + } + + serverName, _ := tlsSetting["serverName"].(string) + if serverName != "" { + address = serverName + } + } + + if security == "xtls" { + params["security"] = "xtls" + xtlsSetting, _ := stream["xtlsSettings"].(map[string]interface{}) + alpns, _ := xtlsSetting["alpn"].([]interface{}) + var alpn []string + for _, a := range alpns { + alpn = append(alpn, a.(string)) + } + if len(alpn) > 0 { + params["alpn"] = strings.Join(alpn, ",") + } + + xtlsSettings, _ := searchKey(xtlsSetting, "settings") + if xtlsSetting != nil { + if sniValue, ok := searchKey(xtlsSettings, "serverName"); ok { + params["sni"], _ = sniValue.(string) + } + if fpValue, ok := searchKey(xtlsSettings, "fingerprint"); ok { + params["fp"], _ = fpValue.(string) + } + if insecure, ok := searchKey(xtlsSettings, "allowInsecure"); ok { + if insecure.(bool) { + params["allowInsecure"] = "1" + } + } + } + + if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { + params["flow"] = clients[clientIndex].Flow + } + + serverName, _ := xtlsSetting["serverName"].(string) + if serverName != "" { + address = serverName + } + } + + link := fmt.Sprintf("trojan://%s@%s:%d", password, address, port) + + url, _ := url.Parse(link) + q := url.Query() + + for k, v := range params { + q.Add(k, v) + } + + // Set the new query values on the URL + url.RawQuery = q.Encode() + + url.Fragment = email + return url.String() +} + +func searchKey(data interface{}, key string) (interface{}, bool) { + switch val := data.(type) { + case map[string]interface{}: + for k, v := range val { + if k == key { + return v, true + } + if result, ok := searchKey(v, key); ok { + return result, true + } + } + case []interface{}: + for _, v := range val { + if result, ok := searchKey(v, key); ok { + return result, true + } + } + } + return nil, false +} + +func searchHost(headers interface{}) string { + data, _ := headers.(map[string]interface{}) + for k, v := range data { + if strings.EqualFold(k, "host") { + switch v.(type) { + case []interface{}: + hosts, _ := v.([]interface{}) + return hosts[0].(string) + case interface{}: + return v.(string) + } + } + } + + return "" +} diff --git a/web/service/tgbot.go b/web/service/tgbot.go index 86097b0f..2ab3dbb0 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -160,14 +160,14 @@ func (t *Tgbot) asnwerCallback(callbackQuery *tgbotapi.CallbackQuery, isAdmin bo t.SendMsgToTgbot(callbackQuery.From.ID, t.getServerUsage()) case "inbounds": t.SendMsgToTgbot(callbackQuery.From.ID, t.getInboundUsages()) - case "exhausted_soon": + case "deplete_soon": t.SendMsgToTgbot(callbackQuery.From.ID, t.getExhausted()) case "get_backup": t.sendBackup(callbackQuery.From.ID) case "client_traffic": t.getClientUsage(callbackQuery.From.ID, callbackQuery.From.UserName) case "client_commands": - t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Passowrd]</code>\r\n \r\nUse UID for vmess and vless and Password for Trojan.") + t.SendMsgToTgbot(callbackQuery.From.ID, "To search for statistics, just use folowing command:\r\n \r\n<code>/usage [UID|Passowrd]</code>\r\n \r\nUse UID for vmess/vless and Password for Trojan.") case "commands": t.SendMsgToTgbot(callbackQuery.From.ID, "Search for a client email:\r\n<code>/usage email</code>\r\n \r\nSearch for inbounds (with client stats):\r\n<code>/inbound [remark]</code>") } @@ -190,7 +190,7 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { ), tgbotapi.NewInlineKeyboardRow( tgbotapi.NewInlineKeyboardButtonData("Get Inbounds", "inbounds"), - tgbotapi.NewInlineKeyboardButtonData("Exhausted soon", "exhausted_soon"), + tgbotapi.NewInlineKeyboardButtonData("Deplete soon", "deplete_soon"), ), tgbotapi.NewInlineKeyboardRow( tgbotapi.NewInlineKeyboardButtonData("Commands", "commands"), @@ -363,6 +363,11 @@ func (t *Tgbot) getInboundUsages() string { } func (t *Tgbot) getClientUsage(chatId int64, tgUserName string) { + if len(tgUserName) == 0 { + msg := "Your configuration is not found!\nYou should configure your telegram username and ask Admin to add it to your configuration." + t.SendMsgToTgbot(chatId, msg) + return + } traffics, err := t.inboundService.GetClientTrafficTgBot(tgUserName) if err != nil { logger.Warning(err) @@ -373,11 +378,14 @@ func (t *Tgbot) getClientUsage(chatId int64, tgUserName string) { if len(traffics) == 0 { msg := "Your configuration is not found!\nPlease ask your Admin to use your telegram username in your configuration(s).\n\nYour username: <b>@" + tgUserName + "</b>" t.SendMsgToTgbot(chatId, msg) + return } for _, traffic := range traffics { expiryTime := "" if traffic.ExpiryTime == 0 { expiryTime = "♾Unlimited" + } else if traffic.ExpiryTime < 0 { + expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000) } else { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } @@ -412,6 +420,8 @@ func (t *Tgbot) searchClient(chatId int64, email string) { expiryTime := "" if traffic.ExpiryTime == 0 { expiryTime = "♾Unlimited" + } else if traffic.ExpiryTime < 0 { + expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000) } else { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } @@ -450,6 +460,8 @@ func (t *Tgbot) searchInbound(chatId int64, remark string) { expiryTime := "" if traffic.ExpiryTime == 0 { expiryTime = "♾Unlimited" + } else if traffic.ExpiryTime < 0 { + expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000) } else { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } @@ -483,6 +495,8 @@ func (t *Tgbot) searchForClient(chatId int64, query string) { expiryTime := "" if traffic.ExpiryTime == 0 { expiryTime = "♾Unlimited" + } else if traffic.ExpiryTime < 0 { + expiryTime = fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000) } else { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } @@ -507,13 +521,13 @@ func (t *Tgbot) getExhausted() string { var disabledInbounds []model.Inbound var disabledClients []xray.ClientTraffic output := "" - TrafficThreshold, err := t.settingService.GetTgTrafficDiff() + TrafficThreshold, err := t.settingService.GetTrafficDiff() if err == nil && TrafficThreshold > 0 { trDiff = int64(TrafficThreshold) * 1073741824 } - ExpireThreshold, err := t.settingService.GetTgExpireDiff() + ExpireThreshold, err := t.settingService.GetExpireDiff() if err == nil && ExpireThreshold > 0 { - exDiff = int64(ExpireThreshold) * 84600000 + exDiff = int64(ExpireThreshold) * 86400000 } inbounds, err := t.inboundService.GetAllInbounds() if err != nil { @@ -541,7 +555,7 @@ func (t *Tgbot) getExhausted() string { disabledInbounds = append(disabledInbounds, *inbound) } } - output += fmt.Sprintf("Exhausted Inbounds count:\r\n🛑 Disabled: %d\r\n🔜 Exhaust soon: %d\r\n \r\n", len(disabledInbounds), len(exhaustedInbounds)) + output += fmt.Sprintf("Exhausted Inbounds count:\r\n🛑 Disabled: %d\r\n🔜 Deplete soon: %d\r\n \r\n", len(disabledInbounds), len(exhaustedInbounds)) if len(exhaustedInbounds) > 0 { output += "Exhausted Inbounds:\r\n" for _, inbound := range exhaustedInbounds { @@ -553,13 +567,15 @@ func (t *Tgbot) getExhausted() string { } } } - output += fmt.Sprintf("Exhausted Clients count:\r\n🛑 Disabled: %d\r\n🔜 Exhaust soon: %d\r\n \r\n", len(disabledClients), len(exhaustedClients)) + output += fmt.Sprintf("Exhausted Clients count:\r\n🛑 Exhausted: %d\r\n🔜 Deplete soon: %d\r\n \r\n", len(disabledClients), len(exhaustedClients)) if len(exhaustedClients) > 0 { output += "Exhausted Clients:\r\n" for _, traffic := range exhaustedClients { expiryTime := "" if traffic.ExpiryTime == 0 { expiryTime = "♾Unlimited" + } else if traffic.ExpiryTime < 0 { + expiryTime += fmt.Sprintf("%d days", traffic.ExpiryTime/-86400000) } else { expiryTime = time.Unix((traffic.ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") } diff --git a/web/service/xray.go b/web/service/xray.go index d9e65f8d..6e63d2d1 100644 --- a/web/service/xray.go +++ b/web/service/xray.go @@ -84,15 +84,16 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) { 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) + clients = RemoveIndex(clients, index-indexDecrease) + indexDecrease++ logger.Info("Remove Inbound User", c["email"], "due the expire or traffic limit") } @@ -101,7 +102,27 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) { } } - settings["clients"] = clients + + // 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 != "alterId" { + delete(c, key) + } + } + final_clients = append(final_clients, interface{}(c)) + } + + settings["clients"] = final_clients modifiedSettings, err := json.Marshal(settings) if err != nil { return nil, err |
