mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-04-20 05:52:24 +00:00
[feature] using xray api and more
Improve DB performance [api] backward compatibility: add client by update Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
This commit is contained in:
parent
1030bcf321
commit
70f250dfe1
8 changed files with 533 additions and 178 deletions
9
go.mod
9
go.mod
|
@ -27,13 +27,15 @@ require (
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||||
github.com/fasthttp/router v1.4.19 // indirect
|
github.com/fasthttp/router v1.4.19 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
|
github.com/gaukas/godicttls v0.0.3 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
github.com/go-playground/validator/v10 v10.14.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/gorilla/context v1.1.1 // indirect
|
github.com/gorilla/context v1.1.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
|
@ -51,14 +53,19 @@ require (
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||||
|
github.com/refraction-networking/utls v1.3.2 // indirect
|
||||||
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||||
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.47.0 // indirect
|
github.com/valyala/fasthttp v1.47.0 // indirect
|
||||||
|
github.com/xtls/reality v0.0.0-20230331223127-176a94313eda // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.9.0 // indirect
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
|
|
18
go.sum
18
go.sum
|
@ -18,13 +18,16 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583j
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
|
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
|
||||||
|
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||||
github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk=
|
github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk=
|
||||||
github.com/fasthttp/router v1.4.19/go.mod h1:+Fh3YOd8x1+he6ZS+d2iUDBH9MGGZ1xQFUor0DE9rKE=
|
github.com/fasthttp/router v1.4.19/go.mod h1:+Fh3YOd8x1+he6ZS+d2iUDBH9MGGZ1xQFUor0DE9rKE=
|
||||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk=
|
github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk=
|
||||||
|
github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||||
github.com/gin-contrib/sessions v0.0.4 h1:gq4fNa1Zmp564iHP5G6EBuktilEos8VKhe2sza1KMgo=
|
github.com/gin-contrib/sessions v0.0.4 h1:gq4fNa1Zmp564iHP5G6EBuktilEos8VKhe2sza1KMgo=
|
||||||
github.com/gin-contrib/sessions v0.0.4/go.mod h1:pQ3sIyviBBGcxgyR8mkeJuXbeV3h3NYmhJADQTq5+Vo=
|
github.com/gin-contrib/sessions v0.0.4/go.mod h1:pQ3sIyviBBGcxgyR8mkeJuXbeV3h3NYmhJADQTq5+Vo=
|
||||||
|
@ -47,8 +50,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||||
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
|
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
@ -86,8 +89,6 @@ github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nV
|
||||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
||||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
|
@ -134,7 +135,9 @@ github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc8
|
||||||
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
||||||
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
|
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
|
||||||
github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
|
github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
|
||||||
|
github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
|
github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
|
||||||
|
@ -143,6 +146,7 @@ github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aW
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||||
|
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
|
github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
|
||||||
github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
|
github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||||
|
@ -154,6 +158,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
@ -164,7 +169,6 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||||
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
|
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
|
||||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||||
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
|
|
||||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||||
|
@ -176,11 +180,13 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
|
||||||
|
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
|
github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
|
||||||
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
||||||
github.com/xtls/reality v0.0.0-20230331223127-176a94313eda h1:psRJD2RrZbnI0OWyHvXfgYCPqlRM5q5SPDcjDoDBWhE=
|
github.com/xtls/reality v0.0.0-20230331223127-176a94313eda h1:psRJD2RrZbnI0OWyHvXfgYCPqlRM5q5SPDcjDoDBWhE=
|
||||||
|
github.com/xtls/reality v0.0.0-20230331223127-176a94313eda/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
|
||||||
github.com/xtls/xray-core v1.8.1 h1:iSTTqXj82ZdwC1ah+eV331X4JTcnrDz+WuKuB/EB3P4=
|
github.com/xtls/xray-core v1.8.1 h1:iSTTqXj82ZdwC1ah+eV331X4JTcnrDz+WuKuB/EB3P4=
|
||||||
github.com/xtls/xray-core v1.8.1/go.mod h1:AXxSso0MZwUE4NhRocCfHCg73BtJ+T2dSpQVo1Cg9VM=
|
github.com/xtls/xray-core v1.8.1/go.mod h1:AXxSso0MZwUE4NhRocCfHCg73BtJ+T2dSpQVo1Cg9VM=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
@ -223,7 +229,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -264,6 +269,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4=
|
gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4=
|
||||||
|
|
|
@ -79,7 +79,6 @@ func (a *InboundController) getInbound(c *gin.Context) {
|
||||||
}
|
}
|
||||||
jsonObj(c, inbound, nil)
|
jsonObj(c, inbound, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *InboundController) getClientTraffics(c *gin.Context) {
|
func (a *InboundController) getClientTraffics(c *gin.Context) {
|
||||||
email := c.Param("email")
|
email := c.Param("email")
|
||||||
clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
|
clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
|
||||||
|
@ -178,13 +177,15 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.inboundService.AddInboundClient(data)
|
needRestart := false
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.AddInboundClient(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
jsonMsg(c, "Client(s) added", nil)
|
jsonMsg(c, "Client(s) added", nil)
|
||||||
if err == nil {
|
if err == nil && needRestart {
|
||||||
a.xrayService.SetToNeedRestart()
|
a.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,13 +198,15 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
|
||||||
}
|
}
|
||||||
clientId := c.Param("clientId")
|
clientId := c.Param("clientId")
|
||||||
|
|
||||||
err = a.inboundService.DelInboundClient(id, clientId)
|
needRestart := false
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.DelInboundClient(id, clientId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
jsonMsg(c, "Client deleted", nil)
|
jsonMsg(c, "Client deleted", nil)
|
||||||
if err == nil {
|
if err == nil && needRestart {
|
||||||
a.xrayService.SetToNeedRestart()
|
a.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,13 +221,15 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.inboundService.UpdateInboundClient(inbound, clientId)
|
needRestart := false
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.UpdateInboundClient(inbound, clientId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
jsonMsg(c, "Client updated", nil)
|
jsonMsg(c, "Client updated", nil)
|
||||||
if err == nil {
|
if err == nil && needRestart {
|
||||||
a.xrayService.SetToNeedRestart()
|
a.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,13 +242,15 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
|
||||||
}
|
}
|
||||||
email := c.Param("email")
|
email := c.Param("email")
|
||||||
|
|
||||||
err = a.inboundService.ResetClientTraffic(id, email)
|
needRestart := false
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.ResetClientTraffic(id, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
jsonMsg(c, "traffic reseted", nil)
|
jsonMsg(c, "traffic reseted", nil)
|
||||||
if err == nil {
|
if err == nil && needRestart {
|
||||||
a.xrayService.SetToNeedRestart()
|
a.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,6 +260,8 @@ func (a *InboundController) resetAllTraffics(c *gin.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
a.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
jsonMsg(c, "All traffics reseted", nil)
|
jsonMsg(c, "All traffics reseted", nil)
|
||||||
}
|
}
|
||||||
|
@ -268,6 +277,8 @@ func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
a.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
jsonMsg(c, "All traffics of client reseted", nil)
|
jsonMsg(c, "All traffics of client reseted", nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,19 +15,21 @@ func NewCheckInboundJob() *CheckInboundJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *CheckInboundJob) Run() {
|
func (j *CheckInboundJob) Run() {
|
||||||
count, err := j.inboundService.DisableInvalidClients()
|
needRestart, count, err := j.inboundService.DisableInvalidClients()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("disable invalid Client err:", err)
|
logger.Warning("Error in disabling invalid clients:", err)
|
||||||
} else if count > 0 {
|
} else if count > 0 {
|
||||||
logger.Debugf("disabled %v Client", count)
|
logger.Debugf("%v clients disabled", count)
|
||||||
|
if needRestart {
|
||||||
j.xrayService.SetToNeedRestart()
|
j.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
count, err = j.inboundService.DisableInvalidInbounds()
|
count, err = j.inboundService.DisableInvalidInbounds()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("disable invalid inbounds err:", err)
|
logger.Warning("Error in disabling invalid inbounds:", err)
|
||||||
} else if count > 0 {
|
} else if count > 0 {
|
||||||
logger.Debugf("disabled %v inbounds", count)
|
logger.Debugf("%v inbounds disabled", count)
|
||||||
j.xrayService.SetToNeedRestart()
|
j.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type InboundService struct {
|
type InboundService struct {
|
||||||
|
xrayApi xray.XrayAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
|
func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
|
||||||
|
@ -156,11 +157,19 @@ func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, err
|
||||||
}
|
}
|
||||||
|
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
tx := db.Begin()
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
tx.Commit()
|
||||||
|
} else {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
err = db.Save(inbound).Error
|
err = tx.Save(inbound).Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, client := range clients {
|
for _, client := range clients {
|
||||||
s.AddClientStat(inbound.Id, &client)
|
s.AddClientStat(tx, inbound.Id, &client)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return inbound, err
|
return inbound, err
|
||||||
|
@ -244,6 +253,12 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return inbound, err
|
return inbound, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = s.updateClientTraffics(oldInbound, inbound)
|
||||||
|
if err != nil {
|
||||||
|
return inbound, err
|
||||||
|
}
|
||||||
|
|
||||||
oldInbound.Up = inbound.Up
|
oldInbound.Up = inbound.Up
|
||||||
oldInbound.Down = inbound.Down
|
oldInbound.Down = inbound.Down
|
||||||
oldInbound.Total = inbound.Total
|
oldInbound.Total = inbound.Total
|
||||||
|
@ -262,36 +277,92 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
|
||||||
return inbound, db.Save(oldInbound).Error
|
return inbound, db.Save(oldInbound).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) AddInboundClient(data *model.Inbound) error {
|
func (s *InboundService) updateClientTraffics(oldInbound *model.Inbound, newInbound *model.Inbound) error {
|
||||||
clients, err := s.GetClients(data)
|
oldClients, err := s.GetClients(oldInbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
newClients, err := s.GetClients(newInbound)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
db := database.GetDB()
|
||||||
|
tx := db.Begin()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
} else {
|
||||||
|
tx.Commit()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
var settings map[string]interface{}
|
var settings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(data.Settings), &settings)
|
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaceClients := settings["clients"].([]interface{})
|
interfaceClients := settings["clients"].([]interface{})
|
||||||
existEmail, err := s.checkEmailsExistForClients(clients)
|
existEmail, err := s.checkEmailsExistForClients(clients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if existEmail != "" {
|
if existEmail != "" {
|
||||||
return common.NewError("Duplicate email:", existEmail)
|
return false, common.NewError("Duplicate email:", existEmail)
|
||||||
}
|
}
|
||||||
|
|
||||||
oldInbound, err := s.GetInbound(data.Id)
|
oldInbound, err := s.GetInbound(data.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldSettings map[string]interface{}
|
var oldSettings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldClients := oldSettings["clients"].([]interface{})
|
oldClients := oldSettings["clients"].([]interface{})
|
||||||
|
@ -301,30 +372,58 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) error {
|
||||||
|
|
||||||
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
|
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldInbound.Settings = string(newSettings)
|
oldInbound.Settings = string(newSettings)
|
||||||
|
|
||||||
|
db := database.GetDB()
|
||||||
|
tx := db.Begin()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
} else {
|
||||||
|
tx.Commit()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
needRestart := false
|
||||||
|
s.xrayApi.Init(p.GetAPIPort())
|
||||||
for _, client := range clients {
|
for _, client := range clients {
|
||||||
if len(client.Email) > 0 {
|
if len(client.Email) > 0 {
|
||||||
s.AddClientStat(data.Id, &client)
|
s.AddClientStat(tx, data.Id, &client)
|
||||||
|
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
|
||||||
|
"email": client.Email,
|
||||||
|
"id": client.ID,
|
||||||
|
"alterId": client.AlterIds,
|
||||||
|
"flow": client.Flow,
|
||||||
|
"password": client.Password,
|
||||||
|
})
|
||||||
|
if err1 == nil {
|
||||||
|
logger.Debug("Client added by api:", client.Email)
|
||||||
|
} else {
|
||||||
|
needRestart = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
needRestart = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db := database.GetDB()
|
s.xrayApi.Close()
|
||||||
return db.Save(oldInbound).Error
|
|
||||||
|
return needRestart, tx.Save(oldInbound).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) DelInboundClient(inboundId int, clientId string) error {
|
func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool, error) {
|
||||||
oldInbound, err := s.GetInbound(inboundId)
|
oldInbound, err := s.GetInbound(inboundId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Load Old Data Error")
|
logger.Error("Load Old Data Error")
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
var settings map[string]interface{}
|
var settings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(oldInbound.Settings), &settings)
|
err = json.Unmarshal([]byte(oldInbound.Settings), &settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
email := ""
|
email := ""
|
||||||
|
@ -351,7 +450,7 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) error
|
||||||
settings["clients"] = newClients
|
settings["clients"] = newClients
|
||||||
newSettings, err := json.MarshalIndent(settings, "", " ")
|
newSettings, err := json.MarshalIndent(settings, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldInbound.Settings = string(newSettings)
|
oldInbound.Settings = string(newSettings)
|
||||||
|
@ -360,39 +459,49 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) error
|
||||||
err = s.DelClientStat(db, email)
|
err = s.DelClientStat(db, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Delete stats Data Error")
|
logger.Error("Delete stats Data Error")
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.DelClientIPs(db, email)
|
err = s.DelClientIPs(db, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error in delete client IPs")
|
logger.Error("Error in delete client IPs")
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
return db.Save(oldInbound).Error
|
needRestart := true
|
||||||
|
s.xrayApi.Init(p.GetAPIPort())
|
||||||
|
if len(email) > 0 {
|
||||||
|
err = s.xrayApi.RemoveUser(oldInbound.Tag, email)
|
||||||
|
if err == nil {
|
||||||
|
logger.Debug("Client deleted by api:", email)
|
||||||
|
needRestart = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.xrayApi.Close()
|
||||||
|
return needRestart, db.Save(oldInbound).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId string) error {
|
func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId string) (bool, error) {
|
||||||
clients, err := s.GetClients(data)
|
clients, err := s.GetClients(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings map[string]interface{}
|
var settings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(data.Settings), &settings)
|
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
inerfaceClients := settings["clients"].([]interface{})
|
inerfaceClients := settings["clients"].([]interface{})
|
||||||
|
|
||||||
oldInbound, err := s.GetInbound(data.Id)
|
oldInbound, err := s.GetInbound(data.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldClients, err := s.GetClients(oldInbound)
|
oldClients, err := s.GetClients(oldInbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldEmail := ""
|
oldEmail := ""
|
||||||
|
@ -416,17 +525,17 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||||
if len(clients[0].Email) > 0 && clients[0].Email != oldEmail {
|
if len(clients[0].Email) > 0 && clients[0].Email != oldEmail {
|
||||||
existEmail, err := s.checkEmailsExistForClients(clients)
|
existEmail, err := s.checkEmailsExistForClients(clients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if existEmail != "" {
|
if existEmail != "" {
|
||||||
return common.NewError("Duplicate email:", existEmail)
|
return false, common.NewError("Duplicate email:", existEmail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldSettings map[string]interface{}
|
var oldSettings map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
settingsClients := oldSettings["clients"].([]interface{})
|
settingsClients := oldSettings["clients"].([]interface{})
|
||||||
settingsClients[clientIndex] = inerfaceClients[0]
|
settingsClients[clientIndex] = inerfaceClients[0]
|
||||||
|
@ -434,36 +543,67 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||||
|
|
||||||
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
|
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldInbound.Settings = string(newSettings)
|
oldInbound.Settings = string(newSettings)
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
tx := db.Begin()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
} else {
|
||||||
|
tx.Commit()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if len(clients[0].Email) > 0 {
|
if len(clients[0].Email) > 0 {
|
||||||
if len(oldEmail) > 0 {
|
if len(oldEmail) > 0 {
|
||||||
err = s.UpdateClientStat(oldEmail, &clients[0])
|
err = s.UpdateClientStat(oldEmail, &clients[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
err = s.UpdateClientIPs(db, oldEmail, clients[0].Email)
|
err = s.UpdateClientIPs(db, oldEmail, clients[0].Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.AddClientStat(data.Id, &clients[0])
|
s.AddClientStat(tx, data.Id, &clients[0])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = s.DelClientStat(db, oldEmail)
|
err = s.DelClientStat(tx, oldEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
err = s.DelClientIPs(db, oldEmail)
|
err = s.DelClientIPs(db, oldEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return db.Save(oldInbound).Error
|
needRestart := true
|
||||||
|
s.xrayApi.Init(p.GetAPIPort())
|
||||||
|
if len(oldEmail) > 0 {
|
||||||
|
s.xrayApi.RemoveUser(oldInbound.Tag, oldEmail)
|
||||||
|
if clients[0].Enable {
|
||||||
|
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
|
||||||
|
"email": clients[0].Email,
|
||||||
|
"id": clients[0].ID,
|
||||||
|
"alterId": clients[0].AlterIds,
|
||||||
|
"flow": clients[0].Flow,
|
||||||
|
"password": clients[0].Password,
|
||||||
|
})
|
||||||
|
if err1 == nil {
|
||||||
|
logger.Debug("Client edited by api:", clients[0].Email)
|
||||||
|
needRestart = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Debug("Client disabled by api:", clients[0].Email)
|
||||||
|
needRestart = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.xrayApi.Close()
|
||||||
|
return needRestart, tx.Save(oldInbound).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) AddTraffic(traffics []*xray.Traffic) error {
|
func (s *InboundService) AddTraffic(traffics []*xray.Traffic) error {
|
||||||
|
@ -489,6 +629,7 @@ func (s *InboundService) AddTraffic(traffics []*xray.Traffic) error {
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err error) {
|
func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err error) {
|
||||||
if len(traffics) == 0 {
|
if len(traffics) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -601,15 +742,42 @@ func (s *InboundService) DisableInvalidInbounds() (int64, error) {
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) DisableInvalidClients() (int64, error) {
|
func (s *InboundService) DisableInvalidClients() (bool, int64, error) {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
now := time.Now().Unix() * 1000
|
now := time.Now().Unix() * 1000
|
||||||
|
needRestart := false
|
||||||
|
|
||||||
|
if p != nil {
|
||||||
|
var results []struct {
|
||||||
|
Tag string
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.Table("inbounds").
|
||||||
|
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 {
|
||||||
|
err = s.xrayApi.RemoveUser(result.Tag, result.Email)
|
||||||
|
if err == nil {
|
||||||
|
logger.Debug("Client deleted by api:", result.Email)
|
||||||
|
} else {
|
||||||
|
needRestart = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.xrayApi.Close()
|
||||||
|
}
|
||||||
result := db.Model(xray.ClientTraffic{}).
|
result := db.Model(xray.ClientTraffic{}).
|
||||||
Where("((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?", now, true).
|
Where("((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?", now, true).
|
||||||
Update("enable", false)
|
Update("enable", false)
|
||||||
err := result.Error
|
err := result.Error
|
||||||
count := result.RowsAffected
|
count := result.RowsAffected
|
||||||
return count, err
|
return needRestart, count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) MigrationRemoveOrphanedTraffics() {
|
func (s *InboundService) MigrationRemoveOrphanedTraffics() {
|
||||||
|
@ -624,9 +792,7 @@ func (s *InboundService) MigrationRemoveOrphanedTraffics() {
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) AddClientStat(inboundId int, client *model.Client) error {
|
func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model.Client) error {
|
||||||
db := database.GetDB()
|
|
||||||
|
|
||||||
clientTraffic := xray.ClientTraffic{}
|
clientTraffic := xray.ClientTraffic{}
|
||||||
clientTraffic.InboundId = inboundId
|
clientTraffic.InboundId = inboundId
|
||||||
clientTraffic.Email = client.Email
|
clientTraffic.Email = client.Email
|
||||||
|
@ -635,7 +801,7 @@ func (s *InboundService) AddClientStat(inboundId int, client *model.Client) erro
|
||||||
clientTraffic.Enable = true
|
clientTraffic.Enable = true
|
||||||
clientTraffic.Up = 0
|
clientTraffic.Up = 0
|
||||||
clientTraffic.Down = 0
|
clientTraffic.Down = 0
|
||||||
result := db.Create(&clientTraffic)
|
result := tx.Create(&clientTraffic)
|
||||||
err := result.Error
|
err := result.Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -779,7 +945,11 @@ func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId string) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inbound.Settings = string(modifiedSettings)
|
inbound.Settings = string(modifiedSettings)
|
||||||
return s.UpdateInboundClient(inbound, clientId)
|
_, err = s.UpdateInboundClient(inbound, clientId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, error) {
|
func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, error) {
|
||||||
|
@ -835,7 +1005,13 @@ func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, er
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
inbound.Settings = string(modifiedSettings)
|
inbound.Settings = string(modifiedSettings)
|
||||||
return !clientOldEnabled, s.UpdateInboundClient(inbound, clientId)
|
|
||||||
|
_, err = s.UpdateInboundClient(inbound, clientId)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return !clientOldEnabled, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) ResetClientIpLimitByEmail(clientEmail string, count int) error {
|
func (s *InboundService) ResetClientIpLimitByEmail(clientEmail string, count int) error {
|
||||||
|
@ -889,9 +1065,13 @@ func (s *InboundService) ResetClientIpLimitByEmail(clientEmail string, count int
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inbound.Settings = string(modifiedSettings)
|
inbound.Settings = string(modifiedSettings)
|
||||||
return s.UpdateInboundClient(inbound, clientId)
|
_, err = s.UpdateInboundClient(inbound, clientId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
func (s *InboundService) ResetClientExpiryTimeByEmail(clientEmail string, expiry_time int64) error {
|
func (s *InboundService) ResetClientExpiryTimeByEmail(clientEmail string, expiry_time int64) error {
|
||||||
_, inbound, err := s.GetClientInboundByEmail(clientEmail)
|
_, inbound, err := s.GetClientInboundByEmail(clientEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -943,7 +1123,12 @@ func (s *InboundService) ResetClientExpiryTimeByEmail(clientEmail string, expiry
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inbound.Settings = string(modifiedSettings)
|
inbound.Settings = string(modifiedSettings)
|
||||||
return s.UpdateInboundClient(inbound, clientId)
|
_, err = s.UpdateInboundClient(inbound, clientId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
|
func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
|
||||||
|
@ -961,19 +1146,55 @@ func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) ResetClientTraffic(id int, clientEmail string) error {
|
func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, error) {
|
||||||
db := database.GetDB()
|
needRestart := false
|
||||||
|
|
||||||
result := db.Model(xray.ClientTraffic{}).
|
|
||||||
Where("inbound_id = ? and email = ?", id, clientEmail).
|
|
||||||
Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0})
|
|
||||||
|
|
||||||
err := result.Error
|
|
||||||
|
|
||||||
|
traffic, err := s.GetClientTrafficByEmail(clientEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
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 {
|
||||||
|
if client.Email == clientEmail {
|
||||||
|
s.xrayApi.Init(p.GetAPIPort())
|
||||||
|
err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]interface{}{
|
||||||
|
"email": client.Email,
|
||||||
|
"id": client.ID,
|
||||||
|
"alterId": client.AlterIds,
|
||||||
|
"flow": client.Flow,
|
||||||
|
"password": client.Password,
|
||||||
|
})
|
||||||
|
if err1 == nil {
|
||||||
|
logger.Debug("Client enabled due to reset traffic:", clientEmail)
|
||||||
|
} else {
|
||||||
|
needRestart = true
|
||||||
|
}
|
||||||
|
s.xrayApi.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
traffic.Up = 0
|
||||||
|
traffic.Down = 0
|
||||||
|
traffic.Enable = true
|
||||||
|
|
||||||
|
db := database.GetDB()
|
||||||
|
err = db.Save(traffic).Error
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return needRestart, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) ResetAllClientTraffics(id int) error {
|
func (s *InboundService) ResetAllClientTraffics(id int) error {
|
||||||
|
@ -1212,10 +1433,19 @@ func (s *InboundService) SearchInbounds(query string) ([]*model.Inbound, error)
|
||||||
|
|
||||||
func (s *InboundService) MigrationRequirements() {
|
func (s *InboundService) MigrationRequirements() {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
tx := db.Begin()
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
tx.Commit()
|
||||||
|
} else {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Fix inbounds based problems
|
// Fix inbounds based problems
|
||||||
var inbounds []*model.Inbound
|
var inbounds []*model.Inbound
|
||||||
err := db.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error
|
err = tx.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error
|
||||||
if err != nil && err != gorm.ErrRecordNotFound {
|
if err != nil && err != gorm.ErrRecordNotFound {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1250,6 +1480,7 @@ func (s *InboundService) MigrationRequirements() {
|
||||||
|
|
||||||
inbounds[inbound_index].Settings = string(modifiedSettings)
|
inbounds[inbound_index].Settings = string(modifiedSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add client traffic row for all clients which has email
|
// Add client traffic row for all clients which has email
|
||||||
modelClients, err := s.GetClients(inbounds[inbound_index])
|
modelClients, err := s.GetClients(inbounds[inbound_index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1258,17 +1489,17 @@ func (s *InboundService) MigrationRequirements() {
|
||||||
for _, modelClient := range modelClients {
|
for _, modelClient := range modelClients {
|
||||||
if len(modelClient.Email) > 0 {
|
if len(modelClient.Email) > 0 {
|
||||||
var count int64
|
var count int64
|
||||||
db.Model(xray.ClientTraffic{}).Where("email = ?", modelClient.Email).Count(&count)
|
tx.Model(xray.ClientTraffic{}).Where("email = ?", modelClient.Email).Count(&count)
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
s.AddClientStat(inbounds[inbound_index].Id, &modelClient)
|
s.AddClientStat(tx, inbounds[inbound_index].Id, &modelClient)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.Save(inbounds)
|
tx.Save(inbounds)
|
||||||
|
|
||||||
// Remove orphaned traffics
|
// Remove orphaned traffics
|
||||||
db.Where("inbound_id = 0").Delete(xray.ClientTraffic{})
|
tx.Where("inbound_id = 0").Delete(xray.ClientTraffic{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) MigrateDB() {
|
func (s *InboundService) MigrateDB() {
|
||||||
|
|
|
@ -18,6 +18,7 @@ var result string
|
||||||
type XrayService struct {
|
type XrayService struct {
|
||||||
inboundService InboundService
|
inboundService InboundService
|
||||||
settingService SettingService
|
settingService SettingService
|
||||||
|
xrayAPI xray.XrayAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *XrayService) IsXrayRunning() bool {
|
func (s *XrayService) IsXrayRunning() bool {
|
||||||
|
@ -143,7 +144,9 @@ func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic,
|
||||||
if !s.IsXrayRunning() {
|
if !s.IsXrayRunning() {
|
||||||
return nil, nil, errors.New("xray is not running")
|
return nil, nil, errors.New("xray is not running")
|
||||||
}
|
}
|
||||||
return p.GetTraffic(true)
|
s.xrayAPI.Init(p.GetAPIPort())
|
||||||
|
defer s.xrayAPI.Close()
|
||||||
|
return s.xrayAPI.GetTraffic(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *XrayService) RestartXray(isForce bool) error {
|
func (s *XrayService) RestartXray(isForce bool) error {
|
||||||
|
@ -158,7 +161,7 @@ func (s *XrayService) RestartXray(isForce bool) error {
|
||||||
|
|
||||||
if p != nil && p.IsRunning() {
|
if p != nil && p.IsRunning() {
|
||||||
if !isForce && p.GetConfig().Equals(xrayConfig) {
|
if !isForce && p.GetConfig().Equals(xrayConfig) {
|
||||||
logger.Debug("not need to restart xray")
|
logger.Debug("It does not need to restart xray")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
p.Stop()
|
p.Stop()
|
||||||
|
@ -166,7 +169,11 @@ func (s *XrayService) RestartXray(isForce bool) error {
|
||||||
|
|
||||||
p = xray.NewProcess(xrayConfig)
|
p = xray.NewProcess(xrayConfig)
|
||||||
result = ""
|
result = ""
|
||||||
return p.Start()
|
err = p.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *XrayService) StopXray() error {
|
func (s *XrayService) StopXray() error {
|
||||||
|
|
182
xray/api.go
Normal file
182
xray/api.go
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package xray
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
"x-ui/util/common"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/app/proxyman/command"
|
||||||
|
statsService "github.com/xtls/xray-core/app/stats/command"
|
||||||
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/proxy/shadowsocks"
|
||||||
|
"github.com/xtls/xray-core/proxy/trojan"
|
||||||
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
|
"github.com/xtls/xray-core/proxy/vmess"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
)
|
||||||
|
|
||||||
|
type XrayAPI struct {
|
||||||
|
HandlerServiceClient *command.HandlerServiceClient
|
||||||
|
StatsServiceClient *statsService.StatsServiceClient
|
||||||
|
grpcClient *grpc.ClientConn
|
||||||
|
isConnected bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XrayAPI) Init(apiPort int) (err error) {
|
||||||
|
if apiPort == 0 {
|
||||||
|
return common.NewError("xray api port wrong:", apiPort)
|
||||||
|
}
|
||||||
|
x.grpcClient, err = grpc.Dial(fmt.Sprintf("127.0.0.1:%v", apiPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
x.isConnected = true
|
||||||
|
|
||||||
|
hsClient := command.NewHandlerServiceClient(x.grpcClient)
|
||||||
|
ssClient := statsService.NewStatsServiceClient(x.grpcClient)
|
||||||
|
|
||||||
|
x.HandlerServiceClient = &hsClient
|
||||||
|
x.StatsServiceClient = &ssClient
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XrayAPI) Close() {
|
||||||
|
x.grpcClient.Close()
|
||||||
|
x.HandlerServiceClient = nil
|
||||||
|
x.StatsServiceClient = nil
|
||||||
|
x.isConnected = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]interface{}) error {
|
||||||
|
var account *serial.TypedMessage
|
||||||
|
switch Protocol {
|
||||||
|
case "vmess":
|
||||||
|
account = serial.ToTypedMessage(&vmess.Account{
|
||||||
|
Id: user["id"].(string),
|
||||||
|
AlterId: uint32(user["alterId"].(uint16)),
|
||||||
|
})
|
||||||
|
case "vless":
|
||||||
|
account = serial.ToTypedMessage(&vless.Account{
|
||||||
|
Id: user["id"].(string),
|
||||||
|
Flow: user["flow"].(string),
|
||||||
|
})
|
||||||
|
case "trojan":
|
||||||
|
account = serial.ToTypedMessage(&trojan.Account{
|
||||||
|
Password: user["password"].(string),
|
||||||
|
})
|
||||||
|
case "shadowsocks":
|
||||||
|
account = serial.ToTypedMessage(&shadowsocks.Account{
|
||||||
|
Password: user["password"].(string),
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
client := *x.HandlerServiceClient
|
||||||
|
|
||||||
|
_, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{
|
||||||
|
Tag: inboundTag,
|
||||||
|
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
||||||
|
User: &protocol.User{
|
||||||
|
Email: user["email"].(string),
|
||||||
|
Account: account,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XrayAPI) RemoveUser(inboundTag string, email string) error {
|
||||||
|
client := *x.HandlerServiceClient
|
||||||
|
_, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{
|
||||||
|
Tag: inboundTag,
|
||||||
|
Operation: serial.ToTypedMessage(&command.RemoveUserOperation{
|
||||||
|
Email: email,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
|
||||||
|
if x.grpcClient == nil {
|
||||||
|
return nil, nil, common.NewError("xray api is not initialized")
|
||||||
|
}
|
||||||
|
var trafficRegex = regexp.MustCompile("(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
|
||||||
|
var ClientTrafficRegex = regexp.MustCompile("(user)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
|
||||||
|
|
||||||
|
client := *x.StatsServiceClient
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||||
|
defer cancel()
|
||||||
|
request := &statsService.QueryStatsRequest{
|
||||||
|
Reset_: reset,
|
||||||
|
}
|
||||||
|
resp, err := client.QueryStats(ctx, request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
tagTrafficMap := map[string]*Traffic{}
|
||||||
|
emailTrafficMap := map[string]*ClientTraffic{}
|
||||||
|
|
||||||
|
clientTraffics := make([]*ClientTraffic, 0)
|
||||||
|
traffics := make([]*Traffic, 0)
|
||||||
|
for _, stat := range resp.GetStat() {
|
||||||
|
matchs := trafficRegex.FindStringSubmatch(stat.Name)
|
||||||
|
if len(matchs) < 3 {
|
||||||
|
|
||||||
|
matchs := ClientTrafficRegex.FindStringSubmatch(stat.Name)
|
||||||
|
if len(matchs) < 3 {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
|
||||||
|
isUser := matchs[1] == "user"
|
||||||
|
email := matchs[2]
|
||||||
|
isDown := matchs[3] == "downlink"
|
||||||
|
if !isUser {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
traffic, ok := emailTrafficMap[email]
|
||||||
|
if !ok {
|
||||||
|
traffic = &ClientTraffic{
|
||||||
|
Email: email,
|
||||||
|
}
|
||||||
|
emailTrafficMap[email] = traffic
|
||||||
|
clientTraffics = append(clientTraffics, traffic)
|
||||||
|
}
|
||||||
|
if isDown {
|
||||||
|
traffic.Down = stat.Value
|
||||||
|
} else {
|
||||||
|
traffic.Up = stat.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isInbound := matchs[1] == "inbound"
|
||||||
|
tag := matchs[2]
|
||||||
|
isDown := matchs[3] == "downlink"
|
||||||
|
if tag == "api" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
traffic, ok := tagTrafficMap[tag]
|
||||||
|
if !ok {
|
||||||
|
traffic = &Traffic{
|
||||||
|
IsInbound: isInbound,
|
||||||
|
Tag: tag,
|
||||||
|
}
|
||||||
|
tagTrafficMap[tag] = traffic
|
||||||
|
traffics = append(traffics, traffic)
|
||||||
|
}
|
||||||
|
if isDown {
|
||||||
|
traffic.Down = stat.Value
|
||||||
|
} else {
|
||||||
|
traffic.Up = stat.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return traffics, clientTraffics, nil
|
||||||
|
}
|
|
@ -3,30 +3,21 @@ package xray
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
"x-ui/config"
|
"x-ui/config"
|
||||||
"x-ui/util/common"
|
"x-ui/util/common"
|
||||||
|
|
||||||
"github.com/Workiva/go-datastructures/queue"
|
"github.com/Workiva/go-datastructures/queue"
|
||||||
statsservice "github.com/xtls/xray-core/app/stats/command"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var trafficRegex = regexp.MustCompile("(inbound|outbound)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
|
|
||||||
var ClientTrafficRegex = regexp.MustCompile("(user)>>>([^>]+)>>>traffic>>>(downlink|uplink)")
|
|
||||||
|
|
||||||
func GetBinaryName() string {
|
func GetBinaryName() string {
|
||||||
return fmt.Sprintf("xray-%s-%s", runtime.GOOS, runtime.GOARCH)
|
return fmt.Sprintf("xray-%s-%s", runtime.GOOS, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
@ -238,85 +229,3 @@ func (p *process) Stop() error {
|
||||||
}
|
}
|
||||||
return p.cmd.Process.Kill()
|
return p.cmd.Process.Kill()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
|
|
||||||
if p.apiPort == 0 {
|
|
||||||
return nil, nil, common.NewError("xray api port wrong:", p.apiPort)
|
|
||||||
}
|
|
||||||
conn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%v", p.apiPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
client := statsservice.NewStatsServiceClient(conn)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
|
||||||
defer cancel()
|
|
||||||
request := &statsservice.QueryStatsRequest{
|
|
||||||
Reset_: reset,
|
|
||||||
}
|
|
||||||
resp, err := client.QueryStats(ctx, request)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
tagTrafficMap := map[string]*Traffic{}
|
|
||||||
emailTrafficMap := map[string]*ClientTraffic{}
|
|
||||||
|
|
||||||
clientTraffics := make([]*ClientTraffic, 0)
|
|
||||||
traffics := make([]*Traffic, 0)
|
|
||||||
for _, stat := range resp.GetStat() {
|
|
||||||
matchs := trafficRegex.FindStringSubmatch(stat.Name)
|
|
||||||
if len(matchs) < 3 {
|
|
||||||
|
|
||||||
matchs := ClientTrafficRegex.FindStringSubmatch(stat.Name)
|
|
||||||
if len(matchs) < 3 {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
|
|
||||||
isUser := matchs[1] == "user"
|
|
||||||
email := matchs[2]
|
|
||||||
isDown := matchs[3] == "downlink"
|
|
||||||
if !isUser {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
traffic, ok := emailTrafficMap[email]
|
|
||||||
if !ok {
|
|
||||||
traffic = &ClientTraffic{
|
|
||||||
Email: email,
|
|
||||||
}
|
|
||||||
emailTrafficMap[email] = traffic
|
|
||||||
clientTraffics = append(clientTraffics, traffic)
|
|
||||||
}
|
|
||||||
if isDown {
|
|
||||||
traffic.Down = stat.Value
|
|
||||||
} else {
|
|
||||||
traffic.Up = stat.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
isInbound := matchs[1] == "inbound"
|
|
||||||
tag := matchs[2]
|
|
||||||
isDown := matchs[3] == "downlink"
|
|
||||||
if tag == "api" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
traffic, ok := tagTrafficMap[tag]
|
|
||||||
if !ok {
|
|
||||||
traffic = &Traffic{
|
|
||||||
IsInbound: isInbound,
|
|
||||||
Tag: tag,
|
|
||||||
}
|
|
||||||
tagTrafficMap[tag] = traffic
|
|
||||||
traffics = append(traffics, traffic)
|
|
||||||
}
|
|
||||||
if isDown {
|
|
||||||
traffic.Down = stat.Value
|
|
||||||
} else {
|
|
||||||
traffic.Up = stat.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return traffics, clientTraffics, nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue