2023-02-09 22:48:06 +03:30
package service
import (
2023-02-18 16:07:32 +03:30
"encoding/json"
2023-02-09 22:48:06 +03:30
"fmt"
2025-05-06 19:57:17 +03:30
"sort"
2024-04-05 12:24:18 +03:00
"strconv"
2023-04-25 18:43:37 +03:30
"strings"
2023-02-09 22:48:06 +03:30
"time"
2024-03-11 01:01:24 +03:30
2023-02-09 22:48:06 +03:30
"x-ui/database"
"x-ui/database/model"
2023-02-18 16:07:32 +03:30
"x-ui/logger"
2023-02-09 22:48:06 +03:30
"x-ui/util/common"
"x-ui/xray"
"gorm.io/gorm"
)
type InboundService struct {
2023-06-05 00:32:19 +03:30
xrayApi xray . XrayAPI
2023-02-09 22:48:06 +03:30
}
func ( s * InboundService ) GetInbounds ( userId int ) ( [ ] * model . Inbound , error ) {
db := database . GetDB ( )
var inbounds [ ] * model . Inbound
err := db . Model ( model . Inbound { } ) . Preload ( "ClientStats" ) . Where ( "user_id = ?" , userId ) . Find ( & inbounds ) . Error
if err != nil && err != gorm . ErrRecordNotFound {
return nil , err
}
return inbounds , nil
}
func ( s * InboundService ) GetAllInbounds ( ) ( [ ] * model . Inbound , error ) {
db := database . GetDB ( )
var inbounds [ ] * model . Inbound
err := db . Model ( model . Inbound { } ) . Preload ( "ClientStats" ) . Find ( & inbounds ) . Error
if err != nil && err != gorm . ErrRecordNotFound {
return nil , err
}
return inbounds , nil
}
2024-01-17 16:21:28 +03:30
func ( s * InboundService ) checkPortExist ( listen string , port int , ignoreId int ) ( bool , error ) {
2023-02-09 22:48:06 +03:30
db := database . GetDB ( )
2024-01-17 16:21:28 +03:30
if listen == "" || listen == "0.0.0.0" || listen == "::" || listen == "::0" {
db = db . Model ( model . Inbound { } ) . Where ( "port = ?" , port )
} else {
db = db . Model ( model . Inbound { } ) .
Where ( "port = ?" , port ) .
Where (
db . Model ( model . Inbound { } ) . Where (
"listen = ?" , listen ,
) . Or (
"listen = \"\"" ,
) . Or (
"listen = \"0.0.0.0\"" ,
) . Or (
"listen = \"::\"" ,
) . Or (
"listen = \"::0\"" ) )
}
2023-02-09 22:48:06 +03:30
if ignoreId > 0 {
db = db . Where ( "id != ?" , ignoreId )
}
var count int64
err := db . Count ( & count ) . Error
if err != nil {
return false , err
}
return count > 0 , nil
}
2023-05-22 18:06:34 +03:30
func ( s * InboundService ) GetClients ( inbound * model . Inbound ) ( [ ] model . Client , error ) {
2023-02-09 22:48:06 +03:30
settings := map [ string ] [ ] model . Client { }
json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings )
if settings == nil {
2023-03-17 19:37:49 +03:30
return nil , fmt . Errorf ( "setting is null" )
2023-02-09 22:48:06 +03:30
}
clients := settings [ "clients" ]
if clients == nil {
return nil , nil
}
return clients , nil
}
2023-04-18 21:34:06 +03:30
func ( s * InboundService ) getAllEmails ( ) ( [ ] string , error ) {
2023-02-09 22:48:06 +03:30
db := database . GetDB ( )
2023-04-18 21:34:06 +03:30
var emails [ ] string
err := db . Raw ( `
SELECT JSON_EXTRACT(client.value, '$.email')
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
` ) . Scan ( & emails ) . Error
if err != nil {
return nil , err
2023-02-09 22:48:06 +03:30
}
2023-04-18 21:34:06 +03:30
return emails , nil
}
2023-02-09 22:48:06 +03:30
2023-04-18 21:34:06 +03:30
func ( s * InboundService ) contains ( slice [ ] string , str string ) bool {
2024-10-10 17:32:50 +02:00
lowerStr := strings . ToLower ( str )
2023-04-18 21:34:06 +03:30
for _ , s := range slice {
2024-10-10 17:32:50 +02:00
if strings . ToLower ( s ) == lowerStr {
2023-04-18 21:34:06 +03:30
return true
2023-02-09 22:48:06 +03:30
}
2023-04-18 21:34:06 +03:30
}
return false
}
2023-02-09 22:48:06 +03:30
2023-04-18 21:34:06 +03:30
func ( s * InboundService ) checkEmailsExistForClients ( clients [ ] model . Client ) ( string , error ) {
allEmails , err := s . getAllEmails ( )
if err != nil {
return "" , err
}
var emails [ ] string
for _ , client := range clients {
if client . Email != "" {
if s . contains ( emails , client . Email ) {
return client . Email , nil
}
if s . contains ( allEmails , client . Email ) {
2023-02-09 22:48:06 +03:30
return client . Email , nil
}
2023-04-18 21:34:06 +03:30
emails = append ( emails , client . Email )
2023-02-09 22:48:06 +03:30
}
}
return "" , nil
}
func ( s * InboundService ) checkEmailExistForInbound ( inbound * model . Inbound ) ( string , error ) {
2023-05-22 18:06:34 +03:30
clients , err := s . GetClients ( inbound )
2023-02-09 22:48:06 +03:30
if err != nil {
return "" , err
}
2023-04-18 21:34:06 +03:30
allEmails , err := s . getAllEmails ( )
if err != nil {
return "" , err
}
var emails [ ] string
2023-02-09 22:48:06 +03:30
for _ , client := range clients {
2023-02-18 16:07:32 +03:30
if client . Email != "" {
2023-04-18 21:34:06 +03:30
if s . contains ( emails , client . Email ) {
return client . Email , nil
}
if s . contains ( allEmails , client . Email ) {
2023-02-09 22:48:06 +03:30
return client . Email , nil
}
2023-04-18 21:34:06 +03:30
emails = append ( emails , client . Email )
2023-02-09 22:48:06 +03:30
}
}
2023-04-18 21:34:06 +03:30
return "" , nil
2023-02-09 22:48:06 +03:30
}
2023-07-18 02:40:22 +03:30
func ( s * InboundService ) AddInbound ( inbound * model . Inbound ) ( * model . Inbound , bool , error ) {
2024-01-17 16:21:28 +03:30
exist , err := s . checkPortExist ( inbound . Listen , inbound . Port , 0 )
2023-02-09 22:48:06 +03:30
if err != nil {
2023-07-18 02:40:22 +03:30
return inbound , false , err
2023-02-09 22:48:06 +03:30
}
if exist {
2023-07-18 02:40:22 +03:30
return inbound , false , common . NewError ( "Port already exists:" , inbound . Port )
2023-02-09 22:48:06 +03:30
}
existEmail , err := s . checkEmailExistForInbound ( inbound )
if err != nil {
2023-07-18 02:40:22 +03:30
return inbound , false , err
2023-02-09 22:48:06 +03:30
}
if existEmail != "" {
2023-07-18 02:40:22 +03:30
return inbound , false , common . NewError ( "Duplicate email:" , existEmail )
2023-02-09 22:48:06 +03:30
}
2023-05-22 18:06:34 +03:30
clients , err := s . GetClients ( inbound )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-07-18 02:40:22 +03:30
return inbound , false , err
2023-03-17 19:37:49 +03:30
}
2025-08-27 21:00:49 +03:30
// Ensure created_at and updated_at on clients in settings
if len ( clients ) > 0 {
var settings map [ string ] any
if err2 := json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings ) ; err2 == nil && settings != nil {
now := time . Now ( ) . Unix ( ) * 1000
updatedClients := make ( [ ] model . Client , 0 , len ( clients ) )
for _ , c := range clients {
if c . CreatedAt == 0 {
c . CreatedAt = now
}
c . UpdatedAt = now
updatedClients = append ( updatedClients , c )
}
settings [ "clients" ] = updatedClients
if bs , err3 := json . MarshalIndent ( settings , "" , " " ) ; err3 == nil {
inbound . Settings = string ( bs )
} else {
logger . Debug ( "Unable to marshal inbound settings with timestamps:" , err3 )
}
} else if err2 != nil {
logger . Debug ( "Unable to parse inbound settings for timestamps:" , err2 )
}
}
2024-04-01 12:08:25 +04:30
// Secure client ID
for _ , client := range clients {
2025-08-17 13:37:49 +02:00
switch inbound . Protocol {
case "trojan" :
2024-04-01 12:08:25 +04:30
if client . Password == "" {
return inbound , false , common . NewError ( "empty client ID" )
}
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-04-01 12:08:25 +04:30
if client . Email == "" {
return inbound , false , common . NewError ( "empty client ID" )
}
2025-08-17 13:37:49 +02:00
default :
2024-04-01 12:08:25 +04:30
if client . ID == "" {
return inbound , false , common . NewError ( "empty client ID" )
}
}
}
2023-02-09 22:48:06 +03:30
db := database . GetDB ( )
2023-06-05 00:32:19 +03:30
tx := db . Begin ( )
defer func ( ) {
if err == nil {
tx . Commit ( )
} else {
tx . Rollback ( )
}
} ( )
2023-02-09 22:48:06 +03:30
2023-06-05 00:32:19 +03:30
err = tx . Save ( inbound ) . Error
2023-02-09 22:48:06 +03:30
if err == nil {
2023-12-08 20:08:44 +01:00
if len ( inbound . ClientStats ) == 0 {
for _ , client := range clients {
s . AddClientStat ( tx , inbound . Id , & client )
}
2023-03-17 19:37:49 +03:30
}
2023-12-08 20:08:44 +01:00
} else {
return inbound , false , err
2023-02-09 22:48:06 +03:30
}
2023-07-18 02:40:22 +03:30
needRestart := false
if inbound . Enable {
s . xrayApi . Init ( p . GetAPIPort ( ) )
inboundJson , err1 := json . MarshalIndent ( inbound . GenXrayInboundConfig ( ) , "" , " " )
if err1 != nil {
logger . Debug ( "Unable to marshal inbound config:" , err1 )
}
err1 = s . xrayApi . AddInbound ( inboundJson )
if err1 == nil {
logger . Debug ( "New inbound added by api:" , inbound . Tag )
} else {
logger . Debug ( "Unable to add inbound by api:" , err1 )
needRestart = true
}
s . xrayApi . Close ( )
}
return inbound , needRestart , err
2023-02-09 22:48:06 +03:30
}
2023-07-18 02:40:22 +03:30
func ( s * InboundService ) DelInbound ( id int ) ( bool , error ) {
2023-02-09 22:48:06 +03:30
db := database . GetDB ( )
2023-07-18 02:40:22 +03:30
var tag string
needRestart := false
result := db . Model ( model . Inbound { } ) . Select ( "tag" ) . Where ( "id = ? and enable = ?" , id , true ) . First ( & tag )
if result . Error == nil {
s . xrayApi . Init ( p . GetAPIPort ( ) )
err1 := s . xrayApi . DelInbound ( tag )
if err1 == nil {
logger . Debug ( "Inbound deleted by api:" , tag )
} else {
logger . Debug ( "Unable to delete inbound by api:" , err1 )
needRestart = true
}
s . xrayApi . Close ( )
} else {
logger . Debug ( "No enabled inbound founded to removing by api" , tag )
}
// Delete client traffics of inbounds
2023-03-17 19:37:49 +03:30
err := db . Where ( "inbound_id = ?" , id ) . Delete ( xray . ClientTraffic { } ) . Error
if err != nil {
2023-07-18 02:40:22 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2023-03-17 18:51:43 +01:00
inbound , err := s . GetInbound ( id )
if err != nil {
2023-07-18 02:40:22 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
2023-05-22 18:06:34 +03:30
clients , err := s . GetClients ( inbound )
2023-03-17 18:51:43 +01:00
if err != nil {
2023-07-18 02:40:22 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
for _ , client := range clients {
2023-03-17 19:29:08 +01:00
err := s . DelClientIPs ( db , client . Email )
2023-03-17 18:51:43 +01:00
if err != nil {
2023-07-18 02:40:22 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
}
2023-07-18 02:40:22 +03:30
return needRestart , db . Delete ( model . Inbound { } , id ) . Error
2023-02-09 22:48:06 +03:30
}
func ( s * InboundService ) GetInbound ( id int ) ( * model . Inbound , error ) {
db := database . GetDB ( )
inbound := & model . Inbound { }
err := db . Model ( model . Inbound { } ) . First ( inbound , id ) . Error
if err != nil {
return nil , err
}
return inbound , nil
}
2023-07-18 02:40:22 +03:30
func ( s * InboundService ) UpdateInbound ( inbound * model . Inbound ) ( * model . Inbound , bool , error ) {
2024-01-17 16:21:28 +03:30
exist , err := s . checkPortExist ( inbound . Listen , inbound . Port , inbound . Id )
2023-02-09 22:48:06 +03:30
if err != nil {
2023-07-18 02:40:22 +03:30
return inbound , false , err
2023-02-09 22:48:06 +03:30
}
if exist {
2023-07-18 02:40:22 +03:30
return inbound , false , common . NewError ( "Port already exists:" , inbound . Port )
2023-02-09 22:48:06 +03:30
}
2023-02-18 16:07:32 +03:30
2023-02-09 22:48:06 +03:30
oldInbound , err := s . GetInbound ( inbound . Id )
if err != nil {
2023-07-18 02:40:22 +03:30
return inbound , false , err
2023-02-09 22:48:06 +03:30
}
2023-06-05 00:32:19 +03:30
2023-07-18 02:40:22 +03:30
tag := oldInbound . Tag
2023-12-04 19:20:16 +01:00
db := database . GetDB ( )
tx := db . Begin ( )
defer func ( ) {
if err != nil {
tx . Rollback ( )
} else {
tx . Commit ( )
}
} ( )
err = s . updateClientTraffics ( tx , oldInbound , inbound )
2023-06-05 00:32:19 +03:30
if err != nil {
2023-07-18 02:40:22 +03:30
return inbound , false , err
2023-06-05 00:32:19 +03:30
}
2025-08-27 21:00:49 +03:30
// Ensure created_at and updated_at exist in inbound.Settings clients
{
var oldSettings map [ string ] any
_ = json . Unmarshal ( [ ] byte ( oldInbound . Settings ) , & oldSettings )
emailToCreated := map [ string ] int64 { }
if oldSettings != nil {
if oc , ok := oldSettings [ "clients" ] . ( [ ] any ) ; ok {
for _ , it := range oc {
if m , ok2 := it . ( map [ string ] any ) ; ok2 {
if email , ok3 := m [ "email" ] . ( string ) ; ok3 {
switch v := m [ "created_at" ] . ( type ) {
case float64 :
emailToCreated [ email ] = int64 ( v )
case int64 :
emailToCreated [ email ] = v
}
}
}
}
}
}
var newSettings map [ string ] any
if err2 := json . Unmarshal ( [ ] byte ( inbound . Settings ) , & newSettings ) ; err2 == nil && newSettings != nil {
now := time . Now ( ) . Unix ( ) * 1000
if nSlice , ok := newSettings [ "clients" ] . ( [ ] any ) ; ok {
for i := range nSlice {
if m , ok2 := nSlice [ i ] . ( map [ string ] any ) ; ok2 {
email , _ := m [ "email" ] . ( string )
if _ , ok3 := m [ "created_at" ] ; ! ok3 {
if v , ok4 := emailToCreated [ email ] ; ok4 && v > 0 {
m [ "created_at" ] = v
} else {
m [ "created_at" ] = now
}
}
m [ "updated_at" ] = now
nSlice [ i ] = m
}
}
newSettings [ "clients" ] = nSlice
if bs , err3 := json . MarshalIndent ( newSettings , "" , " " ) ; err3 == nil {
inbound . Settings = string ( bs )
}
}
}
}
2023-02-09 22:48:06 +03:30
oldInbound . Up = inbound . Up
oldInbound . Down = inbound . Down
oldInbound . Total = inbound . Total
oldInbound . Remark = inbound . Remark
oldInbound . Enable = inbound . Enable
oldInbound . ExpiryTime = inbound . ExpiryTime
oldInbound . Listen = inbound . Listen
oldInbound . Port = inbound . Port
oldInbound . Protocol = inbound . Protocol
oldInbound . Settings = inbound . Settings
oldInbound . StreamSettings = inbound . StreamSettings
oldInbound . Sniffing = inbound . Sniffing
2024-01-17 16:21:28 +03:30
if inbound . Listen == "" || inbound . Listen == "0.0.0.0" || inbound . Listen == "::" || inbound . Listen == "::0" {
2024-02-21 22:20:51 +03:30
oldInbound . Tag = fmt . Sprintf ( "inbound-%v" , inbound . Port )
2024-01-17 16:21:28 +03:30
} else {
oldInbound . Tag = fmt . Sprintf ( "inbound-%v:%v" , inbound . Listen , inbound . Port )
}
2023-07-18 02:40:22 +03:30
needRestart := false
s . xrayApi . Init ( p . GetAPIPort ( ) )
2023-07-31 19:52:28 +03:30
if s . xrayApi . DelInbound ( tag ) == nil {
2023-07-18 02:40:22 +03:30
logger . Debug ( "Old inbound deleted by api:" , tag )
2023-07-31 19:52:28 +03:30
}
if inbound . Enable {
inboundJson , err2 := json . MarshalIndent ( oldInbound . GenXrayInboundConfig ( ) , "" , " " )
if err2 != nil {
logger . Debug ( "Unable to marshal updated inbound config:" , err2 )
needRestart = true
} else {
err2 = s . xrayApi . AddInbound ( inboundJson )
if err2 == nil {
logger . Debug ( "Updated inbound added by api:" , oldInbound . Tag )
2023-07-27 11:58:12 +03:30
} else {
2023-07-31 19:52:28 +03:30
logger . Debug ( "Unable to update inbound by api:" , err2 )
needRestart = true
2023-07-18 02:40:22 +03:30
}
}
}
s . xrayApi . Close ( )
2023-12-04 19:20:16 +01:00
return inbound , needRestart , tx . Save ( oldInbound ) . Error
2023-02-09 22:48:06 +03:30
}
2023-12-04 19:20:16 +01:00
func ( s * InboundService ) updateClientTraffics ( tx * gorm . DB , oldInbound * model . Inbound , newInbound * model . Inbound ) error {
2023-06-05 00:32:19 +03:30
oldClients , err := s . GetClients ( oldInbound )
if err != nil {
return err
}
newClients , err := s . GetClients ( newInbound )
2023-04-18 21:34:06 +03:30
if err != nil {
return err
}
2023-04-19 11:55:38 +03:30
2023-06-05 00:32:19 +03:30
var emailExists bool
for _ , oldClient := range oldClients {
emailExists = false
for _ , newClient := range newClients {
if oldClient . Email == newClient . Email {
emailExists = true
break
}
}
if ! emailExists {
err = s . DelClientStat ( tx , oldClient . Email )
if err != nil {
return err
}
}
}
for _ , newClient := range newClients {
emailExists = false
for _ , oldClient := range oldClients {
if newClient . Email == oldClient . Email {
emailExists = true
break
}
}
if ! emailExists {
err = s . AddClientStat ( tx , oldInbound . Id , & newClient )
if err != nil {
return err
}
}
}
return nil
}
func ( s * InboundService ) AddInboundClient ( data * model . Inbound ) ( bool , error ) {
clients , err := s . GetClients ( data )
if err != nil {
return false , err
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-04-19 11:55:38 +03:30
err = json . Unmarshal ( [ ] byte ( data . Settings ) , & settings )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2025-03-12 20:13:51 +01:00
interfaceClients := settings [ "clients" ] . ( [ ] any )
2025-08-27 21:00:49 +03:30
// Add timestamps for new clients being appended
nowTs := time . Now ( ) . Unix ( ) * 1000
for i := range interfaceClients {
if cm , ok := interfaceClients [ i ] . ( map [ string ] any ) ; ok {
if _ , ok2 := cm [ "created_at" ] ; ! ok2 {
cm [ "created_at" ] = nowTs
}
cm [ "updated_at" ] = nowTs
interfaceClients [ i ] = cm
}
}
2023-04-19 11:55:38 +03:30
existEmail , err := s . checkEmailsExistForClients ( clients )
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-04-19 11:55:38 +03:30
}
2023-03-17 19:37:49 +03:30
if existEmail != "" {
2023-06-05 00:32:19 +03:30
return false , common . NewError ( "Duplicate email:" , existEmail )
2023-03-17 19:37:49 +03:30
}
2023-04-18 21:34:06 +03:30
oldInbound , err := s . GetInbound ( data . Id )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2024-04-01 12:08:25 +04:30
// Secure client ID
for _ , client := range clients {
2025-08-17 13:37:49 +02:00
switch oldInbound . Protocol {
case "trojan" :
2024-04-01 12:08:25 +04:30
if client . Password == "" {
return false , common . NewError ( "empty client ID" )
}
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-04-01 12:08:25 +04:30
if client . Email == "" {
return false , common . NewError ( "empty client ID" )
}
2025-08-17 13:37:49 +02:00
default :
2024-04-01 12:08:25 +04:30
if client . ID == "" {
return false , common . NewError ( "empty client ID" )
}
}
}
2025-03-12 20:13:51 +01:00
var oldSettings map [ string ] any
2023-04-19 11:55:38 +03:30
err = json . Unmarshal ( [ ] byte ( oldInbound . Settings ) , & oldSettings )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2025-03-12 20:13:51 +01:00
oldClients := oldSettings [ "clients" ] . ( [ ] any )
2023-04-19 11:55:38 +03:30
oldClients = append ( oldClients , interfaceClients ... )
2023-04-18 21:34:06 +03:30
2023-04-19 11:55:38 +03:30
oldSettings [ "clients" ] = oldClients
2023-04-18 21:34:06 +03:30
2023-04-19 11:55:38 +03:30
newSettings , err := json . MarshalIndent ( oldSettings , "" , " " )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2023-04-18 21:34:06 +03:30
oldInbound . Settings = string ( newSettings )
2023-03-17 19:37:49 +03:30
2023-06-05 00:32:19 +03:30
db := database . GetDB ( )
tx := db . Begin ( )
defer func ( ) {
if err != nil {
tx . Rollback ( )
} else {
tx . Commit ( )
}
} ( )
needRestart := false
s . xrayApi . Init ( p . GetAPIPort ( ) )
2023-04-18 21:34:06 +03:30
for _ , client := range clients {
if len ( client . Email ) > 0 {
2023-06-05 00:32:19 +03:30
s . AddClientStat ( tx , data . Id , & client )
2023-07-18 02:40:22 +03:30
if client . Enable {
2023-07-27 11:58:12 +03:30
cipher := ""
if oldInbound . Protocol == "shadowsocks" {
cipher = oldSettings [ "method" ] . ( string )
}
2025-03-12 20:13:51 +01:00
err1 := s . xrayApi . AddUser ( string ( oldInbound . Protocol ) , oldInbound . Tag , map [ string ] any {
2023-07-18 02:40:22 +03:30
"email" : client . Email ,
"id" : client . ID ,
2024-08-11 00:47:44 +02:00
"security" : client . Security ,
2023-07-18 02:40:22 +03:30
"flow" : client . Flow ,
"password" : client . Password ,
2023-07-27 11:58:12 +03:30
"cipher" : cipher ,
2023-07-18 02:40:22 +03:30
} )
if err1 == nil {
logger . Debug ( "Client added by api:" , client . Email )
} else {
2023-07-27 11:58:12 +03:30
logger . Debug ( "Error in adding client by api:" , err1 )
2023-07-18 02:40:22 +03:30
needRestart = true
}
2023-06-05 00:32:19 +03:30
}
} else {
needRestart = true
2023-03-17 19:37:49 +03:30
}
}
2023-06-05 00:32:19 +03:30
s . xrayApi . Close ( )
return needRestart , tx . Save ( oldInbound ) . Error
2023-03-17 19:37:49 +03:30
}
2023-06-05 00:32:19 +03:30
func ( s * InboundService ) DelInboundClient ( inboundId int , clientId string ) ( bool , error ) {
2023-04-24 15:07:11 +03:30
oldInbound , err := s . GetInbound ( inboundId )
if err != nil {
logger . Error ( "Load Old Data Error" )
2023-06-05 00:32:19 +03:30
return false , err
2023-04-24 15:07:11 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-04-24 15:07:11 +03:30
err = json . Unmarshal ( [ ] byte ( oldInbound . Settings ) , & settings )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2023-04-24 15:07:11 +03:30
email := ""
client_key := "id"
if oldInbound . Protocol == "trojan" {
client_key = "password"
}
2023-05-06 20:21:14 +03:30
if oldInbound . Protocol == "shadowsocks" {
client_key = "email"
}
2023-04-24 15:07:11 +03:30
2025-03-12 20:13:51 +01:00
interfaceClients := settings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2024-09-02 10:26:19 +02:00
needApiDel := false
2024-04-01 12:08:25 +04:30
for _ , client := range interfaceClients {
2025-03-12 20:13:51 +01:00
c := client . ( map [ string ] any )
2023-04-24 15:07:11 +03:30
c_id := c [ client_key ] . ( string )
if c_id == clientId {
2024-09-02 10:26:19 +02:00
email , _ = c [ "email" ] . ( string )
needApiDel , _ = c [ "enable" ] . ( bool )
2023-04-24 15:07:11 +03:30
} else {
newClients = append ( newClients , client )
}
}
2024-01-24 20:50:58 +03:30
if len ( newClients ) == 0 {
return false , common . NewError ( "no client remained in Inbound" )
}
2023-04-24 15:07:11 +03:30
settings [ "clients" ] = newClients
newSettings , err := json . MarshalIndent ( settings , "" , " " )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2023-04-24 15:07:11 +03:30
oldInbound . Settings = string ( newSettings )
db := database . GetDB ( )
2023-03-17 19:37:49 +03:30
2023-03-17 18:51:43 +01:00
err = s . DelClientIPs ( db , email )
if err != nil {
logger . Error ( "Error in delete client IPs" )
2023-06-05 00:32:19 +03:30
return false , err
}
2023-07-18 02:40:22 +03:30
needRestart := false
2024-09-02 10:26:19 +02:00
2023-06-05 00:32:19 +03:30
if len ( email ) > 0 {
2024-09-02 10:26:19 +02:00
notDepleted := true
err = db . Model ( xray . ClientTraffic { } ) . Select ( "enable" ) . Where ( "email = ?" , email ) . First ( & notDepleted ) . Error
if err != nil {
logger . Error ( "Get stats error" )
return false , err
}
err = s . DelClientStat ( db , email )
if err != nil {
logger . Error ( "Delete stats Data Error" )
return false , err
}
if needApiDel && notDepleted {
s . xrayApi . Init ( p . GetAPIPort ( ) )
err1 := s . xrayApi . RemoveUser ( oldInbound . Tag , email )
if err1 == nil {
logger . Debug ( "Client deleted by api:" , email )
needRestart = false
} else {
2024-11-16 14:35:23 +01:00
if strings . Contains ( err1 . Error ( ) , fmt . Sprintf ( "User %s not found." , email ) ) {
logger . Debug ( "User is already deleted. Nothing to do more..." )
} else {
logger . Debug ( "Error in deleting client by api:" , err1 )
needRestart = true
}
2024-09-02 10:26:19 +02:00
}
s . xrayApi . Close ( )
2023-06-05 00:32:19 +03:30
}
2023-03-17 18:51:43 +01:00
}
2023-06-05 00:32:19 +03:30
return needRestart , db . Save ( oldInbound ) . Error
2023-03-17 19:37:49 +03:30
}
2023-06-05 00:32:19 +03:30
func ( s * InboundService ) UpdateInboundClient ( data * model . Inbound , clientId string ) ( bool , error ) {
2023-05-22 18:06:34 +03:30
clients , err := s . GetClients ( data )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-04-19 11:55:38 +03:30
err = json . Unmarshal ( [ ] byte ( data . Settings ) , & settings )
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-04-19 11:55:38 +03:30
}
2025-03-12 20:13:51 +01:00
interfaceClients := settings [ "clients" ] . ( [ ] any )
2023-04-19 11:55:38 +03:30
2023-04-18 21:34:06 +03:30
oldInbound , err := s . GetInbound ( data . Id )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2023-05-22 18:06:34 +03:30
oldClients , err := s . GetClients ( oldInbound )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2023-04-25 14:38:35 +03:30
oldEmail := ""
2024-03-11 11:52:28 +03:30
newClientId := ""
2024-04-21 00:58:37 +03:30
clientIndex := - 1
2023-04-25 14:38:35 +03:30
for index , oldClient := range oldClients {
oldClientId := ""
2025-08-17 13:37:49 +02:00
switch oldInbound . Protocol {
case "trojan" :
2023-04-25 14:38:35 +03:30
oldClientId = oldClient . Password
2024-03-11 11:52:28 +03:30
newClientId = clients [ 0 ] . Password
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2023-05-06 20:21:14 +03:30
oldClientId = oldClient . Email
2024-03-11 11:52:28 +03:30
newClientId = clients [ 0 ] . Email
2025-08-17 13:37:49 +02:00
default :
2023-04-25 14:38:35 +03:30
oldClientId = oldClient . ID
2024-03-11 11:52:28 +03:30
newClientId = clients [ 0 ] . ID
2023-04-25 14:38:35 +03:30
}
if clientId == oldClientId {
oldEmail = oldClient . Email
clientIndex = index
break
}
}
2024-03-11 11:52:28 +03:30
// Validate new client ID
2024-04-21 00:58:37 +03:30
if newClientId == "" || clientIndex == - 1 {
2024-03-11 11:52:28 +03:30
return false , common . NewError ( "empty client ID" )
}
2023-04-25 14:38:35 +03:30
if len ( clients [ 0 ] . Email ) > 0 && clients [ 0 ] . Email != oldEmail {
2023-04-18 21:34:06 +03:30
existEmail , err := s . checkEmailsExistForClients ( clients )
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-04-18 21:34:06 +03:30
}
if existEmail != "" {
2023-06-05 00:32:19 +03:30
return false , common . NewError ( "Duplicate email:" , existEmail )
2023-04-18 21:34:06 +03:30
}
}
2025-03-12 20:13:51 +01:00
var oldSettings map [ string ] any
2023-04-19 11:55:38 +03:30
err = json . Unmarshal ( [ ] byte ( oldInbound . Settings ) , & oldSettings )
2023-03-17 19:37:49 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 19:37:49 +03:30
}
2025-03-12 20:13:51 +01:00
settingsClients := oldSettings [ "clients" ] . ( [ ] any )
2025-08-27 21:00:49 +03:30
// Preserve created_at and set updated_at for the replacing client
var preservedCreated any
if clientIndex >= 0 && clientIndex < len ( settingsClients ) {
if oldMap , ok := settingsClients [ clientIndex ] . ( map [ string ] any ) ; ok {
if v , ok2 := oldMap [ "created_at" ] ; ok2 {
preservedCreated = v
}
}
}
if len ( interfaceClients ) > 0 {
if newMap , ok := interfaceClients [ 0 ] . ( map [ string ] any ) ; ok {
if preservedCreated == nil {
preservedCreated = time . Now ( ) . Unix ( ) * 1000
}
newMap [ "created_at" ] = preservedCreated
newMap [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
interfaceClients [ 0 ] = newMap
}
}
2024-07-04 00:17:44 +02:00
settingsClients [ clientIndex ] = interfaceClients [ 0 ]
2023-04-19 11:55:38 +03:30
oldSettings [ "clients" ] = settingsClients
2023-04-18 21:34:06 +03:30
2023-04-19 11:55:38 +03:30
newSettings , err := json . MarshalIndent ( oldSettings , "" , " " )
2023-04-18 21:34:06 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-04-18 21:34:06 +03:30
}
2023-03-17 19:37:49 +03:30
2023-04-18 21:34:06 +03:30
oldInbound . Settings = string ( newSettings )
2023-03-17 19:37:49 +03:30
db := database . GetDB ( )
2023-06-05 00:32:19 +03:30
tx := db . Begin ( )
defer func ( ) {
if err != nil {
tx . Rollback ( )
} else {
tx . Commit ( )
}
} ( )
2023-03-17 19:37:49 +03:30
2023-04-18 21:34:06 +03:30
if len ( clients [ 0 ] . Email ) > 0 {
2023-04-25 14:38:35 +03:30
if len ( oldEmail ) > 0 {
2023-12-04 19:20:16 +01:00
err = s . UpdateClientStat ( tx , oldEmail , & clients [ 0 ] )
2023-03-17 18:51:43 +01:00
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
2023-06-07 12:45:58 +03:30
err = s . UpdateClientIPs ( tx , oldEmail , clients [ 0 ] . Email )
2023-03-17 18:51:43 +01:00
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
2023-03-17 19:37:49 +03:30
} else {
2023-06-05 00:32:19 +03:30
s . AddClientStat ( tx , data . Id , & clients [ 0 ] )
2023-03-17 19:37:49 +03:30
}
} else {
2023-06-05 00:32:19 +03:30
err = s . DelClientStat ( tx , oldEmail )
2023-03-17 18:51:43 +01:00
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
2023-06-07 12:45:58 +03:30
err = s . DelClientIPs ( tx , oldEmail )
2023-03-17 18:51:43 +01:00
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-03-17 18:51:43 +01:00
}
2023-03-17 19:37:49 +03:30
}
2023-07-18 02:40:22 +03:30
needRestart := false
2023-06-05 00:32:19 +03:30
if len ( oldEmail ) > 0 {
2023-07-27 11:58:12 +03:30
s . xrayApi . Init ( p . GetAPIPort ( ) )
2024-09-02 10:26:19 +02:00
if oldClients [ clientIndex ] . Enable {
err1 := s . xrayApi . RemoveUser ( oldInbound . Tag , oldEmail )
if err1 == nil {
2024-11-16 14:35:23 +01:00
logger . Debug ( "Old client deleted by api:" , oldEmail )
2024-09-02 10:26:19 +02:00
} else {
2024-11-16 14:35:23 +01:00
if strings . Contains ( err1 . Error ( ) , fmt . Sprintf ( "User %s not found." , oldEmail ) ) {
logger . Debug ( "User is already deleted. Nothing to do more..." )
} else {
logger . Debug ( "Error in deleting client by api:" , err1 )
needRestart = true
}
2024-09-02 10:26:19 +02:00
}
2023-07-31 19:52:28 +03:30
}
2023-06-05 00:32:19 +03:30
if clients [ 0 ] . Enable {
2023-07-27 11:58:12 +03:30
cipher := ""
if oldInbound . Protocol == "shadowsocks" {
cipher = oldSettings [ "method" ] . ( string )
}
2025-03-12 20:13:51 +01:00
err1 := s . xrayApi . AddUser ( string ( oldInbound . Protocol ) , oldInbound . Tag , map [ string ] any {
2023-06-05 00:32:19 +03:30
"email" : clients [ 0 ] . Email ,
"id" : clients [ 0 ] . ID ,
2024-08-11 00:47:44 +02:00
"security" : clients [ 0 ] . Security ,
2023-06-05 00:32:19 +03:30
"flow" : clients [ 0 ] . Flow ,
"password" : clients [ 0 ] . Password ,
2023-07-27 11:58:12 +03:30
"cipher" : cipher ,
2023-06-05 00:32:19 +03:30
} )
if err1 == nil {
logger . Debug ( "Client edited by api:" , clients [ 0 ] . Email )
2023-07-27 11:58:12 +03:30
} else {
logger . Debug ( "Error in adding client by api:" , err1 )
needRestart = true
2023-06-05 00:32:19 +03:30
}
}
2023-07-27 11:58:12 +03:30
s . xrayApi . Close ( )
} else {
logger . Debug ( "Client old email not found" )
needRestart = true
2023-06-05 00:32:19 +03:30
}
return needRestart , tx . Save ( oldInbound ) . Error
2023-03-17 19:37:49 +03:30
}
2024-03-11 11:52:28 +03:30
func ( s * InboundService ) AddTraffic ( inboundTraffics [ ] * xray . Traffic , clientTraffics [ ] * xray . ClientTraffic ) ( error , bool ) {
2023-08-26 15:19:51 +03:30
var err error
2023-04-09 23:13:18 +03:30
db := database . GetDB ( )
2023-02-09 22:48:06 +03:30
tx := db . Begin ( )
2023-04-09 23:13:18 +03:30
2023-02-09 22:48:06 +03:30
defer func ( ) {
if err != nil {
tx . Rollback ( )
} else {
tx . Commit ( )
}
} ( )
2024-03-11 11:52:28 +03:30
err = s . addInboundTraffic ( tx , inboundTraffics )
2023-08-26 15:19:51 +03:30
if err != nil {
return err , false
}
err = s . addClientTraffic ( tx , clientTraffics )
if err != nil {
return err , false
}
2023-12-04 19:20:16 +01:00
needRestart0 , count , err := s . autoRenewClients ( tx )
if err != nil {
logger . Warning ( "Error in renew clients:" , err )
} else if count > 0 {
logger . Debugf ( "%v clients renewed" , count )
}
2023-08-26 15:19:51 +03:30
needRestart1 , count , err := s . disableInvalidClients ( tx )
if err != nil {
logger . Warning ( "Error in disabling invalid clients:" , err )
} else if count > 0 {
logger . Debugf ( "%v clients disabled" , count )
}
needRestart2 , count , err := s . disableInvalidInbounds ( tx )
if err != nil {
logger . Warning ( "Error in disabling invalid inbounds:" , err )
} else if count > 0 {
logger . Debugf ( "%v inbounds disabled" , count )
}
2023-12-04 19:20:16 +01:00
return nil , ( needRestart0 || needRestart1 || needRestart2 )
2023-08-26 15:19:51 +03:30
}
func ( s * InboundService ) addInboundTraffic ( tx * gorm . DB , traffics [ ] * xray . Traffic ) error {
if len ( traffics ) == 0 {
return nil
}
var err error
for _ , traffic := range traffics {
if traffic . IsInbound {
err = tx . Model ( & model . Inbound { } ) . Where ( "tag = ?" , traffic . Tag ) .
2025-03-12 20:13:51 +01:00
Updates ( map [ string ] any {
2025-08-28 02:40:50 +03:30
"up" : gorm . Expr ( "up + ?" , traffic . Up ) ,
"down" : gorm . Expr ( "down + ?" , traffic . Down ) ,
"all_time" : gorm . Expr ( "COALESCE(all_time, 0) + ?" , traffic . Up + traffic . Down ) ,
2023-08-26 15:19:51 +03:30
} ) . Error
if err != nil {
return err
}
}
}
return nil
}
func ( s * InboundService ) addClientTraffic ( tx * gorm . DB , traffics [ ] * xray . ClientTraffic ) ( err error ) {
if len ( traffics ) == 0 {
2023-12-04 19:13:21 +01:00
// Empty onlineUsers
if p != nil {
p . SetOnlineClients ( nil )
}
2023-08-26 15:19:51 +03:30
return nil
}
2023-04-09 23:13:18 +03:30
2023-12-04 19:13:21 +01:00
var onlineClients [ ] string
2023-04-24 14:04:05 +03:30
emails := make ( [ ] string , 0 , len ( traffics ) )
for _ , traffic := range traffics {
emails = append ( emails , traffic . Email )
}
dbClientTraffics := make ( [ ] * xray . ClientTraffic , 0 , len ( traffics ) )
2023-08-26 15:19:51 +03:30
err = tx . Model ( xray . ClientTraffic { } ) . Where ( "email IN (?)" , emails ) . Find ( & dbClientTraffics ) . Error
2023-04-24 14:04:05 +03:30
if err != nil {
return err
}
2023-07-27 11:58:12 +03:30
// Avoid empty slice error
if len ( dbClientTraffics ) == 0 {
return nil
}
2023-04-24 14:04:05 +03:30
dbClientTraffics , err = s . adjustTraffics ( tx , dbClientTraffics )
if err != nil {
return err
}
for dbTraffic_index := range dbClientTraffics {
for traffic_index := range traffics {
if dbClientTraffics [ dbTraffic_index ] . Email == traffics [ traffic_index ] . Email {
dbClientTraffics [ dbTraffic_index ] . Up += traffics [ traffic_index ] . Up
dbClientTraffics [ dbTraffic_index ] . Down += traffics [ traffic_index ] . Down
2025-08-28 02:40:50 +03:30
dbClientTraffics [ dbTraffic_index ] . AllTime += ( traffics [ traffic_index ] . Up + traffics [ traffic_index ] . Down )
2023-12-04 19:13:21 +01:00
// Add user in onlineUsers array on traffic
if traffics [ traffic_index ] . Up + traffics [ traffic_index ] . Down > 0 {
onlineClients = append ( onlineClients , traffics [ traffic_index ] . Email )
}
2023-04-24 14:04:05 +03:30
break
}
}
}
2023-12-04 19:13:21 +01:00
// Set onlineUsers
p . SetOnlineClients ( onlineClients )
2023-04-24 14:04:05 +03:30
err = tx . Save ( dbClientTraffics ) . Error
2023-04-09 23:13:18 +03:30
if err != nil {
logger . Warning ( "AddClientTraffic update data " , err )
}
return nil
}
2023-04-24 14:04:05 +03:30
func ( s * InboundService ) adjustTraffics ( tx * gorm . DB , dbClientTraffics [ ] * xray . ClientTraffic ) ( [ ] * xray . ClientTraffic , error ) {
inboundIds := make ( [ ] int , 0 , len ( dbClientTraffics ) )
for _ , dbClientTraffic := range dbClientTraffics {
if dbClientTraffic . ExpiryTime < 0 {
inboundIds = append ( inboundIds , dbClientTraffic . InboundId )
2023-03-17 01:31:14 +03:30
}
2023-04-24 14:04:05 +03:30
}
2023-03-17 19:37:49 +03:30
2023-04-24 14:04:05 +03:30
if len ( inboundIds ) > 0 {
var inbounds [ ] * model . Inbound
err := tx . Model ( model . Inbound { } ) . Where ( "id IN (?)" , inboundIds ) . Find ( & inbounds ) . Error
2023-03-17 01:31:14 +03:30
if err != nil {
2023-04-24 14:04:05 +03:30
return nil , err
2023-02-09 22:48:06 +03:30
}
2023-04-24 14:04:05 +03:30
for inbound_index := range inbounds {
2025-03-12 20:13:51 +01:00
settings := map [ string ] any { }
2023-04-24 14:04:05 +03:30
json . Unmarshal ( [ ] byte ( inbounds [ inbound_index ] . Settings ) , & settings )
2025-03-12 20:13:51 +01:00
clients , ok := settings [ "clients" ] . ( [ ] any )
2023-04-24 14:04:05 +03:30
if ok {
2025-03-12 20:13:51 +01:00
var newClients [ ] any
2023-04-24 14:04:05 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-04-24 14:04:05 +03:30
for traffic_index := range dbClientTraffics {
2023-04-26 12:57:49 +03:30
if dbClientTraffics [ traffic_index ] . ExpiryTime < 0 && c [ "email" ] == dbClientTraffics [ traffic_index ] . Email {
2023-04-24 14:04:05 +03:30
oldExpiryTime := c [ "expiryTime" ] . ( float64 )
newExpiryTime := ( time . Now ( ) . Unix ( ) * 1000 ) - int64 ( oldExpiryTime )
c [ "expiryTime" ] = newExpiryTime
2025-08-27 21:00:49 +03:30
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2023-04-24 14:04:05 +03:30
dbClientTraffics [ traffic_index ] . ExpiryTime = newExpiryTime
break
}
2023-04-11 15:41:04 +03:30
}
2025-08-27 21:00:49 +03:30
// Backfill created_at and updated_at
if _ , ok := c [ "created_at" ] ; ! ok {
c [ "created_at" ] = time . Now ( ) . Unix ( ) * 1000
}
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-04-09 23:13:18 +03:30
}
2023-04-24 14:04:05 +03:30
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
return nil , err
}
2023-04-24 14:13:25 +03:30
2023-04-24 14:04:05 +03:30
inbounds [ inbound_index ] . Settings = string ( modifiedSettings )
2023-04-24 14:13:25 +03:30
}
2023-02-09 22:48:06 +03:30
}
2023-04-24 14:04:05 +03:30
err = tx . Save ( inbounds ) . Error
if err != nil {
logger . Warning ( "AddClientTraffic update inbounds " , err )
logger . Error ( inbounds )
2023-04-24 14:13:25 +03:30
}
2023-02-09 22:48:06 +03:30
}
2023-04-24 14:13:25 +03:30
2023-04-24 14:04:05 +03:30
return dbClientTraffics , nil
2023-02-09 22:48:06 +03:30
}
2023-12-04 19:20:16 +01:00
func ( s * InboundService ) autoRenewClients ( tx * gorm . DB ) ( bool , int64 , error ) {
// check for time expired
var traffics [ ] * xray . ClientTraffic
now := time . Now ( ) . Unix ( ) * 1000
var err , err1 error
err = tx . Model ( xray . ClientTraffic { } ) . Where ( "reset > 0 and expiry_time > 0 and expiry_time <= ?" , now ) . Find ( & traffics ) . Error
if err != nil {
return false , 0 , err
}
// return if there is no client to renew
if len ( traffics ) == 0 {
return false , 0 , nil
}
var inbound_ids [ ] int
var inbounds [ ] * model . Inbound
needRestart := false
var clientsToAdd [ ] struct {
protocol string
tag string
2025-03-12 20:13:51 +01:00
client map [ string ] any
2023-12-04 19:20:16 +01:00
}
for _ , traffic := range traffics {
inbound_ids = append ( inbound_ids , traffic . InboundId )
}
err = tx . Model ( model . Inbound { } ) . Where ( "id IN ?" , inbound_ids ) . Find ( & inbounds ) . Error
if err != nil {
return false , 0 , err
}
for inbound_index := range inbounds {
2025-03-12 20:13:51 +01:00
settings := map [ string ] any { }
2023-12-04 19:20:16 +01:00
json . Unmarshal ( [ ] byte ( inbounds [ inbound_index ] . Settings ) , & settings )
2025-03-12 20:13:51 +01:00
clients := settings [ "clients" ] . ( [ ] any )
2023-12-04 19:20:16 +01:00
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-12-04 19:20:16 +01:00
for traffic_index , traffic := range traffics {
if traffic . Email == c [ "email" ] . ( string ) {
newExpiryTime := traffic . ExpiryTime
for newExpiryTime < now {
newExpiryTime += ( int64 ( traffic . Reset ) * 86400000 )
}
c [ "expiryTime" ] = newExpiryTime
traffics [ traffic_index ] . ExpiryTime = newExpiryTime
traffics [ traffic_index ] . Down = 0
traffics [ traffic_index ] . Up = 0
if ! traffic . Enable {
traffics [ traffic_index ] . Enable = true
clientsToAdd = append ( clientsToAdd ,
struct {
protocol string
tag string
2025-03-12 20:13:51 +01:00
client map [ string ] any
2023-12-04 19:20:16 +01:00
} {
protocol : string ( inbounds [ inbound_index ] . Protocol ) ,
tag : inbounds [ inbound_index ] . Tag ,
client : c ,
} )
}
2025-03-12 20:13:51 +01:00
clients [ client_index ] = any ( c )
2023-12-04 19:20:16 +01:00
break
}
}
}
settings [ "clients" ] = clients
newSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
return false , 0 , err
}
inbounds [ inbound_index ] . Settings = string ( newSettings )
}
err = tx . Save ( inbounds ) . Error
if err != nil {
return false , 0 , err
}
err = tx . Save ( traffics ) . Error
if err != nil {
return false , 0 , err
}
if p != nil {
err1 = s . xrayApi . Init ( p . GetAPIPort ( ) )
if err1 != nil {
return true , int64 ( len ( traffics ) ) , nil
}
for _ , clientToAdd := range clientsToAdd {
err1 = s . xrayApi . AddUser ( clientToAdd . protocol , clientToAdd . tag , clientToAdd . client )
if err1 != nil {
needRestart = true
}
}
s . xrayApi . Close ( )
}
return needRestart , int64 ( len ( traffics ) ) , nil
}
2023-08-26 15:19:51 +03:30
func ( s * InboundService ) disableInvalidInbounds ( tx * gorm . DB ) ( bool , int64 , error ) {
2023-02-09 22:48:06 +03:30
now := time . Now ( ) . Unix ( ) * 1000
2023-07-18 02:40:22 +03:30
needRestart := false
if p != nil {
var tags [ ] string
2023-08-26 15:19:51 +03:30
err := tx . Table ( "inbounds" ) .
2023-07-18 02:40:22 +03:30
Select ( "inbounds.tag" ) .
Where ( "((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?" , now , true ) .
Scan ( & tags ) . Error
if err != nil {
return false , 0 , err
}
s . xrayApi . Init ( p . GetAPIPort ( ) )
for _ , tag := range tags {
2023-07-27 11:58:12 +03:30
err1 := s . xrayApi . DelInbound ( tag )
2024-03-11 11:46:54 +03:30
if err1 == nil {
2023-07-18 02:40:22 +03:30
logger . Debug ( "Inbound disabled by api:" , tag )
} else {
2024-11-16 14:35:23 +01:00
logger . Debug ( "Error in disabling inbound by api:" , err1 )
needRestart = true
2023-07-18 02:40:22 +03:30
}
}
s . xrayApi . Close ( )
}
2023-08-26 15:19:51 +03:30
result := tx . Model ( model . Inbound { } ) .
2023-02-09 22:48:06 +03:30
Where ( "((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?" , now , true ) .
Update ( "enable" , false )
err := result . Error
count := result . RowsAffected
2023-07-18 02:40:22 +03:30
return needRestart , count , err
2023-02-09 22:48:06 +03:30
}
2023-05-06 00:22:39 +04:30
2023-08-26 15:19:51 +03:30
func ( s * InboundService ) disableInvalidClients ( tx * gorm . DB ) ( bool , int64 , error ) {
2023-04-18 21:34:06 +03:30
now := time . Now ( ) . Unix ( ) * 1000
2023-06-05 00:32:19 +03:30
needRestart := false
if p != nil {
var results [ ] struct {
Tag string
Email string
}
2023-08-26 15:19:51 +03:30
err := tx . Table ( "inbounds" ) .
2023-06-05 00:32:19 +03:30
Select ( "inbounds.tag, client_traffics.email" ) .
Joins ( "JOIN client_traffics ON inbounds.id = client_traffics.inbound_id" ) .
Where ( "((client_traffics.total > 0 AND client_traffics.up + client_traffics.down >= client_traffics.total) OR (client_traffics.expiry_time > 0 AND client_traffics.expiry_time <= ?)) AND client_traffics.enable = ?" , now , true ) .
Scan ( & results ) . Error
if err != nil {
return false , 0 , err
}
s . xrayApi . Init ( p . GetAPIPort ( ) )
for _ , result := range results {
2023-07-27 11:58:12 +03:30
err1 := s . xrayApi . RemoveUser ( result . Tag , result . Email )
if err1 == nil {
2023-07-18 02:40:22 +03:30
logger . Debug ( "Client disabled by api:" , result . Email )
2023-06-05 00:32:19 +03:30
} else {
2024-10-10 17:37:06 +02:00
if strings . Contains ( err1 . Error ( ) , fmt . Sprintf ( "User %s not found." , result . Email ) ) {
logger . Debug ( "User is already disabled. Nothing to do more..." )
} else {
if strings . Contains ( err1 . Error ( ) , fmt . Sprintf ( "User %s not found." , result . Email ) ) {
logger . Debug ( "User is already disabled. Nothing to do more..." )
} else {
logger . Debug ( "Error in disabling client by api:" , err1 )
needRestart = true
}
}
2023-06-05 00:32:19 +03:30
}
}
s . xrayApi . Close ( )
}
2023-08-26 15:19:51 +03:30
result := tx . Model ( xray . ClientTraffic { } ) .
2023-04-18 21:34:06 +03:30
Where ( "((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?" , now , true ) .
Update ( "enable" , false )
err := result . Error
count := result . RowsAffected
2023-06-05 00:32:19 +03:30
return needRestart , count , err
2023-04-18 21:34:06 +03:30
}
2023-05-06 00:22:39 +04:30
2023-12-05 18:13:36 +01:00
func ( s * InboundService ) GetInboundTags ( ) ( string , error ) {
db := database . GetDB ( )
var inboundTags [ ] string
err := db . Model ( model . Inbound { } ) . Select ( "tag" ) . Find ( & inboundTags ) . Error
if err != nil && err != gorm . ErrRecordNotFound {
return "" , err
}
2023-12-08 19:44:52 +01:00
tags , _ := json . Marshal ( inboundTags )
return string ( tags ) , nil
2023-12-05 18:13:36 +01:00
}
2023-05-06 00:22:39 +04:30
func ( s * InboundService ) MigrationRemoveOrphanedTraffics ( ) {
2023-04-13 18:45:18 +03:30
db := database . GetDB ( )
db . Exec ( `
DELETE FROM client_traffics
WHERE email NOT IN (
SELECT JSON_EXTRACT(client.value, '$.email')
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
)
` )
}
2023-05-06 00:22:39 +04:30
2023-06-05 00:32:19 +03:30
func ( s * InboundService ) AddClientStat ( tx * gorm . DB , inboundId int , client * model . Client ) error {
2023-03-17 19:37:49 +03:30
clientTraffic := xray . ClientTraffic { }
clientTraffic . InboundId = inboundId
clientTraffic . Email = client . Email
clientTraffic . Total = client . TotalGB
clientTraffic . ExpiryTime = client . ExpiryTime
clientTraffic . Enable = true
clientTraffic . Up = 0
clientTraffic . Down = 0
2023-12-04 19:20:16 +01:00
clientTraffic . Reset = client . Reset
2023-06-05 00:32:19 +03:30
result := tx . Create ( & clientTraffic )
2023-03-17 19:37:49 +03:30
err := result . Error
2024-03-12 17:35:17 +03:30
return err
2023-02-09 22:48:06 +03:30
}
2023-05-06 00:22:39 +04:30
2023-12-04 19:20:16 +01:00
func ( s * InboundService ) UpdateClientStat ( tx * gorm . DB , email string , client * model . Client ) error {
result := tx . Model ( xray . ClientTraffic { } ) .
2023-03-17 19:37:49 +03:30
Where ( "email = ?" , email ) .
2025-03-12 20:13:51 +01:00
Updates ( map [ string ] any {
2023-03-17 19:37:49 +03:30
"enable" : true ,
"email" : client . Email ,
"total" : client . TotalGB ,
2023-12-04 19:20:16 +01:00
"expiry_time" : client . ExpiryTime ,
2024-03-11 01:01:24 +03:30
"reset" : client . Reset ,
} )
2023-03-17 19:37:49 +03:30
err := result . Error
2024-03-12 17:35:17 +03:30
return err
2023-02-28 23:24:29 +03:30
}
2023-03-17 18:51:43 +01:00
func ( s * InboundService ) UpdateClientIPs ( tx * gorm . DB , oldEmail string , newEmail string ) error {
return tx . Model ( model . InboundClientIps { } ) . Where ( "client_email = ?" , oldEmail ) . Update ( "client_email" , newEmail ) . Error
}
2023-03-17 19:37:49 +03:30
func ( s * InboundService ) DelClientStat ( tx * gorm . DB , email string ) error {
2023-03-17 19:29:08 +01:00
return tx . Where ( "email = ?" , email ) . Delete ( xray . ClientTraffic { } ) . Error
2023-03-17 18:51:43 +01:00
}
func ( s * InboundService ) DelClientIPs ( tx * gorm . DB , email string ) error {
2023-03-17 19:29:08 +01:00
return tx . Where ( "client_email = ?" , email ) . Delete ( model . InboundClientIps { } ) . Error
2023-03-17 19:37:49 +03:30
}
2023-05-14 22:07:49 +03:30
func ( s * InboundService ) GetClientInboundByTrafficID ( trafficId int ) ( traffic * xray . ClientTraffic , inbound * model . Inbound , err error ) {
db := database . GetDB ( )
var traffics [ ] * xray . ClientTraffic
err = db . Model ( xray . ClientTraffic { } ) . Where ( "id = ?" , trafficId ) . Find ( & traffics ) . Error
if err != nil {
2024-07-08 23:08:00 +02:00
logger . Warningf ( "Error retrieving ClientTraffic with trafficId %d: %v" , trafficId , err )
2023-05-14 22:07:49 +03:30
return nil , nil , err
}
if len ( traffics ) > 0 {
inbound , err = s . GetInbound ( traffics [ 0 ] . InboundId )
return traffics [ 0 ] , inbound , err
}
return nil , nil , nil
}
2023-05-05 18:20:56 +03:30
func ( s * InboundService ) GetClientInboundByEmail ( email string ) ( traffic * xray . ClientTraffic , inbound * model . Inbound , err error ) {
2023-05-05 01:16:43 +03:30
db := database . GetDB ( )
2023-05-05 04:34:39 +03:30
var traffics [ ] * xray . ClientTraffic
err = db . Model ( xray . ClientTraffic { } ) . Where ( "email = ?" , email ) . Find ( & traffics ) . Error
if err != nil {
2024-07-08 23:08:00 +02:00
logger . Warningf ( "Error retrieving ClientTraffic with email %s: %v" , email , err )
2023-05-05 18:20:56 +03:30
return nil , nil , err
2023-05-05 04:34:39 +03:30
}
if len ( traffics ) > 0 {
2023-05-05 18:20:56 +03:30
inbound , err = s . GetInbound ( traffics [ 0 ] . InboundId )
return traffics [ 0 ] , inbound , err
}
return nil , nil , nil
}
2023-05-14 22:07:49 +03:30
func ( s * InboundService ) GetClientByEmail ( clientEmail string ) ( * xray . ClientTraffic , * model . Client , error ) {
traffic , inbound , err := s . GetClientInboundByEmail ( clientEmail )
if err != nil {
return nil , nil , err
}
if inbound == nil {
return nil , nil , common . NewError ( "Inbound Not Found For Email:" , clientEmail )
}
2023-05-22 18:06:34 +03:30
clients , err := s . GetClients ( inbound )
2023-05-14 22:07:49 +03:30
if err != nil {
return nil , nil , err
}
for _ , client := range clients {
if client . Email == clientEmail {
return traffic , & client , nil
}
}
return nil , nil , common . NewError ( "Client Not Found In Inbound For Email:" , clientEmail )
}
2024-04-02 15:04:44 +03:30
func ( s * InboundService ) SetClientTelegramUserID ( trafficId int , tgId int64 ) ( bool , error ) {
2023-05-14 22:07:49 +03:30
traffic , inbound , err := s . GetClientInboundByTrafficID ( trafficId )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-14 22:07:49 +03:30
}
if inbound == nil {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Inbound Not Found For Traffic ID:" , trafficId )
2023-05-14 22:07:49 +03:30
}
clientEmail := traffic . Email
2023-05-22 18:06:34 +03:30
oldClients , err := s . GetClients ( inbound )
2023-05-14 22:07:49 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-14 22:07:49 +03:30
}
clientId := ""
for _ , oldClient := range oldClients {
if oldClient . Email == clientEmail {
2025-08-17 13:37:49 +02:00
switch inbound . Protocol {
case "trojan" :
2023-05-14 22:07:49 +03:30
clientId = oldClient . Password
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-01-01 18:07:56 +03:00
clientId = oldClient . Email
2025-08-17 13:37:49 +02:00
default :
2023-05-14 22:07:49 +03:30
clientId = oldClient . ID
}
break
}
}
if len ( clientId ) == 0 {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Client Not Found For Email:" , clientEmail )
2023-05-14 22:07:49 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-05-14 22:07:49 +03:30
err = json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-14 22:07:49 +03:30
}
2025-03-12 20:13:51 +01:00
clients := settings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2023-05-14 22:07:49 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-05-14 22:07:49 +03:30
if c [ "email" ] == clientEmail {
c [ "tgId" ] = tgId
2025-08-27 21:00:49 +03:30
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-05-14 22:07:49 +03:30
}
}
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-14 22:07:49 +03:30
}
inbound . Settings = string ( modifiedSettings )
2024-03-15 21:13:20 +03:00
needRestart , err := s . UpdateInboundClient ( inbound , clientId )
return needRestart , err
2023-05-14 22:07:49 +03:30
}
2024-01-01 18:07:56 +03:00
func ( s * InboundService ) checkIsEnabledByEmail ( clientEmail string ) ( bool , error ) {
_ , inbound , err := s . GetClientInboundByEmail ( clientEmail )
if err != nil {
return false , err
}
if inbound == nil {
return false , common . NewError ( "Inbound Not Found For Email:" , clientEmail )
}
clients , err := s . GetClients ( inbound )
if err != nil {
return false , err
}
isEnable := false
for _ , client := range clients {
if client . Email == clientEmail {
isEnable = client . Enable
break
}
}
return isEnable , err
}
2024-03-15 21:13:20 +03:00
func ( s * InboundService ) ToggleClientEnableByEmail ( clientEmail string ) ( bool , bool , error ) {
2023-05-05 19:50:40 +03:30
_ , inbound , err := s . GetClientInboundByEmail ( clientEmail )
2023-05-05 18:20:56 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , false , err
2023-05-05 18:20:56 +03:30
}
2023-05-05 19:50:40 +03:30
if inbound == nil {
2024-03-15 21:13:20 +03:00
return false , false , common . NewError ( "Inbound Not Found For Email:" , clientEmail )
2023-05-05 18:20:56 +03:30
}
2023-05-22 18:06:34 +03:30
oldClients , err := s . GetClients ( inbound )
2023-05-05 18:20:56 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , false , err
2023-05-05 18:20:56 +03:30
}
clientId := ""
2023-05-05 19:50:40 +03:30
clientOldEnabled := false
2023-05-05 18:20:56 +03:30
for _ , oldClient := range oldClients {
if oldClient . Email == clientEmail {
2025-08-17 13:37:49 +02:00
switch inbound . Protocol {
case "trojan" :
2023-05-05 18:20:56 +03:30
clientId = oldClient . Password
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-01-01 18:07:56 +03:00
clientId = oldClient . Email
2025-08-17 13:37:49 +02:00
default :
2023-05-05 18:20:56 +03:30
clientId = oldClient . ID
}
2023-05-05 19:50:40 +03:30
clientOldEnabled = oldClient . Enable
2023-05-05 18:20:56 +03:30
break
}
}
if len ( clientId ) == 0 {
2024-03-15 21:13:20 +03:00
return false , false , common . NewError ( "Client Not Found For Email:" , clientEmail )
2023-05-05 18:20:56 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-05-05 18:20:56 +03:30
err = json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , false , err
2023-05-05 18:20:56 +03:30
}
2025-03-12 20:13:51 +01:00
clients := settings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2023-05-05 18:20:56 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-05-05 18:20:56 +03:30
if c [ "email" ] == clientEmail {
2023-05-05 19:50:40 +03:30
c [ "enable" ] = ! clientOldEnabled
2025-08-27 21:00:49 +03:30
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-05-05 18:20:56 +03:30
}
}
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , false , err
2023-05-05 18:20:56 +03:30
}
inbound . Settings = string ( modifiedSettings )
2023-06-05 00:32:19 +03:30
2024-03-15 21:13:20 +03:00
needRestart , err := s . UpdateInboundClient ( inbound , clientId )
2023-06-05 00:32:19 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , needRestart , err
2023-06-05 00:32:19 +03:30
}
2024-03-15 21:13:20 +03:00
return ! clientOldEnabled , needRestart , nil
2023-05-05 18:20:56 +03:30
}
2024-03-15 21:13:20 +03:00
func ( s * InboundService ) ResetClientIpLimitByEmail ( clientEmail string , count int ) ( bool , error ) {
2023-05-05 19:50:40 +03:30
_ , inbound , err := s . GetClientInboundByEmail ( clientEmail )
2023-05-05 18:20:56 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 18:20:56 +03:30
}
2023-05-05 19:50:40 +03:30
if inbound == nil {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Inbound Not Found For Email:" , clientEmail )
2023-05-05 18:20:56 +03:30
}
2023-05-22 18:06:34 +03:30
oldClients , err := s . GetClients ( inbound )
2023-05-05 18:20:56 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 18:20:56 +03:30
}
clientId := ""
for _ , oldClient := range oldClients {
if oldClient . Email == clientEmail {
2025-08-17 13:37:49 +02:00
switch inbound . Protocol {
case "trojan" :
2023-05-05 18:20:56 +03:30
clientId = oldClient . Password
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-01-01 18:07:56 +03:00
clientId = oldClient . Email
2025-08-17 13:37:49 +02:00
default :
2023-05-05 18:20:56 +03:30
clientId = oldClient . ID
}
break
}
}
if len ( clientId ) == 0 {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Client Not Found For Email:" , clientEmail )
2023-05-05 18:20:56 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-05-05 18:20:56 +03:30
err = json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 18:20:56 +03:30
}
2025-03-12 20:13:51 +01:00
clients := settings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2023-05-05 18:20:56 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-05-05 18:20:56 +03:30
if c [ "email" ] == clientEmail {
c [ "limitIp" ] = count
2025-08-27 21:00:49 +03:30
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-05-05 18:20:56 +03:30
}
}
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 04:34:39 +03:30
}
2023-05-05 18:20:56 +03:30
inbound . Settings = string ( modifiedSettings )
2024-03-15 21:13:20 +03:00
needRestart , err := s . UpdateInboundClient ( inbound , clientId )
return needRestart , err
2023-06-05 00:32:19 +03:30
}
2023-07-01 15:56:43 +03:30
2024-03-15 21:13:20 +03:00
func ( s * InboundService ) ResetClientExpiryTimeByEmail ( clientEmail string , expiry_time int64 ) ( bool , error ) {
2023-05-05 19:50:40 +03:30
_ , inbound , err := s . GetClientInboundByEmail ( clientEmail )
2023-05-05 04:34:39 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 04:34:39 +03:30
}
if inbound == nil {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Inbound Not Found For Email:" , clientEmail )
2023-05-05 04:34:39 +03:30
}
2023-05-05 01:16:43 +03:30
2023-05-22 18:06:34 +03:30
oldClients , err := s . GetClients ( inbound )
2023-05-05 04:34:39 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 04:34:39 +03:30
}
2023-05-05 01:16:43 +03:30
2023-05-05 04:34:39 +03:30
clientId := ""
for _ , oldClient := range oldClients {
if oldClient . Email == clientEmail {
2025-08-17 13:37:49 +02:00
switch inbound . Protocol {
case "trojan" :
2023-05-05 04:34:39 +03:30
clientId = oldClient . Password
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-01-01 18:07:56 +03:00
clientId = oldClient . Email
2025-08-17 13:37:49 +02:00
default :
2023-05-05 04:34:39 +03:30
clientId = oldClient . ID
}
break
}
}
if len ( clientId ) == 0 {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Client Not Found For Email:" , clientEmail )
2023-05-05 04:34:39 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-05-05 04:34:39 +03:30
err = json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings )
2023-05-05 01:16:43 +03:30
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 01:16:43 +03:30
}
2025-03-12 20:13:51 +01:00
clients := settings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2023-05-05 04:34:39 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-05-05 04:34:39 +03:30
if c [ "email" ] == clientEmail {
c [ "expiryTime" ] = expiry_time
2025-08-27 21:00:49 +03:30
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-05-05 04:34:39 +03:30
}
}
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-05-05 04:34:39 +03:30
}
inbound . Settings = string ( modifiedSettings )
2024-03-15 21:13:20 +03:00
needRestart , err := s . UpdateInboundClient ( inbound , clientId )
return needRestart , err
2023-05-05 01:16:43 +03:30
}
2024-03-15 21:13:20 +03:00
func ( s * InboundService ) ResetClientTrafficLimitByEmail ( clientEmail string , totalGB int ) ( bool , error ) {
2023-11-20 17:47:59 +03:30
if totalGB < 0 {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "totalGB must be >= 0" )
2023-11-20 17:47:59 +03:30
}
_ , inbound , err := s . GetClientInboundByEmail ( clientEmail )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-11-20 17:47:59 +03:30
}
if inbound == nil {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Inbound Not Found For Email:" , clientEmail )
2023-11-20 17:47:59 +03:30
}
oldClients , err := s . GetClients ( inbound )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-11-20 17:47:59 +03:30
}
clientId := ""
for _ , oldClient := range oldClients {
if oldClient . Email == clientEmail {
2025-08-17 13:37:49 +02:00
switch inbound . Protocol {
case "trojan" :
2023-11-20 17:47:59 +03:30
clientId = oldClient . Password
2025-08-17 13:37:49 +02:00
case "shadowsocks" :
2024-01-01 18:07:56 +03:00
clientId = oldClient . Email
2025-08-17 13:37:49 +02:00
default :
2023-11-20 17:47:59 +03:30
clientId = oldClient . ID
}
break
}
}
if len ( clientId ) == 0 {
2024-03-15 21:13:20 +03:00
return false , common . NewError ( "Client Not Found For Email:" , clientEmail )
2023-11-20 17:47:59 +03:30
}
2025-03-12 20:13:51 +01:00
var settings map [ string ] any
2023-11-20 17:47:59 +03:30
err = json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-11-20 17:47:59 +03:30
}
2025-03-12 20:13:51 +01:00
clients := settings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2023-11-20 17:47:59 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-11-20 17:47:59 +03:30
if c [ "email" ] == clientEmail {
c [ "totalGB" ] = totalGB * 1024 * 1024 * 1024
2025-08-27 21:00:49 +03:30
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-11-20 17:47:59 +03:30
}
}
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
2024-03-15 21:13:20 +03:00
return false , err
2023-11-20 17:47:59 +03:30
}
inbound . Settings = string ( modifiedSettings )
2024-03-15 21:13:20 +03:00
needRestart , err := s . UpdateInboundClient ( inbound , clientId )
return needRestart , err
2023-11-20 17:47:59 +03:30
}
2023-05-05 01:16:43 +03:30
func ( s * InboundService ) ResetClientTrafficByEmail ( clientEmail string ) error {
db := database . GetDB ( )
result := db . Model ( xray . ClientTraffic { } ) .
Where ( "email = ?" , clientEmail ) .
2025-03-12 20:13:51 +01:00
Updates ( map [ string ] any { "enable" : true , "up" : 0 , "down" : 0 } )
2023-05-05 01:16:43 +03:30
err := result . Error
if err != nil {
return err
}
return nil
}
2023-06-05 00:32:19 +03:30
func ( s * InboundService ) ResetClientTraffic ( id int , clientEmail string ) ( bool , error ) {
needRestart := false
2023-02-09 22:48:06 +03:30
2023-06-05 00:32:19 +03:30
traffic , err := s . GetClientTrafficByEmail ( clientEmail )
if err != nil {
return false , err
}
2023-02-28 23:24:29 +03:30
2023-06-05 00:32:19 +03:30
if ! traffic . Enable {
inbound , err := s . GetInbound ( id )
if err != nil {
return false , err
}
clients , err := s . GetClients ( inbound )
if err != nil {
return false , err
}
for _ , client := range clients {
2024-10-15 20:54:23 +02:00
if client . Email == clientEmail && client . Enable {
2023-06-05 00:32:19 +03:30
s . xrayApi . Init ( p . GetAPIPort ( ) )
2023-07-27 11:58:12 +03:30
cipher := ""
if string ( inbound . Protocol ) == "shadowsocks" {
2025-03-12 20:13:51 +01:00
var oldSettings map [ string ] any
2023-07-27 11:58:12 +03:30
err = json . Unmarshal ( [ ] byte ( inbound . Settings ) , & oldSettings )
if err != nil {
return false , err
}
cipher = oldSettings [ "method" ] . ( string )
}
2025-03-12 20:13:51 +01:00
err1 := s . xrayApi . AddUser ( string ( inbound . Protocol ) , inbound . Tag , map [ string ] any {
2023-06-05 00:32:19 +03:30
"email" : client . Email ,
"id" : client . ID ,
2024-08-11 00:47:44 +02:00
"security" : client . Security ,
2023-06-05 00:32:19 +03:30
"flow" : client . Flow ,
"password" : client . Password ,
2023-07-27 11:58:12 +03:30
"cipher" : cipher ,
2023-06-05 00:32:19 +03:30
} )
if err1 == nil {
logger . Debug ( "Client enabled due to reset traffic:" , clientEmail )
} else {
2023-07-27 11:58:12 +03:30
logger . Debug ( "Error in enabling client by api:" , err1 )
2023-06-05 00:32:19 +03:30
needRestart = true
}
s . xrayApi . Close ( )
break
}
}
}
traffic . Up = 0
traffic . Down = 0
traffic . Enable = true
2023-02-28 23:24:29 +03:30
2023-06-05 00:32:19 +03:30
db := database . GetDB ( )
err = db . Save ( traffic ) . Error
2023-02-28 23:24:29 +03:30
if err != nil {
2023-06-05 00:32:19 +03:30
return false , err
2023-02-28 23:24:29 +03:30
}
2023-06-05 00:32:19 +03:30
return needRestart , nil
2023-02-28 23:24:29 +03:30
}
2023-04-09 23:13:18 +03:30
func ( s * InboundService ) ResetAllClientTraffics ( id int ) error {
2023-02-09 22:48:06 +03:30
db := database . GetDB ( )
2023-04-25 14:38:35 +03:30
whereText := "inbound_id "
if id == - 1 {
whereText += " > ?"
} else {
whereText += " = ?"
}
2023-04-09 23:13:18 +03:30
result := db . Model ( xray . ClientTraffic { } ) .
2023-04-25 14:38:35 +03:30
Where ( whereText , id ) .
2025-03-12 20:13:51 +01:00
Updates ( map [ string ] any { "enable" : true , "up" : 0 , "down" : 0 } )
2023-04-09 23:13:18 +03:30
err := result . Error
2024-03-12 17:35:17 +03:30
return err
2023-04-09 23:13:18 +03:30
}
func ( s * InboundService ) ResetAllTraffics ( ) error {
db := database . GetDB ( )
result := db . Model ( model . Inbound { } ) .
Where ( "user_id > ?" , 0 ) .
2025-03-12 20:13:51 +01:00
Updates ( map [ string ] any { "up" : 0 , "down" : 0 } )
2023-04-09 23:13:18 +03:30
err := result . Error
2024-03-12 17:35:17 +03:30
return err
2023-04-09 23:13:18 +03:30
}
2023-04-25 18:43:37 +03:30
func ( s * InboundService ) DelDepletedClients ( id int ) ( err error ) {
db := database . GetDB ( )
tx := db . Begin ( )
defer func ( ) {
if err == nil {
tx . Commit ( )
} else {
tx . Rollback ( )
}
} ( )
2023-12-04 19:20:16 +01:00
whereText := "reset = 0 and inbound_id "
2023-04-25 18:43:37 +03:30
if id < 0 {
whereText += "> ?"
} else {
whereText += "= ?"
}
depletedClients := [ ] xray . ClientTraffic { }
err = db . Model ( xray . ClientTraffic { } ) . Where ( whereText + " and enable = ?" , id , false ) . Select ( "inbound_id, GROUP_CONCAT(email) as email" ) . Group ( "inbound_id" ) . Find ( & depletedClients ) . Error
if err != nil {
return err
}
for _ , depletedClient := range depletedClients {
emails := strings . Split ( depletedClient . Email , "," )
oldInbound , err := s . GetInbound ( depletedClient . InboundId )
if err != nil {
return err
}
2025-03-12 20:13:51 +01:00
var oldSettings map [ string ] any
2023-04-25 18:43:37 +03:30
err = json . Unmarshal ( [ ] byte ( oldInbound . Settings ) , & oldSettings )
if err != nil {
return err
}
2025-03-12 20:13:51 +01:00
oldClients := oldSettings [ "clients" ] . ( [ ] any )
var newClients [ ] any
2023-04-25 18:43:37 +03:30
for _ , client := range oldClients {
deplete := false
2025-03-12 20:13:51 +01:00
c := client . ( map [ string ] any )
2023-04-25 18:43:37 +03:30
for _ , email := range emails {
if email == c [ "email" ] . ( string ) {
deplete = true
break
}
}
if ! deplete {
newClients = append ( newClients , client )
}
}
if len ( newClients ) > 0 {
oldSettings [ "clients" ] = newClients
newSettings , err := json . MarshalIndent ( oldSettings , "" , " " )
if err != nil {
return err
}
oldInbound . Settings = string ( newSettings )
err = tx . Save ( oldInbound ) . Error
if err != nil {
return err
}
} else {
// Delete inbound if no client remains
s . DelInbound ( depletedClient . InboundId )
}
}
err = tx . Where ( whereText + " and enable = ?" , id , false ) . Delete ( xray . ClientTraffic { } ) . Error
2024-06-17 21:55:09 +02:00
if err != nil {
return err
}
return nil
2023-04-25 18:43:37 +03:30
}
2024-04-02 15:04:44 +03:30
func ( s * InboundService ) GetClientTrafficTgBot ( tgId int64 ) ( [ ] * xray . ClientTraffic , error ) {
2023-04-09 23:13:18 +03:30
db := database . GetDB ( )
var inbounds [ ] * model . Inbound
2024-07-08 23:08:00 +02:00
// Retrieve inbounds where settings contain the given tgId
err := db . Model ( model . Inbound { } ) . Where ( "settings LIKE ?" , fmt . Sprintf ( ` %%"tgId": %d%% ` , tgId ) ) . Find ( & inbounds ) . Error
2023-04-09 23:13:18 +03:30
if err != nil && err != gorm . ErrRecordNotFound {
2024-07-08 23:08:00 +02:00
logger . Errorf ( "Error retrieving inbounds with tgId %d: %v" , tgId , err )
2023-04-09 23:13:18 +03:30
return nil , err
}
2024-07-08 23:08:00 +02:00
2023-04-09 23:13:18 +03:30
var emails [ ] string
for _ , inbound := range inbounds {
2023-05-22 18:06:34 +03:30
clients , err := s . GetClients ( inbound )
2023-04-09 23:13:18 +03:30
if err != nil {
2024-07-08 23:08:00 +02:00
logger . Errorf ( "Error retrieving clients for inbound %d: %v" , inbound . Id , err )
continue
2023-04-09 23:13:18 +03:30
}
for _ , client := range clients {
2024-01-01 18:07:56 +03:00
if client . TgID == tgId {
2023-04-09 23:13:18 +03:30
emails = append ( emails , client . Email )
}
}
}
2024-07-08 23:08:00 +02:00
2023-04-09 23:13:18 +03:30
var traffics [ ] * xray . ClientTraffic
err = db . Model ( xray . ClientTraffic { } ) . Where ( "email IN ?" , emails ) . Find ( & traffics ) . Error
2023-03-17 19:37:49 +03:30
if err != nil {
if err == gorm . ErrRecordNotFound {
2024-07-08 23:08:00 +02:00
logger . Warning ( "No ClientTraffic records found for emails:" , emails )
return nil , nil
2023-03-17 19:37:49 +03:30
}
2024-07-08 23:08:00 +02:00
logger . Errorf ( "Error retrieving ClientTraffic for emails %v: %v" , emails , err )
return nil , err
2023-03-17 19:37:49 +03:30
}
2024-07-08 23:08:00 +02:00
return traffics , nil
2023-03-17 19:37:49 +03:30
}
2023-02-09 22:48:06 +03:30
2023-04-25 14:38:35 +03:30
func ( s * InboundService ) GetClientTrafficByEmail ( email string ) ( traffic * xray . ClientTraffic , err error ) {
2023-03-17 19:37:49 +03:30
db := database . GetDB ( )
var traffics [ ] * xray . ClientTraffic
2023-02-09 22:48:06 +03:30
2023-04-21 19:06:59 +03:30
err = db . Model ( xray . ClientTraffic { } ) . Where ( "email = ?" , email ) . Find ( & traffics ) . Error
2023-02-09 22:48:06 +03:30
if err != nil {
2024-07-08 23:08:00 +02:00
logger . Warningf ( "Error retrieving ClientTraffic with email %s: %v" , email , err )
2023-04-28 18:40:33 +03:30
return nil , err
}
if len ( traffics ) > 0 {
return traffics [ 0 ] , nil
2023-02-09 22:48:06 +03:30
}
2023-04-28 18:40:33 +03:30
return nil , nil
2023-02-09 22:48:06 +03:30
}
2023-03-17 19:37:49 +03:30
2025-07-23 01:13:48 +03:30
func ( s * InboundService ) UpdateClientTrafficByEmail ( email string , upload int64 , download int64 ) error {
db := database . GetDB ( )
result := db . Model ( xray . ClientTraffic { } ) .
Where ( "email = ?" , email ) .
Updates ( map [ string ] any { "up" : upload , "down" : download } )
err := result . Error
if err != nil {
logger . Warningf ( "Error updating ClientTraffic with email %s: %v" , email , err )
return err
}
return nil
}
2024-07-23 11:28:28 +02:00
func ( s * InboundService ) GetClientTrafficByID ( id string ) ( [ ] xray . ClientTraffic , error ) {
db := database . GetDB ( )
var traffics [ ] xray . ClientTraffic
err := db . Model ( xray . ClientTraffic { } ) . Where ( ` email IN(
SELECT JSON_EXTRACT(client.value, '$.email') as email
FROM inbounds,
JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
WHERE
JSON_EXTRACT(client.value, '$.id') in (?)
) ` , id ) . Find ( & traffics ) . Error
if err != nil {
logger . Debug ( err )
return nil , err
}
return traffics , err
}
2023-03-17 19:37:49 +03:30
func ( s * InboundService ) SearchClientTraffic ( query string ) ( traffic * xray . ClientTraffic , err error ) {
2023-02-09 22:48:06 +03:30
db := database . GetDB ( )
inbound := & model . Inbound { }
traffic = & xray . ClientTraffic { }
2024-07-08 23:08:00 +02:00
// Search for inbound settings that contain the query
err = db . Model ( model . Inbound { } ) . Where ( "settings LIKE ?" , "%\"" + query + "\"%" ) . First ( inbound ) . Error
2023-02-09 22:48:06 +03:30
if err != nil {
if err == gorm . ErrRecordNotFound {
2024-07-08 23:08:00 +02:00
logger . Warningf ( "Inbound settings containing query %s not found: %v" , query , err )
2023-02-09 22:48:06 +03:30
return nil , err
}
2024-07-08 23:08:00 +02:00
logger . Errorf ( "Error searching for inbound settings with query %s: %v" , query , err )
return nil , err
2023-02-09 22:48:06 +03:30
}
2024-07-08 23:08:00 +02:00
2023-02-09 22:48:06 +03:30
traffic . InboundId = inbound . Id
2024-07-08 23:08:00 +02:00
// Unmarshal settings to get clients
2023-02-09 22:48:06 +03:30
settings := map [ string ] [ ] model . Client { }
2024-07-08 23:08:00 +02:00
if err := json . Unmarshal ( [ ] byte ( inbound . Settings ) , & settings ) ; err != nil {
logger . Errorf ( "Error unmarshalling inbound settings for inbound ID %d: %v" , inbound . Id , err )
return nil , err
}
2023-02-09 22:48:06 +03:30
clients := settings [ "clients" ]
for _ , client := range clients {
2024-07-08 23:08:00 +02:00
if ( client . ID == query || client . Password == query ) && client . Email != "" {
2023-02-09 22:48:06 +03:30
traffic . Email = client . Email
2023-03-17 19:37:49 +03:30
break
2023-02-09 22:48:06 +03:30
}
}
2024-07-08 23:08:00 +02:00
2023-03-17 19:37:49 +03:30
if traffic . Email == "" {
2024-07-08 23:08:00 +02:00
logger . Warningf ( "No client found with query %s in inbound ID %d" , query , inbound . Id )
return nil , gorm . ErrRecordNotFound
2023-03-17 19:37:49 +03:30
}
2024-07-08 23:08:00 +02:00
// Retrieve ClientTraffic based on the found email
2023-02-09 22:48:06 +03:30
err = db . Model ( xray . ClientTraffic { } ) . Where ( "email = ?" , traffic . Email ) . First ( traffic ) . Error
if err != nil {
2024-07-08 23:08:00 +02:00
if err == gorm . ErrRecordNotFound {
logger . Warningf ( "ClientTraffic for email %s not found: %v" , traffic . Email , err )
return nil , err
}
logger . Errorf ( "Error retrieving ClientTraffic for email %s: %v" , traffic . Email , err )
2023-02-09 22:48:06 +03:30
return nil , err
}
2024-07-08 23:08:00 +02:00
return traffic , nil
2023-02-09 22:48:06 +03:30
}
2023-03-17 18:51:43 +01:00
2023-03-17 19:37:49 +03:30
func ( s * InboundService ) GetInboundClientIps ( clientEmail string ) ( string , error ) {
db := database . GetDB ( )
InboundClientIps := & model . InboundClientIps { }
err := db . Model ( model . InboundClientIps { } ) . Where ( "client_email = ?" , clientEmail ) . First ( InboundClientIps ) . Error
if err != nil {
return "" , err
}
return InboundClientIps . Ips , nil
}
2023-05-31 01:21:14 +04:30
2023-03-17 18:51:43 +01:00
func ( s * InboundService ) ClearClientIps ( clientEmail string ) error {
2023-03-17 19:37:49 +03:30
db := database . GetDB ( )
result := db . Model ( model . InboundClientIps { } ) .
Where ( "client_email = ?" , clientEmail ) .
Update ( "ips" , "" )
err := result . Error
if err != nil {
return err
}
return nil
}
2023-03-24 17:14:26 +03:30
func ( s * InboundService ) SearchInbounds ( query string ) ( [ ] * model . Inbound , error ) {
db := database . GetDB ( )
var inbounds [ ] * model . Inbound
err := db . Model ( model . Inbound { } ) . Preload ( "ClientStats" ) . Where ( "remark like ?" , "%" + query + "%" ) . Find ( & inbounds ) . Error
if err != nil && err != gorm . ErrRecordNotFound {
return nil , err
}
return inbounds , nil
2023-04-09 23:13:18 +03:30
}
2023-04-25 14:38:35 +03:30
2023-04-24 14:13:25 +03:30
func ( s * InboundService ) MigrationRequirements ( ) {
db := database . GetDB ( )
2023-06-05 00:32:19 +03:30
tx := db . Begin ( )
var err error
defer func ( ) {
if err == nil {
tx . Commit ( )
} else {
tx . Rollback ( )
}
} ( )
2025-08-28 02:40:50 +03:30
// Calculate and backfill all_time from up+down for inbounds and clients
err = tx . Exec ( `
UPDATE inbounds
SET all_time = IFNULL(up, 0) + IFNULL(down, 0)
WHERE IFNULL(all_time, 0) = 0 AND (IFNULL(up, 0) + IFNULL(down, 0)) > 0
` ) . Error
if err != nil {
return
}
err = tx . Exec ( `
UPDATE client_traffics
SET all_time = IFNULL(up, 0) + IFNULL(down, 0)
WHERE IFNULL(all_time, 0) = 0 AND (IFNULL(up, 0) + IFNULL(down, 0)) > 0
` ) . Error
if err != nil {
return
}
2023-04-27 19:05:36 +03:30
// Fix inbounds based problems
2023-04-24 14:13:25 +03:30
var inbounds [ ] * model . Inbound
2023-06-05 00:32:19 +03:30
err = tx . Model ( model . Inbound { } ) . Where ( "protocol IN (?)" , [ ] string { "vmess" , "vless" , "trojan" } ) . Find ( & inbounds ) . Error
2023-04-24 14:13:25 +03:30
if err != nil && err != gorm . ErrRecordNotFound {
return
}
for inbound_index := range inbounds {
2025-03-12 20:13:51 +01:00
settings := map [ string ] any { }
2023-04-24 14:13:25 +03:30
json . Unmarshal ( [ ] byte ( inbounds [ inbound_index ] . Settings ) , & settings )
2025-03-12 20:13:51 +01:00
clients , ok := settings [ "clients" ] . ( [ ] any )
2023-04-24 14:13:25 +03:30
if ok {
2024-02-27 20:33:37 +09:00
// Fix Client configuration problems
2025-03-12 20:13:51 +01:00
var newClients [ ] any
2023-04-24 14:13:25 +03:30
for client_index := range clients {
2025-03-12 20:13:51 +01:00
c := clients [ client_index ] . ( map [ string ] any )
2023-04-24 14:13:25 +03:30
// Add email='' if it is not exists
if _ , ok := c [ "email" ] ; ! ok {
c [ "email" ] = ""
}
2024-04-05 12:24:18 +03:00
// Convert string tgId to int64
if _ , ok := c [ "tgId" ] ; ok {
2025-03-12 20:13:51 +01:00
var tgId any = c [ "tgId" ]
2024-04-05 12:24:18 +03:00
if tgIdStr , ok2 := tgId . ( string ) ; ok2 {
tgIdInt64 , err := strconv . ParseInt ( strings . ReplaceAll ( tgIdStr , " " , "" ) , 10 , 64 )
if err == nil {
c [ "tgId" ] = tgIdInt64
}
}
}
2023-04-24 14:13:25 +03:30
// Remove "flow": "xtls-rprx-direct"
if _ , ok := c [ "flow" ] ; ok {
if c [ "flow" ] == "xtls-rprx-direct" {
c [ "flow" ] = ""
}
}
2025-08-27 21:00:49 +03:30
// Backfill created_at and updated_at
if _ , ok := c [ "created_at" ] ; ! ok {
c [ "created_at" ] = time . Now ( ) . Unix ( ) * 1000
}
c [ "updated_at" ] = time . Now ( ) . Unix ( ) * 1000
2025-03-12 20:13:51 +01:00
newClients = append ( newClients , any ( c ) )
2023-04-24 14:13:25 +03:30
}
settings [ "clients" ] = newClients
modifiedSettings , err := json . MarshalIndent ( settings , "" , " " )
if err != nil {
return
}
inbounds [ inbound_index ] . Settings = string ( modifiedSettings )
}
2023-06-05 00:32:19 +03:30
2023-04-27 19:05:36 +03:30
// Add client traffic row for all clients which has email
2023-05-22 18:06:34 +03:30
modelClients , err := s . GetClients ( inbounds [ inbound_index ] )
2023-04-25 18:36:06 +03:30
if err != nil {
return
}
for _ , modelClient := range modelClients {
if len ( modelClient . Email ) > 0 {
var count int64
2023-06-05 00:32:19 +03:30
tx . Model ( xray . ClientTraffic { } ) . Where ( "email = ?" , modelClient . Email ) . Count ( & count )
2023-04-25 18:36:06 +03:30
if count == 0 {
2023-06-05 00:32:19 +03:30
s . AddClientStat ( tx , inbounds [ inbound_index ] . Id , & modelClient )
2023-04-25 18:36:06 +03:30
}
}
}
2023-04-24 14:13:25 +03:30
}
2023-06-05 00:32:19 +03:30
tx . Save ( inbounds )
2023-04-27 19:05:36 +03:30
// Remove orphaned traffics
2023-06-05 00:32:19 +03:30
tx . Where ( "inbound_id = 0" ) . Delete ( xray . ClientTraffic { } )
2023-12-08 18:45:21 +01:00
// Migrate old MultiDomain to External Proxy
var externalProxy [ ] struct {
Id int
Port int
StreamSettings [ ] byte
}
err = tx . Raw ( ` select id, port, stream_settings
from inbounds
WHERE protocol in ('vmess','vless','trojan')
AND json_extract(stream_settings, '$.security') = 'tls'
AND json_extract(stream_settings, '$.tlsSettings.settings.domains') IS NOT NULL ` ) . Scan ( & externalProxy ) . Error
if err != nil || len ( externalProxy ) == 0 {
return
}
for _ , ep := range externalProxy {
2025-03-12 20:13:51 +01:00
var reverses any
var stream map [ string ] any
2023-12-08 18:45:21 +01:00
json . Unmarshal ( ep . StreamSettings , & stream )
2025-03-12 20:13:51 +01:00
if tlsSettings , ok := stream [ "tlsSettings" ] . ( map [ string ] any ) ; ok {
if settings , ok := tlsSettings [ "settings" ] . ( map [ string ] any ) ; ok {
if domains , ok := settings [ "domains" ] . ( [ ] any ) ; ok {
2023-12-08 18:45:21 +01:00
for _ , domain := range domains {
2025-03-12 20:13:51 +01:00
if domainMap , ok := domain . ( map [ string ] any ) ; ok {
2023-12-08 18:45:21 +01:00
domainMap [ "forceTls" ] = "same"
domainMap [ "port" ] = ep . Port
domainMap [ "dest" ] = domainMap [ "domain" ] . ( string )
delete ( domainMap , "domain" )
}
}
}
reverses = settings [ "domains" ]
delete ( settings , "domains" )
}
}
stream [ "externalProxy" ] = reverses
newStream , _ := json . MarshalIndent ( stream , " " , " " )
tx . Model ( model . Inbound { } ) . Where ( "id = ?" , ep . Id ) . Update ( "stream_settings" , newStream )
}
2024-02-22 23:12:26 +03:30
err = tx . Raw ( ` UPDATE inbounds
SET tag = REPLACE(tag, '0.0.0.0:', '')
WHERE INSTR(tag, '0.0.0.0:') > 0; ` ) . Error
if err != nil {
return
}
2023-04-24 14:13:25 +03:30
}
2023-05-06 00:22:39 +04:30
func ( s * InboundService ) MigrateDB ( ) {
s . MigrationRequirements ( )
s . MigrationRemoveOrphanedTraffics ( )
}
2023-12-04 19:13:21 +01:00
2024-07-07 11:55:59 +02:00
func ( s * InboundService ) GetOnlineClients ( ) [ ] string {
2023-12-04 19:13:21 +01:00
return p . GetOnlineClients ( )
}
2025-05-06 19:57:17 +03:30
func ( s * InboundService ) FilterAndSortClientEmails ( emails [ ] string ) ( [ ] string , [ ] string , error ) {
db := database . GetDB ( )
// Step 1: Get ClientTraffic records for emails in the input list
var clients [ ] xray . ClientTraffic
err := db . Where ( "email IN ?" , emails ) . Find ( & clients ) . Error
if err != nil && err != gorm . ErrRecordNotFound {
return nil , nil , err
}
// Step 2: Sort clients by (Up + Down) descending
sort . Slice ( clients , func ( i , j int ) bool {
return ( clients [ i ] . Up + clients [ i ] . Down ) > ( clients [ j ] . Up + clients [ j ] . Down )
} )
// Step 3: Extract sorted valid emails and track found ones
validEmails := make ( [ ] string , 0 , len ( clients ) )
found := make ( map [ string ] bool )
for _ , client := range clients {
validEmails = append ( validEmails , client . Email )
found [ client . Email ] = true
}
// Step 4: Identify emails that were not found in the database
extraEmails := make ( [ ] string , 0 )
for _ , email := range emails {
if ! found [ email ] {
extraEmails = append ( extraEmails , email )
}
}
return validEmails , extraEmails , nil
}