Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMHSanaei <ho3ein.sanaei@gmail.com>2023-06-05 00:02:19 +0300
committerMHSanaei <ho3ein.sanaei@gmail.com>2023-06-05 00:02:19 +0300
commit70f250dfe1e24249a4cc8102e3fef65959dfb15a (patch)
tree9fdc990d656267abf6facafd851ab7b4835be977
parent1030bcf321f15ada665ca3c55436d7c2449b5faf (diff)
[feature] using xray api and more
Improve DB performance [api] backward compatibility: add client by update Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
-rw-r--r--go.mod9
-rw-r--r--go.sum18
-rw-r--r--web/controller/inbound.go29
-rw-r--r--web/job/check_inbound_job.go14
-rw-r--r--web/service/inbound.go351
-rw-r--r--web/service/xray.go13
-rw-r--r--xray/api.go182
-rw-r--r--xray/process.go91
8 files changed, 531 insertions, 176 deletions
diff --git a/go.mod b/go.mod
index f4dda6dc..533d9933 100644
--- a/go.mod
+++ b/go.mod
@@ -27,13 +27,15 @@ require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/bytedance/sonic v1.9.1 // 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/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/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.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/gorilla/context 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/pires/go-proxyproto v0.7.0 // 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/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // 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/fasthttp v1.47.0 // indirect
+ github.com/xtls/reality v0.0.0-20230331223127-176a94313eda // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
diff --git a/go.sum b/go.sum
index 3ab60d1e..ad0a1921 100644
--- a/go.sum
+++ b/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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
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/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
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/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/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
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/gin-contrib/sessions v0.0.4 h1:gq4fNa1Zmp564iHP5G6EBuktilEos8VKhe2sza1KMgo=
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/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.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
-github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
+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-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
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/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.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/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
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/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/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/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/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
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/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/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/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
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/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.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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/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/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.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
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/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/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
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/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
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/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/go.mod h1:AXxSso0MZwUE4NhRocCfHCg73BtJ+T2dSpQVo1Cg9VM=
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-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-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.2.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.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-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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4=
diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index 815f1788..461c4b27 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -79,7 +79,6 @@ func (a *InboundController) getInbound(c *gin.Context) {
}
jsonObj(c, inbound, nil)
}
-
func (a *InboundController) getClientTraffics(c *gin.Context) {
email := c.Param("email")
clientTraffics, err := a.inboundService.GetClientTrafficByEmail(email)
@@ -178,13 +177,15 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
return
}
- err = a.inboundService.AddInboundClient(data)
+ needRestart := false
+
+ needRestart, err = a.inboundService.AddInboundClient(data)
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client(s) added", nil)
- if err == nil {
+ if err == nil && needRestart {
a.xrayService.SetToNeedRestart()
}
}
@@ -197,13 +198,15 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
}
clientId := c.Param("clientId")
- err = a.inboundService.DelInboundClient(id, clientId)
+ needRestart := false
+
+ needRestart, err = a.inboundService.DelInboundClient(id, clientId)
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client deleted", nil)
- if err == nil {
+ if err == nil && needRestart {
a.xrayService.SetToNeedRestart()
}
}
@@ -218,13 +221,15 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
return
}
- err = a.inboundService.UpdateInboundClient(inbound, clientId)
+ needRestart := false
+
+ needRestart, err = a.inboundService.UpdateInboundClient(inbound, clientId)
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client updated", nil)
- if err == nil {
+ if err == nil && needRestart {
a.xrayService.SetToNeedRestart()
}
}
@@ -237,13 +242,15 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
}
email := c.Param("email")
- err = a.inboundService.ResetClientTraffic(id, email)
+ needRestart := false
+
+ needRestart, err = a.inboundService.ResetClientTraffic(id, email)
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "traffic reseted", nil)
- if err == nil {
+ if err == nil && needRestart {
a.xrayService.SetToNeedRestart()
}
}
@@ -253,6 +260,8 @@ func (a *InboundController) resetAllTraffics(c *gin.Context) {
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
+ } else {
+ a.xrayService.SetToNeedRestart()
}
jsonMsg(c, "All traffics reseted", nil)
}
@@ -268,6 +277,8 @@ func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
+ } else {
+ a.xrayService.SetToNeedRestart()
}
jsonMsg(c, "All traffics of client reseted", nil)
}
diff --git a/web/job/check_inbound_job.go b/web/job/check_inbound_job.go
index 2b24afb0..cb8bd331 100644
--- a/web/job/check_inbound_job.go
+++ b/web/job/check_inbound_job.go
@@ -15,19 +15,21 @@ func NewCheckInboundJob() *CheckInboundJob {
}
func (j *CheckInboundJob) Run() {
- count, err := j.inboundService.DisableInvalidClients()
+ needRestart, count, err := j.inboundService.DisableInvalidClients()
if err != nil {
- logger.Warning("disable invalid Client err:", err)
+ logger.Warning("Error in disabling invalid clients:", err)
} else if count > 0 {
- logger.Debugf("disabled %v Client", count)
- j.xrayService.SetToNeedRestart()
+ logger.Debugf("%v clients disabled", count)
+ if needRestart {
+ j.xrayService.SetToNeedRestart()
+ }
}
count, err = j.inboundService.DisableInvalidInbounds()
if err != nil {
- logger.Warning("disable invalid inbounds err:", err)
+ logger.Warning("Error in disabling invalid inbounds:", err)
} else if count > 0 {
- logger.Debugf("disabled %v inbounds", count)
+ logger.Debugf("%v inbounds disabled", count)
j.xrayService.SetToNeedRestart()
}
}
diff --git a/web/service/inbound.go b/web/service/inbound.go
index 11522ad2..84ce9bd8 100644
--- a/web/service/inbound.go
+++ b/web/service/inbound.go
@@ -15,6 +15,7 @@ import (
)
type InboundService struct {
+ xrayApi xray.XrayAPI
}
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()
+ 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 {
for _, client := range clients {
- s.AddClientStat(inbound.Id, &client)
+ s.AddClientStat(tx, inbound.Id, &client)
}
}
return inbound, err
@@ -244,6 +253,12 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
if err != nil {
return inbound, err
}
+
+ err = s.updateClientTraffics(oldInbound, inbound)
+ if err != nil {
+ return inbound, err
+ }
+
oldInbound.Up = inbound.Up
oldInbound.Down = inbound.Down
oldInbound.Total = inbound.Total
@@ -262,36 +277,92 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
return inbound, db.Save(oldInbound).Error
}
-func (s *InboundService) AddInboundClient(data *model.Inbound) error {
- clients, err := s.GetClients(data)
+func (s *InboundService) updateClientTraffics(oldInbound *model.Inbound, newInbound *model.Inbound) error {
+ oldClients, err := s.GetClients(oldInbound)
+ if err != nil {
+ 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{}
err = json.Unmarshal([]byte(data.Settings), &settings)
if err != nil {
- return err
+ return false, err
}
interfaceClients := settings["clients"].([]interface{})
existEmail, err := s.checkEmailsExistForClients(clients)
if err != nil {
- return err
+ return false, err
}
if existEmail != "" {
- return common.NewError("Duplicate email:", existEmail)
+ return false, common.NewError("Duplicate email:", existEmail)
}
oldInbound, err := s.GetInbound(data.Id)
if err != nil {
- return err
+ return false, err
}
var oldSettings map[string]interface{}
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
if err != nil {
- return err
+ return false, err
}
oldClients := oldSettings["clients"].([]interface{})
@@ -301,30 +372,58 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) error {
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
if err != nil {
- return err
+ return false, err
}
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 {
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()
- return db.Save(oldInbound).Error
+ s.xrayApi.Close()
+
+ 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)
if err != nil {
logger.Error("Load Old Data Error")
- return err
+ return false, err
}
var settings map[string]interface{}
err = json.Unmarshal([]byte(oldInbound.Settings), &settings)
if err != nil {
- return err
+ return false, err
}
email := ""
@@ -351,7 +450,7 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) error
settings["clients"] = newClients
newSettings, err := json.MarshalIndent(settings, "", " ")
if err != nil {
- return err
+ return false, err
}
oldInbound.Settings = string(newSettings)
@@ -360,39 +459,49 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) error
err = s.DelClientStat(db, email)
if err != nil {
logger.Error("Delete stats Data Error")
- return err
+ return false, err
}
err = s.DelClientIPs(db, email)
if err != nil {
logger.Error("Error in delete client IPs")
- return err
+ return false, err
+ }
+ 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
+ }
}
- return db.Save(oldInbound).Error
+ 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)
if err != nil {
- return err
+ return false, err
}
var settings map[string]interface{}
err = json.Unmarshal([]byte(data.Settings), &settings)
if err != nil {
- return err
+ return false, err
}
inerfaceClients := settings["clients"].([]interface{})
oldInbound, err := s.GetInbound(data.Id)
if err != nil {
- return err
+ return false, err
}
oldClients, err := s.GetClients(oldInbound)
if err != nil {
- return err
+ return false, err
}
oldEmail := ""
@@ -416,17 +525,17 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
if len(clients[0].Email) > 0 && clients[0].Email != oldEmail {
existEmail, err := s.checkEmailsExistForClients(clients)
if err != nil {
- return err
+ return false, err
}
if existEmail != "" {
- return common.NewError("Duplicate email:", existEmail)
+ return false, common.NewError("Duplicate email:", existEmail)
}
}
var oldSettings map[string]interface{}
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
if err != nil {
- return err
+ return false, err
}
settingsClients := oldSettings["clients"].([]interface{})
settingsClients[clientIndex] = inerfaceClients[0]
@@ -434,36 +543,67 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
if err != nil {
- return err
+ return false, err
}
oldInbound.Settings = string(newSettings)
db := database.GetDB()
+ tx := db.Begin()
+
+ defer func() {
+ if err != nil {
+ tx.Rollback()
+ } else {
+ tx.Commit()
+ }
+ }()
if len(clients[0].Email) > 0 {
if len(oldEmail) > 0 {
err = s.UpdateClientStat(oldEmail, &clients[0])
if err != nil {
- return err
+ return false, err
}
err = s.UpdateClientIPs(db, oldEmail, clients[0].Email)
if err != nil {
- return err
+ return false, err
}
} else {
- s.AddClientStat(data.Id, &clients[0])
+ s.AddClientStat(tx, data.Id, &clients[0])
}
} else {
- err = s.DelClientStat(db, oldEmail)
+ err = s.DelClientStat(tx, oldEmail)
if err != nil {
- return err
+ return false, err
}
err = s.DelClientIPs(db, oldEmail)
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 {
@@ -489,6 +629,7 @@ func (s *InboundService) AddTraffic(traffics []*xray.Traffic) error {
return err
}
+
func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err error) {
if len(traffics) == 0 {
return nil
@@ -601,15 +742,42 @@ func (s *InboundService) DisableInvalidInbounds() (int64, error) {
return count, err
}
-func (s *InboundService) DisableInvalidClients() (int64, error) {
+func (s *InboundService) DisableInvalidClients() (bool, int64, error) {
db := database.GetDB()
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{}).
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
- return count, err
+ return needRestart, count, err
}
func (s *InboundService) MigrationRemoveOrphanedTraffics() {
@@ -624,9 +792,7 @@ func (s *InboundService) MigrationRemoveOrphanedTraffics() {
`)
}
-func (s *InboundService) AddClientStat(inboundId int, client *model.Client) error {
- db := database.GetDB()
-
+func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model.Client) error {
clientTraffic := xray.ClientTraffic{}
clientTraffic.InboundId = inboundId
clientTraffic.Email = client.Email
@@ -635,7 +801,7 @@ func (s *InboundService) AddClientStat(inboundId int, client *model.Client) erro
clientTraffic.Enable = true
clientTraffic.Up = 0
clientTraffic.Down = 0
- result := db.Create(&clientTraffic)
+ result := tx.Create(&clientTraffic)
err := result.Error
if err != nil {
return err
@@ -779,7 +945,11 @@ func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId string) err
return err
}
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) {
@@ -835,7 +1005,13 @@ func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, er
return false, err
}
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 {
@@ -889,9 +1065,13 @@ func (s *InboundService) ResetClientIpLimitByEmail(clientEmail string, count int
return err
}
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 {
_, inbound, err := s.GetClientInboundByEmail(clientEmail)
if err != nil {
@@ -943,7 +1123,12 @@ func (s *InboundService) ResetClientExpiryTimeByEmail(clientEmail string, expiry
return err
}
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 {
@@ -961,19 +1146,55 @@ func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
return nil
}
-func (s *InboundService) ResetClientTraffic(id int, clientEmail string) error {
- db := database.GetDB()
+func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, error) {
+ needRestart := false
- result := db.Model(xray.ClientTraffic{}).
- Where("inbound_id = ? and email = ?", id, clientEmail).
- Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0})
+ traffic, err := s.GetClientTrafficByEmail(clientEmail)
+ if err != nil {
+ return false, err
+ }
- err := result.Error
+ 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 err
+ return false, err
}
- return nil
+
+ return needRestart, nil
}
func (s *InboundService) ResetAllClientTraffics(id int) error {
@@ -1212,10 +1433,19 @@ func (s *InboundService) SearchInbounds(query string) ([]*model.Inbound, error)
func (s *InboundService) MigrationRequirements() {
db := database.GetDB()
+ tx := db.Begin()
+ var err error
+ defer func() {
+ if err == nil {
+ tx.Commit()
+ } else {
+ tx.Rollback()
+ }
+ }()
// Fix inbounds based problems
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 {
return
}
@@ -1250,6 +1480,7 @@ func (s *InboundService) MigrationRequirements() {
inbounds[inbound_index].Settings = string(modifiedSettings)
}
+
// Add client traffic row for all clients which has email
modelClients, err := s.GetClients(inbounds[inbound_index])
if err != nil {
@@ -1258,17 +1489,17 @@ func (s *InboundService) MigrationRequirements() {
for _, modelClient := range modelClients {
if len(modelClient.Email) > 0 {
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 {
- s.AddClientStat(inbounds[inbound_index].Id, &modelClient)
+ s.AddClientStat(tx, inbounds[inbound_index].Id, &modelClient)
}
}
}
}
- db.Save(inbounds)
+ tx.Save(inbounds)
// Remove orphaned traffics
- db.Where("inbound_id = 0").Delete(xray.ClientTraffic{})
+ tx.Where("inbound_id = 0").Delete(xray.ClientTraffic{})
}
func (s *InboundService) MigrateDB() {
diff --git a/web/service/xray.go b/web/service/xray.go
index bcc886fe..5475891f 100644
--- a/web/service/xray.go
+++ b/web/service/xray.go
@@ -18,6 +18,7 @@ var result string
type XrayService struct {
inboundService InboundService
settingService SettingService
+ xrayAPI xray.XrayAPI
}
func (s *XrayService) IsXrayRunning() bool {
@@ -143,7 +144,9 @@ func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, []*xray.ClientTraffic,
if !s.IsXrayRunning() {
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 {
@@ -158,7 +161,7 @@ func (s *XrayService) RestartXray(isForce bool) error {
if p != nil && p.IsRunning() {
if !isForce && p.GetConfig().Equals(xrayConfig) {
- logger.Debug("not need to restart xray")
+ logger.Debug("It does not need to restart xray")
return nil
}
p.Stop()
@@ -166,7 +169,11 @@ func (s *XrayService) RestartXray(isForce bool) error {
p = xray.NewProcess(xrayConfig)
result = ""
- return p.Start()
+ err = p.Start()
+ if err != nil {