Compare commits

...

43 Commits

Author SHA1 Message Date
刘祥超
83a88299c2 Update components.js 2022-03-21 08:23:34 +08:00
刘祥超
bfae3b86cc Age改为在缓存中的已存活时间 2022-03-20 21:18:51 +08:00
刘祥超
027ee4d336 GRPC通讯支持gzip压缩 2022-03-20 11:28:38 +08:00
刘祥超
b07a65c879 更新相关库 2022-03-20 10:46:09 +08:00
刘祥超
284b2762f5 优化界面 2022-03-18 20:21:00 +08:00
刘祥超
5ba6e3b332 改进文字 2022-03-18 17:02:36 +08:00
刘祥超
8b0e3d960a Update components.js 2022-03-17 19:59:58 +08:00
刘祥超
fba2953974 优化界面 2022-03-17 19:57:41 +08:00
刘祥超
a36b843eff 优化指标统计图表数字展示 2022-03-17 16:01:47 +08:00
刘祥超
0735bc2d8a 源站支持自定义回源主机名 2022-03-17 15:48:08 +08:00
刘祥超
69d6fd645b 修复访问日志按小时搜索无法上翻页的Bug 2022-03-17 12:31:45 +08:00
刘祥超
039b11d434 增加置顶集群功能 2022-03-17 11:12:24 +08:00
刘祥超
485581f680 优化界面 2022-03-17 10:36:30 +08:00
刘祥超
a0c2006e24 Update components.js 2022-03-16 22:48:04 +08:00
刘祥超
7a288c360d IPSet支持IPv6 2022-03-16 20:48:35 +08:00
刘祥超
597d39f651 优化文字 2022-03-16 17:07:46 +08:00
刘祥超
7d27f64b8a 节点可以单独设置缓存目录 2022-03-16 15:24:11 +08:00
刘祥超
bd280bdc53 改进文字 2022-03-14 19:25:19 +08:00
刘祥超
018429866e 优化文字提示 2022-03-14 16:24:09 +08:00
刘祥超
78ad6526b8 缓存策略可以使用存储类型筛选 2022-03-14 15:42:10 +08:00
刘祥超
8c6e960db7 实现回源跟随功能 2022-03-14 15:07:49 +08:00
刘祥超
46d38ff8c0 格式化部分图表中的数字 2022-03-14 12:04:46 +08:00
刘祥超
db6fe469ad 访问日志慢的时候增加指定域名查询建议 2022-03-11 20:35:42 +08:00
刘祥超
5a7630bcd1 增加证书OCSP错误日志管理 2022-03-11 20:27:45 +08:00
刘祥超
099b57169d 上传js 2022-03-10 21:32:56 +08:00
刘祥超
e22dfd3314 优化界面 2022-03-10 15:47:25 +08:00
刘祥超
be71992930 增加OCSP Stapling功能 2022-03-10 11:55:09 +08:00
刘祥超
37433178cb 支持使用小时筛选访问日志 2022-03-09 11:00:49 +08:00
刘祥超
14499a4564 增加对访问日志自动分表配置 2022-03-09 10:01:52 +08:00
刘祥超
0355777f59 优化文字 2022-03-06 19:48:50 +08:00
刘祥超
a55834c78d 优化界面 2022-03-04 17:00:01 +08:00
刘祥超
79bbb47459 更新TeaGo 2022-03-04 15:01:26 +08:00
刘祥超
d3bcf0605b 升级相关依赖库 2022-03-04 12:35:28 +08:00
刘祥超
19a02f3a40 实现基础的区间内容缓存(206 partial content) 2022-03-03 19:32:11 +08:00
刘祥超
db20e9308a 修复选择集群弹窗页面可能只显示前6个集群的Bug 2022-02-28 14:41:55 +08:00
刘祥超
b3f9f28554 优化界面显示 2022-02-27 21:20:49 +08:00
刘祥超
ea5bd3f346 可以在管理界面设置里设置默认每页显示数 2022-02-24 20:52:47 +08:00
刘祥超
5c13797639 缓存可以设置是否使用系统默认设置 2022-02-24 20:39:09 +08:00
刘祥超
f147905532 增加是否同步写入压缩缓存设置 2022-02-24 20:12:15 +08:00
刘祥超
a73314c12a 修改版本为0.4.5 2022-02-24 19:25:12 +08:00
刘祥超
619934a275 修复访问日志XSS漏洞 2022-02-23 17:34:54 +08:00
刘祥超
5fe1384e55 修改版本为0.4.4 2022-02-23 14:48:33 +08:00
刘祥超
9af2c4a18a 修改版本为v0.4.3 2022-02-21 18:32:03 +08:00
104 changed files with 1198 additions and 279 deletions

View File

@@ -28,5 +28,4 @@
有什么问题和建议都可以加入QQ群 `659832182`
## 感谢
* 感谢[JetBrains公司](https://www.jetbrains.com/)提供免费的IDE开发Licence。
* 感谢[Gitee](https://gitee.com/)提供国内源代码托管平台

12
go.mod
View File

@@ -8,9 +8,8 @@ require (
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
github.com/cespare/xxhash v1.1.0
github.com/go-sql-driver/mysql v1.5.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/google/go-cmp v0.5.6 // indirect
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-20211103081026-ee4652210ca4
github.com/json-iterator/go v1.1.12 // indirect
github.com/miekg/dns v1.1.35
@@ -18,9 +17,8 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tealeg/xlsx/v3 v3.2.3
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
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
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

88
go.sum
View File

@@ -1,10 +1,12 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -14,6 +16,10 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -21,18 +27,18 @@ github.com/dgryski/go-rendezvous v0.0.0-20200624174652-8d2f3be8b2d9/go.mod h1:cu
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/frankban/quicktest v1.5.0 h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=
github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -45,6 +51,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=
@@ -60,17 +67,17 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/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/gosock v0.0.0-20210722083328-12b2d66abec3 h1:aBSonas7vFcgTj9u96/bWGILGv1ZbUSTLiOzcI1ZT6c=
github.com/iwind/gosock v0.0.0-20210722083328-12b2d66abec3/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/iwind/TeaGo v0.0.0-20220304042834-d8b5103e9027 h1:4knh28YgldmEtu8QG8pgQhUaI3i//qRjOdEyj9OVqXA=
github.com/iwind/TeaGo v0.0.0-20220304042834-d8b5103e9027/go.mod h1:IyKPaIhjbjsTctPguMWJZDHuBHu+XiYcV5ZEDxQpq94=
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-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/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=
@@ -81,11 +88,9 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
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 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/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=
@@ -118,17 +123,19 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ=
github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
@@ -137,27 +144,28 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
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-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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -175,30 +183,29 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-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-20210615035016-665e8c7367d1/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-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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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.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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
@@ -208,17 +215,23 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/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=
@@ -229,8 +242,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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
@@ -239,13 +253,15 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -94,5 +94,6 @@ func defaultAdminUIConfig() *systemconfigs.AdminUIConfig {
ShowOpenSourceInfo: true,
ShowVersion: true,
ShowFinance: true,
DefaultPageSize: 10,
}
}

View File

@@ -2,8 +2,8 @@ package configs
import (
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"gopkg.in/yaml.v3"
"io/ioutil"
"os"
"path/filepath"

View File

@@ -1,9 +1,9 @@
package teaconst
const (
Version = "0.4.2"
Version = "0.4.5"
APINodeVersion = "0.4.2"
APINodeVersion = "0.4.5"
ProductName = "Edge Admin"
ProcessName = "edge-admin"

View File

@@ -16,6 +16,8 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/encoding/gzip"
"google.golang.org/grpc/metadata"
"net/url"
"sync"
@@ -560,12 +562,14 @@ func (this *RPCClient) init() error {
return errors.New("parse endpoint failed: " + err.Error())
}
var conn *grpc.ClientConn
var callOptions = grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024),
grpc.UseCompressor(gzip.Name))
if u.Scheme == "http" {
conn, err = grpc.Dial(u.Host, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024)))
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
} else if u.Scheme == "https" {
conn, err = grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true,
})), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(128*1024*1024)))
})), callOptions)
} else {
return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
}

24
internal/utils/json.go Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package utils
import (
"encoding/json"
"reflect"
)
// JSONClone 使用JSON克隆对象
func JSONClone(v interface{}) (interface{}, error) {
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
var nv = reflect.New(reflect.TypeOf(v).Elem()).Interface()
err = json.Unmarshal(data, nv)
if err != nil {
return nil, err
}
return nv, nil
}

View File

@@ -0,0 +1,25 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package utils_test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"testing"
)
func TestJSONClone(t *testing.T) {
type A struct {
B int `json:"b"`
C string `json:"c"`
}
var a = &A{B: 123, C: "456"}
for i := 0; i < 5; i++ {
c, err := utils.JSONClone(a)
if err != nil {
t.Fatal(err)
}
t.Logf("%p, %#v", c, c)
}
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
@@ -55,7 +56,14 @@ func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
if len(size) > 0 {
return NewActionPage(this, total, size[0])
}
return NewActionPage(this, total, 10)
var pageSize int64 = 10
adminConfig, err := configloaders.LoadAdminUIConfig()
if err == nil && adminConfig.DefaultPageSize > 0 {
pageSize = int64(adminConfig.DefaultPageSize)
}
return NewActionPage(this, total, pageSize)
}
func (this *ParentAction) Nav(mainMenu string, tab string, firstMenu string) {

View File

@@ -60,11 +60,15 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"name": "DNS设置",
"url": prefix + "/settings/dns?" + query,
"isActive": menuItem == "dns",
"isOn": len(node.DnsRoutes) > 0,
},
{
"name": "缓存设置",
"url": prefix + "/settings/cache?" + query,
"isActive": menuItem == "cache",
"isOn": len(node.CacheDiskDir) > 0 ||
(node.MaxCacheDiskCapacity != nil && node.MaxCacheDiskCapacity.Count > 0) ||
(node.MaxCacheMemoryCapacity != nil && node.MaxCacheMemoryCapacity.Count > 0),
},
}
if teaconst.IsPlus {
@@ -81,11 +85,13 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
"name": "SSH设置",
"url": prefix + "/settings/ssh?" + query,
"isActive": menuItem == "ssh",
"isOn": node.NodeLogin != nil,
},
{
"name": "系统设置",
"url": prefix + "/settings/system?" + query,
"isActive": menuItem == "system",
"isOn": node.MaxCPU > 0,
},
}...)
parentAction.Data["leftMenuItems"] = menuItems

View File

