Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35cb10fffe | ||
|
|
7c84794ac4 | ||
|
|
5859f5df91 | ||
|
|
e370944233 | ||
|
|
a23a2ed826 | ||
|
|
3f9c250dff | ||
|
|
06c9c9403b | ||
|
|
0e580a0890 | ||
|
|
7aba622403 | ||
|
|
72cc8389e6 | ||
|
|
39cf470b0c | ||
|
|
6e71dda713 | ||
|
|
10909e28c8 | ||
|
|
6bd6e350b9 | ||
|
|
d2ae7834ae | ||
|
|
c1ffd25c8b | ||
|
|
931e55162b | ||
|
|
fa2bac6d1d | ||
|
|
2f7b7240dd | ||
|
|
da67e726a2 | ||
|
|
6cb5529c3f | ||
|
|
473d0d9439 | ||
|
|
bf0db231fc | ||
|
|
5644906b77 | ||
|
|
3e32fe8e10 | ||
|
|
8459f106e9 | ||
|
|
b768bbce5d | ||
|
|
9e7beb39c0 | ||
|
|
94287f5857 | ||
|
|
60690dfd01 | ||
|
|
fb00a7931e | ||
|
|
42a6494bde | ||
|
|
85a46a9827 | ||
|
|
088636553c | ||
|
|
95de3b12e2 | ||
|
|
b66b8d198a | ||
|
|
e968a79886 | ||
|
|
4fc5d5b549 | ||
|
|
77606709b3 | ||
|
|
3529ceefcd | ||
|
|
7e851f07b1 | ||
|
|
a62711e520 | ||
|
|
ffce574b39 | ||
|
|
4b1a9f9a45 | ||
|
|
7a86ecb44b | ||
|
|
89a113431a | ||
|
|
ce62d0769b | ||
|
|
a72dc2e011 | ||
|
|
91ca2d6b6b | ||
|
|
0de6fa5ce8 | ||
|
|
84e2628769 | ||
|
|
fc28798c9f | ||
|
|
24c21c5513 | ||
|
|
8445e811a5 | ||
|
|
d54621d500 | ||
|
|
ef045e90f2 | ||
|
|
5205136809 | ||
|
|
179a7760fa | ||
|
|
640e69524c | ||
|
|
3620ab3dc6 | ||
|
|
5789b1afb9 | ||
|
|
6f9f9dfb6f | ||
|
|
171bafce6a | ||
|
|
7c7fecab26 | ||
|
|
7afdf5a2d9 | ||
|
|
ee9718ac77 | ||
|
|
15e10182da | ||
|
|
4341c5b738 | ||
|
|
cf9b31b8eb | ||
|
|
564d440cd1 | ||
|
|
bad9231ab3 | ||
|
|
a78333c490 | ||
|
|
ace44173ec | ||
|
|
5155ce97af | ||
|
|
e2bf3ba1a4 | ||
|
|
9abc65bd2b | ||
|
|
a99156ea49 | ||
|
|
d35db163ae | ||
|
|
e7b0f0df90 | ||
|
|
eab09fa37a | ||
|
|
ec3f89ecf5 | ||
|
|
d58106c7ca | ||
|
|
5da924118d | ||
|
|
51e37f0c52 | ||
|
|
7e9e764322 | ||
|
|
75e41fff4d | ||
|
|
8a9842edaf | ||
|
|
4e8629d74a | ||
|
|
2e02aa556e | ||
|
|
974c95c20a |
@@ -83,6 +83,20 @@ func main() {
|
||||
}
|
||||
}
|
||||
})
|
||||
app.On("debug", func() {
|
||||
var sock = gosock.NewTmpSock(teaconst.ProcessName)
|
||||
reply, err := sock.Send(&gosock.Command{Code: "debug"})
|
||||
if err != nil {
|
||||
fmt.Println("[ERROR]" + err.Error())
|
||||
} else {
|
||||
var isDebug = maps.NewMap(reply.Params).GetBool("debug")
|
||||
if isDebug {
|
||||
fmt.Println("debug on")
|
||||
} else {
|
||||
fmt.Println("debug off")
|
||||
}
|
||||
}
|
||||
})
|
||||
app.Run(func() {
|
||||
nodes.NewAPINode().Start()
|
||||
})
|
||||
|
||||
20
go.mod
20
go.mod
@@ -5,27 +5,23 @@ go 1.15
|
||||
replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183
|
||||
github.com/andybalholm/brotli v1.0.4
|
||||
github.com/cespare/xxhash/v2 v2.1.1
|
||||
github.com/go-acme/lego/v4 v4.5.2
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/lionsoul2014/ip2region v2.2.0-release+incompatible
|
||||
github.com/mozillazg/go-pinyin v0.18.0
|
||||
github.com/pkg/sftp v1.12.0
|
||||
github.com/shirou/gopsutil v3.21.5+incompatible
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
||||
google.golang.org/grpc v1.38.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
github.com/shirou/gopsutil/v3 v3.22.2 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
|
||||
google.golang.org/grpc v1.45.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
96
go.sum
96
go.sum
@@ -43,8 +43,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
@@ -52,6 +50,7 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 h1:dkj8/dxOQ4L1XpwCzRLqukvUBbx
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
@@ -78,6 +77,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cloudflare/cloudflare-go v0.20.0/go.mod h1:sPWL/lIC6biLEdyGZwBQ1rGQKF1FhM7N60fuNiFdYTI=
|
||||
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-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
@@ -101,7 +104,8 @@ github.com/dnsimple/dnsimple-go v0.70.1/go.mod h1:F9WHww9cC76hrnwGFfAfrqdW99j3MO
|
||||
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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/exoscale/egoscale v0.67.0/go.mod h1:wi0myUxPsV8SdEtdJHQJxFLL/wEw9fiw9Gs1PWRkvkM=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
@@ -122,8 +126,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
|
||||
@@ -132,8 +136,6 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -161,6 +163,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
@@ -175,6 +178,9 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
@@ -201,6 +207,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
@@ -231,11 +238,8 @@ github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhK
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
|
||||
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20210628135026-38575a4ab060/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13 h1:HuEJ5xJfujW1Q6rNDhOu5LQXEBB2qLPah3jYslT8Gz4=
|
||||
github.com/iwind/TeaGo v0.0.0-20210831140440-a2a442471b13/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24 h1:1cGulkD2SNJJRok5OKwyhP/Ddm+PgSWKOupn0cR36/A=
|
||||
github.com/iwind/TeaGo v0.0.0-20211026123858-7de7a21cad24/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
|
||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
|
||||
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
|
||||
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
@@ -250,8 +254,6 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
@@ -277,12 +279,11 @@ github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c
|
||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/linode/linodego v0.31.1/go.mod h1:BR0gVkCJffEdIGJSl6bHR80Ty+Uvg/2jkjmrWaFectM=
|
||||
github.com/lionsoul2014/ip2region v2.2.0-release+incompatible h1:1qp9iks+69h7IGLazAplzS9Ca14HAxuD5c0rbFdPGy4=
|
||||
github.com/lionsoul2014/ip2region v2.2.0-release+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
|
||||
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
|
||||
github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -322,7 +323,6 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
@@ -371,6 +371,7 @@ github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
@@ -390,14 +391,17 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
|
||||
github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil/v3 v3.22.2 h1:wCrArWFkHYIdDxx/FSfF5RB4dpJYW6t7rcp3+zL8uks=
|
||||
github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
@@ -438,8 +442,12 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
|
||||
github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
|
||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
|
||||
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
|
||||
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/transip/gotransip/v6 v6.6.1/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
|
||||
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||
@@ -456,13 +464,15 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
@@ -482,8 +492,9 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -507,7 +518,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
@@ -516,7 +526,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -551,8 +560,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -588,6 +599,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -611,6 +623,7 @@ golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -619,11 +632,17 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20211216021012-1d35b9e2eb4e/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-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -631,8 +650,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -674,7 +694,6 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -714,9 +733,12 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20220303160752-862486edd9cc h1:fb/ViRpv3ln/LvbqZtTpoOd1YQDNH12gaGZreoSFovE=
|
||||
google.golang.org/genproto v0.0.0-20220303160752-862486edd9cc/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg=
|
||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -726,9 +748,12 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -739,8 +764,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
//go:build community
|
||||
// +build community
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package accesslogs
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ package configs
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
// +build community
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package teaconst
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.4.0"
|
||||
Version = "0.4.5"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -18,10 +18,13 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "0.4.0"
|
||||
UserNodeVersion = "0.2.1"
|
||||
NodeVersion = "0.4.5"
|
||||
UserNodeVersion = "0.3.2"
|
||||
AuthorityNodeVersion = "0.0.2"
|
||||
MonitorNodeVersion = "0.0.3"
|
||||
DNSNodeVersion = "0.2.1"
|
||||
ReportNodeVersion = "0.1.0"
|
||||
|
||||
// SQLVersion SQL版本号
|
||||
SQLVersion = "5"
|
||||
)
|
||||
|
||||
@@ -6,4 +6,5 @@ var (
|
||||
IsPlus = false
|
||||
MaxNodes int32 = 0
|
||||
NodeId int64 = 0
|
||||
Debug = false
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
acmeutils "github.com/TeaOSLab/EdgeAPI/internal/acme"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/dns"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
@@ -400,6 +401,7 @@ func (this *ACMETaskDAO) runTaskWithoutLog(tx *dbs.Tx, taskId int64) (isOk bool,
|
||||
client := utils.SharedHttpClient(5 * time.Second)
|
||||
req, err := http.NewRequest(http.MethodPost, task.AuthURL, bytes.NewReader(authJSON))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
|
||||
if err != nil {
|
||||
remotelogs.Error("ACME", "parse auth url failed '"+task.AuthURL+"': "+err.Error())
|
||||
} else {
|
||||
|
||||
76
internal/db/models/api_method_stat_dao.go
Normal file
76
internal/db/models/api_method_stat_dao.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type APIMethodStatDAO dbs.DAO
|
||||
|
||||
func NewAPIMethodStatDAO() *APIMethodStatDAO {
|
||||
return dbs.NewDAO(&APIMethodStatDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeAPIMethodStats",
|
||||
Model: new(APIMethodStat),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*APIMethodStatDAO)
|
||||
}
|
||||
|
||||
var SharedAPIMethodStatDAO *APIMethodStatDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedAPIMethodStatDAO = NewAPIMethodStatDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// CreateStat 记录统计数据
|
||||
func (this *APIMethodStatDAO) CreateStat(tx *dbs.Tx, method string, tag string, costMs float64) error {
|
||||
var day = timeutil.Format("Ymd")
|
||||
return this.Query(tx).
|
||||
Param("costMs", costMs).
|
||||
InsertOrUpdateQuickly(map[string]interface{}{
|
||||
"apiNodeId": teaconst.NodeId,
|
||||
"method": method,
|
||||
"tag": tag,
|
||||
"costMs": costMs,
|
||||
"peekMs": costMs,
|
||||
"countCalls": 1,
|
||||
"day": day,
|
||||
}, map[string]interface{}{
|
||||
"costMs": dbs.SQL("(costMs*countCalls+:costMs)/(countCalls+1)"),
|
||||
"peekMs": dbs.SQL("IF(peekMs>:costMs, peekMs, :costMs)"),
|
||||
"countCalls": dbs.SQL("countCalls+1"),
|
||||
})
|
||||
}
|
||||
|
||||
// FindAllStatsWithDay 查询当前统计
|
||||
func (this *APIMethodStatDAO) FindAllStatsWithDay(tx *dbs.Tx, day string) (result []*APIMethodStat, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Attr("day", day).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// CountAllStatsWithDay 统计当天数量
|
||||
func (this *APIMethodStatDAO) CountAllStatsWithDay(tx *dbs.Tx, day string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("day", day).
|
||||
Count()
|
||||
}
|
||||
|
||||
// Clean 清理数据
|
||||
func (this *APIMethodStatDAO) Clean(tx *dbs.Tx) error {
|
||||
var day = timeutil.Format("Ymd")
|
||||
_, err := this.Query(tx).
|
||||
Param("day", day).
|
||||
Where("day<:day").
|
||||
Delete()
|
||||
return err
|
||||
}
|
||||
19
internal/db/models/api_method_stat_dao_test.go
Normal file
19
internal/db/models/api_method_stat_dao_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAPIMethodStatDAO_CreateStat(t *testing.T) {
|
||||
var dao = NewAPIMethodStatDAO()
|
||||
var tx *dbs.Tx
|
||||
|
||||
err := dao.CreateStat(tx, "/pb.Hello/World", "tag", 1.123)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
28
internal/db/models/api_method_stat_model.go
Normal file
28
internal/db/models/api_method_stat_model.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package models
|
||||
|
||||
// APIMethodStat API方法统计
|
||||
type APIMethodStat struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
ApiNodeId uint32 `field:"apiNodeId"` // API节点ID
|
||||
Method string `field:"method"` // 方法
|
||||
Tag string `field:"tag"` // 标签方法
|
||||
CostMs float64 `field:"costMs"` // 耗时Ms
|
||||
PeekMs float64 `field:"peekMs"` // 峰值耗时
|
||||
CountCalls uint64 `field:"countCalls"` // 调用次数
|
||||
Day string `field:"day"` // 日期
|
||||
}
|
||||
|
||||
type APIMethodStatOperator struct {
|
||||
Id interface{} // ID
|
||||
ApiNodeId interface{} // API节点ID
|
||||
Method interface{} // 方法
|
||||
Tag interface{} // 标签方法
|
||||
CostMs interface{} // 耗时Ms
|
||||
PeekMs interface{} // 峰值耗时
|
||||
CountCalls interface{} // 调用次数
|
||||
Day interface{} // 日期
|
||||
}
|
||||
|
||||
func NewAPIMethodStatOperator() *APIMethodStatOperator {
|
||||
return &APIMethodStatOperator{}
|
||||
}
|
||||
1
internal/db/models/api_method_stat_model_ext.go
Normal file
1
internal/db/models/api_method_stat_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package models
|
||||
@@ -62,7 +62,15 @@ func (this *APINodeDAO) DisableAPINode(tx *dbs.Tx, id int64) error {
|
||||
}
|
||||
|
||||
// FindEnabledAPINode 查找启用中的条目
|
||||
func (this *APINodeDAO) FindEnabledAPINode(tx *dbs.Tx, id int64) (*APINode, error) {
|
||||
func (this *APINodeDAO) FindEnabledAPINode(tx *dbs.Tx, id int64, cacheMap *utils.CacheMap) (*APINode, error) {
|
||||
var cacheKey = this.Table + ":FindEnabledAPINode:" + types.String(id)
|
||||
if cacheMap != nil {
|
||||
cache, ok := cacheMap.Get(cacheKey)
|
||||
if ok {
|
||||
return cache.(*APINode), nil
|
||||
}
|
||||
}
|
||||
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Attr("state", APINodeStateEnabled).
|
||||
@@ -70,6 +78,11 @@ func (this *APINodeDAO) FindEnabledAPINode(tx *dbs.Tx, id int64) (*APINode, erro
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, result)
|
||||
}
|
||||
|
||||
return result.(*APINode), err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build community
|
||||
// +build community
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package authority
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@ type httpAccessLogDefinition struct {
|
||||
}
|
||||
|
||||
// HTTP服务访问
|
||||
var httpAccessLogDAOMapping = map[int64]*HTTPAccessLogDAOWrapper{} // dbNodeId => DAO
|
||||
var httpAccessLogTableMapping = map[string]*httpAccessLogDefinition{} // tableName_crc(dsn) => true
|
||||
var httpAccessLogDAOMapping = map[int64]*HTTPAccessLogDAOWrapper{} // dbNodeId => DAO
|
||||
|
||||
// DNS服务访问
|
||||
var nsAccessLogDAOMapping = map[int64]*NSAccessLogDAOWrapper{} // dbNodeId => DAO
|
||||
@@ -86,36 +85,6 @@ func randomNSAccessLogDAO() (dao *NSAccessLogDAOWrapper) {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查表格是否存在
|
||||
func findHTTPAccessLogTableName(db *dbs.DB, day string) (tableName string, hasRemoteAddr bool, hasDomain bool, ok bool, err error) {
|
||||
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
|
||||
err = errors.New("invalid day '" + day + "', should be YYYYMMDD")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := db.Config()
|
||||
if err != nil {
|
||||
return "", false, false, false, err
|
||||
}
|
||||
|
||||
tableName = "edgeHTTPAccessLogs_" + day
|
||||
cacheKey := tableName + "_" + fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(config.Dsn)))
|
||||
|
||||
accessLogLocker.RLock()
|
||||
def, ok := httpAccessLogTableMapping[cacheKey]
|
||||
accessLogLocker.RUnlock()
|
||||
if ok {
|
||||
return tableName, def.HasRemoteAddr, def.HasDomain, true, nil
|
||||
}
|
||||
|
||||
def, err = findHTTPAccessLogTable(db, day, false)
|
||||
if err != nil {
|
||||
return tableName, false, false, false, err
|
||||
}
|
||||
|
||||
return tableName, def.HasRemoteAddr, def.HasDomain, def.Exists, nil
|
||||
}
|
||||
|
||||
func findNSAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool, err error) {
|
||||
if !regexp.MustCompile(`^\d{8}$`).MatchString(day) {
|
||||
err = errors.New("invalid day '" + day + "', should be YYYYMMDD")
|
||||
@@ -145,75 +114,6 @@ func findNSAccessLogTableName(db *dbs.DB, day string) (tableName string, ok bool
|
||||
return tableName, utils.ContainsStringInsensitive(tableNames, tableName), nil
|
||||
}
|
||||
|
||||
// 根据日期获取表名
|
||||
func findHTTPAccessLogTable(db *dbs.DB, day string, force bool) (*httpAccessLogDefinition, error) {
|
||||
config, err := db.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tableName := "edgeHTTPAccessLogs_" + day
|
||||
cacheKey := tableName + "_" + fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(config.Dsn)))
|
||||
|
||||
if !force {
|
||||
accessLogLocker.RLock()
|
||||
definition, ok := httpAccessLogTableMapping[cacheKey]
|
||||
accessLogLocker.RUnlock()
|
||||
if ok {
|
||||
return definition, nil
|
||||
}
|
||||
}
|
||||
|
||||
tableNames, err := db.TableNames()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if utils.ContainsStringInsensitive(tableNames, tableName) {
|
||||
table, err := db.FindTable(tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessLogLocker.Lock()
|
||||
var definition = &httpAccessLogDefinition{
|
||||
Name: tableName,
|
||||
HasRemoteAddr: table.FindFieldWithName("remoteAddr") != nil,
|
||||
HasDomain: table.FindFieldWithName("domain") != nil,
|
||||
Exists: true,
|
||||
}
|
||||
httpAccessLogTableMapping[cacheKey] = definition
|
||||
accessLogLocker.Unlock()
|
||||
return definition, nil
|
||||
}
|
||||
|
||||
if !force {
|
||||
return &httpAccessLogDefinition{
|
||||
Name: tableName,
|
||||
HasRemoteAddr: true,
|
||||
HasDomain: true,
|
||||
Exists: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 创建表格
|
||||
_, err = db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessLogLocker.Lock()
|
||||
var definition = &httpAccessLogDefinition{
|
||||
Name: tableName,
|
||||
HasRemoteAddr: true,
|
||||
Exists: true,
|
||||
}
|
||||
httpAccessLogTableMapping[cacheKey] = definition
|
||||
accessLogLocker.Unlock()
|
||||
|
||||
return definition, nil
|
||||
}
|
||||
|
||||
func findNSAccessLogTable(db *dbs.DB, day string, force bool) (string, error) {
|
||||
config, err := db.Config()
|
||||
if err != nil {
|
||||
@@ -351,22 +251,17 @@ func (this *DBNodeInitializer) loop() error {
|
||||
// 检查表是否存在
|
||||
// httpAccessLog
|
||||
{
|
||||
tableDef, err := findHTTPAccessLogTable(db, timeutil.Format("Ymd"), true)
|
||||
tableDef, err := SharedHTTPAccessLogManager.FindTable(db, timeutil.Format("Ymd"), true)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "1050") { // 非表格已存在错误
|
||||
remotelogs.Error("DB_NODE", "create first table in database node failed: "+err.Error())
|
||||
remotelogs.Error("DB_NODE", "create first table in database node failed: "+err.Error())
|
||||
|
||||
// 创建节点日志
|
||||
createLogErr := SharedNodeLogDAO.CreateLog(nil, nodeconfigs.NodeRoleDatabase, nodeId, 0, 0, "error", "ACCESS_LOG", "can not create access log table: "+err.Error(), time.Now().Unix(), "", nil)
|
||||
if createLogErr != nil {
|
||||
remotelogs.Error("NODE_LOG", createLogErr.Error())
|
||||
}
|
||||
|
||||
continue
|
||||
} else {
|
||||
err = nil
|
||||
continue
|
||||
// 创建节点日志
|
||||
createLogErr := SharedNodeLogDAO.CreateLog(nil, nodeconfigs.NodeRoleDatabase, nodeId, 0, 0, "error", "ACCESS_LOG", "can not create access log table: "+err.Error(), time.Now().Unix(), "", nil)
|
||||
if createLogErr != nil {
|
||||
remotelogs.Error("NODE_LOG", createLogErr.Error())
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
daoObject := dbs.DAOObject{
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDBNodeInitializer_loop(t *testing.T) {
|
||||
@@ -14,32 +12,3 @@ func TestDBNodeInitializer_loop(t *testing.T) {
|
||||
}
|
||||
t.Log(len(accessLogDBMapping), len(httpAccessLogDAOMapping))
|
||||
}
|
||||
|
||||
func TestFindAccessLogTable(t *testing.T) {
|
||||
before := time.Now()
|
||||
db := SharedHTTPAccessLogDAO.Instance
|
||||
tableName, err := findHTTPAccessLogTable(db, "20201010", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(tableName)
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
|
||||
before = time.Now()
|
||||
tableName, err = findHTTPAccessLogTable(db, "20201010", false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(tableName)
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}
|
||||
|
||||
func BenchmarkFindAccessLogTable(b *testing.B) {
|
||||
db := SharedHTTPAccessLogDAO.Instance
|
||||
|
||||
runtime.GOMAXPROCS(1)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = findHTTPAccessLogTable(db, "20201010", false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,25 @@ type HTTPAccessLogDAO dbs.DAO
|
||||
var SharedHTTPAccessLogDAO *HTTPAccessLogDAO
|
||||
|
||||
// 队列
|
||||
var oldAccessLogQueue = make(chan *pb.HTTPAccessLog)
|
||||
var accessLogQueue = make(chan *pb.HTTPAccessLog, 10_000)
|
||||
var accessLogQueueMaxLength = 100_000
|
||||
var accessLogQueuePercent = 100 // 0-100
|
||||
var accessLogCountPerSecond = 10_000 // 0 表示不限制
|
||||
var accessLogConfigJSON = []byte{}
|
||||
var accessLogQueueChanged = make(chan zero.Zero, 1)
|
||||
var (
|
||||
oldAccessLogQueue = make(chan *pb.HTTPAccessLog)
|
||||
accessLogQueue = make(chan *pb.HTTPAccessLog, 10_000)
|
||||
accessLogQueueMaxLength = 100_000
|
||||
accessLogQueuePercent = 100 // 0-100
|
||||
accessLogCountPerSecond = 10_000 // 0 表示不限制
|
||||
accessLogConfigJSON = []byte{}
|
||||
accessLogQueueChanged = make(chan zero.Zero, 1)
|
||||
|
||||
accessLogEnableAutoPartial = true // 是否启用自动分表
|
||||
accessLogRowsPerTable int64 = 500_000 // 自动分表的单表最大值
|
||||
)
|
||||
|
||||
type accessLogTableQuery struct {
|
||||
daoWrapper *HTTPAccessLogDAOWrapper
|
||||
name string
|
||||
hasRemoteAddrField bool
|
||||
hasDomainField bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
@@ -120,7 +132,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLogs(tx *dbs.Tx, accessLogs []*pb.
|
||||
|
||||
// DumpAccessLogsFromQueue 从队列导入访问日志
|
||||
func (this *HTTPAccessLogDAO) DumpAccessLogsFromQueue(tx *dbs.Tx, size int) error {
|
||||
dao := randomHTTPAccessLogDAO()
|
||||
var dao = randomHTTPAccessLogDAO()
|
||||
if dao == nil {
|
||||
dao = &HTTPAccessLogDAOWrapper{
|
||||
DAO: SharedHTTPAccessLogDAO,
|
||||
@@ -168,8 +180,8 @@ Loop:
|
||||
|
||||
// CreateHTTPAccessLog 写入单条访问日志
|
||||
func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLogDAO, accessLog *pb.HTTPAccessLog) error {
|
||||
day := timeutil.Format("Ymd", time.Unix(accessLog.Timestamp, 0))
|
||||
tableDef, err := findHTTPAccessLogTable(dao.Instance, day, false)
|
||||
var day = timeutil.Format("Ymd", time.Unix(accessLog.Timestamp, 0))
|
||||
tableDef, err := SharedHTTPAccessLogManager.FindTable(dao.Instance, day, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -203,27 +215,17 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
|
||||
}
|
||||
fields["content"] = content
|
||||
|
||||
_, err = dao.Query(tx).
|
||||
var lastId int64
|
||||
lastId, err = dao.Query(tx).
|
||||
Table(tableDef.Name).
|
||||
Sets(fields).
|
||||
Insert()
|
||||
if err != nil {
|
||||
// 是否为 Error 1146: Table 'xxx.xxx' doesn't exist 如果是,则创建表之后重试
|
||||
if strings.Contains(err.Error(), "1146") {
|
||||
tableDef, err = findHTTPAccessLogTable(dao.Instance, day, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = dao.Query(tx).
|
||||
Table(tableDef.Name).
|
||||
Sets(fields).
|
||||
Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
remotelogs.Error("HTTP_ACCESS_LOG", err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if accessLogEnableAutoPartial && accessLogRowsPerTable > 0 && lastId%accessLogRowsPerTable == 0 {
|
||||
SharedHTTPAccessLogManager.ResetTable(dao.Instance, day)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -233,6 +235,10 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
|
||||
func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string,
|
||||
size int64,
|
||||
day string,
|
||||
hourFrom string,
|
||||
hourTo string,
|
||||
clusterId int64,
|
||||
nodeId int64,
|
||||
serverId int64,
|
||||
reverse bool,
|
||||
hasError bool,
|
||||
@@ -253,18 +259,36 @@ func (this *HTTPAccessLogDAO) ListAccessLogs(tx *dbs.Tx, lastRequestId string,
|
||||
size = 1000
|
||||
}
|
||||
|
||||
result, nextLastRequestId, err = this.listAccessLogs(tx, lastRequestId, size, day, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
|
||||
result, nextLastRequestId, err = this.listAccessLogs(tx, lastRequestId, size, day, hourFrom, hourTo, clusterId, nodeId, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
|
||||
if err != nil || int64(len(result)) < size {
|
||||
return
|
||||
}
|
||||
|
||||
moreResult, _, _ := this.listAccessLogs(tx, nextLastRequestId, 1, day, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
|
||||
moreResult, _, _ := this.listAccessLogs(tx, nextLastRequestId, 1, day, hourFrom, hourTo, clusterId, nodeId, serverId, reverse, hasError, firewallPolicyId, firewallRuleGroupId, firewallRuleSetId, hasFirewallPolicy, userId, keyword, ip, domain)
|
||||
hasMore = len(moreResult) > 0
|
||||
return
|
||||
}
|
||||
|
||||
// 读取往前的单页访问日志
|
||||
func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, size int64, day string, serverId int64, reverse bool, hasError bool, firewallPolicyId int64, firewallRuleGroupId int64, firewallRuleSetId int64, hasFirewallPolicy bool, userId int64, keyword string, ip string, domain string) (result []*HTTPAccessLog, nextLastRequestId string, err error) {
|
||||
func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx,
|
||||
lastRequestId string,
|
||||
size int64,
|
||||
day string,
|
||||
hourFrom string,
|
||||
hourTo string,
|
||||
clusterId int64,
|
||||
nodeId int64,
|
||||
serverId int64,
|
||||
reverse bool,
|
||||
hasError bool,
|
||||
firewallPolicyId int64,
|
||||
firewallRuleGroupId int64,
|
||||
firewallRuleSetId int64,
|
||||
hasFirewallPolicy bool,
|
||||
userId int64,
|
||||
keyword string,
|
||||
ip string,
|
||||
domain string) (result []*HTTPAccessLog, nextLastRequestId string, err error) {
|
||||
if size <= 0 {
|
||||
return nil, lastRequestId, nil
|
||||
}
|
||||
@@ -294,30 +318,69 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
}}
|
||||
}
|
||||
|
||||
locker := sync.Mutex{}
|
||||
// 查询某个集群下的节点
|
||||
var nodeIds = []int64{}
|
||||
if clusterId > 0 {
|
||||
nodeIds, err = SharedNodeDAO.FindAllEnabledNodeIdsWithClusterId(tx, clusterId)
|
||||
if err != nil {
|
||||
remotelogs.Error("DBNODE", err.Error())
|
||||
return
|
||||
}
|
||||
sort.Slice(nodeIds, func(i, j int) bool {
|
||||
return nodeIds[i] < nodeIds[j]
|
||||
})
|
||||
}
|
||||
|
||||
count := len(daoList)
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(count)
|
||||
// 准备查询
|
||||
var tableQueries = []*accessLogTableQuery{}
|
||||
for _, daoWrapper := range daoList {
|
||||
go func(daoWrapper *HTTPAccessLogDAOWrapper) {
|
||||
var instance = daoWrapper.DAO.Instance
|
||||
tableDefs, err := SharedHTTPAccessLogManager.FindTables(instance, day)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for _, def := range tableDefs {
|
||||
tableQueries = append(tableQueries, &accessLogTableQuery{
|
||||
daoWrapper: daoWrapper,
|
||||
name: def.Name,
|
||||
hasRemoteAddrField: def.HasRemoteAddr,
|
||||
hasDomainField: def.HasDomain,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var locker = sync.Mutex{}
|
||||
|
||||
var statusPrefixReg = regexp.MustCompile(`status:\s*(\d{3})\b`)
|
||||
var statusRangeReg = regexp.MustCompile(`status:\s*(\d{3})-(\d{3})\b`)
|
||||
|
||||
var count = len(tableQueries)
|
||||
var wg = &sync.WaitGroup{}
|
||||
wg.Add(count)
|
||||
for _, tableQuery := range tableQueries {
|
||||
go func(tableQuery *accessLogTableQuery) {
|
||||
defer wg.Done()
|
||||
|
||||
dao := daoWrapper.DAO
|
||||
|
||||
tableName, hasRemoteAddrField, hasDomainField, exists, err := findHTTPAccessLogTableName(dao.Instance, day)
|
||||
if err != nil {
|
||||
logs.Println("[DB_NODE]" + err.Error())
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
// 表格不存在则跳过
|
||||
return
|
||||
}
|
||||
|
||||
query := dao.Query(tx)
|
||||
var dao = tableQuery.daoWrapper.DAO
|
||||
var query = dao.Query(tx)
|
||||
|
||||
// 条件
|
||||
if nodeId > 0 {
|
||||
query.Attr("nodeId", nodeId)
|
||||
} else if clusterId > 0 {
|
||||
if len(nodeIds) > 0 {
|
||||
var nodeIdStrings = []string{}
|
||||
for _, subNodeId := range nodeIds {
|
||||
nodeIdStrings = append(nodeIdStrings, types.String(subNodeId))
|
||||
}
|
||||
|
||||
query.Where("nodeId IN (" + strings.Join(nodeIdStrings, ",") + ")")
|
||||
query.Reuse(false)
|
||||
} else {
|
||||
// 如果没有节点,则直接返回空
|
||||
return
|
||||
}
|
||||
}
|
||||
if serverId > 0 {
|
||||
query.Attr("serverId", serverId)
|
||||
} else if userId > 0 && len(serverIds) > 0 {
|
||||
@@ -344,7 +407,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
// keyword
|
||||
if len(ip) > 0 {
|
||||
// TODO 支持IP范围
|
||||
if hasRemoteAddrField {
|
||||
if tableQuery.hasRemoteAddrField {
|
||||
// IP格式
|
||||
if strings.Contains(ip, ",") || strings.Contains(ip, "-") {
|
||||
rangeConfig, err := shared.ParseIPRange(ip)
|
||||
@@ -354,6 +417,9 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 去掉IPv6的[]
|
||||
ip = strings.Trim(ip, "[]")
|
||||
|
||||
query.Attr("remoteAddr", ip)
|
||||
query.UseIndex("remoteAddr")
|
||||
}
|
||||
@@ -363,7 +429,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
}
|
||||
}
|
||||
if len(domain) > 0 {
|
||||
if hasDomainField {
|
||||
if tableQuery.hasDomainField {
|
||||
if strings.Contains(domain, "*") {
|
||||
domain = strings.ReplaceAll(domain, "*", "%")
|
||||
domain = regexp.MustCompile(`[^a-zA-Z0-9-.%]`).ReplaceAllString(domain, "")
|
||||
@@ -378,11 +444,12 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
Param("host1", domain)
|
||||
}
|
||||
}
|
||||
|
||||
if len(keyword) > 0 {
|
||||
// remoteAddr
|
||||
if hasRemoteAddrField && net.ParseIP(keyword) != nil {
|
||||
if tableQuery.hasRemoteAddrField && net.ParseIP(keyword) != nil {
|
||||
query.Attr("remoteAddr", keyword)
|
||||
} else if hasRemoteAddrField && regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
|
||||
} else if tableQuery.hasRemoteAddrField && regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
|
||||
keyword = keyword[3:]
|
||||
pieces := strings.SplitN(keyword, ",", 2)
|
||||
if len(pieces) == 1 || len(pieces[1]) == 0 {
|
||||
@@ -390,12 +457,21 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
} else {
|
||||
query.Between("INET_ATON(remoteAddr)", utils.IP2Long(pieces[0]), utils.IP2Long(pieces[1]))
|
||||
}
|
||||
} else if statusRangeReg.MatchString(keyword) {
|
||||
var matches = statusRangeReg.FindStringSubmatch(keyword)
|
||||
query.Between("status", types.Int(matches[1]), types.Int(matches[2]))
|
||||
|
||||
// TODO 处理剩余的关键词
|
||||
} else if statusPrefixReg.MatchString(keyword) {
|
||||
var matches = statusPrefixReg.FindStringSubmatch(keyword)
|
||||
query.Attr("status", matches[1])
|
||||
// TODO 处理剩余的关键词
|
||||
} else {
|
||||
if regexp.MustCompile(`^ip:.+`).MatchString(keyword) {
|
||||
keyword = keyword[3:]
|
||||
}
|
||||
|
||||
useOriginKeyword := false
|
||||
var useOriginKeyword = false
|
||||
|
||||
where := "JSON_EXTRACT(content, '$.remoteAddr') LIKE :keyword OR JSON_EXTRACT(content, '$.requestURI') LIKE :keyword OR JSON_EXTRACT(content, '$.host') LIKE :keyword OR JSON_EXTRACT(content, '$.userAgent') LIKE :keyword"
|
||||
|
||||
@@ -421,13 +497,13 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
|
||||
// 响应状态码
|
||||
if regexp.MustCompile(`^\d{3}$`).MatchString(keyword) {
|
||||
where += " OR JSON_EXTRACT(content, '$.status')=:intKeyword"
|
||||
where += " OR status=:intKeyword"
|
||||
query.Param("intKeyword", types.Int(keyword))
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`^\d{3}-\d{3}$`).MatchString(keyword) {
|
||||
pieces := strings.Split(keyword, "-")
|
||||
where += " OR JSON_EXTRACT(content, '$.status') BETWEEN :intKeyword1 AND :intKeyword2"
|
||||
where += " OR status BETWEEN :intKeyword1 AND :intKeyword2"
|
||||
query.Param("intKeyword1", types.Int(pieces[0]))
|
||||
query.Param("intKeyword2", types.Int(pieces[1]))
|
||||
}
|
||||
@@ -445,6 +521,20 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
}
|
||||
}
|
||||
|
||||
// hourFrom - hourTo
|
||||
if len(hourFrom) > 0 && len(hourTo) > 0 {
|
||||
var hourFromInt = types.Int(hourFrom)
|
||||
var hourToInt = types.Int(hourTo)
|
||||
if hourFromInt >= 0 && hourFromInt <= 23 && hourToInt >= hourFromInt && hourToInt <= 23 {
|
||||
var y = types.Int(day[:4])
|
||||
var m = types.Int(day[4:6])
|
||||
var d = types.Int(day[6:])
|
||||
var timeFrom = time.Date(y, time.Month(m), d, hourFromInt, 0, 0, 0, time.Local)
|
||||
var timeTo = time.Date(y, time.Month(m), d, hourToInt, 59, 59, 0, time.Local)
|
||||
query.Between("createdAt", timeFrom.Unix(), timeTo.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
// offset
|
||||
if len(lastRequestId) > 0 {
|
||||
if !reverse {
|
||||
@@ -464,20 +554,21 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
|
||||
// 开始查询
|
||||
ones, err := query.
|
||||
Table(tableName).
|
||||
Table(tableQuery.name).
|
||||
Limit(size).
|
||||
FindAll()
|
||||
if err != nil {
|
||||
logs.Println("[DB_NODE]" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
locker.Lock()
|
||||
for _, one := range ones {
|
||||
accessLog := one.(*HTTPAccessLog)
|
||||
result = append(result, accessLog)
|
||||
}
|
||||
locker.Unlock()
|
||||
}(daoWrapper)
|
||||
}(tableQuery)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
@@ -498,7 +589,7 @@ func (this *HTTPAccessLogDAO) listAccessLogs(tx *dbs.Tx, lastRequestId string, s
|
||||
result = result[:size]
|
||||
}
|
||||
|
||||
requestId := result[len(result)-1].RequestId
|
||||
var requestId = result[len(result)-1].RequestId
|
||||
if reverse {
|
||||
lists.Reverse(result)
|
||||
}
|
||||
@@ -530,28 +621,36 @@ func (this *HTTPAccessLogDAO) FindAccessLogWithRequestId(tx *dbs.Tx, requestId s
|
||||
}}
|
||||
}
|
||||
|
||||
count := len(daoList)
|
||||
wg := &sync.WaitGroup{}
|
||||
// 准备查询
|
||||
var day = timeutil.FormatTime("Ymd", types.Int64(requestId[:10]))
|
||||
var tableQueries = []*accessLogTableQuery{}
|
||||
for _, daoWrapper := range daoList {
|
||||
var instance = daoWrapper.DAO.Instance
|
||||
tableDefs, err := SharedHTTPAccessLogManager.FindTables(instance, day)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, def := range tableDefs {
|
||||
tableQueries = append(tableQueries, &accessLogTableQuery{
|
||||
daoWrapper: daoWrapper,
|
||||
name: def.Name,
|
||||
hasRemoteAddrField: def.HasRemoteAddr,
|
||||
hasDomainField: def.HasDomain,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var count = len(tableQueries)
|
||||
var wg = &sync.WaitGroup{}
|
||||
wg.Add(count)
|
||||
var result *HTTPAccessLog = nil
|
||||
day := timeutil.FormatTime("Ymd", types.Int64(requestId[:10]))
|
||||
for _, daoWrapper := range daoList {
|
||||
go func(daoWrapper *HTTPAccessLogDAOWrapper) {
|
||||
for _, tableQuery := range tableQueries {
|
||||
go func(tableQuery *accessLogTableQuery) {
|
||||
defer wg.Done()
|
||||
|
||||
dao := daoWrapper.DAO
|
||||
|
||||
tableName, _, _, exists, err := findHTTPAccessLogTableName(dao.Instance, day)
|
||||
if err != nil {
|
||||
logs.Println("[DB_NODE]" + err.Error())
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
var dao = tableQuery.daoWrapper.DAO
|
||||
one, err := dao.Query(tx).
|
||||
Table(tableName).
|
||||
Table(tableQuery.name).
|
||||
Attr("requestId", requestId).
|
||||
Find()
|
||||
if err != nil {
|
||||
@@ -561,7 +660,7 @@ func (this *HTTPAccessLogDAO) FindAccessLogWithRequestId(tx *dbs.Tx, requestId s
|
||||
if one != nil {
|
||||
result = one.(*HTTPAccessLog)
|
||||
}
|
||||
}(daoWrapper)
|
||||
}(tableQuery)
|
||||
}
|
||||
wg.Wait()
|
||||
return result, nil
|
||||
@@ -597,11 +696,18 @@ func (this *HTTPAccessLogDAO) SetupQueue() {
|
||||
config.MaxLength = 100_000
|
||||
}
|
||||
|
||||
accessLogEnableAutoPartial = config.EnableAutoPartial
|
||||
if config.RowsPerTable > 0 {
|
||||
accessLogRowsPerTable = config.RowsPerTable
|
||||
}
|
||||
|
||||
if accessLogQueueMaxLength != config.MaxLength {
|
||||
accessLogQueueMaxLength = config.MaxLength
|
||||
oldAccessLogQueue = accessLogQueue
|
||||
accessLogQueue = make(chan *pb.HTTPAccessLog, config.MaxLength)
|
||||
}
|
||||
|
||||
remotelogs.Println("HTTP_ACCESS_LOG_QUEUE", "change queue max length: "+types.String(config.MaxLength)+", percent: "+types.String(config.Percent)+", countPerSecond: "+types.String(config.CountPerSecond))
|
||||
if Tea.IsTesting() {
|
||||
remotelogs.Println("HTTP_ACCESS_LOG_QUEUE", "change queue "+string(configJSON))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0, "", "", "")
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page(t *testing.T) {
|
||||
times := 0 // 防止循环次数太多
|
||||
for {
|
||||
before := time.Now()
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0, "", "", "")
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "")
|
||||
cost := time.Since(before).Seconds()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -111,7 +111,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Reverse(t *testing.T) {
|
||||
}
|
||||
|
||||
before := time.Now()
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), 0, true, false, 0, 0, 0, false, 0, "", "", "")
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), "", "", 0, 0, 0, true, false, 0, 0, 0, false, 0, "", "", "")
|
||||
cost := time.Since(before).Seconds()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -136,7 +136,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page_NotExists(t *testing.T) {
|
||||
times := 0 // 防止循环次数太多
|
||||
for {
|
||||
before := time.Now()
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), 0, false, false, 0, 0, 0, false, 0, "", "", "")
|
||||
accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), "", "", 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "")
|
||||
cost := time.Since(before).Seconds()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
297
internal/db/models/http_access_log_manager.go
Normal file
297
internal/db/models/http_access_log_manager.go
Normal file
@@ -0,0 +1,297 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 访问日志的两个表格形式
|
||||
var accessLogTableMainReg = regexp.MustCompile(`_(\d{8})$`)
|
||||
var accessLogTablePartialReg = regexp.MustCompile(`_(\d{8})_(\d{4})$`)
|
||||
|
||||
var SharedHTTPAccessLogManager = NewHTTPAccessLogManager()
|
||||
|
||||
type HTTPAccessLogManager struct {
|
||||
currentTableMapping map[string]*httpAccessLogDefinition // dsn => def
|
||||
|
||||
locker sync.Mutex
|
||||
}
|
||||
|
||||
func NewHTTPAccessLogManager() *HTTPAccessLogManager {
|
||||
return &HTTPAccessLogManager{
|
||||
currentTableMapping: map[string]*httpAccessLogDefinition{},
|
||||
}
|
||||
}
|
||||
|
||||
// FindTableNames 读取数据库中某日所有日志表名称
|
||||
func (this *HTTPAccessLogManager) FindTableNames(db *dbs.DB, day string) ([]string, error) {
|
||||
var results = []string{}
|
||||
|
||||
// 需要防止用户设置了表名自动小写
|
||||
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
|
||||
ones, columnNames, err := db.FindOnes(`SHOW TABLES LIKE '` + prefix + `'`)
|
||||
if err != nil {
|
||||
return nil, errors.New("query table names error: " + err.Error())
|
||||
}
|
||||
|
||||
var columnName = columnNames[0]
|
||||
|
||||
for _, one := range ones {
|
||||
var tableName = one[columnName].(string)
|
||||
|
||||
if lists.ContainsString(results, tableName) {
|
||||
continue
|
||||
}
|
||||
|
||||
if accessLogTableMainReg.MatchString(tableName) || accessLogTablePartialReg.MatchString(tableName) {
|
||||
results = append(results, tableName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 排序
|
||||
sort.Strings(results)
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// FindTables 读取数据库中某日所有日志表
|
||||
func (this *HTTPAccessLogManager) FindTables(db *dbs.DB, day string) ([]*httpAccessLogDefinition, error) {
|
||||
var results = []*httpAccessLogDefinition{}
|
||||
var tableNames = []string{}
|
||||
|
||||
// 需要防止用户设置了表名自动小写
|
||||
for _, prefix := range []string{"edgeHTTPAccessLogs_" + day + "%", "edgehttpaccesslogs_" + day + "%"} {
|
||||
ones, columnNames, err := db.FindOnes(`SHOW TABLES LIKE '` + prefix + `'`)
|
||||
if err != nil {
|
||||
return nil, errors.New("query table names error: " + err.Error())
|
||||
}
|
||||
|
||||
var columnName = columnNames[0]
|
||||
|
||||
for _, one := range ones {
|
||||
var tableName = one[columnName].(string)
|
||||
|
||||
if lists.ContainsString(tableNames, tableName) {
|
||||
continue
|
||||
}
|
||||
|
||||
if accessLogTableMainReg.MatchString(tableName) {
|
||||
tableNames = append(tableNames, tableName)
|
||||
|
||||
hasRemoteAddrField, hasDomainField, err := this.checkTableFields(db, tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results = append(results, &httpAccessLogDefinition{
|
||||
Name: tableName,
|
||||
HasRemoteAddr: hasRemoteAddrField,
|
||||
HasDomain: hasDomainField,
|
||||
Exists: true,
|
||||
})
|
||||
} else if accessLogTablePartialReg.MatchString(tableName) {
|
||||
tableNames = append(tableNames, tableName)
|
||||
|
||||
results = append(results, &httpAccessLogDefinition{
|
||||
Name: tableName,
|
||||
HasRemoteAddr: true,
|
||||
HasDomain: true,
|
||||
Exists: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 排序
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Name < results[j].Name
|
||||
})
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// FindTable 根据日期获取表名
|
||||
// 表名组成
|
||||
// - PREFIX_DAY
|
||||
// - PREFIX_DAY_0001
|
||||
func (this *HTTPAccessLogManager) FindTable(db *dbs.DB, day string, force bool) (*httpAccessLogDefinition, error) {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
config, err := db.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cacheKey = config.Dsn
|
||||
def, ok := this.currentTableMapping[cacheKey]
|
||||
if ok {
|
||||
return def, nil
|
||||
}
|
||||
|
||||
def, err = this.findTableWithoutCache(db, day, force)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
this.currentTableMapping[cacheKey] = def
|
||||
return def, nil
|
||||
}
|
||||
|
||||
// CreateTable 创建访问日志表格
|
||||
func (this *HTTPAccessLogManager) CreateTable(db *dbs.DB, tableName string) error {
|
||||
_, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
|
||||
if err != nil {
|
||||
// 快速判断错误方法
|
||||
mysqlErr, ok := err.(*mysql.MySQLError)
|
||||
if ok && mysqlErr.Number == 1050 { // Error 1050: Table 'xxx' already exists
|
||||
return nil
|
||||
}
|
||||
|
||||
// 防止二次包装过程中错误丢失的保底错误判断方法
|
||||
if strings.Contains(err.Error(), "Error 1050") {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetTable 清除某个数据库表名缓存
|
||||
func (this *HTTPAccessLogManager) ResetTable(db *dbs.DB, day string) {
|
||||
this.locker.Lock()
|
||||
defer this.locker.Unlock()
|
||||
|
||||
config, err := db.Config()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
delete(this.currentTableMapping, config.Dsn)
|
||||
}
|
||||
|
||||
// 查找某个表格
|
||||
func (this *HTTPAccessLogManager) findTableWithoutCache(db *dbs.DB, day string, force bool) (*httpAccessLogDefinition, error) {
|
||||
tableNames, err := this.FindTableNames(db, day)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var prefix = "edgeHTTPAccessLogs_" + day
|
||||
|
||||
if len(tableNames) == 0 {
|
||||
if force {
|
||||
err := this.CreateTable(db, prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &httpAccessLogDefinition{
|
||||
Name: prefix,
|
||||
HasRemoteAddr: true,
|
||||
HasDomain: true,
|
||||
Exists: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &httpAccessLogDefinition{
|
||||
Name: prefix,
|
||||
HasRemoteAddr: true,
|
||||
HasDomain: true,
|
||||
Exists: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var lastTableName = tableNames[len(tableNames)-1]
|
||||
if !force || !accessLogEnableAutoPartial || accessLogRowsPerTable <= 0 {
|
||||
hasRemoteAddrField, hasDomainField, err := this.checkTableFields(db, lastTableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &httpAccessLogDefinition{
|
||||
Name: lastTableName,
|
||||
HasRemoteAddr: hasRemoteAddrField,
|
||||
HasDomain: hasDomainField,
|
||||
Exists: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 检查是否生成下个分表
|
||||
lastId, err := db.FindCol(0, "SELECT id FROM "+lastTableName+" ORDER BY id DESC LIMIT 1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if lastId != nil {
|
||||
var lastInt64Id = types.Int64(lastId)
|
||||
if accessLogRowsPerTable > 0 && lastInt64Id >= accessLogRowsPerTable {
|
||||
// create next partial table
|
||||
var nextTableName = ""
|
||||
if accessLogTableMainReg.MatchString(lastTableName) {
|
||||
nextTableName = prefix + "_0001"
|
||||
} else if accessLogTablePartialReg.MatchString(lastTableName) {
|
||||
var matches = accessLogTablePartialReg.FindStringSubmatch(lastTableName)
|
||||
if len(matches) < 3 {
|
||||
return nil, errors.New("fatal error: invalid 'accessLogTablePartialReg'")
|
||||
}
|
||||
var lastPartial = matches[2]
|
||||
nextTableName = prefix + "_" + fmt.Sprintf("%04d", types.Int(lastPartial)+1)
|
||||
} else {
|
||||
nextTableName = prefix + "_0001"
|
||||
}
|
||||
|
||||
err = this.CreateTable(db, nextTableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &httpAccessLogDefinition{
|
||||
Name: nextTableName,
|
||||
HasRemoteAddr: true,
|
||||
HasDomain: true,
|
||||
Exists: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 检查字段
|
||||
hasRemoteAddrField, hasDomainField, err := this.checkTableFields(db, lastTableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &httpAccessLogDefinition{
|
||||
Name: lastTableName,
|
||||
HasRemoteAddr: hasRemoteAddrField,
|
||||
HasDomain: hasDomainField,
|
||||
Exists: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO 考虑缓存检查结果
|
||||
func (this *HTTPAccessLogManager) checkTableFields(db *dbs.DB, tableName string) (hasRemoteAddrField bool, hasDomainField bool, err error) {
|
||||
fields, _, err := db.FindOnes("SHOW FIELDS FROM " + tableName)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
for _, field := range fields {
|
||||
var fieldName = field.GetString("Field")
|
||||
if strings.ToLower(fieldName) == strings.ToLower("remoteAddr") {
|
||||
hasRemoteAddrField = true
|
||||
}
|
||||
if strings.ToLower(fieldName) == "domain" {
|
||||
hasDomainField = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
148
internal/db/models/http_access_log_manager_test.go
Normal file
148
internal/db/models/http_access_log_manager_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewHTTPAccessLogManager(t *testing.T) {
|
||||
var config = &dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
Connections: struct {
|
||||
Pool int `yaml:"pool"`
|
||||
Max int `yaml:"max"`
|
||||
Life string `yaml:"life"`
|
||||
LifeDuration time.Duration `yaml:",omitempty"`
|
||||
}{},
|
||||
Models: struct {
|
||||
Package string `yaml:"package"`
|
||||
}{},
|
||||
}
|
||||
|
||||
db, err := dbs.NewInstanceFromConfig(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var manager = models.SharedHTTPAccessLogManager
|
||||
err = manager.CreateTable(db, "accessLog_1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPAccessLogManager_FindTableNames(t *testing.T) {
|
||||
var config = &dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
Connections: struct {
|
||||
Pool int `yaml:"pool"`
|
||||
Max int `yaml:"max"`
|
||||
Life string `yaml:"life"`
|
||||
LifeDuration time.Duration `yaml:",omitempty"`
|
||||
}{},
|
||||
Models: struct {
|
||||
Package string `yaml:"package"`
|
||||
}{},
|
||||
}
|
||||
|
||||
db, err := dbs.NewInstanceFromConfig(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
var before = time.Now()
|
||||
tables, err := models.SharedHTTPAccessLogManager.FindTables(db, "20220306")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data, err := json.Marshal(tables)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(string(data))
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestHTTPAccessLogManager_FindTables(t *testing.T) {
|
||||
var config = &dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
Connections: struct {
|
||||
Pool int `yaml:"pool"`
|
||||
Max int `yaml:"max"`
|
||||
Life string `yaml:"life"`
|
||||
LifeDuration time.Duration `yaml:",omitempty"`
|
||||
}{},
|
||||
Models: struct {
|
||||
Package string `yaml:"package"`
|
||||
}{},
|
||||
}
|
||||
|
||||
db, err := dbs.NewInstanceFromConfig(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
var before = time.Now()
|
||||
tables, err := models.SharedHTTPAccessLogManager.FindTables(db, "20220306")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data, err := json.Marshal(tables)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(string(data))
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPAccessLogManager_FindTable(t *testing.T) {
|
||||
var config = &dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge_log?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
Connections: struct {
|
||||
Pool int `yaml:"pool"`
|
||||
Max int `yaml:"max"`
|
||||
Life string `yaml:"life"`
|
||||
LifeDuration time.Duration `yaml:",omitempty"`
|
||||
}{},
|
||||
Models: struct {
|
||||
Package string `yaml:"package"`
|
||||
}{},
|
||||
}
|
||||
|
||||
db, err := dbs.NewInstanceFromConfig(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
var before = time.Now()
|
||||
tableDef, err := models.SharedHTTPAccessLogManager.FindTable(db, "20220306", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data, err := json.Marshal(tableDef)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(string(data))
|
||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func (this *HTTPCachePolicyDAO) FindAllEnabledCachePolicies(tx *dbs.Tx) (result
|
||||
}
|
||||
|
||||
// CreateCachePolicy 创建缓存策略
|
||||
func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name string, description string, capacityJSON []byte, maxKeys int64, maxSizeJSON []byte, storageType string, storageOptionsJSON []byte) (int64, error) {
|
||||
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) {
|
||||
op := NewHTTPCachePolicyOperator()
|
||||
op.State = HTTPCachePolicyStateEnabled
|
||||
op.IsOn = isOn
|
||||
@@ -112,6 +112,7 @@ func (this *HTTPCachePolicyDAO) CreateCachePolicy(tx *dbs.Tx, isOn bool, name st
|
||||
if len(storageOptionsJSON) > 0 {
|
||||
op.Options = storageOptionsJSON
|
||||
}
|
||||
op.SyncCompressionCache = syncCompressionCache
|
||||
|
||||
// 默认的缓存条件
|
||||
cacheRef := &serverconfigs.HTTPCacheRef{
|
||||
@@ -182,13 +183,19 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
|
||||
|
||||
var storageOptions = &serverconfigs.HTTPFileCacheStorage{
|
||||
Dir: "/opt/cache",
|
||||
MemoryPolicy: &serverconfigs.HTTPCachePolicy{
|
||||
Capacity: &shared.SizeCapacity{
|
||||
Count: 1,
|
||||
Unit: shared.SizeCapacityUnitGB,
|
||||
},
|
||||
},
|
||||
}
|
||||
storageOptionsJSON, err := json.Marshal(storageOptions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, 0, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON)
|
||||
policyId, err := this.CreateCachePolicy(tx, true, "\""+name+"\"缓存策略", "默认创建的缓存策略", capacityJSON, 0, maxSizeJSON, serverconfigs.CachePolicyStorageFile, storageOptionsJSON, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -196,7 +203,7 @@ func (this *HTTPCachePolicyDAO) CreateDefaultCachePolicy(tx *dbs.Tx, name string
|
||||
}
|
||||
|
||||
// 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) error {
|
||||
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 {
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
@@ -217,6 +224,7 @@ func (this *HTTPCachePolicyDAO) UpdateCachePolicy(tx *dbs.Tx, policyId int64, is
|
||||
if len(storageOptionsJSON) > 0 {
|
||||
op.Options = storageOptionsJSON
|
||||
}
|
||||
op.SyncCompressionCache = syncCompressionCache
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -247,6 +255,7 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
||||
config.IsOn = policy.IsOn == 1
|
||||
config.Name = policy.Name
|
||||
config.Description = policy.Description
|
||||
config.SyncCompressionCache = policy.SyncCompressionCache == 1
|
||||
|
||||
// capacity
|
||||
if IsNotNull(policy.Capacity) {
|
||||
@@ -300,24 +309,38 @@ func (this *HTTPCachePolicyDAO) ComposeCachePolicy(tx *dbs.Tx, policyId int64, c
|
||||
}
|
||||
|
||||
// CountAllEnabledHTTPCachePolicies 计算可用缓存策略数量
|
||||
func (this *HTTPCachePolicyDAO) CountAllEnabledHTTPCachePolicies(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
func (this *HTTPCachePolicyDAO) CountAllEnabledHTTPCachePolicies(tx *dbs.Tx, clusterId int64, keyword string, storageType string) (int64, error) {
|
||||
query := this.Query(tx).
|
||||
State(HTTPCachePolicyStateEnabled)
|
||||
if clusterId > 0 {
|
||||
query.Where("id IN (SELECT cachePolicyId FROM " + SharedNodeClusterDAO.Table + " WHERE id=:clusterId)")
|
||||
query.Param("clusterId", clusterId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
if len(storageType) > 0 {
|
||||
query.Attr("type", storageType)
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListEnabledHTTPCachePolicies 列出单页的缓存策略
|
||||
func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, keyword string, offset int64, size int64) ([]*serverconfigs.HTTPCachePolicy, error) {
|
||||
func (this *HTTPCachePolicyDAO) ListEnabledHTTPCachePolicies(tx *dbs.Tx, clusterId int64, keyword string, storageType string, offset int64, size int64) ([]*serverconfigs.HTTPCachePolicy, error) {
|
||||
query := this.Query(tx).
|
||||
State(HTTPCachePolicyStateEnabled)
|
||||
if clusterId > 0 {
|
||||
query.Where("id IN (SELECT cachePolicyId FROM " + SharedNodeClusterDAO.Table + " WHERE id=:clusterId)")
|
||||
query.Param("clusterId", clusterId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
if len(storageType) > 0 {
|
||||
query.Attr("type", storageType)
|
||||
}
|
||||
ones, err := query.
|
||||
ResultPk().
|
||||
Offset(offset).
|
||||
|
||||
@@ -2,39 +2,41 @@ package models
|
||||
|
||||
// HTTPCachePolicy HTTP缓存策略
|
||||
type HTTPCachePolicy struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
TemplateId uint32 `field:"templateId"` // 模版ID
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 名称
|
||||
Capacity string `field:"capacity"` // 容量数据
|
||||
MaxKeys uint64 `field:"maxKeys"` // 最多Key值
|
||||
MaxSize string `field:"maxSize"` // 最大缓存内容尺寸
|
||||
Type string `field:"type"` // 存储类型
|
||||
Options string `field:"options"` // 存储选项
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
Description string `field:"description"` // 描述
|
||||
Refs string `field:"refs"` // 默认的缓存设置
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
TemplateId uint32 `field:"templateId"` // 模版ID
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 名称
|
||||
Capacity string `field:"capacity"` // 容量数据
|
||||
MaxKeys uint64 `field:"maxKeys"` // 最多Key值
|
||||
MaxSize string `field:"maxSize"` // 最大缓存内容尺寸
|
||||
Type string `field:"type"` // 存储类型
|
||||
Options string `field:"options"` // 存储选项
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
Description string `field:"description"` // 描述
|
||||
Refs string `field:"refs"` // 默认的缓存设置
|
||||
SyncCompressionCache uint8 `field:"syncCompressionCache"` // 是否同步写入压缩缓存
|
||||
}
|
||||
|
||||
type HTTPCachePolicyOperator struct {
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
TemplateId interface{} // 模版ID
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 名称
|
||||
Capacity interface{} // 容量数据
|
||||
MaxKeys interface{} // 最多Key值
|
||||
MaxSize interface{} // 最大缓存内容尺寸
|
||||
Type interface{} // 存储类型
|
||||
Options interface{} // 存储选项
|
||||
CreatedAt interface{} // 创建时间
|
||||
State interface{} // 状态
|
||||
Description interface{} // 描述
|
||||
Refs interface{} // 默认的缓存设置
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
TemplateId interface{} // 模版ID
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 名称
|
||||
Capacity interface{} // 容量数据
|
||||
MaxKeys interface{} // 最多Key值
|
||||
MaxSize interface{} // 最大缓存内容尺寸
|
||||
Type interface{} // 存储类型
|
||||
Options interface{} // 存储选项
|
||||
CreatedAt interface{} // 创建时间
|
||||
State interface{} // 状态
|
||||
Description interface{} // 描述
|
||||
Refs interface{} // 默认的缓存设置
|
||||
SyncCompressionCache interface{} // 是否同步写入压缩缓存
|
||||
}
|
||||
|
||||
func NewHTTPCachePolicyOperator() *HTTPCachePolicyOperator {
|
||||
|
||||
@@ -130,6 +130,16 @@ func (this *HTTPFirewallPolicyDAO) CreateFirewallPolicy(tx *dbs.Tx, userId int64
|
||||
if len(outboundJSON) > 0 {
|
||||
op.Outbound = outboundJSON
|
||||
}
|
||||
op.UseLocalFirewall = true
|
||||
|
||||
{
|
||||
synFloodJSON, err := json.Marshal(firewallconfigs.DefaultSYNFloodConfig())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.SynFlood = synFloodJSON
|
||||
}
|
||||
|
||||
err := this.Save(tx, op)
|
||||
return types.Int64(op.Id), err
|
||||
}
|
||||
@@ -249,7 +259,7 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicyInbound(tx *dbs.Tx, polic
|
||||
}
|
||||
|
||||
// UpdateFirewallPolicy 修改策略
|
||||
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte, blockOptionsJSON []byte, mode firewallconfigs.FirewallMode) error {
|
||||
func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int64, isOn bool, name string, description string, inboundJSON []byte, outboundJSON []byte, blockOptionsJSON []byte, mode firewallconfigs.FirewallMode, useLocalFirewall bool, synFloodConfig *firewallconfigs.SYNFloodConfig) error {
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
@@ -272,6 +282,18 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int
|
||||
if len(blockOptionsJSON) > 0 {
|
||||
op.BlockOptions = blockOptionsJSON
|
||||
}
|
||||
|
||||
if synFloodConfig != nil {
|
||||
synFloodConfigJSON, err := json.Marshal(synFloodConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.SynFlood = synFloodConfigJSON
|
||||
} else {
|
||||
op.SynFlood = "null"
|
||||
}
|
||||
|
||||
op.UseLocalFirewall = useLocalFirewall
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -281,8 +303,12 @@ func (this *HTTPFirewallPolicyDAO) UpdateFirewallPolicy(tx *dbs.Tx, policyId int
|
||||
}
|
||||
|
||||
// CountAllEnabledFirewallPolicies 计算所有可用的策略数量
|
||||
func (this *HTTPFirewallPolicyDAO) CountAllEnabledFirewallPolicies(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
func (this *HTTPFirewallPolicyDAO) CountAllEnabledFirewallPolicies(tx *dbs.Tx, clusterId int64, keyword string) (int64, error) {
|
||||
query := this.Query(tx)
|
||||
if clusterId > 0 {
|
||||
query.Where("id IN (SELECT httpFirewallPolicyId FROM " + SharedNodeClusterDAO.Table + " WHERE id=:clusterId)")
|
||||
query.Param("clusterId", clusterId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
@@ -296,8 +322,12 @@ func (this *HTTPFirewallPolicyDAO) CountAllEnabledFirewallPolicies(tx *dbs.Tx, k
|
||||
}
|
||||
|
||||
// ListEnabledFirewallPolicies 列出单页的策略
|
||||
func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*HTTPFirewallPolicy, err error) {
|
||||
func (this *HTTPFirewallPolicyDAO) ListEnabledFirewallPolicies(tx *dbs.Tx, clusterId int64, keyword string, offset int64, size int64) (result []*HTTPFirewallPolicy, err error) {
|
||||
query := this.Query(tx)
|
||||
if clusterId > 0 {
|
||||
query.Where("id IN (SELECT httpFirewallPolicyId FROM " + SharedNodeClusterDAO.Table + " WHERE id=:clusterId)")
|
||||
query.Param("clusterId", clusterId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
@@ -339,6 +369,7 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
||||
config.IsOn = policy.IsOn == 1
|
||||
config.Name = policy.Name
|
||||
config.Description = policy.Description
|
||||
config.UseLocalFirewall = policy.UseLocalFirewall == 1
|
||||
|
||||
if len(policy.Mode) == 0 {
|
||||
policy.Mode = firewallconfigs.FirewallModeDefend
|
||||
@@ -411,6 +442,16 @@ func (this *HTTPFirewallPolicyDAO) ComposeFirewallPolicy(tx *dbs.Tx, policyId in
|
||||
config.BlockOptions = blockAction
|
||||
}
|
||||
|
||||
// syn flood
|
||||
if len(policy.SynFlood) > 0 {
|
||||
var synFloodConfig = &firewallconfigs.SYNFloodConfig{}
|
||||
err = json.Unmarshal([]byte(policy.SynFlood), synFloodConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.SYNFlood = synFloodConfig
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, config)
|
||||
}
|
||||
|
||||
@@ -2,39 +2,43 @@ package models
|
||||
|
||||
// HTTPFirewallPolicy HTTP防火墙
|
||||
type HTTPFirewallPolicy struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
TemplateId uint32 `field:"templateId"` // 模版ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
ServerId uint32 `field:"serverId"` // 服务ID
|
||||
GroupId uint32 `field:"groupId"` // 服务分组ID
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 名称
|
||||
Description string `field:"description"` // 描述
|
||||
Inbound string `field:"inbound"` // 入站规则
|
||||
Outbound string `field:"outbound"` // 出站规则
|
||||
BlockOptions string `field:"blockOptions"` // BLOCK选项
|
||||
Mode string `field:"mode"` // 模式
|
||||
Id uint32 `field:"id"` // ID
|
||||
TemplateId uint32 `field:"templateId"` // 模版ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
ServerId uint32 `field:"serverId"` // 服务ID
|
||||
GroupId uint32 `field:"groupId"` // 服务分组ID
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 名称
|
||||
Description string `field:"description"` // 描述
|
||||
Inbound string `field:"inbound"` // 入站规则
|
||||
Outbound string `field:"outbound"` // 出站规则
|
||||
BlockOptions string `field:"blockOptions"` // BLOCK选项
|
||||
Mode string `field:"mode"` // 模式
|
||||
UseLocalFirewall uint8 `field:"useLocalFirewall"` // 是否自动使用本地防火墙
|
||||
SynFlood string `field:"synFlood"` // SynFlood防御设置
|
||||
}
|
||||
|
||||
type HTTPFirewallPolicyOperator struct {
|
||||
Id interface{} // ID
|
||||
TemplateId interface{} // 模版ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
ServerId interface{} // 服务ID
|
||||
GroupId interface{} // 服务分组ID
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 名称
|
||||
Description interface{} // 描述
|
||||
Inbound interface{} // 入站规则
|
||||
Outbound interface{} // 出站规则
|
||||
BlockOptions interface{} // BLOCK选项
|
||||
Mode interface{} // 模式
|
||||
Id interface{} // ID
|
||||
TemplateId interface{} // 模版ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
ServerId interface{} // 服务ID
|
||||
GroupId interface{} // 服务分组ID
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 名称
|
||||
Description interface{} // 描述
|
||||
Inbound interface{} // 入站规则
|
||||
Outbound interface{} // 出站规则
|
||||
BlockOptions interface{} // BLOCK选项
|
||||
Mode interface{} // 模式
|
||||
UseLocalFirewall interface{} // 是否自动使用本地防火墙
|
||||
SynFlood interface{} // SynFlood防御设置
|
||||
}
|
||||
|
||||
func NewHTTPFirewallPolicyOperator() *HTTPFirewallPolicyOperator {
|
||||
|
||||
@@ -434,6 +434,18 @@ func (this *HTTPWebDAO) ComposeWebConfig(tx *dbs.Tx, webId int64, cacheMap *util
|
||||
}
|
||||
}
|
||||
|
||||
// 请求脚本
|
||||
if len(web.RequestScripts) > 0 {
|
||||
var requestScriptsConfig = &serverconfigs.HTTPRequestScriptsConfig{}
|
||||
if len(web.RequestScripts) > 0 {
|
||||
err = json.Unmarshal([]byte(web.RequestScripts), requestScriptsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.RequestScripts = requestScriptsConfig
|
||||
}
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, config)
|
||||
}
|
||||
@@ -1119,6 +1131,43 @@ func (this *HTTPWebDAO) FindWebRequestLimit(tx *dbs.Tx, webId int64) (*servercon
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// UpdateWebRequestScripts 修改服务的请求脚本设置
|
||||
func (this *HTTPWebDAO) UpdateWebRequestScripts(tx *dbs.Tx, webId int64, config *serverconfigs.HTTPRequestScriptsConfig) error {
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = this.Query(tx).
|
||||
Pk(webId).
|
||||
Set("requestScripts", configJSON).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return this.NotifyUpdate(tx, webId)
|
||||
}
|
||||
|
||||
// FindWebRequestScripts 查找服务的脚本设置
|
||||
func (this *HTTPWebDAO) FindWebRequestScripts(tx *dbs.Tx, webId int64) (*serverconfigs.HTTPRequestScriptsConfig, error) {
|
||||
configString, err := this.Query(tx).
|
||||
Pk(webId).
|
||||
Result("requestScripts").
|
||||
FindStringCol("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config = &serverconfigs.HTTPRequestScriptsConfig{}
|
||||
if len(configString) == 0 {
|
||||
return config, nil
|
||||
}
|
||||
err = json.Unmarshal([]byte(configString), config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *HTTPWebDAO) NotifyUpdate(tx *dbs.Tx, webId int64) error {
|
||||
// server
|
||||
|
||||
@@ -34,6 +34,7 @@ type HTTPWeb struct {
|
||||
RemoteAddr string `field:"remoteAddr"` // 客户端IP配置
|
||||
MergeSlashes uint8 `field:"mergeSlashes"` // 是否合并路径中的斜杠
|
||||
RequestLimit string `field:"requestLimit"` // 请求限制
|
||||
RequestScripts string `field:"requestScripts"` // 请求脚本
|
||||
}
|
||||
|
||||
type HTTPWebOperator struct {
|
||||
@@ -69,6 +70,7 @@ type HTTPWebOperator struct {
|
||||
RemoteAddr interface{} // 客户端IP配置
|
||||
MergeSlashes interface{} // 是否合并路径中的斜杠
|
||||
RequestLimit interface{} // 请求限制
|
||||
RequestScripts interface{} // 请求脚本
|
||||
}
|
||||
|
||||
func NewHTTPWebOperator() *HTTPWebOperator {
|
||||
|
||||
@@ -2,6 +2,8 @@ package models
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
@@ -19,6 +21,20 @@ const (
|
||||
IPItemStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
goman.New(func() {
|
||||
var ticker = time.NewTicker(1 * time.Minute)
|
||||
for range ticker.C {
|
||||
err := SharedIPItemDAO.CleanExpiredIPItems(nil)
|
||||
if err != nil {
|
||||
remotelogs.Error("IPItemDAO", "clean expired ip items failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type IPItemType = string
|
||||
|
||||
const (
|
||||
@@ -156,7 +172,7 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
|
||||
return 0, err
|
||||
}
|
||||
|
||||
op := NewIPItemOperator()
|
||||
var op = NewIPItemOperator()
|
||||
op.ListId = listId
|
||||
op.IpFrom = ipFrom
|
||||
op.IpTo = ipTo
|
||||
@@ -179,6 +195,11 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
|
||||
op.SourceHTTPFirewallRuleGroupId = sourceHTTPFirewallRuleGroupId
|
||||
op.SourceHTTPFirewallRuleSetId = sourceHTTPFirewallRuleSetId
|
||||
|
||||
var autoAdded = listId == firewallconfigs.GlobalListId || sourceNodeId > 0 || sourceServerId > 0 || sourceHTTPFirewallPolicyId > 0
|
||||
if autoAdded {
|
||||
op.IsRead = 0
|
||||
}
|
||||
|
||||
op.State = IPItemStateEnabled
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
@@ -186,8 +207,8 @@ func (this *IPItemDAO) CreateIPItem(tx *dbs.Tx,
|
||||
}
|
||||
itemId := types.Int64(op.Id)
|
||||
|
||||
// 全局名单不需要即时更新,防止数量过多而导致性能问题
|
||||
if listId == firewallconfigs.GlobalListId {
|
||||
// 自动加入名单不需要即时更新,防止数量过多而导致性能问题
|
||||
if autoAdded {
|
||||
return itemId, nil
|
||||
}
|
||||
|
||||
@@ -286,35 +307,6 @@ func (this *IPItemDAO) ListIPItemsWithListId(tx *dbs.Tx, listId int64, keyword s
|
||||
|
||||
// ListIPItemsAfterVersion 根据版本号查找IP列表
|
||||
func (this *IPItemDAO) ListIPItemsAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*IPItem, err error) {
|
||||
// 将过期的设置为已删除,这样是为了在 expiredAt<UNIX_TIMESTAMP()边缘节点让过期的IP有一个执行删除的机会
|
||||
ones, _, err := this.Query(tx).
|
||||
ResultPk().
|
||||
Where("(expiredAt>0 AND expiredAt<=:timestamp)").
|
||||
Param("timestamp", time.Now().Unix()).
|
||||
State(IPItemStateEnabled).
|
||||
Limit(100).
|
||||
FindOnes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, one := range ones {
|
||||
var expiredId = one.GetInt64("id")
|
||||
newVersion, err := SharedIPListDAO.IncreaseVersion(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = this.Query(tx).
|
||||
Pk(expiredId).
|
||||
Set("state", IPItemStateDisabled).
|
||||
Set("expiredAt", 0).
|
||||
Set("version", newVersion).
|
||||
Update()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = this.Query(tx).
|
||||
// 这里不要设置状态参数,因为我们要知道哪些是删除的
|
||||
Gt("version", version).
|
||||
@@ -379,7 +371,7 @@ func (this *IPItemDAO) ExistsEnabledItem(tx *dbs.Tx, itemId int64) (bool, error)
|
||||
}
|
||||
|
||||
// CountAllEnabledIPItems 计算数量
|
||||
func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, ip string, listId int64) (int64, error) {
|
||||
func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, ip string, listId int64, unread bool) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if len(ip) > 0 {
|
||||
query.Attr("ipFrom", ip)
|
||||
@@ -389,6 +381,9 @@ func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, ip string, listId int6
|
||||
} else {
|
||||
query.Where("(listId=" + types.String(firewallconfigs.GlobalListId) + " OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE state=1))")
|
||||
}
|
||||
if unread {
|
||||
query.Attr("isRead", 0)
|
||||
}
|
||||
return query.
|
||||
State(IPItemStateEnabled).
|
||||
Where("(expiredAt=0 OR expiredAt>:expiredAt)").
|
||||
@@ -397,7 +392,7 @@ func (this *IPItemDAO) CountAllEnabledIPItems(tx *dbs.Tx, ip string, listId int6
|
||||
}
|
||||
|
||||
// ListAllEnabledIPItems 搜索所有IP
|
||||
func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, ip string, listId int64, offset int64, size int64) (result []*IPItem, err error) {
|
||||
func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, ip string, listId int64, unread bool, offset int64, size int64) (result []*IPItem, err error) {
|
||||
var query = this.Query(tx)
|
||||
if len(ip) > 0 {
|
||||
query.Attr("ipFrom", ip)
|
||||
@@ -407,6 +402,9 @@ func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, ip string, listId int64
|
||||
} else {
|
||||
query.Where("(listId=" + types.String(firewallconfigs.GlobalListId) + " OR listId IN (SELECT id FROM " + SharedIPListDAO.Table + " WHERE state=1))")
|
||||
}
|
||||
if unread {
|
||||
query.Attr("isRead", 0)
|
||||
}
|
||||
_, err = query.
|
||||
State(IPItemStateEnabled).
|
||||
Where("(expiredAt=0 OR expiredAt>:expiredAt)").
|
||||
@@ -419,6 +417,59 @@ func (this *IPItemDAO) ListAllEnabledIPItems(tx *dbs.Tx, ip string, listId int64
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateItemsRead 设置所有未已读
|
||||
func (this *IPItemDAO) UpdateItemsRead(tx *dbs.Tx) error {
|
||||
return this.Query(tx).
|
||||
Attr("isRead", 0).
|
||||
Set("isRead", 1).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// CleanExpiredIPItems 清除过期数据
|
||||
func (this *IPItemDAO) CleanExpiredIPItems(tx *dbs.Tx) error {
|
||||
// 删除 N 天之前过期的数据
|
||||
_, err := this.Query(tx).
|
||||
Where("expiredAt<=:timestamp").
|
||||
State(IPItemStateDisabled).
|
||||
Param("timestamp", time.Now().Unix()-7*86400). // N 天之前过期的
|
||||
Limit(10000). // 限制条数,防止数量过多导致超时
|
||||
Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 将过期的设置为已删除,这样是为了在 expiredAt<UNIX_TIMESTAMP()边缘节点让过期的IP有一个执行删除的机会
|
||||
ones, _, err := this.Query(tx).
|
||||
ResultPk().
|
||||
Where("(expiredAt>0 AND expiredAt<=:timestamp)").
|
||||
Param("timestamp", time.Now().Unix()).
|
||||
State(IPItemStateEnabled).
|
||||
Limit(500).
|
||||
FindOnes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, one := range ones {
|
||||
var expiredId = one.GetInt64("id")
|
||||
newVersion, err := SharedIPListDAO.IncreaseVersion(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 这里不重置过期时间用于清理
|
||||
_, err = this.Query(tx).
|
||||
Pk(expiredId).
|
||||
Set("state", IPItemStateDisabled).
|
||||
Set("version", newVersion).
|
||||
Update()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
|
||||
// 获取ListId
|
||||
@@ -445,7 +496,7 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
|
||||
return err
|
||||
}
|
||||
for _, clusterId := range clusterIds {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeIPItemChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeIPItemChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -453,7 +504,7 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
|
||||
} else {
|
||||
clusterIds, err := SharedNodeClusterDAO.FindAllEnabledNodeClusterIds(tx)
|
||||
for _, clusterId := range clusterIds {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeIPItemChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeIPItemChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -505,7 +556,7 @@ func (this *IPItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64) error {
|
||||
|
||||
if len(resultClusterIds) > 0 {
|
||||
for _, clusterId := range resultClusterIds {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeIPItemChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeIPItemChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestIPItemDAO_NotifyClustersUpdate(t *testing.T) {
|
||||
@@ -27,3 +31,34 @@ func TestIPItemDAO_DisableIPItemsWithListId(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestIPItemDAO_ListIPItemsAfterVersion(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
_, err := SharedIPItemDAO.ListIPItemsAfterVersion(tx, 0, 100)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestIPItemDAO_CreateManyIPs(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
var dao = NewIPItemDAO()
|
||||
var n = 10
|
||||
for i := 0; i < n; i++ {
|
||||
itemId, err := dao.CreateIPItem(tx, firewallconfigs.GlobalListId, "192."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255))+"."+types.String(rands.Int(0, 255)), "", time.Now().Unix()+86400, "test", IPItemTypeIPv4, "warning", 0, 0, 0, 0, 0, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = itemId
|
||||
/**err = dao.Query(tx).Pk(itemId).Set("state", 0).UpdateQuickly()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}**/
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ type IPItem struct {
|
||||
SourceHTTPFirewallPolicyId uint32 `field:"sourceHTTPFirewallPolicyId"` // 来源策略ID
|
||||
SourceHTTPFirewallRuleGroupId uint32 `field:"sourceHTTPFirewallRuleGroupId"` // 来源规则集分组ID
|
||||
SourceHTTPFirewallRuleSetId uint32 `field:"sourceHTTPFirewallRuleSetId"` // 来源规则集ID
|
||||
IsRead uint8 `field:"isRead"` // 是否已读
|
||||
}
|
||||
|
||||
type IPItemOperator struct {
|
||||
@@ -47,6 +48,7 @@ type IPItemOperator struct {
|
||||
SourceHTTPFirewallPolicyId interface{} // 来源策略ID
|
||||
SourceHTTPFirewallRuleGroupId interface{} // 来源规则集分组ID
|
||||
SourceHTTPFirewallRuleSetId interface{} // 来源规则集ID
|
||||
IsRead interface{} // 是否已读
|
||||
}
|
||||
|
||||
func NewIPItemOperator() *IPItemOperator {
|
||||
|
||||
@@ -184,6 +184,10 @@ func (this *IPListDAO) IncreaseVersion(tx *dbs.Tx) (int64, error) {
|
||||
|
||||
// CheckUserIPList 检查用户权限
|
||||
func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) error {
|
||||
if userId == 0 || listId == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
ok, err := this.Query(tx).
|
||||
Pk(listId).
|
||||
Attr("userId", userId).
|
||||
@@ -194,6 +198,18 @@ func (this *IPListDAO) CheckUserIPList(tx *dbs.Tx, userId int64, listId int64) e
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查是否被用户的服务所使用
|
||||
policyIds, err := SharedHTTPFirewallPolicyDAO.FindEnabledFirewallPolicyIdsWithIPListId(tx, listId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, policyId := range policyIds {
|
||||
if SharedHTTPFirewallPolicyDAO.CheckUserFirewallPolicy(tx, userId, policyId) == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
@@ -284,7 +300,7 @@ func (this *IPListDAO) NotifyUpdate(tx *dbs.Tx, listId int64, taskType NodeTaskT
|
||||
|
||||
if len(resultClusterIds) > 0 {
|
||||
for _, clusterId := range resultClusterIds {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, taskType)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, taskType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 创建管理员日志
|
||||
// CreateLog 创建管理员日志
|
||||
func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level string, description string, action string, ip string) error {
|
||||
op := NewLogOperator()
|
||||
op.Level = level
|
||||
@@ -57,7 +57,7 @@ func (this *LogDAO) CreateLog(tx *dbs.Tx, adminType string, adminId int64, level
|
||||
return err
|
||||
}
|
||||
|
||||
// 计算所有日志数量
|
||||
// CountLogs 计算所有日志数量
|
||||
func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword string, userType string) (int64, error) {
|
||||
dayFrom = this.formatDay(dayFrom)
|
||||
dayTo = this.formatDay(dayTo)
|
||||
@@ -86,7 +86,7 @@ func (this *LogDAO) CountLogs(tx *dbs.Tx, dayFrom string, dayTo string, keyword
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// 列出单页日志
|
||||
// ListLogs 列出单页日志
|
||||
func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom string, dayTo string, keyword string, userType string) (result []*Log, err error) {
|
||||
dayFrom = this.formatDay(dayFrom)
|
||||
dayTo = this.formatDay(dayTo)
|
||||
@@ -120,7 +120,7 @@ func (this *LogDAO) ListLogs(tx *dbs.Tx, offset int64, size int64, dayFrom strin
|
||||
return
|
||||
}
|
||||
|
||||
// 物理删除日志
|
||||
// DeleteLogPermanently 物理删除日志
|
||||
func (this *LogDAO) DeleteLogPermanently(tx *dbs.Tx, logId int64) error {
|
||||
if logId <= 0 {
|
||||
return errors.New("invalid logId")
|
||||
@@ -129,14 +129,14 @@ func (this *LogDAO) DeleteLogPermanently(tx *dbs.Tx, logId int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 物理删除所有日志
|
||||
// DeleteAllLogsPermanently 物理删除所有日志
|
||||
func (this *LogDAO) DeleteAllLogsPermanently(tx *dbs.Tx) error {
|
||||
_, err := this.Query(tx).
|
||||
Delete()
|
||||
return err
|
||||
}
|
||||
|
||||
// 物理删除某些天之前的日志
|
||||
// DeleteLogsPermanentlyBeforeDays 物理删除某些天之前的日志
|
||||
func (this *LogDAO) DeleteLogsPermanentlyBeforeDays(tx *dbs.Tx, days int) error {
|
||||
if days <= 0 {
|
||||
days = 0
|
||||
@@ -148,7 +148,7 @@ func (this *LogDAO) DeleteLogsPermanentlyBeforeDays(tx *dbs.Tx, days int) error
|
||||
return err
|
||||
}
|
||||
|
||||
// 计算当前日志容量大小
|
||||
// SumLogsSize 计算当前日志容量大小
|
||||
func (this *LogDAO) SumLogsSize() (int64, error) {
|
||||
col, err := this.Instance.FindCol(0, "SELECT DATA_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA=? AND TABLE_NAME=? LIMIT 1", this.Instance.Name(), this.Table)
|
||||
if err != nil {
|
||||
|
||||
@@ -334,7 +334,7 @@ func (this *MetricItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64, isPublic bool)
|
||||
return err
|
||||
}
|
||||
for _, clusterId := range clusterIds {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeConfigChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -346,7 +346,7 @@ func (this *MetricItemDAO) NotifyUpdate(tx *dbs.Tx, itemId int64, isPublic bool)
|
||||
return err
|
||||
}
|
||||
for _, clusterId := range clusterIds {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeConfigChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ func (this *NSDomainDAO) NotifyUpdate(tx *dbs.Tx, domainId int64) error {
|
||||
return err
|
||||
}
|
||||
if clusterId > 0 {
|
||||
return models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, models.NSNodeTaskTypeDomainChanged)
|
||||
return models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, models.NSNodeTaskTypeDomainChanged)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -199,7 +199,7 @@ func (this *NSKeyDAO) NotifyUpdate(tx *dbs.Tx, keyId int64) error {
|
||||
return err
|
||||
}
|
||||
if clusterId > 0 {
|
||||
err = models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, models.NSNodeTaskTypeKeyChanged)
|
||||
err = models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, models.NSNodeTaskTypeKeyChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ func (this *NSRecordDAO) NotifyUpdate(tx *dbs.Tx, recordId int64) error {
|
||||
}
|
||||
|
||||
if clusterId > 0 {
|
||||
err = models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, models.NSNodeTaskTypeRecordChanged)
|
||||
err = models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, models.NSNodeTaskTypeRecordChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ func (this *NSRouteDAO) NotifyUpdate(tx *dbs.Tx) error {
|
||||
return err
|
||||
}
|
||||
for _, clusterId := range clusterIds {
|
||||
err = models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, models.NSNodeTaskTypeRouteChanged)
|
||||
err = models.SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, models.NSNodeTaskTypeRouteChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func (this *NodeClusterDAO) CreateCluster(tx *dbs.Tx, adminId int64, name string
|
||||
}
|
||||
|
||||
// UpdateCluster 修改集群
|
||||
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, nodeTCPMaxConnections int32) error {
|
||||
func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, grantId int64, installDir string, timezone string, nodeMaxThreads int32, nodeTCPMaxConnections int32, autoOpenPorts bool) error {
|
||||
if clusterId <= 0 {
|
||||
return errors.New("invalid clusterId")
|
||||
}
|
||||
@@ -198,6 +198,7 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
|
||||
nodeTCPMaxConnections = 0
|
||||
}
|
||||
op.NodeTCPMaxConnections = nodeTCPMaxConnections
|
||||
op.AutoOpenPorts = autoOpenPorts
|
||||
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
@@ -206,6 +207,14 @@ func (this *NodeClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name stri
|
||||
return this.NotifyUpdate(tx, clusterId)
|
||||
}
|
||||
|
||||
// UpdateClusterIsPinned 设置集群是否置顶
|
||||
func (this *NodeClusterDAO) UpdateClusterIsPinned(tx *dbs.Tx, clusterId int64, isPinned bool) error {
|
||||
return this.Query(tx).
|
||||
Pk(clusterId).
|
||||
Set("isPinned", isPinned).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// CountAllEnabledClusters 计算所有集群数量
|
||||
func (this *NodeClusterDAO) CountAllEnabledClusters(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
query := this.Query(tx).
|
||||
@@ -229,6 +238,7 @@ func (this *NodeClusterDAO) ListEnabledClusters(tx *dbs.Tx, keyword string, offs
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
Desc("isPinned").
|
||||
DescPk().
|
||||
FindAll()
|
||||
return
|
||||
@@ -274,7 +284,7 @@ func (this *NodeClusterDAO) FindAllAPINodeAddrsWithCluster(tx *dbs.Tx, clusterId
|
||||
return nil, err
|
||||
}
|
||||
for _, apiNodeId := range apiNodeIds {
|
||||
apiNode, err := SharedAPINodeDAO.FindEnabledAPINode(tx, apiNodeId)
|
||||
apiNode, err := SharedAPINodeDAO.FindEnabledAPINode(tx, apiNodeId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -887,7 +897,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
|
||||
|
||||
cluster, err := this.Query(tx).
|
||||
Pk(clusterId).
|
||||
Result("timeZone", "nodeMaxThreads", "nodeTCPMaxConnections", "cachePolicyId", "httpFirewallPolicyId").
|
||||
Result("timeZone", "nodeMaxThreads", "nodeTCPMaxConnections", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts").
|
||||
Find()
|
||||
if err != nil || cluster == nil {
|
||||
return nil, err
|
||||
@@ -900,7 +910,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *NodeClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeConfigChanged)
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)
|
||||
}
|
||||
|
||||
// NotifyDNSUpdate 通知DNS更新
|
||||
|
||||
@@ -177,5 +177,5 @@ func (this *NodeClusterMetricItemDAO) ExistsClusterItem(tx *dbs.Tx, clusterId in
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *NodeClusterMetricItemDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeConfigChanged)
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, NodeTaskTypeConfigChanged)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ type NodeCluster struct {
|
||||
TimeZone string `field:"timeZone"` // 时区
|
||||
NodeMaxThreads uint32 `field:"nodeMaxThreads"` // 节点最大线程数
|
||||
NodeTCPMaxConnections uint32 `field:"nodeTCPMaxConnections"` // TCP最大连接数
|
||||
AutoOpenPorts uint8 `field:"autoOpenPorts"` // 是否自动尝试开放端口
|
||||
IsPinned uint8 `field:"isPinned"` // 是否置顶
|
||||
}
|
||||
|
||||
type NodeClusterOperator struct {
|
||||
@@ -59,6 +61,8 @@ type NodeClusterOperator struct {
|
||||
TimeZone interface{} // 时区
|
||||
NodeMaxThreads interface{} // 节点最大线程数
|
||||
NodeTCPMaxConnections interface{} // TCP最大连接数
|
||||
AutoOpenPorts interface{} // 是否自动尝试开放端口
|
||||
IsPinned interface{} // 是否置顶
|
||||
}
|
||||
|
||||
func NewNodeClusterOperator() *NodeClusterOperator {
|
||||
|
||||
@@ -456,9 +456,26 @@ func (this *NodeDAO) FindEnabledNodeClusterIds(tx *dbs.Tx, nodeId int64) (result
|
||||
return
|
||||
}
|
||||
|
||||
// FindEnabledNodeIdsWithClusterId 查找某个集群下的所有节点IDs
|
||||
func (this *NodeDAO) FindEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId int64) ([]int64, error) {
|
||||
ones, err := this.Query(tx).
|
||||
Attr("clusterId", clusterId).
|
||||
State(NodeClusterStateEnabled).
|
||||
ResultPk().
|
||||
FindAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = []int64{}
|
||||
for _, one := range ones {
|
||||
result = append(result, int64(one.(*Node).Id))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FindAllNodeIdsMatch 匹配节点并返回节点ID
|
||||
func (this *NodeDAO) FindAllNodeIdsMatch(tx *dbs.Tx, clusterId int64, includeSecondaryNodes bool, isOn configutils.BoolState) (result []int64, err error) {
|
||||
query := this.Query(tx)
|
||||
var query = this.Query(tx)
|
||||
query.State(NodeStateEnabled)
|
||||
if clusterId > 0 {
|
||||
if includeSecondaryNodes {
|
||||
@@ -518,11 +535,11 @@ func (this *NodeDAO) FindAllEnabledNodeIdsWithClusterId(tx *dbs.Tx, clusterId in
|
||||
func (this *NodeDAO) FindAllInactiveNodesWithClusterId(tx *dbs.Tx, clusterId int64) (result []*Node, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(NodeStateEnabled).
|
||||
Result("id", "name", "status").
|
||||
Attr("clusterId", clusterId).
|
||||
Attr("isOn", true). // 只监控启用的节点
|
||||
Attr("isInstalled", true). // 只监控已经安装的节点
|
||||
Attr("isActive", true). // 当前已经在线的
|
||||
Where("(status IS NULL OR (JSON_EXTRACT(status, '$.isActive')=false AND UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>10) OR UNIX_TIMESTAMP()-JSON_EXTRACT(status, '$.updatedAt')>120)").
|
||||
Attr("isActive", false).
|
||||
Result("id", "name").
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
@@ -827,6 +844,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
if clusterIndex == 0 {
|
||||
config.MaxThreads = int(nodeCluster.NodeMaxThreads)
|
||||
config.TCPMaxConnections = int(nodeCluster.NodeTCPMaxConnections)
|
||||
config.AutoOpenPorts = nodeCluster.AutoOpenPorts == 1
|
||||
}
|
||||
|
||||
clusterIndex++
|
||||
@@ -855,6 +873,8 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
}
|
||||
}
|
||||
|
||||
config.CacheDiskDir = node.CacheDiskDir
|
||||
|
||||
// TOA
|
||||
toaConfig, err := SharedNodeClusterDAO.FindClusterTOAConfig(tx, primaryClusterId, cacheMap)
|
||||
if err != nil {
|
||||
@@ -916,6 +936,25 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
|
||||
config.MetricItems = metricItems
|
||||
|
||||
// 产品
|
||||
adminUIConfig, err := SharedSysSettingDAO.ReadAdminUIConfig(tx, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if adminUIConfig != nil {
|
||||
config.ProductConfig = &nodeconfigs.ProductConfig{
|
||||
Name: adminUIConfig.ProductName,
|
||||
Version: adminUIConfig.Version,
|
||||
}
|
||||
}
|
||||
|
||||
// OCSP
|
||||
ocspVersion, err := SharedSSLCertDAO.FindCertOCSPLatestVersion(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.OCSPVersion = ocspVersion
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -1192,7 +1231,7 @@ func (this *NodeDAO) UpdateNodeSystem(tx *dbs.Tx, nodeId int64, maxCPU int32) er
|
||||
}
|
||||
|
||||
// UpdateNodeCache 设置缓存相关
|
||||
func (this *NodeDAO) UpdateNodeCache(tx *dbs.Tx, nodeId int64, maxCacheDiskCapacityJSON []byte, maxCacheMemoryCapacityJSON []byte) error {
|
||||
func (this *NodeDAO) UpdateNodeCache(tx *dbs.Tx, nodeId int64, maxCacheDiskCapacityJSON []byte, maxCacheMemoryCapacityJSON []byte, cacheDiskDir string) error {
|
||||
if nodeId <= 0 {
|
||||
return errors.New("invalid nodeId")
|
||||
}
|
||||
@@ -1204,6 +1243,7 @@ func (this *NodeDAO) UpdateNodeCache(tx *dbs.Tx, nodeId int64, maxCacheDiskCapac
|
||||
if len(maxCacheMemoryCapacityJSON) > 0 {
|
||||
op.MaxCacheMemoryCapacity = maxCacheMemoryCapacityJSON
|
||||
}
|
||||
op.CacheDiskDir = cacheDiskDir
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1458,7 +1498,7 @@ func (this *NodeDAO) NotifyUpdate(tx *dbs.Tx, nodeId int64) error {
|
||||
return err
|
||||
}
|
||||
if clusterId > 0 {
|
||||
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, NodeTaskTypeConfigChanged, 0)
|
||||
return SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, 0, NodeTaskTypeConfigChanged, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build community
|
||||
// +build community
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package models
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ func (this *NodeLogDAO) DeleteExpiredLogs(tx *dbs.Tx, days int) error {
|
||||
// CountNodeLogs 计算节点日志数量
|
||||
func (this *NodeLogDAO) CountNodeLogs(tx *dbs.Tx,
|
||||
role string,
|
||||
nodeClusterId int64,
|
||||
nodeId int64,
|
||||
serverId int64,
|
||||
originId int64,
|
||||
@@ -142,7 +143,8 @@ func (this *NodeLogDAO) CountNodeLogs(tx *dbs.Tx,
|
||||
dayTo string,
|
||||
keyword string,
|
||||
level string,
|
||||
isUnread bool) (int64, error) {
|
||||
isUnread bool,
|
||||
tag string) (int64, error) {
|
||||
query := this.Query(tx)
|
||||
if len(role) > 0 {
|
||||
query.Attr("role", role)
|
||||
@@ -150,11 +152,16 @@ func (this *NodeLogDAO) CountNodeLogs(tx *dbs.Tx,
|
||||
if nodeId > 0 {
|
||||
query.Attr("nodeId", nodeId)
|
||||
} else {
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleNode:
|
||||
query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE state=1 AND clusterId>0)")
|
||||
case nodeconfigs.NodeRoleDNS:
|
||||
query.Where("nodeId IN (SELECT id FROM edgeNSNodes WHERE state=1 AND clusterId > 0)") // 没有用 SharedNSNodeDAO() 因为有包循环引用的问题
|
||||
if nodeClusterId > 0 {
|
||||
query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE clusterId=:nodeClusterId AND state=1)")
|
||||
query.Param("nodeClusterId", nodeClusterId)
|
||||
} else {
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleNode:
|
||||
query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE state=1 AND clusterId>0)")
|
||||
case nodeconfigs.NodeRoleDNS:
|
||||
query.Where("nodeId IN (SELECT id FROM edgeNSNodes WHERE state=1 AND clusterId > 0)") // 没有用 SharedNSNodeDAO() 因为有包循环引用的问题
|
||||
}
|
||||
}
|
||||
}
|
||||
if serverId > 0 {
|
||||
@@ -181,6 +188,9 @@ func (this *NodeLogDAO) CountNodeLogs(tx *dbs.Tx,
|
||||
if isUnread {
|
||||
query.Attr("isRead", 0)
|
||||
}
|
||||
if len(tag) > 0 {
|
||||
query.Like("tag", "%"+tag+"%")
|
||||
}
|
||||
|
||||
return query.Count()
|
||||
}
|
||||
@@ -188,6 +198,7 @@ func (this *NodeLogDAO) CountNodeLogs(tx *dbs.Tx,
|
||||
// ListNodeLogs 列出单页日志
|
||||
func (this *NodeLogDAO) ListNodeLogs(tx *dbs.Tx,
|
||||
role string,
|
||||
nodeClusterId int64,
|
||||
nodeId int64,
|
||||
serverId int64,
|
||||
originId int64,
|
||||
@@ -198,6 +209,7 @@ func (this *NodeLogDAO) ListNodeLogs(tx *dbs.Tx,
|
||||
level string,
|
||||
fixedState configutils.BoolState,
|
||||
isUnread bool,
|
||||
tag string,
|
||||
offset int64,
|
||||
size int64) (result []*NodeLog, err error) {
|
||||
query := this.Query(tx)
|
||||
@@ -207,11 +219,16 @@ func (this *NodeLogDAO) ListNodeLogs(tx *dbs.Tx,
|
||||
if nodeId > 0 {
|
||||
query.Attr("nodeId", nodeId)
|
||||
} else {
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleNode:
|
||||
query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE state=1 AND clusterId>0)")
|
||||
case nodeconfigs.NodeRoleDNS:
|
||||
query.Where("nodeId IN (SELECT id FROM edgeNSNodes WHERE state=1 AND clusterId>0)") // 没有用 SharedNSNodeDAO() 因为有包循环引用的问题
|
||||
if nodeClusterId > 0 {
|
||||
query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE clusterId=:nodeClusterId AND state=1)")
|
||||
query.Param("nodeClusterId", nodeClusterId)
|
||||
} else {
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleNode:
|
||||
query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE state=1 AND clusterId>0)")
|
||||
case nodeconfigs.NodeRoleDNS:
|
||||
query.Where("nodeId IN (SELECT id FROM edgeNSNodes WHERE state=1 AND clusterId>0)") // 没有用 SharedNSNodeDAO() 因为有包循环引用的问题
|
||||
}
|
||||
}
|
||||
}
|
||||
if serverId > 0 {
|
||||
@@ -240,11 +257,19 @@ func (this *NodeLogDAO) ListNodeLogs(tx *dbs.Tx,
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
if len(level) > 0 {
|
||||
query.Attr("level", level)
|
||||
var pieces = strings.Split(level, ",")
|
||||
if len(pieces) == 1 {
|
||||
query.Attr("level", pieces[0])
|
||||
} else {
|
||||
query.Attr("level", pieces)
|
||||
}
|
||||
}
|
||||
if isUnread {
|
||||
query.Attr("isRead", 0)
|
||||
}
|
||||
if len(tag) > 0 {
|
||||
query.Like("tag", "%"+tag+"%")
|
||||
}
|
||||
_, err = query.
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
|
||||
@@ -31,6 +31,7 @@ type Node struct {
|
||||
DnsRoutes string `field:"dnsRoutes"` // DNS线路设置
|
||||
MaxCacheDiskCapacity string `field:"maxCacheDiskCapacity"` // 硬盘缓存容量
|
||||
MaxCacheMemoryCapacity string `field:"maxCacheMemoryCapacity"` // 内存缓存容量
|
||||
CacheDiskDir string `field:"cacheDiskDir"` // 缓存目录
|
||||
}
|
||||
|
||||
type NodeOperator struct {
|
||||
@@ -63,6 +64,7 @@ type NodeOperator struct {
|
||||
DnsRoutes interface{} // DNS线路设置
|
||||
MaxCacheDiskCapacity interface{} // 硬盘缓存容量
|
||||
MaxCacheMemoryCapacity interface{} // 内存缓存容量
|
||||
CacheDiskDir interface{} // 缓存目录
|
||||
}
|
||||
|
||||
func NewNodeOperator() *NodeOperator {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package models
|
||||
|
||||
// 区域计费设置
|
||||
// NodePriceItem 区域计费设置
|
||||
type NodePriceItem struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package models
|
||||
|
||||
// 节点区域
|
||||
// NodeRegion 节点区域
|
||||
type NodeRegion struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
|
||||
@@ -1 +1,18 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func (this *NodeRegion) DecodePriceMap() map[int64]float64 {
|
||||
var m = map[int64]float64{}
|
||||
if len(this.Prices) == 0 {
|
||||
return m
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(this.Prices), &m)
|
||||
if err != nil {
|
||||
// 忽略错误
|
||||
return m
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -49,17 +49,18 @@ func init() {
|
||||
}
|
||||
|
||||
// CreateNodeTask 创建单个节点任务
|
||||
func (this *NodeTaskDAO) CreateNodeTask(tx *dbs.Tx, role string, clusterId int64, nodeId int64, taskType NodeTaskType, version int64) error {
|
||||
func (this *NodeTaskDAO) CreateNodeTask(tx *dbs.Tx, role string, clusterId int64, nodeId int64, serverId int64, taskType NodeTaskType, version int64) error {
|
||||
if clusterId <= 0 || nodeId <= 0 {
|
||||
return nil
|
||||
}
|
||||
uniqueId := role + "@" + types.String(nodeId) + "@node@" + taskType
|
||||
updatedAt := time.Now().Unix()
|
||||
var uniqueId = role + "@" + types.String(nodeId) + "@node@" + types.String(serverId) + "@" + taskType
|
||||
var updatedAt = time.Now().Unix()
|
||||
_, _, err := this.Query(tx).
|
||||
InsertOrUpdate(maps.Map{
|
||||
"role": role,
|
||||
"clusterId": clusterId,
|
||||
"nodeId": nodeId,
|
||||
"serverId": serverId,
|
||||
"type": taskType,
|
||||
"uniqueId": uniqueId,
|
||||
"updatedAt": updatedAt,
|
||||
@@ -75,22 +76,24 @@ func (this *NodeTaskDAO) CreateNodeTask(tx *dbs.Tx, role string, clusterId int64
|
||||
"error": "",
|
||||
"isNotified": 0,
|
||||
"version": version,
|
||||
"serverId": serverId,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateClusterTask 创建集群任务
|
||||
func (this *NodeTaskDAO) CreateClusterTask(tx *dbs.Tx, role string, clusterId int64, taskType NodeTaskType) error {
|
||||
func (this *NodeTaskDAO) CreateClusterTask(tx *dbs.Tx, role string, clusterId int64, serverId int64, taskType NodeTaskType) error {
|
||||
if clusterId <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
uniqueId := role + "@" + types.String(clusterId) + "@cluster@" + taskType
|
||||
updatedAt := time.Now().Unix()
|
||||
var uniqueId = role + "@" + types.String(clusterId) + "@" + types.String(serverId) + "@cluster@" + types.String(serverId) + "@" + taskType
|
||||
var updatedAt = time.Now().Unix()
|
||||
_, _, err := this.Query(tx).
|
||||
InsertOrUpdate(maps.Map{
|
||||
"role": role,
|
||||
"clusterId": clusterId,
|
||||
"serverId": serverId,
|
||||
"nodeId": 0,
|
||||
"type": taskType,
|
||||
"uniqueId": uniqueId,
|
||||
@@ -107,12 +110,13 @@ func (this *NodeTaskDAO) CreateClusterTask(tx *dbs.Tx, role string, clusterId in
|
||||
"isNotified": 0,
|
||||
"error": "",
|
||||
"version": time.Now().UnixNano(),
|
||||
"serverId": serverId,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// ExtractNodeClusterTask 分解边缘节点集群任务
|
||||
func (this *NodeTaskDAO) ExtractNodeClusterTask(tx *dbs.Tx, clusterId int64, taskType NodeTaskType) error {
|
||||
func (this *NodeTaskDAO) ExtractNodeClusterTask(tx *dbs.Tx, clusterId int64, serverId int64, taskType NodeTaskType) error {
|
||||
nodeIds, err := SharedNodeDAO.FindAllNodeIdsMatch(tx, clusterId, true, configutils.BoolStateYes)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -131,7 +135,7 @@ func (this *NodeTaskDAO) ExtractNodeClusterTask(tx *dbs.Tx, clusterId int64, tas
|
||||
|
||||
var version = time.Now().UnixNano()
|
||||
for _, nodeId := range nodeIds {
|
||||
err = this.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, taskType, version)
|
||||
err = this.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, clusterId, nodeId, serverId, taskType, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -170,7 +174,7 @@ func (this *NodeTaskDAO) ExtractNSClusterTask(tx *dbs.Tx, clusterId int64, taskT
|
||||
|
||||
var version = time.Now().UnixNano()
|
||||
for _, nodeId := range nodeIds {
|
||||
err = this.CreateNodeTask(tx, nodeconfigs.NodeRoleDNS, clusterId, nodeId, taskType, version)
|
||||
err = this.CreateNodeTask(tx, nodeconfigs.NodeRoleDNS, clusterId, nodeId, 0, taskType, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -202,7 +206,8 @@ func (this *NodeTaskDAO) ExtractAllClusterTasks(tx *dbs.Tx, role string) error {
|
||||
clusterId := int64(one.(*NodeTask).ClusterId)
|
||||
switch role {
|
||||
case nodeconfigs.NodeRoleNode:
|
||||
err = this.ExtractNodeClusterTask(tx, clusterId, one.(*NodeTask).Type)
|
||||
var nodeTask = one.(*NodeTask)
|
||||
err = this.ExtractNodeClusterTask(tx, clusterId, int64(nodeTask.ServerId), nodeTask.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestNodeTaskDAO_CreateNodeTask(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, NodeTaskTypeConfigChanged, 0)
|
||||
err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, NodeTaskTypeConfigChanged, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ func TestNodeTaskDAO_CreateClusterTask(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, NodeTaskTypeConfigChanged)
|
||||
err := SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func TestNodeTaskDAO_ExtractClusterTask(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
var tx *dbs.Tx
|
||||
err := SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, NodeTaskTypeConfigChanged)
|
||||
err := SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ type NodeTask struct {
|
||||
Role string `field:"role"` // 节点角色
|
||||
NodeId uint32 `field:"nodeId"` // 节点ID
|
||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||
ServerId uint32 `field:"serverId"` // 服务ID
|
||||
Type string `field:"type"` // 任务类型
|
||||
UniqueId string `field:"uniqueId"` // 唯一ID:nodeId@type
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
|
||||
@@ -21,6 +22,7 @@ type NodeTaskOperator struct {
|
||||
Role interface{} // 节点角色
|
||||
NodeId interface{} // 节点ID
|
||||
ClusterId interface{} // 集群ID
|
||||
ServerId interface{} // 服务ID
|
||||
Type interface{} // 任务类型
|
||||
UniqueId interface{} // 唯一ID:nodeId@type
|
||||
UpdatedAt interface{} // 修改时间
|
||||
|
||||
@@ -57,12 +57,10 @@ func (this *NodeValueDAO) CreateValue(tx *dbs.Tx, clusterId int64, role nodeconf
|
||||
|
||||
// Clean 清除数据
|
||||
func (this *NodeValueDAO) Clean(tx *dbs.Tx) error {
|
||||
// 删除N天之前的所有数据
|
||||
expiredDays := 2
|
||||
day := timeutil.Format("Ymd", time.Now().AddDate(0, 0, -expiredDays))
|
||||
var hour = timeutil.Format("YmdH", time.Now().Add(-2*time.Hour))
|
||||
_, err := this.Query(tx).
|
||||
Where("day<=:day").
|
||||
Param("day", day).
|
||||
Where("hour<=:hour").
|
||||
Param("hour", hour).
|
||||
Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNodeValueDAO_CreateValue(t *testing.T) {
|
||||
dao := NewNodeValueDAO()
|
||||
var dao = NewNodeValueDAO()
|
||||
m := maps.Map{
|
||||
"hello": "world12344",
|
||||
}
|
||||
@@ -20,3 +20,12 @@ func TestNodeValueDAO_CreateValue(t *testing.T) {
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestNodeValueDAO_Clean(t *testing.T) {
|
||||
var dao = NewNodeValueDAO()
|
||||
err := dao.Clean(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
@@ -195,5 +195,5 @@ func (this *NSClusterDAO) FindClusterRecursion(tx *dbs.Tx, clusterId int64) ([]b
|
||||
|
||||
// NotifyUpdate 通知更改
|
||||
func (this *NSClusterDAO) NotifyUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, NSNodeTaskTypeConfigChanged)
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleDNS, clusterId, 0, NSNodeTaskTypeConfigChanged)
|
||||
}
|
||||
|
||||
@@ -87,8 +87,22 @@ func (this *OriginDAO) FindOriginName(tx *dbs.Tx, id int64) (string, error) {
|
||||
}
|
||||
|
||||
// CreateOrigin 创建源站
|
||||
func (this *OriginDAO) CreateOrigin(tx *dbs.Tx, adminId int64, userId int64, name string, addrJSON string, description string, weight int32, isOn bool, connTimeout *shared.TimeDuration, readTimeout *shared.TimeDuration, idleTimeout *shared.TimeDuration, maxConns int32, maxIdleConns int32, domains []string) (originId int64, err error) {
|
||||
op := NewOriginOperator()
|
||||
func (this *OriginDAO) CreateOrigin(tx *dbs.Tx,
|
||||
adminId int64,
|
||||
userId int64,
|
||||
name string,
|
||||
addrJSON string,
|
||||
description string,
|
||||
weight int32, isOn bool,
|
||||
connTimeout *shared.TimeDuration,
|
||||
readTimeout *shared.TimeDuration,
|
||||
idleTimeout *shared.TimeDuration,
|
||||
maxConns int32,
|
||||
maxIdleConns int32,
|
||||
certRef *sslconfigs.SSLCertRef,
|
||||
domains []string,
|
||||
host string) (originId int64, err error) {
|
||||
var op = NewOriginOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
op.IsOn = isOn
|
||||
@@ -133,6 +147,15 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx, adminId int64, userId int64, nam
|
||||
}
|
||||
op.Weight = weight
|
||||
|
||||
// cert
|
||||
if certRef != nil {
|
||||
certRefJSON, err := json.Marshal(certRef)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Cert = certRefJSON
|
||||
}
|
||||
|
||||
if len(domains) > 0 {
|
||||
domainsJSON, err := json.Marshal(domains)
|
||||
if err != nil {
|
||||
@@ -143,6 +166,8 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx, adminId int64, userId int64, nam
|
||||
op.Domains = "[]"
|
||||
}
|
||||
|
||||
op.Host = host
|
||||
|
||||
op.State = OriginStateEnabled
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
@@ -152,11 +177,25 @@ func (this *OriginDAO) CreateOrigin(tx *dbs.Tx, adminId int64, userId int64, nam
|
||||
}
|
||||
|
||||
// UpdateOrigin 修改源站
|
||||
func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx, originId int64, name string, addrJSON string, description string, weight int32, isOn bool, connTimeout *shared.TimeDuration, readTimeout *shared.TimeDuration, idleTimeout *shared.TimeDuration, maxConns int32, maxIdleConns int32, domains []string) error {
|
||||
func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
|
||||
originId int64,
|
||||
name string,
|
||||
addrJSON string,
|
||||
description string,
|
||||
weight int32,
|
||||
isOn bool,
|
||||
connTimeout *shared.TimeDuration,
|
||||
readTimeout *shared.TimeDuration,
|
||||
idleTimeout *shared.TimeDuration,
|
||||
maxConns int32,
|
||||
maxIdleConns int32,
|
||||
certRef *sslconfigs.SSLCertRef,
|
||||
domains []string,
|
||||
host string) error {
|
||||
if originId <= 0 {
|
||||
return errors.New("invalid originId")
|
||||
}
|
||||
op := NewOriginOperator()
|
||||
var op = NewOriginOperator()
|
||||
op.Id = originId
|
||||
op.Name = name
|
||||
op.Addr = addrJSON
|
||||
@@ -201,6 +240,17 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx, originId int64, name string, add
|
||||
op.IsOn = isOn
|
||||
op.Version = dbs.SQL("version+1")
|
||||
|
||||
// cert
|
||||
if certRef != nil {
|
||||
certRefJSON, err := json.Marshal(certRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.Cert = certRefJSON
|
||||
} else {
|
||||
op.Cert = dbs.SQL("NULL")
|
||||
}
|
||||
|
||||
if len(domains) > 0 {
|
||||
domainsJSON, err := json.Marshal(domains)
|
||||
if err != nil {
|
||||
@@ -211,6 +261,8 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx, originId int64, name string, add
|
||||
op.Domains = "[]"
|
||||
}
|
||||
|
||||
op.Host = host
|
||||
|
||||
err := this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -238,7 +290,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, cacheMap
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
config := &serverconfigs.OriginConfig{
|
||||
var config = &serverconfigs.OriginConfig{
|
||||
Id: int64(origin.Id),
|
||||
IsOn: origin.IsOn == 1,
|
||||
Version: int(origin.Version),
|
||||
|
||||
@@ -80,7 +80,17 @@ func (this *PlanDAO) FindPlanName(tx *dbs.Tx, id int64) (string, error) {
|
||||
}
|
||||
|
||||
// CreatePlan 创建套餐
|
||||
func (this *PlanDAO) CreatePlan(tx *dbs.Tx, name string, clusterId int64, trafficLimitJSON []byte, featuresJSON []byte, priceType serverconfigs.PlanPriceType, trafficPriceJSON []byte, monthlyPrice float32, seasonallyPrice float32, yearlyPrice float32) (int64, error) {
|
||||
func (this *PlanDAO) CreatePlan(tx *dbs.Tx,
|
||||
name string,
|
||||
clusterId int64,
|
||||
trafficLimitJSON []byte,
|
||||
featuresJSON []byte,
|
||||
priceType serverconfigs.PlanPriceType,
|
||||
trafficPriceJSON []byte,
|
||||
bandwidthPriceJSON []byte,
|
||||
monthlyPrice float32,
|
||||
seasonallyPrice float32,
|
||||
yearlyPrice float32) (int64, error) {
|
||||
var op = NewPlanOperator()
|
||||
op.Name = name
|
||||
op.ClusterId = clusterId
|
||||
@@ -94,6 +104,9 @@ func (this *PlanDAO) CreatePlan(tx *dbs.Tx, name string, clusterId int64, traffi
|
||||
if len(trafficPriceJSON) > 0 {
|
||||
op.TrafficPrice = trafficPriceJSON
|
||||
}
|
||||
if len(bandwidthPriceJSON) > 0 {
|
||||
op.BandwidthPrice = bandwidthPriceJSON
|
||||
}
|
||||
if monthlyPrice >= 0 {
|
||||
op.MonthlyPrice = monthlyPrice
|
||||
}
|
||||
@@ -109,7 +122,19 @@ func (this *PlanDAO) CreatePlan(tx *dbs.Tx, name string, clusterId int64, traffi
|
||||
}
|
||||
|
||||
// UpdatePlan 修改套餐
|
||||
func (this *PlanDAO) UpdatePlan(tx *dbs.Tx, planId int64, name string, isOn bool, clusterId int64, trafficLimitJSON []byte, featuresJSON []byte, priceType serverconfigs.PlanPriceType, trafficPriceJSON []byte, monthlyPrice float32, seasonallyPrice float32, yearlyPrice float32) error {
|
||||
func (this *PlanDAO) UpdatePlan(tx *dbs.Tx,
|
||||
planId int64,
|
||||
name string,
|
||||
isOn bool,
|
||||
clusterId int64,
|
||||
trafficLimitJSON []byte,
|
||||
featuresJSON []byte,
|
||||
priceType serverconfigs.PlanPriceType,
|
||||
trafficPriceJSON []byte,
|
||||
bandwidthPriceJSON []byte,
|
||||
monthlyPrice float32,
|
||||
seasonallyPrice float32,
|
||||
yearlyPrice float32) error {
|
||||
if planId <= 0 {
|
||||
return errors.New("invalid planId")
|
||||
}
|
||||
@@ -138,6 +163,9 @@ func (this *PlanDAO) UpdatePlan(tx *dbs.Tx, planId int64, name string, isOn bool
|
||||
if len(trafficPriceJSON) > 0 {
|
||||
op.TrafficPrice = trafficPriceJSON
|
||||
}
|
||||
if len(bandwidthPriceJSON) > 0 {
|
||||
op.BandwidthPrice = bandwidthPriceJSON
|
||||
}
|
||||
if monthlyPrice >= 0 {
|
||||
op.MonthlyPrice = monthlyPrice
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,7 @@ type Plan struct {
|
||||
TrafficLimit string `field:"trafficLimit"` // 流量限制
|
||||
Features string `field:"features"` // 允许的功能
|
||||
TrafficPrice string `field:"trafficPrice"` // 流量价格设定
|
||||
BandwidthPrice string `field:"bandwidthPrice"` // 带宽价格
|
||||
MonthlyPrice float64 `field:"monthlyPrice"` // 月付
|
||||
SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
|
||||
YearlyPrice float64 `field:"yearlyPrice"` // 年付
|
||||
@@ -25,6 +26,7 @@ type PlanOperator struct {
|
||||
TrafficLimit interface{} // 流量限制
|
||||
Features interface{} // 允许的功能
|
||||
TrafficPrice interface{} // 流量价格设定
|
||||
BandwidthPrice interface{} // 带宽价格
|
||||
MonthlyPrice interface{} // 月付
|
||||
SeasonallyPrice interface{} // 季付
|
||||
YearlyPrice interface{} // 年付
|
||||
|
||||
@@ -1 +1,38 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
)
|
||||
|
||||
// DecodeTrafficPrice 流量价格配置
|
||||
func (this *Plan) DecodeTrafficPrice() *serverconfigs.PlanTrafficPriceConfig {
|
||||
var config = &serverconfigs.PlanTrafficPriceConfig{}
|
||||
|
||||
if len(this.TrafficPrice) == 0 {
|
||||
return config
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(this.TrafficPrice), config)
|
||||
if err != nil {
|
||||
// 忽略错误
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// DecodeBandwidthPrice 带宽价格配置
|
||||
func (this *Plan) DecodeBandwidthPrice() *serverconfigs.PlanBandwidthPriceConfig {
|
||||
var config = &serverconfigs.PlanBandwidthPriceConfig{}
|
||||
|
||||
if len(this.BandwidthPrice) == 0 {
|
||||
return config
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(this.BandwidthPrice), config)
|
||||
if err != nil {
|
||||
// 忽略错误
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 启用条目
|
||||
// EnableRegionCity 启用条目
|
||||
func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -47,7 +47,7 @@ func (this *RegionCityDAO) EnableRegionCity(tx *dbs.Tx, id uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 禁用条目
|
||||
// DisableRegionCity 禁用条目
|
||||
func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -56,7 +56,7 @@ func (this *RegionCityDAO) DisableRegionCity(tx *dbs.Tx, id uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找启用中的条目
|
||||
// FindEnabledRegionCity 查找启用中的条目
|
||||
func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionCity, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -68,7 +68,7 @@ func (this *RegionCityDAO) FindEnabledRegionCity(tx *dbs.Tx, id int64) (*RegionC
|
||||
return result.(*RegionCity), err
|
||||
}
|
||||
|
||||
// 根据主键查找名称
|
||||
// FindRegionCityName 根据主键查找名称
|
||||
func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -76,7 +76,7 @@ func (this *RegionCityDAO) FindRegionCityName(tx *dbs.Tx, id uint32) (string, er
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// 根据数据ID查找城市
|
||||
// FindCityWithDataId 根据数据ID查找城市
|
||||
func (this *RegionCityDAO) FindCityWithDataId(tx *dbs.Tx, dataId string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("dataId", dataId).
|
||||
@@ -84,7 +84,7 @@ func (this *RegionCityDAO) FindCityWithDataId(tx *dbs.Tx, dataId string) (int64,
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// 创建城市
|
||||
// CreateCity 创建城市
|
||||
func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string, dataId string) (int64, error) {
|
||||
op := NewRegionCityOperator()
|
||||
op.ProvinceId = provinceId
|
||||
@@ -105,7 +105,7 @@ func (this *RegionCityDAO) CreateCity(tx *dbs.Tx, provinceId int64, name string,
|
||||
return types.Int64(op.Id), nil
|
||||
}
|
||||
|
||||
// 根据城市名查找城市ID
|
||||
// FindCityIdWithNameCacheable 根据城市名查找城市ID
|
||||
func (this *RegionCityDAO) FindCityIdWithNameCacheable(tx *dbs.Tx, provinceId int64, cityName string) (int64, error) {
|
||||
key := cityName + "@" + numberutils.FormatInt64(provinceId)
|
||||
|
||||
@@ -132,3 +132,12 @@ func (this *RegionCityDAO) FindCityIdWithNameCacheable(tx *dbs.Tx, provinceId in
|
||||
|
||||
return cityId, nil
|
||||
}
|
||||
|
||||
// FindAllEnabledCities 获取所有城市信息
|
||||
func (this *RegionCityDAO) FindAllEnabledCities(tx *dbs.Tx) (result []*RegionCity, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(RegionCityStateEnabled).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1 +1,18 @@
|
||||
package regions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
)
|
||||
|
||||
func (this *RegionCity) DecodeCodes() []string {
|
||||
if len(this.Codes) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
result := []string{}
|
||||
err := json.Unmarshal([]byte(this.Codes), &result)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 启用条目
|
||||
// EnableRegionProvider 启用条目
|
||||
func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -45,7 +45,7 @@ func (this *RegionProviderDAO) EnableRegionProvider(tx *dbs.Tx, id uint32) error
|
||||
return err
|
||||
}
|
||||
|
||||
// 禁用条目
|
||||
// DisableRegionProvider 禁用条目
|
||||
func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -54,8 +54,8 @@ func (this *RegionProviderDAO) DisableRegionProvider(tx *dbs.Tx, id uint32) erro
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找启用中的条目
|
||||
func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id uint32) (*RegionProvider, error) {
|
||||
// FindEnabledRegionProvider 查找启用中的条目
|
||||
func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id int64) (*RegionProvider, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Attr("state", RegionProviderStateEnabled).
|
||||
@@ -66,7 +66,7 @@ func (this *RegionProviderDAO) FindEnabledRegionProvider(tx *dbs.Tx, id uint32)
|
||||
return result.(*RegionProvider), err
|
||||
}
|
||||
|
||||
// 根据主键查找名称
|
||||
// FindRegionProviderName 根据主键查找名称
|
||||
func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
@@ -74,7 +74,7 @@ func (this *RegionProviderDAO) FindRegionProviderName(tx *dbs.Tx, id uint32) (st
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// 根据服务商名称查找服务商ID
|
||||
// FindProviderIdWithNameCacheable 根据服务商名称查找服务商ID
|
||||
func (this *RegionProviderDAO) FindProviderIdWithNameCacheable(tx *dbs.Tx, providerName string) (int64, error) {
|
||||
SharedCacheLocker.RLock()
|
||||
providerId, ok := regionProviderNameAndIdCacheMap[providerName]
|
||||
@@ -100,7 +100,7 @@ func (this *RegionProviderDAO) FindProviderIdWithNameCacheable(tx *dbs.Tx, provi
|
||||
return providerId, nil
|
||||
}
|
||||
|
||||
// 创建Provider
|
||||
// CreateProvider 创建Provider
|
||||
func (this *RegionProviderDAO) CreateProvider(tx *dbs.Tx, name string) (int64, error) {
|
||||
op := NewRegionProviderOperator()
|
||||
op.Name = name
|
||||
@@ -112,3 +112,12 @@ func (this *RegionProviderDAO) CreateProvider(tx *dbs.Tx, name string) (int64, e
|
||||
op.Codes = codesJSON
|
||||
return this.SaveInt64(tx, op)
|
||||
}
|
||||
|
||||
// FindAllEnabledProviders 查找所有服务商
|
||||
func (this *RegionProviderDAO) FindAllEnabledProviders(tx *dbs.Tx) (result []*RegionProvider, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(RegionProviderStateEnabled).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1 +1,18 @@
|
||||
package regions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
)
|
||||
|
||||
func (this *RegionProvider) DecodeCodes() []string {
|
||||
if len(this.Codes) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
result := []string{}
|
||||
err := json.Unmarshal([]byte(this.Codes), &result)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
|
||||
config.RequestURI = reverseProxy.RequestURI
|
||||
config.StripPrefix = reverseProxy.StripPrefix
|
||||
config.AutoFlush = reverseProxy.AutoFlush == 1
|
||||
config.FollowRedirects = reverseProxy.FollowRedirects == 1
|
||||
|
||||
schedulingConfig := &serverconfigs.SchedulingConfig{}
|
||||
if len(reverseProxy.Scheduling) > 0 && reverseProxy.Scheduling != "null" {
|
||||
@@ -312,12 +313,13 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
|
||||
idleTimeout *shared.TimeDuration,
|
||||
maxConns int32,
|
||||
maxIdleConns int32,
|
||||
proxyProtocolJSON []byte) error {
|
||||
proxyProtocolJSON []byte,
|
||||
followRedirects bool) error {
|
||||
if reverseProxyId <= 0 {
|
||||
return errors.New("invalid reverseProxyId")
|
||||
}
|
||||
|
||||
op := NewReverseProxyOperator()
|
||||
var op = NewReverseProxyOperator()
|
||||
op.Id = reverseProxyId
|
||||
|
||||
if requestHostType < 0 {
|
||||
@@ -329,6 +331,7 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
|
||||
op.RequestURI = requestURI
|
||||
op.StripPrefix = stripPrefix
|
||||
op.AutoFlush = autoFlush
|
||||
op.FollowRedirects = followRedirects
|
||||
|
||||
if len(addHeaders) == 0 {
|
||||
addHeaders = []string{}
|
||||
|
||||
@@ -24,6 +24,7 @@ type ReverseProxy struct {
|
||||
MaxConns uint32 `field:"maxConns"` // 最大并发连接数
|
||||
MaxIdleConns uint32 `field:"maxIdleConns"` // 最大空闲连接数
|
||||
ProxyProtocol string `field:"proxyProtocol"` // Proxy Protocol配置
|
||||
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
|
||||
}
|
||||
|
||||
type ReverseProxyOperator struct {
|
||||
@@ -49,6 +50,7 @@ type ReverseProxyOperator struct {
|
||||
MaxConns interface{} // 最大并发连接数
|
||||
MaxIdleConns interface{} // 最大空闲连接数
|
||||
ProxyProtocol interface{} // Proxy Protocol配置
|
||||
FollowRedirects interface{} // 回源跟随
|
||||
}
|
||||
|
||||
func NewReverseProxyOperator() *ReverseProxyOperator {
|
||||
|
||||
108
internal/db/models/server_bill_dao.go
Normal file
108
internal/db/models/server_bill_dao.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ServerBillDAO dbs.DAO
|
||||
|
||||
func NewServerBillDAO() *ServerBillDAO {
|
||||
return dbs.NewDAO(&ServerBillDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeServerBills",
|
||||
Model: new(ServerBill),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*ServerBillDAO)
|
||||
}
|
||||
|
||||
var SharedServerBillDAO *ServerBillDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedServerBillDAO = NewServerBillDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// CreateOrUpdateServerBill 创建账单
|
||||
func (this *ServerBillDAO) CreateOrUpdateServerBill(tx *dbs.Tx,
|
||||
userId int64,
|
||||
serverId int64,
|
||||
month string,
|
||||
userPlanId int64,
|
||||
planId int64,
|
||||
totalTrafficBytes int64,
|
||||
bandwidthPercentileBytes int64,
|
||||
bandwidthPercentile int,
|
||||
priceType string,
|
||||
fee float64) error {
|
||||
fee = math.Floor(fee*100) / 100
|
||||
return this.Query(tx).
|
||||
InsertOrUpdateQuickly(maps.Map{
|
||||
"userId": userId,
|
||||
"serverId": serverId,
|
||||
"month": month,
|
||||
"priceType": priceType,
|
||||
"amount": fee,
|
||||
"userPlanId": userPlanId,
|
||||
"planId": planId,
|
||||
"totalTrafficBytes": totalTrafficBytes,
|
||||
"bandwidthPercentileBytes": bandwidthPercentileBytes,
|
||||
"bandwidthPercentile": bandwidthPercentile,
|
||||
"createdAt": time.Now().Unix(),
|
||||
}, maps.Map{
|
||||
"userId": userId,
|
||||
"priceType": priceType,
|
||||
"amount": fee,
|
||||
"userPlanId": userPlanId,
|
||||
"planId": planId,
|
||||
"totalTrafficBytes": totalTrafficBytes,
|
||||
"bandwidthPercentileBytes": bandwidthPercentileBytes,
|
||||
"bandwidthPercentile": bandwidthPercentile,
|
||||
"createdAt": time.Now().Unix(),
|
||||
})
|
||||
}
|
||||
|
||||
// SumUserMonthlyAmount 计算总费用
|
||||
func (this *ServerBillDAO) SumUserMonthlyAmount(tx *dbs.Tx, userId int64, month string) (float64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("userId", userId).
|
||||
Attr("month", month).
|
||||
Sum("amount", 0)
|
||||
}
|
||||
|
||||
// CountServerBills 计算总账单数量
|
||||
func (this *ServerBillDAO) CountServerBills(tx *dbs.Tx, userId int64, month string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if len(month) > 0 {
|
||||
query.Attr("month", month)
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListServerBills 列出单页账单
|
||||
func (this *ServerBillDAO) ListServerBills(tx *dbs.Tx, userId int64, month string, offset int64, size int64) (result []*ServerBill, err error) {
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if len(month) > 0 {
|
||||
query.Attr("month", month)
|
||||
}
|
||||
_, err = query.
|
||||
Desc("serverId").
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
20
internal/db/models/server_bill_dao_test.go
Normal file
20
internal/db/models/server_bill_dao_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServerBillDAO_CreateOrUpdateServerBill(t *testing.T) {
|
||||
var dao = NewServerBillDAO()
|
||||
var tx *dbs.Tx
|
||||
var month = timeutil.Format("Y02")
|
||||
err := dao.CreateOrUpdateServerBill(tx, 1, 2, month, 4, 5, 6, 7, 95, "", 100)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
36
internal/db/models/server_bill_model.go
Normal file
36
internal/db/models/server_bill_model.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package models
|
||||
|
||||
// ServerBill 服务账单
|
||||
type ServerBill struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
ServerId uint32 `field:"serverId"` // 服务ID
|
||||
Amount float64 `field:"amount"` // 金额
|
||||
Month string `field:"month"` // 月份
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
UserPlanId uint32 `field:"userPlanId"` // 用户套餐ID
|
||||
PlanId uint32 `field:"planId"` // 套餐ID
|
||||
TotalTrafficBytes uint64 `field:"totalTrafficBytes"` // 总流量
|
||||
BandwidthPercentileBytes uint64 `field:"bandwidthPercentileBytes"` // 带宽百分位字节
|
||||
BandwidthPercentile uint8 `field:"bandwidthPercentile"` // 带宽百分位
|
||||
PriceType string `field:"priceType"` // 计费类型
|
||||
}
|
||||
|
||||
type ServerBillOperator struct {
|
||||
Id interface{} // ID
|
||||
UserId interface{} // 用户ID
|
||||
ServerId interface{} // 服务ID
|
||||
Amount interface{} // 金额
|
||||
Month interface{} // 月份
|
||||
CreatedAt interface{} // 创建时间
|
||||
UserPlanId interface{} // 用户套餐ID
|
||||
PlanId interface{} // 套餐ID
|
||||
TotalTrafficBytes interface{} // 总流量
|
||||
BandwidthPercentileBytes interface{} // 带宽百分位字节
|
||||
BandwidthPercentile interface{} // 带宽百分位
|
||||
PriceType interface{} // 计费类型
|
||||
}
|
||||
|
||||
func NewServerBillOperator() *ServerBillOperator {
|
||||
return &ServerBillOperator{}
|
||||
}
|
||||
1
internal/db/models/server_bill_model_ext.go
Normal file
1
internal/db/models/server_bill_model_ext.go
Normal file
@@ -0,0 +1 @@
|
||||
package models
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/rands"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -24,7 +26,7 @@ func init() {
|
||||
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||
goman.New(func() {
|
||||
for range ticker.C {
|
||||
err := SharedServerDailyStatDAO.Clean(nil, 30) // 只保留N天
|
||||
err := SharedServerDailyStatDAO.Clean(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
|
||||
if err != nil {
|
||||
logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
|
||||
}
|
||||
@@ -130,15 +132,15 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
|
||||
return nil
|
||||
}
|
||||
|
||||
// SumUserMonthly 根据用户计算某月合计
|
||||
// SumServerMonthlyWithRegion 根据服务计算某月合计
|
||||
// month 格式为YYYYMM
|
||||
func (this *ServerDailyStatDAO) SumUserMonthly(tx *dbs.Tx, userId int64, regionId int64, month string) (int64, error) {
|
||||
func (this *ServerDailyStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId int64, regionId int64, month string) (int64, error) {
|
||||
query := this.Query(tx)
|
||||
if regionId > 0 {
|
||||
query.Attr("regionId", regionId)
|
||||
}
|
||||
return query.Between("day", month+"01", month+"32").
|
||||
Attr("userId", userId).
|
||||
Attr("serverId", serverId).
|
||||
SumInt64("bytes", 0)
|
||||
}
|
||||
|
||||
@@ -156,16 +158,6 @@ func (this *ServerDailyStatDAO) SumUserMonthlyWithoutPlan(tx *dbs.Tx, userId int
|
||||
SumInt64("bytes", 0)
|
||||
}
|
||||
|
||||
// SumUserMonthlyFee 计算用户某个月费用
|
||||
// month 格式为YYYYMM
|
||||
func (this *ServerDailyStatDAO) SumUserMonthlyFee(tx *dbs.Tx, userId int64, month string) (float64, error) {
|
||||
return this.Query(tx).
|
||||
Attr("userId", userId).
|
||||
Between("day", month+"01", month+"32").
|
||||
Gt("fee", 0).
|
||||
Sum("fee", 0)
|
||||
}
|
||||
|
||||
// SumUserMonthlyPeek 获取某月带宽峰值
|
||||
// month 格式为YYYYMM
|
||||
func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, regionId int64, month string) (int64, error) {
|
||||
@@ -195,6 +187,15 @@ func (this *ServerDailyStatDAO) SumUserDaily(tx *dbs.Tx, userId int64, regionId
|
||||
SumInt64("bytes", 0)
|
||||
}
|
||||
|
||||
// SumUserMonthly 获取某月流量总和
|
||||
// month 格式为YYYYMM
|
||||
func (this *ServerDailyStatDAO) SumUserMonthly(tx *dbs.Tx, userId int64, month string) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Between("day", month+"01", month+"31").
|
||||
Attr("userId", userId).
|
||||
SumInt64("bytes", 0)
|
||||
}
|
||||
|
||||
// SumUserDailyPeek 获取某天带宽峰值
|
||||
// day 格式为YYYYMMDD
|
||||
func (this *ServerDailyStatDAO) SumUserDailyPeek(tx *dbs.Tx, userId int64, regionId int64, day string) (int64, error) {
|
||||
@@ -339,6 +340,59 @@ func (this *ServerDailyStatDAO) SumMonthlyStat(tx *dbs.Tx, serverId int64, month
|
||||
return
|
||||
}
|
||||
|
||||
// SumMonthlyBytes 获取某月内的流量
|
||||
// month 格式为YYYYMM
|
||||
func (this *ServerDailyStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, month string) (result int64, err error) {
|
||||
if !regexp.MustCompile(`^\d{6}$`).MatchString(month) {
|
||||
return
|
||||
}
|
||||
|
||||
return this.Query(tx).
|
||||
Result("SUM(bytes) AS bytes").
|
||||
Attr("serverId", serverId).
|
||||
Between("day", month+"01", month+"31").
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// FindMonthlyPercentile 获取某月内百分位
|
||||
func (this *ServerDailyStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int) (result int64, err error) {
|
||||
if percentile <= 0 {
|
||||
percentile = 95
|
||||
}
|
||||
if percentile > 100 {
|
||||
percentile = 100
|
||||
}
|
||||
|
||||
total, err := this.Query(tx).
|
||||
Attr("serverId", serverId).
|
||||
Between("day", month+"01", month+"31").
|
||||
Count()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if total == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var offset int64
|
||||
|
||||
if total > 1 {
|
||||
offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
|
||||
}
|
||||
result, err = this.Query(tx).
|
||||
Result("bytes").
|
||||
Attr("serverId", serverId).
|
||||
Between("day", month+"01", month+"31").
|
||||
Desc("bytes").
|
||||
Offset(offset).
|
||||
Limit(1).
|
||||
FindInt64Col(0)
|
||||
|
||||
// 因为是5分钟统计,所以需要除以300
|
||||
result = result / 300
|
||||
return
|
||||
}
|
||||
|
||||
// FindDailyStats 按天统计
|
||||
func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) {
|
||||
ones, err := this.Query(tx).
|
||||
@@ -428,6 +482,25 @@ func (this *ServerDailyStatDAO) FindTopUserStats(tx *dbs.Tx, hourFrom string, ho
|
||||
return
|
||||
}
|
||||
|
||||
// FindDistinctServerIds 查找所有有流量的服务ID列表
|
||||
// dayFrom YYYYMMDD
|
||||
// dayTo YYYYMMDD
|
||||
func (this *ServerDailyStatDAO) FindDistinctServerIds(tx *dbs.Tx, dayFrom string, dayTo string) (serverIds []int64, err error) {
|
||||
dayFrom = strings.ReplaceAll(dayFrom, "-", "")
|
||||
dayTo = strings.ReplaceAll(dayTo, "-", "")
|
||||
ones, _, err := this.Query(tx).
|
||||
Result("DISTINCT(serverId) AS serverId").
|
||||
Between("day", dayFrom, dayTo).
|
||||
FindOnes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, one := range ones {
|
||||
serverIds = append(serverIds, one.GetInt64("serverId"))
|
||||
}
|
||||
return serverIds, nil
|
||||
}
|
||||
|
||||
// UpdateStatFee 设置费用
|
||||
func (this *ServerDailyStatDAO) UpdateStatFee(tx *dbs.Tx, statId int64, fee float32) error {
|
||||
return this.Query(tx).
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
|
||||
func TestServerDailyStatDAO_SumUserMonthly(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
var tx *dbs.Tx
|
||||
bytes, err := NewServerDailyStatDAO().SumUserMonthly(tx, 1, 1, timeutil.Format("Ym"))
|
||||
bytes, err := NewServerDailyStatDAO().SumUserMonthly(tx, 1, timeutil.Format("Ym"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -68,9 +68,28 @@ func TestServerDailyStatDAO_SumMinutelyRequests(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
var tx *dbs.Tx
|
||||
|
||||
stat, err := NewServerDailyStatDAO().SumMinutelyStat(tx, 23, timeutil.Format("Ymd") + "1435")
|
||||
stat, err := NewServerDailyStatDAO().SumMinutelyStat(tx, 23, timeutil.Format("Ymd")+"1435")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
logs.PrintAsJSON(stat, t)
|
||||
}
|
||||
|
||||
func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
|
||||
var tx *dbs.Tx
|
||||
serverIds, err := NewServerDailyStatDAO().FindDistinctServerIds(tx, timeutil.Format("Ym01"), timeutil.Format("Ymd"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(serverIds)
|
||||
}
|
||||
|
||||
func TestServerDailyStatDAO_FindMonthlyPercentile(t *testing.T) {
|
||||
var tx *dbs.Tx
|
||||
var dao = NewServerDailyStatDAO()
|
||||
result, err := dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("result:", result)
|
||||
}
|
||||
|
||||
@@ -221,6 +221,7 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
|
||||
op.DnsName = dnsName
|
||||
|
||||
op.UserPlanId = userPlanId
|
||||
op.LastUserPlanId = userPlanId
|
||||
|
||||
op.Version = 1
|
||||
op.IsOn = 1
|
||||
@@ -1226,6 +1227,16 @@ func (this *ServerDAO) FindAllEnabledServerIdsWithSSLPolicyIds(tx *dbs.Tx, sslPo
|
||||
return
|
||||
}
|
||||
|
||||
// ExistEnabledUserServerWithSSLPolicyId 检查是否存在某个用户的策略
|
||||
func (this *ServerDAO) ExistEnabledUserServerWithSSLPolicyId(tx *dbs.Tx, userId int64, sslPolicyId int64) (bool, error) {
|
||||
return this.Query(tx).
|
||||
State(ServerStateEnabled).
|
||||
Attr("userId", userId).
|
||||
Where("(JSON_CONTAINS(https, :jsonQuery) OR JSON_CONTAINS(tls, :jsonQuery))").
|
||||
Param("jsonQuery", maps.Map{"sslPolicyRef": maps.Map{"sslPolicyId": sslPolicyId}}.AsJSON()).
|
||||
Exist()
|
||||
}
|
||||
|
||||
// CountEnabledServersWithWebIds 计算使用某个缓存策略的所有服务数量
|
||||
func (this *ServerDAO) CountEnabledServersWithWebIds(tx *dbs.Tx, webIds []int64) (count int64, err error) {
|
||||
if len(webIds) == 0 {
|
||||
@@ -1262,9 +1273,13 @@ func (this *ServerDAO) CountAllEnabledServersWithNodeClusterId(tx *dbs.Tx, clust
|
||||
}
|
||||
|
||||
// CountAllEnabledServersWithGroupId 计算使用某个分组的服务数量
|
||||
func (this *ServerDAO) CountAllEnabledServersWithGroupId(tx *dbs.Tx, groupId int64) (int64, error) {
|
||||
return this.Query(tx).
|
||||
State(ServerStateEnabled).
|
||||
func (this *ServerDAO) CountAllEnabledServersWithGroupId(tx *dbs.Tx, groupId int64, userId int64) (int64, error) {
|
||||
var query = this.Query(tx).
|
||||
State(ServerStateEnabled)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
return query.
|
||||
Where("JSON_CONTAINS(groupIds, :groupId)").
|
||||
Param("groupId", numberutils.FormatInt64(groupId)).
|
||||
Count()
|
||||
@@ -1496,11 +1511,11 @@ func (this *ServerDAO) UpdateUserServersClusterId(tx *dbs.Tx, userId int64, oldC
|
||||
}
|
||||
|
||||
if oldClusterId > 0 {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, oldClusterId, NodeTaskTypeConfigChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, oldClusterId, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, oldClusterId, NodeTaskTypeIPItemChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, oldClusterId, 0, NodeTaskTypeIPItemChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1511,11 +1526,11 @@ func (this *ServerDAO) UpdateUserServersClusterId(tx *dbs.Tx, userId int64, oldC
|
||||
}
|
||||
|
||||
if newClusterId > 0 {
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, newClusterId, NodeTaskTypeConfigChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, newClusterId, 0, NodeTaskTypeConfigChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, newClusterId, NodeTaskTypeIPItemChanged)
|
||||
err = SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, newClusterId, 0, NodeTaskTypeIPItemChanged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2238,6 +2253,7 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
|
||||
err = this.Query(tx).
|
||||
Pk(serverId).
|
||||
Set("userPlanId", userPlanId).
|
||||
Set("lastUserPlanId", userPlanId).
|
||||
Set("clusterId", plan.ClusterId).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
@@ -2246,6 +2262,19 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
|
||||
return this.NotifyUpdate(tx, serverId)
|
||||
}
|
||||
|
||||
// FindServerLastUserPlanIdAndUserId 查找最后使用的套餐
|
||||
func (this *ServerDAO) FindServerLastUserPlanIdAndUserId(tx *dbs.Tx, serverId int64) (userPlanId int64, userId int64, err error) {
|
||||
one, err := this.Query(tx).
|
||||
Pk(serverId).
|
||||
Result("lastUserPlanId", "userId").
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return int64(one.(*Server).LastUserPlanId), int64(one.(*Server).UserId), nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 同步集群
|
||||
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
|
||||
// 创建任务
|
||||
@@ -2256,7 +2285,7 @@ func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
|
||||
if clusterId == 0 {
|
||||
return nil
|
||||
}
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, NodeTaskTypeConfigChanged)
|
||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, serverId, NodeTaskTypeConfigChanged)
|
||||
}
|
||||
|
||||
// NotifyDNSUpdate 通知DNS更新
|
||||
|
||||
@@ -77,10 +77,11 @@ func (this *ServerGroupDAO) FindServerGroupName(tx *dbs.Tx, id int64) (string, e
|
||||
}
|
||||
|
||||
// CreateGroup 创建分组
|
||||
func (this *ServerGroupDAO) CreateGroup(tx *dbs.Tx, name string) (groupId int64, err error) {
|
||||
func (this *ServerGroupDAO) CreateGroup(tx *dbs.Tx, name string, userId int64) (groupId int64, err error) {
|
||||
op := NewServerGroupOperator()
|
||||
op.State = ServerGroupStateEnabled
|
||||
op.Name = name
|
||||
op.UserId = userId
|
||||
op.IsOn = true
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
@@ -102,9 +103,15 @@ func (this *ServerGroupDAO) UpdateGroup(tx *dbs.Tx, groupId int64, name string)
|
||||
}
|
||||
|
||||
// FindAllEnabledGroups 查找所有分组
|
||||
func (this *ServerGroupDAO) FindAllEnabledGroups(tx *dbs.Tx) (result []*ServerGroup, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(ServerGroupStateEnabled).
|
||||
func (this *ServerGroupDAO) FindAllEnabledGroups(tx *dbs.Tx, userId int64) (result []*ServerGroup, err error) {
|
||||
var query = this.Query(tx).
|
||||
State(ServerGroupStateEnabled)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
} else {
|
||||
query.Attr("userId", 0)
|
||||
}
|
||||
_, err = query.
|
||||
Desc("order").
|
||||
AscPk().
|
||||
Slice(&result).
|
||||
@@ -113,9 +120,13 @@ func (this *ServerGroupDAO) FindAllEnabledGroups(tx *dbs.Tx) (result []*ServerGr
|
||||
}
|
||||
|
||||
// UpdateGroupOrders 修改分组排序
|
||||
func (this *ServerGroupDAO) UpdateGroupOrders(tx *dbs.Tx, groupIds []int64) error {
|
||||
func (this *ServerGroupDAO) UpdateGroupOrders(tx *dbs.Tx, groupIds []int64, userId int64) error {
|
||||
for index, groupId := range groupIds {
|
||||
_, err := this.Query(tx).
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
_, err := query.
|
||||
Pk(groupId).
|
||||
Set("order", len(groupIds)-index).
|
||||
Update()
|
||||
@@ -383,6 +394,22 @@ func (this *ServerGroupDAO) FindEnabledGroupIdWithReverseProxyId(tx *dbs.Tx, rev
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// CheckUserGroup 检查用户分组
|
||||
func (this *ServerGroupDAO) CheckUserGroup(tx *dbs.Tx, userId int64, groupId int64) error {
|
||||
b, err := this.Query(tx).
|
||||
Pk(groupId).
|
||||
Attr("userId", userId).
|
||||
State(ServerGroupStateEnabled).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !b {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *ServerGroupDAO) NotifyUpdate(tx *dbs.Tx, groupId int64) error {
|
||||
serverIds, err := SharedServerDAO.FindAllEnabledServerIdsWithGroupId(tx, groupId)
|
||||
|
||||
@@ -43,6 +43,7 @@ type Server struct {
|
||||
TrafficLimitStatus string `field:"trafficLimitStatus"` // 流量限制状态
|
||||
TotalTraffic float64 `field:"totalTraffic"` // 总流量
|
||||
UserPlanId uint32 `field:"userPlanId"` // 所属套餐ID
|
||||
LastUserPlanId uint32 `field:"lastUserPlanId"` // 上一次使用的套餐
|
||||
}
|
||||
|
||||
type ServerOperator struct {
|
||||
@@ -87,6 +88,7 @@ type ServerOperator struct {
|
||||
TrafficLimitStatus interface{} // 流量限制状态
|
||||
TotalTraffic interface{} // 总流量
|
||||
UserPlanId interface{} // 所属套餐ID
|
||||
LastUserPlanId interface{} // 上一次使用的套餐
|
||||
}
|
||||
|
||||
func NewServerOperator() *ServerOperator {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
@@ -113,6 +114,8 @@ func (this *SSLCertDAO) CreateCert(tx *dbs.Tx, adminId int64, userId int64, isOn
|
||||
}
|
||||
op.CommonNames = commonNamesJSON
|
||||
|
||||
op.OcspIsUpdated = false
|
||||
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -121,11 +124,33 @@ func (this *SSLCertDAO) CreateCert(tx *dbs.Tx, adminId int64, userId int64, isOn
|
||||
}
|
||||
|
||||
// UpdateCert 修改证书
|
||||
func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx, certId int64, isOn bool, name string, description string, serverName string, isCA bool, certData []byte, keyData []byte, timeBeginAt int64, timeEndAt int64, dnsNames []string, commonNames []string) error {
|
||||
func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx,
|
||||
certId int64,
|
||||
isOn bool,
|
||||
name string,
|
||||
description string,
|
||||
serverName string,
|
||||
isCA bool,
|
||||
certData []byte,
|
||||
keyData []byte,
|
||||
timeBeginAt int64,
|
||||
timeEndAt int64,
|
||||
dnsNames []string, commonNames []string) error {
|
||||
if certId <= 0 {
|
||||
return errors.New("invalid certId")
|
||||
}
|
||||
op := NewSSLCertOperator()
|
||||
|
||||
oldOne, err := this.Query(tx).Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if oldOne == nil {
|
||||
return nil
|
||||
}
|
||||
var oldCert = oldOne.(*SSLCert)
|
||||
var dataIsChanged = bytes.Compare(certData, []byte(oldCert.CertData)) != 0 || bytes.Compare(keyData, []byte(oldCert.KeyData)) != 0
|
||||
|
||||
var op = NewSSLCertOperator()
|
||||
op.Id = certId
|
||||
op.IsOn = isOn
|
||||
op.Name = name
|
||||
@@ -156,6 +181,16 @@ func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx, certId int64, isOn bool, name str
|
||||
}
|
||||
op.CommonNames = commonNamesJSON
|
||||
|
||||
// OCSP
|
||||
if dataIsChanged {
|
||||
op.OcspIsUpdated = 0
|
||||
op.Ocsp = ""
|
||||
op.OcspUpdatedAt = 0
|
||||
op.OcspError = ""
|
||||
op.OcspTries = 0
|
||||
op.OcspExpiresAt = 0
|
||||
}
|
||||
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -195,6 +230,13 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, cacheMap *ut
|
||||
config.TimeBeginAt = int64(cert.TimeBeginAt)
|
||||
config.TimeEndAt = int64(cert.TimeEndAt)
|
||||
|
||||
// OCSP
|
||||
if int64(cert.OcspExpiresAt) > time.Now().Unix() {
|
||||
config.OCSP = []byte(cert.Ocsp)
|
||||
config.OCSPExpiresAt = int64(cert.OcspExpiresAt)
|
||||
}
|
||||
config.OCSPError = cert.OcspError
|
||||
|
||||
if IsNotNull(cert.DnsNames) {
|
||||
dnsNames := []string{}
|
||||
err := json.Unmarshal([]byte(cert.DnsNames), &dnsNames)
|
||||
@@ -356,6 +398,197 @@ func (this *SSLCertDAO) CheckUserCert(tx *dbs.Tx, certId int64, userId int64) er
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListCertsToUpdateOCSP 查找需要更新OCSP的证书
|
||||
func (this *SSLCertDAO) ListCertsToUpdateOCSP(tx *dbs.Tx, maxTries int, size int64) (result []*SSLCert, err error) {
|
||||
var nowTime = time.Now().Unix()
|
||||
var query = this.Query(tx).
|
||||
State(SSLCertStateEnabled).
|
||||
Lt("ocspExpiresAt", nowTime+120). // 提前 N 秒钟准备更新
|
||||
Lt("ocspTries", maxTries).
|
||||
Lt("timeBeginAt", nowTime).
|
||||
Gt("timeEndAt", nowTime)
|
||||
|
||||
// TODO 需要排除没有被server使用的policy,或许可以增加一个字段记录policy最近使用时间
|
||||
|
||||
// 检查函数
|
||||
var JSONArrayAggIsEnabled = false
|
||||
_, err = this.Object().Instance.Exec("SELECT JSON_ARRAYAGG('1')")
|
||||
if err == nil {
|
||||
JSONArrayAggIsEnabled = true
|
||||
}
|
||||
|
||||
if JSONArrayAggIsEnabled {
|
||||
query.Where("JSON_CONTAINS((SELECT JSON_ARRAYAGG(JSON_EXTRACT(certs, '$[*].certId')) FROM edgeSSLPolicies WHERE state=1 AND ocspIsOn=1 AND certs IS NOT NULL), CAST(id AS CHAR))")
|
||||
} else {
|
||||
query.Where("JSON_CONTAINS((SELECT REPLACE(GROUP_CONCAT(JSON_EXTRACT(certs, '$[*].certId')), '],[', ',') FROM edgeSSLPolicies WHERE state=1 AND ocspIsOn=1 AND certs IS NOT NULL), CAST(id AS CHAR))")
|
||||
}
|
||||
|
||||
_, err = query.
|
||||
Asc("ocspUpdatedAt").
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// ListCertOCSPAfterVersion 列出某个版本后的OCSP
|
||||
func (this *SSLCertDAO) ListCertOCSPAfterVersion(tx *dbs.Tx, version int64, size int64) (result []*SSLCert, err error) {
|
||||
// 不需要判断ocsp是否为空
|
||||
_, err = this.Query(tx).
|
||||
Result("id", "ocsp", "ocspUpdatedVersion", "ocspExpiresAt").
|
||||
State(SSLCertStateEnabled).
|
||||
Attr("ocspIsUpdated", 1).
|
||||
Gt("ocspUpdatedVersion", version).
|
||||
Asc("ocspUpdatedVersion").
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindCertOCSPLatestVersion 获取OCSP最新版本
|
||||
func (this *SSLCertDAO) FindCertOCSPLatestVersion(tx *dbs.Tx) (int64, error) {
|
||||
return this.Query(tx).
|
||||
Result("ocspUpdatedVersion").
|
||||
Desc("ocspUpdatedVersion").
|
||||
Limit(1).
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// PrepareCertOCSPUpdating 更新OCSP更新时间,以便于准备更新,相当于锁定
|
||||
func (this *SSLCertDAO) PrepareCertOCSPUpdating(tx *dbs.Tx, certId int64) error {
|
||||
return this.Query(tx).
|
||||
Pk(certId).
|
||||
Set("ocspUpdatedAt", time.Now().Unix()).
|
||||
UpdateQuickly()
|
||||
|
||||
}
|
||||
|
||||
// UpdateCertOCSP 修改OCSP
|
||||
func (this *SSLCertDAO) UpdateCertOCSP(tx *dbs.Tx, certId int64, ocsp []byte, expiresAt int64, hasErr bool, errString string) error {
|
||||
if hasErr && len(errString) == 0 {
|
||||
errString = "failed"
|
||||
}
|
||||
|
||||
version, err := SharedSysLockerDAO.Increase(tx, "SSL_CERT_OCSP_VERSION", 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ocsp == nil {
|
||||
ocsp = []byte{}
|
||||
}
|
||||
|
||||
// 限制长度
|
||||
if len(errString) > 300 {
|
||||
errString = errString[:300]
|
||||
}
|
||||
|
||||
var query = this.Query(tx).
|
||||
Pk(certId).
|
||||
Set("ocsp", ocsp).
|
||||
Set("ocspError", errString).
|
||||
Set("ocspIsUpdated", true).
|
||||
Set("ocspUpdatedAt", time.Now().Unix()).
|
||||
Set("ocspUpdatedVersion", version).
|
||||
Set("ocspExpiresAt", expiresAt)
|
||||
|
||||
if hasErr {
|
||||
query.Set("ocspTries", dbs.SQL("ocspTries+1"))
|
||||
} else {
|
||||
query.Set("ocspTries", 0)
|
||||
}
|
||||
|
||||
err = query.UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 注意:这里不通知更新,避免频繁的更新导致服务不稳定
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountAllSSLCertsWithOCSPError 计算有OCSP错误的证书数量
|
||||
func (this *SSLCertDAO) CountAllSSLCertsWithOCSPError(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword OR description LIKE :keyword OR dnsNames LIKE :keyword OR commonNames LIKE :keyword OR ocspError LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
|
||||
return query.
|
||||
State(SSLCertStateEnabled).
|
||||
Attr("ocspIsUpdated", true).
|
||||
Where("LENGTH(ocspError) > 0").
|
||||
Count()
|
||||
}
|
||||
|
||||
// ListSSLCertsWithOCSPError 列出有OCSP错误的证书
|
||||
func (this *SSLCertDAO) ListSSLCertsWithOCSPError(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*SSLCert, err error) {
|
||||
var query = this.Query(tx)
|
||||
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(name LIKE :keyword OR description LIKE :keyword OR dnsNames LIKE :keyword OR commonNames LIKE :keyword OR ocspError LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
|
||||
_, err = query.
|
||||
State(SSLCertStateEnabled).
|
||||
Attr("ocspIsUpdated", true).
|
||||
Where("LENGTH(ocspError) > 0").
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
DescPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// IgnoreSSLCertsWithOCSPError 忽略一组OCSP证书错误
|
||||
func (this *SSLCertDAO) IgnoreSSLCertsWithOCSPError(tx *dbs.Tx, certIds []int64) error {
|
||||
for _, certId := range certIds {
|
||||
err := this.Query(tx).
|
||||
Pk(certId).
|
||||
Set("ocspError", "").
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetSSLCertsWithOCSPError 重置一组证书OCSP错误状态
|
||||
func (this *SSLCertDAO) ResetSSLCertsWithOCSPError(tx *dbs.Tx, certIds []int64) error {
|
||||
for _, certId := range certIds {
|
||||
err := this.Query(tx).
|
||||
Pk(certId).
|
||||
Set("ocspIsUpdated", 0).
|
||||
Set("ocspUpdatedAt", 0).
|
||||
Set("ocspError", "").
|
||||
Set("ocspTries", 0).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetAllSSLCertsWithOCSPError 重置所有证书OCSP错误状态
|
||||
func (this *SSLCertDAO) ResetAllSSLCertsWithOCSPError(tx *dbs.Tx) error {
|
||||
return this.Query(tx).
|
||||
State(SSLCertStateEnabled).
|
||||
Attr("ocspIsUpdated", 1).
|
||||
Where("LENGTH(ocspError)>0").
|
||||
Set("ocspIsUpdated", 0).
|
||||
Set("ocspUpdatedAt", 0).
|
||||
Set("ocspError", "").
|
||||
Set("ocspTries", 0).
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更新
|
||||
func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
|
||||
policyIds, err := SharedSSLPolicyDAO.FindAllEnabledPolicyIdsWithCertId(tx, certId)
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
package models
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSSLCertDAO_ListCertsToUpdateOCSP(t *testing.T) {
|
||||
var dao = models.NewSSLCertDAO()
|
||||
certs, err := dao.ListCertsToUpdateOCSP(nil, 3600, 10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, cert := range certs {
|
||||
t.Log(cert.Id, cert.Name, "updatedAt:", cert.OcspUpdatedAt, timeutil.FormatTime("Y-m-d H:i:s", int64(cert.OcspUpdatedAt)), cert.OcspIsUpdated)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +1,66 @@
|
||||
package models
|
||||
|
||||
// SSL证书
|
||||
// SSLCert SSL证书
|
||||
type SSLCert struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 证书名
|
||||
Description string `field:"description"` // 描述
|
||||
CertData string `field:"certData"` // 证书内容
|
||||
KeyData string `field:"keyData"` // 密钥内容
|
||||
ServerName string `field:"serverName"` // 证书使用的主机名
|
||||
IsCA uint8 `field:"isCA"` // 是否为CA证书
|
||||
GroupIds string `field:"groupIds"` // 证书分组
|
||||
TimeBeginAt uint64 `field:"timeBeginAt"` // 开始时间
|
||||
TimeEndAt uint64 `field:"timeEndAt"` // 结束时间
|
||||
DnsNames string `field:"dnsNames"` // DNS名称列表
|
||||
CommonNames string `field:"commonNames"` // 发行单位列表
|
||||
IsACME uint8 `field:"isACME"` // 是否为ACME自动生成的
|
||||
AcmeTaskId uint64 `field:"acmeTaskId"` // ACME任务ID
|
||||
NotifiedAt uint64 `field:"notifiedAt"` // 最后通知时间
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
UserId uint32 `field:"userId"` // 用户ID
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Name string `field:"name"` // 证书名
|
||||
Description string `field:"description"` // 描述
|
||||
CertData string `field:"certData"` // 证书内容
|
||||
KeyData string `field:"keyData"` // 密钥内容
|
||||
ServerName string `field:"serverName"` // 证书使用的主机名
|
||||
IsCA uint8 `field:"isCA"` // 是否为CA证书
|
||||
GroupIds string `field:"groupIds"` // 证书分组
|
||||
TimeBeginAt uint64 `field:"timeBeginAt"` // 开始时间
|
||||
TimeEndAt uint64 `field:"timeEndAt"` // 结束时间
|
||||
DnsNames string `field:"dnsNames"` // DNS名称列表
|
||||
CommonNames string `field:"commonNames"` // 发行单位列表
|
||||
IsACME uint8 `field:"isACME"` // 是否为ACME自动生成的
|
||||
AcmeTaskId uint64 `field:"acmeTaskId"` // ACME任务ID
|
||||
NotifiedAt uint64 `field:"notifiedAt"` // 最后通知时间
|
||||
Ocsp string `field:"ocsp"` // OCSP缓存
|
||||
OcspIsUpdated uint8 `field:"ocspIsUpdated"` // OCSP是否已更新
|
||||
OcspUpdatedAt uint64 `field:"ocspUpdatedAt"` // OCSP更新时间
|
||||
OcspError string `field:"ocspError"` // OCSP更新错误
|
||||
OcspUpdatedVersion uint64 `field:"ocspUpdatedVersion"` // OCSP更新版本
|
||||
OcspExpiresAt uint64 `field:"ocspExpiresAt"` // OCSP过期时间(UTC)
|
||||
OcspTries uint32 `field:"ocspTries"` // OCSP尝试次数
|
||||
}
|
||||
|
||||
type SSLCertOperator struct {
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
UpdatedAt interface{} // 修改时间
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 证书名
|
||||
Description interface{} // 描述
|
||||
CertData interface{} // 证书内容
|
||||
KeyData interface{} // 密钥内容
|
||||
ServerName interface{} // 证书使用的主机名
|
||||
IsCA interface{} // 是否为CA证书
|
||||
GroupIds interface{} // 证书分组
|
||||
TimeBeginAt interface{} // 开始时间
|
||||
TimeEndAt interface{} // 结束时间
|
||||
DnsNames interface{} // DNS名称列表
|
||||
CommonNames interface{} // 发行单位列表
|
||||
IsACME interface{} // 是否为ACME自动生成的
|
||||
AcmeTaskId interface{} // ACME任务ID
|
||||
NotifiedAt interface{} // 最后通知时间
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
UpdatedAt interface{} // 修改时间
|
||||
IsOn interface{} // 是否启用
|
||||
Name interface{} // 证书名
|
||||
Description interface{} // 描述
|
||||
CertData interface{} // 证书内容
|
||||
KeyData interface{} // 密钥内容
|
||||
ServerName interface{} // 证书使用的主机名
|
||||
IsCA interface{} // 是否为CA证书
|
||||
GroupIds interface{} // 证书分组
|
||||
TimeBeginAt interface{} // 开始时间
|
||||
TimeEndAt interface{} // 结束时间
|
||||
DnsNames interface{} // DNS名称列表
|
||||
CommonNames interface{} // 发行单位列表
|
||||
IsACME interface{} // 是否为ACME自动生成的
|
||||
AcmeTaskId interface{} // ACME任务ID
|
||||
NotifiedAt interface{} // 最后通知时间
|
||||
Ocsp interface{} // OCSP缓存
|
||||
OcspIsUpdated interface{} // OCSP是否已更新
|
||||
OcspUpdatedAt interface{} // OCSP更新时间
|
||||
OcspError interface{} // OCSP更新错误
|
||||
OcspUpdatedVersion interface{} // OCSP更新版本
|
||||
OcspExpiresAt interface{} // OCSP过期时间(UTC)
|
||||
OcspTries interface{} // OCSP尝试次数
|
||||
}
|
||||
|
||||
func NewSSLCertOperator() *SSLCertOperator {
|
||||
|
||||
@@ -1 +1,31 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func (this *SSLCert) DecodeDNSNames() []string {
|
||||
if len(this.DnsNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
var err = json.Unmarshal([]byte(this.DnsNames), &result)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (this *SSLCert) DecodeCommonNames() []string {
|
||||
if len(this.CommonNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
var err = json.Unmarshal([]byte(this.CommonNames), &result)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -167,6 +167,9 @@ func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheM
|
||||
config.HSTS = hstsConfig
|
||||
}
|
||||
|
||||
// ocsp
|
||||
config.OCSPIsOn = policy.OcspIsOn == 1
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, config)
|
||||
}
|
||||
@@ -196,7 +199,7 @@ func (this *SSLPolicyDAO) FindAllEnabledPolicyIdsWithCertId(tx *dbs.Tx, certId i
|
||||
}
|
||||
|
||||
// CreatePolicy 创建Policy
|
||||
func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) (int64, error) {
|
||||
func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, ocspIsOn bool, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) (int64, error) {
|
||||
op := NewSSLPolicyOperator()
|
||||
op.State = SSLPolicyStateEnabled
|
||||
op.IsOn = true
|
||||
@@ -213,6 +216,8 @@ func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64,
|
||||
op.Hsts = hstsJSON
|
||||
}
|
||||
|
||||
op.OcspIsOn = ocspIsOn
|
||||
|
||||
op.ClientAuthType = clientAuthType
|
||||
if len(clientCACertsJSON) > 0 {
|
||||
op.ClientCACerts = clientCACertsJSON
|
||||
@@ -234,7 +239,7 @@ func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64,
|
||||
}
|
||||
|
||||
// UpdatePolicy 修改Policy
|
||||
func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) error {
|
||||
func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, ocspIsOn bool, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) error {
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
@@ -251,6 +256,8 @@ func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled
|
||||
op.Hsts = hstsJSON
|
||||
}
|
||||
|
||||
op.OcspIsOn = ocspIsOn
|
||||
|
||||
op.ClientAuthType = clientAuthType
|
||||
if len(clientCACertsJSON) > 0 {
|
||||
op.ClientCACerts = clientCACertsJSON
|
||||
@@ -274,9 +281,9 @@ func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled
|
||||
}
|
||||
|
||||
// CheckUserPolicy 检查是否为用户所属策略
|
||||
func (this *SSLPolicyDAO) CheckUserPolicy(tx *dbs.Tx, policyId int64, userId int64) error {
|
||||
func (this *SSLPolicyDAO) CheckUserPolicy(tx *dbs.Tx, userId int64, policyId int64) error {
|
||||
if policyId <= 0 || userId <= 0 {
|
||||
return errors.New("not found")
|
||||
return ErrNotFound
|
||||
}
|
||||
ok, err := this.Query(tx).
|
||||
State(SSLPolicyStateEnabled).
|
||||
@@ -287,7 +294,14 @@ func (this *SSLPolicyDAO) CheckUserPolicy(tx *dbs.Tx, policyId int64, userId int
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("not found")
|
||||
// 是否为当前用户的某个服务所用
|
||||
exists, err := SharedServerDAO.ExistEnabledUserServerWithSSLPolicyId(tx, userId, policyId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return ErrNotFound
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package models
|
||||
|
||||
//
|
||||
// SSLPolicy SSL配置策略
|
||||
type SSLPolicy struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||
@@ -14,6 +14,7 @@ type SSLPolicy struct {
|
||||
CipherSuites string `field:"cipherSuites"` // 加密算法套件
|
||||
Hsts string `field:"hsts"` // HSTS设置
|
||||
Http2Enabled uint8 `field:"http2Enabled"` // 是否启用HTTP/2
|
||||
OcspIsOn uint8 `field:"ocspIsOn"` // 是否启用OCSP
|
||||
State uint8 `field:"state"` // 状态
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
}
|
||||
@@ -31,6 +32,7 @@ type SSLPolicyOperator struct {
|
||||
CipherSuites interface{} // 加密算法套件
|
||||
Hsts interface{} // HSTS设置
|
||||
Http2Enabled interface{} // 是否启用HTTP/2
|
||||
OcspIsOn interface{} // 是否启用OCSP
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func init() {
|
||||
var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
|
||||
goman.New(func() {
|
||||
for range ticker.C {
|
||||
err := SharedServerDomainHourlyStatDAO.Clean(nil, 7) // 只保留7天
|
||||
err := SharedServerDomainHourlyStatDAO.Clean(nil, 7) // 只保留 N 天
|
||||
if err != nil {
|
||||
remotelogs.Error("ServerDomainHourlyStatDAO", "clean expired data failed: "+err.Error())
|
||||
}
|
||||
@@ -374,7 +374,9 @@ func (this *ServerDomainHourlyStatDAO) Clean(tx *dbs.Tx, days int) error {
|
||||
Table(table).
|
||||
Lt("hour", hour).
|
||||
Delete()
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -109,10 +109,13 @@ func (this *ServerHTTPFirewallDailyStatDAO) GroupDailyCount(tx *dbs.Tx, userId i
|
||||
}
|
||||
|
||||
// FindDailyStats 查询某个日期段内的记录
|
||||
func (this *ServerHTTPFirewallDailyStatDAO) FindDailyStats(tx *dbs.Tx, userId int64, serverId int64, action string, dayFrom string, dayTo string) (result []*ServerHTTPFirewallDailyStat, err error) {
|
||||
func (this *ServerHTTPFirewallDailyStatDAO) FindDailyStats(tx *dbs.Tx, userId int64, serverId int64, actions []string, dayFrom string, dayTo string) (result []*ServerHTTPFirewallDailyStat, err error) {
|
||||
if len(actions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
query := this.Query(tx).
|
||||
Between("day", dayFrom, dayTo).
|
||||
Attr("action", action)
|
||||
Attr("action", actions)
|
||||
if serverId > 0 {
|
||||
query.Attr("serverId", serverId)
|
||||
} else if userId > 0 {
|
||||
|
||||
@@ -30,7 +30,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// 开锁
|
||||
// Lock 开锁
|
||||
func (this *SysLockerDAO) Lock(tx *dbs.Tx, key string, timeout int64) (ok bool, err error) {
|
||||
maxErrors := 5
|
||||
for {
|
||||
@@ -103,7 +103,7 @@ func (this *SysLockerDAO) Lock(tx *dbs.Tx, key string, timeout int64) (ok bool,
|
||||
}
|
||||
}
|
||||
|
||||
// 解锁
|
||||
// Unlock 解锁
|
||||
func (this *SysLockerDAO) Unlock(tx *dbs.Tx, key string) error {
|
||||
_, err := this.Query(tx).
|
||||
Attr("key", key).
|
||||
@@ -112,7 +112,7 @@ func (this *SysLockerDAO) Unlock(tx *dbs.Tx, key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 增加版本号
|
||||
// Increase 增加版本号
|
||||
func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (int64, error) {
|
||||
if tx == nil {
|
||||
var result int64
|
||||
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/zero"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
@@ -138,6 +140,72 @@ func (this *SysSettingDAO) ReadGlobalConfig(tx *dbs.Tx) (*serverconfigs.GlobalCo
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// ReadUserServerConfig 读取用户服务配置
|
||||
func (this *SysSettingDAO) ReadUserServerConfig(tx *dbs.Tx) (*userconfigs.UserServerConfig, error) {
|
||||
valueJSON, err := this.ReadSetting(tx, systemconfigs.SettingCodeUserServerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(valueJSON) == 0 {
|
||||
return userconfigs.DefaultUserServerConfig(), nil
|
||||
}
|
||||
|
||||
var config = userconfigs.DefaultUserServerConfig()
|
||||
err = json.Unmarshal(valueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// ReadUserFinanceConfig 读取用户服务配置
|
||||
func (this *SysSettingDAO) ReadUserFinanceConfig(tx *dbs.Tx) (*userconfigs.UserFinanceConfig, error) {
|
||||
valueJSON, err := this.ReadSetting(tx, systemconfigs.SettingCodeUserFinanceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(valueJSON) == 0 {
|
||||
return userconfigs.DefaultUserFinanceConfig(), nil
|
||||
}
|
||||
|
||||
var config = userconfigs.DefaultUserFinanceConfig()
|
||||
err = json.Unmarshal(valueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// ReadAdminUIConfig 读取管理员界面配置
|
||||
func (this *SysSettingDAO) ReadAdminUIConfig(tx *dbs.Tx, cacheMap *utils.CacheMap) (*systemconfigs.AdminUIConfig, error) {
|
||||
var cacheKey = this.Table + ":ReadAdminUIConfig"
|
||||
if cacheMap != nil {
|
||||
cache, ok := cacheMap.Get(cacheKey)
|
||||
if ok && cache != nil {
|
||||
return cache.(*systemconfigs.AdminUIConfig), nil
|
||||
}
|
||||
}
|
||||
|
||||
valueJSON, err := this.ReadSetting(tx, systemconfigs.SettingCodeAdminUIConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(valueJSON) > 0 {
|
||||
var config = &systemconfigs.AdminUIConfig{}
|
||||
err = json.Unmarshal(valueJSON, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, config)
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
return &systemconfigs.AdminUIConfig{}, nil
|
||||
}
|
||||
|
||||
// NotifyUpdate 通知更改
|
||||
func (this *SysSettingDAO) NotifyUpdate(tx *dbs.Tx, code string) error {
|
||||
switch code {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
@@ -23,7 +22,7 @@ func init() {
|
||||
|
||||
goman.New(func() {
|
||||
// 自动生成账单任务
|
||||
var ticker = time.NewTicker(1 * time.Minute)
|
||||
var ticker = time.NewTicker(1 * time.Hour)
|
||||
for range ticker.C {
|
||||
// 是否已经生成了,如果已经生成了就跳过
|
||||
var lastMonth = timeutil.Format("Ym", time.Now().AddDate(0, -1, 0))
|
||||
@@ -136,7 +135,7 @@ func (this *UserBillDAO) FindUnpaidBills(tx *dbs.Tx, size int64) (result []*User
|
||||
}
|
||||
|
||||
// CreateBill 创建账单
|
||||
func (this *UserBillDAO) CreateBill(tx *dbs.Tx, userId int64, billType BillType, description string, amount float32, month string) error {
|
||||
func (this *UserBillDAO) CreateBill(tx *dbs.Tx, userId int64, billType BillType, description string, amount float64, month string, canPay bool) error {
|
||||
code, err := this.GenerateBillCode(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -149,9 +148,11 @@ func (this *UserBillDAO) CreateBill(tx *dbs.Tx, userId int64, billType BillType,
|
||||
"amount": amount,
|
||||
"month": month,
|
||||
"code": code,
|
||||
"isPaid": false,
|
||||
"isPaid": amount == 0,
|
||||
"canPay": canPay,
|
||||
}, maps.Map{
|
||||
"amount": amount,
|
||||
"canPay": canPay,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -172,19 +173,22 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(regions) == 0 {
|
||||
return nil
|
||||
|
||||
var priceItems []*NodePriceItem
|
||||
if len(regions) > 0 {
|
||||
priceItems, err = SharedNodePriceItemDAO.FindAllEnabledRegionPrices(tx, NodePriceTypeTraffic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
priceItems, err := SharedNodePriceItemDAO.FindAllEnabledRegionPrices(tx, NodePriceTypeTraffic)
|
||||
// 默认计费方式
|
||||
userFinanceConfig, err := SharedSysSettingDAO.ReadUserFinanceConfig(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(priceItems) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 计算套餐费用
|
||||
// 计算服务套餐费用
|
||||
plans, err := SharedPlanDAO.FindAllEnabledPlans(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -194,54 +198,220 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
|
||||
planMap[int64(plan.Id)] = plan
|
||||
}
|
||||
|
||||
stats, err := SharedServerDailyStatDAO.FindMonthlyStatsWithPlan(tx, month)
|
||||
var dayFrom = month + "01"
|
||||
var dayTo = month + "32"
|
||||
serverIds, err := SharedServerDailyStatDAO.FindDistinctServerIds(tx, dayFrom, dayTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, stat := range stats {
|
||||
plan, ok := planMap[int64(stat.PlanId)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if plan.PriceType != serverconfigs.PlanPriceTypeTraffic {
|
||||
continue
|
||||
}
|
||||
if len(plan.TrafficPrice) == 0 {
|
||||
continue
|
||||
}
|
||||
var priceConfig = &serverconfigs.PlanTrafficPrice{}
|
||||
err = json.Unmarshal([]byte(plan.TrafficPrice), priceConfig)
|
||||
var cacheMap = utils.NewCacheMap()
|
||||
var userIds = []int64{}
|
||||
for _, serverId := range serverIds {
|
||||
// 套餐类型
|
||||
userPlanId, userId, err := SharedServerDAO.FindServerLastUserPlanIdAndUserId(tx, serverId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if priceConfig.Base > 0 {
|
||||
var fee = priceConfig.Base * (float32(stat.Bytes) / 1024 / 1024 / 1024)
|
||||
err = SharedServerDailyStatDAO.UpdateStatFee(tx, int64(stat.Id), fee)
|
||||
if userId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
userIds = append(userIds, userId)
|
||||
if userPlanId == 0 {
|
||||
// 总流量
|
||||
totalTrafficBytes, err := SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 默认计费方式
|
||||
if userFinanceConfig != nil && userFinanceConfig.IsOn { // 默认计费方式
|
||||
switch userFinanceConfig.PriceType {
|
||||
case serverconfigs.PlanPriceTypeTraffic:
|
||||
var config = userFinanceConfig.TrafficPriceConfig
|
||||
var fee float64 = 0
|
||||
if config != nil && config.Base > 0 {
|
||||
fee = float64(totalTrafficBytes) / 1024 / 1024 / 1024 * float64(config.Base)
|
||||
}
|
||||
|
||||
// 百分位
|
||||
var percentile = 95
|
||||
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, userId, serverId, month, userPlanId, 0, totalTrafficBytes, percentileBytes, percentile, userFinanceConfig.PriceType, fee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case serverconfigs.PlanPriceTypeBandwidth:
|
||||
// 百分位
|
||||
var percentile = 95
|
||||
var config = userFinanceConfig.BandwidthPriceConfig
|
||||
if config != nil {
|
||||
percentile = config.Percentile
|
||||
if percentile <= 0 {
|
||||
percentile = 95
|
||||
} else if percentile > 100 {
|
||||
percentile = 100
|
||||
}
|
||||
}
|
||||
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var mb = float32(percentileBytes) / 1024 / 1024
|
||||
var price float32
|
||||
if config != nil {
|
||||
price = config.LookupPrice(mb)
|
||||
}
|
||||
var fee = float64(price)
|
||||
err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, userId, serverId, month, userPlanId, 0, totalTrafficBytes, percentileBytes, percentile, userFinanceConfig.PriceType, fee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else { // 区域流量计费
|
||||
var fee float64
|
||||
|
||||
for _, region := range regions {
|
||||
var regionId = int64(region.Id)
|
||||
var pricesMap = region.DecodePriceMap()
|
||||
if len(pricesMap) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
trafficBytes, err := SharedServerDailyStatDAO.SumServerMonthlyWithRegion(tx, serverId, regionId, month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if trafficBytes == 0 {
|
||||
continue
|
||||
}
|
||||
var itemId = SharedNodePriceItemDAO.SearchItemsWithBytes(priceItems, trafficBytes)
|
||||
if itemId == 0 {
|
||||
continue
|
||||
}
|
||||
price, ok := pricesMap[itemId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if price <= 0 {
|
||||
continue
|
||||
}
|
||||
var regionFee = float64(trafficBytes) / 1000 / 1000 / 1000 * 8 * price
|
||||
fee += regionFee
|
||||
}
|
||||
|
||||
// 百分位
|
||||
var percentile = 95
|
||||
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, userId, serverId, month, userPlanId, 0, totalTrafficBytes, percentileBytes, percentile, "", fee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
userPlan, err := SharedUserPlanDAO.FindUserPlanWithoutState(tx, userPlanId, cacheMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if userPlan == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
plan, ok := planMap[int64(userPlan.PlanId)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 总流量
|
||||
totalTrafficBytes, err := SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch plan.PriceType {
|
||||
case serverconfigs.PlanPriceTypePeriod:
|
||||
// 已经在购买套餐的时候付过费,这里不再重复计费
|
||||
var fee float64 = 0
|
||||
|
||||
// 百分位
|
||||
var percentile = 95
|
||||
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, int64(userPlan.UserId), serverId, month, userPlanId, int64(userPlan.PlanId), totalTrafficBytes, percentileBytes, percentile, plan.PriceType, fee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case serverconfigs.PlanPriceTypeTraffic:
|
||||
var config = plan.DecodeTrafficPrice()
|
||||
var fee float64 = 0
|
||||
if config != nil && config.Base > 0 {
|
||||
fee = float64(totalTrafficBytes) / 1024 / 1024 / 1024 * float64(config.Base)
|
||||
}
|
||||
|
||||
// 百分位
|
||||
var percentile = 95
|
||||
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, int64(userPlan.UserId), serverId, month, userPlanId, int64(userPlan.PlanId), totalTrafficBytes, percentileBytes, percentile, plan.PriceType, fee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case serverconfigs.PlanPriceTypeBandwidth:
|
||||
// 百分位
|
||||
var percentile = 95
|
||||
var config = plan.DecodeBandwidthPrice()
|
||||
if config != nil {
|
||||
percentile = config.Percentile
|
||||
if percentile <= 0 {
|
||||
percentile = 95
|
||||
} else if percentile > 100 {
|
||||
percentile = 100
|
||||
}
|
||||
}
|
||||
percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var mb = float32(percentileBytes) / 1024 / 1024
|
||||
var price float32
|
||||
if config != nil {
|
||||
price = config.LookupPrice(mb)
|
||||
}
|
||||
var fee = float64(price)
|
||||
err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, int64(userPlan.UserId), serverId, month, userPlanId, int64(userPlan.PlanId), totalTrafficBytes, percentileBytes, percentile, plan.PriceType, fee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户
|
||||
offset := int64(0)
|
||||
size := int64(100) // 每次只查询N次,防止由于执行时间过长而锁表
|
||||
for {
|
||||
userIds, err := SharedUserDAO.ListEnabledUserIds(tx, offset, size)
|
||||
// 计算用户费用
|
||||
for _, userId := range userIds {
|
||||
if userId == 0 {
|
||||
continue
|
||||
}
|
||||
amount, err := SharedServerBillDAO.SumUserMonthlyAmount(tx, userId, month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offset += size
|
||||
if len(userIds) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
for _, userId := range userIds {
|
||||
// CDN流量账单
|
||||
err := this.generateTrafficBill(tx, userId, month, regions, priceItems)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = SharedUserBillDAO.CreateBill(tx, userId, BillTypeTraffic, "流量带宽费用", amount, month, month < timeutil.Format("Ym"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,74 +426,11 @@ func (this *UserBillDAO) UpdateUserBillIsPaid(tx *dbs.Tx, billId int64, isPaid b
|
||||
UpdateQuickly()
|
||||
}
|
||||
|
||||
// 生成CDN流量账单
|
||||
// month 格式YYYYMM
|
||||
func (this *UserBillDAO) generateTrafficBill(tx *dbs.Tx, userId int64, month string, regions []*NodeRegion, priceItems []*NodePriceItem) error {
|
||||
// 检查是否已经有账单了
|
||||
if month < timeutil.Format("Ym") {
|
||||
b, err := this.ExistBill(tx, userId, BillTypeTraffic, month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var cost = float32(0)
|
||||
for _, region := range regions {
|
||||
if len(region.Prices) == 0 || region.Prices == "null" {
|
||||
continue
|
||||
}
|
||||
priceMap := map[string]float32{}
|
||||
err := json.Unmarshal([]byte(region.Prices), &priceMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trafficBytes, err := SharedServerDailyStatDAO.SumUserMonthlyWithoutPlan(tx, userId, int64(region.Id), month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if trafficBytes == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
itemId := SharedNodePriceItemDAO.SearchItemsWithBytes(priceItems, trafficBytes)
|
||||
if itemId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
price, ok := priceMap[numberutils.FormatInt64(itemId)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 计算钱
|
||||
// 这里采用1000进制
|
||||
cost += (float32(trafficBytes*8) / 1_000_000_000) * price
|
||||
}
|
||||
|
||||
// 套餐费用
|
||||
planFee, err := SharedServerDailyStatDAO.SumUserMonthlyFee(tx, userId, month)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cost += float32(planFee)
|
||||
|
||||
if cost == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建账单
|
||||
return this.CreateBill(tx, userId, BillTypeTraffic, "按流量计费", cost, month)
|
||||
}
|
||||
|
||||
// BillTypeName 获取账单类型名称
|
||||
func (this *UserBillDAO) BillTypeName(billType BillType) string {
|
||||
switch billType {
|
||||
case BillTypeTraffic:
|
||||
return "流量"
|
||||
return "流量带宽"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ type UserBill struct {
|
||||
Type string `field:"type"` // 消费类型
|
||||
Description string `field:"description"` // 描述
|
||||
Amount float64 `field:"amount"` // 消费数额
|
||||
DayFrom string `field:"dayFrom"` // YYYYMMDD
|
||||
DayTo string `field:"dayTo"` // YYYYMMDD
|
||||
Month string `field:"month"` // 帐期YYYYMM
|
||||
CanPay uint8 `field:"canPay"` // 是否可以支付
|
||||
IsPaid uint8 `field:"isPaid"` // 是否已支付
|
||||
PaidAt uint64 `field:"paidAt"` // 支付时间
|
||||
Code string `field:"code"` // 账单编号
|
||||
@@ -20,7 +23,10 @@ type UserBillOperator struct {
|
||||
Type interface{} // 消费类型
|
||||
Description interface{} // 描述
|
||||
Amount interface{} // 消费数额
|
||||
DayFrom interface{} // YYYYMMDD
|
||||
DayTo interface{} // YYYYMMDD
|
||||
Month interface{} // 帐期YYYYMM
|
||||
CanPay interface{} // 是否可以支付
|
||||
IsPaid interface{} // 是否已支付
|
||||
PaidAt interface{} // 支付时间
|
||||
Code interface{} // 账单编号
|
||||
|
||||
@@ -95,6 +95,18 @@ func (this *UserDAO) FindEnabledBasicUser(tx *dbs.Tx, id int64) (*User, error) {
|
||||
return result.(*User), err
|
||||
}
|
||||
|
||||
// FindBasicUserWithoutState 查找用户基本信息,并忽略状态
|
||||
func (this *UserDAO) FindBasicUserWithoutState(tx *dbs.Tx, id int64) (*User, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Result("id", "fullname", "username").
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*User), err
|
||||
}
|
||||
|
||||
// FindUserFullname 获取管理员名称
|
||||
func (this *UserDAO) FindUserFullname(tx *dbs.Tx, userId int64) (string, error) {
|
||||
return this.Query(tx).
|
||||
@@ -104,7 +116,18 @@ func (this *UserDAO) FindUserFullname(tx *dbs.Tx, userId int64) (string, error)
|
||||
}
|
||||
|
||||
// CreateUser 创建用户
|
||||
func (this *UserDAO) CreateUser(tx *dbs.Tx, username string, password string, fullname string, mobile string, tel string, email string, remark string, source string, clusterId int64) (int64, error) {
|
||||
func (this *UserDAO) CreateUser(tx *dbs.Tx, username string,
|
||||
password string,
|
||||
fullname string,
|
||||
mobile string,
|
||||
tel string,
|
||||
email string,
|
||||
remark string,
|
||||
source string,
|
||||
clusterId int64,
|
||||
features []string,
|
||||
registeredIP string,
|
||||
isVerified bool) (int64, error) {
|
||||
op := NewUserOperator()
|
||||
op.Username = username
|
||||
op.Password = stringutil.Md5(password)
|
||||
@@ -112,10 +135,24 @@ func (this *UserDAO) CreateUser(tx *dbs.Tx, username string, password string, fu
|
||||
op.Mobile = mobile
|
||||
op.Tel = tel
|
||||
op.Email = email
|
||||
op.EmailIsVerified = false
|
||||
op.Remark = remark
|
||||
op.Source = source
|
||||
op.ClusterId = clusterId
|
||||
op.Day = timeutil.Format("Ymd")
|
||||
op.IsVerified = isVerified
|
||||
op.RegisteredIP = registeredIP
|
||||
|
||||
// features
|
||||
if len(features) == 0 {
|
||||
op.Features = "[]"
|
||||
} else {
|
||||
featuresJSON, err := json.Marshal(features)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Features = featuresJSON
|
||||
}
|
||||
|
||||
op.IsOn = true
|
||||
op.State = UserStateEnabled
|
||||
@@ -149,13 +186,15 @@ func (this *UserDAO) UpdateUser(tx *dbs.Tx, userId int64, username string, passw
|
||||
}
|
||||
|
||||
// UpdateUserInfo 修改用户基本信息
|
||||
func (this *UserDAO) UpdateUserInfo(tx *dbs.Tx, userId int64, fullname string) error {
|
||||
func (this *UserDAO) UpdateUserInfo(tx *dbs.Tx, userId int64, fullname string, mobile string, email string) error {
|
||||
if userId <= 0 {
|
||||
return errors.New("invalid userId")
|
||||
}
|
||||
op := NewUserOperator()
|
||||
op.Id = userId
|
||||
op.Fullname = fullname
|
||||
op.Mobile = mobile
|
||||
op.Email = email
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
@@ -175,7 +214,7 @@ func (this *UserDAO) UpdateUserLogin(tx *dbs.Tx, userId int64, username string,
|
||||
}
|
||||
|
||||
// CountAllEnabledUsers 计算用户数量
|
||||
func (this *UserDAO) CountAllEnabledUsers(tx *dbs.Tx, clusterId int64, keyword string) (int64, error) {
|
||||
func (this *UserDAO) CountAllEnabledUsers(tx *dbs.Tx, clusterId int64, keyword string, isVerifying bool) (int64, error) {
|
||||
query := this.Query(tx)
|
||||
query.State(UserStateEnabled)
|
||||
if clusterId > 0 {
|
||||
@@ -185,11 +224,22 @@ func (this *UserDAO) CountAllEnabledUsers(tx *dbs.Tx, clusterId int64, keyword s
|
||||
query.Where("(username LIKE :keyword OR fullname LIKE :keyword OR mobile LIKE :keyword OR email LIKE :keyword OR tel LIKE :keyword OR remark LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
if isVerifying {
|
||||
query.Attr("isVerified", 0)
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// CountAllVerifyingUsers 获取等待审核的用户数
|
||||
func (this *UserDAO) CountAllVerifyingUsers(tx *dbs.Tx) (int64, error) {
|
||||
query := this.Query(tx)
|
||||
query.State(UserStateEnabled)
|
||||
query.Attr("isVerified", 0)
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListEnabledUsers 列出单页用户
|
||||
func (this *UserDAO) ListEnabledUsers(tx *dbs.Tx, clusterId int64, keyword string, offset int64, size int64) (result []*User, err error) {
|
||||
func (this *UserDAO) ListEnabledUsers(tx *dbs.Tx, clusterId int64, keyword string, isVerifying bool, offset int64, size int64) (result []*User, err error) {
|
||||
query := this.Query(tx)
|
||||
query.State(UserStateEnabled)
|
||||
if clusterId > 0 {
|
||||
@@ -199,6 +249,9 @@ func (this *UserDAO) ListEnabledUsers(tx *dbs.Tx, clusterId int64, keyword strin
|
||||
query.Where("(username LIKE :keyword OR fullname LIKE :keyword OR mobile LIKE :keyword OR email LIKE :keyword OR tel LIKE :keyword OR remark LIKE :keyword)").
|
||||
Param("keyword", "%"+keyword+"%")
|
||||
}
|
||||
if isVerifying {
|
||||
query.Attr("isVerified", 0)
|
||||
}
|
||||
_, err = query.
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
@@ -355,3 +408,16 @@ func (this *UserDAO) CountDailyUsers(tx *dbs.Tx, dayFrom string, dayTo string) (
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateUserIsVerified 审核用户
|
||||
func (this *UserDAO) UpdateUserIsVerified(tx *dbs.Tx, userId int64, isRejected bool, rejectReason string) error {
|
||||
if userId <= 0 {
|
||||
return errors.New("invalid userId")
|
||||
}
|
||||
var op = NewUserOperator()
|
||||
op.Id = userId
|
||||
op.IsRejected = isRejected
|
||||
op.RejectReason = rejectReason
|
||||
op.IsVerified = true
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
@@ -2,43 +2,55 @@ package models
|
||||
|
||||
// User 用户
|
||||
type User struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Username string `field:"username"` // 用户名
|
||||
Password string `field:"password"` // 密码
|
||||
Fullname string `field:"fullname"` // 真实姓名
|
||||
Mobile string `field:"mobile"` // 手机号
|
||||
Tel string `field:"tel"` // 联系电话
|
||||
Remark string `field:"remark"` // 备注
|
||||
Email string `field:"email"` // 邮箱地址
|
||||
AvatarFileId uint64 `field:"avatarFileId"` // 头像文件ID
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
Day string `field:"day"` // YYYYMMDD
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
Source string `field:"source"` // 来源
|
||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||
Features string `field:"features"` // 允许操作的特征
|
||||
Id uint32 `field:"id"` // ID
|
||||
IsOn uint8 `field:"isOn"` // 是否启用
|
||||
Username string `field:"username"` // 用户名
|
||||
Password string `field:"password"` // 密码
|
||||
Fullname string `field:"fullname"` // 真实姓名
|
||||
Mobile string `field:"mobile"` // 手机号
|
||||
Tel string `field:"tel"` // 联系电话
|
||||
Remark string `field:"remark"` // 备注
|
||||
Email string `field:"email"` // 邮箱地址
|
||||
EmailIsVerified uint8 `field:"emailIsVerified"` // 邮箱是否已验证
|
||||
AvatarFileId uint64 `field:"avatarFileId"` // 头像文件ID
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
Day string `field:"day"` // YYYYMMDD
|
||||
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
Source string `field:"source"` // 来源
|
||||
ClusterId uint32 `field:"clusterId"` // 集群ID
|
||||
Features string `field:"features"` // 允许操作的特征
|
||||
RegisteredIP string `field:"registeredIP"` // 注册使用的IP
|
||||
IsRejected uint8 `field:"isRejected"` // 是否已拒绝
|
||||
RejectReason string `field:"rejectReason"` // 拒绝理由
|
||||
IsVerified uint8 `field:"isVerified"` // 是否验证通过
|
||||
RequirePlans uint8 `field:"requirePlans"` // 是否需要购买套餐
|
||||
}
|
||||
|
||||
type UserOperator struct {
|
||||
Id interface{} // ID
|
||||
IsOn interface{} // 是否启用
|
||||
Username interface{} // 用户名
|
||||
Password interface{} // 密码
|
||||
Fullname interface{} // 真实姓名
|
||||
Mobile interface{} // 手机号
|
||||
Tel interface{} // 联系电话
|
||||
Remark interface{} // 备注
|
||||
Email interface{} // 邮箱地址
|
||||
AvatarFileId interface{} // 头像文件ID
|
||||
CreatedAt interface{} // 创建时间
|
||||
Day interface{} // YYYYMMDD
|
||||
UpdatedAt interface{} // 修改时间
|
||||
State interface{} // 状态
|
||||
Source interface{} // 来源
|
||||
ClusterId interface{} // 集群ID
|
||||
Features interface{} // 允许操作的特征
|
||||
Id interface{} // ID
|
||||
IsOn interface{} // 是否启用
|
||||
Username interface{} // 用户名
|
||||
Password interface{} // 密码
|
||||
Fullname interface{} // 真实姓名
|
||||
Mobile interface{} // 手机号
|
||||
Tel interface{} // 联系电话
|
||||
Remark interface{} // 备注
|
||||
Email interface{} // 邮箱地址
|
||||
EmailIsVerified interface{} // 邮箱是否已验证
|
||||
AvatarFileId interface{} // 头像文件ID
|
||||
CreatedAt interface{} // 创建时间
|
||||
Day interface{} // YYYYMMDD
|
||||
UpdatedAt interface{} // 修改时间
|
||||
State interface{} // 状态
|
||||
Source interface{} // 来源
|
||||
ClusterId interface{} // 集群ID
|
||||
Features interface{} // 允许操作的特征
|
||||
RegisteredIP interface{} // 注册使用的IP
|
||||
IsRejected interface{} // 是否已拒绝
|
||||
RejectReason interface{} // 拒绝理由
|
||||
IsVerified interface{} // 是否验证通过
|
||||
RequirePlans interface{} // 是否需要购买套餐
|
||||
}
|
||||
|
||||
func NewUserOperator() *UserOperator {
|
||||
|
||||
@@ -85,6 +85,31 @@ func (this *UserPlanDAO) FindEnabledUserPlan(tx *dbs.Tx, userPlanId int64, cache
|
||||
return result.(*UserPlan), err
|
||||
}
|
||||
|
||||
// FindUserPlanWithoutState 查找套餐,并不检查状态
|
||||
// 防止因为删除套餐而导致计费失败
|
||||
func (this *UserPlanDAO) FindUserPlanWithoutState(tx *dbs.Tx, userPlanId int64, cacheMap *utils.CacheMap) (*UserPlan, error) {
|
||||
var cacheKey = this.Table + ":FindUserPlanWithoutState:" + types.String(userPlanId)
|
||||
if cacheMap != nil {
|
||||
cache, ok := cacheMap.Get(cacheKey)
|
||||
if ok {
|
||||
return cache.(*UserPlan), nil
|
||||
}
|
||||
}
|
||||
|
||||
result, err := this.Query(tx).
|
||||
Pk(userPlanId).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cacheMap != nil {
|
||||
cacheMap.Put(cacheKey, result)
|
||||
}
|
||||
|
||||
return result.(*UserPlan), err
|
||||
}
|
||||
|
||||
// CountAllEnabledUserPlans 计算套餐数量
|
||||
func (this *UserPlanDAO) CountAllEnabledUserPlans(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int32) (int64, error) {
|
||||
var query = this.Query(tx).
|
||||
|
||||
@@ -150,13 +150,13 @@ func (this *AliDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record)
|
||||
resp := alidns.CreateAddDomainRecordResponse()
|
||||
err := this.doAPI(req, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
if resp.IsSuccess() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New(resp.GetHttpContentString())
|
||||
return this.WrapError(errors.New(resp.GetHttpContentString()), domain, newRecord)
|
||||
}
|
||||
|
||||
// UpdateRecord 修改记录
|
||||
@@ -174,7 +174,7 @@ func (this *AliDNSProvider) UpdateRecord(domain string, record *dnstypes.Record,
|
||||
|
||||
resp := alidns.CreateUpdateDomainRecordResponse()
|
||||
err := this.doAPI(req, resp)
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
// DeleteRecord 删除记录
|
||||
@@ -184,7 +184,7 @@ func (this *AliDNSProvider) DeleteRecord(domain string, record *dnstypes.Record)
|
||||
|
||||
resp := alidns.CreateDeleteDomainRecordResponse()
|
||||
err := this.doAPI(req, resp)
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
|
||||
// DefaultRoute 默认线路
|
||||
|
||||
@@ -1,4 +1,29 @@
|
||||
package dnsclients
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type BaseProvider struct {
|
||||
}
|
||||
|
||||
// WrapError 封装解析相关错误
|
||||
func (this *BaseProvider) WrapError(err error, domain string, record *dnstypes.Record) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if record == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fullname = ""
|
||||
if len(record.Name) == 0 {
|
||||
fullname = domain
|
||||
} else {
|
||||
fullname = record.Name + "." + domain
|
||||
}
|
||||
return errors.New("record operation failed: '" + fullname + " " + record.Type + " " + record.Value + " " + types.String(record.TTL) + "': " + err.Error())
|
||||
}
|
||||
|
||||
38
internal/dnsclients/provider_base_test.go
Normal file
38
internal/dnsclients/provider_base_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package dnsclients_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBaseProvider_WrapError(t *testing.T) {
|
||||
var provider = &dnsclients.BaseProvider{}
|
||||
t.Log(provider.WrapError(nil, "example.com", &dnstypes.Record{
|
||||
Id: "",
|
||||
Name: "a",
|
||||
Type: "A",
|
||||
Value: "192.168.1.100",
|
||||
Route: "",
|
||||
TTL: 3600,
|
||||
}))
|
||||
t.Log(provider.WrapError(errors.New("fake error"), "example.com", &dnstypes.Record{
|
||||
Id: "",
|
||||
Name: "a",
|
||||
Type: "A",
|
||||
Value: "192.168.1.100",
|
||||
Route: "",
|
||||
TTL: 3600,
|
||||
}))
|
||||
t.Log(provider.WrapError(errors.New("fake error"), "example.com", &dnstypes.Record{
|
||||
Id: "",
|
||||
Name: "",
|
||||
Type: "A",
|
||||
Value: "192.168.1.100",
|
||||
Route: "",
|
||||
TTL: 3600,
|
||||
}))
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/cloudflare"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
@@ -168,7 +169,7 @@ func (this *CloudFlareProvider) QueryRecord(domain string, name string, recordTy
|
||||
func (this *CloudFlareProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
resp := new(cloudflare.CreateDNSRecordResponse)
|
||||
@@ -185,7 +186,7 @@ func (this *CloudFlareProvider) AddRecord(domain string, newRecord *dnstypes.Rec
|
||||
"ttl": ttl,
|
||||
}, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -194,7 +195,7 @@ func (this *CloudFlareProvider) AddRecord(domain string, newRecord *dnstypes.Rec
|
||||
func (this *CloudFlareProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
var ttl = newRecord.TTL
|
||||
@@ -215,13 +216,13 @@ func (this *CloudFlareProvider) UpdateRecord(domain string, record *dnstypes.Rec
|
||||
func (this *CloudFlareProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
|
||||
resp := new(cloudflare.DeleteDNSRecordResponse)
|
||||
err = this.doAPI(http.MethodDelete, "zones/"+zoneId+"/dns_records/"+record.Id, map[string]string{}, nil, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -257,6 +258,7 @@ func (this *CloudFlareProvider) doAPI(method string, apiPath string, args map[st
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-Auth-Key", this.apiKey)
|
||||
req.Header.Set("x-Auth-Email", this.email)
|
||||
|
||||
@@ -29,6 +29,8 @@ var customHTTPClient = &http.Client{
|
||||
type CustomHTTPProvider struct {
|
||||
url string
|
||||
secret string
|
||||
|
||||
BaseProvider
|
||||
}
|
||||
|
||||
// Auth 认证
|
||||
@@ -96,7 +98,7 @@ func (this *CustomHTTPProvider) QueryRecord(domain string, name string, recordTy
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp) == 0 {
|
||||
if len(resp) == 0 || string(resp) == "null" {
|
||||
return nil, nil
|
||||
}
|
||||
record := &dnstypes.Record{}
|
||||
@@ -117,7 +119,7 @@ func (this *CustomHTTPProvider) AddRecord(domain string, newRecord *dnstypes.Rec
|
||||
"domain": domain,
|
||||
"newRecord": newRecord,
|
||||
})
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
// UpdateRecord 修改记录
|
||||
@@ -128,7 +130,7 @@ func (this *CustomHTTPProvider) UpdateRecord(domain string, record *dnstypes.Rec
|
||||
"record": record,
|
||||
"newRecord": newRecord,
|
||||
})
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
// DeleteRecord 删除记录
|
||||
@@ -138,7 +140,7 @@ func (this *CustomHTTPProvider) DeleteRecord(domain string, record *dnstypes.Rec
|
||||
"domain": domain,
|
||||
"record": record,
|
||||
})
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
|
||||
// DefaultRoute 默认线路
|
||||
@@ -162,10 +164,11 @@ func (this *CustomHTTPProvider) post(params maps.Map) (respData []byte, err erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
var timestamp = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
req.Header.Set("Timestamp", timestamp)
|
||||
req.Header.Set("Token", fmt.Sprintf("%x", sha1.Sum([]byte(this.secret+"@"+timestamp))))
|
||||
req.Header.Set("User-Agent", "GoEdge/"+teaconst.Version)
|
||||
req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := customHTTPClient.Do(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -182,7 +182,7 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record)
|
||||
args["ttl"] = types.String(newRecord.TTL)
|
||||
}
|
||||
_, err := this.post("/Record.Create", args)
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
// UpdateRecord 修改记录
|
||||
@@ -211,7 +211,7 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record,
|
||||
args["ttl"] = types.String(newRecord.TTL)
|
||||
}
|
||||
_, err := this.post("/Record.Modify", args)
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
// DeleteRecord 删除记录
|
||||
@@ -225,7 +225,7 @@ func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record)
|
||||
"record_id": record.Id,
|
||||
})
|
||||
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
|
||||
@@ -1331,7 +1331,7 @@ func (this *HuaweiDNSProvider) QueryRecord(domain string, name string, recordTyp
|
||||
func (this *HuaweiDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
var resp = new(huaweidns.ZonesCreateRecordSetResponse)
|
||||
@@ -1354,7 +1354,7 @@ func (this *HuaweiDNSProvider) AddRecord(domain string, newRecord *dnstypes.Reco
|
||||
"ttl": ttl,
|
||||
}, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
newRecord.Id = resp.Id + "@" + newRecord.Value
|
||||
@@ -1366,7 +1366,7 @@ func (this *HuaweiDNSProvider) AddRecord(domain string, newRecord *dnstypes.Reco
|
||||
func (this *HuaweiDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
var recordId string
|
||||
@@ -1397,7 +1397,7 @@ func (this *HuaweiDNSProvider) UpdateRecord(domain string, record *dnstypes.Reco
|
||||
"ttl": ttl,
|
||||
}, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1407,7 +1407,7 @@ func (this *HuaweiDNSProvider) UpdateRecord(domain string, record *dnstypes.Reco
|
||||
func (this *HuaweiDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
||||
zoneId, err := this.findZoneIdWithDomain(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
|
||||
var recordId string
|
||||
@@ -1421,7 +1421,7 @@ func (this *HuaweiDNSProvider) DeleteRecord(domain string, record *dnstypes.Reco
|
||||
var resp = new(huaweidns.ZonesDeleteRecordSetResponse)
|
||||
err = this.doAPI(http.MethodDelete, "/v2.1/zones/"+zoneId+"/recordsets/"+recordId, map[string]string{}, maps.Map{}, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -17,6 +17,8 @@ import (
|
||||
type LocalEdgeDNSProvider struct {
|
||||
clusterId int64 // 集群ID
|
||||
ttl int32 // TTL
|
||||
|
||||
BaseProvider
|
||||
}
|
||||
|
||||
// Auth 认证
|
||||
@@ -193,10 +195,10 @@ func (this *LocalEdgeDNSProvider) AddRecord(domain string, newRecord *dnstypes.R
|
||||
var tx *dbs.Tx
|
||||
domainId, err := nameservers.SharedNSDomainDAO.FindDomainIdWithName(tx, this.clusterId, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
if domainId == 0 {
|
||||
return errors.New("can not find domain '" + domain + "'")
|
||||
return this.WrapError(errors.New("can not find domain '"+domain+"'"), domain, newRecord)
|
||||
}
|
||||
|
||||
var routeIds = []string{}
|
||||
@@ -209,7 +211,7 @@ func (this *LocalEdgeDNSProvider) AddRecord(domain string, newRecord *dnstypes.R
|
||||
}
|
||||
_, err = nameservers.SharedNSRecordDAO.CreateRecord(tx, domainId, "", newRecord.Name, newRecord.Type, newRecord.Value, newRecord.TTL, routeIds)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -220,7 +222,7 @@ func (this *LocalEdgeDNSProvider) UpdateRecord(domain string, record *dnstypes.R
|
||||
var tx *dbs.Tx
|
||||
domainId, err := nameservers.SharedNSDomainDAO.FindDomainIdWithName(tx, this.clusterId, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
if domainId == 0 {
|
||||
return errors.New("can not find domain '" + domain + "'")
|
||||
@@ -238,17 +240,17 @@ func (this *LocalEdgeDNSProvider) UpdateRecord(domain string, record *dnstypes.R
|
||||
if len(record.Id) > 0 {
|
||||
err = nameservers.SharedNSRecordDAO.UpdateRecord(tx, types.Int64(record.Id), "", newRecord.Name, newRecord.Type, newRecord.Value, newRecord.TTL, routeIds, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
} else {
|
||||
realRecord, err := nameservers.SharedNSRecordDAO.FindEnabledRecordWithName(tx, domainId, record.Name, record.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
if realRecord != nil {
|
||||
err = nameservers.SharedNSRecordDAO.UpdateRecord(tx, types.Int64(realRecord.Id), "", newRecord.Name, newRecord.Type, newRecord.Value, newRecord.TTL, routeIds, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, newRecord)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +263,7 @@ func (this *LocalEdgeDNSProvider) DeleteRecord(domain string, record *dnstypes.R
|
||||
var tx *dbs.Tx
|
||||
domainId, err := nameservers.SharedNSDomainDAO.FindDomainIdWithName(tx, this.clusterId, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
if domainId == 0 {
|
||||
return errors.New("can not find domain '" + domain + "'")
|
||||
@@ -270,17 +272,17 @@ func (this *LocalEdgeDNSProvider) DeleteRecord(domain string, record *dnstypes.R
|
||||
if len(record.Id) > 0 {
|
||||
err = nameservers.SharedNSRecordDAO.DisableNSRecord(tx, types.Int64(record.Id))
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
} else {
|
||||
realRecord, err := nameservers.SharedNSRecordDAO.FindEnabledRecordWithName(tx, domainId, record.Name, record.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
if realRecord != nil {
|
||||
err = nameservers.SharedNSRecordDAO.DisableNSRecord(tx, types.Int64(realRecord.Id))
|
||||
if err != nil {
|
||||
return err
|
||||
return this.WrapError(err, domain, record)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,19 +9,30 @@ import (
|
||||
|
||||
var SharedDeployManager = NewDeployManager()
|
||||
|
||||
// DeployManager 节点部署文件管理器
|
||||
// 如果节点部署文件有变化,需要重启API节点以便于生效
|
||||
type DeployManager struct {
|
||||
dir string
|
||||
dir string
|
||||
nodeFiles []*DeployFile
|
||||
nsNodeFiles []*DeployFile
|
||||
}
|
||||
|
||||
// NewDeployManager 节点部署文件管理器
|
||||
// NewDeployManager 获取新节点部署文件管理器
|
||||
func NewDeployManager() *DeployManager {
|
||||
return &DeployManager{
|
||||
var manager = &DeployManager{
|
||||
dir: Tea.Root + "/deploy",
|
||||
}
|
||||
manager.LoadNodeFiles()
|
||||
manager.LoadNSNodeFiles()
|
||||
return manager
|
||||
}
|
||||
|
||||
// LoadNodeFiles 加载所有边缘节点文件
|
||||
func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
||||
if len(this.nodeFiles) > 0 {
|
||||
return this.nodeFiles
|
||||
}
|
||||
|
||||
keyMap := map[string]*DeployFile{} // key => File
|
||||
|
||||
reg := regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||
@@ -52,6 +63,9 @@ func (this *DeployManager) LoadNodeFiles() []*DeployFile {
|
||||
for _, v := range keyMap {
|
||||
result = append(result, v)
|
||||
}
|
||||
|
||||
this.nodeFiles = result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -67,6 +81,10 @@ func (this *DeployManager) FindNodeFile(os string, arch string) *DeployFile {
|
||||
|
||||
// LoadNSNodeFiles 加载所有NS节点安装文件
|
||||
func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
||||
if len(this.nsNodeFiles) > 0 {
|
||||
return this.nsNodeFiles
|
||||
}
|
||||
|
||||
keyMap := map[string]*DeployFile{} // key => File
|
||||
|
||||
reg := regexp.MustCompile(`^edge-dns-(\w+)-(\w+)-v([0-9.]+)\.zip$`)
|
||||
@@ -97,6 +115,9 @@ func (this *DeployManager) LoadNSNodeFiles() []*DeployFile {
|
||||
for _, v := range keyMap {
|
||||
result = append(result, v)
|
||||
}
|
||||
|
||||
this.nsNodeFiles = result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -11,9 +12,9 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/events"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/setup"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
@@ -35,6 +37,9 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// grpc decompression
|
||||
_ "google.golang.org/grpc/encoding/gzip"
|
||||
)
|
||||
|
||||
var sharedAPIConfig *configs.APIConfig = nil
|
||||
@@ -214,10 +219,10 @@ func (this *APINode) listenRPC(listener net.Listener, tlsConfig *tls.Config) err
|
||||
var rpcServer *grpc.Server
|
||||
if tlsConfig == nil {
|
||||
remotelogs.Println("API_NODE", "listening GRPC http://"+listener.Addr().String()+" ...")
|
||||
rpcServer = grpc.NewServer(grpc.MaxRecvMsgSize(128 * 1024 * 1024))
|
||||
rpcServer = grpc.NewServer(grpc.MaxRecvMsgSize(128*1024*1024), grpc.UnaryInterceptor(this.unaryInterceptor))
|
||||
} else {
|
||||
logs.Println("[API_NODE]listening GRPC https://" + listener.Addr().String() + " ...")
|
||||
rpcServer = grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)), grpc.MaxRecvMsgSize(128*1024*1024))
|
||||
rpcServer = grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)), grpc.MaxRecvMsgSize(128*1024*1024), grpc.UnaryInterceptor(this.unaryInterceptor))
|
||||
}
|
||||
this.registerServices(rpcServer)
|
||||
err := rpcServer.Serve(listener)
|
||||
@@ -274,7 +279,7 @@ func (this *APINode) autoUpgrade() error {
|
||||
if err != nil {
|
||||
return errors.New("decode database config failed: " + err.Error())
|
||||
}
|
||||
dbConfig := config.DBs[Tea.Env]
|
||||
var dbConfig = config.DBs[Tea.Env]
|
||||
db, err := dbs.NewInstanceFromConfig(dbConfig)
|
||||
if err != nil {
|
||||
return errors.New("load database failed: " + err.Error())
|
||||
@@ -285,8 +290,8 @@ func (this *APINode) autoUpgrade() error {
|
||||
}
|
||||
if one != nil {
|
||||
// 如果是同样的版本,则直接认为是最新版本
|
||||
version := one.GetString("version")
|
||||
if stringutil.VersionCompare(version, teaconst.Version) >= 0 {
|
||||
var version = one.GetString("version")
|
||||
if stringutil.VersionCompare(version, setup.ComposeSQLVersion()) >= 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -572,6 +577,11 @@ func (this *APINode) listenSock() error {
|
||||
"result": result,
|
||||
},
|
||||
})
|
||||
case "debug":
|
||||
teaconst.Debug = !teaconst.Debug
|
||||
_ = cmd.Reply(&gosock.Command{
|
||||
Params: map[string]interface{}{"debug": teaconst.Debug},
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -588,3 +598,29 @@ func (this *APINode) listenSock() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 服务过滤器
|
||||
func (this *APINode) unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
||||
if teaconst.Debug {
|
||||
var before = time.Now()
|
||||
var traceCtx = rpc.NewContext(ctx)
|
||||
resp, err = handler(traceCtx, req)
|
||||
|
||||
var costMs = time.Since(before).Seconds() * 1000
|
||||
statErr := models.SharedAPIMethodStatDAO.CreateStat(nil, info.FullMethod, "", costMs)
|
||||
if statErr != nil {
|
||||
remotelogs.Error("API_NODE", "create method stat failed: "+statErr.Error())
|
||||
}
|
||||
|
||||
var tagMap = traceCtx.TagMap()
|
||||
for tag, tagCostMs := range tagMap {
|
||||
statErr = models.SharedAPIMethodStatDAO.CreateStat(nil, info.FullMethod, tag, tagCostMs)
|
||||
if statErr != nil {
|
||||
remotelogs.Error("API_NODE", "create method stat failed: "+statErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
@@ -63,6 +63,11 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
||||
pb.RegisterAPINodeServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.APIMethodStatService{}).(*services.APIMethodStatService)
|
||||
pb.RegisterAPIMethodStatServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.OriginService{}).(*services.OriginService)
|
||||
pb.RegisterOriginServiceServer(server, instance)
|
||||
@@ -263,6 +268,16 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
||||
pb.RegisterRegionProvinceServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.RegionCityService{}).(*services.RegionCityService)
|
||||
pb.RegisterRegionCityServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.RegionProviderService{}).(*services.RegionProviderService)
|
||||
pb.RegisterRegionProviderServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.IPListService{}).(*services.IPListService)
|
||||
pb.RegisterIPListServiceServer(server, instance)
|
||||
@@ -333,6 +348,11 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
||||
pb.RegisterUserBillServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService)
|
||||
pb.RegisterServerBillServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
instance := this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
|
||||
pb.RegisterUserNodeServiceServer(server, instance)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
// +build community
|
||||
//go:build !plus
|
||||
// +build !plus
|
||||
|
||||
package nodes
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user