Compare commits

...

38 Commits

Author SHA1 Message Date
刘祥超
84483dce61 版本号更改为1.2.2 2023-07-18 14:33:53 +08:00
刘祥超
a4eb7a47f3 更新SQL 2023-07-16 19:12:10 +08:00
刘祥超
20c84d7fe5 手动同步集群任务后把所有相关任务标记为已完成 2023-07-14 10:04:44 +08:00
刘祥超
9d5acd2b36 优化代码 2023-07-12 17:10:33 +08:00
刘祥超
7508f6b92b 增加页面优化相关API 2023-07-11 19:46:00 +08:00
刘祥超
379030fe71 版本号改为1.2.1 2023-07-09 17:38:09 +08:00
刘祥超
10027eea20 缓存策略移除“容纳Key数量”选项 2023-07-08 18:50:58 +08:00
刘祥超
69f25a176b 提交SQL 2023-07-07 18:52:37 +08:00
刘祥超
ac19f06b6c 网站列表增加QPS和攻击QPS信息 2023-07-07 18:51:36 +08:00
刘祥超
87a81f59c7 修复查询网站日流量统计时可能不兼容MySQL8的问题 2023-07-07 17:35:23 +08:00
刘祥超
7389e5e54b 远程安装时可以覆盖运行中的文件 2023-07-07 15:59:51 +08:00
刘祥超
e6792b8188 优化自定义页面设置,页面URL不再支持填写本地文件 2023-07-07 11:48:48 +08:00
刘祥超
a037546cfa 优化代码 2023-07-07 09:52:53 +08:00
刘祥超
8efaacf1ef 国家/地区、省份等相关表增加真实ID字段,防止数据表被用户修改时无法对应 2023-07-07 09:52:46 +08:00
刘祥超
a38dd1cef8 “集群设置 -- 网站设置”增加“允许记录访问日志”选项 2023-07-05 15:29:11 +08:00
刘祥超
77521112d0 试用 executils.LookPath()代替 exec.LookPath() 2023-07-05 11:34:52 +08:00
刘祥超
4f9a5d238c 优化本地mysql服务自动启动逻辑 2023-07-05 11:14:51 +08:00
刘祥超
d5fb39ed50 更新TeaGo库 2023-07-05 09:25:27 +08:00
刘祥超
58a84083ae 优化自增锁性能 2023-07-04 22:02:17 +08:00
刘祥超
9f564a4739 重写规则API支持用户操作 2023-07-04 18:31:12 +08:00
刘祥超
c20accbf58 减少在自增锁中生成的sql statements 2023-07-04 14:42:14 +08:00
刘祥超
3f21b3148e 优化代码 2023-07-03 17:12:24 +08:00
刘祥超
74e909a501 增加清空节点同步任务、清空DNS同步任务API 2023-07-02 17:29:19 +08:00
刘祥超
4150ee1b47 优化自增锁算法 2023-07-02 15:27:49 +08:00
刘祥超
df04de2151 修复测试用例 2023-07-02 15:25:13 +08:00
刘祥超
4dc5d9aa7e 修复自动生成的用户没有绑定集群、用户名不规范的问题 2023-07-02 14:30:46 +08:00
刘祥超
0ef7e6ccd8 增加部分数据清理周期设置 2023-07-01 17:54:40 +08:00
刘祥超
ed2b831e5a 查找当前API节点版本中增加角色 2023-07-01 15:09:54 +08:00
刘祥超
5d392ecd43 优化代码 2023-06-30 19:06:55 +08:00
刘祥超
ea147d7506 优化代码 2023-06-30 19:01:47 +08:00
刘祥超
b45136c2c8 优化代码 2023-06-30 18:54:45 +08:00
刘祥超
530e1513ec 日志API增加多语言代号参数 2023-06-30 18:10:11 +08:00
刘祥超
6c60677b72 添加多语言最基础代码 2023-06-28 09:11:20 +08:00
刘祥超
a1bec5e578 创建Web配置时自动设置访客IP获取方式为“直接获取” 2023-06-23 17:05:52 +08:00
刘祥超
9dece058d9 优化查询所有集群性能 2023-06-23 16:23:21 +08:00
刘祥超
89df6ae6bf 优化集群列表性能 2023-06-23 16:15:22 +08:00
刘祥超
85b6e6428c 源站支持HTTP/2 2023-06-23 11:44:02 +08:00
刘祥超
0df204a1df 初始化时修改默认生成的用户名,并将用户自动关联到默认集群 2023-06-21 11:51:07 +08:00
94 changed files with 15043 additions and 6371 deletions

View File