@@ -59,6 +59,7 @@ func (this *IndexAction) RunGet(params struct {
var nodeMap = this.Data["node"].(maps.Map)
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
nodeMap["cacheDiskDir"] = node.CacheDiskDir
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
this.Show()
@@ -67,6 +68,7 @@ func (this *IndexAction) RunGet(params struct {
func (this *IndexAction) RunPost(params struct {
NodeId int64
MaxCacheDiskCapacityJSON []byte
CacheDiskDir string
MaxCacheMemoryCapacityJSON []byte
Must *actions.Must
@@ -106,6 +108,7 @@ func (this *IndexAction) RunPost(params struct {
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
NodeId: params.NodeId,
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
CacheDiskDir: params.CacheDiskDir,
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
})
if err != nil {

View File

@@ -34,6 +34,8 @@ func (this *CreatePopupAction) RunPost(params struct {
// ipset
IpsetWhiteName string
IpsetBlackName string
IpsetWhiteNameIPv6 string
IpsetBlackNameIPv6 string
IpsetAutoAddToIPTables bool
IpsetAutoAddToFirewalld bool
@@ -49,7 +51,7 @@ func (this *CreatePopupAction) RunPost(params struct {
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("创建WAF动作")
defer this.CreateLogInfo("创建集群 %d 的WAF动作", params.ClusterId)
params.Must.
Field("name", params.Name).
@@ -66,11 +68,19 @@ func (this *CreatePopupAction) RunPost(params struct {
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
Field("ipsetBlackName", params.IpsetBlackName).
Require("请输入IPSet黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet黑名单名称")
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
Require("请输入IPSet IPv6白名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
Require("请输入IPSet IPv6黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
WhiteName: params.IpsetWhiteName,
BlackName: params.IpsetBlackName,
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
BlackNameIPv6: params.IpsetBlackNameIPv6,
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
}

View File

@@ -63,6 +63,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
// ipset
IpsetWhiteName string
IpsetBlackName string
IpsetWhiteNameIPv6 string
IpsetBlackNameIPv6 string
IpsetAutoAddToIPTables bool
IpsetAutoAddToFirewalld bool
@@ -95,11 +97,19 @@ func (this *UpdatePopupAction) RunPost(params struct {
Match(`^\w+$`, "请输入正确的IPSet白名单名称").
Field("ipsetBlackName", params.IpsetBlackName).
Require("请输入IPSet黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet黑名单名称")
Match(`^\w+$`, "请输入正确的IPSet黑名单名称").
Field("ipsetWhiteNameIPv6", params.IpsetWhiteNameIPv6).
Require("请输入IPSet IPv6白名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6白名单名称").
Field("ipsetBlackNameIPv6", params.IpsetBlackNameIPv6).
Require("请输入IPSet IPv6黑名单名称").
Match(`^\w+$`, "请输入正确的IPSet IPv6黑名单名称")
actionParams = &firewallconfigs.FirewallActionIPSetConfig{
WhiteName: params.IpsetWhiteName,
BlackName: params.IpsetBlackName,
WhiteNameIPv6: params.IpsetWhiteNameIPv6,
BlackNameIPv6: params.IpsetBlackNameIPv6,
AutoAddToIPTables: params.IpsetAutoAddToIPTables,
AutoAddToFirewalld: params.IpsetAutoAddToFirewalld,
}

View File

@@ -27,6 +27,14 @@ func (this *CreateAction) RunGet(params struct{}) {
}
this.Data["hasDomains"] = hasDomainsResp.Exist
// 集群总数
totalResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["totalNodeClusters"] = totalResp.Count
this.Show()
}

View File

@@ -29,6 +29,14 @@ func (this *IndexAction) RunGet(params struct {
this.Data["searchType"] = params.SearchType
this.Data["isSearching"] = isSearching
// 集群总数
totalResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["totalNodeClusters"] = totalResp.Count
// 常用的集群
latestClusterMaps := []maps.Map{}
if !isSearching {
@@ -137,6 +145,7 @@ func (this *IndexAction) RunGet(params struct {
"dnsDomainName": dnsDomainName,
"countServers": countServersResp.Count,
"timeZone": cluster.TimeZone,
"isPinned": cluster.IsPinned,
})
}
}

View File

@@ -16,6 +16,7 @@ func init() {
Prefix("/clusters").
Get("", new(IndexAction)).
GetPost("/create", new(CreateAction)).
Post("/pin", new(PinAction)).
// 只要登录即可访问的Action
EndHelpers().

View File

@@ -0,0 +1,34 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package clusters
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type PinAction struct {
actionutils.ParentAction
}
func (this *PinAction) RunPost(params struct {
ClusterId int64
IsPinned bool
}) {
if params.IsPinned {
defer this.CreateLogInfo("置顶集群 %d", params.ClusterId)
} else {
defer this.CreateLogInfo("取消置顶集群 %d", params.ClusterId)
}
_, err := this.RPC().NodeClusterRPC().UpdateNodeClusterPinned(this.AdminContext(), &pb.UpdateNodeClusterPinnedRequest{
NodeClusterId: params.ClusterId,
IsPinned: params.IsPinned,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -35,11 +35,11 @@ func (this *SelectPopupAction) RunGet(params struct {
return
}
var count = countResp.Count
var page = this.NewPage(count)
page.Size = 6
var pageSize int64 = 6
if params.PageSize > 0 {
page.Size = params.PageSize
pageSize = params.PageSize
}
var page = this.NewPage(count, pageSize)
this.Data["page"] = page.AsHTML()
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{

View File

@@ -26,14 +26,14 @@ func (this *CertPopupAction) RunGet(params struct {
return
}
certConfig := &sslconfigs.SSLCertConfig{}
var certConfig = &sslconfigs.SSLCertConfig{}
err = json.Unmarshal(certResp.SslCertJSON, certConfig)
if err != nil {
this.ErrorPage(err)
return
}
reverseCommonNames := []string{}
var reverseCommonNames = []string{}
for i := len(certConfig.CommonNames) - 1; i >= 0; i-- {
reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i])
}
@@ -62,7 +62,7 @@ func (this *CertPopupAction) RunGet(params struct {
this.ErrorPage(err)
return
}
serverMaps := []maps.Map{}
var serverMaps = []maps.Map{}
for _, server := range serversResp.Servers {
serverMaps = append(serverMaps, maps.Map{
"id": server.Id,

View File

@@ -1,8 +1,11 @@
package certs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net/http"
)
@@ -13,14 +16,29 @@ func NewHelper() *Helper {
return &Helper{}
}
func (this *Helper) BeforeAction(action *actions.ActionObject) {
func (this *Helper) BeforeAction(actionWrapper actions.ActionWrapper) {
var action = actionWrapper.Object()
if action.Request.Method != http.MethodGet {
return
}
action.Data["teaMenu"] = "servers"
action.Data["leftMenuItems"] = []maps.Map{
var countOCSP int64 = 0
parentAction, ok := actionWrapper.(actionutils.ActionInterface)
if ok {
countOCSPResp, err := parentAction.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(parentAction.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{})
if err == nil {
countOCSP = countOCSPResp.Count
}
}
var ocspMenuName = "OCSP日志"
if countOCSP > 0 {
ocspMenuName += "(" + types.String(countOCSP) + ")"
}
var menu = []maps.Map{
{
"name": "证书",
"url": "/servers/certs",
@@ -31,5 +49,11 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) {
"url": "/servers/certs/acme",
"isActive": action.Data.GetString("leftMenuItem") == "acme",
},
{
"name": ocspMenuName,
"url": "/servers/certs/ocsp",
"isActive": action.Data.GetString("leftMenuItem") == "ocsp",
},
}
action.Data["leftMenuItems"] = menu
}

View File

@@ -25,12 +25,12 @@ func (this *IndexAction) RunGet(params struct {
this.Data["type"] = params.Type
this.Data["keyword"] = params.Keyword
countAll := int64(0)
countCA := int64(0)
countAvailable := int64(0)
countExpired := int64(0)
count7Days := int64(0)
count30Days := int64(0)
var countAll = int64(0)
var countCA = int64(0)
var countAvailable = int64(0)
var countExpired = int64(0)
var count7Days = int64(0)
var count30Days = int64(0)
// 计算数量
{
@@ -147,7 +147,7 @@ func (this *IndexAction) RunGet(params struct {
return
}
certConfigs := []*sslconfigs.SSLCertConfig{}
var certConfigs = []*sslconfigs.SSLCertConfig{}
err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs)
if err != nil {
this.ErrorPage(err)
@@ -155,8 +155,8 @@ func (this *IndexAction) RunGet(params struct {
}
this.Data["certs"] = certConfigs
certMaps := []maps.Map{}
nowTime := time.Now().Unix()
var certMaps = []maps.Map{}
var nowTime = time.Now().Unix()
for _, certConfig := range certConfigs {
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: certConfig.Id})
if err != nil {

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/accounts"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/ocsp"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
@@ -55,6 +56,14 @@ func init() {
GetPost("/updatePopup", new(accounts.UpdatePopupAction)).
Post("/delete", new(accounts.DeleteAction)).
// OCSP
Prefix("/servers/certs/ocsp").
Data("leftMenuItem", "ocsp").
Get("", new(ocsp.IndexAction)).
Post("/reset", new(ocsp.ResetAction)).
Post("/resetAll", new(ocsp.ResetAllAction)).
Post("/ignore", new(ocsp.IgnoreAction)).
//
EndAll()
})

View File

@@ -0,0 +1,26 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type IgnoreAction struct {
actionutils.ParentAction
}
func (this *IgnoreAction) RunPost(params struct {
CertIds []int64
}) {
defer this.CreateLogInfo("忽略一组证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().IgnoreSSLCertsWithOCSPError(this.AdminContext(), &pb.IgnoreSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,65 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
"time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.SecondMenu("ocsp")
}
func (this *IndexAction) RunGet(params struct {
Keyword string
}) {
this.Data["keyword"] = params.Keyword
countResp, err := this.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(this.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{Keyword: params.Keyword})
if err != nil {
this.ErrorPage(err)
return
}
var count = countResp.Count
var page = this.NewPage(count)
this.Data["page"] = page.AsHTML()
certsResp, err := this.RPC().SSLCertRPC().ListSSLCertsWithOCSPError(this.AdminContext(), &pb.ListSSLCertsWithOCSPErrorRequest{
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
var certMaps = []maps.Map{}
for _, cert := range certsResp.SslCerts {
certMaps = append(certMaps, maps.Map{
"id": cert.Id,
"isOn": cert.IsOn,
"dnsNames": cert.DnsNames,
"commonNames": cert.CommonNames,
"hasOCSP": len(cert.Ocsp) > 0,
"ocspIsUpdated": cert.OcspIsUpdated,
"ocspError": cert.OcspError,
"isCA": cert.IsCA,
"isACME": cert.IsACME,
"name": cert.Name,
"isExpired": cert.TimeEndAt < time.Now().Unix(),
"beginDay": timeutil.FormatTime("Y-m-d", cert.TimeBeginAt),
"endDay": timeutil.FormatTime("Y-m-d", cert.TimeEndAt),
})
}
this.Data["certs"] = certMaps
this.Show()
}

View File

@@ -0,0 +1,26 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ResetAction struct {
actionutils.ParentAction
}
func (this *ResetAction) RunPost(params struct {
CertIds []int64
}) {
defer this.CreateLogInfo("重置一组证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().ResetSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,24 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package ocsp
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ResetAllAction struct {
actionutils.ParentAction
}
func (this *ResetAllAction) RunPost(params struct{}) {
defer this.CreateLogInfo("忽略所有证书的OCSP状态")
_, err := this.RPC().SSLCertRPC().ResetAllSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetAllSSLCertsWithOCSPErrorRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -33,9 +33,10 @@ func (this *CreatePopupAction) RunPost(params struct {
FileMemoryCapacityJSON []byte
FileOpenFileCacheMax int
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
SyncCompressionCache bool
Description string
IsOn bool
@@ -90,14 +91,15 @@ func (this *CreatePopupAction) RunPost(params struct {
return
}
createResp, err := this.RPC().HTTPCachePolicyRPC().CreateHTTPCachePolicy(this.AdminContext(), &pb.CreateHTTPCachePolicyRequest{
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
SyncCompressionCache: params.SyncCompressionCache,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -17,15 +17,18 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
ClusterId int64
Keyword string
ClusterId int64
Keyword string
StorageType string
}) {
this.Data["keyword"] = params.Keyword
this.Data["clusterId"] = params.ClusterId
this.Data["storageType"] = params.StorageType
countResp, err := this.RPC().HTTPCachePolicyRPC().CountAllEnabledHTTPCachePolicies(this.AdminContext(), &pb.CountAllEnabledHTTPCachePoliciesRequest{
NodeClusterId: params.ClusterId,
Keyword: params.Keyword,
Type: params.StorageType,
})
if err != nil {
this.ErrorPage(err)
@@ -38,6 +41,7 @@ func (this *IndexAction) RunGet(params struct {
listResp, err := this.RPC().HTTPCachePolicyRPC().ListEnabledHTTPCachePolicies(this.AdminContext(), &pb.ListEnabledHTTPCachePoliciesRequest{
Keyword: params.Keyword,
NodeClusterId: params.ClusterId,
Type: params.StorageType,
Offset: page.Offset,
Size: page.Size,
})
@@ -70,5 +74,8 @@ func (this *IndexAction) RunGet(params struct {
}
this.Data["infos"] = infos
// 所有的存储类型
this.Data["storageTypes"] = serverconfigs.AllCachePolicyStorageTypes
this.Show()
}

View File

@@ -57,9 +57,10 @@ func (this *UpdateAction) RunPost(params struct {
FileMemoryCapacityJSON []byte
FileOpenFileCacheMax int
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
CapacityJSON []byte
MaxSizeJSON []byte
MaxKeys int64
SyncCompressionCache bool
Description string
IsOn bool
@@ -135,15 +136,16 @@ func (this *UpdateAction) RunPost(params struct {
}
_, err = this.RPC().HTTPCachePolicyRPC().UpdateHTTPCachePolicy(this.AdminContext(), &pb.UpdateHTTPCachePolicyRequest{
HttpCachePolicyId: params.CachePolicyId,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
HttpCachePolicyId: params.CachePolicyId,
IsOn: params.IsOn,
Name: params.Name,
Description: params.Description,
CapacityJSON: params.CapacityJSON,
MaxKeys: params.MaxKeys,
MaxSizeJSON: params.MaxSizeJSON,
Type: params.Type,
OptionsJSON: optionsJSON,
SyncCompressionCache: params.SyncCompressionCache,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -64,6 +64,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
@@ -79,6 +80,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
backupOriginMaps = append(backupOriginMaps, m)
}

View File

@@ -106,6 +106,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON,
})

View File

@@ -64,6 +64,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
@@ -79,6 +80,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
backupOriginMaps = append(backupOriginMaps, m)
}

View File

@@ -106,6 +106,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON,
})

View File

@@ -64,6 +64,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
@@ -79,6 +80,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
backupOriginMaps = append(backupOriginMaps, m)
}

View File

@@ -96,6 +96,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
})
this.Success()

View File

@@ -25,6 +25,7 @@ func (this *IndexAction) RunGet(params struct {
ClusterId int64
NodeId int64
Day string
Hour string
Keyword string
Ip string
Domain string
@@ -45,6 +46,7 @@ func (this *IndexAction) RunGet(params struct {
this.Data["serverId"] = 0
this.Data["path"] = this.Request.URL.Path
this.Data["day"] = params.Day
this.Data["hour"] = params.Hour
this.Data["keyword"] = params.Keyword
this.Data["ip"] = params.Ip
this.Data["domain"] = params.Domain
@@ -76,6 +78,8 @@ func (this *IndexAction) RunGet(params struct {
HasError: params.HasError > 0,
HasFirewallPolicy: params.HasWAF > 0,
Day: day,
HourFrom: params.Hour,
HourTo: params.Hour,
Keyword: params.Keyword,
Ip: params.Ip,
Domain: params.Domain,
@@ -120,6 +124,8 @@ func (this *IndexAction) RunGet(params struct {
HasError: params.HasError > 0,
HasFirewallPolicy: params.HasWAF > 0,
Day: day,
HourFrom: params.Hour,
HourTo: params.Hour,
Keyword: params.Keyword,
Ip: params.Ip,
Domain: params.Domain,

View File

@@ -27,9 +27,11 @@ func (this *SettingsAction) RunGet(params struct{}) {
}
var config = &serverconfigs.AccessLogQueueConfig{
MaxLength: 0,
CountPerSecond: 0,
Percent: 100,
MaxLength: 0,
CountPerSecond: 0,
Percent: 100,
EnableAutoPartial: true,
RowsPerTable: 500_000,
}
if len(settingsResp.ValueJSON) > 0 {
err = json.Unmarshal(settingsResp.ValueJSON, config)
@@ -59,9 +61,11 @@ func (this *SettingsAction) RunGet(params struct{}) {
}
func (this *SettingsAction) RunPost(params struct {
Percent int
CountPerSecond int
MaxLength int
Percent int
CountPerSecond int
MaxLength int
EnableAutoPartial bool
RowsPerTable int64
Must *actions.Must
CSRF *actionutils.CSRF
@@ -72,9 +76,11 @@ func (this *SettingsAction) RunPost(params struct {
Lte(100, "请输入小于100的整数")
var config = &serverconfigs.AccessLogQueueConfig{
MaxLength: params.MaxLength,
CountPerSecond: params.CountPerSecond,
Percent: params.Percent,
MaxLength: params.MaxLength,
CountPerSecond: params.CountPerSecond,
Percent: params.Percent,
EnableAutoPartial: params.EnableAutoPartial,
RowsPerTable: params.RowsPerTable,
}
configJSON, err := json.Marshal(config)
if err != nil {

View File

@@ -21,6 +21,7 @@ func (this *HistoryAction) Init() {
func (this *HistoryAction) RunGet(params struct {
ServerId int64
Day string
Hour string
Keyword string
Ip string
Domain string
@@ -40,6 +41,7 @@ func (this *HistoryAction) RunGet(params struct {
this.Data["path"] = this.Request.URL.Path
this.Data["day"] = params.Day
this.Data["hour"] = params.Hour
this.Data["keyword"] = params.Keyword
this.Data["ip"] = params.Ip
this.Data["domain"] = params.Domain
@@ -68,6 +70,8 @@ func (this *HistoryAction) RunGet(params struct {
HasError: params.HasError > 0,
HasFirewallPolicy: params.HasWAF > 0,
Day: day,
HourFrom: params.Hour,
HourTo: params.Hour,
Keyword: params.Keyword,
Ip: params.Ip,
Domain: params.Domain,

View File

@@ -2,6 +2,7 @@ package cache
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
@@ -28,7 +29,7 @@ func (this *CreatePopupAction) RunPost(params struct {
Must *actions.Must
}) {
cacheRef := &serverconfigs.HTTPCacheRef{}
var cacheRef = &serverconfigs.HTTPCacheRef{}
err := json.Unmarshal(params.CacheRefJSON, cacheRef)
if err != nil {
this.ErrorPage(err)
@@ -42,7 +43,13 @@ func (this *CreatePopupAction) RunPost(params struct {
this.Fail("请填写匹配条件分组")
}
err = cacheRef.Init()
this.Data["cacheRef"] = cacheRef
cacheRefClone, err := utils.JSONClone(cacheRef)
if err != nil {
this.Fail(err.Error())
}
err = cacheRefClone.(*serverconfigs.HTTPCacheRef).Init()
if err != nil {
this.ErrorPage(err)
return

View File

@@ -143,6 +143,7 @@ func (this *IndexAction) RunPost(params struct {
MinVersion: sslPolicy.MinVersion,
SslCertsJSON: certsJSON,
HstsJSON: hstsJSON,
OcspIsOn: sslPolicy.OCSPIsOn,
ClientAuthType: types.Int32(sslPolicy.ClientAuthType),
ClientCACertsJSON: clientCACertsJSON,
CipherSuitesIsOn: sslPolicy.CipherSuitesIsOn,
@@ -158,6 +159,7 @@ func (this *IndexAction) RunPost(params struct {
MinVersion: sslPolicy.MinVersion,
SslCertsJSON: certsJSON,
HstsJSON: hstsJSON,
OcspIsOn: sslPolicy.OCSPIsOn,
ClientAuthType: types.Int32(sslPolicy.ClientAuthType),
ClientCACertsJSON: clientCACertsJSON,
CipherSuitesIsOn: sslPolicy.CipherSuitesIsOn,

View File

@@ -65,6 +65,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
@@ -80,6 +81,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
backupOriginMaps = append(backupOriginMaps, m)
}

View File

@@ -97,6 +97,7 @@ func (this *SettingAction) RunPost(params struct {
StripPrefix: reverseProxyConfig.StripPrefix,
AutoFlush: reverseProxyConfig.AutoFlush,
AddHeaders: reverseProxyConfig.AddHeaders,
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON,
})

View File

@@ -66,6 +66,7 @@ func (this *AddPopupAction) RunPost(params struct {
CertIdsJSON []byte
DomainsJSON []byte
Host string
Description string
IsOn bool
@@ -157,6 +158,7 @@ func (this *AddPopupAction) RunPost(params struct {
}
}
// 专属域名
var domains = []string{}
if len(params.DomainsJSON) > 0 {
err = json.Unmarshal(params.DomainsJSON, &domains)
@@ -188,6 +190,7 @@ func (this *AddPopupAction) RunPost(params struct {
MaxIdleConns: params.MaxIdleConns,
CertRefJSON: certRefJSON,
Domains: domains,
Host: params.Host,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -60,17 +60,17 @@ func (this *UpdatePopupAction) RunGet(params struct {
this.ErrorPage(err)
return
}
configData := originResp.OriginJSON
config := &serverconfigs.OriginConfig{}
var configData = originResp.OriginJSON
var config = &serverconfigs.OriginConfig{}
err = json.Unmarshal(configData, config)
if err != nil {
this.ErrorPage(err)
return
}
connTimeout := 0
readTimeout := 0
idleTimeout := 0
var connTimeout = 0
var readTimeout = 0
var idleTimeout = 0
if config.ConnTimeout != nil {
connTimeout = types.Int(config.ConnTimeout.Count)
}
@@ -108,6 +108,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
"maxIdleConns": config.MaxIdleConns,
"cert": config.Cert,
"domains": config.Domains,
"host": config.RequestHost,
}
this.Show()
@@ -130,7 +131,9 @@ func (this *UpdatePopupAction) RunPost(params struct {
IdleTimeout int
CertIdsJSON []byte
DomainsJSON []byte
Host string
Description string
IsOn bool
@@ -164,8 +167,8 @@ func (this *UpdatePopupAction) RunPost(params struct {
}
portIndex = strings.LastIndex(addr, ":")
}
host := addr[:portIndex]
port := addr[portIndex+1:]
var host = addr[:portIndex]
var port = addr[portIndex+1:]
if port == "0" {
this.Fail("端口号不能为0")
}
@@ -222,6 +225,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
}
}
// 专属域名
var domains = []string{}
if len(params.DomainsJSON) > 0 {
err = json.Unmarshal(params.DomainsJSON, &domains)
@@ -254,6 +258,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
MaxIdleConns: params.MaxIdleConns,
CertRefJSON: certRefJSON,
Domains: domains,
Host: params.Host,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -92,6 +92,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
primaryOriginMaps = append(primaryOriginMaps, m)
}
@@ -107,6 +108,7 @@ func (this *IndexAction) RunGet(params struct {
"isOn": originConfig.IsOn,
"domains": originConfig.Domains,
"hasCert": originConfig.Cert != nil,
"host": originConfig.RequestHost,
}
backupOriginMaps = append(backupOriginMaps, m)
}

View File

@@ -131,6 +131,7 @@ func (this *SettingAction) RunPost(params struct {
MaxConns: types.Int32(reverseProxyConfig.MaxConns),
MaxIdleConns: types.Int32(reverseProxyConfig.MaxIdleConns),
ProxyProtocolJSON: proxyProtocolJSON,
FollowRedirects: reverseProxyConfig.FollowRedirects,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -128,6 +128,7 @@ func (this *IndexAction) RunPost(params struct {
MinVersion: sslPolicy.MinVersion,
SslCertsJSON: certsJSON,
HstsJSON: hstsJSON,
OcspIsOn: sslPolicy.OCSPIsOn,
ClientAuthType: types.Int32(sslPolicy.ClientAuthType),
ClientCACertsJSON: clientCACertsJSON,
CipherSuitesIsOn: sslPolicy.CipherSuitesIsOn,
@@ -143,6 +144,7 @@ func (this *IndexAction) RunPost(params struct {
MinVersion: sslPolicy.MinVersion,
SslCertsJSON: certsJSON,
HstsJSON: hstsJSON,
OcspIsOn: sslPolicy.OCSPIsOn,
ClientAuthType: types.Int32(sslPolicy.ClientAuthType),
ClientCACertsJSON: clientCACertsJSON,
CipherSuitesIsOn: sslPolicy.CipherSuitesIsOn,

View File

@@ -3,10 +3,10 @@ package database
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/go-sql-driver/mysql"
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
"gopkg.in/yaml.v3"
"io/ioutil"
"strings"
)

View File

@@ -22,6 +22,9 @@ func (this *IndexAction) RunGet(params struct{}) {
this.ErrorPage(err)
return
}
if config.DefaultPageSize == 0 {
config.DefaultPageSize = 10
}
this.Data["config"] = config
this.Show()
@@ -36,6 +39,7 @@ func (this *IndexAction) RunPost(params struct {
Version string
FaviconFile *actions.File
LogoFile *actions.File
DefaultPageSize int
Must *actions.Must
CSRF *actionutils.CSRF
@@ -46,7 +50,10 @@ func (this *IndexAction) RunPost(params struct {
Field("productName", params.ProductName).
Require("请输入产品名称").
Field("adminSystemName", params.AdminSystemName).
Require("请输入管理员系统名称")
Require("请输入管理员系统名称").
Field("defaultPageSize", params.DefaultPageSize).
Gte(0, "默认每页显示数不能小于0").
Lte(100, "默认每页显示数不能大于100")
config, err := configloaders.LoadAdminUIConfig()
if err != nil {
@@ -60,6 +67,12 @@ func (this *IndexAction) RunPost(params struct {
config.ShowVersion = params.ShowVersion
config.Version = params.Version
if params.DefaultPageSize > 0 {
config.DefaultPageSize = params.DefaultPageSize
} else {
config.DefaultPageSize = 10
}
// 上传Favicon文件
if params.FaviconFile != nil {
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{

View File

@@ -10,13 +10,13 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/gosock/pkg/gosock"
"gopkg.in/yaml.v3"
"io/ioutil"
"os"
"os/exec"

View File

@@ -1924,7 +1924,8 @@ Vue.component("ssl-config-box", {
hsts: null,
cipherSuitesIsOn: false,
cipherSuites: [],
http2Enabled: true
http2Enabled: true,
ocspIsOn: false
}
} else {
if (policy.certRefs == null) {
@@ -2401,6 +2402,14 @@ Vue.component("ssl-config-box", {
</td>
</tr>
<!-- OCSP -->
<tr>
<td>OCSP Stapling</td>
<td><checkbox name="ocspIsOn" v-model="policy.ocspIsOn"></checkbox>
<p class="comment">选中表示启用OCSP Stapling。</p>
</td>
</tr>
<!-- 客户端认证 -->
<tr>
<td>客户端认证方式</td>
@@ -2575,6 +2584,7 @@ Vue.component("http-cache-refs-box", {
<grey-label v-if="cacheRef.methods != null && cacheRef.methods.length > 0">{{cacheRef.methods.join(", ")}}</grey-label>
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
</td>
<td>
<span v-if="cacheRef.conds.connector == 'and'">和</span>
@@ -2866,6 +2876,7 @@ Vue.component("http-cache-ref-box", {
enableRequestCachePragma: false,
conds: null,
allowChunkedEncoding: true,
allowPartialContent: false,
isReverse: this.vIsReverse,
methods: [],
expiresTime: {
@@ -2993,7 +3004,14 @@ Vue.component("http-cache-ref-box", {
<td>支持分片内容</td>
<td>
<checkbox name="allowChunkedEncoding" value="1" v-model="ref.allowChunkedEncoding"></checkbox>
<p class="comment">选中后GzipChunked内容可以直接缓存无需检查内容长度。</p>
<p class="comment">选中后Gzip等压缩后的Chunked内容可以直接缓存无需检查内容长度。</p>
</td>
</tr>
<tr v-show="moreOptionsVisible && !vIsReverse">
<td>支持缓存区间内容</td>
<td>
<checkbox name="allowPartialContent" value="1" v-model="ref.allowPartialContent"></checkbox>
<p class="comment">选中后,支持缓存源站返回的某个区间的内容,该内容通过<code-label>206 Partial Content</code-label>状态码返回。此功能目前为<code-label>试验性质</code-label>。</p>
</td>
</tr>
<tr v-show="moreOptionsVisible && !vIsReverse">
@@ -3322,7 +3340,7 @@ Vue.component("http-firewall-config-box", {
</td>
</tr>
<tr>
<td class="title">是否启用WAF</td>
<td class="title">启用WAF</td>
<td>
<div class="ui checkbox">
<input type="checkbox" v-model="firewall.isOn"/>
@@ -3442,8 +3460,11 @@ Vue.component("metric-chart", {
case "byte":
value = teaweb.formatBytes(value)
break
case "count":
value = teaweb.formatNumber(value)
break
}
return stat.keys[0] + ": " + value + "占比:" + percent + "%"
return stat.keys[0] + "<br/>" + that.valueTypeName + ": " + value + "<br/>占比:" + percent + "%"
}
},
series: [
@@ -3651,8 +3672,11 @@ Vue.component("metric-chart", {
case "byte":
value = teaweb.formatBytes(value)
break
case "count":
value = teaweb.formatNumber(value)
break
}
return stat.keys[0] + ": " + value + "占比:" + percent + "%"
return stat.keys[0] + "<br/>" + that.valueTypeName + "" + value + "<br/>占比:" + percent + "%"
}
},
yAxis: {
@@ -3771,15 +3795,23 @@ Vue.component("http-cache-config-box", {
enableCacheControlMaxAge: false,
cacheRefs: [],
purgeIsOn: false,
purgeKey: ""
purgeKey: "",
disablePolicyRefs: false
}
}
if (cacheConfig.cacheRefs == null) {
cacheConfig.cacheRefs = []
}
return {
cacheConfig: cacheConfig,
moreOptionsVisible: false
moreOptionsVisible: false,
enablePolicyRefs: !cacheConfig.disablePolicyRefs
}
},
watch: {
enablePolicyRefs: function (v) {
this.cacheConfig.disablePolicyRefs = !v
}
},
methods: {
@@ -3821,7 +3853,7 @@ Vue.component("http-cache-config-box", {
</td>
</tr>
<tr>
<td class="title">是否开启缓存</td>
<td class="title">启缓存</td>
<td>
<div class="ui checkbox">
<input type="checkbox" v-model="cacheConfig.isOn"/>
@@ -3838,6 +3870,13 @@ Vue.component("http-cache-config-box", {
</tr>
</tbody>
<tbody v-show="isOn() && moreOptionsVisible">
<tr>
<td>使用默认缓存条件</td>
<td>
<checkbox v-model="enablePolicyRefs"></checkbox>
<p class="comment">选中后使用系统中已经定义的默认缓存条件。</p>
</td>
</tr>
<tr>
<td>添加X-Cache Header</td>
<td>
@@ -3849,7 +3888,7 @@ Vue.component("http-cache-config-box", {
<td>添加Age Header</td>
<td>
<checkbox v-model="cacheConfig.addAgeHeader"></checkbox>
<p class="comment">选中后自动在响应Header中增加<code-label>Age: [有效时间秒数]</code-label>。</p>
<p class="comment">选中后自动在响应Header中增加<code-label>Age: [存活时间秒数]</code-label>。</p>
</td>
</tr>
<tr>
@@ -4285,10 +4324,6 @@ Vue.component("http-cache-refs-config-box", {
callback: function (resp) {
resp.data.cacheRef.id = that.refs[index].id
Vue.set(that.refs, index, resp.data.cacheRef)
// 通知子组件更新
that.$refs.cacheRef[index].notifyChange()
that.change()
}
})
@@ -4363,6 +4398,7 @@ Vue.component("http-cache-refs-config-box", {
<grey-label v-if="cacheRef.methods != null && cacheRef.methods.length > 0">{{cacheRef.methods.join(", ")}}</grey-label>
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
</td>
<td>
<span v-if="cacheRef.conds.connector == 'and'">和</span>
@@ -4475,14 +4511,11 @@ Vue.component("origin-list-table", {
</thead>
<tr v-for="origin in vOrigins">
<td :class="{disabled:!origin.isOn}"><a href="" @click.prevent="updateOrigin(origin.id)">{{origin.addr}} &nbsp;<i class="icon clone outline small"></i></a>
<div v-if="origin.name.length > 0" style="margin-top: 0.5em">
<tiny-basic-label>{{origin.name}}</tiny-basic-label>
</div>
<div v-if="origin.domains != null && origin.domains.length > 0">
<grey-label v-for="domain in origin.domains">{{domain}}</grey-label>
</div>
<div v-if="origin.hasCert">
<tiny-basic-label>证书</tiny-basic-label>
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || (origin.domains != null && origin.domains.length > 0)">
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
<tiny-basic-label v-if="origin.host != null && origin.host.length > 0">主机名: {{origin.host}}</tiny-basic-label>
<span v-if="origin.domains != null && origin.domains.length > 0"><tiny-basic-label v-for="domain in origin.domains">匹配: {{domain}}</tiny-basic-label></span>
</div>
</td>
<td :class="{disabled:!origin.isOn}">{{origin.weight}}</td>
@@ -5825,6 +5858,8 @@ Vue.component("http-firewall-actions-box", {
<option value="service">当前服务</option>
<option value="global">所有服务</option>
</select>
<p class="comment" v-if="blockScope == 'service'">只封锁用户对当前网站服务的访问,其他服务不受影响。</p>
<p class="comment" v-if="blockScope =='global'">封锁用户对所有网站服务的访问。</p>
</td>
</tr>
@@ -7674,7 +7709,8 @@ Vue.component("reverse-proxy-box", {
readTimeout: {count: 0, unit: "second"},
idleTimeout: {count: 0, unit: "second"},
maxConns: 0,
maxIdleConns: 0
maxIdleConns: 0,
followRedirects: false
}
}
if (reverseProxyConfig.addHeaders == null) {
@@ -7834,6 +7870,13 @@ Vue.component("reverse-proxy-box", {
</tbody>
<more-options-tbody @change="changeAdvancedVisible" v-if="isOn()"></more-options-tbody>
<tbody v-show="isOn() && advancedVisible">
<tr v-show="family == null || family == 'http'">
<td>回源跟随</td>
<td>
<checkbox v-model="reverseProxyConfig.followRedirects"></checkbox>
<p class="comment">选中后,自动读取源站跳转后的网页内容。</p>
</td>
</tr>
<tr v-show="family == null || family == 'http'">
<td>自动添加的Header</td>
<td>
@@ -8214,11 +8257,11 @@ Vue.component("http-access-log-search-box", {
<div class="ui field">
<div class="ui input left right labeled small">
<span class="ui label basic" style="font-weight: normal">关键词</span>
<input type="text" name="keyword" v-model="keyword" placeholder="路径、UserAgent等..." size="18"/>
<input type="text" name="keyword" v-model="keyword" placeholder="路径、UserAgent等..." size="30"/>
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
</div>
</div>
<slot></slot>
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码status:200<br/>状态码范围status:500-504<br/>查询IPip:192.168.1.100"></tip-icon></div>
</div>
<div class="ui fields inline" style="margin-top: 0.5em">
<div class="ui field">
@@ -8227,6 +8270,7 @@ Vue.component("http-access-log-search-box", {
<div class="ui field" v-if="clusterId > 0">
<node-combo-box :v-cluster-id="clusterId" :v-node-id="vNodeId"></node-combo-box>
</div>
<slot></slot>
<div class="ui field">
<button class="ui button small" type="submit">搜索日志</button>
</div>
@@ -11446,6 +11490,10 @@ Vue.component("grey-label", {
template: `<span class="ui label basic tiny" :class="labelColor" style="margin-top: 0.4em; font-size: 0.7em; border: 1px solid #ddd!important; font-weight: normal;"><slot></slot></span>`
})
// 可选标签
Vue.component("optional-label", {
template: `<em><span class="grey">(可选)</span></em>`
})
/**
* 一级菜单
@@ -12136,9 +12184,9 @@ Vue.component("checkbox", {
}
let checkedValue = this.value
if (checkedValue == null && this.checked == "checked") {
checkedValue = elementValue
}
if (checkedValue == null && this.checked == "checked") {
checkedValue = elementValue
}
return {
elementId: elementId,
@@ -12149,15 +12197,24 @@ Vue.component("checkbox", {
methods: {
change: function () {
this.$emit("input", this.newValue)
},
check: function () {
this.newValue = this.elementValue
},
uncheck: function () {
this.newValue = ""
},
isChecked: function () {
return this.newValue == this.elementValue
}
},
watch: {
value: function (v) {
if (typeof v == "boolean") {
this.newValue = v
}
}
},
watch: {
value: function (v) {
if (typeof v == "boolean") {
this.newValue = v
}
}
},
template: `<div class="ui checkbox">
<input type="checkbox" :name="name" :value="elementValue" :id="elementId" @change="change" v-model="newValue"/>
<label :for="elementId" style="font-size: 0.85em!important;"><slot></slot></label>
@@ -12226,17 +12283,39 @@ Vue.component("keyword", {
if (word == null) {
word = ""
} else {
word = word.replace(/\)/, "\\)")
word = word.replace(/\(/, "\\(")
word = word.replace(/\+/, "\\+")
word = word.replace(/\^/, "\\^")
word = word.replace(/\$/, "\\$")
word = word.replace(/\)/g, "\\)")
word = word.replace(/\(/g, "\\(")
word = word.replace(/\+/g, "\\+")
word = word.replace(/\^/g, "\\^")
word = word.replace(/\$/g, "\\$")
word = word.replace(/\?/, "\\?")
word = word.replace(/\*/, "\\*")
word = word.replace(/\[/, "\\[")
word = word.replace(/{/, "\\{")
word = word.replace(/\./, "\\.")
}
let slot = this.$slots["default"][0]
let text = this.encodeHTML(slot.text)
let text = slot.text
if (word.length > 0) {
text = text.replace(new RegExp("(" + word + ")", "ig"), "<span style=\"border: 1px #ccc dashed; color: #ef4d58\">$1</span>")
let that = this
let m = [] // replacement => tmp
let tmpIndex = 0
text = text.replaceAll(new RegExp("(" + word + ")", "ig"), function (replacement) {
tmpIndex++
let s = "<span style=\"border: 1px #ccc dashed; color: #ef4d58\">" + that.encodeHTML(replacement) + "</span>"
let tmpKey = "$TMP__KEY__" + tmpIndex.toString() + "$"
m.push([tmpKey, s])
return tmpKey
})
text = this.encodeHTML(text)
m.forEach(function (r) {
text = text.replace(r[0], r[1])
})
} else {
text = this.encodeHTML(text)
}
return {
@@ -12246,9 +12325,10 @@ Vue.component("keyword", {
},
methods: {
encodeHTML: function (s) {
s = s.replace("&", "&amp;")
s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;")
s = s.replace(/&/g, "&amp;")
s = s.replace(/</g, "&lt;")
s = s.replace(/>/g, "&gt;")
s = s.replace(/"/g, "&quot;")
return s
}
},

View File

@@ -14,9 +14,9 @@ Vue.component("checkbox", {
}
let checkedValue = this.value
if (checkedValue == null && this.checked == "checked") {
checkedValue = elementValue
}
if (checkedValue == null && this.checked == "checked") {
checkedValue = elementValue
}
return {
elementId: elementId,
@@ -27,15 +27,24 @@ Vue.component("checkbox", {
methods: {
change: function () {
this.$emit("input", this.newValue)
},
check: function () {
this.newValue = this.elementValue
},
uncheck: function () {
this.newValue = ""
},
isChecked: function () {
return this.newValue == this.elementValue
}
},
watch: {
value: function (v) {
if (typeof v == "boolean") {
this.newValue = v
}
}
},
watch: {
value: function (v) {
if (typeof v == "boolean") {
this.newValue = v
}
}
},
template: `<div class="ui checkbox">
<input type="checkbox" :name="name" :value="elementValue" :id="elementId" @change="change" v-model="newValue"/>
<label :for="elementId" style="font-size: 0.85em!important;"><slot></slot></label>

View File

@@ -5,17 +5,39 @@ Vue.component("keyword", {
if (word == null) {
word = ""
} else {
word = word.replace(/\)/, "\\)")
word = word.replace(/\(/, "\\(")
word = word.replace(/\+/, "\\+")
word = word.replace(/\^/, "\\^")
word = word.replace(/\$/, "\\$")
word = word.replace(/\)/g, "\\)")
word = word.replace(/\(/g, "\\(")
word = word.replace(/\+/g, "\\+")
word = word.replace(/\^/g, "\\^")
word = word.replace(/\$/g, "\\$")
word = word.replace(/\?/, "\\?")
word = word.replace(/\*/, "\\*")
word = word.replace(/\[/, "\\[")
word = word.replace(/{/, "\\{")
word = word.replace(/\./, "\\.")
}
let slot = this.$slots["default"][0]
let text = this.encodeHTML(slot.text)
let text = slot.text
if (word.length > 0) {
text = text.replace(new RegExp("(" + word + ")", "ig"), "<span style=\"border: 1px #ccc dashed; color: #ef4d58\">$1</span>")
let that = this
let m = [] // replacement => tmp
let tmpIndex = 0
text = text.replaceAll(new RegExp("(" + word + ")", "ig"), function (replacement) {
tmpIndex++
let s = "<span style=\"border: 1px #ccc dashed; color: #ef4d58\">" + that.encodeHTML(replacement) + "</span>"
let tmpKey = "$TMP__KEY__" + tmpIndex.toString() + "$"
m.push([tmpKey, s])
return tmpKey
})
text = this.encodeHTML(text)
m.forEach(function (r) {
text = text.replace(r[0], r[1])
})
} else {
text = this.encodeHTML(text)
}
return {
@@ -25,9 +47,10 @@ Vue.component("keyword", {
},
methods: {
encodeHTML: function (s) {
s = s.replace("&", "&amp;")
s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;")
s = s.replace(/&/g, "&amp;")
s = s.replace(/</g, "&lt;")
s = s.replace(/>/g, "&gt;")
s = s.replace(/"/g, "&quot;")
return s
}
},

View File

@@ -43,3 +43,8 @@ Vue.component("grey-label", {
},
template: `<span class="ui label basic tiny" :class="labelColor" style="margin-top: 0.4em; font-size: 0.7em; border: 1px solid #ddd!important; font-weight: normal;"><slot></slot></span>`
})
// 可选标签
Vue.component("optional-label", {
template: `<em><span class="grey">(可选)</span></em>`
})

View File

@@ -78,11 +78,11 @@ Vue.component("http-access-log-search-box", {
<div class="ui field">
<div class="ui input left right labeled small">
<span class="ui label basic" style="font-weight: normal">关键词</span>
<input type="text" name="keyword" v-model="keyword" placeholder="路径、UserAgent等..." size="18"/>
<input type="text" name="keyword" v-model="keyword" placeholder="路径、UserAgent等..." size="30"/>
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
</div>
</div>
<slot></slot>
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码status:200<br/>状态码范围status:500-504<br/>查询IPip:192.168.1.100"></tip-icon></div>
</div>
<div class="ui fields inline" style="margin-top: 0.5em">
<div class="ui field">
@@ -91,6 +91,7 @@ Vue.component("http-access-log-search-box", {
<div class="ui field" v-if="clusterId > 0">
<node-combo-box :v-cluster-id="clusterId" :v-node-id="vNodeId"></node-combo-box>
</div>
<slot></slot>
<div class="ui field">
<button class="ui button small" type="submit">搜索日志</button>
</div>

View File

@@ -11,15 +11,23 @@ Vue.component("http-cache-config-box", {
enableCacheControlMaxAge: false,
cacheRefs: [],
purgeIsOn: false,
purgeKey: ""
purgeKey: "",
disablePolicyRefs: false
}
}
if (cacheConfig.cacheRefs == null) {
cacheConfig.cacheRefs = []
}
return {
cacheConfig: cacheConfig,
moreOptionsVisible: false
moreOptionsVisible: false,
enablePolicyRefs: !cacheConfig.disablePolicyRefs
}
},
watch: {
enablePolicyRefs: function (v) {
this.cacheConfig.disablePolicyRefs = !v
}
},
methods: {
@@ -61,7 +69,7 @@ Vue.component("http-cache-config-box", {
</td>
</tr>
<tr>
<td class="title">是否开启缓存</td>
<td class="title">启缓存</td>
<td>
<div class="ui checkbox">
<input type="checkbox" v-model="cacheConfig.isOn"/>
@@ -78,6 +86,13 @@ Vue.component("http-cache-config-box", {
</tr>
</tbody>
<tbody v-show="isOn() && moreOptionsVisible">
<tr>
<td>使用默认缓存条件</td>
<td>
<checkbox v-model="enablePolicyRefs"></checkbox>
<p class="comment">选中后使用系统中已经定义的默认缓存条件。</p>
</td>
</tr>
<tr>
<td>添加X-Cache Header</td>
<td>
@@ -89,7 +104,7 @@ Vue.component("http-cache-config-box", {
<td>添加Age Header</td>
<td>
<checkbox v-model="cacheConfig.addAgeHeader"></checkbox>
<p class="comment">选中后自动在响应Header中增加<code-label>Age: [有效时间秒数]</code-label>。</p>
<p class="comment">选中后自动在响应Header中增加<code-label>Age: [存活时间秒数]</code-label>。</p>
</td>
</tr>
<tr>

View File

@@ -20,6 +20,7 @@ Vue.component("http-cache-ref-box", {
enableRequestCachePragma: false,
conds: null,
allowChunkedEncoding: true,
allowPartialContent: false,
isReverse: this.vIsReverse,
methods: [],
expiresTime: {
@@ -147,7 +148,14 @@ Vue.component("http-cache-ref-box", {
<td>支持分片内容</td>
<td>
<checkbox name="allowChunkedEncoding" value="1" v-model="ref.allowChunkedEncoding"></checkbox>
<p class="comment">选中后GzipChunked内容可以直接缓存无需检查内容长度。</p>
<p class="comment">选中后Gzip等压缩后的Chunked内容可以直接缓存无需检查内容长度。</p>
</td>
</tr>
<tr v-show="moreOptionsVisible && !vIsReverse">
<td>支持缓存区间内容</td>
<td>
<checkbox name="allowPartialContent" value="1" v-model="ref.allowPartialContent"></checkbox>
<p class="comment">选中后,支持缓存源站返回的某个区间的内容,该内容通过<code-label>206 Partial Content</code-label>状态码返回。此功能目前为<code-label>试验性质</code-label>。</p>
</td>
</tr>
<tr v-show="moreOptionsVisible && !vIsReverse">

View File

@@ -52,6 +52,7 @@ Vue.component("http-cache-refs-box", {
<grey-label v-if="cacheRef.methods != null && cacheRef.methods.length > 0">{{cacheRef.methods.join(", ")}}</grey-label>
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
</td>
<td>
<span v-if="cacheRef.conds.connector == 'and'">和</span>

View File

@@ -97,10 +97,6 @@ Vue.component("http-cache-refs-config-box", {
callback: function (resp) {
resp.data.cacheRef.id = that.refs[index].id
Vue.set(that.refs, index, resp.data.cacheRef)
// 通知子组件更新
that.$refs.cacheRef[index].notifyChange()
that.change()
}
})
@@ -175,6 +171,7 @@ Vue.component("http-cache-refs-config-box", {
<grey-label v-if="cacheRef.methods != null && cacheRef.methods.length > 0">{{cacheRef.methods.join(", ")}}</grey-label>
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
</td>
<td>
<span v-if="cacheRef.conds.connector == 'and'">和</span>

View File

@@ -599,6 +599,8 @@ Vue.component("http-firewall-actions-box", {
<option value="service">当前服务</option>
<option value="global">所有服务</option>
</select>
<p class="comment" v-if="blockScope == 'service'">只封锁用户对当前网站服务的访问,其他服务不受影响。</p>
<p class="comment" v-if="blockScope =='global'">封锁用户对所有网站服务的访问。</p>
</td>
</tr>

View File

@@ -29,7 +29,7 @@ Vue.component("http-firewall-config-box", {
</td>
</tr>
<tr>
<td class="title">是否启用WAF</td>
<td class="title">启用WAF</td>
<td>
<div class="ui checkbox">
<input type="checkbox" v-model="firewall.isOn"/>

View File

@@ -103,8 +103,11 @@ Vue.component("metric-chart", {
case "byte":
value = teaweb.formatBytes(value)
break
case "count":
value = teaweb.formatNumber(value)
break
}
return stat.keys[0] + ": " + value + "占比:" + percent + "%"
return stat.keys[0] + "<br/>" + that.valueTypeName + ": " + value + "<br/>占比:" + percent + "%"
}
},
series: [
@@ -312,8 +315,11 @@ Vue.component("metric-chart", {
case "byte":
value = teaweb.formatBytes(value)
break
case "count":
value = teaweb.formatNumber(value)
break
}
return stat.keys[0] + ": " + value + "占比:" + percent + "%"
return stat.keys[0] + "<br/>" + that.valueTypeName + "" + value + "<br/>占比:" + percent + "%"
}
},
yAxis: {

View File

@@ -86,14 +86,11 @@ Vue.component("origin-list-table", {
</thead>
<tr v-for="origin in vOrigins">
<td :class="{disabled:!origin.isOn}"><a href="" @click.prevent="updateOrigin(origin.id)">{{origin.addr}} &nbsp;<i class="icon clone outline small"></i></a>
<div v-if="origin.name.length > 0" style="margin-top: 0.5em">
<tiny-basic-label>{{origin.name}}</tiny-basic-label>
</div>
<div v-if="origin.domains != null && origin.domains.length > 0">
<grey-label v-for="domain in origin.domains">{{domain}}</grey-label>
</div>
<div v-if="origin.hasCert">
<tiny-basic-label>证书</tiny-basic-label>
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || (origin.domains != null && origin.domains.length > 0)">
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
<tiny-basic-label v-if="origin.host != null && origin.host.length > 0">主机名: {{origin.host}}</tiny-basic-label>
<span v-if="origin.domains != null && origin.domains.length > 0"><tiny-basic-label v-for="domain in origin.domains">匹配: {{domain}}</tiny-basic-label></span>
</div>
</td>
<td :class="{disabled:!origin.isOn}">{{origin.weight}}</td>

View File

@@ -23,7 +23,8 @@ Vue.component("reverse-proxy-box", {
readTimeout: {count: 0, unit: "second"},
idleTimeout: {count: 0, unit: "second"},
maxConns: 0,
maxIdleConns: 0
maxIdleConns: 0,
followRedirects: false
}
}
if (reverseProxyConfig.addHeaders == null) {
@@ -183,6 +184,13 @@ Vue.component("reverse-proxy-box", {
</tbody>
<more-options-tbody @change="changeAdvancedVisible" v-if="isOn()"></more-options-tbody>
<tbody v-show="isOn() && advancedVisible">
<tr v-show="family == null || family == 'http'">
<td>回源跟随</td>
<td>
<checkbox v-model="reverseProxyConfig.followRedirects"></checkbox>
<p class="comment">选中后,自动读取源站跳转后的网页内容。</p>
</td>
</tr>
<tr v-show="family == null || family == 'http'">
<td>自动添加的Header</td>
<td>

View File

@@ -21,7 +21,8 @@ Vue.component("ssl-config-box", {
hsts: null,
cipherSuitesIsOn: false,
cipherSuites: [],
http2Enabled: true
http2Enabled: true,
ocspIsOn: false
}
} else {
if (policy.certRefs == null) {
@@ -498,6 +499,14 @@ Vue.component("ssl-config-box", {
</td>
</tr>
<!-- OCSP -->
<tr>
<td>OCSP Stapling</td>
<td><checkbox name="ocspIsOn" v-model="policy.ocspIsOn"></checkbox>
<p class="comment">选中表示启用OCSP Stapling。</p>
</td>
</tr>
<!-- 客户端认证 -->
<tr>
<td>客户端认证方式</td>

View File

@@ -624,10 +624,10 @@ window.teaweb = {
return instance
},
encodeHTML: function (s) {
s = s.replace("&", "&amp;")
s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;")
s = s.replace("\"", "&quot;")
s = s.replace(/&/g, "&amp;")
s = s.replace(/</g, "&lt;")
s = s.replace(/>/g, "&gt;")
s = s.replace(/"/, "&quot;")
return s
}
}

View File

@@ -31,6 +31,9 @@ span.red,
pre.red {
color: #db2828;
}
span.blue {
color: #4183c4;
}
pre:not(.CodeMirror-line) {
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
}

View File

@@ -1 +1 @@
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":";AACA;EACC,WAAA;;AAGD;EACC,aAAA;;AAGD;EACC,qBAAA;;AAGD,CAAC;AAAW,CAAC,SAAS;AAAQ,CAAC,SAAS;AAAS,IAAI;EACpD,sBAAA;;AAGD,CAAC;AAAU,IAAI;AAAU,IAAI;EAC5B,cAAA;;AAGD,IAAI;AAAO,KAAK;AAAO,CAAC;EACvB,sBAAA;;AAGD,CAAC;EACA,iBAAA;;AAGD,IAAI;AAAM,GAAG;EACZ,cAAA;;AAGD,GAAG,IAAI;EACN,mBAAmB,8CAAnB;;AAGD;EACC,uBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAO;AAAI,MAAO;EACjB,2BAAA;;AAGD,CAAC;AAAU,GAAG;EACb,yBAAA;EACA,kBAAA;EACA,mBAAA;;AAGD,CAAC,QAAS;AAAI,GAAG,QAAS;EACzB,6BAAA;;AAGD;EACC,mBAAA;EACA,2BAAA;EACA,gBAAA;EACA,uBAAA;;AAGD,GAAG;AAAS,CAAC;EACZ,eAAA;;;AAID,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,YAAA;;AAGD,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,WAAA;;;AAID,MAAM;EACL,aAAA;;;AAID;EACC,kBAAA;EACA,UAAA;EACA,UAAA;EACA,mBAAA;EACA,kBAAA;EACA,UAAA;;AASD,mBANqC;EACpC;IACC,SAAA;;;AAIF,KAAK;EACJ,SAAA;;AAGD,KAAK;EACJ,UAAA;;AASD,mBANqC;EACpC,KAAK;IACJ,SAAA;;;AAIF,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM;EACX,mBAAA;;AAGD,KAAM,GAAE;EACP,yCAAA;;AAGD,KAAM,MAAM,GAAE;EACb,mBAAA;;AAGD,KAAM,MAAM,GAAE;EACb,sBAAA;;AAGD,KAAM,MAAM,GAAE,aAAc;EAC3B,mBAAA;;AAGD,KAAM,MAAM,GAAG;EACd,mBAAA;EACA,kBAAA;EACA,gBAAA;;AAGD,KAAM;EACL,mBAAA;EACA,4BAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,cAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;EACA,0BAAA;EACA,UAAA;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM;EACL,mBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,gBAAA;;AAGD,KAAM,QAAO;EACZ,gBAAA;EACA,cAAA;EACA,gBAAA;;;AAID,KAAK;EACJ,gBAAA;;AAGD,KAAK,KAAK;EACT,UAAA;EACA,WAAA;;;AAID;EACC,wBAAA;;;AAID,iBAAkB;EACjB,2BAAA;;AAGD,iBAAkB,MAAK;EACtB,UAAA;;AAGD,iBAAkB,MAAM;EACvB,2BAAA;;AAGD,MAAM;EACL,sBAAA;;;AAWD,mBAPqC;EACpC,OAAO,IAAI;IACV,sBAAA;;;;AAKF,KAAK;EACJ,0BAAA;;AAGD,KAAK;EACJ,yBAAA;;;AAOD,WAAY,MAAK;EAChB,wBAAA;EACA,2BAAA;;AAGD,WAAY;EACX,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK;EACjB,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK,KAAM;EACvB,kBAAA;;AAGD,YAAa;EACZ,wBAAA;;AAGD,KAAM;EACL,aAAA;;;AAID,IAAI;AAAQ,GAAG;EACd,yBAAA;;AAGD,GAAG;EACF,8BAAA;;;AAID,QAAS;EACR,WAAA;EACA,kBAAA;;;AAID,SAAU,MAAM;AAAG,SAAU;EAC5B,2BAAA;;;AAID;EACC,eAAA;EAEA,2BAAA;;AAHD,KAKC;EACC,qBAAA;EACA,mBAAA;EACA,WAAA;EACA,iBAAA;EACA,SAAA;EACA,gBAAA;EACA,sBAAA;EACA,cAAA;;AAbF,KAgBC,EAAC;EACA,8BAAA;EACA,YAAA;;AAlBF,KAqBC,EAAC;EACA,gBAAA;;AAKF;EACC,kBAAA;;AAGD,cAAc;AAAQ,aAAa;AAAQ,YAAY;EACtD,iCAAA;;AAGD;AAAgB;AAAe;EAC9B,iCAAA;;AAGD;EACC,2BAAA;;AAID,KAAK;EACJ,oCAAA;;AAID,QAAQ;EACP,4BAA4B,wBAA5B;EACA,2BAAA","file":"@layout_popup.css"}
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":";AACA;EACC,WAAA;;AAGD;EACC,aAAA;;AAGD;EACC,qBAAA;;AAGD,CAAC;AAAW,CAAC,SAAS;AAAQ,CAAC,SAAS;AAAS,IAAI;EACpD,sBAAA;;AAGD,CAAC;AAAU,IAAI;AAAU,IAAI;EAC5B,cAAA;;AAGD,IAAI;AAAO,KAAK;AAAO,CAAC;EACvB,sBAAA;;AAGD,CAAC;EACA,iBAAA;;AAGD,IAAI;AAAM,GAAG;EACZ,cAAA;;AAGD,IAAI;EACH,cAAA;;AAGD,GAAG,IAAI;EACN,mBAAmB,8CAAnB;;AAGD;EACC,uBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAO;AAAI,MAAO;EACjB,2BAAA;;AAGD,CAAC;AAAU,GAAG;EACb,yBAAA;EACA,kBAAA;EACA,mBAAA;;AAGD,CAAC,QAAS;AAAI,GAAG,QAAS;EACzB,6BAAA;;AAGD;EACC,mBAAA;EACA,2BAAA;EACA,gBAAA;EACA,uBAAA;;AAGD,GAAG;AAAS,CAAC;EACZ,eAAA;;;AAID,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,YAAA;;AAGD,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,WAAA;;;AAID,MAAM;EACL,aAAA;;;AAID;EACC,kBAAA;EACA,UAAA;EACA,UAAA;EACA,mBAAA;EACA,kBAAA;EACA,UAAA;;AASD,mBANqC;EACpC;IACC,SAAA;;;AAIF,KAAK;EACJ,SAAA;;AAGD,KAAK;EACJ,UAAA;;AASD,mBANqC;EACpC,KAAK;IACJ,SAAA;;;AAIF,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM;EACX,mBAAA;;AAGD,KAAM,GAAE;EACP,yCAAA;;AAGD,KAAM,MAAM,GAAE;EACb,mBAAA;;AAGD,KAAM,MAAM,GAAE;EACb,sBAAA;;AAGD,KAAM,MAAM,GAAE,aAAc;EAC3B,mBAAA;;AAGD,KAAM,MAAM,GAAG;EACd,mBAAA;EACA,kBAAA;EACA,gBAAA;;AAGD,KAAM;EACL,mBAAA;EACA,4BAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,cAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;EACA,0BAAA;EACA,UAAA;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM;EACL,mBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,gBAAA;;AAGD,KAAM,QAAO;EACZ,gBAAA;EACA,cAAA;EACA,gBAAA;;;AAID,KAAK;EACJ,gBAAA;;AAGD,KAAK,KAAK;EACT,UAAA;EACA,WAAA;;;AAID;EACC,wBAAA;;;AAID,iBAAkB;EACjB,2BAAA;;AAGD,iBAAkB,MAAK;EACtB,UAAA;;AAGD,iBAAkB,MAAM;EACvB,2BAAA;;AAGD,MAAM;EACL,sBAAA;;;AAWD,mBAPqC;EACpC,OAAO,IAAI;IACV,sBAAA;;;;AAKF,KAAK;EACJ,0BAAA;;AAGD,KAAK;EACJ,yBAAA;;;AAOD,WAAY,MAAK;EAChB,wBAAA;EACA,2BAAA;;AAGD,WAAY;EACX,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK;EACjB,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK,KAAM;EACvB,kBAAA;;AAGD,YAAa;EACZ,wBAAA;;AAGD,KAAM;EACL,aAAA;;;AAID,IAAI;AAAQ,GAAG;EACd,yBAAA;;AAGD,GAAG;EACF,8BAAA;;;AAID,QAAS;EACR,WAAA;EACA,kBAAA;;;AAID,SAAU,MAAM;AAAG,SAAU;EAC5B,2BAAA;;;AAID;EACC,eAAA;EAEA,2BAAA;;AAHD,KAKC;EACC,qBAAA;EACA,mBAAA;EACA,WAAA;EACA,iBAAA;EACA,SAAA;EACA,gBAAA;EACA,sBAAA;EACA,cAAA;;AAbF,KAgBC,EAAC;EACA,8BAAA;EACA,YAAA;;AAlBF,KAqBC,EAAC;EACA,gBAAA;;AAKF;EACC,kBAAA;;AAGD,cAAc;AAAQ,aAAa;AAAQ,YAAY;EACtD,iCAAA;;AAGD;AAAgB;AAAe;EAC9B,iCAAA;;AAGD;EACC,2BAAA;;AAID,KAAK;EACJ,oCAAA;;AAID,QAAQ;EACP,4BAA4B,wBAA5B;EACA,2BAAA","file":"@layout_popup.css"}

View File

@@ -31,6 +31,10 @@ span.red, pre.red {
color: #db2828;
}
span.blue {
color: #4183c4;
}
pre:not(.CodeMirror-line) {
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
}

View File

@@ -1,4 +1,5 @@
<first-menu>
<menu-item href="/clusters" code="index">集群列表</menu-item>
<menu-item href="/clusters" code="index">集群列表({{totalNodeClusters}})</menu-item>
<menu-item href="/clusters/create" code="create">创建集群</menu-item>
</first-menu>

View File

@@ -193,7 +193,7 @@ Tea.context(function () {
attackRatio = Math.round(stats[index].countAttackRequests * 10000 / stats[index].countRequests) / 100
}
return stats[index].day + " " + stats[index].hour + "时<br/>总请求数:" + stats[index].countRequests + "<br/>缓存请求数:" + stats[index].countCachedRequests + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + stats[index].countAttackRequests + "<br/>拦截比例:" + attackRatio + "%"
return stats[index].day + " " + stats[index].hour + "时<br/>总请求数:" + teaweb.formatNumber(stats[index].countRequests) + "<br/>缓存请求数:" + teaweb.formatNumber(stats[index].countCachedRequests) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + teaweb.formatNumber(stats[index].countAttackRequests) + "<br/>拦截比例:" + attackRatio + "%"
})
}
@@ -208,7 +208,7 @@ Tea.context(function () {
attackRatio = Math.round(stats[index].countAttackRequests * 10000 / stats[index].countRequests) / 100
}
return stats[index].day + "<br/>总请求数:" + stats[index].countRequests + "<br/>缓存请求数:" + stats[index].countCachedRequests + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + stats[index].countAttackRequests + "<br/>拦截比例:" + attackRatio + "%"
return stats[index].day + "<br/>总请求数:" + teaweb.formatNumber(stats[index].countRequests) + "<br/>缓存请求数:" + teaweb.formatNumber(stats[index].countCachedRequests) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + teaweb.formatNumber(stats[index].countAttackRequests) + "<br/>拦截比例:" + attackRatio + "%"
})
}

View File

@@ -252,7 +252,7 @@ Tea.context(function () {
attackRatio = Math.round(stats[index].countAttackRequests * 10000 / stats[index].countRequests) / 100
}
return stats[index].day + " " + stats[index].hour + "时<br/>总请求数:" + stats[index].countRequests + "<br/>缓存请求数:" + stats[index].countCachedRequests + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + stats[index].countAttackRequests + "<br/>拦截比例:" + attackRatio + "%"
return stats[index].day + " " + stats[index].hour + "时<br/>总请求数:" + teaweb.formatNumber(stats[index].countRequests) + "<br/>缓存请求数:" + teaweb.formatNumber(stats[index].countCachedRequests) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + teaweb.formatNumber(stats[index].countAttackRequests) + "<br/>拦截比例:" + attackRatio + "%"
})
}
@@ -267,7 +267,7 @@ Tea.context(function () {
attackRatio = Math.round(stats[index].countAttackRequests * 10000 / stats[index].countRequests) / 100
}
return stats[index].day + "<br/>总请求数:" + stats[index].countRequests + "<br/>缓存请求数:" + stats[index].countCachedRequests + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + stats[index].countAttackRequests + "<br/>拦截比例:" + attackRatio + "%"
return stats[index].day + "<br/>总请求数:" + teaweb.formatNumber(stats[index].countRequests) + "<br/>缓存请求数:" + teaweb.formatNumber(stats[index].countCachedRequests) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + teaweb.formatNumber(stats[index].countAttackRequests) + "<br/>拦截比例:" + attackRatio + "%"
})
}

View File

@@ -14,6 +14,13 @@
<p class="comment">缓存能使用的磁盘的最大容量0表示不限制。</p>
</td>
</tr>
<tr>
<td>磁盘缓存目录</td>
<td>
<input type="text" name="cacheDiskDir" maxlength="500" value="" v-model="node.cacheDiskDir"/>
<p class="comment">存放文件缓存的目录,通常填写绝对路径。不填则表示使用集群缓存策略中定义的目录。</p>
</td>
</tr>
<tr>
<td>缓存内存容量</td>
<td>

View File

@@ -27,7 +27,7 @@
</td>
</tr>
<tr>
<td>自动设置CNAME记录</td>
<td>自动设置CNAME记录<optional-label></optional-label></td>
<td>
<values-box :values="cnameRecords" name="cnameRecords" placeholder="记录名" ref="cnameRecords"></values-box>
<p class="comment">除集群已创建的网站服务之外自动解析到集群的CNAME记录比如<code-label @click.prevent="addCnameRecord('@')">@</code-label><code-label @click.prevent="addCnameRecord('www')">www</code-label></p>

View File

@@ -0,0 +1,5 @@
.white-span {
background: white;
border: 1px;
}
/*# sourceMappingURL=createPopup.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AAAA;EACC,iBAAA;EACA,WAAA","file":"createPopup.css"}

View File

@@ -32,17 +32,31 @@
<!-- IPSet -->
<tbody v-if="type == 'ipset'">
<tr>
<td>IPSet白名单名称 *</td>
<td>IPv4白名单名称 *</td>
<td>
<input type="text" name="ipsetWhiteName" value="edge_white_list" maxlength="64"/>
<p class="comment">只能是英文、数字、下划线的组合。</p>
<p class="comment"><span class="ui label basic grey tiny">白名单</span> 用来存放<span class="red">IPv4地址</span>只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPSet黑名单名称 *</td>
<td>IPv6白名单名称 *</td>
<td>
<input type="text" name="ipsetWhiteNameIPv6" value="edge_white_list_ipv6" maxlength="64"/>
<p class="comment"><span class="ui label basic grey tiny">白名单</span> 用来存放<span class="red">IPv6地址</span>。只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPv4黑名单名称 *</td>
<td>
<input type="text" name="ipsetBlackName" value="edge_black_list" maxlength="64"/>
<p class="comment">只能是英文、数字、下划线的组合。</p>
<p class="comment"><span class="ui label black tiny">黑名单</span> 用来存放<span class="red">IPv4地址</span>只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPv6 黑名单名称 *</td>
<td>
<input type="text" name="ipsetBlackNameIPv6" value="edge_black_list_ipv6" maxlength="64"/>
<p class="comment"><span class="ui label black tiny">黑名单</span> 用来存放<span class="red">IPv6地址</span>。只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>

View File

@@ -31,20 +31,34 @@
<!-- IPSet -->
<tbody v-if="type == 'ipset'">
<tr>
<td>IPSet白名单名称 *</td>
<td>
<input type="text" name="ipsetWhiteName" value="edge_white_list" maxlength="64" v-model="action.params.whiteName"/>
<p class="comment">只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPSet黑名单名称 *</td>
<td>
<input type="text" name="ipsetBlackName" value="edge_black_list" maxlength="64" v-model="action.params.blackName"/>
<p class="comment">只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPv4白名单名称 *</td>
<td>
<input type="text" name="ipsetWhiteName" value="edge_white_list" maxlength="64" v-model="action.params.whiteName"/>
<p class="comment"><span class="ui label basic grey tiny">白名单</span> 用来存放<span class="red">IPv4地址</span>只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPv6白名单名称 *</td>
<td>
<input type="text" name="ipsetWhiteNameIPv6" value="edge_white_list_ipv6" maxlength="64" v-model="action.params.whiteNameIPv6"/>
<p class="comment"><span class="ui label basic grey tiny">白名单</span> 用来存放<span class="red">IPv6地址</span>只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPv4黑名单名称 *</td>
<td>
<input type="text" name="ipsetBlackName" value="edge_black_list" maxlength="64" v-model="action.params.blackName"/>
<p class="comment"><span class="ui label black tiny">黑名单</span> 用来存放<span class="red">IPv4地址</span>。只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>IPv6 黑名单名称 *</td>
<td>
<input type="text" name="ipsetBlackNameIPv6" value="edge_black_list_ipv6" maxlength="64" v-model="action.params.blackNameIPv6"/>
<p class="comment"><span class="ui label black tiny">黑名单</span> 用来存放<span class="red">IPv6地址</span>。只能是英文、数字、下划线的组合。</p>
</td>
</tr>
<tr>
<td>创建IPTables规则</td>
<td>

View File

@@ -0,0 +1,21 @@
.cluster-name-td {
position: relative;
}
.cluster-name-td .icon.pin {
display: none;
position: absolute;
right: 1em;
top: 50%;
margin-top: -0.7em;
opacity: 0.6;
}
.cluster-name-td .icon.visible {
display: inline;
}
.cluster-name-td .icon.opacity {
opacity: 0.3;
}
.cluster-name-td:hover .icon.pin {
display: inline;
}
/*# sourceMappingURL=index.css.map */

View File

@@ -1 +1 @@
undefined
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;;AADD,gBAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,kBAAA;EACA,YAAA;;AATF,gBAYC,MAAK;EACJ,eAAA;;AAbF,gBAgBC,MAAK;EACJ,YAAA;;AAIF,gBAAgB,MACf,MAAK;EACJ,eAAA","file":"index.css"}

View File

@@ -41,11 +41,14 @@
</tr>
</thead>
<tr v-for="cluster in clusters">
<td>
<td class="cluster-name-td">
<a :href="'/clusters/cluster?clusterId=' + cluster.id"><keyword :v-word="keyword">{{cluster.name}}</keyword></a>
<div v-if="cluster.timeZone != null && cluster.timeZone.length > 0">
<grey-label>时区:{{cluster.timeZone}}</grey-label>
</div>
<a href="" title="取消置顶" v-if="cluster.isPinned" @click.prevent="pin(cluster.id, false)"><i class="icon pin grey visible"></i></a>
<a href="" title="置顶" v-else @click.prevent="pin(cluster.id, true)"><i class="icon pin grey opacity"></i></a>
</td>
<td class="center">
<a :href="'/clusters/cluster/nodes?clusterId=' + cluster.id" v-if="cluster.countAllNodes > 0"><span :class="{red:cluster.countAllNodes > cluster.countActiveNodes}">{{cluster.countAllNodes}}</span></a>

View File

@@ -4,4 +4,15 @@ Tea.context(function () {
this.showLatest = function () {
this.latestVisible = !this.latestVisible
}
this.pin = function (clusterId, isPinned) {
this.$post(".pin")
.params({
clusterId: clusterId,
isPinned: isPinned
})
.success(function () {
teaweb.reload()
})
}
})

View File

@@ -1,2 +1,26 @@
table a span {
.cluster-name-td {
position: relative;
.icon.pin {
display: none;
position: absolute;
right: 1em;
top: 50%;
margin-top: -0.7em;
opacity: 0.6;
}
.icon.visible {
display: inline;
}
.icon.opacity {
opacity: 0.3;
}
}
.cluster-name-td:hover {
.icon.pin {
display: inline;
}
}

View File

@@ -13,7 +13,8 @@
</div>
</form>
<table class="ui table celled selectable">
<p class="comment" v-if="clusters.length == 0">没有找到相应的集群。</p>
<table class="ui table celled selectable" v-if="clusters.length > 0">
<thead>
<tr>
<th>集群名称</th>
@@ -23,7 +24,9 @@
</tr>
</thead>
<tr v-for="cluster in clusters">
<td>{{cluster.name}}</td>
<td>
<keyword :v-word="keyword">{{cluster.name}}</keyword>
</td>
<td>{{cluster.countNodes}}</td>
<td><label-on :v-is-on="cluster.isOn"></label-on></td>
<td>

View File

@@ -6,7 +6,7 @@
<input type="hidden" name="domainId" :value="domain.id"/>
<table class="ui table definition selectable">
<tr>
<td class="title">是否启用TSIG *</td>
<td class="title">启用TSIG *</td>
<td>
<checkbox name="isOn" v-model="tsig.isOn"></checkbox>
</td>

View File

@@ -0,0 +1,84 @@
{$layout}
{$template "/left_menu_top"}
<div class="right-box without-tabbar">
<div class="margin"></div>
<form class="ui form" method="get" action="/servers/certs/ocsp">
<div class="ui fields inline">
<div class="ui field">
<input type="text" placeholder="关键词" style="width: 10em" name="keyword" v-model="keyword"/>
</div>
<div class="ui field">
<button class="ui button small">搜索</button>
&nbsp; <a href="/servers/certs/ocsp" v-if="keyword.length > 0">[清除条件]</a>
</div>
</div>
</form>
<div class="margin"></div>
<form class="ui form" v-if="certs.length > 0">
<div class="ui divider"></div>
<div class="ui fields inline">
<div class="ui field" v-if="certIds.length == 0" @click.prevent="resetAllCerts">
<button class="ui button small basic">重试所有证书</button>
</div>
<div class="ui field" v-if="certIds.length > 0">
<button class="ui button small basic" @click.prevent="resetCerts">重试选中证书</button>
</div>
<div class="ui field" v-if="certIds.length > 0">
<button class="ui button small basic" @click.prevent="ignoreCerts">忽略选中证书</button>
</div>
</div>
</form>
<p class="comment" v-if="certs.length == 0">暂时没有OCSP日志。</p>
<table class="ui table selectable celled" v-if="certs.length > 0">
<thead>
<tr>
<th style="width: 1em"><checkbox v-model="allChecked"></checkbox></th>
<th>证书说明</th>
<th>顶级发行组织</th>
<th>域名</th>
<th class="six wide">更新错误信息</th>
<th class="center">状态</th>
<th class="one op">操作</th>
</tr>
</thead>
<tbody v-for="(cert, index) in certs">
<tr>
<td><checkbox :id="'cert_' + cert.id" ref="certCheckboxes" @input="changeCerts"></checkbox></td>
<td><keyword :v-word="keyword">{{cert.name}}</keyword>
<div v-if="cert.isCA" style="margin-top:0.5em">
<micro-basic-label class="olive">CA</micro-basic-label>
</div>
<div v-if="cert.isACME" style="margin-top: 0.5em">
<micro-basic-label class="olive" title="通过ACME协议免费申请">ACME</micro-basic-label>
</div>
</td>
<td>
<span v-if="cert.commonNames != null && cert.commonNames.length > 0">{{cert.commonNames[cert.commonNames.length-1]}}</span>
</td>
<td>
<div v-for="dnsName in cert.dnsNames" style="margin-bottom:0.4em">
<span class="ui label tiny basic"><keyword :v-word="keyword">{{dnsName}}</keyword></span>
</div>
</td>
<td style="word-break: break-all">
<span class="red">{{cert.ocspError}}</span>
</td>
<td nowrap="" class="center">
<span class="ui label red tiny basic" v-if="!cert.isOn">未启用</span>
<span class="ui label red tiny basic" v-else-if="cert.isExpired">已过期</span>
<span class="ui label green tiny basic" v-else>有效中</span>
</td>
<td>
<a href="" @click.prevent="viewCert(cert.id)">详情</a> &nbsp;
</td>
</tr>
</tbody>
</table>
<div class="page" v-html="page"></div>
</div>

View File

@@ -0,0 +1,62 @@
Tea.context(function () {
this.certIds = []
this.allChecked = false
this.$delay(function () {
let that = this
this.$watch("allChecked", function (b) {
let boxes = that.$refs.certCheckboxes
boxes.forEach(function (box) {
if (b) {
box.check()
} else {
box.uncheck()
}
that.changeCerts()
})
})
})
this.changeCerts = function () {
let boxes = this.$refs.certCheckboxes
let that = this
this.certIds = []
boxes.forEach(function (box) {
if (box.isChecked()) {
let boxId = box.id
that.certIds.push(parseInt(boxId.split("_")[1]))
}
})
}
this.resetAllCerts = function () {
this.$post(".resetAll")
.success(function () {
teaweb.successRefresh("操作成功,将很快开始重试")
})
}
this.resetCerts = function () {
this.$post(".reset")
.params({ certIds: this.certIds })
.success(function () {
teaweb.successRefresh("操作成功,将很快开始重试")
})
}
this.ignoreCerts = function () {
this.$post(".ignore")
.params({ certIds: this.certIds })
.success(function () {
teaweb.successRefresh("忽略成功")
})
}
// 查看证书详情
this.viewCert = function (certId) {
teaweb.popup("/servers/certs/certPopup?certId=" + certId, {
height: "28em",
width: "48em"
})
}
})

View File

@@ -35,7 +35,7 @@
<tr>
<td class="color-border">内存最大容量</td>
<td>
<size-capacity-box :v-name="'fileMemoryCapacityJSON'" :v-count="0" :v-unit="'gb'" :key="'fileMemoryCapacityJSON'"></size-capacity-box>
<size-capacity-box :v-name="'fileMemoryCapacityJSON'" :v-count="1" :v-unit="'gb'" :key="'fileMemoryCapacityJSON'"></size-capacity-box>
<p class="comment">作为一级缓存的内存最大容量如果为0表示不使用内存作为一级缓存。</p>
</td>
</tr>
@@ -58,17 +58,18 @@
</tr>
</tbody>
<tr>
<td>最大内容尺寸</td>
<td>
<size-capacity-box :v-name="'maxSizeJSON'" :v-count="256" :v-unit="'mb'" :key="'maxSizeJSON'"></size-capacity-box>
<p class="comment">允许缓存的单个内容最大尺寸如果为0表示没有限制。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr>
<td>最大内容长度</td>
<td>
<size-capacity-box :v-name="'maxSizeJSON'" :v-count="256" :v-unit="'mb'" :key="'maxSizeJSON'"></size-capacity-box>
<p class="comment">允许缓存的最大内容长度如果为0表示没有限制。</p>
</td>
</tr>
<tr>
<td>容纳Key数量</td>
<td>
@@ -76,6 +77,13 @@
<p class="comment">可以容纳多少数量的Key0表示不限制。</p>
</td>
</tr>
<tr>
<td>同步写入压缩缓存</td>
<td>
<checkbox name="syncCompressionCache"></checkbox>
<p class="comment">选中后在压缩设置开启的情况下在缓存源站内容的同时也会同步写入压缩缓存不选中表示在源站内容缓存后下一次调用才会缓存压缩内容防止同一时间内硬盘IO负载过高。</p>
</td>
</tr>
<tr>
<td>描述</td>
<td>

View File

@@ -16,10 +16,16 @@
<div class="ui field">
<input type="text" name="keyword" v-model="keyword" placeholder="策略名称..."/>
</div>
<div class="ui field">
<select class="ui dropdown" name="storageType" v-model="storageType">
<option value="">[存储类型]</option>
<option v-for="storageType in storageTypes" :value="storageType.type">{{storageType.name}}</option>
</select>
</div>
<div class="ui field">
<button type="submit" class="ui button">搜索</button>
&nbsp;
<a :href="Tea.url('.')" v-if="keyword.length > 0 || clusterId > 0">[清除条件]</a>
<a :href="Tea.url('.')" v-if="keyword.length > 0 || clusterId > 0 || storageType.length > 0">[清除条件]</a>
</div>
</div>
</form>
@@ -38,10 +44,20 @@
</tr>
</thead>
<tr v-for="(policy, index) in cachePolicies">
<td><a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id"><keyword :v-word="keyword">{{policy.name}}</keyword></a></td>
<td>
<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id"><keyword :v-word="keyword">{{policy.name}}</keyword>
&nbsp;
<i class="icon disk small blue" v-if="policy.type == 'file'" title="硬盘"></i>
</a>
</td>
<td>{{infos[index].typeName}} <span class="small">{{policy.type}}</span></td>
<td>
<span v-if="policy.capacity != null && policy.capacity.count > 0">{{policy.capacity.count}}{{policy.capacity.unit.toUpperCase()}}</span>
<span v-if="policy.capacity != null && policy.capacity.count > 0">
{{policy.capacity.count}}{{policy.capacity.unit.toUpperCase()}}
<span v-if="policy.type == 'file' && policy.options.memoryPolicy != null && policy.options.memoryPolicy.capacity != null && policy.options.memoryPolicy.capacity.count > 0" class="small grey" title="内存容量">
(内存:{{policy.options.memoryPolicy.capacity.count}}{{policy.options.memoryPolicy.capacity.unit.toUpperCase()}}
</span>
</span>
<span v-else class="disabled">不限</span>
</td>
<td class="center">{{infos[index].countClusters}}</td>

View File

@@ -63,7 +63,7 @@
<td>最大内容长度</td>
<td>
<size-capacity-view :v-value="cachePolicy.maxSize" :v-default-text="'不限'"></size-capacity-view>
<p class="comment">允许缓存的最大内容长度如果为0表示没有限制。</p>
<p class="comment">允许缓存的单个内容最大尺寸如果为0表示没有限制。</p>
</td>
</tr>
<tr>
@@ -74,6 +74,13 @@
<p class="comment">可以容纳多少数量的Key0表示不限制。</p>
</td>
</tr>
<tr>
<td>同步写入压缩缓存</td>
<td>
<span v-if="cachePolicy.syncCompressionCache" class="green">Y</span>
<span v-else class="disabled">N</span>
</td>
</tr>
<tr>
<td>描述</td>
<td>

View File

@@ -66,17 +66,17 @@
</td>
</tr>
</tbody>
<tr>
<td>最大内容长度</td>
<td>
<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
<p class="comment">允许缓存的单个内容最大尺寸如果为0表示没有限制。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr>
<td>最大内容长度</td>
<td>
<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
<p class="comment">允许缓存的最大内容长度如果为0表示没有限制。</p>
</td>
</tr>
<tr>
<td>容纳Key数量</td>
<td>
@@ -84,6 +84,13 @@
<p class="comment">可以容纳多少数量的Key0表示不限制。</p>
</td>
</tr>
<tr>
<td>同步写入压缩缓存</td>
<td>
<checkbox name="syncCompressionCache" v-model="cachePolicy.syncCompressionCache"></checkbox>
<p class="comment">选中后在压缩设置开启的情况下在缓存源站内容的同时也会同步写入压缩缓存不选中表示在源站内容缓存后下一次调用才会缓存压缩内容防止同一时间内硬盘IO负载过高。</p>
</td>
</tr>
<tr>
<td>描述</td>
<td>

View File

@@ -13,7 +13,7 @@
<div v-show="tab == 'domainMatch'">
<table class="ui table selectable definition">
<tr>
<td class="title">是否严格匹配域名</td>
<td class="title">严格匹配域名</td>
<td>
<checkbox name="matchDomainStrictly" v-model="globalConfig.httpAll.matchDomainStrictly"></checkbox>
<p class="comment">如果选择了严格匹配域名,找不到匹配的域名时会采取对应的动作。</p>

View File

@@ -2,9 +2,9 @@
{$template "/datepicker"}
<first-menu>
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&hasError=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" :active="hasError > 0">错误日志</menu-item>
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&hasWAF=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" :active="hasWAF > 0">WAF日志</menu-item>
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&hasError=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError > 0">错误日志</menu-item>
<menu-item :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&day=' + day + '&hasWAF=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasWAF > 0">WAF日志</menu-item>
<menu-item :href="'/servers/logs/settings'" code="settings">设置</menu-item>
</first-menu>
@@ -14,12 +14,21 @@
<input type="hidden" name="hasWAF" :value="hasWAF"/>
<http-access-log-search-box :v-cluster-id="clusterId" :v-node-id="nodeId" :v-ip="ip" :v-domain="domain" :v-keyword="keyword">
<div class="ui field">
<input type="text" name="day" maxlength="10" placeholder="选择日期" style="width:7.8em" id="day-input" v-model="day"/>
<div class="ui right labeled input">
<input type="text" name="day" maxlength="10" placeholder="选择日期" style="width:7.8em" id="day-input" v-model="day"/>
<span class="ui label"></span>
</div>
</div>
<div class="ui field">
<div class="ui right labeled input">
<input type="text" name="hour" maxlength="2" style="width: 3.5em" v-model="hour"/>
<span class="ui label"></span>
</div>
</div>
</http-access-log-search-box>
</form>
<warning-message v-if="isSlowQuery">看起来你的访问日志查询非常慢({{slowQueryCost}}s建议通过添加新的 <a href="/db">[日志节点]</a> 来分散存储访问日志。</warning-message>
<warning-message v-if="isSlowQuery">看起来你的访问日志查询非常慢({{slowQueryCost}}s建议<span v-if="domain.length == 0"> 1指定具体域名查询2</span>通过添加新的 <a href="/db">[日志节点]</a> 来分散存储访问日志。</warning-message>
<p class="comment" v-if="accessLogs.length == 0">暂时还没有访问日志。</p>
@@ -31,10 +40,10 @@
</table>
<div v-if="accessLogs.length > 0">
<a :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" v-if="hasPrev">上一页</a>
<a :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" v-if="hasPrev">上一页</a>
<span v-else class="disabled">上一页</span>
<span class="disabled">&nbsp; | &nbsp;</span>
<a :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" v-if="hasMore">下一页</a>
<a :href="path + '?clusterId=' + clusterId + '&nodeId=' + nodeId + '&serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" v-if="hasMore">下一页</a>
<span v-else class="disabled">下一页</span>
<page-size-selector></page-size-selector>

View File

@@ -41,5 +41,24 @@
</td>
</tr>
</table>
<h3>自动分表设置</h3>
<table class="ui table definition selectable">
<tr>
<td class="title">启用自动分表</td>
<td>
<checkbox name="enableAutoPartial" v-model="config.enableAutoPartial"></checkbox>
<p class="comment">启用后,可以将单天访问日志自动存储到多个数据表中,以提升查询速度。</p>
</td>
</tr>
<tr v-show="config.enableAutoPartial">
<td>单表最多行数</td>
<td>
<input type="text" style="width: 8em" name="rowsPerTable" v-model="config.rowsPerTable" maxlength="16"/>
<p class="comment">单个数据表最多能存储的最多行数。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -203,7 +203,7 @@ Tea.context(function () {
attackRatio = Math.round(stats[index].countAttackRequests * 10000 / stats[index].countRequests) / 100
}
return stats[index].day + " " + stats[index].hour + "时<br/>总请求数:" + stats[index].countRequests + "<br/>缓存请求数:" + stats[index].countCachedRequests + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + stats[index].countAttackRequests + "<br/>拦截比例:" + attackRatio + "%"
return stats[index].day + " " + stats[index].hour + "时<br/>总请求数:" + teaweb.formatNumber(stats[index].countRequests) + "<br/>缓存请求数:" + teaweb.formatNumber(stats[index].countCachedRequests) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + teaweb.formatNumber(stats[index].countAttackRequests) + "<br/>拦截比例:" + attackRatio + "%"
})
}
@@ -218,7 +218,7 @@ Tea.context(function () {
attackRatio = Math.round(stats[index].countAttackRequests * 10000 / stats[index].countRequests) / 100
}
return stats[index].day + "<br/>总请求数:" + stats[index].countRequests + "<br/>缓存请求数:" + stats[index].countCachedRequests + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + stats[index].countAttackRequests + "<br/>拦截比例:" + attackRatio + "%"
return stats[index].day + "<br/>总请求数:" + teaweb.formatNumber(stats[index].countRequests) + "<br/>缓存请求数:" + teaweb.formatNumber(stats[index].countCachedRequests) + "<br/>缓存命中率:" + cachedRatio + "%<br/>拦截攻击数:" + teaweb.formatNumber(stats[index].countAttackRequests) + "<br/>拦截比例:" + attackRatio + "%"
})
}

View File

@@ -5,9 +5,9 @@
<div class="right-box">
<first-menu>
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasError=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" :active="hasError > 0">错误日志</menu-item>
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasWAF=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" :active="hasWAF > 0">WAF日志</menu-item>
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError == 0 && hasWAF == 0">所有日志</menu-item>
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasError=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasError > 0">错误日志</menu-item>
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasWAF=1' + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" :active="hasWAF > 0">WAF日志</menu-item>
</first-menu>
<form method="get" class="ui form small" :action="path">
@@ -18,6 +18,12 @@
<div class="ui field">
<input type="text" name="day" maxlength="10" placeholder="选择日期" style="width:7.8em" id="day-input" v-model="day"/>
</div>
<div class="ui field">
<div class="ui right labeled input">
<input type="text" name="hour" maxlength="2" style="width: 3.5em" v-model="hour"/>
<span class="ui label"></span>
</div>
</div>
</http-access-log-search-box>
</form>
@@ -31,10 +37,10 @@
</table>
<div v-if="accessLogs.length > 0">
<a :href="path + '?serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" v-if="hasPrev">上一页</a>
<a :href="path + '?serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" v-if="hasPrev">上一页</a>
<span v-else class="disabled">上一页</span>
<span class="disabled">&nbsp; | &nbsp;</span>
<a :href="path + '?serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&pageSize=' + pageSize" v-if="hasMore">下一页</a>
<a :href="path + '?serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError + '&hasWAF=' + hasWAF + '&keyword=' + keyword + '&ip=' + ip + '&domain=' + domain + '&hour=' + hour + '&pageSize=' + pageSize" v-if="hasMore">下一页</a>
<span v-else class="disabled">下一页</span>
<page-size-selector></page-size-selector>
</div>

View File

@@ -9,7 +9,7 @@
<input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition">
<tr>
<td class="title">是否启用HTTP</td>
<td class="title">启用HTTP</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="httpConfig.isOn"/>

View File

@@ -15,7 +15,7 @@
<input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition">
<tr>
<td class="title">是否启用HTTPS</td>
<td class="title">启用HTTPS</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="httpsConfig.isOn"/>

View File

@@ -55,7 +55,7 @@
<td>专属域名</td>
<td>
<domains-box></domains-box>
<p class="comment">默认不需要填写,表示支持所有域名。如果填写了专属域名,表示当前路由规则只会在这些域名被访问时才生效。</p>
<p class="comment">默认不需要填写,表示支持所有域名。如果填写了专属域名,表示当前路由规则只会在所列的专属域名被访问时才生效。</p>
</td>
</tr>
<tr>

Some files were not shown because too many files have changed in this diff Show More