@@ -52,7 +52,7 @@ func main() {
return return
} }
unzip := helpers.NewUnzip(zipPath, targetPath) var unzip = helpers.NewUnzip(zipPath, targetPath)
err := unzip.Run() err := unzip.Run()
if err != nil { if err != nil {
stderr("ERROR: " + err.Error()) stderr("ERROR: " + err.Error())

6
go.mod
View File

@@ -10,10 +10,11 @@ require (
github.com/andybalholm/brotli v1.0.4 github.com/andybalholm/brotli v1.0.4
github.com/cespare/xxhash v1.1.0 github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.1.1 github.com/cespare/xxhash/v2 v2.1.1
github.com/fsnotify/fsnotify v1.6.0
github.com/go-acme/lego/v4 v4.10.2 github.com/go-acme/lego/v4 v4.10.2
github.com/go-sql-driver/mysql v1.7.0 github.com/go-sql-driver/mysql v1.7.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470 github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62
github.com/miekg/dns v1.1.50 github.com/miekg/dns v1.1.50
github.com/mozillazg/go-pinyin v0.18.0 github.com/mozillazg/go-pinyin v0.18.0
@@ -29,7 +30,6 @@ require (
require ( require (
github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -41,6 +41,8 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/smartwalle/crypto4go v1.0.2 // indirect github.com/smartwalle/crypto4go v1.0.2 // indirect
github.com/tdewolff/minify/v2 v2.12.7 // indirect
github.com/tdewolff/parse/v2 v2.6.6 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.9 // indirect github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect github.com/tklauser/numcpus v0.3.0 // indirect

19
go.sum
View File

@@ -19,6 +19,7 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -30,6 +31,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -81,8 +84,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc= github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470 h1:TuRxvKRv9PxKVijWOkUnZm5TeanQqWGUJyPx9u6cra4= github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b h1:yYUaxnc04uzfr7C9HBN52ZZvcQomND+C5aZTpjOUYFI=
github.com/iwind/TeaGo v0.0.0-20230304012706-c1f4a4e27470/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s= github.com/iwind/TeaGo v0.0.0-20230704135818-4a5646ab1f5b/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo= github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62 h1:HJH6RDheAY156DnIfJSD/bEvqyXzsZuE2gzs8PuUjoo=
github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA= github.com/iwind/gosock v0.0.0-20220505115348-f88412125a62/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -98,10 +101,11 @@ github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -142,12 +146,20 @@ github.com/smartwalle/crypto4go v1.0.2 h1:9DUEOOsPhmp00438L4oBdcL8EZG1zumecft5bW
github.com/smartwalle/crypto4go v1.0.2/go.mod h1:LQ7vCZIb7BE5+MuMtJBuO8ORkkQ01m4DXDBWPzLbkMY= github.com/smartwalle/crypto4go v1.0.2/go.mod h1:LQ7vCZIb7BE5+MuMtJBuO8ORkkQ01m4DXDBWPzLbkMY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/tdewolff/minify/v2 v2.12.7 h1:pBzz2tAfz5VghOXiQIsSta6srhmTeinQPjRDHWoumCA=
github.com/tdewolff/minify/v2 v2.12.7/go.mod h1:ZRKTheiOGyLSK8hOZWWv+YoJAECzDivNgAlVYDHp/Ws=
github.com/tdewolff/parse/v2 v2.6.6 h1:Yld+0CrKUJaCV78DL1G2nk3C9lKrxyRTux5aaK/AkDo=
github.com/tdewolff/parse/v2 v2.6.6/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs=
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
@@ -225,7 +237,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@@ -1,7 +1,7 @@
package teaconst package teaconst
const ( const (
Version = "1.2.0" Version = "1.2.2"
ProductName = "Edge API" ProductName = "Edge API"
ProcessName = "edge-api" ProcessName = "edge-api"
@@ -18,7 +18,7 @@ const (
// 其他节点版本号,用来检测是否有需要升级的节点 // 其他节点版本号,用来检测是否有需要升级的节点
NodeVersion = "1.2.0" NodeVersion = "1.2.2"
// SQLVersion SQL版本号 // SQLVersion SQL版本号
SQLVersion = "11" SQLVersion = "11"

View File

@@ -2,6 +2,22 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
AdminField_Id dbs.FieldName = "id" // ID
AdminField_IsOn dbs.FieldName = "isOn" // 是否启用
AdminField_Username dbs.FieldName = "username" // 用户名
AdminField_Password dbs.FieldName = "password" // 密码
AdminField_Fullname dbs.FieldName = "fullname" // 全名
AdminField_IsSuper dbs.FieldName = "isSuper" // 是否为超级管理员
AdminField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
AdminField_UpdatedAt dbs.FieldName = "updatedAt" // 修改时间
AdminField_State dbs.FieldName = "state" // 状态
AdminField_Modules dbs.FieldName = "modules" // 允许的模块
AdminField_CanLogin dbs.FieldName = "canLogin" // 是否可以登录
AdminField_Theme dbs.FieldName = "theme" // 模板设置
AdminField_Lang dbs.FieldName = "lang" // 语言代号
)
// Admin 管理员 // Admin 管理员
type Admin struct { type Admin struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -16,6 +32,7 @@ type Admin struct {
Modules dbs.JSON `field:"modules"` // 允许的模块 Modules dbs.JSON `field:"modules"` // 允许的模块
CanLogin bool `field:"canLogin"` // 是否可以登录 CanLogin bool `field:"canLogin"` // 是否可以登录
Theme string `field:"theme"` // 模板设置 Theme string `field:"theme"` // 模板设置
Lang string `field:"lang"` // 语言代号
} }
type AdminOperator struct { type AdminOperator struct {
@@ -31,6 +48,7 @@ type AdminOperator struct {
Modules any // 允许的模块 Modules any // 允许的模块
CanLogin any // 是否可以登录 CanLogin any // 是否可以登录
Theme any // 模板设置 Theme any // 模板设置
Lang any // 语言代号
} }
func NewAdminOperator() *AdminOperator { func NewAdminOperator() *AdminOperator {

View File

@@ -155,6 +155,12 @@ func (this *DNSTaskDAO) DeleteDNSTask(tx *dbs.Tx, taskId int64) error {
return err return err
} }
// DeleteAllDNSTasks 删除所有任务
func (this *DNSTaskDAO) DeleteAllDNSTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// UpdateDNSTaskError 设置任务错误 // UpdateDNSTaskError 设置任务错误
func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string) error { func (this *DNSTaskDAO) UpdateDNSTaskError(tx *dbs.Tx, taskId int64, err string) error {
if taskId <= 0 { if taskId <= 0 {
@@ -195,6 +201,27 @@ func (this *DNSTaskDAO) UpdateDNSTaskDone(tx *dbs.Tx, taskId int64, taskVersion
return this.Save(tx, op) return this.Save(tx, op)
} }
// GenerateVersion 生成最新的版本号
func (this *DNSTaskDAO) GenerateVersion() int64 {
return time.Now().UnixNano()
}
// UpdateClusterDNSTasksDone 设置所有集群任务完成
func (this *DNSTaskDAO) UpdateClusterDNSTasksDone(tx *dbs.Tx, clusterId int64, maxVersion int64) error {
if clusterId <= 0 || maxVersion <= 0 {
return nil
}
return this.Query(tx).
Attr("clusterId", clusterId).
Attr("isOk", false).
Lte("version", maxVersion).
Set("isDone", true).
Set("isOk", true).
Set("error", "").
UpdateQuickly()
}
// DeleteDNSTasksWithClusterId 删除集群相关任务 // DeleteDNSTasksWithClusterId 删除集群相关任务
func (this *DNSTaskDAO) DeleteDNSTasksWithClusterId(tx *dbs.Tx, clusterId int64) error { func (this *DNSTaskDAO) DeleteDNSTasksWithClusterId(tx *dbs.Tx, clusterId int64) error {
if clusterId <= 0 { if clusterId <= 0 {

View File

@@ -1,17 +1,28 @@
package dns package dns_test
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
_ "github.com/iwind/TeaGo/bootstrap" _ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"testing" "testing"
"time"
) )
func TestDNSTaskDAO_CreateDNSTask(t *testing.T) { func TestDNSTaskDAO_CreateDNSTask(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
err := SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "cdn", "taskType") err := dns.SharedDNSTaskDAO.CreateDNSTask(nil, 1, 2, 3, 0, "cdn", "taskType")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log("ok") t.Log("ok")
} }
func TestDNSTaskDAO_UpdateClusterDNSTasksDone(t *testing.T) {
var dao = dns.NewDNSTaskDAO()
var tx *dbs.Tx
err := dao.UpdateClusterDNSTasksDone(tx, 46, time.Now().UnixNano())
if err != nil {
t.Fatal(err)
}
}

View File

@@ -96,7 +96,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
} }
// CreateCachePolicy 创建缓存策略 // CreateCachePolicy 创建缓存策略
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) { func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) (int64, error) {
var op = NewHTTPCachePolicyOperator() var op = NewHTTPCachePolicyOperator()
op.State = HTTPCachePolicyStateEnabled op.State = HTTPCachePolicyStateEnabled
op.IsOn = isOn op.IsOn = isOn
@@ -105,7 +105,6 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
if len(capacityJSON) > 0 { if len(capacityJSON) > 0 {
op.Capacity = capacityJSON op.Capacity = capacityJSON
} }
op.MaxKeys = maxKeys
if len(maxSizeJSON) > 0 { if len(maxSizeJSON) > 0 {
op.MaxSize = maxSizeJSON op.MaxSize = maxSizeJSON
} }
@@ -184,7 +183,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
return 0, err return 0, err
} }
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, 0, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false) policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@@ -192,7 +191,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
} }
// UpdateCachePolicy 修改缓存策略 // UpdateCachePolicy 修改缓存策略
func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) error { func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, capacityJSON []byte, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte, syncCompressionCache bool) error {
if policyId <= 0 { if policyId <= 0 {
return errors.New("invalid policyId") return errors.New("invalid policyId")
} }
@@ -205,7 +204,6 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
if len(capacityJSON) > 0 { if len(capacityJSON) > 0 {
op.Capacity = capacityJSON op.Capacity = capacityJSON
} }
op.MaxKeys = maxKeys
if len(maxSizeJSON) > 0 { if len(maxSizeJSON) > 0 {
op.MaxSize = maxSizeJSON op.MaxSize = maxSizeJSON
} }
@@ -256,8 +254,6 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
config.Capacity = capacityConfig config.Capacity = capacityConfig
} }
config.MaxKeys = types.Int64(policy.MaxKeys)
// max size // max size
if IsNotNull(policy.MaxSize) { if IsNotNull(policy.MaxSize) {
maxSizeConfig := &shared.SizeCapacity{} maxSizeConfig := &shared.SizeCapacity{}

View File

@@ -33,7 +33,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedHTTPCacheTaskDAO.Clean(nil, 30) // 只保留N天 err := SharedHTTPCacheTaskDAO.CleanDefaultDays(nil, 30) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("HTTPCacheTaskDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("HTTPCacheTaskDAO", "clean expired data failed: "+err.Error())
} }
@@ -228,8 +228,8 @@ func (this *HTTPCacheTaskDAO) CheckUserTask(tx *dbs.Tx, userId int64, taskId int
return nil return nil
} }
// Clean 清理以往的任务 // CleanDays 清理N天以前的任务
func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error { func (this *HTTPCacheTaskDAO) CleanDays(tx *dbs.Tx, days int) error {
if days <= 0 { if days <= 0 {
days = 30 days = 30
} }
@@ -248,6 +248,23 @@ func (this *HTTPCacheTaskDAO) Clean(tx *dbs.Tx, days int) error {
return err return err
} }
// CleanDefaultDays 清除任务
func (this *HTTPCacheTaskDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.HTTPCacheTask.Clean.Days > 0 {
defaultDays = databaseConfig.HTTPCacheTask.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 30
}
return this.CleanDays(tx, defaultDays)
}
// NotifyChange 发送通知 // NotifyChange 发送通知
func (this *HTTPCacheTaskDAO) NotifyChange(tx *dbs.Tx, taskId int64) error { func (this *HTTPCacheTaskDAO) NotifyChange(tx *dbs.Tx, taskId int64) error {
// TODO // TODO

View File

@@ -11,7 +11,7 @@ import (
func TestHTTPCacheTaskDAO_Clean(t *testing.T) { func TestHTTPCacheTaskDAO_Clean(t *testing.T) {
dbs.NotifyReady() dbs.NotifyReady()
err := models.SharedHTTPCacheTaskDAO.Clean(nil, 30) err := models.SharedHTTPCacheTaskDAO.CleanDays(nil, 30)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -124,8 +124,9 @@ func (this *HTTPRewriteRuleDAO) ComposeRewriteRule(tx *dbs.Tx, rewriteRuleId int
} }
// CreateRewriteRule 创建规则 // CreateRewriteRule 创建规则
func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) { func (this *HTTPRewriteRuleDAO) CreateRewriteRule(tx *dbs.Tx, userId int64, pattern string, replace string, mode string, redirectStatus int, isBreak bool, proxyHost string, withQuery bool, isOn bool, condsJSON []byte) (int64, error) {
var op = NewHTTPRewriteRuleOperator() var op = NewHTTPRewriteRuleOperator()
op.UserId = userId
op.State = HTTPRewriteRuleStateEnabled op.State = HTTPRewriteRuleStateEnabled
op.IsOn = isOn op.IsOn = isOn
@@ -172,6 +173,34 @@ func (this *HTTPRewriteRuleDAO) UpdateRewriteRule(tx *dbs.Tx, rewriteRuleId int6
return this.NotifyUpdate(tx, rewriteRuleId) return this.NotifyUpdate(tx, rewriteRuleId)
} }
func (this *HTTPRewriteRuleDAO) CheckUserRewriteRule(tx *dbs.Tx, userId int64, rewriteRuleId int64) error {
if rewriteRuleId <= 0 {
return ErrNotFound
}
exists, err := this.Query(tx).
Pk(rewriteRuleId).
Attr("userId", userId).
Exist()
if err != nil {
return err
}
if !exists {
return ErrNotFound
}
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)
if err != nil {
return err
}
if webId <= 0 {
return ErrNotFound
}
return SharedHTTPWebDAO.CheckUserWeb(tx, userId, webId)
}
// NotifyUpdate 通知更新 // NotifyUpdate 通知更新
func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error { func (this *HTTPRewriteRuleDAO) NotifyUpdate(tx *dbs.Tx, rewriteRuleId int64) error {
webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId) webId, err := SharedHTTPWebDAO.FindEnabledWebIdWithRewriteRuleId(tx, rewriteRuleId)

View File

@@ -151,6 +151,18 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, isLocationOrGr
} }
} }
// Optimization
if IsNotNull(web.Optimization) {
var optimizationConfig = serverconfigs.NewHTTPPageOptimizationConfig()
err = json.Unmarshal(web.Optimization, optimizationConfig)
if err != nil {
return nil, err
}
if this.shouldCompose(isLocationOrGroup, forNode, optimizationConfig.IsPrior, true) {
config.Optimization = optimizationConfig
}
}
// charset // charset
if IsNotNull(web.Charset) { if IsNotNull(web.Charset) {
var charsetConfig = &serverconfigs.HTTPCharsetConfig{} var charsetConfig = &serverconfigs.HTTPCharsetConfig{}
@@ -550,7 +562,20 @@ func (this *HTTPWebDAO) CreateWeb(tx *dbs.Tx, adminId int64, userId int64, rootJ
if len(rootJSON) > 0 { if len(rootJSON) > 0 {
op.Root = JSONBytes(rootJSON) op.Root = JSONBytes(rootJSON)
} }
err := this.Save(tx, op)
// 设置默认的remote-addr
// set default remote-addr config
var remoteAddrConfig = &serverconfigs.HTTPRemoteAddrConfig{
IsOn: true,
Value: "${rawRemoteAddr}",
}
remoteAddrConfigJSON, err := json.Marshal(remoteAddrConfig)
if err != nil {
return 0, err
}
op.RemoteAddr = remoteAddrConfigJSON
err = this.Save(tx, op)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@@ -574,14 +599,42 @@ func (this *HTTPWebDAO) UpdateWeb(tx *dbs.Tx, webId int64, rootJSON []byte) erro
} }
// UpdateWebCompression 修改压缩配置 // UpdateWebCompression 修改压缩配置
func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressionConfig []byte) error { func (this *HTTPWebDAO) UpdateWebCompression(tx *dbs.Tx, webId int64, compressionConfig *serverconfigs.HTTPCompressionConfig) error {
if webId <= 0 { if webId <= 0 {
return errors.New("invalid webId") return errors.New("invalid webId")
} }
compressionJSON, err := json.Marshal(compressionConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator() var op = NewHTTPWebOperator()
op.Id = webId op.Id = webId
op.Compression = JSONBytes(compressionConfig) op.Compression = compressionJSON
err := this.Save(tx, op) err = this.Save(tx, op)
if err != nil {
return err
}
return this.NotifyUpdate(tx, webId)
}
// UpdateWebOptimization 修改页面优化配置
func (this *HTTPWebDAO) UpdateWebOptimization(tx *dbs.Tx, webId int64, optimizationConfig *serverconfigs.HTTPPageOptimizationConfig) error {
if webId <= 0 {
return errors.New("invalid webId")
}
optimizationJSON, err := json.Marshal(optimizationConfig)
if err != nil {
return err
}
var op = NewHTTPWebOperator()
op.Id = webId
op.Optimization = optimizationJSON
err = this.Save(tx, op)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,6 +2,47 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
HTTPWebField_Id dbs.FieldName = "id" // ID
HTTPWebField_IsOn dbs.FieldName = "isOn" // 是否启用
HTTPWebField_TemplateId dbs.FieldName = "templateId" // 模版ID
HTTPWebField_AdminId dbs.FieldName = "adminId" // 管理员ID
HTTPWebField_UserId dbs.FieldName = "userId" // 用户ID
HTTPWebField_State dbs.FieldName = "state" // 状态
HTTPWebField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
HTTPWebField_Root dbs.FieldName = "root" // 根目录
HTTPWebField_Charset dbs.FieldName = "charset" // 字符集
HTTPWebField_Shutdown dbs.FieldName = "shutdown" // 临时关闭页面配置
HTTPWebField_Pages dbs.FieldName = "pages" // 特殊页面
HTTPWebField_RedirectToHttps dbs.FieldName = "redirectToHttps" // 跳转到HTTPS设置
HTTPWebField_Indexes dbs.FieldName = "indexes" // 首页文件列表
HTTPWebField_MaxRequestBodySize dbs.FieldName = "maxRequestBodySize" // 最大允许的请求内容尺寸
HTTPWebField_RequestHeader dbs.FieldName = "requestHeader" // 请求Header配置
HTTPWebField_ResponseHeader dbs.FieldName = "responseHeader" // 响应Header配置
HTTPWebField_AccessLog dbs.FieldName = "accessLog" // 访问日志配置
HTTPWebField_Stat dbs.FieldName = "stat" // 统计配置
HTTPWebField_Gzip dbs.FieldName = "gzip" // Gzip配置v0.3.2弃用)
HTTPWebField_Compression dbs.FieldName = "compression" // 压缩配置
HTTPWebField_Cache dbs.FieldName = "cache" // 缓存配置
HTTPWebField_Firewall dbs.FieldName = "firewall" // 防火墙设置
HTTPWebField_Locations dbs.FieldName = "locations" // 路由规则配置
HTTPWebField_Websocket dbs.FieldName = "websocket" // Websocket设置
HTTPWebField_RewriteRules dbs.FieldName = "rewriteRules" // 重写规则配置
HTTPWebField_HostRedirects dbs.FieldName = "hostRedirects" // 域名跳转
HTTPWebField_Fastcgi dbs.FieldName = "fastcgi" // Fastcgi配置
HTTPWebField_Auth dbs.FieldName = "auth" // 认证策略配置
HTTPWebField_Webp dbs.FieldName = "webp" // WebP配置
HTTPWebField_RemoteAddr dbs.FieldName = "remoteAddr" // 客户端IP配置
HTTPWebField_MergeSlashes dbs.FieldName = "mergeSlashes" // 是否合并路径中的斜杠
HTTPWebField_RequestLimit dbs.FieldName = "requestLimit" // 请求限制
HTTPWebField_RequestScripts dbs.FieldName = "requestScripts" // 请求脚本
HTTPWebField_Uam dbs.FieldName = "uam" // UAM设置
HTTPWebField_Cc dbs.FieldName = "cc" // CC设置
HTTPWebField_Referers dbs.FieldName = "referers" // 防盗链设置
HTTPWebField_UserAgent dbs.FieldName = "userAgent" // UserAgent设置
HTTPWebField_Optimization dbs.FieldName = "optimization" // 页面优化配置
)
// HTTPWeb HTTP Web // HTTPWeb HTTP Web
type HTTPWeb struct { type HTTPWeb struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -41,6 +82,7 @@ type HTTPWeb struct {
Cc dbs.JSON `field:"cc"` // CC设置 Cc dbs.JSON `field:"cc"` // CC设置
Referers dbs.JSON `field:"referers"` // 防盗链设置 Referers dbs.JSON `field:"referers"` // 防盗链设置
UserAgent dbs.JSON `field:"userAgent"` // UserAgent设置 UserAgent dbs.JSON `field:"userAgent"` // UserAgent设置
Optimization dbs.JSON `field:"optimization"` // 页面优化配置
} }
type HTTPWebOperator struct { type HTTPWebOperator struct {
@@ -81,6 +123,7 @@ type HTTPWebOperator struct {
Cc any // CC设置 Cc any // CC设置
Referers any // 防盗链设置 Referers any // 防盗链设置
UserAgent any // UserAgent设置 UserAgent any // UserAgent设置
Optimization any // 页面优化配置
} }
func NewHTTPWebOperator() *HTTPWebOperator { func NewHTTPWebOperator() *HTTPWebOperator {

View File

@@ -339,7 +339,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countries = []*iplibrary.Country{} var countries = []*iplibrary.Country{}
for _, country := range dbCountries { for _, country := range dbCountries {
countries = append(countries, &iplibrary.Country{ countries = append(countries, &iplibrary.Country{
Id: types.Uint16(country.Id), Id: types.Uint16(country.ValueId),
Name: country.DisplayName(), Name: country.DisplayName(),
Codes: country.AllCodes(), Codes: country.AllCodes(),
}) })
@@ -354,7 +354,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var provinces = []*iplibrary.Province{} var provinces = []*iplibrary.Province{}
for _, province := range dbProvinces { for _, province := range dbProvinces {
provinces = append(provinces, &iplibrary.Province{ provinces = append(provinces, &iplibrary.Province{
Id: types.Uint16(province.Id), Id: types.Uint16(province.ValueId),
Name: province.DisplayName(), Name: province.DisplayName(),
Codes: province.AllCodes(), Codes: province.AllCodes(),
}) })
@@ -369,7 +369,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var cities = []*iplibrary.City{} var cities = []*iplibrary.City{}
for _, city := range dbCities { for _, city := range dbCities {
cities = append(cities, &iplibrary.City{ cities = append(cities, &iplibrary.City{
Id: city.Id, Id: city.ValueId,
Name: city.DisplayName(), Name: city.DisplayName(),
Codes: city.AllCodes(), Codes: city.AllCodes(),
}) })
@@ -384,7 +384,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var towns = []*iplibrary.Town{} var towns = []*iplibrary.Town{}
for _, town := range dbTowns { for _, town := range dbTowns {
towns = append(towns, &iplibrary.Town{ towns = append(towns, &iplibrary.Town{
Id: town.Id, Id: town.ValueId,
Name: town.DisplayName(), Name: town.DisplayName(),
Codes: town.AllCodes(), Codes: town.AllCodes(),
}) })
@@ -399,7 +399,7 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var providers = []*iplibrary.Provider{} var providers = []*iplibrary.Provider{}
for _, provider := range dbProviders { for _, provider := range dbProviders {
providers = append(providers, &iplibrary.Provider{ providers = append(providers, &iplibrary.Provider{
Id: types.Uint16(provider.Id), Id: types.Uint16(provider.ValueId),
Name: provider.DisplayName(), Name: provider.DisplayName(),
Codes: provider.AllCodes(), Codes: provider.AllCodes(),
}) })
@@ -440,35 +440,35 @@ func (this *IPLibraryFileDAO) GenerateIPLibrary(tx *dbs.Tx, libraryFileId int64)
var countryMap = map[string]int64{} // countryName => countryId var countryMap = map[string]int64{} // countryName => countryId
for _, country := range dbCountries { for _, country := range dbCountries {
for _, code := range country.AllCodes() { for _, code := range country.AllCodes() {
countryMap[code] = int64(country.Id) countryMap[code] = int64(country.ValueId)
} }
} }
var provinceMap = map[string]int64{} // countryId_provinceName => provinceId var provinceMap = map[string]int64{} // countryId_provinceName => provinceId
for _, province := range dbProvinces { for _, province := range dbProvinces {
for _, code := range province.AllCodes() { for _, code := range province.AllCodes() {
provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.Id) provinceMap[types.String(province.CountryId)+"_"+code] = int64(province.ValueId)
} }
} }
var cityMap = map[string]int64{} // provinceId_cityName => cityId var cityMap = map[string]int64{} // provinceId_cityName => cityId
for _, city := range dbCities { for _, city := range dbCities {
for _, code := range city.AllCodes() { for _, code := range city.AllCodes() {
cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.Id) cityMap[types.String(city.ProvinceId)+"_"+code] = int64(city.ValueId)
} }
} }
var townMap = map[string]int64{} // cityId_townName => townId var townMap = map[string]int64{} // cityId_townName => townId
for _, town := range dbTowns { for _, town := range dbTowns {
for _, code := range town.AllCodes() { for _, code := range town.AllCodes() {
townMap[types.String(town.CityId)+"_"+code] = int64(town.Id) townMap[types.String(town.CityId)+"_"+code] = int64(town.ValueId)
} }
} }
var providerMap = map[string]int64{} // providerName => providerId var providerMap = map[string]int64{} // providerName => providerId
for _, provider := range dbProviders { for _, provider := range dbProviders {
for _, code := range provider.AllCodes() { for _, code := range provider.AllCodes() {
providerMap[code] = int64(provider.Id) providerMap[code] = int64(provider.ValueId)
} }
} }

View File

@@ -1,9 +1,11 @@
package models package models
import ( import (
"encoding/json"
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils" dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -36,7 +38,7 @@ func init() {
} }
// CreateLog 创建管理员日志 // CreateLog 创建管理员日志
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string) error { func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string, langMessageCode langs.MessageCode, langMessageArgs []any) error {
var op = NewLogOperator() var op = NewLogOperator()
op.Level = level op.Level = level
op.Description = utils.LimitString(description, 1000) op.Description = utils.LimitString(description, 1000)
@@ -53,6 +55,16 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
op.ProviderId = adminId op.ProviderId = adminId
} }
// i18n
op.LangMessageCode = langMessageCode
if len(langMessageArgs) > 0 {
langMessageArgsJSON, err := json.Marshal(langMessageArgs)
if err != nil {
return err
}
op.LangMessageArgs = langMessageArgsJSON
}
op.Day = timeutil.Format("Ymd") op.Day = timeutil.Format("Ymd")
op.Type = LogTypeAdmin op.Type = LogTypeAdmin
err := this.Save(tx, op) err := this.Save(tx, op)

View File

@@ -1,34 +1,60 @@
package models package models
// 操作日志 import "github.com/iwind/TeaGo/dbs"
const (
LogField_Id dbs.FieldName = "id" // ID
LogField_Level dbs.FieldName = "level" // 级别
LogField_Description dbs.FieldName = "description" // 描述
LogField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
LogField_Action dbs.FieldName = "action" // 动作
LogField_UserId dbs.FieldName = "userId" // 用户ID
LogField_AdminId dbs.FieldName = "adminId" // 管理员ID
LogField_ProviderId dbs.FieldName = "providerId" // 供应商ID
LogField_Ip dbs.FieldName = "ip" // IP地址
LogField_Type dbs.FieldName = "type" // 类型admin, user
LogField_Day dbs.FieldName = "day" // 日期
LogField_BillId dbs.FieldName = "billId" // 账单ID
LogField_LangMessageCode dbs.FieldName = "langMessageCode" // 多语言消息代号
LogField_LangMessageArgs dbs.FieldName = "langMessageArgs" // 多语言参数
LogField_Params dbs.FieldName = "params" // 关联对象参数
)
// Log 操作日志
type Log struct { type Log struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
Level string `field:"level"` // 级别 Level string `field:"level"` // 级别
Description string `field:"description"` // 描述 Description string `field:"description"` // 描述
CreatedAt uint64 `field:"createdAt"` // 创建时间 CreatedAt uint64 `field:"createdAt"` // 创建时间
Action string `field:"action"` // 动作 Action string `field:"action"` // 动作
UserId uint32 `field:"userId"` // 用户ID UserId uint32 `field:"userId"` // 用户ID
AdminId uint32 `field:"adminId"` // 管理员ID AdminId uint32 `field:"adminId"` // 管理员ID
ProviderId uint32 `field:"providerId"` // 供应商ID ProviderId uint32 `field:"providerId"` // 供应商ID
Ip string `field:"ip"` // IP地址 Ip string `field:"ip"` // IP地址
Type string `field:"type"` // 类型admin, user Type string `field:"type"` // 类型admin, user
Day string `field:"day"` // 日期 Day string `field:"day"` // 日期
BillId uint32 `field:"billId"` // 账单ID BillId uint32 `field:"billId"` // 账单ID
LangMessageCode string `field:"langMessageCode"` // 多语言消息代号
LangMessageArgs dbs.JSON `field:"langMessageArgs"` // 多语言参数
Params dbs.JSON `field:"params"` // 关联对象参数
} }
type LogOperator struct { type LogOperator struct {
Id interface{} // ID Id any // ID
Level interface{} // 级别 Level any // 级别
Description interface{} // 描述 Description any // 描述
CreatedAt interface{} // 创建时间 CreatedAt any // 创建时间
Action interface{} // 动作 Action any // 动作
UserId interface{} // 用户ID UserId any // 用户ID
AdminId interface{} // 管理员ID AdminId any // 管理员ID
ProviderId interface{} // 供应商ID ProviderId any // 供应商ID
Ip interface{} // IP地址 Ip any // IP地址
Type interface{} // 类型admin, user Type any // 类型admin, user
Day interface{} // 日期 Day any // 日期
BillId interface{} // 账单ID BillId any // 账单ID
LangMessageCode any // 多语言消息代号
LangMessageArgs any // 多语言参数
Params any // 关联对象参数
} }
func NewLogOperator() *LogOperator { func NewLogOperator() *LogOperator {

View File

@@ -100,6 +100,7 @@ func (this *NodeClusterDAO) FindNodeClusterName(tx *dbs.Tx, clusterId int64) (st
// FindAllEnableClusters 查找所有可用的集群 // FindAllEnableClusters 查找所有可用的集群
func (this *NodeClusterDAO) FindAllEnableClusters(tx *dbs.Tx) (result []*NodeCluster, err error) { func (this *NodeClusterDAO) FindAllEnableClusters(tx *dbs.Tx) (result []*NodeCluster, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
Result(NodeClusterField_Id, NodeClusterField_Name, NodeClusterField_IsOn, NodeClusterField_HealthCheck, NodeClusterField_AutoRemoteStart, NodeClusterField_AutoRegister, NodeClusterField_CreatedAt, NodeClusterField_UniqueId, NodeClusterField_Secret).
State(NodeClusterStateEnabled). State(NodeClusterStateEnabled).
Slice(&result). Slice(&result).
Desc("isPinned"). Desc("isPinned").
@@ -175,7 +176,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
// 全局服务配置 // 全局服务配置
if globalServerConfig == nil { if globalServerConfig == nil {
globalServerConfig = serverconfigs.DefaultGlobalServerConfig() globalServerConfig = serverconfigs.NewGlobalServerConfig()
} }
globalServerConfigJSON, err := json.Marshal(globalServerConfig) globalServerConfigJSON, err := json.Marshal(globalServerConfig)
if err != nil { if err != nil {
@@ -262,19 +263,40 @@ func (this *NodeClusterDAO) CountAllEnabledClusters(tx *dbs.Tx, keyword string)
// ListEnabledClusters 列出单页集群 // ListEnabledClusters 列出单页集群
func (this *NodeClusterDAO) ListEnabledClusters(tx *dbs.Tx, keyword string, offset, size int64) (result []*NodeCluster, err error) { func (this *NodeClusterDAO) ListEnabledClusters(tx *dbs.Tx, keyword string, offset, size int64) (result []*NodeCluster, err error) {
query := this.Query(tx). var query = this.Query(tx).
State(NodeClusterStateEnabled) State(NodeClusterStateEnabled)
if len(keyword) > 0 { if len(keyword) > 0 {
query.Where("(name LIKE :keyword OR dnsName like :keyword OR (dnsDomainId > 0 AND dnsDomainId IN (SELECT id FROM "+dns.SharedDNSDomainDAO.Table+" WHERE name LIKE :keyword AND state=1)))"). query.Where("(name LIKE :keyword OR dnsName like :keyword OR (dnsDomainId > 0 AND dnsDomainId IN (SELECT id FROM "+dns.SharedDNSDomainDAO.Table+" WHERE name LIKE :keyword AND state=1)))").
Param("keyword", dbutils.QuoteLike(keyword)) Param("keyword", dbutils.QuoteLike(keyword))
} }
_, err = query. _, err = query.
Result(
NodeClusterField_Id,
NodeClusterField_Name,
NodeClusterField_IsOn,
NodeClusterField_IsPinned,
NodeClusterField_InstallDir,
NodeClusterField_HttpFirewallPolicyId,
NodeClusterField_AdminId,
NodeClusterField_IsOn,
NodeClusterField_IsAD,
NodeClusterField_UserId,
NodeClusterField_DnsName,
NodeClusterField_DnsDomainId,
NodeClusterField_Dns,
NodeClusterField_CreatedAt,
NodeClusterField_UniqueId,
NodeClusterField_Secret,
NodeClusterField_GrantId,
NodeClusterField_TimeZone,
).
Offset(offset). Offset(offset).
Limit(size). Limit(size).
Slice(&result). Slice(&result).
Desc("isPinned"). Desc("isPinned").
DescPk(). DescPk().
FindAll() FindAll()
return return
} }
@@ -1113,11 +1135,12 @@ func (this *NodeClusterDAO) FindClusterUAMPolicy(tx *dbs.Tx, clusterId int64, ca
return nil, err return nil, err
} }
var policy = nodeconfigs.NewUAMPolicy()
if IsNull(uamJSON) { if IsNull(uamJSON) {
return nodeconfigs.DefaultUAMPolicy, nil return policy, nil
} }
var policy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(uamJSON, policy) err = json.Unmarshal(uamJSON, policy)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1373,7 +1396,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
return nil, err return nil, err
} }
var config = serverconfigs.DefaultGlobalServerConfig() var config = serverconfigs.NewGlobalServerConfig()
if IsNull(configJSON) { if IsNull(configJSON) {
return config, nil return config, nil
} }
@@ -1389,7 +1412,7 @@ func (this *NodeClusterDAO) FindClusterGlobalServerConfig(tx *dbs.Tx, clusterId
// UpdateClusterGlobalServerConfig 修改全局服务配置 // UpdateClusterGlobalServerConfig 修改全局服务配置
func (this *NodeClusterDAO) UpdateClusterGlobalServerConfig(tx *dbs.Tx, clusterId int64, config *serverconfigs.GlobalServerConfig) error { func (this *NodeClusterDAO) UpdateClusterGlobalServerConfig(tx *dbs.Tx, clusterId int64, config *serverconfigs.GlobalServerConfig) error {
if config == nil { if config == nil {
config = serverconfigs.DefaultGlobalServerConfig() config = serverconfigs.NewGlobalServerConfig()
} }
configJSON, err := json.Marshal(config) configJSON, err := json.Marshal(config)
if err != nil { if err != nil {

View File

@@ -2,6 +2,49 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
NodeClusterField_Id dbs.FieldName = "id" // ID
NodeClusterField_AdminId dbs.FieldName = "adminId" // 管理员ID
NodeClusterField_UserId dbs.FieldName = "userId" // 用户ID
NodeClusterField_IsOn dbs.FieldName = "isOn" // 是否启用
NodeClusterField_Name dbs.FieldName = "name" // 名称
NodeClusterField_UseAllAPINodes dbs.FieldName = "useAllAPINodes" // 是否使用所有API节点
NodeClusterField_ApiNodes dbs.FieldName = "apiNodes" // 使用的API节点
NodeClusterField_InstallDir dbs.FieldName = "installDir" // 安装目录
NodeClusterField_Order dbs.FieldName = "order" // 排序
NodeClusterField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
NodeClusterField_GrantId dbs.FieldName = "grantId" // 默认认证方式
NodeClusterField_SshParams dbs.FieldName = "sshParams" // SSH默认参数
NodeClusterField_State dbs.FieldName = "state" // 状态
NodeClusterField_AutoRegister dbs.FieldName = "autoRegister" // 是否开启自动注册
NodeClusterField_UniqueId dbs.FieldName = "uniqueId" // 唯一ID
NodeClusterField_Secret dbs.FieldName = "secret" // 密钥
NodeClusterField_HealthCheck dbs.FieldName = "healthCheck" // 健康检查
NodeClusterField_DnsName dbs.FieldName = "dnsName" // DNS名称
NodeClusterField_DnsDomainId dbs.FieldName = "dnsDomainId" // 域名ID
NodeClusterField_Dns dbs.FieldName = "dns" // DNS配置
NodeClusterField_Toa dbs.FieldName = "toa" // TOA配置
NodeClusterField_CachePolicyId dbs.FieldName = "cachePolicyId" // 缓存策略ID
NodeClusterField_HttpFirewallPolicyId dbs.FieldName = "httpFirewallPolicyId" // WAF策略ID
NodeClusterField_AccessLog dbs.FieldName = "accessLog" // 访问日志设置
NodeClusterField_SystemServices dbs.FieldName = "systemServices" // 系统服务设置
NodeClusterField_TimeZone dbs.FieldName = "timeZone" // 时区
NodeClusterField_NodeMaxThreads dbs.FieldName = "nodeMaxThreads" // 节点最大线程数
NodeClusterField_DdosProtection dbs.FieldName = "ddosProtection" // DDoS防护设置
NodeClusterField_AutoOpenPorts dbs.FieldName = "autoOpenPorts" // 是否自动尝试开放端口
NodeClusterField_IsPinned dbs.FieldName = "isPinned" // 是否置顶
NodeClusterField_Webp dbs.FieldName = "webp" // WebP设置
NodeClusterField_Uam dbs.FieldName = "uam" // UAM设置
NodeClusterField_Clock dbs.FieldName = "clock" // 时钟配置
NodeClusterField_GlobalServerConfig dbs.FieldName = "globalServerConfig" // 全局服务配置
NodeClusterField_AutoRemoteStart dbs.FieldName = "autoRemoteStart" // 自动远程启动
NodeClusterField_AutoInstallNftables dbs.FieldName = "autoInstallNftables" // 自动安装nftables
NodeClusterField_IsAD dbs.FieldName = "isAD" // 是否为高防集群
NodeClusterField_HttpPages dbs.FieldName = "httpPages" // 自定义页面设置
NodeClusterField_Cc dbs.FieldName = "cc" // CC设置
NodeClusterField_Http3 dbs.FieldName = "http3" // HTTP3设置
)
// NodeCluster 节点集群 // NodeCluster 节点集群
type NodeCluster struct { type NodeCluster struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID

View File

@@ -60,7 +60,7 @@ func (this *NodeCluster) DecodeClock() *nodeconfigs.ClockConfig {
// DecodeGlobalServerConfig 解析全局服务配置 // DecodeGlobalServerConfig 解析全局服务配置
func (this *NodeCluster) DecodeGlobalServerConfig() *serverconfigs.GlobalServerConfig { func (this *NodeCluster) DecodeGlobalServerConfig() *serverconfigs.GlobalServerConfig {
var config = serverconfigs.DefaultGlobalServerConfig() var config = serverconfigs.NewGlobalServerConfig()
if IsNotNull(this.GlobalServerConfig) { if IsNotNull(this.GlobalServerConfig) {
err := json.Unmarshal(this.GlobalServerConfig, config) err := json.Unmarshal(this.GlobalServerConfig, config)
if err != nil { if err != nil {

View File

@@ -1174,7 +1174,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
// UAM // UAM
if IsNotNull(nodeCluster.Uam) { if IsNotNull(nodeCluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{} var uamPolicy = nodeconfigs.NewUAMPolicy()
err = json.Unmarshal(nodeCluster.Uam, uamPolicy) err = json.Unmarshal(nodeCluster.Uam, uamPolicy)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -233,6 +233,12 @@ func (this *NodeTaskDAO) DeleteNodeTasks(tx *dbs.Tx, role string, nodeId int64)
return err return err
} }
// DeleteAllNodeTasks 删除所有节点相关任务
func (this *NodeTaskDAO)DeleteAllNodeTasks(tx *dbs.Tx) error {
return this.Query(tx).
DeleteQuickly()
}
// FindDoingNodeTasks 查询一个节点的所有任务 // FindDoingNodeTasks 查询一个节点的所有任务
func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) { func (this *NodeTaskDAO) FindDoingNodeTasks(tx *dbs.Tx, role string, nodeId int64, version int64) (result []*NodeTask, err error) {
if nodeId <= 0 { if nodeId <= 0 {

View File

@@ -22,7 +22,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedNodeTrafficDailyStatDAO.Clean(nil, 30) // 只保留N天 err := SharedNodeTrafficDailyStatDAO.CleanDefaultDays(nil, 32) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("NodeTrafficDailyStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("NodeTrafficDailyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -134,11 +134,27 @@ func (this *NodeTrafficDailyStatDAO) SumDailyStat(tx *dbs.Tx, role string, nodeI
return one.(*NodeTrafficDailyStat), nil return one.(*NodeTrafficDailyStat), nil
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *NodeTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *NodeTrafficDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("day", day). Lt("day", day).
Delete() Delete()
return err return err
} }
func (this *NodeTrafficDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.NodeTrafficDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.NodeTrafficDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 32
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -104,7 +104,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef, certRef *sslconfigs.SSLCertRef,
domains []string, domains []string,
host string, host string,
followPort bool) (originId int64, err error) { followPort bool,
http2Enabled bool) (originId int64, err error) {
var op = NewOriginOperator() var op = NewOriginOperator()
op.AdminId = adminId op.AdminId = adminId
op.UserId = userId op.UserId = userId
@@ -182,6 +183,7 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
op.Host = host op.Host = host
op.FollowPort = followPort op.FollowPort = followPort
op.Http2Enabled = http2Enabled
op.State = OriginStateEnabled op.State = OriginStateEnabled
err = this.Save(tx, op) err = this.Save(tx, op)
@@ -208,7 +210,8 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
certRef *sslconfigs.SSLCertRef, certRef *sslconfigs.SSLCertRef,
domains []string, domains []string,
host string, host string,
followPort bool) error { followPort bool,
http2Enabled bool) error {
if originId <= 0 { if originId <= 0 {
return errors.New("invalid originId") return errors.New("invalid originId")
} }
@@ -290,6 +293,7 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
op.Host = host op.Host = host
op.FollowPort = followPort op.FollowPort = followPort
op.Http2Enabled = http2Enabled
err := this.Save(tx, op) err := this.Save(tx, op)
if err != nil { if err != nil {
@@ -353,6 +357,7 @@ func (this *OriginDAO) CloneOrigin(tx *dbs.Tx, fromOriginId int64) (newOriginId
op.Domains = origin.Domains op.Domains = origin.Domains
} }
op.FollowPort = origin.FollowPort op.FollowPort = origin.FollowPort
op.Http2Enabled = origin.Http2Enabled
op.State = origin.State op.State = origin.State
return this.SaveInt64(tx, op) return this.SaveInt64(tx, op)
} }
@@ -391,6 +396,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
RequestHost: origin.Host, RequestHost: origin.Host,
Domains: origin.DecodeDomains(), Domains: origin.DecodeDomains(),
FollowPort: origin.FollowPort, FollowPort: origin.FollowPort,
HTTP2Enabled: origin.Http2Enabled,
} }
// addr // addr

View File

@@ -32,6 +32,7 @@ type Origin struct {
Domains dbs.JSON `field:"domains"` // 所属域名 Domains dbs.JSON `field:"domains"` // 所属域名
FollowPort bool `field:"followPort"` // 端口跟随 FollowPort bool `field:"followPort"` // 端口跟随
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
Http2Enabled bool `field:"http2Enabled"` // 是否支持HTTP/2
} }
type OriginOperator struct { type OriginOperator struct {
@@ -63,6 +64,7 @@ type OriginOperator struct {
Domains any // 所属域名 Domains any // 所属域名
FollowPort any // 端口跟随 FollowPort any // 端口跟随
State any // 状态 State any // 状态
Http2Enabled any // 是否支持HTTP/2
} }
func NewOriginOperator() *OriginOperator { func NewOriginOperator() *OriginOperator {

View File

@@ -42,7 +42,7 @@ func init() {
// EnableRegionCity 启用条目 // EnableRegionCity 启用条目
func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error { func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionCityStateEnabled). Set("state", RegionCityStateEnabled).
Update() Update()
return err return err
@@ -51,7 +51,7 @@ func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
// DisableRegionCity 禁用条目 // DisableRegionCity 禁用条目
func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error { func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionCityStateDisabled). Set("state", RegionCityStateDisabled).
Update() Update()
return err return err
@@ -60,7 +60,7 @@ func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
// FindEnabledRegionCity 查找启用中的条目 // FindEnabledRegionCity 查找启用中的条目
func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionCity, error) { func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionCity, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Attr("state", RegionCityStateEnabled). Attr("state", RegionCityStateEnabled).
Find() Find()
if result == nil { if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionC
// FindRegionCityName 根据主键查找名称 // FindRegionCityName 根据主键查找名称
func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, error) { func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx). return this.Query(tx).
Pk(id). Attr("valueId", id).
Result("name"). Result("name").
FindStringCol("") FindStringCol("")
} }
@@ -81,7 +81,7 @@ func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, er
func (this *RegionCityDAO) FindCityWithDataId(tx *dbs.Tx, dataId string) (int64, error) { func (this *RegionCityDAO) FindCityWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx). return this.Query(tx).
Attr("dataId", dataId). Attr("dataId", dataId).
ResultPk(). Result(RegionCityField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -93,7 +93,7 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
op.DataId = dataId op.DataId = dataId
op.State = RegionCityStateEnabled op.State = RegionCityStateEnabled
codes := []string{name} var codes = []string{name}
codesJSON, err := json.Marshal(codes) codesJSON, err := json.Marshal(codes)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -103,7 +103,18 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
if err != nil { if err != nil {
return 0, err return 0, err
} }
return types.Int64(op.Id), nil var cityId = types.Int64(op.Id)
// value id
err = this.Query(tx).
Pk(cityId).
Set(RegionCityField_ValueId, cityId).
UpdateQuickly()
if err != nil {
return 0, err
}
return cityId, nil
} }
// FindCityIdWithName 根据城市名查找城市ID // FindCityIdWithName 根据城市名查找城市ID
@@ -113,7 +124,7 @@ func (this *RegionCityDAO) FindCityIdWithName(tx *dbs.Tx, provinceId int64, city
Where("(name=:cityName OR customName=:cityName OR JSON_CONTAINS(codes, :cityNameJSON) OR JSON_CONTAINS(customCodes, :cityNameJSON))"). Where("(name=:cityName OR customName=:cityName OR JSON_CONTAINS(codes, :cityNameJSON) OR JSON_CONTAINS(customCodes, :cityNameJSON))").
Param("cityName", cityName). Param("cityName", cityName).
Param("cityNameJSON", strconv.Quote(cityName)). // 查询的需要是个JSON字符串所以这里加双引号 Param("cityNameJSON", strconv.Quote(cityName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk(). Result(RegionCityField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -147,7 +158,7 @@ func (this *RegionCityDAO) UpdateCityCustom(tx *dbs.Tx, cityId int64, customName
} }
return this.Query(tx). return this.Query(tx).
Pk(cityId). Attr(RegionCityField_ValueId, cityId).
Set("customName", customName). Set("customName", customName).
Set("customCodes", customCodesJSON). Set("customCodes", customCodesJSON).
UpdateQuickly() UpdateQuickly()

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
RegionCityField_Id dbs.FieldName = "id" // ID
RegionCityField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionCityField_ProvinceId dbs.FieldName = "provinceId" // 省份ID
RegionCityField_Name dbs.FieldName = "name" // 名称
RegionCityField_Codes dbs.FieldName = "codes" // 代号
RegionCityField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionCityField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionCityField_State dbs.FieldName = "state" // 状态
RegionCityField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionCity 区域-城市 // RegionCity 区域-城市
type RegionCity struct { type RegionCity struct {
Id uint32 `field:"id"` // ID Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ProvinceId uint32 `field:"provinceId"` // 省份ID ProvinceId uint32 `field:"provinceId"` // 省份ID
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionCity struct {
} }
type RegionCityOperator struct { type RegionCityOperator struct {
Id interface{} // ID Id any // ID
ProvinceId interface{} // 省份ID ValueId any // 实际ID
Name interface{} // 名称 ProvinceId any // 省份ID
Codes interface{} // 代号 Name any // 名称
CustomName interface{} // 自定义名称 Codes any // 代号
CustomCodes interface{} // 自定义代号 CustomName any // 自定义名称
State interface{} // 状态 CustomCodes any // 自定义代号
DataId interface{} // 原始数据ID State any // 状态
DataId any // 原始数据ID
} }
func NewRegionCityOperator() *RegionCityOperator { func NewRegionCityOperator() *RegionCityOperator {

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils" "github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
@@ -20,10 +21,6 @@ const (
RegionCountryStateDisabled = 0 // 已禁用 RegionCountryStateDisabled = 0 // 已禁用
) )
const (
CountryChinaId = 1
)
var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name var regionCountryIdAndNameCacheMap = map[int64]string{} // country id => name
type RegionCountryDAO dbs.DAO type RegionCountryDAO dbs.DAO
@@ -50,7 +47,7 @@ func init() {
// EnableRegionCountry 启用条目 // EnableRegionCountry 启用条目
func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error { func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionCountryStateEnabled). Set("state", RegionCountryStateEnabled).
Update() Update()
return err return err
@@ -59,7 +56,7 @@ func (this *RegionCountryDAO) EnableRegionCountry(tx *dbs.Tx, id uint32) error {
// DisableRegionCountry 禁用条目 // DisableRegionCountry 禁用条目
func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error { func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionCountryStateDisabled). Set("state", RegionCountryStateDisabled).
Update() Update()
return err return err
@@ -68,7 +65,7 @@ func (this *RegionCountryDAO) DisableRegionCountry(tx *dbs.Tx, id int64) error {
// FindEnabledRegionCountry 查找启用中的条目 // FindEnabledRegionCountry 查找启用中的条目
func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) { func (this *RegionCountryDAO) FindEnabledRegionCountry(tx *dbs.Tx, id int64) (*RegionCountry, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Attr("state", RegionCountryStateEnabled). Attr("state", RegionCountryStateEnabled).
Find() Find()
if result == nil { if result == nil {
@@ -88,7 +85,7 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
} }
name, err := this.Query(tx). name, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Result("name"). Result("name").
FindStringCol("") FindStringCol("")
if err != nil { if err != nil {
@@ -105,7 +102,7 @@ func (this *RegionCountryDAO) FindRegionCountryName(tx *dbs.Tx, id int64) (strin
func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) { func (this *RegionCountryDAO) FindCountryIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx). return this.Query(tx).
Attr("dataId", dataId). Attr("dataId", dataId).
ResultPk(). Result(RegionCountryField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -115,7 +112,7 @@ func (this *RegionCountryDAO) FindCountryIdWithName(tx *dbs.Tx, countryName stri
Where("(name=:countryName OR JSON_CONTAINS(codes, :countryNameJSON) OR customName=:countryName OR JSON_CONTAINS(customCodes, :countryNameJSON))"). Where("(name=:countryName OR JSON_CONTAINS(codes, :countryNameJSON) OR customName=:countryName OR JSON_CONTAINS(customCodes, :countryNameJSON))").
Param("countryName", countryName). Param("countryName", countryName).
Param("countryNameJSON", strconv.Quote(countryName)). // 查询的需要是个JSON字符串所以这里加双引号 Param("countryNameJSON", strconv.Quote(countryName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk(). Result(RegionCountryField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -145,16 +142,61 @@ func (this *RegionCountryDAO) CreateCountry(tx *dbs.Tx, name string, dataId stri
if err != nil { if err != nil {
return 0, err return 0, err
} }
return types.Int64(op.Id), nil var countryId = types.Int64(op.Id)
err = this.Query(tx).
Pk(countryId).
Set(RegionCountryField_ValueId, countryId).
UpdateQuickly()
if err != nil {
return 0, err
}
return countryId, nil
} }
// FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家并按拼音排序 // FindAllEnabledCountriesOrderByPinyin 查找所有可用的国家并按拼音排序
func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) { func (this *RegionCountryDAO) FindAllEnabledCountriesOrderByPinyin(tx *dbs.Tx) (result []*RegionCountry, err error) {
_, err = this.Query(tx). ones, err := this.Query(tx).
State(RegionCountryStateEnabled). State(RegionCountryStateEnabled).
Slice(&result). Asc("JSON_EXTRACT(pinyin, '$[0]')").
Asc("pinyin").
FindAll() FindAll()
if err != nil {
return nil, err
}
// resort China special regions
var chinaRegionMap = map[int64]*RegionCountry{} // countryId => *RegionCountry
for _, one := range ones {
var country = one.(*RegionCountry)
var valueId = int64(country.ValueId)
if regionconfigs.CheckRegionIsInGreaterChina(valueId) {
chinaRegionMap[valueId] = country
}
}
for _, one := range ones {
var country = one.(*RegionCountry)
var valueId = int64(country.ValueId)
if valueId == regionconfigs.RegionChinaId {
result = append(result, country)
// add hk, tw, mo, mainland ...
for _, subRegionId := range regionconfigs.FindAllGreaterChinaSubRegionIds() {
subRegion, ok := chinaRegionMap[subRegionId]
if ok {
result = append(result, subRegion)
}
}
continue
}
if regionconfigs.CheckRegionIsInGreaterChina(valueId) {
continue
}
result = append(result, country)
}
return return
} }
@@ -163,7 +205,7 @@ func (this *RegionCountryDAO) FindAllCountries(tx *dbs.Tx) (result []*RegionCoun
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionCountryStateEnabled). State(RegionCountryStateEnabled).
Slice(&result). Slice(&result).
AscPk(). Asc(RegionCountryField_ValueId).
FindAll() FindAll()
return return
} }
@@ -185,7 +227,7 @@ func (this *RegionCountryDAO) UpdateCountryCustom(tx *dbs.Tx, countryId int64, c
}() }()
return this.Query(tx). return this.Query(tx).
Pk(countryId). Attr("valueId", countryId).
Set("customName", customName). Set("customName", customName).
Set("customCodes", customCodesJSON). Set("customCodes", customCodesJSON).
UpdateQuickly() UpdateQuickly()

View File

@@ -2,9 +2,25 @@ package regions
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
RegionCountryField_Id dbs.FieldName = "id" // ID
RegionCountryField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionCountryField_ValueCode dbs.FieldName = "valueCode" // 值代号
RegionCountryField_Name dbs.FieldName = "name" // 名称
RegionCountryField_Codes dbs.FieldName = "codes" // 代号
RegionCountryField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionCountryField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionCountryField_State dbs.FieldName = "state" // 状态
RegionCountryField_DataId dbs.FieldName = "dataId" // 原始数据ID
RegionCountryField_Pinyin dbs.FieldName = "pinyin" // 拼音
RegionCountryField_IsCommon dbs.FieldName = "isCommon" // 是否常用
)
// RegionCountry 区域-国家/地区 // RegionCountry 区域-国家/地区
type RegionCountry struct { type RegionCountry struct {
Id uint32 `field:"id"` // ID Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
ValueCode string `field:"valueCode"` // 值代号
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
CustomName string `field:"customName"` // 自定义名称 CustomName string `field:"customName"` // 自定义名称
@@ -12,17 +28,21 @@ type RegionCountry struct {
State uint8 `field:"state"` // 状态 State uint8 `field:"state"` // 状态
DataId string `field:"dataId"` // 原始数据ID DataId string `field:"dataId"` // 原始数据ID
Pinyin dbs.JSON `field:"pinyin"` // 拼音 Pinyin dbs.JSON `field:"pinyin"` // 拼音
IsCommon bool `field:"isCommon"` // 是否常用
} }
type RegionCountryOperator struct { type RegionCountryOperator struct {
Id interface{} // ID Id any // ID
Name interface{} // 名称 ValueId any // 实际ID
Codes interface{} // 代号 ValueCode any // 代号
CustomName interface{} // 自定义名称 Name any // 名称
CustomCodes interface{} // 自定义代号 Codes any // 代号
State interface{} // 状态 CustomName any // 自定义名称
DataId interface{} // 原始数据ID CustomCodes any // 自定义代号
Pinyin interface{} // 拼音 State any // 状态
DataId any // 原始数据ID
Pinyin any // 拼音
IsCommon any // 是否常用
} }
func NewRegionCountryOperator() *RegionCountryOperator { func NewRegionCountryOperator() *RegionCountryOperator {

View File

@@ -41,7 +41,7 @@ func init() {
// EnableRegionProvider 启用条目 // EnableRegionProvider 启用条目
func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error { func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionProviderStateEnabled). Set("state", RegionProviderStateEnabled).
Update() Update()
return err return err
@@ -50,7 +50,7 @@ func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error
// DisableRegionProvider 禁用条目 // DisableRegionProvider 禁用条目
func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) error { func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionProviderStateDisabled). Set("state", RegionProviderStateDisabled).
Update() Update()
return err return err
@@ -59,7 +59,7 @@ func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) erro
// FindEnabledRegionProvider 查找启用中的条目 // FindEnabledRegionProvider 查找启用中的条目
func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (*RegionProvider, error) { func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (*RegionProvider, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Attr("state", RegionProviderStateEnabled). Attr("state", RegionProviderStateEnabled).
Find() Find()
if result == nil { if result == nil {
@@ -71,7 +71,7 @@ func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (
// FindRegionProviderName 根据主键查找名称 // FindRegionProviderName 根据主键查找名称
func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (string, error) { func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx). return this.Query(tx).
Pk(id). Attr("valueId", id).
Result("name"). Result("name").
FindStringCol("") FindStringCol("")
} }
@@ -82,7 +82,7 @@ func (this *RegionProviderDAO) FindProviderIdWithName(tx *dbs.Tx, providerName s
Where("(name=:providerName OR customName=:providerName OR JSON_CONTAINS(codes, :providerNameJSON) OR JSON_CONTAINS(customCodes, :providerNameJSON))"). Where("(name=:providerName OR customName=:providerName OR JSON_CONTAINS(codes, :providerNameJSON) OR JSON_CONTAINS(customCodes, :providerNameJSON))").
Param("providerName", providerName). Param("providerName", providerName).
Param("providerNameJSON", strconv.Quote(providerName)). // 查询的需要是个JSON字符串所以这里加双引号 Param("providerNameJSON", strconv.Quote(providerName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk(). Result(RegionProviderField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -96,7 +96,20 @@ func (this *RegionProviderDAO) CreateProvider(tx *dbs.Tx, name string) (int64, e
return 0, err return 0, err
} }
op.Codes = codesJSON op.Codes = codesJSON
return this.SaveInt64(tx, op) providerId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.Query(tx).
Pk(providerId).
Set(RegionProviderField_ValueId, providerId).
UpdateQuickly()
if err != nil {
return 0, err
}
return providerId, nil
} }
// FindAllEnabledProviders 查找所有服务商 // FindAllEnabledProviders 查找所有服务商
@@ -119,7 +132,7 @@ func (this *RegionProviderDAO) UpdateProviderCustom(tx *dbs.Tx, providerId int64
} }
return this.Query(tx). return this.Query(tx).
Pk(providerId). Attr("valueId", providerId).
Set("customName", customName). Set("customName", customName).
Set("customCodes", customCodesJSON). Set("customCodes", customCodesJSON).
UpdateQuickly() UpdateQuickly()

View File

@@ -2,9 +2,20 @@ package regions
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
RegionProviderField_Id dbs.FieldName = "id" // ID
RegionProviderField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionProviderField_Name dbs.FieldName = "name" // 名称
RegionProviderField_Codes dbs.FieldName = "codes" // 代号
RegionProviderField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionProviderField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionProviderField_State dbs.FieldName = "state" // 状态
)
// RegionProvider 区域-运营商 // RegionProvider 区域-运营商
type RegionProvider struct { type RegionProvider struct {
Id uint32 `field:"id"` // ID Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
CustomName string `field:"customName"` // 自定义名称 CustomName string `field:"customName"` // 自定义名称
@@ -13,12 +24,13 @@ type RegionProvider struct {
} }
type RegionProviderOperator struct { type RegionProviderOperator struct {
Id interface{} // ID Id any // ID
Name interface{} // 名称 ValueId any // 实际ID
Codes interface{} // 代号 Name any // 名称
CustomName interface{} // 自定义名称 Codes any // 代号
CustomCodes interface{} // 自定义代号 CustomName any // 自定义名称
State interface{} // 状态 CustomCodes any // 自定义代号
State any // 状态
} }
func NewRegionProviderOperator() *RegionProviderOperator { func NewRegionProviderOperator() *RegionProviderOperator {

View File

@@ -42,7 +42,7 @@ func init() {
// EnableRegionProvince 启用条目 // EnableRegionProvince 启用条目
func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error { func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionProvinceStateEnabled). Set("state", RegionProvinceStateEnabled).
Update() Update()
return err return err
@@ -51,7 +51,7 @@ func (this *RegionProvinceDAO) EnableRegionProvince(tx *dbs.Tx, id int64) error
// DisableRegionProvince 禁用条目 // DisableRegionProvince 禁用条目
func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error { func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionProvinceStateDisabled). Set("state", RegionProvinceStateDisabled).
Update() Update()
return err return err
@@ -60,7 +60,7 @@ func (this *RegionProvinceDAO) DisableRegionProvince(tx *dbs.Tx, id int64) error
// FindEnabledRegionProvince 查找启用中的条目 // FindEnabledRegionProvince 查找启用中的条目
func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (*RegionProvince, error) { func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (*RegionProvince, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Attr("state", RegionProvinceStateEnabled). Attr("state", RegionProvinceStateEnabled).
Find() Find()
if result == nil { if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionProvinceDAO) FindEnabledRegionProvince(tx *dbs.Tx, id int64) (
// FindRegionProvinceName 根据主键查找名称 // FindRegionProvinceName 根据主键查找名称
func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (string, error) { func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (string, error) {
return this.Query(tx). return this.Query(tx).
Pk(id). Attr("valueId", id).
Result("name"). Result("name").
FindStringCol("") FindStringCol("")
} }
@@ -81,7 +81,7 @@ func (this *RegionProvinceDAO) FindRegionProvinceName(tx *dbs.Tx, id int64) (str
func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) { func (this *RegionProvinceDAO) FindProvinceIdWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
return this.Query(tx). return this.Query(tx).
Attr("dataId", dataId). Attr("dataId", dataId).
ResultPk(). Result(RegionProvinceField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -92,7 +92,7 @@ func (this *RegionProvinceDAO) FindProvinceIdWithName(tx *dbs.Tx, countryId int6
Where("(name=:provinceName OR customName=:provinceName OR JSON_CONTAINS(codes, :provinceNameJSON) OR JSON_CONTAINS(customCodes, :provinceNameJSON))"). Where("(name=:provinceName OR customName=:provinceName OR JSON_CONTAINS(codes, :provinceNameJSON) OR JSON_CONTAINS(customCodes, :provinceNameJSON))").
Param("provinceName", provinceName). Param("provinceName", provinceName).
Param("provinceNameJSON", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串所以这里加双引号 Param("provinceNameJSON", strconv.Quote(provinceName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk(). Result(RegionProvinceField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
@@ -104,7 +104,7 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
op.DataId = dataId op.DataId = dataId
op.State = RegionProvinceStateEnabled op.State = RegionProvinceStateEnabled
codes := []string{name} var codes = []string{name}
codesJSON, err := json.Marshal(codes) codesJSON, err := json.Marshal(codes)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -114,7 +114,17 @@ func (this *RegionProvinceDAO) CreateProvince(tx *dbs.Tx, countryId int64, name
if err != nil { if err != nil {
return 0, err return 0, err
} }
return types.Int64(op.Id), nil var provinceId = types.Int64(op.Id)
err = this.Query(tx).
Pk(provinceId).
Set(RegionProvinceField_ValueId, provinceId).
UpdateQuickly()
if err != nil {
return 0, err
}
return provinceId, nil
} }
// FindAllEnabledProvincesWithCountryId 查找某个国家/地区的所有省份 // FindAllEnabledProvincesWithCountryId 查找某个国家/地区的所有省份
@@ -122,7 +132,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionProvinceStateEnabled). State(RegionProvinceStateEnabled).
Attr("countryId", countryId). Attr("countryId", countryId).
AscPk(). Asc(RegionProvinceField_ValueId).
Slice(&result). Slice(&result).
FindAll() FindAll()
return return
@@ -132,7 +142,7 @@ func (this *RegionProvinceDAO) FindAllEnabledProvincesWithCountryId(tx *dbs.Tx,
func (this *RegionProvinceDAO) FindAllEnabledProvinces(tx *dbs.Tx) (result []*RegionProvince, err error) { func (this *RegionProvinceDAO) FindAllEnabledProvinces(tx *dbs.Tx) (result []*RegionProvince, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionProvinceStateEnabled). State(RegionProvinceStateEnabled).
AscPk(). Asc(RegionProvinceField_ValueId).
Slice(&result). Slice(&result).
FindAll() FindAll()
return return
@@ -149,7 +159,7 @@ func (this *RegionProvinceDAO) UpdateProvinceCustom(tx *dbs.Tx, provinceId int64
} }
return this.Query(tx). return this.Query(tx).
Pk(provinceId). Attr("valueId", provinceId).
Set("customName", customName). Set("customName", customName).
Set("customCodes", customCodesJSON). Set("customCodes", customCodesJSON).
UpdateQuickly() UpdateQuickly()

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
RegionProvinceField_Id dbs.FieldName = "id" // ID
RegionProvinceField_ValueId dbs.FieldName = "valueId" // 实际ID
RegionProvinceField_CountryId dbs.FieldName = "countryId" // 国家ID
RegionProvinceField_Name dbs.FieldName = "name" // 名称
RegionProvinceField_Codes dbs.FieldName = "codes" // 代号
RegionProvinceField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionProvinceField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionProvinceField_State dbs.FieldName = "state" // 状态
RegionProvinceField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionProvince 区域-省份 // RegionProvince 区域-省份
type RegionProvince struct { type RegionProvince struct {
Id uint32 `field:"id"` // ID Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 实际ID
CountryId uint32 `field:"countryId"` // 国家ID CountryId uint32 `field:"countryId"` // 国家ID
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionProvince struct {
} }
type RegionProvinceOperator struct { type RegionProvinceOperator struct {
Id interface{} // ID Id any // ID
CountryId interface{} // 国家ID ValueId any // 实际ID
Name interface{} // 名称 CountryId any // 国家ID
Codes interface{} // 代号 Name any // 名称
CustomName interface{} // 自定义名称 Codes any // 代号
CustomCodes interface{} // 自定义代号 CustomName any // 自定义名称
State interface{} // 状态 CustomCodes any // 自定义代号
DataId interface{} // 原始数据ID State any // 状态
DataId any // 原始数据ID
} }
func NewRegionProvinceOperator() *RegionProvinceOperator { func NewRegionProvinceOperator() *RegionProvinceOperator {

View File

@@ -41,7 +41,7 @@ func init() {
// EnableRegionTown 启用条目 // EnableRegionTown 启用条目
func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error { func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionTownStateEnabled). Set("state", RegionTownStateEnabled).
Update() Update()
return err return err
@@ -50,7 +50,7 @@ func (this *RegionTownDAO) EnableRegionTown(tx *dbs.Tx, id uint32) error {
// DisableRegionTown 禁用条目 // DisableRegionTown 禁用条目
func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error { func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Set("state", RegionTownStateDisabled). Set("state", RegionTownStateDisabled).
Update() Update()
return err return err
@@ -59,7 +59,7 @@ func (this *RegionTownDAO) DisableRegionTown(tx *dbs.Tx, id uint32) error {
// FindEnabledRegionTown 查找启用中的区县 // FindEnabledRegionTown 查找启用中的区县
func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionTown, error) { func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionTown, error) {
result, err := this.Query(tx). result, err := this.Query(tx).
Pk(id). Attr("valueId", id).
Attr("state", RegionTownStateEnabled). Attr("state", RegionTownStateEnabled).
Find() Find()
if result == nil { if result == nil {
@@ -72,7 +72,7 @@ func (this *RegionTownDAO) FindEnabledRegionTown(tx *dbs.Tx, id int64) (*RegionT
func (this *RegionTownDAO) FindAllRegionTowns(tx *dbs.Tx) (result []*RegionTown, err error) { func (this *RegionTownDAO) FindAllRegionTowns(tx *dbs.Tx) (result []*RegionTown, err error) {
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionTownStateEnabled). State(RegionTownStateEnabled).
AscPk(). Asc(RegionTownField_ValueId).
Slice(&result). Slice(&result).
FindAll() FindAll()
return return
@@ -83,7 +83,7 @@ func (this *RegionTownDAO) FindAllRegionTownsWithCityId(tx *dbs.Tx, cityId int64
_, err = this.Query(tx). _, err = this.Query(tx).
State(RegionTownStateEnabled). State(RegionTownStateEnabled).
Attr("cityId", cityId). Attr("cityId", cityId).
AscPk(). Asc(RegionTownField_ValueId).
Slice(&result). Slice(&result).
FindAll() FindAll()
return return
@@ -96,14 +96,14 @@ func (this *RegionTownDAO) FindTownIdWithName(tx *dbs.Tx, cityId int64, townName
Where("(name=:townName OR customName=:townName OR JSON_CONTAINS(codes, :townNameJSON) OR JSON_CONTAINS(customCodes, :townNameJSON))"). Where("(name=:townName OR customName=:townName OR JSON_CONTAINS(codes, :townNameJSON) OR JSON_CONTAINS(customCodes, :townNameJSON))").
Param("townName", townName). Param("townName", townName).
Param("townNameJSON", strconv.Quote(townName)). // 查询的需要是个JSON字符串所以这里加双引号 Param("townNameJSON", strconv.Quote(townName)). // 查询的需要是个JSON字符串所以这里加双引号
ResultPk(). Result(RegionTownField_ValueId).
FindInt64Col(0) FindInt64Col(0)
} }
// FindRegionTownName 根据主键查找名称 // FindRegionTownName 根据主键查找名称
func (this *RegionTownDAO) FindRegionTownName(tx *dbs.Tx, id uint32) (string, error) { func (this *RegionTownDAO) FindRegionTownName(tx *dbs.Tx, id uint32) (string, error) {
return this.Query(tx). return this.Query(tx).
Pk(id). Attr("valueId", id).
Result("name"). Result("name").
FindStringCol("") FindStringCol("")
} }
@@ -118,7 +118,7 @@ func (this *RegionTownDAO) UpdateTownCustom(tx *dbs.Tx, townId int64, customName
return err return err
} }
return this.Query(tx). return this.Query(tx).
Pk(townId). Attr("valueId", townId).
Set("customName", customName). Set("customName", customName).
Set("customCodes", customCodesJSON). Set("customCodes", customCodesJSON).
UpdateQuickly() UpdateQuickly()
@@ -176,5 +176,18 @@ func (this *RegionTownDAO) CreateTown(tx *dbs.Tx, cityId int64, townName string)
op.Codes = codes op.Codes = codes
op.State = RegionTownStateEnabled op.State = RegionTownStateEnabled
return this.SaveInt64(tx, op) townId, err := this.SaveInt64(tx, op)
if err != nil {
return 0, err
}
err = this.Query(tx).
Pk(townId).
Set(RegionTownField_ValueId, townId).
UpdateQuickly()
if err != nil {
return 0, err
}
return townId, nil
} }

View File

@@ -2,9 +2,22 @@ package regions
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
RegionTownField_Id dbs.FieldName = "id" // ID
RegionTownField_ValueId dbs.FieldName = "valueId" // 真实ID
RegionTownField_CityId dbs.FieldName = "cityId" // 城市ID
RegionTownField_Name dbs.FieldName = "name" // 名称
RegionTownField_Codes dbs.FieldName = "codes" // 代号
RegionTownField_CustomName dbs.FieldName = "customName" // 自定义名称
RegionTownField_CustomCodes dbs.FieldName = "customCodes" // 自定义代号
RegionTownField_State dbs.FieldName = "state" // 状态
RegionTownField_DataId dbs.FieldName = "dataId" // 原始数据ID
)
// RegionTown 区域-省份 // RegionTown 区域-省份
type RegionTown struct { type RegionTown struct {
Id uint32 `field:"id"` // ID Id1 uint32 `field:"id"` // ID
ValueId uint32 `field:"valueId"` // 真实ID
CityId uint32 `field:"cityId"` // 城市ID CityId uint32 `field:"cityId"` // 城市ID
Name string `field:"name"` // 名称 Name string `field:"name"` // 名称
Codes dbs.JSON `field:"codes"` // 代号 Codes dbs.JSON `field:"codes"` // 代号
@@ -15,14 +28,15 @@ type RegionTown struct {
} }
type RegionTownOperator struct { type RegionTownOperator struct {
Id interface{} // ID Id any // ID
CityId interface{} // 城市ID ValueId any // 真实ID
Name interface{} // 名称 CityId any // 城市ID
Codes interface{} // 代号 Name any // 名称
CustomName interface{} // 自定义名称 Codes any // 代号
CustomCodes interface{} // 自定义代号 CustomName any // 自定义名称
State interface{} // 状态 CustomCodes any // 自定义代号
DataId interface{} // 原始数据ID State any // 状态
DataId any // 原始数据ID
} }
func NewRegionTownOperator() *RegionTownOperator { func NewRegionTownOperator() *RegionTownOperator {

View File

@@ -34,7 +34,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedServerBandwidthStatDAO.Clean(nil) err := SharedServerBandwidthStatDAO.CleanDefaultDays(nil, 100)
if err != nil { if err != nil {
remotelogs.Error("SharedServerBandwidthStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("SharedServerBandwidthStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -745,9 +745,9 @@ func (this *ServerBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, serverId int64, reg
return return
} }
// Clean 清理过期数据 // CleanDays 清理过期数据
func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error { func (this *ServerBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据 var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error { return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Table(table). Table(table).
@@ -757,6 +757,22 @@ func (this *ServerBandwidthStatDAO) Clean(tx *dbs.Tx) error {
}) })
} }
func (this *ServerBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerBandwidthStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerBandwidthStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 100
}
return this.CleanDays(tx, defaultDays)
}
// 批量执行 // 批量执行
func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error { func (this *ServerBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{} var locker = &sync.Mutex{}

View File

@@ -72,11 +72,11 @@ func TestServerBandwidthStatDAO_FindAllServerStatsWithDay(t *testing.T) {
} }
} }
func TestServerBandwidthStatDAO_Clean(t *testing.T) { func TestServerBandwidthStatDAO_CleanDays(t *testing.T) {
var dao = models.NewServerBandwidthStatDAO() var dao = models.NewServerBandwidthStatDAO()
var tx *dbs.Tx var tx *dbs.Tx
var before = time.Now() var before = time.Now()
err := dao.Clean(tx) err := dao.CleanDays(tx, 100)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -16,6 +16,7 @@ import (
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
"regexp" "regexp"
"sort"
"strings" "strings"
"time" "time"
) )
@@ -28,7 +29,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedServerDailyStatDAO.Clean(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单 err := SharedServerDailyStatDAO.CleanDefaultDays(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
if err != nil { if err != nil {
logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error()) logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -513,7 +514,8 @@ func (this *ServerDailyStatDAO) FindStatsWithDay(tx *dbs.Tx, serverId int64, day
Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day", "timeFrom", "MIN(timeTo) AS timeTo"). Result("SUM(bytes) AS bytes", "SUM(cachedBytes) AS cachedBytes", "SUM(countRequests) AS countRequests", "SUM(countCachedRequests) AS countCachedRequests", "SUM(countAttackRequests) AS countAttackRequests", "SUM(attackBytes) AS attackBytes", "day", "timeFrom", "MIN(timeTo) AS timeTo").
Attr("serverId", serverId). Attr("serverId", serverId).
Attr("day", day). Attr("day", day).
Group("day").Group("timeFrom", dbs.QueryOrderDesc) Group("day").
Group("timeFrom")
if len(timeFrom) > 0 { if len(timeFrom) > 0 {
query.Gte("timeFrom", timeFrom) query.Gte("timeFrom", timeFrom)
@@ -530,6 +532,11 @@ func (this *ServerDailyStatDAO) FindStatsWithDay(tx *dbs.Tx, serverId int64, day
return nil, err return nil, err
} }
// sort results
sort.Slice(result, func(i, j int) bool {
return result[i].TimeFrom < result[j].TimeFrom
})
return return
} }
@@ -673,8 +680,8 @@ func (this *ServerDailyStatDAO) compatFindHourlyStats(tx *dbs.Tx, serverId int64
result = append(result, stat) result = append(result, stat)
} else { } else {
result = append(result, &ServerDailyStat{ result = append(result, &ServerDailyStat{
Hour: hour, Hour: hour,
Day: hour[:8], Day: hour[:8],
TimeFrom: hour[8:] + "00", TimeFrom: hour[8:] + "00",
}) })
} }
@@ -742,11 +749,27 @@ func (this *ServerDailyStatDAO) UpdateStatFee(tx *dbs.Tx, statId int64, fee floa
UpdateQuickly() UpdateQuickly()
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *ServerDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *ServerDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("day", day). Lt("day", day).
Delete() Delete()
return err return err
} }
func (this *ServerDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 60
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -140,6 +140,6 @@ func TestServerDailyStatDAO_FindStatsWithDay(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
for _, stat := range stats { for _, stat := range stats {
t.Log(stat.TimeFrom, stat.TimeTo, stat.Bytes) t.Log(stat.Day, stat.TimeFrom, stat.TimeTo, stat.Bytes)
} }
} }

View File

@@ -903,6 +903,22 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), bandwidthBytes, 0)") query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), bandwidthBytes, 0)")
query.Param("times", strings.Join(times, ",")) query.Param("times", strings.Join(times, ","))
query.DescPk() query.DescPk()
case "requestsAsc":
query.Asc("IF(FIND_IN_SET(bandwidthTime, :times), countRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "requestsDesc":
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), countRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "attackRequestsAsc":
query.Asc("IF(FIND_IN_SET(bandwidthTime, :times), countAttackRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
case "attackRequestsDesc":
query.Desc("IF(FIND_IN_SET(bandwidthTime, :times), countAttackRequests, 0)")
query.Param("times", strings.Join(times, ","))
query.DescPk()
default: default:
query.DescPk() query.DescPk()
} }
@@ -913,6 +929,8 @@ func (this *ServerDAO) ListEnabledServersMatch(tx *dbs.Tx, offset int64, size in
for _, server := range result { for _, server := range result {
if len(server.BandwidthTime) > 0 && !lists.ContainsString(times, server.BandwidthTime) { if len(server.BandwidthTime) > 0 && !lists.ContainsString(times, server.BandwidthTime) {
server.BandwidthBytes = 0 server.BandwidthBytes = 0
server.CountRequests = 0
server.CountAttackRequests = 0
} }
} }
@@ -2737,7 +2755,7 @@ func (this *ServerDAO) FindUserServerClusterIds(tx *dbs.Tx, userId int64) ([]int
// UpdateServerBandwidth 更新服务带宽 // UpdateServerBandwidth 更新服务带宽
// fullTime YYYYMMDDHHII // fullTime YYYYMMDDHHII
func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64) error { func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTime string, bandwidthBytes int64, countRequests int64, countAttackRequests int64) error {
if serverId <= 0 { if serverId <= 0 {
return nil return nil
} }
@@ -2758,13 +2776,19 @@ func (this *ServerDAO) UpdateServerBandwidth(tx *dbs.Tx, serverId int64, fullTim
Pk(serverId). Pk(serverId).
Set("bandwidthTime", fullTime). Set("bandwidthTime", fullTime).
Set("bandwidthBytes", bandwidthBytes). Set("bandwidthBytes", bandwidthBytes).
Set("countRequests", countRequests).
Set("countAttackRequests", countAttackRequests).
UpdateQuickly() UpdateQuickly()
} else { } else {
return this.Query(tx). return this.Query(tx).
Pk(serverId). Pk(serverId).
Set("bandwidthTime", fullTime). Set("bandwidthTime", fullTime).
Set("bandwidthBytes", dbs.SQL("bandwidthBytes+:bytes")). Set("bandwidthBytes", dbs.SQL("bandwidthBytes+:bytes")).
Set("countRequests", dbs.SQL("countRequests+:countRequests")).
Set("countAttackRequests", dbs.SQL("countAttackRequests+:countAttackRequests")).
Param("bytes", bandwidthBytes). Param("bytes", bandwidthBytes).
Param("countRequests", countRequests).
Param("countAttackRequests", countAttackRequests).
UpdateQuickly() UpdateQuickly()
} }
} }

View File

@@ -326,7 +326,7 @@ func TestServerDAO_FindBool(t *testing.T) {
func TestServerDAO_UpdateServerBandwidth(t *testing.T) { func TestServerDAO_UpdateServerBandwidth(t *testing.T) {
var dao = models.NewServerDAO() var dao = models.NewServerDAO()
var tx *dbs.Tx var tx *dbs.Tx
err := dao.UpdateServerBandwidth(tx, 1, timeutil.FormatTime("YmdHi", time.Now().Unix()/300*300), 1024) err := dao.UpdateServerBandwidth(tx, 1, timeutil.FormatTime("YmdHi", time.Now().Unix()/300*300), 1024, 1, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -2,6 +2,57 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
ServerField_Id dbs.FieldName = "id" // ID
ServerField_IsOn dbs.FieldName = "isOn" // 是否启用
ServerField_UserId dbs.FieldName = "userId" // 用户ID
ServerField_AdminId dbs.FieldName = "adminId" // 管理员ID
ServerField_Type dbs.FieldName = "type" // 服务类型
ServerField_Name dbs.FieldName = "name" // 名称
ServerField_Description dbs.FieldName = "description" // 描述
ServerField_PlainServerNames dbs.FieldName = "plainServerNames" // 扁平化域名列表
ServerField_ServerNames dbs.FieldName = "serverNames" // 域名列表
ServerField_AuditingAt dbs.FieldName = "auditingAt" // 审核提交时间
ServerField_AuditingServerNames dbs.FieldName = "auditingServerNames" // 审核中的域名
ServerField_IsAuditing dbs.FieldName = "isAuditing" // 是否正在审核
ServerField_AuditingResult dbs.FieldName = "auditingResult" // 审核结果
ServerField_Http dbs.FieldName = "http" // HTTP配置
ServerField_Https dbs.FieldName = "https" // HTTPS配置
ServerField_Tcp dbs.FieldName = "tcp" // TCP配置
ServerField_Tls dbs.FieldName = "tls" // TLS配置
ServerField_Unix dbs.FieldName = "unix" // Unix配置
ServerField_Udp dbs.FieldName = "udp" // UDP配置
ServerField_WebId dbs.FieldName = "webId" // WEB配置
ServerField_ReverseProxy dbs.FieldName = "reverseProxy" // 反向代理配置
ServerField_GroupIds dbs.FieldName = "groupIds" // 分组ID列表
ServerField_Config dbs.FieldName = "config" // 服务配置,自动生成
ServerField_ConfigMd5 dbs.FieldName = "configMd5" // Md5
ServerField_ClusterId dbs.FieldName = "clusterId" // 集群ID
ServerField_IncludeNodes dbs.FieldName = "includeNodes" // 部署条件
ServerField_ExcludeNodes dbs.FieldName = "excludeNodes" // 节点排除条件
ServerField_Version dbs.FieldName = "version" // 版本号
ServerField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
ServerField_State dbs.FieldName = "state" // 状态
ServerField_DnsName dbs.FieldName = "dnsName" // DNS名称
ServerField_TcpPorts dbs.FieldName = "tcpPorts" // 所包含TCP端口
ServerField_UdpPorts dbs.FieldName = "udpPorts" // 所包含UDP端口
ServerField_SupportCNAME dbs.FieldName = "supportCNAME" // 允许CNAME不在域名名单
ServerField_TrafficLimit dbs.FieldName = "trafficLimit" // 流量限制
ServerField_TrafficDay dbs.FieldName = "trafficDay" // YYYYMMDD
ServerField_TrafficMonth dbs.FieldName = "trafficMonth" // YYYYMM
ServerField_TotalDailyTraffic dbs.FieldName = "totalDailyTraffic" // 日流量
ServerField_TotalMonthlyTraffic dbs.FieldName = "totalMonthlyTraffic" // 月流量
ServerField_TrafficLimitStatus dbs.FieldName = "trafficLimitStatus" // 流量限制状态
ServerField_TotalTraffic dbs.FieldName = "totalTraffic" // 总流量
ServerField_UserPlanId dbs.FieldName = "userPlanId" // 所属套餐ID
ServerField_LastUserPlanId dbs.FieldName = "lastUserPlanId" // 上一次使用的套餐
ServerField_Uam dbs.FieldName = "uam" // UAM设置
ServerField_BandwidthTime dbs.FieldName = "bandwidthTime" // 带宽更新时间YYYYMMDDHHII
ServerField_BandwidthBytes dbs.FieldName = "bandwidthBytes" // 最近带宽峰值
ServerField_CountAttackRequests dbs.FieldName = "countAttackRequests" // 最近攻击请求数
ServerField_CountRequests dbs.FieldName = "countRequests" // 最近总请求数
)
// Server 服务 // Server 服务
type Server struct { type Server struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -50,6 +101,8 @@ type Server struct {
Uam dbs.JSON `field:"uam"` // UAM设置 Uam dbs.JSON `field:"uam"` // UAM设置
BandwidthTime string `field:"bandwidthTime"` // 带宽更新时间YYYYMMDDHHII BandwidthTime string `field:"bandwidthTime"` // 带宽更新时间YYYYMMDDHHII
BandwidthBytes uint64 `field:"bandwidthBytes"` // 最近带宽峰值 BandwidthBytes uint64 `field:"bandwidthBytes"` // 最近带宽峰值
CountAttackRequests uint64 `field:"countAttackRequests"` // 最近攻击请求数
CountRequests uint64 `field:"countRequests"` // 最近总请求数
} }
type ServerOperator struct { type ServerOperator struct {
@@ -99,6 +152,8 @@ type ServerOperator struct {
Uam any // UAM设置 Uam any // UAM设置
BandwidthTime any // 带宽更新时间YYYYMMDDHHII BandwidthTime any // 带宽更新时间YYYYMMDDHHII
BandwidthBytes any // 最近带宽峰值 BandwidthBytes any // 最近带宽峰值
CountAttackRequests any // 最近攻击请求数
CountRequests any // 最近总请求数
} }
func NewServerOperator() *ServerOperator { func NewServerOperator() *ServerOperator {

View File

@@ -1,6 +1,7 @@
package stats package stats
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -22,7 +23,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedNodeClusterTrafficDailyStatDAO.Clean(nil, 30) // 只保留N天 err := SharedNodeClusterTrafficDailyStatDAO.CleanDefaultDays(nil, 30) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("NodeClusterTrafficDailyStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("NodeClusterTrafficDailyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -128,11 +129,27 @@ func (this *NodeClusterTrafficDailyStatDAO) SumDailyStat(tx *dbs.Tx, clusterId i
return one.(*NodeClusterTrafficDailyStat), nil return one.(*NodeClusterTrafficDailyStat), nil
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *NodeClusterTrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *NodeClusterTrafficDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("day", day). Lt("day", day).
Delete() Delete()
return err return err
} }
func (this *NodeClusterTrafficDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := models.SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.NodeClusterTrafficDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.NodeClusterTrafficDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 30
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -1,6 +1,7 @@
package stats package stats
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -22,7 +23,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedNodeTrafficHourlyStatDAO.Clean(nil, 15) // 只保留N天 err := SharedNodeTrafficHourlyStatDAO.CleanDefaultDays(nil, 15) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("NodeTrafficHourlyStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("NodeTrafficHourlyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -197,11 +198,27 @@ func (this *NodeTrafficHourlyStatDAO) FindHourlyStatsWithNodeId(tx *dbs.Tx, role
return result, nil return result, nil
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *NodeTrafficHourlyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *NodeTrafficHourlyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days)) var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("hour", hour). Lt("hour", hour).
Delete() Delete()
return err return err
} }
func (this *NodeTrafficHourlyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := models.SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.NodeTrafficHourlyStat.Clean.Days > 0 {
defaultDays = databaseConfig.NodeTrafficHourlyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 15
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -1,6 +1,7 @@
package stats package stats
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -25,7 +26,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedServerDomainHourlyStatDAO.Clean(nil, 7) // 只保留 N 天 err := SharedServerDomainHourlyStatDAO.CleanDefaultDays(nil, 7) // 只保留 N 天
if err != nil { if err != nil {
remotelogs.Error("ServerDomainHourlyStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("ServerDomainHourlyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -366,8 +367,8 @@ func (this *ServerDomainHourlyStatDAO) FindTopDomainStatsWithServerId(tx *dbs.Tx
return return
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *ServerDomainHourlyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *ServerDomainHourlyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days)) var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days))
for _, table := range this.FindAllPartitionTables() { for _, table := range this.FindAllPartitionTables() {
_, err := this.Query(tx). _, err := this.Query(tx).
@@ -380,3 +381,19 @@ func (this *ServerDomainHourlyStatDAO) Clean(tx *dbs.Tx, days int) error {
} }
return nil return nil
} }
func (this *ServerDomainHourlyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := models.SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.ServerDomainHourlyStat.Clean.Days > 0 {
defaultDays = databaseConfig.ServerDomainHourlyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 7
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -1,6 +1,7 @@
package stats package stats
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -22,7 +23,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedTrafficDailyStatDAO.Clean(nil, 30) // 只保留N天 err := SharedTrafficDailyStatDAO.CleanDefaultDays(nil, 30) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("TrafficDailyStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("TrafficDailyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -124,11 +125,27 @@ func (this *TrafficDailyStatDAO) FindDailyStat(tx *dbs.Tx, day string) (*Traffic
return one.(*TrafficDailyStat), nil return one.(*TrafficDailyStat), nil
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *TrafficDailyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *TrafficDailyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("day", day). Lt("day", day).
Delete() Delete()
return err return err
} }
func (this *TrafficDailyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := models.SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.TrafficDailyStat.Clean.Days > 0 {
defaultDays = databaseConfig.TrafficDailyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 30
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -1,6 +1,7 @@
package stats package stats
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/goman"
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
@@ -22,7 +23,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedTrafficHourlyStatDAO.Clean(nil, 15) // 只保留N天 err := SharedTrafficHourlyStatDAO.CleanDefaultDays(nil, 15) // 只保留N天
if err != nil { if err != nil {
remotelogs.Error("TrafficHourlyStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("TrafficHourlyStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -137,11 +138,27 @@ func (this *TrafficHourlyStatDAO) SumHourlyStats(tx *dbs.Tx, hourFrom string, ho
return one.(*TrafficHourlyStat), nil return one.(*TrafficHourlyStat), nil
} }
// Clean 清理历史数据 // CleanDays 清理历史数据
func (this *TrafficHourlyStatDAO) Clean(tx *dbs.Tx, days int) error { func (this *TrafficHourlyStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days)) var hour = timeutil.Format("Ymd00", time.Now().AddDate(0, 0, -days))
_, err := this.Query(tx). _, err := this.Query(tx).
Lt("hour", hour). Lt("hour", hour).
Delete() Delete()
return err return err
} }
func (this *TrafficHourlyStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := models.SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.TrafficHourlyStat.Clean.Days > 0 {
defaultDays = databaseConfig.TrafficHourlyStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 15
}
return this.CleanDays(tx, defaultDays)
}

View File

@@ -1,16 +1,23 @@
package models package models
import ( import (
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/zero"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"strings"
"time" "time"
) )
type SysLockerDAO dbs.DAO type SysLockerDAO dbs.DAO
// concurrent transactions control
// 考虑到存在多个API节点的可能性容量不能太大也不能使用mutex
var sysLockerConcurrentLimiter = make(chan zero.Zero, 8)
func NewSysLockerDAO() *SysLockerDAO { func NewSysLockerDAO() *SysLockerDAO {
return dbs.NewDAO(&SysLockerDAO{ return dbs.NewDAO(&SysLockerDAO{
DAOObject: dbs.DAOObject{ DAOObject: dbs.DAOObject{
@@ -114,9 +121,20 @@ func (this *SysLockerDAO) Unlock(tx *dbs.Tx, key string) error {
// Increase 增加版本号 // Increase 增加版本号
func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (int64, error) { func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (int64, error) {
// validate key
if strings.Contains(key, "'") {
return 0, errors.New("invalid key '" + key + "'")
}
if tx == nil { if tx == nil {
var result int64 var result int64
var err error var err error
sysLockerConcurrentLimiter <- zero.Zero{} // push
defer func() {
<-sysLockerConcurrentLimiter // pop
}()
err = this.Instance.RunTx(func(tx *dbs.Tx) error { err = this.Instance.RunTx(func(tx *dbs.Tx) error {
result, err = this.Increase(tx, key, defaultValue) result, err = this.Increase(tx, key, defaultValue)
if err != nil { if err != nil {
@@ -126,7 +144,22 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
}) })
return result, err return result, err
} }
err := this.Query(tx).
// combine statements to make increasing faster
colValue, err := tx.FindCol(0, "INSERT INTO `"+this.Table+"` (`key`, `version`) VALUES ('"+key+"', "+types.String(defaultValue)+") ON DUPLICATE KEY UPDATE `version`=`version`+1; SELECT `version` FROM `"+this.Table+"` WHERE `key`='"+key+"'")
if err != nil {
if CheckSQLErrCode(err, 1064 /** syntax error **/) {
// continue to use seperated query
err = nil
} else {
return 0, err
}
} else {
return types.Int64(colValue), nil
}
err = this.Query(tx).
Reuse(false). // no need to prepare statement in every transaction
InsertOrUpdateQuickly(maps.Map{ InsertOrUpdateQuickly(maps.Map{
"key": key, "key": key,
"version": defaultValue, "version": defaultValue,
@@ -137,12 +170,12 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
return 0, err return 0, err
} }
return this.Query(tx). return this.Query(tx).
Reuse(false). // no need to prepare statement in every transaction
Attr("key", key). Attr("key", key).
Result("version"). Result("version").
FindInt64Col(0) FindInt64Col(0)
} }
// 读取当前版本号 // 读取当前版本号
func (this *SysLockerDAO) Read(tx *dbs.Tx, key string) (int64, error) { func (this *SysLockerDAO) Read(tx *dbs.Tx, key string) (int64, error) {
return this.Query(tx). return this.Query(tx).

View File

@@ -3,44 +3,146 @@ package models
import ( import (
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
"sync" "sync"
"testing" "testing"
"time"
) )
func TestSysLockerDAO_Lock(t *testing.T) { func TestSysLockerDAO_Lock(t *testing.T) {
var tx *dbs.Tx var tx *dbs.Tx
isOk, err := SharedSysLockerDAO.Lock(tx, "test", 600) var dao = NewSysLockerDAO()
isOk, err := dao.Lock(tx, "test", 600)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Log(isOk) t.Log(isOk)
if isOk { if isOk {
err = SharedSysLockerDAO.Unlock(tx, "test") err = dao.Unlock(tx, "test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
} }
func TestSysLocker_Increase_SQL(t *testing.T) {
var dao = NewSysLockerDAO()
value, err := dao.Read(nil, "hello")
if err != nil {
t.Fatal(err)
}
t.Log("before:", value)
v, err := dao.Increase(nil, "hello", 0)
if err != nil {
t.Log("err:", err)
return
}
t.Log("after:", v)
}
func TestSysLocker_Increase(t *testing.T) { func TestSysLocker_Increase(t *testing.T) {
count := 100 dbs.NotifyReady()
wg := sync.WaitGroup{}
var count = 1000
var dao = NewSysLockerDAO()
value, err := dao.Read(nil, "hello")
if err != nil {
t.Fatal(err)
}
t.Log("before", value)
var locker = sync.Mutex{}
var allValueMap = map[int64]bool{}
var before = time.Now()
var wg = sync.WaitGroup{}
wg.Add(count) wg.Add(count)
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
go func() { go func(i int) {
defer wg.Done() defer wg.Done()
v, err := NewSysLockerDAO().Increase(nil, "hello", 0)
var key = "hello"
v, err := dao.Increase(nil, key, 0)
if err != nil { if err != nil {
t.Log("err:", err) t.Log("err:", err)
return return
} }
t.Log("v:", v)
}() locker.Lock()
if allValueMap[v] {
t.Log("duplicated:", v)
} else {
allValueMap[v] = true
}
locker.Unlock()
//t.Log("v:", v)
_ = v
}(i)
} }
wg.Wait() wg.Wait()
t.Log("ok")
t.Log("cost:", time.Since(before).Seconds()*1000, "ms")
value, err = dao.Read(nil, "hello")
if err != nil {
t.Fatal(err)
}
t.Log("after", value, "values:", len(allValueMap))
}
func TestSysLocker_Increase_Performance(t *testing.T) {
dbs.NotifyReady()
var count = 1000
var dao = NewSysLockerDAO()
var before = time.Now()
var wg = sync.WaitGroup{}
wg.Add(count)
for i := 0; i < count; i++ {
go func(i int) {
defer wg.Done()
var key = "hello" + types.String(i%10)
v, err := dao.Increase(nil, key, 0)
if err != nil {
t.Log("err:", err)
return
}
//t.Log("v:", v)
_ = v
}(i)
}
wg.Wait()
t.Log("cost:", time.Since(before).Seconds()*1000, "ms")
}
func BenchmarkSysLockerDAO_Increase(b *testing.B) {
var dao = NewSysLockerDAO()
_, _ = dao.Increase(nil, "hello", 0)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, err := dao.Increase(nil, "hello", 0)
if err != nil {
b.Fatal(err)
}
}
})
} }

View File

@@ -262,3 +262,20 @@ func (this *SysSettingDAO) ReadUserRegisterConfig(tx *dbs.Tx) (*userconfigs.User
} }
return config, nil return config, nil
} }
func (this *SysSettingDAO) ReadDatabaseConfig(tx *dbs.Tx) (config *systemconfigs.DatabaseConfig, err error) {
valueJSON, err := this.ReadSetting(tx, systemconfigs.SettingCodeDatabaseConfigSetting)
if err != nil {
return nil, err
}
if len(valueJSON) == 0 {
return systemconfigs.NewDatabaseConfig(), nil
}
config = systemconfigs.NewDatabaseConfig()
err = json.Unmarshal(valueJSON, config)
if err != nil {
return nil, err
}
return config, nil
}

View File

@@ -36,7 +36,7 @@ func init() {
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour) var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
goman.New(func() { goman.New(func() {
for range ticker.C { for range ticker.C {
err := SharedUserBandwidthStatDAO.Clean(nil) err := SharedUserBandwidthStatDAO.CleanDefaultDays(nil, 100)
if err != nil { if err != nil {
remotelogs.Error("SharedUserBandwidthStatDAO", "clean expired data failed: "+err.Error()) remotelogs.Error("SharedUserBandwidthStatDAO", "clean expired data failed: "+err.Error())
} }
@@ -460,9 +460,9 @@ func (this *UserBandwidthStatDAO) SumDailyStat(tx *dbs.Tx, userId int64, regionI
return return
} }
// Clean 清理过期数据 // CleanDays 清理过期数据
func (this *UserBandwidthStatDAO) Clean(tx *dbs.Tx) error { func (this *UserBandwidthStatDAO) CleanDays(tx *dbs.Tx, days int) error {
var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -100)) // 保留大约3个月的数据 var day = timeutil.Format("Ymd", time.Now().AddDate(0, 0, -days)) // 保留大约3个月的数据
return this.runBatch(func(table string, locker *sync.Mutex) error { return this.runBatch(func(table string, locker *sync.Mutex) error {
_, err := this.Query(tx). _, err := this.Query(tx).
Table(table). Table(table).
@@ -472,6 +472,22 @@ func (this *UserBandwidthStatDAO) Clean(tx *dbs.Tx) error {
}) })
} }
func (this *UserBandwidthStatDAO) CleanDefaultDays(tx *dbs.Tx, defaultDays int) error {
databaseConfig, err := SharedSysSettingDAO.ReadDatabaseConfig(tx)
if err != nil {
return err
}
if databaseConfig != nil && databaseConfig.UserBandwidthStat.Clean.Days > 0 {
defaultDays = databaseConfig.UserBandwidthStat.Clean.Days
}
if defaultDays <= 0 {
defaultDays = 100
}
return this.CleanDays(tx, defaultDays)
}
// 批量执行 // 批量执行
func (this *UserBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error { func (this *UserBandwidthStatDAO) runBatch(f func(table string, locker *sync.Mutex) error) error {
var locker = &sync.Mutex{} var locker = &sync.Mutex{}

View File

@@ -57,10 +57,10 @@ func TestUserBandwidthStatDAO_UpdateServerBandwidth(t *testing.T) {
t.Log("ok") t.Log("ok")
} }
func TestUserBandwidthStatDAO_Clean(t *testing.T) { func TestUserBandwidthStatDAO_CleanDays(t *testing.T) {
var dao = models.NewUserBandwidthStatDAO() var dao = models.NewUserBandwidthStatDAO()
var tx *dbs.Tx var tx *dbs.Tx
err := dao.Clean(tx) err := dao.CleanDays(tx, 100)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -2,6 +2,42 @@ package models
import "github.com/iwind/TeaGo/dbs" import "github.com/iwind/TeaGo/dbs"
const (
UserField_Id dbs.FieldName = "id" // ID
UserField_IsOn dbs.FieldName = "isOn" // 是否启用
UserField_Username dbs.FieldName = "username" // 用户名
UserField_Password dbs.FieldName = "password" // 密码
UserField_Fullname dbs.FieldName = "fullname" // 真实姓名
UserField_Mobile dbs.FieldName = "mobile" // 手机号
UserField_VerifiedMobile dbs.FieldName = "verifiedMobile" // 已验证手机号
UserField_Tel dbs.FieldName = "tel" // 联系电话
UserField_Remark dbs.FieldName = "remark" // 备注
UserField_Email dbs.FieldName = "email" // 邮箱地址
UserField_VerifiedEmail dbs.FieldName = "verifiedEmail" // 激活后的邮箱
UserField_EmailIsVerified dbs.FieldName = "emailIsVerified" // 邮箱是否已验证
UserField_AvatarFileId dbs.FieldName = "avatarFileId" // 头像文件ID
UserField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
UserField_Day dbs.FieldName = "day" // YYYYMMDD
UserField_UpdatedAt dbs.FieldName = "updatedAt" // 修改时间
UserField_State dbs.FieldName = "state" // 状态
UserField_Source dbs.FieldName = "source" // 来源
UserField_ClusterId dbs.FieldName = "clusterId" // 集群ID
UserField_Features dbs.FieldName = "features" // 允许操作的特征
UserField_RegisteredIP dbs.FieldName = "registeredIP" // 注册使用的IP
UserField_IsRejected dbs.FieldName = "isRejected" // 是否已拒绝
UserField_RejectReason dbs.FieldName = "rejectReason" // 拒绝理由
UserField_IsVerified dbs.FieldName = "isVerified" // 是否验证通过
UserField_RequirePlans dbs.FieldName = "requirePlans" // 是否需要购买套餐
UserField_Modules dbs.FieldName = "modules" // 用户模块
UserField_PriceType dbs.FieldName = "priceType" // 计费类型traffic|bandwidth
UserField_PricePeriod dbs.FieldName = "pricePeriod" // 结算周期
UserField_ServersEnabled dbs.FieldName = "serversEnabled" // 是否禁用所有服务
UserField_Notification dbs.FieldName = "notification" // 通知设置
UserField_BandwidthAlgo dbs.FieldName = "bandwidthAlgo" // 带宽算法
UserField_BandwidthModifier dbs.FieldName = "bandwidthModifier" // 带宽修正值
UserField_Lang dbs.FieldName = "lang" // 语言代号
)
// User 用户 // User 用户
type User struct { type User struct {
Id uint32 `field:"id"` // ID Id uint32 `field:"id"` // ID
@@ -36,6 +72,7 @@ type User struct {
Notification dbs.JSON `field:"notification"` // 通知设置 Notification dbs.JSON `field:"notification"` // 通知设置
BandwidthAlgo string `field:"bandwidthAlgo"` // 带宽算法 BandwidthAlgo string `field:"bandwidthAlgo"` // 带宽算法
BandwidthModifier float64 `field:"bandwidthModifier"` // 带宽修正值 BandwidthModifier float64 `field:"bandwidthModifier"` // 带宽修正值
Lang string `field:"lang"` // 语言代号
} }
type UserOperator struct { type UserOperator struct {
@@ -71,6 +108,7 @@ type UserOperator struct {
Notification any // 通知设置 Notification any // 通知设置
BandwidthAlgo any // 带宽算法 BandwidthAlgo any // 带宽算法
BandwidthModifier any // 带宽修正值 BandwidthModifier any // 带宽修正值
Lang any // 语言代号
} }
func NewUserOperator() *UserOperator { func NewUserOperator() *UserOperator {

View File

@@ -80,3 +80,12 @@ func CheckSQLDuplicateErr(err error) bool {
} }
return CheckSQLErrCode(err, 1062) return CheckSQLErrCode(err, 1062)
} }
// IsMySQLError Check error is MySQLError
func IsMySQLError(err error) bool {
if err == nil {
return false
}
_, ok := err.(*mysql.MySQLError)
return ok
}

View File

@@ -1,10 +1,18 @@
package dbutils package dbutils
import ( import (
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"net" "net"
"os"
"os/exec"
"regexp"
"strings" "strings"
"time"
) )
// NewQuery 构造Query // NewQuery 构造Query
@@ -127,3 +135,79 @@ func MySQLVersionFrom8() (bool, error) {
} }
return false, nil return false, nil
} }
// FindMySQLPath find out mysqld_safe path from system processes
func FindMySQLPath() string {
psExe, err := executils.LookPath("ps")
if err != nil {
return ""
}
var cmd = executils.NewTimeoutCmd(3*time.Second, psExe, "-ef").
WithStdout().
WithStderr()
err = cmd.Run()
if err != nil {
return ""
}
var reg = regexp.MustCompile(`\s(/\S+/mysqld_safe)\s`)
var matches = reg.FindStringSubmatch(cmd.Stdout())
if len(matches) > 1 {
var path = matches[1]
_, err = os.Stat(path)
if err != nil {
return ""
}
return path
}
return ""
}
// FindMySQLPathAndRemember find out mysqld_safe path then remember it for future usage
func FindMySQLPathAndRemember() {
var path = FindMySQLPath()
if len(path) == 0 {
return
}
var cacheFile = Tea.Root + "/data/mysql-path.cache"
_ = os.WriteFile(cacheFile, []byte(path), 0666) // ignore error
}
// StartLocalMySQL try to start local mysql server
func StartLocalMySQL() {
// possible installed paths
var mysqldSafeFiles = []string{}
// read last path from cache file
var cacheFile = Tea.Root + "/data/mysql-path.cache"
cacheData, err := os.ReadFile(cacheFile)
if err == nil && len(cacheData) > 0 {
mysqldSafeFiles = append(mysqldSafeFiles, string(cacheData))
}
// from $PATH variable
exePath, lookErr := executils.LookPath("mysqld_safe")
if lookErr == nil && len(exePath) > 0 && !lists.ContainsString(mysqldSafeFiles, exePath) {
mysqldSafeFiles = append(mysqldSafeFiles, exePath)
}
// these installed by edge-boot or foolish-mysql
for _, path := range []string{
"/usr/local/mysql/bin/mysqld_safe",
"/usr/local/mysql8/bin/mysqld_safe",
} {
if !lists.ContainsString(mysqldSafeFiles, path) {
mysqldSafeFiles = append(mysqldSafeFiles, path)
}
}
for _, mysqldSafeFile := range mysqldSafeFiles {
_, err := os.Stat(mysqldSafeFile)
if err == nil {
logs.Println("[API_NODE]try to start local mysql server from '" + mysqldSafeFile + "' ...")
var mysqlCmd = exec.Command(mysqldSafeFile)
_ = mysqlCmd.Start()
break
}
}
}

View File

@@ -35,3 +35,11 @@ func TestMySQLVersion(t *testing.T) {
func TestMySQLVersionFrom8(t *testing.T) { func TestMySQLVersionFrom8(t *testing.T) {
t.Log(dbutils.MySQLVersionFrom8()) t.Log(dbutils.MySQLVersionFrom8())
} }
func TestFindMySQLPath(t *testing.T) {
t.Log(dbutils.FindMySQLPath())
}
func TestStartLocalMySQL(t *testing.T) {
dbutils.StartLocalMySQL()
}

View File

@@ -37,8 +37,8 @@ func (this *Unzip) Run() error {
}() }()
for _, file := range reader.File { for _, file := range reader.File {
info := file.FileInfo() var info = file.FileInfo()
target := this.targetDir + "/" + file.Name var target = this.targetDir + "/" + file.Name
// 目录 // 目录
if info.IsDir() { if info.IsDir() {
@@ -62,7 +62,7 @@ func (this *Unzip) Run() error {
} }
// 文件 // 文件
err := func(file *zip.File, target string) error { err = func(file *zip.File, target string) error {
fileReader, err := file.Open() fileReader, err := file.Open()
if err != nil { if err != nil {
return err return err
@@ -71,6 +71,10 @@ func (this *Unzip) Run() error {
_ = fileReader.Close() _ = fileReader.Close()
}() }()
// remove old
_ = os.Remove(target)
// create new
fileWriter, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, file.FileInfo().Mode()) fileWriter, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, file.FileInfo().Mode())
if err != nil { if err != nil {
return err return err

View File

@@ -295,6 +295,9 @@ func (this *APINode) listenRPC(listener net.Listener, tlsConfig *tls.Config) err
func (this *APINode) checkDB() error { func (this *APINode) checkDB() error {
logs.Println("[API_NODE]checking database connection ...") logs.Println("[API_NODE]checking database connection ...")
// lookup mysqld_safe process
go dbutils.FindMySQLPathAndRemember()
db, err := dbs.Default() db, err := dbs.Default()
if err != nil { if err != nil {
return err return err
@@ -311,13 +314,7 @@ func (this *APINode) checkDB() error {
if strings.Contains(err.Error(), "connection refused") { if strings.Contains(err.Error(), "connection refused") {
config, _ := db.Config() config, _ := db.Config()
if config != nil && (strings.Contains(config.Dsn, "tcp(127.0.0.1:") || strings.Contains(config.Dsn, "tcp(localhost:")) && os.Getgid() == 0 /** ROOT 用户 **/ { if config != nil && (strings.Contains(config.Dsn, "tcp(127.0.0.1:") || strings.Contains(config.Dsn, "tcp(localhost:")) && os.Getgid() == 0 /** ROOT 用户 **/ {
var mysqldSafeFile = "/usr/local/mysql/bin/mysqld_safe" dbutils.StartLocalMySQL()
_, err = os.Stat(mysqldSafeFile)
if err == nil {
logs.Println("[API_NODE]try to start local mysql server from '" + mysqldSafeFile + "' ...")
var mysqlCmd = exec.Command(mysqldSafeFile)
_ = mysqlCmd.Start()
}
} }
} }
@@ -835,7 +832,7 @@ func (this *APINode) unaryInterceptor(ctx context.Context, req any, info *grpc.U
if err != nil { if err != nil {
statusErr, ok := status.FromError(err) statusErr, ok := status.FromError(err)
if ok { if ok {
err = status.Error(statusErr.Code(), "'" + info.FullMethod + "()' says: " + err.Error()) err = status.Error(statusErr.Code(), "'"+info.FullMethod+"()' says: "+err.Error())
} else { } else {
err = errors.New("'" + info.FullMethod + "()' says: " + err.Error()) err = errors.New("'" + info.FullMethod + "()' says: " + err.Error())
} }

View File

@@ -283,7 +283,7 @@ func (this *AdminService) FindAllAdminModules(ctx context.Context, req *pb.FindA
return nil, err return nil, err
} }
result := []*pb.AdminModuleList{} var result = []*pb.AdminModuleList{}
for _, admin := range admins { for _, admin := range admins {
modules := []*systemconfigs.AdminModule{} modules := []*systemconfigs.AdminModule{}
if len(admin.Modules) > 0 { if len(admin.Modules) > 0 {
@@ -292,7 +292,7 @@ func (this *AdminService) FindAllAdminModules(ctx context.Context, req *pb.FindA
return nil, err return nil, err
} }
} }
pbModules := []*pb.AdminModule{} var pbModules = []*pb.AdminModule{}
for _, module := range modules { for _, module := range modules {
pbModules = append(pbModules, &pb.AdminModule{ pbModules = append(pbModules, &pb.AdminModule{
AllowAll: module.AllowAll, AllowAll: module.AllowAll,
@@ -301,11 +301,12 @@ func (this *AdminService) FindAllAdminModules(ctx context.Context, req *pb.FindA
}) })
} }
list := &pb.AdminModuleList{ var list = &pb.AdminModuleList{
AdminId: int64(admin.Id), AdminId: int64(admin.Id),
IsSuper: admin.IsSuper, IsSuper: admin.IsSuper,
Fullname: admin.Fullname, Fullname: admin.Fullname,
Theme: admin.Theme, Theme: admin.Theme,
Lang: admin.Lang,
Modules: pbModules, Modules: pbModules,
} }
result = append(result, list) result = append(result, list)

View File

@@ -240,7 +240,7 @@ func (this *APINodeService) FindEnabledAPINode(ctx context.Context, req *pb.Find
// FindCurrentAPINodeVersion 获取当前API节点的版本 // FindCurrentAPINodeVersion 获取当前API节点的版本
func (this *APINodeService) FindCurrentAPINodeVersion(ctx context.Context, req *pb.FindCurrentAPINodeVersionRequest) (*pb.FindCurrentAPINodeVersionResponse, error) { func (this *APINodeService) FindCurrentAPINodeVersion(ctx context.Context, req *pb.FindCurrentAPINodeVersionRequest) (*pb.FindCurrentAPINodeVersionResponse, error) {
_, _, _, err := rpcutils.ValidateRequest(ctx) role, _, _, err := rpcutils.ValidateRequest(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -249,6 +249,7 @@ func (this *APINodeService) FindCurrentAPINodeVersion(ctx context.Context, req *
Version: teaconst.Version, Version: teaconst.Version,
Os: runtime.GOOS, Os: runtime.GOOS,
Arch: runtime.GOARCH, Arch: runtime.GOARCH,
Role: role,
}, nil }, nil
} }

View File

@@ -303,7 +303,24 @@ func (this *DNSDomainService) SyncDNSDomainData(ctx context.Context, req *pb.Syn
if err != nil { if err != nil {
return nil, err return nil, err
} }
return this.syncClusterDNS(req)
var latestVersion = dns.SharedDNSTaskDAO.GenerateVersion()
resp, err := this.syncClusterDNS(req)
if err != nil {
return resp, err
}
// 标记集群所有任务已完成
if req.NodeClusterId > 0 && resp != nil && resp.IsOk {
var tx = this.NullTx()
err = dns.SharedDNSTaskDAO.UpdateClusterDNSTasksDone(tx, req.NodeClusterId, latestVersion)
if err != nil {
return resp, err
}
}
return resp, err
} }
// FindAllDNSDomainRoutes 查看支持的线路 // FindAllDNSDomainRoutes 查看支持的线路

View File

@@ -117,3 +117,19 @@ func (this *DNSTaskService) DeleteDNSTask(ctx context.Context, req *pb.DeleteDNS
} }
return this.Success() return this.Success()
} }
// DeleteAllDNSTasks 删除所有同步任务
func (this *DNSTaskService) DeleteAllDNSTasks(ctx context.Context, req *pb.DeleteAllDNSTasksRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = dns.SharedDNSTaskDAO.DeleteAllDNSTasks(tx)
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -46,7 +46,7 @@ func (this *HTTPCachePolicyService) CreateHTTPCachePolicy(ctx context.Context, r
var tx = this.NullTx() var tx = this.NullTx()
policyId, err := models.SharedHTTPCachePolicyDAO.CreateCachePolicy(tx, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxKeys, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache) policyId, err := models.SharedHTTPCachePolicyDAO.CreateCachePolicy(tx, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -63,7 +63,7 @@ func (this *HTTPCachePolicyService) UpdateHTTPCachePolicy(ctx context.Context, r
var tx = this.NullTx() var tx = this.NullTx()
err = models.SharedHTTPCachePolicyDAO.UpdateCachePolicy(tx, req.HttpCachePolicyId, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxKeys, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache) err = models.SharedHTTPCachePolicyDAO.UpdateCachePolicy(tx, req.HttpCachePolicyId, req.IsOn, req.Name, req.Description, req.CapacityJSON, req.MaxSizeJSON, req.Type, req.OptionsJSON, req.SyncCompressionCache)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -3,8 +3,11 @@ package services
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
) )
@@ -22,6 +25,34 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
var tx = this.NullTx() var tx = this.NullTx()
// validate
const maxURLLength = 512
const maxBodyLength = 32 * 1024
switch req.BodyType {
case shared.BodyTypeURL:
if len(req.Url) > maxURLLength {
return nil, errors.New("'url' too long")
}
if !regexputils.HTTPProtocol.MatchString(req.Url) {
return nil, errors.New("invalid 'url' format")
}
if len(req.Body) > maxBodyLength { // we keep short body for user experience
req.Body = ""
}
case shared.BodyTypeHTML:
if len(req.Body) > maxBodyLength {
return nil, errors.New("'body' too long")
}
if len(req.Url) > maxURLLength { // we keep short url for user experience
req.Url = ""
}
default:
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
}
pageId, err := models.SharedHTTPPageDAO.CreatePage(tx, userId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus)) pageId, err := models.SharedHTTPPageDAO.CreatePage(tx, userId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -46,6 +77,34 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
} }
} }
// validate
const maxURLLength = 512
const maxBodyLength = 32 * 1024
switch req.BodyType {
case shared.BodyTypeURL:
if len(req.Url) > maxURLLength {
return nil, errors.New("'url' too long")
}
if !regexputils.HTTPProtocol.MatchString(req.Url) {
return nil, errors.New("invalid 'url' format")
}
if len(req.Body) > maxBodyLength { // we keep short body for user experience
req.Body = ""
}
case shared.BodyTypeHTML:
if len(req.Body) > maxBodyLength {
return nil, errors.New("'body' too long")
}
if len(req.Url) > maxURLLength { // we keep short url for user experience
req.Url = ""
}
default:
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
}
err = models.SharedHTTPPageDAO.UpdatePage(tx, req.HttpPageId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus)) err = models.SharedHTTPPageDAO.UpdatePage(tx, req.HttpPageId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -15,14 +15,14 @@ type HTTPRewriteRuleService struct {
// CreateHTTPRewriteRule 创建重写规则 // CreateHTTPRewriteRule 创建重写规则
func (this *HTTPRewriteRuleService) CreateHTTPRewriteRule(ctx context.Context, req *pb.CreateHTTPRewriteRuleRequest) (*pb.CreateHTTPRewriteRuleResponse, error) { func (this *HTTPRewriteRuleService) CreateHTTPRewriteRule(ctx context.Context, req *pb.CreateHTTPRewriteRuleRequest) (*pb.CreateHTTPRewriteRuleResponse, error) {
// 校验请求 // 校验请求
_, err := this.ValidateAdmin(ctx) _, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var tx = this.NullTx() var tx = this.NullTx()
rewriteRuleId, err := models.SharedHTTPRewriteRuleDAO.CreateRewriteRule(tx, req.Pattern, req.Replace, req.Mode, types.Int(req.RedirectStatus), req.IsBreak, req.ProxyHost, req.WithQuery, req.IsOn, req.CondsJSON) rewriteRuleId, err := models.SharedHTTPRewriteRuleDAO.CreateRewriteRule(tx, userId, req.Pattern, req.Replace, req.Mode, types.Int(req.RedirectStatus), req.IsBreak, req.ProxyHost, req.WithQuery, req.IsOn, req.CondsJSON)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -33,12 +33,18 @@ func (this *HTTPRewriteRuleService) CreateHTTPRewriteRule(ctx context.Context, r
// UpdateHTTPRewriteRule 修改重写规则 // UpdateHTTPRewriteRule 修改重写规则
func (this *HTTPRewriteRuleService) UpdateHTTPRewriteRule(ctx context.Context, req *pb.UpdateHTTPRewriteRuleRequest) (*pb.RPCSuccess, error) { func (this *HTTPRewriteRuleService) UpdateHTTPRewriteRule(ctx context.Context, req *pb.UpdateHTTPRewriteRuleRequest) (*pb.RPCSuccess, error) {
// 校验请求 // 校验请求
_, err := this.ValidateAdmin(ctx) _, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var tx = this.NullTx() var tx = this.NullTx()
if userId > 0 {
err = models.SharedHTTPRewriteRuleDAO.CheckUserRewriteRule(tx, userId, req.RewriteRuleId)
if err != nil {
return nil, err
}
}
err = models.SharedHTTPRewriteRuleDAO.UpdateRewriteRule(tx, req.RewriteRuleId, req.Pattern, req.Replace, req.Mode, types.Int(req.RedirectStatus), req.IsBreak, req.ProxyHost, req.WithQuery, req.IsOn, req.CondsJSON) err = models.SharedHTTPRewriteRuleDAO.UpdateRewriteRule(tx, req.RewriteRuleId, req.Pattern, req.Replace, req.Mode, types.Int(req.RedirectStatus), req.IsBreak, req.ProxyHost, req.WithQuery, req.IsOn, req.CondsJSON)
if err != nil { if err != nil {

View File

@@ -5,8 +5,10 @@ import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/dbs"
) )
@@ -109,6 +111,8 @@ func (this *HTTPWebService) UpdateHTTPWeb(ctx context.Context, req *pb.UpdateHTT
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.RootJSON = []byte("{}") // 为了安全
} }
var tx = this.NullTx() var tx = this.NullTx()
@@ -139,7 +143,60 @@ func (this *HTTPWebService) UpdateHTTPWebCompression(ctx context.Context, req *p
var tx = this.NullTx() var tx = this.NullTx()
err = models.SharedHTTPWebDAO.UpdateWebCompression(tx, req.HttpWebId, req.CompressionJSON) if len(req.CompressionJSON) == 0 {
return nil, errors.New("'compressionJSON' should not be empty")
}
var compressionConfig = &serverconfigs.HTTPCompressionConfig{}
err = json.Unmarshal(req.CompressionJSON, compressionConfig)
if err != nil {
return nil, err
}
err = compressionConfig.Init()
if err != nil {
return nil, err
}
err = models.SharedHTTPWebDAO.UpdateWebCompression(tx, req.HttpWebId, compressionConfig)
if err != nil {
return nil, err
}
return this.Success()
}
// UpdateHTTPWebOptimization 修改页面优化配置
func (this *HTTPWebService) UpdateHTTPWebOptimization(ctx context.Context, req *pb.UpdateHTTPWebOptimizationRequest) (*pb.RPCSuccess, error) {
// 校验请求
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if userId > 0 {
// 检查用户权限
err = models.SharedHTTPWebDAO.CheckUserWeb(nil, userId, req.HttpWebId)
if err != nil {
return nil, err
}
}
var tx = this.NullTx()
if len(req.OptimizationJSON) == 0 {
return nil, errors.New("invalid 'optimizationJSON'")
}
var optimizationConfig = serverconfigs.NewHTTPPageOptimizationConfig()
err = json.Unmarshal(req.OptimizationJSON, optimizationConfig)
if err != nil {
return nil, err
}
err = optimizationConfig.Init()
if err != nil {
return nil, err
}
err = models.SharedHTTPWebDAO.UpdateWebOptimization(tx, req.HttpWebId, optimizationConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -292,8 +349,53 @@ func (this *HTTPWebService) UpdateHTTPWebShutdown(ctx context.Context, req *pb.U
} }
var tx = this.NullTx() var tx = this.NullTx()
var newShutdownJSON = req.ShutdownJSON
if len(req.ShutdownJSON) > 0 {
const maxURLLength = 512
const maxBodyLength = 32 * 1024
err = models.SharedHTTPWebDAO.UpdateWebShutdown(tx, req.HttpWebId, req.ShutdownJSON) var shutdownConfig = &serverconfigs.HTTPShutdownConfig{}
err = json.Unmarshal(req.ShutdownJSON, shutdownConfig)
if err != nil {
return nil, err
}
err = shutdownConfig.Init()
if err != nil {
return nil, errors.New("validate config failed: " + err.Error())
}
switch shutdownConfig.BodyType {
case shared.BodyTypeURL:
if len(shutdownConfig.URL) > maxURLLength {
return nil, errors.New("'url' too long")
}
if !regexputils.HTTPProtocol.MatchString(shutdownConfig.URL) {
return nil, errors.New("invalid 'url' format")
}
if len(shutdownConfig.Body) > maxBodyLength { // we keep short body for user experience
shutdownConfig.Body = ""
}
case shared.BodyTypeHTML:
if len(shutdownConfig.Body) > maxBodyLength {
return nil, errors.New("'body' too long")
}
if len(shutdownConfig.URL) > maxURLLength { // we keep short url for user experience
shutdownConfig.URL = ""
}
default:
return nil, errors.New("invalid 'bodyType': " + shutdownConfig.BodyType)
}
newShutdownJSON, err = json.Marshal(shutdownConfig)
if err != nil {
return nil, err
}
}
err = models.SharedHTTPWebDAO.UpdateWebShutdown(tx, req.HttpWebId, newShutdownJSON)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -319,14 +421,23 @@ func (this *HTTPWebService) UpdateHTTPWebPages(ctx context.Context, req *pb.Upda
var tx = this.NullTx() var tx = this.NullTx()
// 检查配置 // 检查配置
var pages = []*serverconfigs.HTTPPageConfig{}
err = json.Unmarshal(req.PagesJSON, &pages)
if err != nil {
return nil, errors.New("decode 'pages' failed: " + err.Error())
}
var newPages = []*serverconfigs.HTTPPageConfig{} var newPages = []*serverconfigs.HTTPPageConfig{}
for _, page := range pages { if len(req.PagesJSON) > 0 {
newPages = append(newPages, &serverconfigs.HTTPPageConfig{Id: page.Id}) var pages = []*serverconfigs.HTTPPageConfig{}
err = json.Unmarshal(req.PagesJSON, &pages)
for _, page := range pages {
err = page.Init()
if err != nil {
return nil, errors.New("validate page failed: " + err.Error())
}
// reset not needed fields, keep "id" reference only
page.URL = ""
page.Body = ""
newPages = append(newPages, &serverconfigs.HTTPPageConfig{Id: page.Id})
}
} }
newPagesJSON, err := json.Marshal(newPages) newPagesJSON, err := json.Marshal(newPages)
if err != nil { if err != nil {

View File

@@ -309,7 +309,7 @@ func (this *IPLibraryFileService) CheckCountriesWithIPLibraryFileId(ctx context.
} }
for _, similarCountry := range similarCountries { for _, similarCountry := range similarCountries {
pbMissingCountry.SimilarCountries = append(pbMissingCountry.SimilarCountries, &pb.RegionCountry{ pbMissingCountry.SimilarCountries = append(pbMissingCountry.SimilarCountries, &pb.RegionCountry{
Id: int64(similarCountry.Id), Id: int64(similarCountry.ValueId),
Name: similarCountry.Name, Name: similarCountry.Name,
DisplayName: similarCountry.DisplayName(), DisplayName: similarCountry.DisplayName(),
}) })
@@ -391,7 +391,7 @@ func (this *IPLibraryFileService) CheckProvincesWithIPLibraryFileId(ctx context.
for _, similarProvince := range similarProvinces { for _, similarProvince := range similarProvinces {
pbMissingProvince.SimilarProvinces = append(pbMissingProvince.SimilarProvinces, &pb.RegionProvince{ pbMissingProvince.SimilarProvinces = append(pbMissingProvince.SimilarProvinces, &pb.RegionProvince{
Id: int64(similarProvince.Id), Id: int64(similarProvince.ValueId),
Name: similarProvince.Name, Name: similarProvince.Name,
DisplayName: similarProvince.DisplayName(), DisplayName: similarProvince.DisplayName(),
}) })
@@ -482,7 +482,7 @@ func (this *IPLibraryFileService) CheckCitiesWithIPLibraryFileId(ctx context.Con
for _, similarCity := range similarCities { for _, similarCity := range similarCities {
pbMissingCity.SimilarCities = append(pbMissingCity.SimilarCities, &pb.RegionCity{ pbMissingCity.SimilarCities = append(pbMissingCity.SimilarCities, &pb.RegionCity{
Id: int64(similarCity.Id), Id: int64(similarCity.ValueId),
Name: similarCity.Name, Name: similarCity.Name,
DisplayName: similarCity.DisplayName(), DisplayName: similarCity.DisplayName(),
}) })
@@ -597,7 +597,7 @@ func (this *IPLibraryFileService) CheckTownsWithIPLibraryFileId(ctx context.Cont
for _, similarTown := range similarTowns { for _, similarTown := range similarTowns {
pbMissingTown.SimilarTowns = append(pbMissingTown.SimilarTowns, &pb.RegionTown{ pbMissingTown.SimilarTowns = append(pbMissingTown.SimilarTowns, &pb.RegionTown{
Id: int64(similarTown.Id), Id: int64(similarTown.ValueId),
Name: similarTown.Name, Name: similarTown.Name,
DisplayName: similarTown.DisplayName(), DisplayName: similarTown.DisplayName(),
}) })
@@ -654,7 +654,7 @@ func (this *IPLibraryFileService) CheckProvidersWithIPLibraryFileId(ctx context.
} }
for _, similarProvider := range similarProviders { for _, similarProvider := range similarProviders {
pbMissingProvider.SimilarProviders = append(pbMissingProvider.SimilarProviders, &pb.RegionProvider{ pbMissingProvider.SimilarProviders = append(pbMissingProvider.SimilarProviders, &pb.RegionProvider{
Id: int64(similarProvider.Id), Id: int64(similarProvider.ValueId),
Name: similarProvider.Name, Name: similarProvider.Name,
DisplayName: similarProvider.DisplayName(), DisplayName: similarProvider.DisplayName(),
}) })

View File

@@ -2,8 +2,10 @@ package services
import ( import (
"context" "context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/db/models"
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils" rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
) )
@@ -22,7 +24,16 @@ func (this *LogService) CreateLog(ctx context.Context, req *pb.CreateLogRequest)
var tx = this.NullTx() var tx = this.NullTx()
err = models.SharedLogDAO.CreateLog(tx, userType, userId, req.Level, req.Description, req.Action, req.Ip) // i18n
var langMessageArgs = []any{}
if len(req.LangMessageArgsJSON) > 0 {
err = json.Unmarshal(req.LangMessageArgsJSON, &langMessageArgs)
if err != nil {
return nil, err
}
}
err = models.SharedLogDAO.CreateLog(tx, userType, userId, req.Level, req.Description, req.Action, req.Ip, langs.MessageCode(req.LangMessageCode), langMessageArgs)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -2016,7 +2016,7 @@ func (this *NodeService) FindNodeGlobalServerConfig(ctx context.Context, req *pb
} }
} }
if config == nil { if config == nil {
config = serverconfigs.DefaultGlobalServerConfig() config = serverconfigs.NewGlobalServerConfig()
} }
configJSON, err := json.Marshal(config) configJSON, err := json.Marshal(config)

View File

@@ -34,7 +34,7 @@ func (this *NodeClusterService) CreateNodeCluster(ctx context.Context, req *pb.C
} }
// 全局服务配置 // 全局服务配置
var serverGlobalConfig = serverconfigs.DefaultGlobalServerConfig() var serverGlobalConfig = serverconfigs.NewGlobalServerConfig()
if len(req.GlobalServerConfigJSON) > 0 { if len(req.GlobalServerConfigJSON) > 0 {
err = json.Unmarshal(req.GlobalServerConfigJSON, serverGlobalConfig) err = json.Unmarshal(req.GlobalServerConfigJSON, serverGlobalConfig)
if err != nil { if err != nil {
@@ -1130,15 +1130,15 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
} }
// UAM // UAM
var uamPolicy = nodeconfigs.NewUAMPolicy()
if models.IsNotNull(cluster.Uam) { if models.IsNotNull(cluster.Uam) {
var uamPolicy = &nodeconfigs.UAMPolicy{}
err = json.Unmarshal(cluster.Uam, uamPolicy) err = json.Unmarshal(cluster.Uam, uamPolicy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result.UamIsOn = uamPolicy.IsOn result.UamIsOn = uamPolicy.IsOn
} else { } else {
result.UamIsOn = nodeconfigs.DefaultUAMPolicy.IsOn result.UamIsOn = uamPolicy.IsOn
} }
// HTTP CC // HTTP CC
@@ -1292,7 +1292,7 @@ func (this *NodeClusterService) UpdateNodeClusterUAMPolicy(ctx context.Context,
return nil, err return nil, err
} }
var uamPolicy = &nodeconfigs.UAMPolicy{} var uamPolicy = nodeconfigs.NewUAMPolicy()
err = json.Unmarshal(req.UamPolicyJSON, uamPolicy) err = json.Unmarshal(req.UamPolicyJSON, uamPolicy)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1444,7 +1444,7 @@ func (this *NodeClusterService) UpdateNodeClusterGlobalServerConfig(ctx context.
return nil, err return nil, err
} }
var config = serverconfigs.DefaultGlobalServerConfig() var config = serverconfigs.NewGlobalServerConfig()
err = json.Unmarshal(req.GlobalServerConfigJSON, config) err = json.Unmarshal(req.GlobalServerConfigJSON, config)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -216,6 +216,22 @@ func (this *NodeTaskService) DeleteNodeTasks(ctx context.Context, req *pb.Delete
return this.Success() return this.Success()
} }
// DeleteAllNodeTasks 删除所有任务
func (this *NodeTaskService) DeleteAllNodeTasks(ctx context.Context, req *pb.DeleteAllNodeTasksRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = models.SharedNodeTaskDAO.DeleteAllNodeTasks(tx)
if err != nil {
return nil, err
}
return this.Success()
}
// CountDoingNodeTasks 计算正在执行的任务数量 // CountDoingNodeTasks 计算正在执行的任务数量
func (this *NodeTaskService) CountDoingNodeTasks(ctx context.Context, req *pb.CountDoingNodeTasksRequest) (*pb.RPCCountResponse, error) { func (this *NodeTaskService) CountDoingNodeTasks(ctx context.Context, req *pb.CountDoingNodeTasksRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx) _, err := this.ValidateAdmin(ctx)

View File

@@ -84,7 +84,7 @@ func (this *OriginService) CreateOrigin(ctx context.Context, req *pb.CreateOrigi
} }
} }
originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, userId, req.Name, addrMap.AsJSON(), ossConfig, req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host, req.FollowPort) originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, userId, req.Name, addrMap.AsJSON(), ossConfig, req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host, req.FollowPort, req.Http2Enabled)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -166,7 +166,7 @@ func (this *OriginService) UpdateOrigin(ctx context.Context, req *pb.UpdateOrigi
} }
} }
err = models.SharedOriginDAO.UpdateOrigin(tx, req.OriginId, req.Name, addrMap.AsJSON(), ossConfig, req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host, req.FollowPort) err = models.SharedOriginDAO.UpdateOrigin(tx, req.OriginId, req.Name, addrMap.AsJSON(), ossConfig, req.Description, req.Weight, req.IsOn, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, certRef, req.Domains, req.Host, req.FollowPort, req.Http2Enabled)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -204,7 +204,7 @@ func (this *OriginService) FindEnabledOrigin(ctx context.Context, req *pb.FindEn
return nil, err return nil, err
} }
result := &pb.Origin{ return &pb.FindEnabledOriginResponse{Origin: &pb.Origin{
Id: int64(origin.Id), Id: int64(origin.Id),
IsOn: origin.IsOn, IsOn: origin.IsOn,
Name: origin.Name, Name: origin.Name,
@@ -213,10 +213,11 @@ func (this *OriginService) FindEnabledOrigin(ctx context.Context, req *pb.FindEn
Host: addr.Host, Host: addr.Host,
PortRange: addr.PortRange, PortRange: addr.PortRange,
}, },
Description: origin.Description, Description: origin.Description,
Domains: origin.DecodeDomains(), Domains: origin.DecodeDomains(),
} FollowPort: origin.FollowPort,
return &pb.FindEnabledOriginResponse{Origin: result}, nil Http2Enabled: origin.Http2Enabled,
}}, nil
} }
// FindEnabledOriginConfig 查找源站配置 // FindEnabledOriginConfig 查找源站配置

View File

@@ -49,7 +49,7 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
} }
pbProvince = &pb.RegionProvince{ pbProvince = &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.Name, Name: province.Name,
Codes: province.DecodeCodes(), Codes: province.DecodeCodes(),
DisplayName: province.DisplayName(), DisplayName: province.DisplayName(),
@@ -57,7 +57,7 @@ func (this *RegionCityService) FindAllEnabledRegionCities(ctx context.Context, r
} }
pbCities = append(pbCities, &pb.RegionCity{ pbCities = append(pbCities, &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
RegionProvinceId: int64(city.ProvinceId), RegionProvinceId: int64(city.ProvinceId),
@@ -108,7 +108,7 @@ func (this *RegionCityService) FindAllRegionCities(ctx context.Context, req *pb.
} }
pbProvince = &pb.RegionProvince{ pbProvince = &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.Name, Name: province.Name,
Codes: province.DecodeCodes(), Codes: province.DecodeCodes(),
CustomName: province.CustomName, CustomName: province.CustomName,
@@ -118,7 +118,7 @@ func (this *RegionCityService) FindAllRegionCities(ctx context.Context, req *pb.
} }
pbCities = append(pbCities, &pb.RegionCity{ pbCities = append(pbCities, &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
RegionProvinceId: int64(city.ProvinceId), RegionProvinceId: int64(city.ProvinceId),
@@ -155,7 +155,7 @@ func (this *RegionCityService) FindAllRegionCitiesWithRegionProvinceId(ctx conte
var pbProvince = &pb.RegionProvince{Id: provinceId} var pbProvince = &pb.RegionProvince{Id: provinceId}
pbCities = append(pbCities, &pb.RegionCity{ pbCities = append(pbCities, &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
RegionProvinceId: int64(city.ProvinceId), RegionProvinceId: int64(city.ProvinceId),
@@ -192,7 +192,7 @@ func (this *RegionCityService) FindEnabledRegionCity(ctx context.Context, req *p
return &pb.FindEnabledRegionCityResponse{ return &pb.FindEnabledRegionCityResponse{
RegionCity: &pb.RegionCity{ RegionCity: &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
RegionProvinceId: int64(city.ProvinceId), RegionProvinceId: int64(city.ProvinceId),
@@ -223,7 +223,7 @@ func (this *RegionCityService) FindRegionCity(ctx context.Context, req *pb.FindR
return &pb.FindRegionCityResponse{ return &pb.FindRegionCityResponse{
RegionCity: &pb.RegionCity{ RegionCity: &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
RegionProvinceId: int64(city.ProvinceId), RegionProvinceId: int64(city.ProvinceId),

View File

@@ -40,13 +40,14 @@ func (this *RegionCountryService) FindAllEnabledRegionCountries(ctx context.Cont
} }
result = append(result, &pb.RegionCountry{ result = append(result, &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.Name, Name: country.Name,
Codes: country.DecodeCodes(), Codes: country.DecodeCodes(),
Pinyin: pinyinStrings, Pinyin: pinyinStrings,
CustomName: country.CustomName, CustomName: country.CustomName,
CustomCodes: country.DecodeCustomCodes(), CustomCodes: country.DecodeCustomCodes(),
DisplayName: country.DisplayName(), DisplayName: country.DisplayName(),
IsCommon: country.IsCommon,
}) })
} }
return &pb.FindAllEnabledRegionCountriesResponse{ return &pb.FindAllEnabledRegionCountriesResponse{
@@ -74,7 +75,7 @@ func (this *RegionCountryService) FindEnabledRegionCountry(ctx context.Context,
} }
return &pb.FindEnabledRegionCountryResponse{RegionCountry: &pb.RegionCountry{ return &pb.FindEnabledRegionCountryResponse{RegionCountry: &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.Name, Name: country.Name,
Codes: country.DecodeCodes(), Codes: country.DecodeCodes(),
CustomName: country.CustomName, CustomName: country.CustomName,
@@ -110,13 +111,14 @@ func (this *RegionCountryService) FindAllRegionCountries(ctx context.Context, re
} }
result = append(result, &pb.RegionCountry{ result = append(result, &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.Name, Name: country.Name,
Codes: country.DecodeCodes(), Codes: country.DecodeCodes(),
Pinyin: pinyinStrings, Pinyin: pinyinStrings,
CustomName: country.CustomName, CustomName: country.CustomName,
CustomCodes: country.DecodeCustomCodes(), CustomCodes: country.DecodeCustomCodes(),
DisplayName: country.DisplayName(), DisplayName: country.DisplayName(),
IsCommon: country.IsCommon,
}) })
} }
return &pb.FindAllRegionCountriesResponse{ return &pb.FindAllRegionCountriesResponse{
@@ -143,12 +145,13 @@ func (this *RegionCountryService) FindRegionCountry(ctx context.Context, req *pb
} }
return &pb.FindRegionCountryResponse{RegionCountry: &pb.RegionCountry{ return &pb.FindRegionCountryResponse{RegionCountry: &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.Name, Name: country.Name,
Codes: country.DecodeCodes(), Codes: country.DecodeCodes(),
CustomName: country.CustomName, CustomName: country.CustomName,
CustomCodes: country.DecodeCustomCodes(), CustomCodes: country.DecodeCustomCodes(),
DisplayName: country.DisplayName(), DisplayName: country.DisplayName(),
IsCommon: country.IsCommon,
}}, nil }}, nil
} }

View File

@@ -30,7 +30,7 @@ func (this *RegionProviderService) FindAllEnabledRegionProviders(ctx context.Con
var pbProviders = []*pb.RegionProvider{} var pbProviders = []*pb.RegionProvider{}
for _, provider := range providers { for _, provider := range providers {
pbProviders = append(pbProviders, &pb.RegionProvider{ pbProviders = append(pbProviders, &pb.RegionProvider{
Id: int64(provider.Id), Id: int64(provider.ValueId),
Name: provider.Name, Name: provider.Name,
Codes: provider.DecodeCodes(), Codes: provider.DecodeCodes(),
CustomName: provider.CustomName, CustomName: provider.CustomName,
@@ -65,7 +65,7 @@ func (this *RegionProviderService) FindEnabledRegionProvider(ctx context.Context
return &pb.FindEnabledRegionProviderResponse{ return &pb.FindEnabledRegionProviderResponse{
RegionProvider: &pb.RegionProvider{ RegionProvider: &pb.RegionProvider{
Id: int64(provider.Id), Id: int64(provider.ValueId),
Name: provider.Name, Name: provider.Name,
Codes: provider.DecodeCodes(), Codes: provider.DecodeCodes(),
CustomName: provider.CustomName, CustomName: provider.CustomName,
@@ -91,7 +91,7 @@ func (this *RegionProviderService) FindAllRegionProviders(ctx context.Context, r
var pbProviders = []*pb.RegionProvider{} var pbProviders = []*pb.RegionProvider{}
for _, provider := range providers { for _, provider := range providers {
pbProviders = append(pbProviders, &pb.RegionProvider{ pbProviders = append(pbProviders, &pb.RegionProvider{
Id: int64(provider.Id), Id: int64(provider.ValueId),
Name: provider.Name, Name: provider.Name,
Codes: provider.DecodeCodes(), Codes: provider.DecodeCodes(),
CustomName: provider.CustomName, CustomName: provider.CustomName,
@@ -125,7 +125,7 @@ func (this *RegionProviderService) FindRegionProvider(ctx context.Context, req *
return &pb.FindRegionProviderResponse{ return &pb.FindRegionProviderResponse{
RegionProvider: &pb.RegionProvider{ RegionProvider: &pb.RegionProvider{
Id: int64(provider.Id), Id: int64(provider.ValueId),
Name: provider.Name, Name: provider.Name,
Codes: provider.DecodeCodes(), Codes: provider.DecodeCodes(),
CustomName: provider.CustomName, CustomName: provider.CustomName,

View File

@@ -29,7 +29,7 @@ func (this *RegionProvinceService) FindAllEnabledRegionProvincesWithCountryId(ct
result := []*pb.RegionProvince{} result := []*pb.RegionProvince{}
for _, province := range provinces { for _, province := range provinces {
result = append(result, &pb.RegionProvince{ result = append(result, &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.Name, Name: province.Name,
Codes: province.DecodeCodes(), Codes: province.DecodeCodes(),
CustomName: province.CustomName, CustomName: province.CustomName,
@@ -64,7 +64,7 @@ func (this *RegionProvinceService) FindEnabledRegionProvince(ctx context.Context
return &pb.FindEnabledRegionProvinceResponse{ return &pb.FindEnabledRegionProvinceResponse{
RegionProvince: &pb.RegionProvince{ RegionProvince: &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.Name, Name: province.Name,
Codes: province.DecodeCodes(), Codes: province.DecodeCodes(),
CustomName: province.CustomName, CustomName: province.CustomName,
@@ -91,7 +91,7 @@ func (this *RegionProvinceService) FindAllRegionProvincesWithRegionCountryId(ctx
var result = []*pb.RegionProvince{} var result = []*pb.RegionProvince{}
for _, province := range provinces { for _, province := range provinces {
result = append(result, &pb.RegionProvince{ result = append(result, &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.Name, Name: province.Name,
Codes: province.DecodeCodes(), Codes: province.DecodeCodes(),
CustomName: province.CustomName, CustomName: province.CustomName,
@@ -125,7 +125,7 @@ func (this *RegionProvinceService) FindRegionProvince(ctx context.Context, req *
return &pb.FindRegionProvinceResponse{ return &pb.FindRegionProvinceResponse{
RegionProvince: &pb.RegionProvince{ RegionProvince: &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.Name, Name: province.Name,
Codes: province.DecodeCodes(), Codes: province.DecodeCodes(),
CustomName: province.CustomName, CustomName: province.CustomName,

View File

@@ -48,7 +48,7 @@ func (this *RegionTownService) FindAllRegionTowns(ctx context.Context, req *pb.F
} }
pbCity = &pb.RegionCity{ pbCity = &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.Name, Name: city.Name,
Codes: city.DecodeCodes(), Codes: city.DecodeCodes(),
CustomName: city.CustomName, CustomName: city.CustomName,
@@ -58,7 +58,7 @@ func (this *RegionTownService) FindAllRegionTowns(ctx context.Context, req *pb.F
} }
pbTowns = append(pbTowns, &pb.RegionTown{ pbTowns = append(pbTowns, &pb.RegionTown{
Id: int64(town.Id), Id: int64(town.ValueId),
Name: town.Name, Name: town.Name,
Codes: town.DecodeCodes(), Codes: town.DecodeCodes(),
RegionCityId: int64(town.CityId), RegionCityId: int64(town.CityId),
@@ -95,7 +95,7 @@ func (this *RegionTownService) FindAllRegionTownsWithRegionCityId(ctx context.Co
var pbCity = &pb.RegionCity{Id: cityId} var pbCity = &pb.RegionCity{Id: cityId}
pbTowns = append(pbTowns, &pb.RegionTown{ pbTowns = append(pbTowns, &pb.RegionTown{
Id: int64(town.Id), Id: int64(town.ValueId),
Name: town.Name, Name: town.Name,
Codes: town.DecodeCodes(), Codes: town.DecodeCodes(),
RegionCityId: int64(town.CityId), RegionCityId: int64(town.CityId),
@@ -131,7 +131,7 @@ func (this *RegionTownService) FindRegionTown(ctx context.Context, req *pb.FindR
return &pb.FindRegionTownResponse{ return &pb.FindRegionTownResponse{
RegionTown: &pb.RegionTown{ RegionTown: &pb.RegionTown{
Id: int64(town.Id), Id: int64(town.ValueId),
Name: town.Name, Name: town.Name,
Codes: town.DecodeCodes(), Codes: town.DecodeCodes(),
RegionCityId: int64(town.CityId), RegionCityId: int64(town.CityId),

View File

@@ -392,7 +392,7 @@ func (this *ServerService) CreateBasicHTTPServer(ctx context.Context, req *pb.Cr
return nil, err return nil, err
} }
originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, req.UserId, "", addrJSON, nil, "", 10, true, nil, nil, nil, 0, 0, nil, nil, u.Host, false) originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, req.UserId, "", addrJSON, nil, "", 10, true, nil, nil, nil, 0, 0, nil, nil, u.Host, false, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -651,7 +651,7 @@ func (this *ServerService) CreateBasicTCPServer(ctx context.Context, req *pb.Cre
return nil, err return nil, err
} }
originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, req.UserId, "", addrJSON, nil, "", 10, true, nil, nil, nil, 0, 0, nil, nil, "", false) originId, err := models.SharedOriginDAO.CreateOrigin(tx, adminId, req.UserId, "", addrJSON, nil, "", 10, true, nil, nil, nil, 0, 0, nil, nil, "", false, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1301,6 +1301,14 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
order = "trafficOutAsc" order = "trafficOutAsc"
} else if req.TrafficOutDesc { } else if req.TrafficOutDesc {
order = "trafficOutDesc" order = "trafficOutDesc"
} else if req.RequestsAsc {
order = "requestsAsc"
} else if req.RequestsDesc {
order = "requestsDesc"
} else if req.AttackRequestsAsc {
order = "attackRequestsAsc"
} else if req.AttackRequestsDesc {
order = "attackRequestsDesc"
} }
servers, err := models.SharedServerDAO.ListEnabledServersMatch(tx, req.Offset, req.Size, req.ServerGroupId, req.Keyword, req.UserId, req.NodeClusterId, req.AuditingFlag, utils.SplitStrings(req.ProtocolFamily, ","), order) servers, err := models.SharedServerDAO.ListEnabledServersMatch(tx, req.Offset, req.Size, req.ServerGroupId, req.Keyword, req.UserId, req.NodeClusterId, req.AuditingFlag, utils.SplitStrings(req.ProtocolFamily, ","), order)
@@ -1418,11 +1426,13 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
Id: int64(server.ClusterId), Id: int64(server.ClusterId),
Name: clusterName, Name: clusterName,
}, },
ServerGroups: pbGroups, ServerGroups: pbGroups,
UserId: int64(server.UserId), UserId: int64(server.UserId),
User: pbUser, User: pbUser,
BandwidthTime: server.BandwidthTime, BandwidthTime: server.BandwidthTime,
BandwidthBytes: int64(server.BandwidthBytes), BandwidthBytes: int64(server.BandwidthBytes),
CountRequests: int64(server.CountRequests),
CountAttackRequests: int64(server.CountAttackRequests),
}) })
} }

View File

@@ -65,12 +65,12 @@ func init() {
for _, stat := range m { for _, stat := range m {
// 更新服务的带宽峰值 // 更新服务的带宽峰值
if stat.ServerId > 0 { if stat.ServerId > 0 {
err := models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.NodeRegionId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests) err = models.SharedServerBandwidthStatDAO.UpdateServerBandwidth(tx, stat.UserId, stat.ServerId, stat.NodeRegionId, stat.Day, stat.TimeAt, stat.Bytes, stat.TotalBytes, stat.CachedBytes, stat.AttackBytes, stat.CountRequests, stat.CountCachedRequests, stat.CountAttackRequests)
if err != nil { if err != nil {
remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error()) remotelogs.Error("ServerBandwidthStatService", "dump bandwidth stats failed: "+err.Error())
} }
err = models.SharedServerDAO.UpdateServerBandwidth(tx, stat.ServerId, stat.Day+stat.TimeAt, stat.Bytes) err = models.SharedServerDAO.UpdateServerBandwidth(tx, stat.ServerId, stat.Day+stat.TimeAt, stat.Bytes, stat.CountRequests, stat.CountAttackRequests)
if err != nil { if err != nil {
remotelogs.Error("ServerBandwidthStatService", "update server bandwidth failed: "+err.Error()) remotelogs.Error("ServerBandwidthStatService", "update server bandwidth failed: "+err.Error())
} }

View File

@@ -483,6 +483,7 @@ func (this *ServerGroupService) FindEnabledServerGroupConfigInfo(ctx context.Con
result.HasAccessLogConfig = webConfig != nil && webConfig.AccessLogRef != nil && webConfig.AccessLogRef.IsPrior result.HasAccessLogConfig = webConfig != nil && webConfig.AccessLogRef != nil && webConfig.AccessLogRef.IsPrior
result.HasStatConfig = webConfig != nil && webConfig.StatRef != nil && webConfig.StatRef.IsPrior result.HasStatConfig = webConfig != nil && webConfig.StatRef != nil && webConfig.StatRef.IsPrior
result.HasCompressionConfig = webConfig != nil && webConfig.Compression != nil && webConfig.Compression.IsPrior result.HasCompressionConfig = webConfig != nil && webConfig.Compression != nil && webConfig.Compression.IsPrior
result.HasOptimizationConfig = webConfig != nil && webConfig.Optimization != nil && webConfig.Optimization.IsPrior
result.HasWebsocketConfig = webConfig != nil && webConfig.WebsocketRef != nil && webConfig.WebsocketRef.IsPrior result.HasWebsocketConfig = webConfig != nil && webConfig.WebsocketRef != nil && webConfig.WebsocketRef.IsPrior
result.HasRequestHeadersConfig = webConfig != nil && webConfig.RequestHeaderPolicyRef != nil && webConfig.RequestHeaderPolicyRef.IsPrior result.HasRequestHeadersConfig = webConfig != nil && webConfig.RequestHeaderPolicyRef != nil && webConfig.RequestHeaderPolicyRef.IsPrior
result.HasResponseHeadersConfig = webConfig != nil && webConfig.ResponseHeaderPolicyRef != nil && webConfig.ResponseHeaderPolicyRef.IsPrior result.HasResponseHeadersConfig = webConfig != nil && webConfig.ResponseHeaderPolicyRef != nil && webConfig.ResponseHeaderPolicyRef.IsPrior

View File

@@ -62,15 +62,15 @@ func (this *ServerRegionCityMonthlyStatService) FindTopServerRegionCityMonthlySt
continue continue
} }
pbStat.RegionCountry = &pb.RegionCountry{ pbStat.RegionCountry = &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.DisplayName(), Name: country.DisplayName(),
} }
pbStat.RegionProvince = &pb.RegionProvince{ pbStat.RegionProvince = &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.DisplayName(), Name: province.DisplayName(),
} }
pbStat.RegionCity = &pb.RegionCity{ pbStat.RegionCity = &pb.RegionCity{
Id: int64(city.Id), Id: int64(city.ValueId),
Name: city.DisplayName(), Name: city.DisplayName(),
} }
pbStats = append(pbStats, pbStat) pbStats = append(pbStats, pbStat)

View File

@@ -46,7 +46,7 @@ func (this *ServerRegionCountryMonthlyStatService) FindTopServerRegionCountryMon
continue continue
} }
pbStat.RegionCountry = &pb.RegionCountry{ pbStat.RegionCountry = &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.DisplayName(), Name: country.DisplayName(),
} }

View File

@@ -45,7 +45,7 @@ func (this *ServerRegionProviderMonthlyStatService) FindTopServerRegionProviderM
continue continue
} }
pbStat.RegionProvider = &pb.RegionProvider{ pbStat.RegionProvider = &pb.RegionProvider{
Id: int64(provider.Id), Id: int64(provider.ValueId),
Name: provider.DisplayName(), Name: provider.DisplayName(),
} }
pbStats = append(pbStats, pbStat) pbStats = append(pbStats, pbStat)

View File

@@ -52,11 +52,11 @@ func (this *ServerRegionProvinceMonthlyStatService) FindTopServerRegionProvinceM
continue continue
} }
pbStat.RegionCountry = &pb.RegionCountry{ pbStat.RegionCountry = &pb.RegionCountry{
Id: int64(country.Id), Id: int64(country.ValueId),
Name: country.DisplayName(), Name: country.DisplayName(),
} }
pbStat.RegionProvince = &pb.RegionProvince{ pbStat.RegionProvince = &pb.RegionProvince{
Id: int64(province.Id), Id: int64(province.ValueId),
Name: province.DisplayName(), Name: province.DisplayName(),
} }
pbStats = append(pbStats, pbStat) pbStats = append(pbStats, pbStat)

View File

@@ -261,6 +261,7 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable
IsEnterpriseIdentified: isEnterpriseIdentified, IsEnterpriseIdentified: isEnterpriseIdentified,
BandwidthAlgo: user.BandwidthAlgo, BandwidthAlgo: user.BandwidthAlgo,
OtpLogin: pbOtpAuth, OtpLogin: pbOtpAuth,
Lang: user.Lang,
}}, nil }}, nil
} }

View File

@@ -97,7 +97,13 @@ func (this *Setup) Run() error {
} }
for _, db := range config.DBs { for _, db := range config.DBs {
// 可以同时运行多条语句 // 可以同时运行多条语句
db.Dsn += "&multiStatements=true" if !strings.Contains(db.Dsn, "multiStatements=") {
if strings.Contains(db.Dsn, "?") {
db.Dsn += "&multiStatements=true"
} else {
db.Dsn += "?multiStatements=true"
}
}
} }
dbConfig, ok := config.DBs[Tea.Env] dbConfig, ok := config.DBs[Tea.Env]
if !ok { if !ok {

File diff suppressed because it is too large Load Diff

View File

@@ -87,14 +87,8 @@ func (this *SQLExecutor) Run(showLog bool) error {
// 检查数据 // 检查数据
func (this *SQLExecutor) checkData(db *dbs.DB) error { func (this *SQLExecutor) checkData(db *dbs.DB) error {
// 检查初始化用户
err := this.checkUser(db)
if err != nil {
return err
}
// 检查管理员平台节点 // 检查管理员平台节点
err = this.checkAdminNode(db) err := this.checkAdminNode(db)
if err != nil { if err != nil {
return err return err
} }
@@ -111,6 +105,13 @@ func (this *SQLExecutor) checkData(db *dbs.DB) error {
return err return err
} }
// 检查初始化用户
// 需要放在检查集群后面
err = this.checkUser(db)
if err != nil {
return err
}
// 检查IP名单 // 检查IP名单
err = this.checkIPList(db) err = this.checkIPList(db)
if err != nil { if err != nil {
@@ -154,7 +155,14 @@ func (this *SQLExecutor) checkUser(db *dbs.DB) error {
return nil return nil
} }
_, err = db.Exec("INSERT INTO edgeUsers (`username`, `password`, `fullname`, `isOn`, `state`, `createdAt`) VALUES (?, ?, ?, ?, ?, ?)", "USER-"+rands.HexString(10), stringutil.Md5(rands.HexString(32)), "默认用户", 1, 1, time.Now().Unix()) // 读取默认集群ID
// Read default cluster id
clusterId, err := db.FindCol(0, "SELECT id FROM edgeNodeClusters WHERE state=1 ORDER BY id ASC LIMIT 1")
if err != nil {
return err
}
_, err = db.Exec("INSERT INTO edgeUsers (`username`, `password`, `fullname`, `isOn`, `state`, `createdAt`, `clusterId`) VALUES (?, ?, ?, ?, ?, ?, ?)", "USER_"+rands.HexString(10), stringutil.Md5(rands.HexString(32)), "默认用户", 1, 1, time.Now().Unix(), clusterId)
return err return err
} }

View File

@@ -17,6 +17,7 @@ import (
"github.com/iwind/TeaGo/rands" "github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string" stringutil "github.com/iwind/TeaGo/utils/string"
"strings"
) )
type upgradeVersion struct { type upgradeVersion struct {
@@ -91,6 +92,9 @@ var upgradeFuncs = []*upgradeVersion{
{ {
"0.5.8", upgradeV0_5_8, "0.5.8", upgradeV0_5_8,
}, },
{
"1.2.1", upgradeV1_2_1,
},
} }
// UpgradeSQLData 升级SQL数据 // UpgradeSQLData 升级SQL数据
@@ -536,7 +540,7 @@ func upgradeV0_4_1(db *dbs.DB) error {
} }
// 执行域名统计清理 // 执行域名统计清理
err = stats.NewServerDomainHourlyStatDAO().Clean(nil, 7) err = stats.NewServerDomainHourlyStatDAO().CleanDays(nil, 7)
if err != nil { if err != nil {
return err return err
} }
@@ -719,3 +723,32 @@ func upgradeV0_4_11(db *dbs.DB) error {
return nil return nil
} }
// v1.2.1
func upgradeV1_2_1(db *dbs.DB) error {
// upgrade generated USER-xxx in old versions
ones, _, err := db.FindOnes("SELECT id, username, clusterId FROM edgeUsers WHERE username LIKE 'USER-%'")
if err != nil {
return err
}
for _, one := range ones {
var userId = one.GetInt64("id")
var clusterId = one.GetInt64("clusterId")
var username = one.GetString("username")
if clusterId <= 0 {
defaultClusterIdValue, err := db.FindCol(0, "SELECT id FROM edgeNodeClusters WHERE state=1 ORDER BY id ASC LIMIT 1")
if err != nil {
return err
}
var defaultClusterId = types.Int64(defaultClusterIdValue)
if defaultClusterId > 0 {
_, err = db.Exec("UPDATE edgeUsers SET username=?, clusterId=? WHERE id=?", strings.ReplaceAll(username, "-", "_"), defaultClusterId, userId)
if err != nil {
return err
}
}
}
}
return nil
}

View File

@@ -252,3 +252,23 @@ func TestUpgradeSQLData_v0_5_3(t *testing.T) {
t.Log("ok") t.Log("ok")
} }
func TestUpgradeSQLData_v1_2_1(t *testing.T) {
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
Driver: "mysql",
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
Prefix: "edge",
})
if err != nil {
t.Fatal(err)
}
defer func() {
_ = db.Close()
}()
err = upgradeV1_2_1(db)
if err != nil {
t.Fatal(err)
}
t.Log("ok")
}

View File

@@ -52,7 +52,7 @@ func (this *ServerAccessLogCleaner) Loop() error {
if len(configJSON) == 0 { if len(configJSON) == 0 {
return nil return nil
} }
var config = &systemconfigs.DatabaseConfig{} var config = systemconfigs.NewDatabaseConfig()
err = json.Unmarshal(configJSON, config) err = json.Unmarshal(configJSON, config)
if err != nil { if err != nil {
return err return err

View File

@@ -0,0 +1,59 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build linux
package executils
import (
"golang.org/x/sys/unix"
"io/fs"
"os"
"os/exec"
"syscall"
)
// LookPath customize our LookPath() function, to work in broken $PATH environment variable
func LookPath(file string) (string, error) {
result, err := exec.LookPath(file)
if err == nil && len(result) > 0 {
return result, nil
}
// add common dirs contains executable files these may be excluded in $PATH environment variable
var binPaths = []string{
"/usr/sbin",
"/usr/bin",
"/usr/local/sbin",
"/usr/local/bin",
}
for _, binPath := range binPaths {
var fullPath = binPath + string(os.PathSeparator) + file
stat, err := os.Stat(fullPath)
if err != nil {
continue
}
if stat.IsDir() {
return "", syscall.EISDIR
}
var mode = stat.Mode()
if mode.IsDir() {
return "", syscall.EISDIR
}
err = syscall.Faccessat(unix.AT_FDCWD, fullPath, unix.X_OK, unix.AT_EACCESS)
if err == nil || (err != syscall.ENOSYS && err != syscall.EPERM) {
return fullPath, err
}
if mode&0111 != 0 {
return fullPath, nil
}
return "", fs.ErrPermission
}
return "", &exec.Error{
Name: file,
Err: exec.ErrNotFound,
}
}

View File

@@ -0,0 +1,10 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !linux
package executils
import "os/exec"
func LookPath(file string) (string, error) {
return exec.LookPath(file)
}

View File

@@ -4,6 +4,7 @@ package utils
import ( import (
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"os/exec" "os/exec"
"runtime" "runtime"
@@ -14,7 +15,7 @@ func AddPortsToFirewall(ports []int) {
// Linux // Linux
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
// firewalld // firewalld
firewallCmd, _ := exec.LookPath("firewall-cmd") firewallCmd, _ := executils.LookPath("firewall-cmd")
if len(firewallCmd) > 0 { if len(firewallCmd) > 0 {
err := exec.Command(firewallCmd, "--add-port="+types.String(port)+"/tcp").Run() err := exec.Command(firewallCmd, "--add-port="+types.String(port)+"/tcp").Run()
if err == nil { if err == nil {

View File

@@ -5,6 +5,7 @@ package utils
import ( import (
"errors" "errors"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
executils "github.com/TeaOSLab/EdgeAPI/internal/utils/exec"
"github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files" "github.com/iwind/TeaGo/files"
"os" "os"
@@ -15,13 +16,13 @@ import (
var systemdServiceFile = "/etc/systemd/system/edge-api.service" var systemdServiceFile = "/etc/systemd/system/edge-api.service"
var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName
// 安装服务 // Install 安装服务
func (this *ServiceManager) Install(exePath string, args []string) error { func (this *ServiceManager) Install(exePath string, args []string) error {
if os.Getgid() != 0 { if os.Getgid() != 0 {
return errors.New("only root users can install the service") return errors.New("only root users can install the service")
} }
systemd, err := exec.LookPath("systemctl") systemd, err := executils.LookPath("systemctl")
if err != nil { if err != nil {
return this.installInitService(exePath, args) return this.installInitService(exePath, args)
} }
@@ -29,14 +30,14 @@ func (this *ServiceManager) Install(exePath string, args []string) error {
return this.installSystemdService(systemd, exePath, args) return this.installSystemdService(systemd, exePath, args)
} }
// 启动服务 // Start 启动服务
func (this *ServiceManager) Start() error { func (this *ServiceManager) Start() error {
if os.Getgid() != 0 { if os.Getgid() != 0 {
return errors.New("only root users can start the service") return errors.New("only root users can start the service")
} }
if files.NewFile(systemdServiceFile).Exists() { if files.NewFile(systemdServiceFile).Exists() {
systemd, err := exec.LookPath("systemctl") systemd, err := executils.LookPath("systemctl")
if err != nil { if err != nil {
return err return err
} }
@@ -53,7 +54,7 @@ func (this *ServiceManager) Uninstall() error {
} }
if files.NewFile(systemdServiceFile).Exists() { if files.NewFile(systemdServiceFile).Exists() {
systemd, err := exec.LookPath("systemctl") systemd, err := executils.LookPath("systemctl")
if err != nil { if err != nil {
return err return err
} }
@@ -93,7 +94,7 @@ func (this *ServiceManager) installInitService(exePath string, args []string) er
return err return err
} }
chkCmd, err := exec.LookPath("chkconfig") chkCmd, err := executils.LookPath("chkconfig")
if err != nil { if err != nil {
return err return err
} }