Compare commits

..

319 Commits

Author SHA1 Message Date
刘祥超
7f8dd70c9b 增加简化版的创建TCP网站API 2023-06-18 17:14:29 +08:00
刘祥超
1748637c31 增加简化版的创建HTTP网站API 2023-06-18 16:19:52 +08:00
刘祥超
90c06c4175 把“服务”改成“网站” 2023-06-18 10:57:07 +08:00
刘祥超
fe9bc332c1 增加API注释 2023-06-17 21:05:03 +08:00
刘祥超
f436763c8d 默认不启用性能优化 2023-06-17 19:19:40 +08:00
刘祥超
6bf017ee22 完善API注释 2023-06-16 18:27:16 +08:00
刘祥超
70bc6e7d8e 缓存条件类型增加“URL通配符” 2023-06-16 11:34:59 +08:00
刘祥超
e42b13f278 用户设置中增加登录状态下检查客户端区域的选项 2023-06-16 10:59:30 +08:00
刘祥超
cd545b25c9 80/443端口的源站自动修正HTTP和HTTPS协议,防止有些小白用户不知道HTTP和HTTPS的区别 2023-06-16 08:47:47 +08:00
刘祥超
574b264a37 缓存条件增加"强制返回区间内容"选项 2023-06-15 15:14:25 +08:00
刘祥超
12abb714e0 优化OSS源站相关代码 2023-06-13 15:44:43 +08:00
刘祥超
8bef580c2e 智能DNS实现DoH功能 2023-06-11 17:57:41 +08:00
刘祥超
b08064c1de 初步实现对象存储源站 2023-06-07 17:26:34 +08:00
刘祥超
555673b87d 允许在集群设置 -- “网站设置” 中设置节点IP访问显示的内容 2023-06-05 19:27:05 +08:00
刘祥超
e9145ec22c 网站全局设置增加“强制Ln请求“选项 2023-06-05 17:05:49 +08:00
刘祥超
ffd261b285 改进智能DNS验证相关API 2023-06-05 12:34:51 +08:00
刘祥超
2ff4c67e57 增加一处测试用例 2023-06-02 14:58:08 +08:00
刘祥超
1e1e6e7e81 查找HTTP3端口时只计算已经启用的 2023-06-01 19:42:40 +08:00
刘祥超
71e03f5e07 初步实现HTTP3 2023-06-01 17:48:01 +08:00
刘祥超
6a1a2640d3 Update rpc.json 2023-05-28 19:26:18 +08:00
刘祥超
be32bff7db 提供用户某日刷新/预热缓存数量查询API 2023-05-28 18:00:42 +08:00
刘祥超
afd9e3134d WAF增加“跳转”动作 2023-05-28 17:45:39 +08:00
刘祥超
a9dd5e3ba3 URL跳转精准匹配/匹配前缀支持URL查询参数 2023-05-27 21:00:34 +08:00
刘祥超
5caafcb99a 增加读取节点数配额接口 2023-05-27 15:30:05 +08:00
刘祥超
f34633f22a WAF国家/地区封禁、省份封禁增加例外URL、限制URL 2023-05-25 12:02:25 +08:00
刘祥超
2966240a5c 网站全局设置中增加“自动匹配证书”选项 2023-05-25 11:00:25 +08:00
刘祥超
05255c18d8 智能调度动作可以排序 2023-05-24 15:38:37 +08:00
刘祥超
a74a751a50 删除不需要的文件 2023-05-24 15:06:22 +08:00
刘祥超
c24fa291bd 改进流量相关的智能调度过期时间设置 2023-05-24 15:04:07 +08:00
刘祥超
e33f98f869 优化代码 2023-05-23 19:51:28 +08:00
刘祥超
e3ada6da81 实现集群CC防护策略设置 2023-05-23 19:16:09 +08:00
刘祥超
47c0ade078 实现集群自定义页面 2023-05-22 17:30:08 +08:00
刘祥超
2af8e6c7f8 HTTP Header中支持设置非标Header 2023-05-19 19:52:22 +08:00
刘祥超
e909d4c59a 优化代码 2023-05-19 16:44:02 +08:00
刘祥超
ee744d6c70 HTTP Header - CORS跨域设置增加多个选项 2023-05-19 16:33:13 +08:00
刘祥超
dbea336fee 增加复制节点动作API 2023-05-19 11:12:09 +08:00
刘祥超
5961d955d7 实现基础的智能调度 2023-05-17 18:42:35 +08:00
刘祥超
529a98e694 域名解析功能实现健康检查 2023-05-03 17:09:36 +08:00
刘祥超
48aeffba7e 防盗链增加”同时检查Origin选项“ 2023-05-02 17:05:56 +08:00
刘祥超
a7ac768709 优化编译脚本 2023-04-25 10:26:34 +08:00
刘祥超
ca8226fe9d 远程升级API节点时自动上传边缘节点安装文件 2023-04-23 19:43:01 +08:00
刘祥超
a6395b34a3 5秒盾“加入IP白名单”默认为true 2023-04-23 16:04:59 +08:00
刘祥超
97f56c7bb1 创建ACME用户、ACME任务时可以指定平台用户 2023-04-23 15:01:10 +08:00
刘祥超
c0856d3b46 安全设置中增加“检查客户端指纹”、“检查客户端区域”选项 2023-04-19 18:21:44 +08:00
刘祥超
4e80f62837 IP库查询增加更多信息 2023-04-19 18:20:34 +08:00
刘祥超
753552d4a4 修复证书数据可能获取不到的问题 2023-04-10 09:13:05 +08:00
刘祥超
1f7e60d062 修复证书更新后服务配置无法更新的问题 2023-04-09 21:31:31 +08:00
刘祥超
9dc9cdb28f 修复一个单词拼写错误 2023-04-09 20:12:00 +08:00
刘祥超
90bba69ee5 去除不需要的接口 2023-04-09 17:04:45 +08:00
刘祥超
498f388cf2 增加服务之间拷贝配置的API(开源版本只有定义,没有实现) 2023-04-09 16:00:21 +08:00
刘祥超
8adb09b95f 提供批量更新服务配置API(阶段性提交) 2023-04-06 20:49:47 +08:00
刘祥超
521eee5f2f 审计日志列表增加级别筛选 2023-04-06 10:06:37 +08:00
刘祥超
caf544eff1 自动检查管理员弱密码并提醒 2023-04-04 17:26:22 +08:00
刘祥超
c9ae3df3d3 5秒盾策略变化时只更新策略配置 2023-04-03 15:59:45 +08:00
刘祥超
3485db9a4a 可以使用用户ID查询IP名单 2023-04-03 10:02:47 +08:00
刘祥超
1b368ee490 默认支持低版本HTTP 2023-04-01 21:46:31 +08:00
刘祥超
9ec79adac6 集群服务设置增加“支持低版本HTTP”选项 2023-04-01 09:52:01 +08:00
刘祥超
c3e43503a0 可以批量上传IP名单 2023-03-31 21:37:32 +08:00
刘祥超
eb5d47935c 提供修改网站名称的接口 2023-03-31 15:30:31 +08:00
刘祥超
5521c42cb6 优化代码 2023-03-31 14:05:18 +08:00
刘祥超
226e91a106 IP库增加释放方法 2023-03-31 12:40:13 +08:00
刘祥超
917f8d76a1 增加查询授权版本接口 2023-03-31 12:39:48 +08:00
刘祥超
cfc1a7461c IP库加密/其他对IP库的改进 2023-03-30 20:02:46 +08:00
刘祥超
67941b5379 更新IP库文件 2023-03-29 21:19:11 +08:00
刘祥超
e35caae373 优化IP库模板分析程序 2023-03-29 21:19:01 +08:00
刘祥超
ad84614b2e 优化IP库生成文件的尺寸 2023-03-29 20:08:08 +08:00
刘祥超
32c89d3ae7 IP库制品列表中显示文件尺寸 2023-03-29 20:07:15 +08:00
刘祥超
22bf132efb 修复IP库模板可能无法正确解析数据的问题 2023-03-29 20:06:56 +08:00
刘祥超
67aafeee30 修复IP查询结果显示时可能不显示县级单位的问题 2023-03-29 20:06:15 +08:00
刘祥超
033a3a624d 增加默认CC设置 2023-03-26 12:40:50 +08:00
刘祥超
8d067b6efc 上传单个证书时可以选择所属用户 2023-03-26 12:24:58 +08:00
刘祥超
602a89602e 服务基本信息API中增加用户ID信息 2023-03-25 20:51:28 +08:00
刘祥超
0036b0730b 增加多个接口定义 2023-03-24 19:07:04 +08:00
刘祥超
4b0fe4b78d 上传流量数据时同时上传服务所属用户ID 2023-03-22 19:33:31 +08:00
刘祥超
ca580e820b 合并部分流量查询和带宽查询 2023-03-22 17:53:01 +08:00
刘祥超
9681b29f2c 用户界面设置增加“自动检查CNAME”选项 2023-03-21 11:59:17 +08:00
刘祥超
b2224aa4ae 更新相关库 2023-03-19 17:45:25 +08:00
刘祥超
fad1c3c6ae DNS集群增加自动检测端口选项 2023-03-19 17:45:15 +08:00
刘祥超
995acfe133 修复DataMap无法在多个节点之间共享的问题 2023-03-19 10:23:32 +08:00
刘祥超
9b943f7f03 节点组合配置时服务间可以共用证书数据 2023-03-18 22:15:13 +08:00
刘祥超
d43cbc4f90 查询节点DNS信息时可以区分节点是否已安装 2023-03-18 16:04:27 +08:00
刘祥超
914070f7cc 删除不必要的文件内容 2023-03-17 12:15:30 +08:00
刘祥超
46dc42ffe3 当HTTP和HTTPS端口冲突时提示用户 2023-03-17 11:12:23 +08:00
刘祥超
e938bb34f1 用户系统增加页面背景颜色设置 2023-03-16 16:58:14 +08:00
刘祥超
3ad6c00956 读取节点列表时可以按照连接数排序 2023-03-15 17:58:01 +08:00
刘祥超
e6efbacb98 节点看板数据中增加当月、昨日、今日流量 2023-03-15 17:02:14 +08:00
刘祥超
37e05101be 集群看板数据中增加当月流量 2023-03-15 16:25:22 +08:00
刘祥超
a6830af28e 调整统计相关配置默认值 2023-03-12 10:56:53 +08:00
刘祥超
65973c65ac 上传统计数据时使用ID取代名称 2023-03-12 10:21:14 +08:00
刘祥超
01890aa83d 在集群服务设置中增加服务统计相关选项 2023-03-11 10:42:59 +08:00
刘祥超
34f33a0979 WAF cc2模板中增加启用指纹选项 2023-03-10 15:16:29 +08:00
刘祥超
dd3b6b0fe8 优化旧cc统计注释说明 2023-03-10 10:16:44 +08:00
刘祥超
4c7618f623 提供删除运行日志的接口 2023-03-09 16:20:24 +08:00
刘祥超
c73a05eceb 增加CC防护相关API定义、配置 2023-03-09 12:10:31 +08:00
刘祥超
f4a690a5c3 优化URL匹配方法 2023-03-07 17:21:38 +08:00
刘祥超
866697ddd0 集群服务设置增加“记录找不到网站日志”选项 2023-03-07 10:30:44 +08:00
刘祥超
22b945ec40 5秒盾支持例外URL和限制URL 2023-03-06 21:49:11 +08:00
刘祥超
d835b36660 远程升级API节点(部分实现) 2023-03-04 21:22:17 +08:00
刘祥超
b375a40340 智能DNS增加记录权重 2023-03-02 20:06:54 +08:00
刘祥超
a068ce9a4f 对边缘节点配置缓存进行加密,提升安全性 2023-03-02 10:28:15 +08:00
刘祥超
4379acbeea WAF拦截动作可以设置最大封禁时间,从而实现封禁时间随机 2023-03-01 18:59:47 +08:00
刘祥超
a086496d7c WAF支持忽略全局WAF规则 2023-03-01 16:52:30 +08:00
刘祥超
7d80c58871 节点IP地址可以设置专属集群 2023-03-01 11:39:01 +08:00
刘祥超
0933ae903b 实现峰值带宽和平均带宽两种带宽算法 2023-02-27 10:47:31 +08:00
刘祥超
727ac23e17 增加多个配置项 2023-02-23 21:28:42 +08:00
刘祥超
99acf99a48 验证相关和一些注释 2023-02-22 19:46:50 +08:00
刘祥超
23db1c4b77 增加高防相应对象 2023-02-22 17:36:41 +08:00
刘祥超
d03775957e 增加${requestPathLowerExtension}变量 2023-02-10 10:53:05 +08:00
刘祥超
ec166af0c3 修复客户端CA证书设置不起作用的Bug 2023-02-09 11:31:33 +08:00
刘祥超
be29ba72a0 增加管理员和用户登录SESSION API 2023-02-04 15:17:27 +08:00
刘祥超
ce72dcf4dc 增加生成文档的测试用例 2023-01-13 19:36:10 +08:00
刘祥超
c024049778 优化域名匹配,现在 example.com:* 可以匹配 example.com 2023-01-10 10:03:43 +08:00
刘祥超
0863912e0c 用户界面设置中增加“在流量图表中显示缓存相关信息”选项 2023-01-08 11:49:45 +08:00
刘祥超
b19c7f5aa6 用户Dashboard中增加缓存、攻击相关信息 2023-01-08 11:49:30 +08:00
刘祥超
f5bdf33618 WAF增加“在IP列表内”操作符/优化部分操作符代号 2023-01-08 10:15:57 +08:00
刘祥超
c6face62b1 集群服务设置增加自动读超时选项 2023-01-07 20:04:13 +08:00
刘祥超
d3c8d8fd04 调整WAF操作符顺序 2023-01-07 09:35:09 +08:00
刘祥超
16e418447a WAF增加包含任一字符串、包含所有字符串操作符 2023-01-06 20:06:57 +08:00
刘祥超
c77724cf9e IP范围支持多行 2023-01-06 19:13:37 +08:00
刘祥超
606a73f6dd 优化请求条件操作符描述 2023-01-06 16:12:14 +08:00
刘祥超
f48a441f23 集群服务设置中增加性能设置 2023-01-01 19:27:09 +08:00
刘祥超
8d55c38459 优化证书加载速度 2022-12-31 18:34:09 +08:00
刘祥超
37e045876e 优化证书加载速度 2022-12-31 17:22:10 +08:00
刘祥超
bd5a1c5eda 优化证书数量很多时的页面加载速度 2022-12-31 17:12:55 +08:00
刘祥超
bd4cc6f5f5 实现UA名单功能 2022-12-30 20:48:44 +08:00
刘祥超
d417f6f751 内容压缩支持例外扩展名 2022-12-30 12:04:23 +08:00
刘祥超
d48697f4ce 默认情况下内容压缩不支持Partial Content 2022-12-30 11:43:53 +08:00
刘祥超
841a98349d 增加CORS自适应跨域 2022-12-29 17:16:11 +08:00
刘祥超
24d710d39c 用户系统增加自定义页脚 2022-12-28 16:36:37 +08:00
刘祥超
1ed754f285 增加修改服务所属用户API 2022-12-22 11:42:44 +08:00
刘祥超
243ceab3db DNS完善实现SRV和CAA记录 2022-12-15 16:18:00 +08:00
刘祥超
eaca98ee3e 智能DNS初步支持搜索引擎线路 2022-12-13 18:39:11 +08:00
刘祥超
11b0a12304 实现用户通过邮件重置密码功能 2022-12-10 15:54:39 +08:00
刘祥超
ce7911c3fe 初步完成用户电子邮箱绑定(激活) 2022-12-08 20:26:20 +08:00
刘祥超
44a3952f05 实现线路优先级/多个NS接口增加用户ID参数 2022-12-03 20:49:10 +08:00
刘祥超
a8340b8a8a 增加查询某个集群已验证域名API 2022-12-01 19:39:53 +08:00
刘祥超
b4f56c044c 优化WAF操作符提示 2022-12-01 15:20:03 +08:00
刘祥超
8b2088d498 用户可以使用管理员设置的公用线路 2022-11-24 17:20:26 +08:00
刘祥超
e7bf608552 导出API列表时对数据进行排序,以保证每次输出的稳定性 2022-11-22 16:45:14 +08:00
刘祥超
2c06c8932d 优化API角色提取 2022-11-22 14:36:06 +08:00
刘祥超
789aeab579 节点状态中增加API调用统计 2022-11-22 14:35:31 +08:00
刘祥超
a95d202ef0 在节点详情中显示API节点地址/DNS节点也支持自定义API节点地址 2022-11-21 21:08:17 +08:00
刘祥超
64f54d462e 节点可以单独设置所使用的API节点地址 2022-11-21 19:55:09 +08:00
刘祥超
52a20b9915 DNS API支持查询多个同名记录 2022-11-17 17:34:10 +08:00
刘祥超
69ab70b750 优化代码 2022-11-17 14:45:41 +08:00
刘祥超
890296c88b 请求变量增加${cname},WAF checkpoint增加cname和isCNAME 2022-11-16 15:01:00 +08:00
刘祥超
e5ba474419 改进变量分析测试用例 2022-11-16 14:27:20 +08:00
刘祥超
0f7482511e 只有边缘节点有自定义缓存目录时才会更新缓存策略 2022-11-15 20:40:59 +08:00
刘祥超
ea58e6094c 边缘节点支持设置多个缓存目录 2022-11-15 20:35:39 +08:00
刘祥超
4d5fd28f97 增加操作系统和浏览器信息维护接口 2022-11-11 17:46:27 +08:00
刘祥超
7a139b43a9 域名匹配增加通配符端口 2022-11-09 18:21:05 +08:00
刘祥超
0d1108387d 智能DNS:用户添加域名时,可以不需要经过TXT验证 2022-11-09 15:47:17 +08:00
刘祥超
e67af97487 MX记录支持优先级设置 2022-11-06 20:21:11 +08:00
刘祥超
629a2a5a8e 获取单节点同步任务接口增加版本号(version)参数 2022-11-06 11:51:58 +08:00
刘祥超
884776fb85 域名跳转增加忽略跳转前端口选项 2022-11-04 20:59:29 +08:00
刘祥超
f0e9b5c7e1 带宽相关数据增加百分位 2022-11-04 20:29:56 +08:00
刘祥超
3849b651af 用户看板增加带宽百分位 2022-11-04 17:39:33 +08:00
刘祥超
4d550577ee 删除不必要的文件 2022-11-04 16:56:14 +08:00
刘祥超
b3e64f7241 时钟同步增加是否检查chrony选项 2022-11-03 14:58:25 +08:00
刘祥超
f315b7b1d6 NSDomainService.FindNSDomainWithNameRequest()增加userId参数 2022-11-01 09:47:13 +08:00
刘祥超
2de1a8aa4e 增加默认集群DNS设置 2022-10-28 15:26:44 +08:00
刘祥超
cb3bf14df8 节点SSH登录自动使用集群设置 2022-10-26 19:23:29 +08:00
刘祥超
1d66029ef0 集群全局服务配置中增加多个访问日志相关选项 2022-10-26 17:49:45 +08:00
刘祥超
b795f60672 URL跳转中增加域名跳转、端口跳转 2022-10-26 16:07:32 +08:00
刘祥超
76e98174ee 节点设置中增加“通过IP名单”选项 2022-10-26 10:42:02 +08:00
刘祥超
18765d29f2 优化从API实现代码中提取角色的方法 2022-10-25 16:32:16 +08:00
刘祥超
9a38d40937 IP名单增加模糊搜索 2022-10-25 12:27:23 +08:00
刘祥超
43ad1ff67e proto文件增加注释 2022-10-24 18:33:51 +08:00
刘祥超
9f4e838f1d WAF参数定义增加优先级 2022-10-24 17:56:37 +08:00
刘祥超
e95909e293 修复域名解析--集群中单节点多IP时无法修改IP的Bug 2022-10-24 16:34:12 +08:00
刘祥超
759189bca1 添加、修改、删除HTTP Header时增加通用Header提示 2022-10-24 15:42:23 +08:00
刘祥超
3dd24dc5e7 集群服务设置--访问日志中可以设置是否只记录通用Header 2022-10-24 14:39:27 +08:00
刘祥超
156172dacf 防盗链功能增加禁止的来源域名 2022-10-24 10:21:13 +08:00
刘祥超
b6e0740b27 更新用户服务可用状态时同时返回状态 2022-10-23 20:12:33 +08:00
刘祥超
57f3c72058 修改部分小数数字精度(float->double),增加用户服务状态API 2022-10-23 16:29:08 +08:00
刘祥超
a9789c2f22 用户账单接口增加多个参数 2022-10-21 15:44:36 +08:00
刘祥超
ca02782ba5 增加操作节点区域相关接口 2022-10-20 15:14:22 +08:00
刘祥超
1e75f61464 增加流量包相关接口 2022-10-20 10:24:52 +08:00
刘祥超
e98de100b9 增加修改和读取用户计费方式和计费周期接口 2022-10-15 19:15:36 +08:00
刘祥超
387ee8d9c9 增加流量带宽子账单接口/把 regionId 改为 nodeRegionId 2022-10-14 16:17:18 +08:00
刘祥超
a5af5e0597 可以使用账单号获取账单信息 2022-10-14 10:56:01 +08:00
刘祥超
9af8721d8d 优化代码 2022-10-14 10:03:49 +08:00
刘祥超
0d8c8064bf 增加多个服务带宽、流量统计接口 2022-10-03 19:26:47 +08:00
刘祥超
010a9b61d5 删除不必要的代码 2022-10-01 07:17:41 +08:00
刘祥超
b277af4ac2 优化服务列表API 2022-09-30 19:04:36 +08:00
刘祥超
b85016d6c9 完善订单、DNS套餐服务API 2022-09-29 19:21:35 +08:00
刘祥超
10ea8911bc 完善订单、支付相关接口定义 2022-09-29 10:22:51 +08:00
刘祥超
fbfcc8d2c0 阶段性提交 2022-09-28 17:39:28 +08:00
刘祥超
11c2682f59 删除不必要的文件 2022-09-28 09:03:52 +08:00
刘祥超
8a005850db 查询5分钟流量接口增加timeFrom和timeTo参数 2022-09-24 18:55:25 +08:00
刘祥超
a0acc54565 服务流量接口增加5分钟查询接口 2022-09-24 18:36:34 +08:00
刘祥超
8234d0301f 优化智能DNS相关接口 2022-09-24 14:07:59 +08:00
刘祥超
59de46d34f 智能DNS支持应答模式配置 2022-09-23 19:02:21 +08:00
刘祥超
0dcdde06e0 删除不必要的文件 2022-09-23 14:42:52 +08:00
刘祥超
b9b7ca4c41 智能DNS访问日志增加只记录失败查询选项 2022-09-22 18:41:51 +08:00
刘祥超
5244b53270 增加防盗链功能 2022-09-22 16:33:42 +08:00
刘祥超
dd460bc40d 每个服务只初始化一次 2022-09-22 11:09:11 +08:00
刘祥超
d9fb6a2c84 优化代码 2022-09-21 15:09:23 +08:00
刘祥超
c05072d12e 增加查找NS集群主机地址的API 2022-09-21 15:06:01 +08:00
刘祥超
caba96bfeb DNS集群设置时区 2022-09-19 17:00:27 +08:00
刘祥超
a36344f3bb 同步域名解析时不再强制要求修复节点问题 2022-09-18 10:40:43 +08:00
刘祥超
5db4568d7e 优化代码/DNS域名增加分页 2022-09-18 10:22:47 +08:00
刘祥超
4e219b09e0 集群增加自动安装nftables配置 2022-09-18 09:26:01 +08:00
刘祥超
1d7986289d 集群增加是否远程启动选项 2022-09-17 15:11:25 +08:00
刘祥超
710ec09b14 检查域名是否存在时同时检查泛域名 2022-09-17 11:38:51 +08:00
刘祥超
324d24fe5a 创建集群的时候初始化全局服务配置 2022-09-16 19:34:24 +08:00
刘祥超
0f060002e3 集群设置中增加服务设置 2022-09-16 18:41:10 +08:00
刘祥超
2eb19348cc 访问日志中增加源站状态码 2022-09-16 10:07:29 +08:00
刘祥超
a92d8887e3 集群增加自动同步时钟选项 2022-09-15 15:57:16 +08:00
刘祥超
f914802b06 可以修改界面上显示的组件 2022-09-13 19:55:07 +08:00
刘祥超
a2f21e8d58 用户系统可以切换CDN和智能DNS 2022-09-13 19:04:07 +08:00
刘祥超
cf4b9a49ed 增加DNS套餐相关API 2022-09-13 10:50:26 +08:00
刘祥超
da02e6df4a 优化代码 2022-09-11 14:41:14 +08:00
刘祥超
a092f496dd NS域名可以使用状态筛选 2022-09-10 17:00:24 +08:00
刘祥超
98ad80e1cb 实现DNS域名验证 2022-09-10 16:13:26 +08:00
刘祥超
6ed4e2315f NS域名增加状态 2022-09-09 15:25:46 +08:00
刘祥超
55ce6570f8 增加一些NS相关API 2022-09-08 19:36:13 +08:00
刘祥超
70fa03e93b 创建集群的时候可以设置DNS记录的默认TTL 2022-09-08 11:02:36 +08:00
刘祥超
8fe1480d8d 增加获取NS节点最新版本API 2022-09-08 10:42:33 +08:00
刘祥超
f796dc5921 支持中文域名(转换punycode后)访问 2022-09-07 17:08:59 +08:00
刘祥超
f725f3bb07 增加简化的缓存条件设置 2022-09-03 18:15:56 +08:00
刘祥超
f3db0d5b69 NS记录可以按照名称、类型、TTL排序 2022-09-03 16:00:20 +08:00
刘祥超
b6fe3df3d6 DDoS防护增加秒级连接速率限制 2022-08-31 10:01:00 +08:00
刘祥超
5c885050fa 优化鉴权 2022-08-30 11:24:07 +08:00
刘祥超
b54c44bfb9 用户系统也可以申请ACME证书 2022-08-28 20:02:20 +08:00
刘祥超
78664a9218 增加修改全体用户功能API 2022-08-28 17:00:59 +08:00
刘祥超
def814ff5c 提供按小时、按天查询带宽峰值的API 2022-08-28 15:56:33 +08:00
刘祥超
1bf13d381d 服务列表带宽使用新的算法 2022-08-27 18:37:51 +08:00
刘祥超
2975ba8701 WAF默认不启用SQL注释,减少错误检测 2022-08-26 21:08:24 +08:00
刘祥超
14759c3621 可以修改服务的CNAME 2022-08-26 19:51:12 +08:00
刘祥超
5ae65edd0a DDoS防护增加单IP TCP新连接速率黑名单 2022-08-26 11:31:50 +08:00
刘祥超
184d6f97bf Ln节点可以指定访问IP 2022-08-25 20:37:15 +08:00
刘祥超
8972acdfd7 集群DNS设置中增加”包含Ln节点“选项 2022-08-25 19:18:25 +08:00
刘祥超
a957903b98 节点运行日志可以按照节点ID设置为已读 2022-08-25 18:26:40 +08:00
刘祥超
b029c1e95a 优化JS Cookie验证文字提示 2022-08-25 16:03:18 +08:00
刘祥超
095ff97149 增加Javascript Cookie验证 2022-08-25 15:36:01 +08:00
刘祥超
d00ebb31aa NS批量操作时增加用户ID选项 2022-08-25 11:36:45 +08:00
刘祥超
1c7f51c5e0 优化代码 2022-08-24 16:13:16 +08:00
刘祥超
acc70669f1 修复从API代码中提取角色时无法查找子目录的Bug 2022-08-23 21:55:59 +08:00
刘祥超
2add42a284 从API代码中提取节点角色时可以保留多个 2022-08-23 21:41:54 +08:00
刘祥超
225d03a65f 实现IP库制品管理API、自动更新程序 2022-08-23 14:54:53 +08:00
刘祥超
f851212a55 NS节点基本的DDoS防护 2022-08-22 15:10:48 +08:00
刘祥超
199794a63a 优化IP库内存 2022-08-22 08:31:53 +08:00
刘祥超
49129ea227 优化IP库内存使用 2022-08-21 23:09:25 +08:00
刘祥超
91b865dd23 在Daemon模式下不初始化IP库 2022-08-21 21:13:03 +08:00
刘祥超
0e311496b6 实现集成的IP库/初步完成IP库制作API 2022-08-21 20:36:56 +08:00
刘祥超
ed0f627ae4 延长WAF默认封禁时间:阻止动作从60秒增加到300秒;SYN Flood从600秒延长到1800秒 2022-08-20 22:38:12 +08:00
刘祥超
569f27918a 智能DNS增加若干查询记录统计接口 2022-08-20 19:58:38 +08:00
刘祥超
ec02d83ee6 IP库阶段性提交(未完成) 2022-08-14 19:42:05 +08:00
刘祥超
debf4a5249 IP库阶段性提交(未完成) 2022-08-14 16:33:11 +08:00
刘祥超
4ddc1ac89f 新版IP库管理阶段性提交(未完成) 2022-08-13 23:55:59 +08:00
刘祥超
507457dec1 增加批量操作NS域名和记录相关接口 2022-08-09 21:03:04 +08:00
刘祥超
525429bbb0 访问日志ES存储增加Data Stream模式 2022-08-09 18:12:15 +08:00
刘祥超
25e33ac1ee 缓存条件增加If-None-Match和If-Modified-Since是否回源选项 2022-08-07 16:37:03 +08:00
刘祥超
f428cb2de9 优化代码 2022-08-07 15:09:39 +08:00
刘祥超
86070bc8aa 增加NS域名分组、批量添加域名和记录接口 2022-08-06 20:29:26 +08:00
刘祥超
afef00b473 增加查找使用某个证书的NS集群数量的API 2022-08-04 16:25:00 +08:00
刘祥超
812e9482af 自动从代码中分析接口方法所适用的角色 2022-08-04 16:01:57 +08:00
刘祥超
fa5dc80426 优化代码 2022-08-04 11:52:28 +08:00
刘祥超
76b6a5c847 优化代码 2022-08-04 11:24:50 +08:00
刘祥超
a19b738d73 源站读取错误时自动尝试下一个源站 2022-08-03 20:33:31 +08:00
刘祥超
526d72fd99 增加工单相关接口定义 2022-08-03 10:45:23 +08:00
刘祥超
7ea8189c19 服务带宽API增加按月、按日查询接口 2022-08-01 15:41:07 +08:00
刘祥超
c453222774 实现用户订单、在线支付接口(商业版可用) 2022-07-31 19:57:28 +08:00
刘祥超
905163880c EdgeDNS:访问日志增加集群和记录类型筛选 2022-07-27 20:19:19 +08:00
刘祥超
ac106ca4f0 NS节点也增加DDoS配置 2022-07-27 19:41:51 +08:00
刘祥超
262dcf0c8d 智能DNS支持自定义端口 2022-07-27 16:56:32 +08:00
刘祥超
f6b3a0b829 修改文字 2022-07-26 11:28:09 +08:00
刘祥超
ac7ab51dbb 智能DNS增加中国香港、中国澳门、中国台湾、中国大陆、海外等线路 2022-07-26 11:15:05 +08:00
刘祥超
41ea2d0dda 用户实现OTP登录 2022-07-24 16:45:07 +08:00
刘祥超
a4b68cd21c 用户列表中显示实名审核状态 2022-07-24 11:57:38 +08:00
刘祥超
70d864191e 相关接口增加实名认证参数 2022-07-24 11:29:28 +08:00
刘祥超
9fdbaf92cc 可以重置用户实名认证状态 2022-07-24 10:08:13 +08:00
刘祥超
a75e57a8f7 实现基础的实名认证功能 2022-07-24 09:56:34 +08:00
刘祥超
9b187dadbe API节点信息增加instanceCode(实例代号)字段 2022-07-21 19:20:06 +08:00
刘祥超
3ab783bbd0 节点状态中增加主程序位置字段 2022-07-21 15:17:42 +08:00
刘祥超
0e95a5a4bc 增加proto相关注释 2022-07-20 18:14:57 +08:00
刘祥超
dcec62a1a2 服务配置中增加CNAME相关信息 2022-07-18 09:12:58 +08:00
刘祥超
9117af3021 增加用户身份认证相关接口 2022-07-17 10:59:55 +08:00
刘祥超
65095d1290 WAF策略增加记录区域封禁日志选项 2022-07-16 18:45:50 +08:00
刘祥超
380bf3e1c2 集群DNS设置增加允许通过CNAME访问网站服务选项 2022-07-14 09:49:41 +08:00
刘祥超
0090cf1e30 安全设置中增加禁止搜索引擎、禁止爬虫、允许访问的域名等选项 2022-07-07 19:59:00 +08:00
刘祥超
a24cbe43b6 服务看板中增加峰值带宽数据 2022-07-07 17:07:24 +08:00
刘祥超
0976b35357 用户界面设置中增加流量、带宽相关设置 2022-07-07 12:40:19 +08:00
刘祥超
84f8a7192e 增加按用户统计带宽/升级Go为1.18 2022-07-07 09:19:15 +08:00
刘祥超
22479278b9 增加服务带宽统计 2022-07-05 20:09:19 +08:00
刘祥超
f27a55c2b6 增加UAM(5秒盾)集群设置 2022-07-03 22:10:18 +08:00
刘祥超
106bd2ae87 反向代理设置中增加移除回源主机名端口功能 2022-06-30 12:11:30 +08:00
刘祥超
ef4eb23226 实现源站端口跟随功能 2022-06-29 21:55:37 +08:00
刘祥超
d9a2284936 DNS自定义线路中增加CIDR、区域以及排除功能 2022-06-28 20:26:44 +08:00
刘祥超
62027e95b2 支持ZSTD压缩 2022-06-27 22:41:11 +08:00
刘祥超
551cb2f3c1 增加修改服务所在分组API/proto文件增加若干注释 2022-06-25 19:22:19 +08:00
刘祥超
75dcaa7e7e 优化rpc json生成程序 2022-06-22 14:36:33 +08:00
刘祥超
c6952e794a 编译proto文件时自动生成RPC列表JSON 2022-06-21 21:26:22 +08:00
刘祥超
7ad94bff2f fix typo 2022-06-21 09:58:56 +08:00
刘祥超
20469e0487 修复源站设置专属域名导致其他源站不可用的Bug 2022-06-20 07:46:41 +08:00
刘祥超
4834cb2886 增加统计服务某日、某月流量API 2022-06-18 14:25:33 +08:00
刘祥超
1f33bcfee7 创建IPList时可以指定服务ID 2022-06-15 19:22:56 +08:00
刘祥超
8f8e769ead 优化缓存任务Key状态增加执行中状态 2022-06-15 15:18:22 +08:00
刘祥超
03296c7530 城市API增加省份信息 2022-06-14 17:37:32 +08:00
刘祥超
fecfb0f888 WAF规则中增加${requestURL}参数 2022-06-09 19:43:52 +08:00
刘祥超
5e277de82b API相关提示更详细 2022-06-08 15:17:21 +08:00
刘祥超
de4366bbc3 节点状态中增加时间戳字段 2022-06-07 11:45:45 +08:00
刘祥超
a8d38937e3 可以设置用户每天执行缓存任务的额度 2022-06-05 21:15:44 +08:00
刘祥超
0ea04c9883 增加刷新、预热缓存任务管理 2022-06-05 17:14:14 +08:00
刘祥超
85553bf5d9 优化源站有专属域名情况下的算法 2022-05-23 19:59:05 +08:00
刘祥超
24f8ccb166 NodeService.FindAllEnabledNodesWithNodeClusterIdRequest()增加参数includeSecondary 2022-05-23 19:56:11 +08:00
刘祥超
fb0b1d42ef 增加LICENSE和README 2022-05-22 11:36:49 +08:00
刘祥超
38005406b0 WAF默认验证码页面显示请求ID 2022-05-21 20:00:34 +08:00
刘祥超
6aee09b22b 新创建WAF时增加默认选项 2022-05-21 18:57:59 +08:00
刘祥超
8c450a9b43 WAF策略中增加验证码相关定制设置 2022-05-20 22:10:58 +08:00
刘祥超
a660815df7 健康检查增加是否记录访问日志选项 2022-05-19 17:13:26 +08:00
刘祥超
2b6d749566 实现基础的DDoS防护 2022-05-18 21:02:58 +08:00
刘祥超
dd900700e9 增加通过IP删除IP名单中IP参数 2022-05-10 15:12:03 +08:00
刘祥超
032b171025 增加注释 2022-05-08 19:33:33 +08:00
刘祥超
ab005caa4a DNS服务商增加厂家筛选 2022-05-07 20:41:28 +08:00
刘祥超
8e91af92ae 路由规则可以单独设置UAM(仅企业版可用) 2022-05-04 20:32:03 +08:00
刘祥超
97575e29a1 节点增加DNS解析库类型设置 2022-05-04 16:40:43 +08:00
刘祥超
146b57216a WebP判断内容长度时,忽略ChunkEncoding传输的内容 2022-04-29 10:50:04 +08:00
529 changed files with 121511 additions and 14013 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*_plus.go
*_plus_test.go

29
LICENSE Normal file
View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2020, LiuXiangChao
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,3 +1,5 @@
GoEdge公共配置项。
目录结构:
~~~
pkg/
@@ -12,6 +14,7 @@ pkg/
userconfigs - 用户相关配置
configutils/ - 配置公共函数等
iplibrary/ - IP库
errors/ - 错误处理
rpc/ - RPC通讯
protos/ RPC数据和接口定义

View File

@@ -1,5 +1,23 @@
#!/usr/bin/env bash
echo "starting ..."
#rm -f ../pkg/rpc/pb/*.pb.go
protoc --go_out=plugins=grpc:../pkg/rpc --proto_path=../pkg/rpc/protos ../pkg/rpc/protos/*.proto
RESULT=$?
if [ "${RESULT}" != "0" ]; then
exit
fi
protoc --go_out=plugins=grpc:../pkg/rpc --proto_path=../pkg/rpc/protos ../pkg/rpc/protos/models/*.proto
RESULT=$?
if [ "${RESULT}" != "0" ]; then
exit
fi
# generate rpc.json
./proto-json.sh --quiet
echo "ok"

3
build/proto-json.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
go run ../cmd/proto-json/main.go $1

22947
build/rpc.json Normal file

File diff suppressed because it is too large Load Diff

448
cmd/proto-json/main.go Normal file
View File

@@ -0,0 +1,448 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
)
type ServiceInfo struct {
Name string `json:"name"`
Methods []*MethodInfo `json:"methods"`
Filename string `json:"filename"`
Doc string `json:"doc"`
}
type MethodInfo struct {
Name string `json:"name"`
RequestMessageName string `json:"requestMessageName"`
ResponseMessageName string `json:"responseMessageName"`
Code string `json:"code"`
Doc string `json:"doc"`
Roles []string `json:"roles"`
IsDeprecated bool `json:"isDeprecated"`
}
type MessageInfo struct {
Name string `json:"name"`
Code string `json:"code"`
Doc string `json:"doc"`
}
type LinkInfo struct {
Name string `json:"name"`
Content string `json:"content"`
}
type RPCList struct {
Services []*ServiceInfo `json:"services"`
Messages []*MessageInfo `json:"messages"`
Links []*LinkInfo `json:"links"`
}
func readComments(data []byte) string {
var lines = bytes.Split(data, []byte{'\n'})
var comments = [][]byte{}
for i := len(lines) - 1; i >= 0; i-- {
var line = bytes.TrimLeft(lines[i], " \t")
if len(line) == 0 {
comments = append([][]byte{{' '}}, comments...)
continue
}
if bytes.HasPrefix(line, []byte("//")) {
line = bytes.TrimSpace(bytes.TrimLeft(line, "/"))
comments = append([][]byte{line}, comments...)
} else {
break
}
}
return string(bytes.TrimSpace(bytes.Join(comments, []byte{'\n'})))
}
func removeDuplicates(s []string) []string {
if len(s) == 0 {
return s
}
var m = map[string]bool{}
var result = []string{}
for _, item := range s {
_, ok := m[item]
if ok {
continue
}
result = append(result, item)
m[item] = true
}
return result
}
// 生成JSON格式API列表
func main() {
var quiet = false
flag.BoolVar(&quiet, "quiet", false, "")
flag.Parse()
var methodRolesMap = map[string][]string{} // method => roles
{
var rootDir = filepath.Clean(Tea.Root + "/../../EdgeAPI/internal/rpc/services")
entries, err := os.ReadDir(rootDir)
if err != nil {
logs.Println("[ERROR]read api services from '" + rootDir + "' failed: " + err.Error())
return
}
var rootDirs = []string{rootDir}
for _, entry := range entries {
if entry.IsDir() {
rootDirs = append(rootDirs, rootDir+string(os.PathSeparator)+entry.Name())
}
}
// 排序以保证输出内容的稳定性
sort.Strings(rootDirs)
for _, rootDir := range rootDirs {
files, err := filepath.Glob(rootDir + "/service_*.go")
if err != nil {
fmt.Println("[ERROR]list service implementation files failed: " + err.Error())
return
}
// 排序以保证输出内容的稳定性
sort.Strings(files)
var methodNameReg = regexp.MustCompile(`func\s*\(\w+\s+\*\s*(\w+Service)\)\s*(\w+)\s*\(`) // $1: serviceName, $2 methodName
for _, file := range files {
data, err := os.ReadFile(file)
if err != nil {
fmt.Println("[ERROR]read file '" + file + "' failed: " + err.Error())
return
}
var sourceCode = string(data)
var locList = methodNameReg.FindAllStringIndex(sourceCode, -1)
for index, loc := range locList {
var methodSource = ""
if index == len(locList)-1 { // last one
methodSource = sourceCode[loc[0]:]
} else {
methodSource = sourceCode[loc[0]:locList[index+1][0]]
}
// 方法名
var submatch = methodNameReg.FindStringSubmatch(methodSource)
if len(submatch) == 0 {
continue
}
var serviceName = submatch[1]
if serviceName == "BaseService" {
continue
}
var methodName = submatch[2]
if methodName[0] < 'A' || methodName[0] > 'Z' {
continue
}
var roles = []string{}
if strings.Contains(methodSource, ".ValidateNode(") {
roles = append(roles, "node")
}
if strings.Contains(methodSource, ".ValidateUserNode(") {
var hasRoles = false
var wordIndex = strings.Index(methodSource, ".ValidateUserNode(")
if wordIndex > 0 {
if len(methodSource[wordIndex:]) > 100 {
if strings.Contains(methodSource[wordIndex:wordIndex+100], ".ValidateUserNode(ctx, false)") {
hasRoles = true
}
}
if !hasRoles {
roles = append(roles, "user")
}
}
}
if strings.Contains(methodSource, ".ValidateAdmin(") {
roles = append(roles, "admin")
}
if strings.Contains(methodSource, ".ValidateAdminAndUser(") {
var hasRoles = false
var wordIndex = strings.Index(methodSource, ".ValidateAdminAndUser(")
if wordIndex > 0 {
if len(methodSource[wordIndex:]) > 100 {
if strings.Contains(methodSource[wordIndex:wordIndex+100], ".ValidateAdminAndUser(ctx, false)") {
roles = append(roles, "admin")
hasRoles = true
}
}
if !hasRoles {
roles = append(roles, "admin", "user")
}
}
}
if strings.Contains(methodSource, ".ValidateNSNode(") {
roles = append(roles, "dns")
}
if strings.Contains(methodSource, ".ValidateMonitorNode(") {
roles = append(roles, "monitor")
}
if strings.Contains(methodSource, "rpcutils.UserTypeDNS") {
roles = append(roles, "dns")
}
if strings.Contains(methodSource, "rpcutils.UserTypeUser") {
roles = append(roles, "user")
}
if strings.Contains(methodSource, "rpcutils.UserTypeNode") {
roles = append(roles, "node")
}
if strings.Contains(methodSource, "rpcutils.UserTypeMonitor") {
roles = append(roles, "monitor")
}
if strings.Contains(methodSource, "rpcutils.UserTypeReport") {
roles = append(roles, "report")
}
if strings.Contains(methodSource, "rpcutils.UserTypeCluster") {
roles = append(roles, "cluster")
}
if strings.Contains(methodSource, "rpcutils.UserTypeAdmin") {
roles = append(roles, "admin")
}
methodRolesMap[strings.ToLower(methodName)] = removeDuplicates(roles)
}
}
}
}
var services = []*ServiceInfo{}
var messages = []*MessageInfo{}
{
var dirs = []string{Tea.Root + "/../pkg/rpc/protos/", Tea.Root + "/../pkg/rpc/protos/models"}
for _, dir := range dirs {
func(dir string) {
dir = filepath.Clean(dir)
files, err := filepath.Glob(dir + "/*.proto")
if err != nil {
fmt.Println("[ERROR]list proto files failed: " + err.Error())
return
}
// 排序以保持稳定性
sort.Strings(files)
for _, path := range files {
func(path string) {
var filename = filepath.Base(path)
if filename == "service_authority_key.proto" || filename == "service_authority_node.proto" {
return
}
data, err := os.ReadFile(path)
if err != nil {
fmt.Println("[ERROR]" + err.Error())
return
}
// 先将rpc代码替换成临时代码
var methodCodeMap = map[string][]byte{} // code => method
var methodIndex = 0
var methodReg = regexp.MustCompile(`(?s)rpc\s+(\w+)\s*\(\s*(\w+)\s*\)\s*returns\s*\(\s*(\w+)\s*\)\s*(\{.+})?\s*;`)
data = methodReg.ReplaceAllFunc(data, func(methodData []byte) []byte {
methodIndex++
var code = "METHOD" + types.String(methodIndex)
methodCodeMap[code] = methodData
return []byte("\n" + code)
})
// 服务列表
// TODO 这里需要改进一下,当前实现方法如果方法注释里有括号(}),就会导致部分方法解析不到
var serviceNameReg = regexp.MustCompile(`(?sU)\n\s*service\s+(\w+)\s*\{(.+)}`)
var serviceMatches = serviceNameReg.FindAllSubmatch(data, -1)
var serviceNamePositions = serviceNameReg.FindAllIndex(data, -1)
for serviceMatchIndex, serviceMatch := range serviceMatches {
var serviceName = string(serviceMatch[1])
var serviceNamePosition = serviceNamePositions[serviceMatchIndex][0]
var comment = readComments(data[:serviceNamePosition])
// 方法列表
var methods = []*MethodInfo{}
var serviceData = serviceMatch[2]
var methodCodeReg = regexp.MustCompile(`\b(METHOD\d+)\b`)
var methodCodeMatches = methodCodeReg.FindAllSubmatch(serviceData, -1)
var methodCodePositions = methodCodeReg.FindAllIndex(serviceData, -1)
for methodMatchIndex, methodMatch := range methodCodeMatches {
var methodCode = string(methodMatch[1])
var methodData = methodCodeMap[methodCode]
var methodPieces = methodReg.FindSubmatch(methodData)
var methodCodePosition = methodCodePositions[methodMatchIndex]
var roles = methodRolesMap[strings.ToLower(string(methodPieces[1]))]
if roles == nil {
roles = []string{}
}
methods = append(methods, &MethodInfo{
Name: string(methodPieces[1]),
RequestMessageName: string(methodPieces[2]),
ResponseMessageName: string(methodPieces[3]),
IsDeprecated: strings.Contains(string(methodPieces[4]), "deprecated"),
Code: string(methodData),
Doc: readComments(serviceData[:methodCodePosition[0]]),
Roles: roles,
})
}
services = append(services, &ServiceInfo{
Name: serviceName,
Methods: methods,
Filename: filename,
Doc: comment,
})
}
// 消息列表
var topMessageCodeMap = map[string][]byte{} // code => message
var allMessageCodeMap = map[string][]byte{}
var messageCodeIndex = 0
var messagesReg = regexp.MustCompile(`(?sU)\n\s*message\s+(\w+)\s*\{([^{}]+)\n\s*}`)
var firstMessagesReg = regexp.MustCompile(`message\s+(\w+)`)
var messageCodeREG = regexp.MustCompile(`MESSAGE\d+`)
for {
var hasMessage = false
data = messagesReg.ReplaceAllFunc(data, func(messageData []byte) []byte {
messageCodeIndex++
hasMessage = true
// 是否包含子Message
var subMatches = messageCodeREG.FindAllSubmatch(messageData, -1)
for _, subMatch := range subMatches {
var subMatchCode = string(subMatch[0])
delete(topMessageCodeMap, subMatchCode)
}
var code = "MESSAGE" + types.String(messageCodeIndex)
topMessageCodeMap[code] = messageData
allMessageCodeMap[code] = messageData
return []byte("\n" + code)
})
if !hasMessage {
break
}
}
for messageCode, messageData := range topMessageCodeMap {
// 替换其中的子Message
for {
if messageCodeREG.Match(messageData) {
messageData = messageCodeREG.ReplaceAllFunc(messageData, func(messageCodeData []byte) []byte {
return allMessageCodeMap[string(messageCodeData)]
})
} else {
break
}
}
// 注释
var index = bytes.Index(data, []byte(messageCode))
var messageName = string(firstMessagesReg.FindSubmatch(messageData)[1])
messages = append(messages, &MessageInfo{
Name: messageName,
Code: string(bytes.TrimSpace(messageData)),
Doc: readComments(data[:index]),
})
}
}(path)
}
}(dir)
}
}
var countServices = len(services)
var countMethods = 0
var countMessages = len(messages)
for _, service := range services {
countMethods += len(service.Methods)
}
// 链接
var links = []*LinkInfo{}
// json links
{
var dirs = []string{Tea.Root + "/../pkg/rpc/jsons"}
for _, dir := range dirs {
func(dir string) {
dir = filepath.Clean(dir)
files, err := filepath.Glob(dir + "/*.md")
if err != nil {
fmt.Println("[ERROR]list .md files failed: " + err.Error())
return
}
// 排序以保持稳定性
sort.Strings(files)
for _, path := range files {
func(path string) {
var name = strings.TrimSuffix(filepath.Base(path), ".md")
data, err := os.ReadFile(path)
if err != nil {
fmt.Println("[ERROR]read '" + path + "' failed: " + err.Error())
return
}
links = append(links, &LinkInfo{
Name: "json:" + name,
Content: string(data),
})
}(path)
}
}(dir)
}
}
// 对消息进行排序,以保持稳定性
sort.Slice(messages, func(i, j int) bool {
return messages[i].Name < messages[j].Name
})
var rpcList = &RPCList{
Services: services,
Messages: messages,
Links: links,
}
jsonData, err := json.MarshalIndent(rpcList, "", " ")
if err != nil {
fmt.Println("[ERROR]marshal to json failed: " + err.Error())
return
}
var jsonFile = Tea.Root + "/rpc.json"
err = os.WriteFile(jsonFile, jsonData, 0666)
if err != nil {
fmt.Println("[ERROR]write json to file failed: " + err.Error())
return
}
if !quiet {
fmt.Println("services:", countServices, "methods:", countMethods, "messages:", countMessages)
fmt.Println("===")
fmt.Println("generated " + filepath.Base(jsonFile) + " successfully")
}
}

13
go.mod
View File

@@ -1,15 +1,18 @@
module github.com/TeaOSLab/EdgeCommon
go 1.15
go 1.18
require (
github.com/cespare/xxhash/v2 v2.1.1
github.com/golang/protobuf v1.5.2
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
golang.org/x/net v0.8.0
google.golang.org/grpc v1.45.0
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
require (
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
)

22
go.sum
View File

@@ -7,7 +7,6 @@ github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5Db
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/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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=
@@ -114,8 +113,8 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
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-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
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=
@@ -137,20 +136,15 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-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/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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=
@@ -168,8 +162,6 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
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-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=
@@ -179,8 +171,6 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
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=

View File

@@ -50,8 +50,8 @@ func MatchDomain(pattern string, domain string) (isMatched bool) {
}
// 其他匹配
patternPieces := strings.Split(pattern, ".")
domainPieces := strings.Split(domain, ".")
var patternPieces = strings.Split(pattern, ".")
var domainPieces = strings.Split(domain, ".")
if len(patternPieces) != len(domainPieces) {
return
}
@@ -60,6 +60,15 @@ func MatchDomain(pattern string, domain string) (isMatched bool) {
if patternPiece == "" || patternPiece == "*" || patternPiece == domainPieces[index] {
continue
}
if strings.HasSuffix(patternPiece, ":*") {
var portIndex = strings.LastIndex(patternPiece, ":*")
if portIndex >= 0 {
var prefix = patternPiece[:portIndex]
if strings.HasPrefix(domainPieces[index], prefix+":") || domainPieces[index] == prefix {
continue
}
}
}
isMatched = false
break
}

View File

@@ -6,86 +6,110 @@ import (
)
func TestMatchDomain(t *testing.T) {
a := assert.NewAssertion(t)
var a = assert.NewAssertion(t)
{
ok := MatchDomains([]string{}, "example.com")
var ok = MatchDomains([]string{}, "example.com")
a.IsFalse(ok)
}
{
ok := MatchDomains([]string{"example.com"}, "example.com")
var ok = MatchDomains([]string{"example.com"}, "example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"www.example.com"}, "example.com")
var ok = MatchDomains([]string{"www.example.com"}, "example.com")
a.IsFalse(ok)
}
{
ok := MatchDomains([]string{".example.com"}, "www.example.com")
var ok = MatchDomains([]string{".example.com"}, "www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{".example.com"}, "a.www.example.com")
var ok = MatchDomains([]string{".example.com"}, "a.www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{".example.com"}, "a.www.example123.com")
var ok = MatchDomains([]string{".example.com"}, "a.www.example123.com")
a.IsFalse(ok)
}
{
ok := MatchDomains([]string{"*.example.com"}, "www.example.com")
var ok = MatchDomains([]string{"*.example.com"}, "www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"*.*.com"}, "www.example.com")
var ok = MatchDomains([]string{"*.*.com"}, "www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"www.*.com"}, "www.example.com")
var ok = MatchDomains([]string{"www.*.com"}, "www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"gallery.*.com"}, "www.example.com")
var ok = MatchDomains([]string{"gallery.*.com"}, "www.example.com")
a.IsFalse(ok)
}
{
ok := MatchDomains([]string{"~\\w+.example.com"}, "www.example.com")
var ok = MatchDomains([]string{"~\\w+.example.com"}, "www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"~\\w+.example.com"}, "a.www.example.com")
var ok = MatchDomains([]string{"~\\w+.example.com"}, "a.www.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"~^\\d+.example.com$"}, "www.example.com")
var ok = MatchDomains([]string{"~^\\d+.example.com$"}, "www.example.com")
a.IsFalse(ok)
}
{
ok := MatchDomains([]string{"~^\\d+.example.com$"}, "123.example.com")
var ok = MatchDomains([]string{"~^\\d+.example.com$"}, "123.example.com")
a.IsTrue(ok)
}
{
ok := MatchDomains([]string{"*"}, "example.com")
var ok = MatchDomains([]string{"*"}, "example.com")
a.IsTrue(ok)
}
// port
{
ok := MatchDomains([]string{"example.com:8001"}, "example.com:8001")
var ok = MatchDomains([]string{"example.com:8001"}, "example.com:8001")
a.IsTrue(ok)
}
{
var ok = MatchDomains([]string{"example.com:8002"}, "example.com:8001")
a.IsFalse(ok)
}
{
var ok = MatchDomains([]string{"*.example.com:8001"}, "a.example.com:8001")
a.IsTrue(ok)
}
{
var ok = MatchDomains([]string{"a.example.com:*"}, "a.example.com:8001")
a.IsTrue(ok)
}
{
var ok = MatchDomains([]string{"a.example.com:*"}, "a.example.com")
a.IsTrue(ok)
}
{
var ok = MatchDomains([]string{"*.example.com:*"}, "a.example.com:8001")
a.IsTrue(ok)
}
{
var ok = MatchDomains([]string{"*.example.com:8002"}, "a.example.com:8001")
a.IsFalse(ok)
}
}
func TestIsSpecialDomain(t *testing.T) {

View File

@@ -2,27 +2,71 @@ package configutils
import (
"encoding/binary"
"github.com/cespare/xxhash/v2"
"math"
"math/big"
"net"
"strings"
)
// IP2Long 将IP转换为整型
// IPString2Long 将IP转换为整型
// 注意IPv6没有顺序
func IP2Long(ip string) uint64 {
func IPString2Long(ip string) uint64 {
if len(ip) == 0 {
return 0
}
s := net.ParseIP(ip)
if len(s) == 0 {
var netIP = net.ParseIP(ip)
if len(netIP) == 0 {
return 0
}
return IP2Long(netIP)
}
// IP2Long 将IP对象转换为整型
func IP2Long(netIP net.IP) uint64 {
if len(netIP) == 0 {
return 0
}
if strings.Contains(ip, ":") {
return math.MaxUint32 + xxhash.Sum64(s)
var b4 = netIP.To4()
if b4 != nil {
return uint64(binary.BigEndian.Uint32(b4.To4()))
}
return uint64(binary.BigEndian.Uint32(s.To4()))
var i = big.NewInt(0)
i.SetBytes(netIP.To16())
return i.Uint64()
}
// IsIPv4 检查是否为IPv4
func IsIPv4(netIP net.IP) bool {
if len(netIP) == 0 {
return false
}
return netIP.To4() != nil
}
// IsIPv6 检查是否为IPv6
func IsIPv6(netIP net.IP) bool {
if len(netIP) == 0 {
return false
}
return netIP.To4() == nil && netIP.To16() != nil
}
// IPVersion 获取IP版本号
func IPVersion(netIP net.IP) int {
if len(netIP) == 0 {
return 0
}
if netIP.To4() != nil {
return 4
}
if netIP.To16() != nil {
return 6
}
return 0
}
// ParseCIDR 计算CIDR最大值

View File

@@ -1,11 +1,46 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package configutils
package configutils_test
import "testing"
import (
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/iwind/TeaGo/assert"
"net"
"testing"
)
func TestParseCIDR(t *testing.T) {
t.Log(ParseCIDR("192.168.1.1/32"))
t.Log(ParseCIDR("192.168.1.1/24"))
t.Log(ParseCIDR("192.168.1.1/16"))
t.Log(configutils.ParseCIDR("192.168.1.1/32"))
t.Log(configutils.ParseCIDR("192.168.1.1/24"))
t.Log(configutils.ParseCIDR("192.168.1.1/16"))
}
func TestIPString2Long(t *testing.T) {
for _, ip := range []string{"127.0.0.1", "192.168.1.100", "::1", "fd00:6868:6868:0:10ac:d056:3bf6:7452", "fd00:6868:6868:0:10ac:d056:3bf6:7453", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "wrong ip"} {
t.Log(fmt.Sprintf("%42s", ip), "=>", configutils.IPString2Long(ip))
}
}
func TestIsIPv4(t *testing.T) {
t.Log(configutils.IsIPv4(net.ParseIP("192.168.1.100")))
t.Log(configutils.IsIPv4(net.ParseIP("::1")))
}
func TestIsIPv6(t *testing.T) {
t.Log(configutils.IsIPv6(net.ParseIP("192.168.1.100")))
t.Log(configutils.IsIPv6(net.ParseIP("::1")))
}
func TestIPVersion(t *testing.T) {
var a = assert.NewAssertion(t)
a.IsTrue(configutils.IPVersion(net.ParseIP("192.168.1.100")) == 4)
a.IsTrue(configutils.IPVersion(net.ParseIP("1.2.3")) == 0)
a.IsTrue(configutils.IPVersion(net.ParseIP("::1")) == 6)
a.IsTrue(configutils.IPVersion(net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")) == 6)
}
func TestQuoteIP(t *testing.T) {
t.Log(configutils.QuoteIP(configutils.QuoteIP("2001:da8:22::10")))
}

View File

@@ -55,11 +55,13 @@ func BenchmarkParseVariables(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ParseVariables("hello, ${name}, ${age}, ${gender}, ${home}, world", func(s string) string {
return "Lu"
})
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = ParseVariables("hello, ${name}, ${age}, ${gender}, ${home}, world", func(s string) string {
return "Lu"
})
}
})
}
func BenchmarkParseVariablesFromHolders(b *testing.B) {

View File

@@ -2,11 +2,11 @@ package configutils
import (
"gopkg.in/yaml.v3"
"io/ioutil"
"os"
)
func UnmarshalYamlFile(file string, ptr interface{}) error {
data, err := ioutil.ReadFile(file)
data, err := os.ReadFile(file)
if err != nil {
return err
}

1
pkg/dnsconfigs/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ns_*

View File

@@ -2,9 +2,18 @@ package dnsconfigs
// ClusterDNSConfig 集群的DNS设置
type ClusterDNSConfig struct {
CNameRecords []string `yaml:"cnameRecords" json:"cnameRecords"` // 自动加入的CNAME
TTL int32 `yaml:"ttl" json:"ttl"` // 默认TTL各个DNS服务商对记录的TTL的限制各有不同
CNAMERecords []string `yaml:"cnameRecords" json:"cnameRecords"` // 自动加入的CNAME
TTL int32 `yaml:"ttl" json:"ttl"` // 默认TTL各个DNS服务商对记录的TTL的限制各有不同
CNAMEAsDomain bool `yaml:"cnameAsDomain" json:"cnameAsDomain"` // 是否可以像域名一样直接访问CNAME
IncludingLnNodes bool `yaml:"includingLnNodes" json:"includingLnNodes"` // 是否包含Ln节点
NodesAutoSync bool `yaml:"nodesAutoSync" json:"nodesAutoSync"` // 是否自动同步节点状态
ServersAutoSync bool `yaml:"serversAutoSync" json:"serversAutoSync"` // 是否自动同步服务状态
}
func DefaultClusterDNSConfig() *ClusterDNSConfig {
return &ClusterDNSConfig{
CNAMEAsDomain: true,
IncludingLnNodes: true,
}
}

View File

@@ -0,0 +1,29 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnsconfigs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/iwind/TeaGo/types"
)
type DNSResolver struct {
Host string `json:"host"`
Port int `json:"port"`
Protocol string `json:"protocol"`
}
func (this *DNSResolver) Addr() string {
var port = this.Port
if port <= 0 {
// 暂时不支持DoH
// 实际应用中只支持udp
switch this.Protocol {
case "tls":
port = 853
default:
port = 53
}
}
return configutils.QuoteIP(this.Host) + ":" + types.String(port)
}

View File

@@ -1,13 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
type NSAccessLogRef struct {
IsPrior bool `yaml:"isPrior" json:"isPrior"` // 是否覆盖
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
LogMissingDomains bool `yaml:"logMissingDomains" json:"logMissingDomains"` // 是否记录找不到的域名
}
func (this *NSAccessLogRef) Init() error {
return nil
}

View File

@@ -1,69 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
type KeyAlgorithmType = string
const (
KeyAlgorithmTypeHmacSHA1 KeyAlgorithmType = "hmac-sha1."
KeyAlgorithmTypeHmacSHA224 KeyAlgorithmType = "hmac-sha224."
KeyAlgorithmTypeHmacSHA256 KeyAlgorithmType = "hmac-sha256."
KeyAlgorithmTypeHmacSHA384 KeyAlgorithmType = "hmac-sha384."
KeyAlgorithmTypeHmacSHA512 KeyAlgorithmType = "hmac-sha512."
)
type KeyAlgorithmDefinition struct {
Name string `json:"name"`
Code string `json:"code"`
}
func FindAllKeyAlgorithmTypes() []*KeyAlgorithmDefinition {
return []*KeyAlgorithmDefinition{
{
Name: "HmacSHA1",
Code: KeyAlgorithmTypeHmacSHA1,
},
{
Name: "HmacSHA224",
Code: KeyAlgorithmTypeHmacSHA224,
},
{
Name: "HmacSHA256",
Code: KeyAlgorithmTypeHmacSHA256,
},
{
Name: "HmacSHA384",
Code: KeyAlgorithmTypeHmacSHA384,
},
{
Name: "HmacSHA512",
Code: KeyAlgorithmTypeHmacSHA512,
},
}
}
func FindKeyAlgorithmTypeName(algoType KeyAlgorithmType) string {
for _, def := range FindAllKeyAlgorithmTypes() {
if def.Code == algoType {
return def.Name
}
}
return ""
}
type NSKeySecretType = string
const (
NSKeySecretTypeClear NSKeySecretType = "clear"
NSKeySecretTypeBase64 NSKeySecretType = "base64"
)
func FindKeySecretTypeName(secretType NSKeySecretType) string {
switch secretType {
case NSKeySecretTypeClear:
return "明文"
case NSKeySecretTypeBase64:
return "BASE64"
}
return ""
}

View File

@@ -1,34 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
import "fmt"
type NSNodeConfig struct {
Id int64 `yaml:"id" json:"id"`
NodeId string `yaml:"nodeId" json:"nodeId"`
Secret string `yaml:"secret" json:"secret"`
ClusterId int64 `yaml:"clusterId" json:"clusterId"`
AccessLogRef *NSAccessLogRef `yaml:"accessLogRef" json:"accessLogRef"`
RecursionConfig *RecursionConfig `yaml:"recursionConfig" json:"recursionConfig"`
paddedId string
}
func (this *NSNodeConfig) Init() error {
this.paddedId = fmt.Sprintf("%08d", this.Id)
// accessLog
if this.AccessLogRef != nil {
err := this.AccessLogRef.Init()
if err != nil {
return err
}
}
return nil
}
func (this *NSNodeConfig) PaddedId() string {
return this.paddedId
}

View File

@@ -1,6 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
type NSSetting struct {
}

View File

@@ -1,65 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
type RecordTTL struct {
Name string `json:"name"`
Value int `json:"value"`
}
func FindAllRecordTTL() []*RecordTTL {
return []*RecordTTL{
{
Name: "5秒",
Value: 5,
},
{
Name: "10秒",
Value: 10,
},
{
Name: "30秒",
Value: 30,
},
{
Name: "1分钟",
Value: 60,
},
{
Name: "3分钟",
Value: 3 * 60,
},
{
Name: "5分钟",
Value: 5 * 60,
},
{
Name: "10分钟",
Value: 10 * 60,
},
{
Name: "30分钟",
Value: 30 * 60,
},
{
Name: "1小时",
Value: 3600,
},
{
Name: "12小时",
Value: 12 * 3600,
},
{
Name: "1天",
Value: 86400,
},
{
Name: "30天",
Value: 30 * 86400,
},
{
Name: "一年",
Value: 365 * 86400,
},
}
}

View File

@@ -13,11 +13,13 @@ const (
RecordTypeSRV RecordType = "SRV"
RecordTypeTXT RecordType = "TXT"
RecordTypeCAA RecordType = "CAA"
RecordTypeSOA RecordType = "SOA"
)
type RecordTypeDefinition struct {
Type RecordType `json:"type"`
Description string `json:"description"`
CanDefine bool `json:"canDefine"` // 用户是否可以自定义
}
func FindAllRecordTypeDefinitions() []*RecordTypeDefinition {
@@ -25,34 +27,57 @@ func FindAllRecordTypeDefinitions() []*RecordTypeDefinition {
{
Type: RecordTypeA,
Description: "将域名指向一个IPV4地址",
CanDefine: true,
},
{
Type: RecordTypeCNAME,
Description: "将域名指向另外一个域名",
CanDefine: true,
},
{
Type: RecordTypeAAAA,
Description: "将域名指向一个IPV6地址",
CanDefine: true,
},
{
Type: RecordTypeNS,
Description: "将子域名指定其他DNS服务器解析",
CanDefine: false,
},
{
Type: RecordTypeSOA,
Description: "起始授权机构记录",
CanDefine: false,
},
{
Type: RecordTypeMX,
Description: "将域名指向邮件服务器地址",
CanDefine: true,
},
{
Type: RecordTypeSRV,
Description: "记录提供特定的服务的服务器",
CanDefine: true,
},
{
Type: RecordTypeTXT,
Description: "文本长度限制512通常做SPF记录或者校验域名所有者",
CanDefine: true,
},
{
Type: RecordTypeCAA,
Description: "CA证书颁发机构授权校验",
CanDefine: true,
},
}
}
func FindAllUserRecordTypeDefinitions() []*RecordTypeDefinition {
var result = []*RecordTypeDefinition{}
for _, r := range FindAllRecordTypeDefinitions() {
if r.CanDefine {
result = append(result, r)
}
}
return result
}

View File

@@ -1,18 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
type DNSHost struct {
Host string `json:"host"`
Port int `json:"port"`
Protocol string `json:"protocol"`
}
// RecursionConfig 递归DNS设置
type RecursionConfig struct {
IsOn bool `json:"isOn"`
Hosts []*DNSHost `json:"hosts"`
UseLocalHosts bool `json:"useLocalHosts"` // 自动从本机读取DNS
AllowDomains []string `json:"allowDomains"`
DenyDomains []string `json:"denyDomains"`
}

View File

@@ -1,40 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/configutils"
type RouteRangeType = string
const (
RouteRangeTypeIP RouteRangeType = "ipRange"
)
type RouteRangeInterface interface {
Init() error
Contains(ip uint64) bool
}
// RouteRangeIPRange IP范围配置
type RouteRangeIPRange struct {
IPFrom string `json:"ipFrom"`
IPTo string `json:"ipTo"`
ipFromLong uint64
ipToLong uint64
}
func (this *RouteRangeIPRange) Init() error {
this.ipFromLong = configutils.IP2Long(this.IPFrom)
this.ipToLong = configutils.IP2Long(this.IPTo)
if this.ipFromLong > this.ipToLong {
this.ipFromLong, this.ipToLong = this.ipToLong, this.ipFromLong
}
return nil
}
func (this *RouteRangeIPRange) Contains(ip uint64) bool {
return this.ipFromLong <= ip && this.ipToLong >= ip
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
import (
"strings"
"testing"
)
func TestRoutes(t *testing.T) {
// 检查代号是否有空,或者代号是否重复
var codeMap = map[string]bool{} // code => true
for _, routes := range [][]*Route{
AllDefaultChinaProvinceRoutes,
AllDefaultISPRoutes,
AllDefaultWorldRegionRoutes,
} {
for _, route := range routes {
if len(route.Name) == 0 {
t.Fatal("route name should not empty:", route)
}
if len(route.AliasNames) == 0 {
t.Fatal("route alias names should not empty:", route)
}
if len(route.Code) == 0 || route.Code == "world:" {
t.Fatal("route code should not empty:", route)
}
_, ok := codeMap[route.Code]
if ok {
t.Fatal("code duplicated:", route)
}
codeMap[route.Code] = true
if strings.HasPrefix(route.Code, "world:sp:") || (strings.HasPrefix(route.Code, "world:") && route.Code != "world:UAR" && len(route.Code) != 8) {
t.Log("no shorten code:", route)
}
}
}
}
func TestFindDefaultRoute(t *testing.T) {
t.Log(FindDefaultRoute("isp:china_unicom"))
t.Log(FindDefaultRoute("china:province:beijing"))
t.Log(FindDefaultRoute("world:CN"))
t.Log(FindDefaultRoute("world:US"))
}
func TestRoutes_Markdown(t *testing.T) {
var markdown = ""
for index, routes := range [][]*Route{
AllDefaultRoutes,
AllDefaultChinaProvinceRoutes,
AllDefaultISPRoutes,
AllDefaultWorldRegionRoutes,
} {
switch index {
case 0:
markdown += "## 默认线路\n"
case 1:
markdown += "## 中国地区\n"
case 2:
markdown += "## 运营商\n"
case 3:
markdown += "## 全球地区\n"
}
markdown += "| 名称 | 代号 |\n"
markdown += "|-----------|-----------|\n"
for _, route := range routes {
markdown += "| " + route.Name + " | " + route.Code + " |\n"
}
markdown += "\n"
}
t.Log(markdown)
}
func BenchmarkFindDefaultRoute(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = FindDefaultRoute("world:CN")
}
}

View File

@@ -1,8 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
// TSIGConfig 配置
type TSIGConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"`
}

View File

@@ -29,7 +29,7 @@ func (this *errorObj) Error() string {
return s
}
// 新错误
// New 新错误
func New(errText string) error {
ptr, file, line, ok := runtime.Caller(1)
funcName := ""
@@ -45,7 +45,7 @@ func New(errText string) error {
}
}
// 包装已有错误
// Wrap 包装已有错误
func Wrap(err error) error {
if err == nil {
return nil

1
pkg/iplibrary/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*-plus.db

View File

@@ -0,0 +1,124 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"bytes"
"compress/gzip"
_ "embed"
"net"
"sync"
)
//go:embed internal-ip-library.db
var ipLibraryData []byte
var defaultLibrary = NewIPLibrary()
var commonLibrary *IPLibrary
var libraryLocker = &sync.Mutex{} // 为了保持加载顺序性
func DefaultIPLibraryData() []byte {
return ipLibraryData
}
// InitDefault 加载默认的IP库
func InitDefault() error {
libraryLocker.Lock()
defer libraryLocker.Unlock()
if commonLibrary != nil {
defaultLibrary = commonLibrary
return nil
}
var library = NewIPLibrary()
err := library.InitFromData(ipLibraryData, "")
if err != nil {
return err
}
commonLibrary = library
defaultLibrary = commonLibrary
return nil
}
// Lookup 查询IP信息
func Lookup(ip net.IP) *QueryResult {
return defaultLibrary.Lookup(ip)
}
// LookupIP 查询IP信息
func LookupIP(ip string) *QueryResult {
return defaultLibrary.LookupIP(ip)
}
type IPLibrary struct {
reader *Reader
}
func NewIPLibrary() *IPLibrary {
return &IPLibrary{}
}
func NewIPLibraryWithReader(reader *Reader) *IPLibrary {
return &IPLibrary{reader: reader}
}
func (this *IPLibrary) InitFromData(data []byte, password string) error {
if len(data) == 0 || this.reader != nil {
return nil
}
if len(password) > 0 {
srcData, err := NewEncrypt().Decode(data, password)
if err != nil {
return err
}
data = srcData
}
var reader = bytes.NewReader(data)
gzipReader, err := gzip.NewReader(reader)
if err != nil {
return err
}
defer func() {
_ = gzipReader.Close()
}()
libReader, err := NewReader(gzipReader)
if err != nil {
return err
}
this.reader = libReader
return nil
}
func (this *IPLibrary) Lookup(ip net.IP) *QueryResult {
if this.reader == nil {
return &QueryResult{}
}
var result = this.reader.Lookup(ip)
if result == nil {
result = &QueryResult{}
}
return result
}
func (this *IPLibrary) LookupIP(ip string) *QueryResult {
if this.reader == nil {
return &QueryResult{}
}
return this.Lookup(net.ParseIP(ip))
}
func (this *IPLibrary) Destroy() {
if this.reader != nil {
this.reader.Destroy()
this.reader = nil
}
}

View File

@@ -0,0 +1,101 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"net"
"runtime"
"runtime/debug"
"testing"
"time"
)
func TestIPLibrary_Init(t *testing.T) {
var lib = iplibrary.NewIPLibrary()
err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
if err != nil {
t.Fatal(err)
}
}
func TestIPLibrary_Load(t *testing.T) {
for i := 0; i < 10; i++ {
err := iplibrary.InitDefault()
if err != nil {
t.Fatal(err)
}
}
}
func TestIPLibrary_Lookup(t *testing.T) {
var stat1 = &runtime.MemStats{}
runtime.ReadMemStats(stat1)
var lib = iplibrary.NewIPLibrary()
var before = time.Now()
err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
if err != nil {
t.Fatal(err)
}
var costMs = time.Since(before).Seconds() * 1000
runtime.GC()
debug.FreeOSMemory()
var stat2 = &runtime.MemStats{}
runtime.ReadMemStats(stat2)
t.Log((stat2.Alloc-stat1.Alloc)/1024/1024, "M", fmt.Sprintf("%.2f", costMs), "ms")
for _, ip := range []string{
"127.0.0.1",
"8.8.8.8",
"4.4.4.4",
"202.96.0.20",
"111.197.165.199",
"66.249.66.69",
"2222", // wrong ip
"2406:8c00:0:3401:133:18:168:70", // ipv6
} {
var result = lib.Lookup(net.ParseIP(ip))
t.Log(ip, "=>", result.IsOk(), "[", result.CountryName(), result.CountryId(), "][", result.ProvinceName(), result.ProvinceId(), "][", result.TownName(), result.TownId(), "][", result.ProviderName(), result.ProviderId(), "]")
}
}
func TestIPLibrary_LookupIP(t *testing.T) {
var lib = iplibrary.NewIPLibrary()
err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
if err != nil {
t.Fatal(err)
}
for _, ip := range []string{
"66.249.66.69",
} {
var result = lib.LookupIP(ip)
if result.IsOk() {
t.Log(ip, "=>", result.IsOk(), "[", result.CountryName(), result.CountryId(), "][", result.ProvinceName(), result.ProvinceId(), "][", result.TownName(), result.TownId(), "][", result.ProviderName(), result.ProviderId(), "]")
} else {
t.Log(ip, "=>", result.IsOk())
}
}
}
func BenchmarkIPLibrary_Lookup(b *testing.B) {
var lib = iplibrary.NewIPLibrary()
err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = lib.LookupIP("66.249.66.69")
}
}

32
pkg/iplibrary/encrypt.go Normal file
View File

@@ -0,0 +1,32 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import "github.com/TeaOSLab/EdgeCommon/pkg/nodeutils"
type Encrypt struct {
}
func NewEncrypt() *Encrypt {
return &Encrypt{}
}
func (this *Encrypt) Encode(srcData []byte, password string) ([]byte, error) {
var method = nodeutils.AES256CFBMethod{}
err := method.Init([]byte(password), []byte(password))
if err != nil {
return nil, err
}
return method.Encrypt(srcData)
}
func (this *Encrypt) Decode(encodedData []byte, password string) ([]byte, error) {
var method = nodeutils.AES256CFBMethod{}
err := method.Init([]byte(password), []byte(password))
if err != nil {
return nil, err
}
return method.Decrypt(encodedData)
}

Binary file not shown.

47
pkg/iplibrary/ip_item.go Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"github.com/iwind/TeaGo/types"
)
type ipv4Item struct {
IPFrom uint32
IPTo uint32
Region *ipRegion
}
type ipv6Item struct {
IPFrom uint64
IPTo uint64
Region *ipRegion
}
type ipRegion struct {
CountryId uint16
ProvinceId uint16
CityId uint32
TownId uint32
ProviderId uint16
}
func HashRegion(countryId uint16, provinceId uint16, cityId uint32, townId uint32, providerId uint16) string {
var providerHash = ""
if providerId > 0 {
providerHash = "_" + types.String(providerId)
}
if townId > 0 {
return "t" + types.String(townId) + providerHash
}
if cityId > 0 {
return "c" + types.String(cityId) + providerHash
}
if provinceId > 0 {
return "p" + types.String(provinceId) + providerHash
}
return "a" + types.String(countryId) + providerHash
}

95
pkg/iplibrary/meta.go Normal file
View File

@@ -0,0 +1,95 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
type Country struct {
Id uint16 `json:"id"`
Name string `json:"name"`
Codes []string `json:"codes"`
}
type Province struct {
Id uint16 `json:"id"`
Name string `json:"name"`
Codes []string `json:"codes"`
}
type City struct {
Id uint32 `json:"id"`
Name string `json:"name"`
Codes []string `json:"codes"`
}
type Town struct {
Id uint32 `json:"id"`
Name string `json:"name"`
Codes []string `json:"codes"`
}
type Provider struct {
Id uint16 `json:"id"`
Name string `json:"name"`
Codes []string `json:"codes"`
}
type Meta struct {
Version int `json:"version"` // IP库版本
Code string `json:"code"` // 代号用来区分不同的IP库
Author string `json:"author"`
Countries []*Country `json:"countries"`
Provinces []*Province `json:"provinces"`
Cities []*City `json:"cities"`
Towns []*Town `json:"towns"`
Providers []*Provider `json:"providers"`
CreatedAt int64 `json:"createdAt"`
countryMap map[uint16]*Country // id => *Country
provinceMap map[uint16]*Province // id => *Province
cityMap map[uint32]*City // id => *City
townMap map[uint32]*Town // id => *Town
providerMap map[uint16]*Provider // id => *Provider
}
func (this *Meta) Init() {
this.countryMap = map[uint16]*Country{}
this.provinceMap = map[uint16]*Province{}
this.cityMap = map[uint32]*City{}
this.townMap = map[uint32]*Town{}
this.providerMap = map[uint16]*Provider{}
for _, country := range this.Countries {
this.countryMap[country.Id] = country
}
for _, province := range this.Provinces {
this.provinceMap[province.Id] = province
}
for _, city := range this.Cities {
this.cityMap[city.Id] = city
}
for _, town := range this.Towns {
this.townMap[town.Id] = town
}
for _, provider := range this.Providers {
this.providerMap[provider.Id] = provider
}
}
func (this *Meta) CountryWithId(countryId uint16) *Country {
return this.countryMap[countryId]
}
func (this *Meta) ProvinceWithId(provinceId uint16) *Province {
return this.provinceMap[provinceId]
}
func (this *Meta) CityWithId(cityId uint32) *City {
return this.cityMap[cityId]
}
func (this *Meta) TownWithId(townId uint32) *Town {
return this.townMap[townId]
}
func (this *Meta) ProviderWithId(providerId uint16) *Provider {
return this.providerMap[providerId]
}

View File

@@ -0,0 +1,3 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test

64
pkg/iplibrary/parser.go Normal file
View File

@@ -0,0 +1,64 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"bytes"
"errors"
)
type Parser struct {
config *ParserConfig
data []byte
}
func NewParser(config *ParserConfig) (*Parser, error) {
if config == nil {
config = &ParserConfig{}
}
if config.Template == nil {
return nil, errors.New("template must not be nil")
}
return &Parser{
config: config,
}, nil
}
func (this *Parser) Write(data []byte) {
this.data = append(this.data, data...)
}
func (this *Parser) Parse() error {
if len(this.data) == 0 {
return nil
}
for {
var index = bytes.IndexByte(this.data, '\n')
if index >= 0 {
var line = this.data[:index+1]
values, found := this.config.Template.Extract(string(line), this.config.EmptyValues)
if found {
if this.config.Iterator != nil {
err := this.config.Iterator(values)
if err != nil {
return err
}
}
} else {
// 防止错误信息太长
if len(line) > 256 {
line = line[:256]
}
return errors.New("invalid line '" + string(line) + "'")
}
this.data = this.data[index+1:]
} else {
break
}
}
return nil
}

View File

@@ -0,0 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
type ParserConfig struct {
Template *Template
EmptyValues []string
Iterator func(values map[string]string) error
}

View File

@@ -0,0 +1,54 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"errors"
"io"
)
type ReaderParser struct {
reader io.Reader
rawParser *Parser
}
func NewReaderParser(reader io.Reader, config *ParserConfig) (*ReaderParser, error) {
if config == nil {
config = &ParserConfig{}
}
if config.Template == nil {
return nil, errors.New("template must not be nil")
}
parser, err := NewParser(config)
if err != nil {
return nil, err
}
return &ReaderParser{
reader: reader,
rawParser: parser,
}, nil
}
func (this *ReaderParser) Parse() error {
var buf = make([]byte, 1024)
for {
n, err := this.reader.Read(buf)
if n > 0 {
this.rawParser.Write(buf[:n])
parseErr := this.rawParser.Parse()
if parseErr != nil {
return parseErr
}
}
if err != nil {
if err != io.EOF {
return err
}
break
}
}
return nil
}

View File

@@ -0,0 +1,62 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"bytes"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"testing"
)
func TestNewReaderParser(t *testing.T) {
template, err := iplibrary.NewTemplate("${ipFrom}|${ipTo}|${country}|${any}|${province}|${city}|${provider}")
if err != nil {
t.Fatal(err)
}
var buf = &bytes.Buffer{}
buf.WriteString(`8.45.160.0|8.45.161.255|美国|0|华盛顿|西雅图|Level3
8.45.162.0|8.45.162.255|美国|0|马萨诸塞|0|Level3
8.45.163.0|8.45.164.255|美国|0|俄勒冈|0|Level3
8.45.165.0|8.45.165.255|美国|0|华盛顿|0|Level3
8.45.166.0|8.45.167.255|美国|0|华盛顿|西雅图|Level3
8.45.168.0|8.127.255.255|美国|0|0|0|Level3
8.128.0.0|8.128.3.255|中国|0|上海|上海市|阿里巴巴
8.128.4.0|8.128.255.255|中国|0|0|0|阿里巴巴
8.129.0.0|8.129.255.255|中国|0|广东省|深圳市|阿里云
8.130.0.0|8.130.55.255|中国|0|北京|北京市|阿里云
8.130.56.0|8.131.255.255|中国|0|北京|北京市|阿里巴巴
8.132.0.0|8.133.255.255|中国|0|上海|上海市|阿里巴巴
8.134.0.0|8.134.20.63|中国|0|0|0|阿里云
8.134.20.64|8.134.79.255|中国|0|广东省|深圳市|阿里云
8.134.80.0|8.191.255.255|中国|0|0|0|阿里巴巴
8.192.0.0|8.192.0.255|美国|0|0|0|Level3
8.192.1.0|8.192.1.255|美国|0|马萨诸塞|波士顿|Level3
8.192.2.0|8.207.255.255|美国|0|0|0|Level3
8.208.0.0|8.208.127.255|英国|0|伦敦|伦敦|阿里云
8.208.128.0|8.208.255.255|英国|0|伦敦|伦敦|阿里巴巴
8.209.0.0|8.209.15.255|俄罗斯|0|莫斯科|莫斯科|阿里云
8.209.16.0|8.209.31.255|俄罗斯|0|莫斯科|莫斯科|阿里巴巴
8.209.32.0|8.209.32.15|中国|0|台湾省|台北|阿里云
8.209.32.16|8.209.32.255|中国|0|台湾省|台北|阿里巴巴
8.209.33.0|8.209.34.255|中国|0|台湾省|台北|阿里云
8.209.35.0|8.209.35.255|中国|0|台湾省|台北|阿里巴巴`)
var count int
parser, err := iplibrary.NewReaderParser(buf, &iplibrary.ParserConfig{
Template: template,
EmptyValues: []string{"0"},
Iterator: func(values map[string]string) error {
count++
t.Log(count, values)
return nil
},
})
if err != nil {
t.Fatal(err)
}
err = parser.Parse()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,44 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"testing"
)
func TestNewParser(t *testing.T) {
template, err := iplibrary.NewTemplate("${ipFrom}|${ipTo}|${country}|${any}|${province}|${city}|${provider}")
if err != nil {
t.Fatal(err)
}
parser, err := iplibrary.NewParser(&iplibrary.ParserConfig{
Template: template,
EmptyValues: []string{"0"},
Iterator: func(values map[string]string) error {
t.Log(values)
return nil
},
})
if err != nil {
t.Fatal(err)
}
parser.Write([]byte(`0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP
1.0.0.0|1.0.0.255|澳大利亚|0|0|0|0
1.0.1.0|1.0.3.255|中国|0|福建省|福州市|电信
1.0.4.0|1.0.7.255|澳大利亚|0|维多利亚|墨尔本|0
1.0.8.0|1.0.15.255|中国|0|广东省|广州市|电信
1.0.16.0|1.0.31.255|日本|0|0|0|0
1.0.32.0|1.0.63.255|中国|0|广东省|广州市|电信
1.0.64.0|1.0.79.255|日本|0|广岛县|0|0
1.0.80.0|1.0.127.255|日本|0|冈山县|0|0
1.0.128.0|1.0.128.255|泰国|0|清莱府|0|TOT
1.0.129.0|1.0.132.191|泰国|0|曼谷|曼谷|TOT`))
err = parser.Parse()
if err != nil {
t.Fatal(err)
}
}

322
pkg/iplibrary/reader.go Normal file
View File

@@ -0,0 +1,322 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"bytes"
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"io"
"net"
"sort"
"strconv"
"strings"
)
// Reader IP库Reader
type Reader struct {
meta *Meta
regionMap map[string]*ipRegion // 缓存重复的区域用来节约内存
ipV4Items []*ipv4Item
ipV6Items []*ipv6Item
lastIPFrom uint64
lastCountryId uint16
lastProvinceId uint16
lastCityId uint32
lastTownId uint32
lastProviderId uint16
}
// NewReader 创建新Reader对象
func NewReader(reader io.Reader) (*Reader, error) {
var libReader = &Reader{
regionMap: map[string]*ipRegion{},
}
err := libReader.load(reader)
if err != nil {
return nil, err
}
return libReader, nil
}
// 从Reader中加载数据
func (this *Reader) load(reader io.Reader) error {
var buf = make([]byte, 1024)
var metaLine = []byte{}
var metaLineFound = false
var dataBuf = []byte{}
for {
n, err := reader.Read(buf)
if n > 0 {
var data = buf[:n]
dataBuf = append(dataBuf, data...)
if metaLineFound {
left, err := this.parse(dataBuf)
if err != nil {
return err
}
dataBuf = left
} else {
var index = bytes.IndexByte(dataBuf, '\n')
if index > 0 {
metaLine = dataBuf[:index]
dataBuf = dataBuf[index+1:]
metaLineFound = true
var meta = &Meta{}
err = json.Unmarshal(metaLine, &meta)
if err != nil {
return err
}
meta.Init()
this.meta = meta
left, err := this.parse(dataBuf)
if err != nil {
return err
}
dataBuf = left
}
}
}
if err != nil {
if err != io.EOF {
return err
}
break
}
}
sort.Slice(this.ipV4Items, func(i, j int) bool {
var from0 = this.ipV4Items[i].IPFrom
var to0 = this.ipV4Items[i].IPTo
var from1 = this.ipV4Items[j].IPFrom
var to1 = this.ipV4Items[j].IPTo
if from0 == from1 {
return to0 < to1
}
return from0 < from1
})
sort.Slice(this.ipV6Items, func(i, j int) bool {
var from0 = this.ipV6Items[i].IPFrom
var to0 = this.ipV6Items[i].IPTo
var from1 = this.ipV6Items[j].IPFrom
var to1 = this.ipV6Items[j].IPTo
if from0 == from1 {
return to0 < to1
}
return from0 < from1
})
// 清理内存
this.regionMap = nil
return nil
}
func (this *Reader) Lookup(ip net.IP) *QueryResult {
if ip == nil {
return &QueryResult{}
}
var ipLong = configutils.IP2Long(ip)
var isV4 = configutils.IsIPv4(ip)
var resultItem any
if isV4 {
sort.Search(len(this.ipV4Items), func(i int) bool {
var item = this.ipV4Items[i]
if item.IPFrom <= uint32(ipLong) {
if item.IPTo >= uint32(ipLong) {
resultItem = item
return false
}
return false
}
return true
})
} else {
sort.Search(len(this.ipV6Items), func(i int) bool {
var item = this.ipV6Items[i]
if item.IPFrom <= ipLong {
if item.IPTo >= ipLong {
resultItem = item
return false
}
return false
}
return true
})
}
return &QueryResult{
item: resultItem,
meta: this.meta,
}
}
func (this *Reader) Meta() *Meta {
return this.meta
}
func (this *Reader) IPv4Items() []*ipv4Item {
return this.ipV4Items
}
func (this *Reader) IPv6Items() []*ipv6Item {
return this.ipV6Items
}
func (this *Reader) Destroy() {
this.meta = nil
this.regionMap = nil
this.ipV4Items = nil
this.ipV6Items = nil
}
// 分析数据
func (this *Reader) parse(data []byte) (left []byte, err error) {
if len(data) == 0 {
return
}
for {
var index = bytes.IndexByte(data, '\n')
if index >= 0 {
var line = data[:index]
err = this.parseLine(line)
if err != nil {
return nil, err
}
data = data[index+1:]
} else {
left = data
break
}
}
return
}
// 单行分析
func (this *Reader) parseLine(line []byte) error {
const maxPieces = 8
var pieces = strings.Split(string(line), "|")
var countPieces = len(pieces)
if countPieces < maxPieces { // 补足一行
for i := 0; i < maxPieces-countPieces; i++ {
pieces = append(pieces, "")
}
} else if countPieces > maxPieces {
return errors.New("invalid ip definition '" + string(line) + "'")
}
var version = pieces[0]
if len(version) == 0 {
version = "4"
}
if version != "4" && version != "6" {
return errors.New("invalid ip version '" + string(line) + "'")
}
// ip range
var ipFrom uint64
var ipTo uint64
if strings.HasPrefix(pieces[1], "+") {
ipFrom = this.lastIPFrom + this.decodeUint64(pieces[1][1:])
} else {
ipFrom = this.decodeUint64(pieces[1])
}
if len(pieces[2]) == 0 {
ipTo = ipFrom
} else {
ipTo = this.decodeUint64(pieces[2]) + ipFrom
}
this.lastIPFrom = ipFrom
// country
var countryId uint16
if pieces[3] == "+" {
countryId = this.lastCountryId
} else {
countryId = uint16(this.decodeUint64(pieces[3]))
}
this.lastCountryId = countryId
var provinceId uint16
if pieces[4] == "+" {
provinceId = this.lastProvinceId
} else {
provinceId = uint16(this.decodeUint64(pieces[4]))
}
this.lastProvinceId = provinceId
// city
var cityId uint32
if pieces[5] == "+" {
cityId = this.lastCityId
} else {
cityId = uint32(this.decodeUint64(pieces[5]))
}
this.lastCityId = cityId
// town
var townId uint32
if pieces[6] == "+" {
townId = this.lastTownId
} else {
townId = uint32(this.decodeUint64(pieces[6]))
}
this.lastTownId = townId
// provider
var providerId uint16
if pieces[7] == "+" {
providerId = this.lastProviderId
} else {
providerId = uint16(this.decodeUint64(pieces[7]))
}
this.lastProviderId = providerId
var hash = HashRegion(countryId, provinceId, cityId, townId, providerId)
region, ok := this.regionMap[hash]
if !ok {
region = &ipRegion{
CountryId: countryId,
ProvinceId: provinceId,
CityId: cityId,
TownId: townId,
ProviderId: providerId,
}
this.regionMap[hash] = region
}
if version == "4" {
this.ipV4Items = append(this.ipV4Items, &ipv4Item{
IPFrom: uint32(ipFrom),
IPTo: uint32(ipTo),
Region: region,
})
} else {
this.ipV6Items = append(this.ipV6Items, &ipv6Item{
IPFrom: ipFrom,
IPTo: ipTo,
Region: region,
})
}
return nil
}
func (this *Reader) decodeUint64(s string) uint64 {
if this.meta != nil && this.meta.Version == Version2 {
i, _ := strconv.ParseUint(s, 32, 64)
return i
}
i, _ := strconv.ParseUint(s, 10, 64)
return i
}

View File

@@ -0,0 +1,71 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"bytes"
"compress/gzip"
"errors"
"io"
"net"
"os"
)
type FileReader struct {
rawReader *Reader
password string
}
func NewFileReader(path string, password string) (*FileReader, error) {
fp, err := os.Open(path)
if err != nil {
return nil, err
}
defer func() {
_ = fp.Close()
}()
return NewFileDataReader(fp, password)
}
func NewFileDataReader(dataReader io.Reader, password string) (*FileReader, error) {
if len(password) > 0 {
data, err := io.ReadAll(dataReader)
if err != nil {
return nil, err
}
sourceData, err := NewEncrypt().Decode(data, password)
if err != nil {
return nil, err
}
dataReader = bytes.NewReader(sourceData)
}
gzReader, err := gzip.NewReader(dataReader)
if err != nil {
return nil, errors.New("create gzip reader failed: " + err.Error())
}
reader, err := NewReader(gzReader)
if err != nil {
return nil, err
}
return &FileReader{
rawReader: reader,
}, nil
}
func (this *FileReader) Meta() *Meta {
return this.rawReader.meta
}
func (this *FileReader) Lookup(ip net.IP) *QueryResult {
return this.rawReader.Lookup(ip)
}
func (this *FileReader) RawReader() *Reader {
return this.rawReader
}

View File

@@ -0,0 +1,51 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"encoding/json"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/iwind/TeaGo/maps"
"net"
"testing"
)
func TestNewFileReader(t *testing.T) {
reader, err := iplibrary.NewFileReader("./ip-20c1461c.db", "123456")
if err != nil {
t.Fatal(err)
}
for _, ip := range []string{
"127.0.0.1",
"192.168.0.1",
"192.168.0.150",
"8.8.8.8",
"111.197.165.199",
"175.178.206.125",
} {
var result = reader.Lookup(net.ParseIP(ip))
if result.IsOk() {
var data = maps.Map{
"countryId": result.CountryId(),
"countryName": result.CountryName(),
"provinceId": result.ProvinceId(),
"provinceName": result.ProvinceName(),
"cityId": result.CityId(),
"cityName": result.CityName(),
"townId": result.TownId(),
"townName": result.TownName(),
"providerId": result.ProviderId(),
"providerName": result.ProviderName(),
"summary": result.Summary(),
}
dataJSON, err := json.MarshalIndent(data, "", " ")
if err != nil {
t.Fatal(err)
}
t.Log(ip, "=>", string(dataJSON))
} else {
t.Log(ip+":", "not found")
}
}
}

View File

@@ -0,0 +1,249 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"github.com/iwind/TeaGo/lists"
"strings"
)
type QueryResult struct {
item any
meta *Meta
}
func (this *QueryResult) IsOk() bool {
return this.item != nil
}
func (this *QueryResult) CountryId() int64 {
return int64(this.realCountryId())
}
func (this *QueryResult) CountryName() string {
if this.item == nil {
return ""
}
var countryId = this.realCountryId()
if countryId > 0 {
var country = this.meta.CountryWithId(countryId)
if country != nil {
return country.Name
}
}
return ""
}
func (this *QueryResult) CountryCodes() []string {
if this.item == nil {
return nil
}
var countryId = this.realCountryId()
if countryId > 0 {
var country = this.meta.CountryWithId(countryId)
if country != nil {
return country.Codes
}
}
return nil
}
func (this *QueryResult) ProvinceId() int64 {
return int64(this.realProvinceId())
}
func (this *QueryResult) ProvinceName() string {
if this.item == nil {
return ""
}
var provinceId = this.realProvinceId()
if provinceId > 0 {
var province = this.meta.ProvinceWithId(provinceId)
if province != nil {
return province.Name
}
}
return ""
}
func (this *QueryResult) ProvinceCodes() []string {
if this.item == nil {
return nil
}
var provinceId = this.realProvinceId()
if provinceId > 0 {
var province = this.meta.ProvinceWithId(provinceId)
if province != nil {
return province.Codes
}
}
return nil
}
func (this *QueryResult) CityId() int64 {
return int64(this.realCityId())
}
func (this *QueryResult) CityName() string {
if this.item == nil {
return ""
}
var cityId = this.realCityId()
if cityId > 0 {
var city = this.meta.CityWithId(cityId)
if city != nil {
return city.Name
}
}
return ""
}
func (this *QueryResult) TownId() int64 {
return int64(this.realTownId())
}
func (this *QueryResult) TownName() string {
if this.item == nil {
return ""
}
var townId = this.realTownId()
if townId > 0 {
var town = this.meta.TownWithId(townId)
if town != nil {
return town.Name
}
}
return ""
}
func (this *QueryResult) ProviderId() int64 {
return int64(this.realProviderId())
}
func (this *QueryResult) ProviderName() string {
if this.item == nil {
return ""
}
var providerId = this.realProviderId()
if providerId > 0 {
var provider = this.meta.ProviderWithId(providerId)
if provider != nil {
return provider.Name
}
}
return ""
}
func (this *QueryResult) ProviderCodes() []string {
if this.item == nil {
return nil
}
var providerId = this.realProviderId()
if providerId > 0 {
var provider = this.meta.ProviderWithId(providerId)
if provider != nil {
return provider.Codes
}
}
return nil
}
func (this *QueryResult) Summary() string {
if this.item == nil {
return ""
}
var pieces = []string{}
var countryName = this.CountryName()
var provinceName = this.ProvinceName()
var cityName = this.CityName()
var townName = this.TownName()
var providerName = this.ProviderName()
if len(countryName) > 0 {
pieces = append(pieces, countryName)
}
if len(provinceName) > 0 && !lists.ContainsString(pieces, provinceName) {
pieces = append(pieces, provinceName)
}
if len(cityName) > 0 && !lists.ContainsString(pieces, cityName) && !lists.ContainsString(pieces, strings.TrimSuffix(cityName, "市")) {
pieces = append(pieces, cityName)
}
if len(townName) > 0 && !lists.ContainsString(pieces, townName) && !lists.ContainsString(pieces, strings.TrimSuffix(townName, "县")) {
pieces = append(pieces, townName)
}
if len(providerName) > 0 && !lists.ContainsString(pieces, providerName) {
if len(pieces) > 0 {
pieces = append(pieces, "|")
}
pieces = append(pieces, providerName)
}
return strings.Join(pieces, " ")
}
func (this *QueryResult) realCountryId() uint16 {
if this.item != nil {
switch item := this.item.(type) {
case *ipv4Item:
return item.Region.CountryId
case *ipv6Item:
return item.Region.CountryId
}
}
return 0
}
func (this *QueryResult) realProvinceId() uint16 {
if this.item != nil {
switch item := this.item.(type) {
case *ipv4Item:
return item.Region.ProvinceId
case *ipv6Item:
return item.Region.ProvinceId
}
}
return 0
}
func (this *QueryResult) realCityId() uint32 {
if this.item != nil {
switch item := this.item.(type) {
case *ipv4Item:
return item.Region.CityId
case *ipv6Item:
return item.Region.CityId
}
}
return 0
}
func (this *QueryResult) realTownId() uint32 {
if this.item != nil {
switch item := this.item.(type) {
case *ipv4Item:
return item.Region.TownId
case *ipv6Item:
return item.Region.TownId
}
}
return 0
}
func (this *QueryResult) realProviderId() uint16 {
if this.item != nil {
switch item := this.item.(type) {
case *ipv4Item:
return item.Region.ProviderId
case *ipv6Item:
return item.Region.ProviderId
}
}
return 0
}

View File

@@ -0,0 +1,149 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"bytes"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
"net"
"runtime"
"testing"
"time"
)
func TestNewReader(t *testing.T) {
var buf = &bytes.Buffer{}
var writer = iplibrary.NewWriter(buf, &iplibrary.Meta{
Author: "GoEdge <https://goedge.cn>",
})
err := writer.WriteMeta()
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.1.100", "192.168.1.100", 1, 200, 300, 400, 500)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.2.100", "192.168.3.100", 2, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.3.101", "192.168.3.101", 3, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.0.101", "192.168.0.200", 4, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
err = writer.Write("::1", "::5", 5, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
/**var n = func() string {
return types.String(rands.Int(0, 255))
}
for i := 0; i < 1_000_000; i++ {
err = writer.Write(n()+"."+n()+"."+n()+"."+n(), n()+"."+n()+"."+n()+"."+n(), int64(i)+100, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
}**/
var stat = &runtime.MemStats{}
runtime.ReadMemStats(stat)
reader, err := iplibrary.NewReader(buf)
var stat2 = &runtime.MemStats{}
runtime.ReadMemStats(stat2)
t.Log((stat2.Alloc-stat.Alloc)/1024/1024, "M")
if err != nil {
t.Fatal(err)
}
t.Log("version:", reader.Meta().Version, "author:", reader.Meta().Author, "createdTime:", timeutil.FormatTime("Y-m-d H:i:s", reader.Meta().CreatedAt))
if len(reader.IPv4Items()) < 10 {
t.Log("===")
for _, item := range reader.IPv4Items() {
t.Logf("%+v", item)
}
t.Log("===")
}
if len(reader.IPv6Items()) < 10 {
t.Log("===")
for _, item := range reader.IPv6Items() {
t.Logf("%+v", item)
}
t.Log("===")
}
var before = time.Now()
for _, ip := range []string{
"192.168.0.1",
"192.168.0.150",
"192.168.1.100",
"192.168.2.100",
"192.168.3.50",
"192.168.0.150",
"192.168.4.80",
"::3",
"::8",
} {
var result = reader.Lookup(net.ParseIP(ip))
if result.IsOk() {
t.Log(ip+":", "countryId:", result.CountryId())
} else {
t.Log(ip+":", "not found")
}
}
t.Log(time.Since(before).Seconds()*1000, "ms")
}
func BenchmarkNewReader(b *testing.B) {
runtime.GOMAXPROCS(1)
var buf = &bytes.Buffer{}
var writer = iplibrary.NewWriter(buf, &iplibrary.Meta{
Author: "GoEdge <https://goedge.cn>",
})
err := writer.WriteMeta()
if err != nil {
b.Fatal(err)
}
var n = func() string {
return types.String(rands.Int(0, 255))
}
for i := 0; i < 1_000_000; i++ {
err = writer.Write(n()+"."+n()+"."+n()+"."+n(), n()+"."+n()+"."+n()+"."+n(), int64(i)+100, 201, 301, 401, 501)
if err != nil {
b.Fatal(err)
}
}
reader, err := iplibrary.NewReader(buf)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
var ip = "192.168.1.100"
reader.Lookup(net.ParseIP(ip))
}
}

75
pkg/iplibrary/template.go Normal file
View File

@@ -0,0 +1,75 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"github.com/iwind/TeaGo/lists"
"regexp"
)
type Template struct {
templateString string
reg *regexp.Regexp
}
func NewTemplate(templateString string) (*Template, error) {
var t = &Template{
templateString: templateString,
}
err := t.init()
if err != nil {
return nil, err
}
return t, nil
}
func (this *Template) init() error {
var template = regexp.QuoteMeta(this.templateString)
var keywordReg = regexp.MustCompile(`\\\$\\{(\w+)\\}`)
template = keywordReg.ReplaceAllStringFunc(template, func(keyword string) string {
var matches = keywordReg.FindStringSubmatch(keyword)
if len(matches) > 1 {
switch matches[1] {
case "ipFrom", "ipTo", "country", "province", "city", "town", "provider":
return "(?P<" + matches[1] + ">.*)"
}
return ".*"
}
return keyword
})
reg, err := regexp.Compile("^(?U)" + template + "\n?$")
if err != nil {
return err
}
this.reg = reg
return nil
}
func (this *Template) Extract(text string, emptyValues []string) (values map[string]string, ok bool) {
var matches = this.reg.FindStringSubmatch(text)
if len(matches) == 0 {
return
}
values = map[string]string{}
for index, name := range this.reg.SubexpNames() {
if len(name) == 0 {
continue
}
var v = matches[index]
if name != "ipFrom" && name != "ipTo" && (v == "0" || v == "无" || v == "空" || lists.ContainsString(emptyValues, v)) {
v = ""
}
values[name] = v
}
for _, keyword := range []string{"ipFrom", "ipTo", "country", "province", "city", "town", "provider"} {
_, hasKeyword := values[keyword]
if !hasKeyword {
values[keyword] = ""
}
}
ok = true
return
}

View File

@@ -0,0 +1,39 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"testing"
)
func TestNewTemplate(t *testing.T) {
template, err := iplibrary.NewTemplate("${ipFrom}|${ipTo}|${country}|${any}|${province}|${city}|${provider}")
if err != nil {
t.Fatal(err)
}
for _, s := range []string{
"0.0.0.0|0.255.255.255|0|0|0|内网IP|内网IP",
"42.0.32.0|42.0.63.255|中国|0|广东省|广州市|电信",
"42.0.32.0|42.0.63.255|中国|0|广东省|广州市|电信\n123",
"42.0.32.0|42.0.63.255|中国||广东省|广州市|电信",
"42.0.32.0|42.0.63.255|中国|0||广州市|电信",
"42.0.32.0|42.0.63.255|中国|0|广东省|广州市",
} {
values, ok := template.Extract(s, []string{})
t.Log(ok, s, "=>\n", values)
}
}
func TestNewTemplate2(t *testing.T) {
template, err := iplibrary.NewTemplate("${any},${any},${ipFrom},${ipTo},${country},${province},${city},${town},${provider},${any},${any}")
if err != nil {
t.Fatal(err)
}
for _, s := range []string{
"22723584,22723839,1.90.188.0,1.90.188.255,中国,北京,北京,房山,歌华有线,102400,010,城域网",
} {
values, _ := template.Extract(s, []string{})
t.Log(s, "=>\n", values)
}
}

268
pkg/iplibrary/updater.go Normal file
View File

@@ -0,0 +1,268 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"io"
"os"
"strings"
"time"
)
type UpdaterSource interface {
// DataDir 文件目录
DataDir() string
// FindLatestFile 检查最新的IP库文件
FindLatestFile() (code string, fileId int64, err error)
// DownloadFile 下载文件
DownloadFile(fileId int64, writer io.Writer) error
// LogInfo 普通日志
LogInfo(message string)
// LogError 错误日志
LogError(err error)
}
type Updater struct {
source UpdaterSource
currentCode string
ticker *time.Ticker
isUpdating bool
}
func NewUpdater(source UpdaterSource, interval time.Duration) *Updater {
return &Updater{
source: source,
ticker: time.NewTicker(interval),
}
}
func (this *Updater) Start() {
// 初始化
err := this.Init()
if err != nil {
this.source.LogError(err)
}
// 先运行一次
err = this.Loop()
if err != nil {
this.source.LogError(err)
}
// 开始定时运行
for range this.ticker.C {
err = this.Loop()
if err != nil {
this.source.LogError(err)
}
}
}
func (this *Updater) Init() error {
// 检查当前正在使用的IP库
var path = this.source.DataDir() + "/ip-library.db"
fp, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return errors.New("read ip library file failed '" + err.Error() + "'")
}
defer func() {
_ = fp.Close()
}()
return this.loadFile(fp)
}
func (this *Updater) Loop() error {
if this.isUpdating {
return nil
}
this.isUpdating = true
defer func() {
this.isUpdating = false
}()
code, fileId, err := this.source.FindLatestFile()
if err != nil {
// 不提示连接错误
if this.isConnError(err) {
return nil
}
return err
}
if len(code) == 0 || fileId <= 0 {
// 还原到内置IP库
if len(this.currentCode) > 0 {
this.currentCode = ""
this.source.LogInfo("resetting to default ip library ...")
var defaultPath = this.source.DataDir() + "/ip-library.db"
_, err = os.Stat(defaultPath)
if err == nil {
err = os.Remove(defaultPath)
if err != nil {
this.source.LogError(errors.New("can not remove default 'ip-library.db'"))
}
}
err = InitDefault()
if err != nil {
this.source.LogError(errors.New("initialize default ip library failed: " + err.Error()))
}
}
return nil
}
// 下载
if this.currentCode == code {
// 不再重复下载
return nil
}
// 检查是否存在
var dir = this.source.DataDir()
var path = dir + "/ip-" + code + ".db"
stat, err := os.Stat(path)
if err == nil && !stat.IsDir() && stat.Size() > 0 {
fp, err := os.Open(path)
if err != nil {
return err
}
defer func() {
_ = fp.Close()
}()
err = this.loadFile(fp)
if err != nil {
// 尝试删除
_ = os.Remove(path)
} else {
this.currentCode = code
// 拷贝到 ip-library.db
err = this.createDefaultFile(path, dir)
if err != nil {
this.source.LogError(err)
}
}
return err
}
// write to file
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
return errors.New("create ip library file failed: " + err.Error())
}
var isOk = false
defer func() {
if !isOk {
_ = os.Remove(path)
}
}()
err = this.source.DownloadFile(fileId, fp)
if err != nil {
_ = fp.Close()
return err
}
err = fp.Close()
if err != nil {
return nil
}
// load library from file
fp, err = os.Open(path)
if err != nil {
return nil
}
err = this.loadFile(fp)
_ = fp.Close()
if err != nil {
return errors.New("load file failed: " + err.Error())
}
isOk = true
this.currentCode = code
// 拷贝到 ip-library.db
err = this.createDefaultFile(path, dir)
if err != nil {
this.source.LogError(err)
}
return nil
}
func (this *Updater) loadFile(fp *os.File) error {
this.source.LogInfo("load ip library from '" + fp.Name() + "' ...")
fileReader, err := NewFileDataReader(fp, "")
if err != nil {
return errors.New("load ip library from reader failed: " + err.Error())
}
var reader = fileReader.RawReader()
defaultLibrary = NewIPLibraryWithReader(reader)
this.currentCode = reader.Meta().Code
return nil
}
func (this *Updater) createDefaultFile(sourcePath string, dir string) error {
sourceFp, err := os.Open(sourcePath)
if err != nil {
return errors.New("prepare to copy file to 'ip-library.db' failed: " + err.Error())
}
defer func() {
_ = sourceFp.Close()
}()
dstFp, err := os.Create(dir + "/ip-library.db")
if err != nil {
return errors.New("prepare to copy file to 'ip-library.db' failed: " + err.Error())
}
defer func() {
_ = dstFp.Close()
}()
_, err = io.Copy(dstFp, sourceFp)
if err != nil {
return errors.New("copy file to 'ip-library.db' failed: " + err.Error())
}
return nil
}
// isConnError 是否为连接错误
func (this *Updater) isConnError(err error) bool {
if err == nil {
return false
}
// 检查是否为连接错误
statusErr, ok := status.FromError(err)
if ok {
var errorCode = statusErr.Code()
return errorCode == codes.Unavailable || errorCode == codes.Canceled
}
if strings.Contains(err.Error(), "code = Canceled") {
return true
}
return false
}

View File

@@ -0,0 +1,53 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
"io"
"testing"
"time"
)
type updaterSource struct {
t *testing.T
}
func (this *updaterSource) DataDir() string {
return Tea.Root + "/data"
}
func (this *updaterSource) FindLatestFile() (code string, fileId int64, err error) {
return "CODE", 1, nil
}
func (this *updaterSource) DownloadFile(fileId int64, writer io.Writer) error {
this.t.Log("downloading file:", fileId, "writer:", writer)
_, err := writer.Write(iplibrary.DefaultIPLibraryData())
return err
}
func (this *updaterSource) LogInfo(message string) {
this.t.Log(message)
}
func (this *updaterSource) LogError(err error) {
this.t.Fatal(err)
}
func TestNewUpdater(t *testing.T) {
var updater = iplibrary.NewUpdater(&updaterSource{
t: t,
}, 1*time.Minute)
err := updater.Init()
if err != nil {
t.Fatal(err)
}
err = updater.Loop()
if err != nil {
t.Fatal(err)
}
}

10
pkg/iplibrary/version.go Normal file
View File

@@ -0,0 +1,10 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
type Version = int
const (
Version1 Version = 1
Version2 Version = 2 // 主要变更为数字使用32进制
)

202
pkg/iplibrary/writer.go Normal file
View File

@@ -0,0 +1,202 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"hash"
"io"
"net"
"strconv"
"strings"
"time"
)
type hashWriter struct {
rawWriter io.Writer
hash hash.Hash
}
func newHashWriter(writer io.Writer) *hashWriter {
return &hashWriter{
rawWriter: writer,
hash: md5.New(),
}
}
func (this *hashWriter) Write(p []byte) (n int, err error) {
n, err = this.rawWriter.Write(p)
this.hash.Write(p)
return
}
func (this *hashWriter) Sum() string {
return fmt.Sprintf("%x", this.hash.Sum(nil))
}
type Writer struct {
writer *hashWriter
meta *Meta
lastIPFrom uint64 // 上一次的IP
lastCountryId int64
lastProvinceId int64
lastCityId int64
lastTownId int64
lastProviderId int64
}
func NewWriter(writer io.Writer, meta *Meta) *Writer {
if meta == nil {
meta = &Meta{}
}
meta.Version = Version2
meta.CreatedAt = time.Now().Unix()
var libWriter = &Writer{
writer: newHashWriter(writer),
meta: meta,
}
return libWriter
}
func (this *Writer) WriteMeta() error {
metaJSON, err := json.Marshal(this.meta)
if err != nil {
return err
}
_, err = this.writer.Write(metaJSON)
if err != nil {
return err
}
_, err = this.writer.Write([]byte("\n"))
return err
}
func (this *Writer) Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error {
// validate IP
var fromIP = net.ParseIP(ipFrom)
if fromIP == nil {
return errors.New("invalid 'ipFrom': '" + ipFrom + "'")
}
var fromIsIPv4 = configutils.IsIPv4(fromIP)
var toIP = net.ParseIP(ipTo)
if toIP == nil {
return errors.New("invalid 'ipTo': " + ipTo)
}
var toIsIPv4 = configutils.IsIPv4(toIP)
if fromIsIPv4 != toIsIPv4 {
return errors.New("'ipFrom(" + ipFrom + ")' and 'ipTo(" + ipTo + ")' should have the same IP version")
}
var pieces = []string{}
// 0
if fromIsIPv4 {
pieces = append(pieces, "")
} else {
pieces = append(pieces, "6")
}
// 1
var fromIPLong = configutils.IP2Long(fromIP)
var toIPLong = configutils.IP2Long(toIP)
if toIPLong < fromIPLong {
fromIPLong, toIPLong = toIPLong, fromIPLong
}
if this.lastIPFrom > 0 && fromIPLong > this.lastIPFrom {
pieces = append(pieces, "+"+this.formatUint64(fromIPLong-this.lastIPFrom))
} else {
pieces = append(pieces, this.formatUint64(fromIPLong))
}
this.lastIPFrom = fromIPLong
if ipFrom == ipTo {
// 2
pieces = append(pieces, "")
} else {
// 2
pieces = append(pieces, this.formatUint64(toIPLong-fromIPLong))
}
// 3
if countryId > 0 {
if countryId == this.lastCountryId {
pieces = append(pieces, "+")
} else {
pieces = append(pieces, this.formatUint64(uint64(countryId)))
}
} else {
pieces = append(pieces, "")
}
this.lastCountryId = countryId
// 4
if provinceId > 0 {
if provinceId == this.lastProvinceId {
pieces = append(pieces, "+")
} else {
pieces = append(pieces, this.formatUint64(uint64(provinceId)))
}
} else {
pieces = append(pieces, "")
}
this.lastProvinceId = provinceId
// 5
if cityId > 0 {
if cityId == this.lastCityId {
pieces = append(pieces, "+")
} else {
pieces = append(pieces, this.formatUint64(uint64(cityId)))
}
} else {
pieces = append(pieces, "")
}
this.lastCityId = cityId
// 6
if townId > 0 {
if townId == this.lastTownId {
pieces = append(pieces, "+")
} else {
pieces = append(pieces, this.formatUint64(uint64(townId)))
}
} else {
pieces = append(pieces, "")
}
this.lastTownId = townId
// 7
if providerId > 0 {
if providerId == this.lastProviderId {
pieces = append(pieces, "+")
} else {
pieces = append(pieces, this.formatUint64(uint64(providerId)))
}
} else {
pieces = append(pieces, "")
}
this.lastProviderId = providerId
_, err := this.writer.Write([]byte(strings.TrimRight(strings.Join(pieces, "|"), "|")))
if err != nil {
return err
}
_, err = this.writer.Write([]byte("\n"))
return err
}
func (this *Writer) Sum() string {
return this.writer.Sum()
}
func (this *Writer) formatUint64(i uint64) string {
return strconv.FormatUint(i, 32)
}

View File

@@ -0,0 +1,80 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary
import (
"compress/gzip"
"os"
)
type FileWriter struct {
fp *os.File
gzWriter *gzip.Writer
password string
rawWriter *Writer
}
func NewFileWriter(path string, meta *Meta, password string) (*FileWriter, error) {
fp, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
return nil, err
}
gzWriter, err := gzip.NewWriterLevel(fp, gzip.BestCompression)
if err != nil {
return nil, err
}
var writer = &FileWriter{
fp: fp,
gzWriter: gzWriter,
rawWriter: NewWriter(gzWriter, meta),
password: password,
}
return writer, nil
}
func (this *FileWriter) WriteMeta() error {
return this.rawWriter.WriteMeta()
}
func (this *FileWriter) Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error {
return this.rawWriter.Write(ipFrom, ipTo, countryId, provinceId, cityId, townId, providerId)
}
func (this *FileWriter) Sum() string {
return this.rawWriter.Sum()
}
func (this *FileWriter) Close() error {
err1 := this.gzWriter.Close()
err2 := this.fp.Close()
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
// 加密内容
if len(this.password) > 0 {
var filePath = this.fp.Name()
data, err := os.ReadFile(filePath)
if err != nil {
return err
}
if len(data) > 0 {
encodedData, err := NewEncrypt().Encode(data, this.password)
if err != nil {
return err
}
err = os.WriteFile(filePath, encodedData, 0666)
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -0,0 +1,56 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
"testing"
)
func TestNewFileWriter(t *testing.T) {
writer, err := iplibrary.NewFileWriter("./internal-ip-library-test.db", &iplibrary.Meta{
Author: "GoEdge",
}, "")
if err != nil {
t.Fatal(err)
}
err = writer.WriteMeta()
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.1.100", "192.168.1.100", 100, 200, 300, 400, 500)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.2.100", "192.168.3.100", 101, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.3.101", "192.168.3.101", 101, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
var n = func() string {
return types.String(rands.Int(0, 255))
}
for i := 0; i < 1; i++ {
err = writer.Write(n()+"."+n()+"."+n()+"."+n(), n()+"."+n()+"."+n()+"."+n(), int64(i)+100, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
}
err = writer.Close()
if err != nil {
t.Fatal(err)
}
t.Log("ok", writer.Sum())
}

View File

@@ -0,0 +1,44 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package iplibrary_test
import (
"bytes"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"testing"
)
func TestNewWriter(t *testing.T) {
var buf = &bytes.Buffer{}
var writer = iplibrary.NewWriter(buf, &iplibrary.Meta{
Author: "GoEdge <https://goedge.cn>",
})
err := writer.WriteMeta()
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.1.100", "192.168.1.100", 100, 200, 300, 400, 500)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.2.100", "192.168.3.100", 101, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
err = writer.Write("192.168.3.101", "192.168.3.101", 101, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
err = writer.Write("::1", "::2", 101, 201, 301, 401, 501)
if err != nil {
t.Fatal(err)
}
t.Log(buf.String())
t.Log("sum:", writer.Sum())
}

View File

@@ -7,10 +7,9 @@ const (
MessageCodeWriteCache MessageCode = "writeCache" // 写入缓存
MessageCodeReadCache MessageCode = "readCache" // 读取缓存
MessageCodeStatCache MessageCode = "statCache" // 统计缓存
MessageCodePurgeCache MessageCode = "purgeCache" // 删除缓存
MessageCodeCleanCache MessageCode = "cleanCache" // 清理缓存
MessageCodePreheatCache MessageCode = "preheatCache" // 预热缓存
MessageCodeCheckSystemdService MessageCode = "checkSystemdService" // 检查Systemd服务
MessageCodeCheckLocalFirewall MessageCode = "checkLocalFirewall" // 检查本地防火墙
MessageCodeNewNodeTask MessageCode = "newNodeTask" // 有新的节点任务产生
MessageCodeChangeAPINode MessageCode = "changeAPINode" // 改变新的API节点
)
@@ -45,30 +44,15 @@ type CleanCacheMessage struct {
CachePolicyJSON []byte `json:"cachePolicyJSON"`
}
// PurgeCacheMessageType 删除缓存
type PurgeCacheMessageType = string
const (
PurgeCacheMessageTypeFile PurgeCacheMessageType = "file"
PurgeCacheMessageTypeDir PurgeCacheMessageType = "dir"
)
type PurgeCacheMessage struct {
CachePolicyJSON []byte `json:"cachePolicyJSON"`
Keys []string `json:"keys"`
Type PurgeCacheMessageType `json:"type"` // 清理类型
}
// PreheatCacheMessage 预热缓存
type PreheatCacheMessage struct {
CachePolicyJSON []byte `json:"cachePolicyJSON"`
Keys []string `json:"keys"`
}
// CheckSystemdServiceMessage Systemd服务
type CheckSystemdServiceMessage struct {
}
// CheckLocalFirewallMessage 检查本地防火墙
type CheckLocalFirewallMessage struct {
Name string `json:"name"`
}
// NewNodeTaskMessage 有新的节点任务
type NewNodeTaskMessage struct {
}

View File

@@ -0,0 +1,22 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
func DefaultClockConfig() *ClockConfig {
return &ClockConfig{
AutoSync: true,
Server: "",
CheckChrony: true,
}
}
// ClockConfig 时钟相关配置
type ClockConfig struct {
AutoSync bool `yaml:"autoSync" json:"autoSync"` // 自动尝试同步时钟
Server string `yaml:"server" json:"server"` // 时钟同步服务器
CheckChrony bool `yaml:"checkChrony" json:"checkChrony"` // 检查 chronyd 是否在运行
}
func (this *ClockConfig) Init() error {
return nil
}

View File

@@ -2,14 +2,36 @@
package nodeconfigs
import "github.com/iwind/TeaGo/maps"
// 一组系统默认值
// 修改单个IP相关限制值时要考虑到NAT中每个IP会代表很多个主机并非1对1的关系
const (
DefaultMaxThreads = 20000 // 单节点最大线程数
DefaultMaxThreadsMin = 1000 // 单节点最大线程数最小值
DefaultMaxThreadsMax = 100_000 // 单节点最大线程数最大值
DefaultTCPMaxConnections = 100_000 // 单节点TCP最大连接数
DefaultTCPLinger = 3 // 单节点TCP Linger值
DefaultTLSHandshakeTimeout = 3 // TLS握手超时时间
DefaultTCPMaxConnections = 100_000 // 单节点TCP最大连接数
DefaultTCPMaxConnectionsPerIP = 1000 // 单IP最大连接数
DefaultTCPMinConnectionsPerIP = 5 // 单IP最小连接数
DefaultTCPNewConnectionsMinutelyRate = 500 // 单IP连接速率限制按分钟
DefaultTCPNewConnectionsMinMinutelyRate = 3 // 单IP最小连接速率
DefaultTCPNewConnectionsSecondlyRate = 300 // 单IP连接速率限制按秒
DefaultTCPNewConnectionsMinSecondlyRate = 3 // 单IP最小连接速率
DefaultTCPLinger = 3 // 单节点TCP Linger值
DefaultTLSHandshakeTimeout = 3 // TLS握手超时时间
)
var DefaultConfigs = maps.Map{
"tcpMaxConnections": DefaultTCPMaxConnections,
"tcpMaxConnectionsPerIP": DefaultTCPMaxConnectionsPerIP,
"tcpMinConnectionsPerIP": DefaultTCPMinConnectionsPerIP,
"tcpNewConnectionsMinutelyRate": DefaultTCPNewConnectionsMinutelyRate,
"tcpNewConnectionsMinMinutelyRate": DefaultTCPNewConnectionsMinMinutelyRate,
"tcpNewConnectionsSecondlyRate": DefaultTCPNewConnectionsSecondlyRate,
"tcpNewConnectionsMinSecondlyRate": DefaultTCPNewConnectionsMinSecondlyRate,
}

View File

@@ -0,0 +1,25 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
type DNSResolverType = string
const (
DNSResolverTypeDefault = "default"
DNSResolverTypeGoNative = "goNative"
DNSResolverTypeCGO = "cgo"
)
func DefaultDNSResolverConfig() *DNSResolverConfig {
return &DNSResolverConfig{
Type: DNSResolverTypeDefault,
}
}
type DNSResolverConfig struct {
Type string `yaml:"type" json:"type"` // 使用Go语言内置的DNS解析器
}
func (this *DNSResolverConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,23 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
const DefaultHTTP3Port = 443
type HTTP3Policy struct {
IsOn bool `yaml:"isOn" json:"isOn"`
Port int `yaml:"port" json:"port"`
}
func NewHTTP3Policy() *HTTP3Policy {
return &HTTP3Policy{
Port: DefaultHTTP3Port,
}
}
func (this *HTTP3Policy) Init() error {
if this.Port <= 0 {
this.Port = DefaultHTTP3Port
}
return nil
}

View File

@@ -0,0 +1,22 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
// HTTPCCPolicy CC策略
type HTTPCCPolicy struct {
IsOn bool `json:"isOn" yaml:"isOn"`
Thresholds []*serverconfigs.HTTPCCThreshold `json:"thresholds" yaml:"thresholds"` // 阈值
}
func NewHTTPCCPolicy() *HTTPCCPolicy {
return &HTTPCCPolicy{
IsOn: true,
}
}
func (this *HTTPCCPolicy) Init() error {
return nil
}

View File

@@ -0,0 +1,28 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
// HTTPPagesPolicy 全局的HTTP自定义页面设置
type HTTPPagesPolicy struct {
IsOn bool `json:"isOn" yaml:"isOn"` // 是否启用
Pages []*serverconfigs.HTTPPageConfig `json:"pages" yaml:"pages"` // 自定义页面
}
func NewHTTPPagesPolicy() *HTTPPagesPolicy {
return &HTTPPagesPolicy{}
}
func (this *HTTPPagesPolicy) Init() error {
if len(this.Pages) > 0 {
for _, page := range this.Pages {
err := page.Init()
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -1,21 +1,33 @@
package nodeconfigs
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
"sync"
)
var sharedNodeConfig *NodeConfig = nil
var uamPolicyLocker = &sync.RWMutex{}
var httpCCPolicyLocker = &sync.RWMutex{}
var http3PolicyLocker = &sync.RWMutex{}
var httpPagesPolicyLocker = &sync.RWMutex{}
type ServerError struct {
Id int64
@@ -28,42 +40,54 @@ func NewServerError(serverId int64, message string) *ServerError {
// NodeConfig 边缘节点配置
type NodeConfig struct {
Id int64 `yaml:"id" json:"id"`
NodeId string `yaml:"nodeId" json:"nodeId"`
Secret string `yaml:"secret" json:"secret"`
IsOn bool `yaml:"isOn" json:"isOn"`
Servers []*serverconfigs.ServerConfig `yaml:"servers" json:"servers"`
SupportCNAME bool `yaml:"supportCNAME" json:"supportCNAME"`
Version int64 `yaml:"version" json:"version"`
Name string `yaml:"name" json:"name"`
GroupId int64 `yaml:"groupId" json:"groupId"`
RegionId int64 `yaml:"regionId" json:"regionId"`
OCSPVersion int64 `yaml:"ocspVersion" json:"ocspVersion"`
Id int64 `yaml:"id" json:"id"`
Edition string `yaml:"edition" json:"edition"`
NodeId string `yaml:"nodeId" json:"nodeId"`
Secret string `yaml:"secret" json:"secret"`
IsOn bool `yaml:"isOn" json:"isOn"`
Servers []*serverconfigs.ServerConfig `yaml:"servers" json:"servers"`
SupportCNAME bool `yaml:"supportCNAME" json:"supportCNAME"`
Version int64 `yaml:"version" json:"version"`
Name string `yaml:"name" json:"name"`
GroupId int64 `yaml:"groupId" json:"groupId"`
RegionId int64 `yaml:"regionId" json:"regionId"`
OCSPVersion int64 `yaml:"ocspVersion" json:"ocspVersion"`
DataMap *shared.DataMap `yaml:"dataMap" json:"dataMap"`
UpdatingServerListId int64 `yaml:"updatingServerListId" json:"updatingServerListId"`
// 性能
MaxCPU int32 `yaml:"maxCPU" json:"maxCPU"`
CacheDiskDir string `yaml:"cacheDiskDir" json:"cacheDiskDir"` // 文件缓存目录
MaxCacheDiskCapacity *shared.SizeCapacity `yaml:"maxCacheDiskCapacity" json:"maxCacheDiskCapacity"` // 文件缓存容量
MaxCacheMemoryCapacity *shared.SizeCapacity `yaml:"maxCacheMemoryCapacity" json:"maxCacheMemoryCapacity"` // 内容缓存容量
MaxThreads int `yaml:"maxThreads" json:"maxThreads"`
TCPMaxConnections int `yaml:"tcpMaxConnections" json:"tcpMaxConnections"`
MaxCPU int32 `yaml:"maxCPU" json:"maxCPU"`
APINodeAddrs []*serverconfigs.NetworkAddressConfig `yaml:"apiNodeAddrs" json:"apiNodeAddrs"`
CacheDiskDir string `yaml:"cacheDiskDir" json:"cacheDiskDir"` // 文件缓存目录
MaxCacheDiskCapacity *shared.SizeCapacity `yaml:"maxCacheDiskCapacity" json:"maxCacheDiskCapacity"` // 文件缓存容量
CacheDiskSubDirs []*serverconfigs.CacheDir `yaml:"cacheDiskSubDirs" json:"cacheDiskSubDirs"` // 其余缓存目录
MaxCacheMemoryCapacity *shared.SizeCapacity `yaml:"maxCacheMemoryCapacity" json:"maxCacheMemoryCapacity"` // 内容缓存容量
MaxThreads int `yaml:"maxThreads" json:"maxThreads"` // 最大线程数
DDoSProtection *ddosconfigs.ProtectionConfig `yaml:"ddosProtection" json:"ddosProtection"` // DDoS防护
EnableIPLists bool `yaml:"enableIPLists" json:"enableIPLists"` // 启用IP名单
// 级别
Level int32 `yaml:"level" json:"level"`
ParentNodes map[int64][]*ParentNodeConfig `yaml:"parentNodes" json:"parentNodes"` // clusterId => []*ParentNodeConfig
// 全局配置
GlobalConfig *serverconfigs.GlobalConfig `yaml:"globalConfig" json:"globalConfig"` // 全局配置
ProductConfig *ProductConfig `yaml:"productConfig" json:"productConfig"`
GlobalConfig *serverconfigs.GlobalConfig `yaml:"globalConfig" json:"globalConfig"` // 全局配置
GlobalServerConfig *serverconfigs.GlobalServerConfig `yaml:"globalServerConfig" json:"globalServerConfig"` // 服务全局配置,用来替代 GlobalConfig
ProductConfig *ProductConfig `yaml:"productConfig" json:"productConfig"`
// 集群统一配置
HTTPFirewallPolicies []*firewallconfigs.HTTPFirewallPolicy `yaml:"httpFirewallPolicies" json:"httpFirewallPolicies"`
HTTPCachePolicies []*serverconfigs.HTTPCachePolicy `yaml:"httpCachePolicies" json:"httpCachePolicies"`
TOA *TOAConfig `yaml:"toa" json:"toa"`
SystemServices map[string]maps.Map `yaml:"systemServices" json:"systemServices"` // 系统服务配置 type => params
FirewallActions []*firewallconfigs.FirewallActionConfig `yaml:"firewallActions" json:"firewallActions"`
TimeZone string `yaml:"timeZone" json:"timeZone"`
AutoOpenPorts bool `yaml:"autoOpenPorts" json:"autoOpenPorts"`
SystemServices map[string]maps.Map `yaml:"systemServices" json:"systemServices"` // 系统服务配置 type => params
FirewallActions []*firewallconfigs.FirewallActionConfig `yaml:"firewallActions" json:"firewallActions"` // 防火墙动作
TimeZone string `yaml:"timeZone" json:"timeZone"` // 自动设置时区
AutoOpenPorts bool `yaml:"autoOpenPorts" json:"autoOpenPorts"` // 自动开放所需端口
Clock *ClockConfig `yaml:"clock" json:"clock"` // 时钟配置
AutoInstallNftables bool `yaml:"autoInstallNftables" json:"autoInstallNftables"` // 自动安装nftables
// 指标
MetricItems []*serverconfigs.MetricItemConfig `yaml:"metricItems" json:"metricItems"`
@@ -74,8 +98,14 @@ type NodeConfig struct {
// 脚本
CommonScripts []*serverconfigs.CommonScript `yaml:"commonScripts" json:"commonScripts"`
// WebP
WebPImagePolicies map[int64]*WebPImagePolicy `yaml:"webpImagePolicies" json:"webpImagePolicies"` // clusterId => *WebPImagePolicy
WebPImagePolicies map[int64]*WebPImagePolicy `yaml:"webpImagePolicies" json:"webpImagePolicies"` // WebP相关配置clusterId => *WebPImagePolicy
UAMPolicies map[int64]*UAMPolicy `yaml:"uamPolicies" json:"uamPolicies"` // UAM相关配置clusterId => *UAMPolicy
HTTPCCPolicies map[int64]*HTTPCCPolicy `yaml:"httpCCPolicies" json:"httpCCPolicies"` // CC相关配置 clusterId => *HTTPCCPolicy
HTTP3Policies map[int64]*HTTP3Policy `yaml:"http3Policies" json:"http3Policies"` // HTTP3相关配置 clusterId => *HTTP3Policy
HTTPPagesPolicies map[int64]*HTTPPagesPolicy `yaml:"httpPagesPolicies" json:"httpPagesPolicies"` // 自定义页面clusterId => *HTTPPagesPolicy
// DNS
DNSResolver *DNSResolverConfig `yaml:"dnsResolver" json:"dnsResolver"`
paddedId string
@@ -106,17 +136,50 @@ func SharedNodeConfig() (*NodeConfig, error) {
return sharedNodeConfig, nil
}
data, err := ioutil.ReadFile(Tea.ConfigFile("node.json"))
// 从本地缓存读取
var configFile = Tea.ConfigFile("node.json")
var readCacheOk = false
defer func() {
if !readCacheOk {
_ = os.Remove(configFile)
}
}()
data, err := os.ReadFile(configFile)
if err != nil {
return &NodeConfig{}, err
}
config := &NodeConfig{}
err = json.Unmarshal(data, &config)
encodedNodeInfo, encodedJSONData, found := bytes.Cut(data, []byte("\n"))
if !found {
// 删除缓存文件
return &NodeConfig{}, errors.New("node.json: invalid data format")
}
encodedNodeInfoData, err := base64.StdEncoding.DecodeString(string(encodedNodeInfo))
if err != nil {
// 删除缓存文件
return &NodeConfig{}, err
}
nodeUniqueId, nodeSecret, found := strings.Cut(string(encodedNodeInfoData), "|")
if !found {
// 删除缓存文件
return &NodeConfig{}, errors.New("node.json: node info: invalid data format")
}
jsonData, err := nodeutils.DecryptData(nodeUniqueId, nodeSecret, string(encodedJSONData))
if err != nil {
return &NodeConfig{}, err
}
var config = &NodeConfig{}
err = json.Unmarshal(jsonData, &config)
if err != nil {
return &NodeConfig{}, err
}
readCacheOk = true
sharedNodeConfig = config
return config, nil
}
@@ -134,6 +197,18 @@ func CloneNodeConfig(nodeConfig *NodeConfig) (*NodeConfig, error) {
return nil, errors.New("node config should not be nil")
}
uamPolicyLocker.RLock()
defer uamPolicyLocker.RUnlock()
httpCCPolicyLocker.RLock()
defer httpCCPolicyLocker.RUnlock()
http3PolicyLocker.RLock()
defer http3PolicyLocker.RUnlock()
httpPagesPolicyLocker.RLock()
defer httpPagesPolicyLocker.RUnlock()
var newConfigValue = reflect.Indirect(reflect.ValueOf(&NodeConfig{}))
var oldValue = reflect.Indirect(reflect.ValueOf(nodeConfig))
var valueType = oldValue.Type()
@@ -156,14 +231,25 @@ func CloneNodeConfig(nodeConfig *NodeConfig) (*NodeConfig, error) {
}
// Init 初始化
func (this *NodeConfig) Init() (err error, serverErrors []*ServerError) {
func (this *NodeConfig) Init(ctx context.Context) (err error, serverErrors []*ServerError) {
// 设置Context
if ctx == nil {
ctx = context.Background()
}
ctx = context.WithValue(ctx, "DataMap", this.DataMap)
this.secretHash = fmt.Sprintf("%x", sha256.Sum256([]byte(this.NodeId+"@"+this.Secret)))
this.paddedId = fmt.Sprintf("%08d", this.Id)
// servers
for _, server := range this.Servers {
// 避免在运行时重新初始化
if server.IsInitialized() {
continue
}
// 初始化
errs := server.Init()
errs := server.Init(ctx)
if len(errs) > 0 {
// 这里不返回错误,而是继续往下,防止单个服务错误而影响其他服务
for _, serverErr := range errs {
@@ -306,6 +392,84 @@ func (this *NodeConfig) Init() (err error, serverErrors []*ServerError) {
}
}
// uam policy
uamPolicyLocker.RLock()
if len(this.UAMPolicies) > 0 {
for _, policy := range this.UAMPolicies {
err = policy.Init()
if err != nil {
uamPolicyLocker.RUnlock()
return
}
}
}
uamPolicyLocker.RUnlock()
// http cc policy
httpCCPolicyLocker.RLock()
if len(this.HTTPCCPolicies) > 0 {
for _, policy := range this.HTTPCCPolicies {
err = policy.Init()
if err != nil {
httpCCPolicyLocker.RUnlock()
return
}
}
}
httpCCPolicyLocker.RUnlock()
// http3 policy
http3PolicyLocker.RLock()
if len(this.HTTP3Policies) > 0 {
for _, policy := range this.HTTP3Policies {
err = policy.Init()
if err != nil {
http3PolicyLocker.RUnlock()
return
}
}
}
http3PolicyLocker.RUnlock()
// http pages policy
httpPagesPolicyLocker.RLock()
if len(this.HTTPPagesPolicies) > 0 {
for _, policy := range this.HTTPPagesPolicies {
err = policy.Init()
if err != nil {
httpPagesPolicyLocker.RUnlock()
return
}
}
}
httpPagesPolicyLocker.RUnlock()
// dns resolver
if this.DNSResolver != nil {
err = this.DNSResolver.Init()
if err != nil {
return
}
}
// 全局服务设置
if this.GlobalServerConfig != nil {
err = this.GlobalServerConfig.Init()
if err != nil {
return
}
}
// api node addrs
if len(this.APINodeAddrs) > 0 {
for _, addr := range this.APINodeAddrs {
err := addr.Init()
if err != nil {
return err, nil
}
}
}
return
}
@@ -340,7 +504,7 @@ func (this *NodeConfig) RemoveServer(serverId int64) {
// AvailableGroups 根据网络地址和协议分组
func (this *NodeConfig) AvailableGroups() []*serverconfigs.ServerAddressGroup {
groupMapping := map[string]*serverconfigs.ServerAddressGroup{} // protocol://addr => Server Group
var groupMapping = map[string]*serverconfigs.ServerAddressGroup{} // protocol://addr => Server Group
for _, server := range this.Servers {
if !server.IsOk() || !server.IsOn {
continue
@@ -356,13 +520,26 @@ func (this *NodeConfig) AvailableGroups() []*serverconfigs.ServerAddressGroup {
groupMapping[addr] = group
}
}
result := []*serverconfigs.ServerAddressGroup{}
var result = []*serverconfigs.ServerAddressGroup{}
for _, group := range groupMapping {
result = append(result, group)
}
return result
}
// HTTP3Group HTTP/3网站分组
// 这里暂时不区分集群
func (this *NodeConfig) HTTP3Group() *serverconfigs.ServerAddressGroup {
var group = serverconfigs.NewServerAddressGroup("HTTP3")
for _, server := range this.Servers {
if !server.SupportsHTTP3() {
continue
}
group.Add(server)
}
return group
}
// FindAllFirewallPolicies 获取所有的防火墙策略
func (this *NodeConfig) FindAllFirewallPolicies() []*firewallconfigs.HTTPFirewallPolicy {
return this.firewallPolicies
@@ -378,7 +555,14 @@ func (this *NodeConfig) Save() error {
return err
}
return ioutil.WriteFile(Tea.ConfigFile("node.json"), data, 0777)
var headerData = []byte(base64.StdEncoding.EncodeToString([]byte(this.NodeId+"|"+this.Secret)) + "\n")
encodedData, err := nodeutils.EncryptData(this.NodeId, this.Secret, data)
if err != nil {
return err
}
return os.WriteFile(Tea.ConfigFile("node.json"), append(headerData, encodedData...), 0777)
}
// PaddedId 获取填充后的ID
@@ -409,12 +593,25 @@ func (this *NodeConfig) lookupWeb(server *serverconfigs.ServerConfig, web *serve
return
}
if web.FirewallPolicy != nil && web.FirewallPolicy.IsOn {
// 复用节点的拦截选项设置
if web.FirewallPolicy.BlockOptions == nil && server.HTTPFirewallPolicy != nil && server.HTTPFirewallPolicy.BlockOptions != nil {
web.FirewallPolicy.BlockOptions = server.HTTPFirewallPolicy.BlockOptions
// 复用节点的选项设置
if server.HTTPFirewallPolicy != nil {
if (web.FirewallPolicy.BlockOptions == nil || !web.FirewallPolicy.BlockOptions.IsPrior) && server.HTTPFirewallPolicy.BlockOptions != nil {
web.FirewallPolicy.BlockOptions = server.HTTPFirewallPolicy.BlockOptions
}
if (web.FirewallPolicy.CaptchaOptions == nil || !web.FirewallPolicy.CaptchaOptions.IsPrior) && server.HTTPFirewallPolicy.CaptchaOptions != nil {
web.FirewallPolicy.CaptchaOptions = server.HTTPFirewallPolicy.CaptchaOptions
}
if (web.FirewallPolicy.SYNFlood == nil || !web.FirewallPolicy.SYNFlood.IsPrior) && server.HTTPFirewallPolicy.SYNFlood != nil {
web.FirewallPolicy.SYNFlood = server.HTTPFirewallPolicy.SYNFlood
}
if (web.FirewallPolicy.Log == nil || !web.FirewallPolicy.Log.IsPrior) && server.HTTPFirewallPolicy.Log != nil {
web.FirewallPolicy.Log = server.HTTPFirewallPolicy.Log
}
web.FirewallPolicy.Mode = server.HTTPFirewallPolicy.Mode
web.FirewallPolicy.UseLocalFirewall = server.HTTPFirewallPolicy.UseLocalFirewall
}
this.firewallPolicies = append(this.firewallPolicies, web.FirewallPolicy)
}
if len(web.Locations) > 0 {
@@ -483,6 +680,92 @@ func (this *NodeConfig) FindWebPImagePolicyWithClusterId(clusterId int64) *WebPI
return this.WebPImagePolicies[clusterId]
}
// FindUAMPolicyWithClusterId 使用集群ID查找UAM策略
func (this *NodeConfig) FindUAMPolicyWithClusterId(clusterId int64) *UAMPolicy {
uamPolicyLocker.RLock()
defer uamPolicyLocker.RUnlock()
if this.UAMPolicies == nil {
return nil
}
return this.UAMPolicies[clusterId]
}
// UpdateUAMPolicies 修改集群UAM策略
func (this *NodeConfig) UpdateUAMPolicies(policies map[int64]*UAMPolicy) {
uamPolicyLocker.Lock()
defer uamPolicyLocker.Unlock()
this.UAMPolicies = policies
}
// FindHTTPCCPolicyWithClusterId 使用集群ID查找CC策略
func (this *NodeConfig) FindHTTPCCPolicyWithClusterId(clusterId int64) *HTTPCCPolicy {
httpCCPolicyLocker.RLock()
defer httpCCPolicyLocker.RUnlock()
if this.HTTPCCPolicies == nil {
return nil
}
return this.HTTPCCPolicies[clusterId]
}
// UpdateHTTPCCPolicies 修改集群CC策略
func (this *NodeConfig) UpdateHTTPCCPolicies(policies map[int64]*HTTPCCPolicy) {
httpCCPolicyLocker.Lock()
defer httpCCPolicyLocker.Unlock()
this.HTTPCCPolicies = policies
}
// FindHTTP3PolicyWithClusterId 使用集群ID查找HTTP/3策略
func (this *NodeConfig) FindHTTP3PolicyWithClusterId(clusterId int64) *HTTP3Policy {
http3PolicyLocker.RLock()
defer http3PolicyLocker.RUnlock()
if this.HTTP3Policies == nil {
return nil
}
return this.HTTP3Policies[clusterId]
}
// FindHTTP3Ports 查询HTTP/3所有端口
func (this *NodeConfig) FindHTTP3Ports() (ports []int) {
http3PolicyLocker.RLock()
defer http3PolicyLocker.RUnlock()
for _, policy := range this.HTTP3Policies {
if !policy.IsOn {
continue
}
if policy.Port <= 0 {
policy.Port = DefaultHTTP3Port
}
if !lists.ContainsInt(ports, policy.Port) {
ports = append(ports, policy.Port)
}
}
return
}
// UpdateHTTP3Policies 修改集群HTTP/3策略
func (this *NodeConfig) UpdateHTTP3Policies(policies map[int64]*HTTP3Policy) {
http3PolicyLocker.Lock()
defer http3PolicyLocker.Unlock()
this.HTTP3Policies = policies
}
// UpdateHTTPPagesPolicies 修改集群自定义页面策略
func (this *NodeConfig) UpdateHTTPPagesPolicies(policies map[int64]*HTTPPagesPolicy) {
httpPagesPolicyLocker.Lock()
defer httpPagesPolicyLocker.Unlock()
this.HTTPPagesPolicies = policies
}
// FindHTTPPagesPolicyWithClusterId 使用集群ID查找自定义页面策略
func (this *NodeConfig) FindHTTPPagesPolicyWithClusterId(clusterId int64) *HTTPPagesPolicy {
httpPagesPolicyLocker.RLock()
defer httpPagesPolicyLocker.RUnlock()
if this.HTTPPagesPolicies == nil {
return nil
}
return this.HTTPPagesPolicies[clusterId]
}
// SecretHash 对Id和Secret的Hash计算
func (this *NodeConfig) SecretHash() string {
return this.secretHash

View File

@@ -97,5 +97,24 @@ func TestNodeConfig_AddServer(t *testing.T) {
for _, s := range config.Servers {
t.Log(s.Id)
}
}
func TestCloneNodeConfig_UAMPolicies(t *testing.T) {
var config = &NodeConfig{}
config.UAMPolicies = map[int64]*UAMPolicy{}
t.Logf("%p", config.UAMPolicies)
clonedConfig, err := CloneNodeConfig(config)
if err != nil {
t.Fatal(err)
}
t.Logf("%p", clonedConfig.UAMPolicies)
}
func BenchmarkNodeConfig(b *testing.B) {
var config = &NodeConfig{}
for i := 0; i < b.N; i++ {
_, _ = CloneNodeConfig(config)
}
}

View File

@@ -20,10 +20,14 @@ type NodeStatus struct {
DiskMaxUsagePartition string `json:"diskMaxUsagePartition"`
DiskTotal uint64 `json:"diskTotal"`
UpdatedAt int64 `json:"updatedAt"`
Timestamp int64 `json:"timestamp"` // 当前节点时间戳
Load1m float64 `json:"load1m"`
Load5m float64 `json:"load5m"`
Load15m float64 `json:"load15m"`
ConnectionCount int `json:"connectionCount"` // 连接数
ConnectionCount int `json:"connectionCount"` // 连接数
ExePath string `json:"exePath"` // 可执行文件路径
APISuccessPercent float64 `json:"apiSuccessPercent"` // API成功比例
APIAvgCostSeconds float64 `json:"apiAvgCostSeconds"` // API平均耗时
TrafficInBytes uint64 `json:"trafficInBytes"`
TrafficOutBytes uint64 `json:"trafficOutBytes"`

View File

@@ -10,11 +10,14 @@ import (
type NodeValueItem = string
const (
NodeValueItemCPU NodeValueItem = "cpu" // CPU
NodeValueItemMemory NodeValueItem = "memory" // 内存
NodeValueItemLoad NodeValueItem = "load" // 负载
NodeValueItemTrafficIn NodeValueItem = "trafficIn" // 上行流量
NodeValueItemTrafficOut NodeValueItem = "trafficOut" // 行流量
NodeValueItemCPU NodeValueItem = "cpu" // CPU
NodeValueItemMemory NodeValueItem = "memory" // 内存
NodeValueItemLoad NodeValueItem = "load" // 负载
NodeValueItemTrafficIn NodeValueItem = "trafficIn" // 业务上行流量
NodeValueItemTrafficOut NodeValueItem = "trafficOut" // 业务下行流量
NodeValueItemAllTraffic NodeValueItem = "allTraffic" // 所有流量
NodeValueItemConnections NodeValueItem = "connections" // 连接数
NodeValueItemRequests NodeValueItem = "requests" // 请求访问量
NodeValueItemAttackRequests NodeValueItem = "attackRequests" // 攻击请求访问量

View File

@@ -0,0 +1,11 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
func DefaultSSHParams() *SSHParams {
return &SSHParams{Port: 22}
}
type SSHParams struct {
Port int `json:"port"`
}

View File

@@ -0,0 +1,14 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package nodeconfigs
var DefaultUAMPolicy = &UAMPolicy{}
type UAMPolicy struct {
IsOn bool `yaml:"isOn" json:"isOn"`
}
func (this *UAMPolicy) Init() error {
return nil
}

View File

@@ -13,7 +13,7 @@ type AES256CFBMethod struct {
func (this *AES256CFBMethod) Init(key, iv []byte) error {
// 判断key是否为32长度
l := len(key)
var l = len(key)
if l > 32 {
key = key[:32]
} else if l < 32 {
@@ -27,7 +27,7 @@ func (this *AES256CFBMethod) Init(key, iv []byte) error {
this.block = block
// 判断iv长度
l2 := len(iv)
var l2 = len(iv)
if l2 > aes.BlockSize {
iv = iv[:aes.BlockSize]
} else if l2 < aes.BlockSize {
@@ -49,7 +49,7 @@ func (this *AES256CFBMethod) Encrypt(src []byte) (dst []byte, err error) {
dst = make([]byte, len(src))
encrypter := cipher.NewCFBEncrypter(this.block, this.iv)
var encrypter = cipher.NewCFBEncrypter(this.block, this.iv)
encrypter.XORKeyStream(dst, src)
return
@@ -65,7 +65,7 @@ func (this *AES256CFBMethod) Decrypt(dst []byte) (src []byte, err error) {
}()
src = make([]byte, len(dst))
decrypter := cipher.NewCFBDecrypter(this.block, this.iv)
var decrypter = cipher.NewCFBDecrypter(this.block, this.iv)
decrypter.XORKeyStream(src, dst)
return

View File

@@ -10,8 +10,8 @@ import (
"time"
)
// EncryptData 加密
func EncryptData(nodeUniqueId string, nodeSecret string, data maps.Map, timeout int32) (string, error) {
// EncryptMap 加密
func EncryptMap(nodeUniqueId string, nodeSecret string, data maps.Map, timeout int32) (string, error) {
if data == nil {
data = maps.Map{}
}
@@ -42,8 +42,8 @@ func EncryptData(nodeUniqueId string, nodeSecret string, data maps.Map, timeout
return base64.StdEncoding.EncodeToString(result), nil
}
// DecryptData 解密
func DecryptData(nodeUniqueId string, nodeSecret string, encodedString string) (maps.Map, error) {
// DecryptMap 解密
func DecryptMap(nodeUniqueId string, nodeSecret string, encodedString string) (maps.Map, error) {
var method = &AES256CFBMethod{}
err := method.Init([]byte(nodeUniqueId), []byte(nodeSecret))
if err != nil {
@@ -73,3 +73,42 @@ func DecryptData(nodeUniqueId string, nodeSecret string, encodedString string) (
return result.GetMap("data"), nil
}
// EncryptData 加密
func EncryptData(nodeUniqueId string, nodeSecret string, data []byte) (string, error) {
if len(data) == 0 {
return "", nil
}
var method = &AES256CFBMethod{}
err := method.Init([]byte(nodeUniqueId), []byte(nodeSecret))
if err != nil {
return "", err
}
result, err := method.Encrypt(data)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(result), nil
}
// DecryptData 解密
func DecryptData(nodeUniqueId string, nodeSecret string, encodedString string) ([]byte, error) {
if len(encodedString) == 0 {
return nil, nil
}
var method = &AES256CFBMethod{}
err := method.Init([]byte(nodeUniqueId), []byte(nodeSecret))
if err != nil {
return nil, err
}
encodedData, err := base64.StdEncoding.DecodeString(encodedString)
if err != nil {
return nil, errors.New("base64 decode failed: " + err.Error())
}
return method.Decrypt(encodedData)
}

View File

@@ -7,8 +7,8 @@ import (
"testing"
)
func TestEncryptData(t *testing.T) {
e, err := EncryptData("a", "b", maps.Map{
func TestEncryptMap(t *testing.T) {
e, err := EncryptMap("a", "b", maps.Map{
"c": 1,
}, 5)
if err != nil {
@@ -16,16 +16,30 @@ func TestEncryptData(t *testing.T) {
}
t.Log("e:", e)
s, err := DecryptData("a", "b", e)
s, err := DecryptMap("a", "b", e)
if err != nil {
t.Fatal(err)
}
t.Log("s:", s)
}
func TestEncryptData(t *testing.T) {
encoded, err := EncryptData("a", "b", []byte("Hello, World"))
if err != nil {
t.Fatal(err)
}
t.Log("encoded:", encoded)
source, err := DecryptData("a", "b", encoded)
if err != nil {
t.Fatal(err)
}
t.Log("source:", string(source))
}
func BenchmarkEncryptData(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = EncryptData("a", "b", maps.Map{
_, _ = EncryptMap("a", "b", maps.Map{
"c": 1,
}, 5)
}

View File

@@ -102,6 +102,7 @@ func (this *IPListDAO) CreateIPListForServerId(ctx context.Context, serverId int
Type: listType,
Name: "IP名单",
Code: listType,
ServerId: serverId,
TimeoutJSON: nil,
})
if err != nil {

View File

@@ -12,7 +12,6 @@ type RPCClient interface {
SysSettingRPC() pb.SysSettingServiceClient
NodeClusterRPC() pb.NodeClusterServiceClient
NodeRegionRPC() pb.NodeRegionServiceClient
NodePriceItemRPC() pb.NodePriceItemServiceClient
ServerRPC() pb.ServerServiceClient
ServerGroupRPC() pb.ServerGroupServiceClient
OriginRPC() pb.OriginServiceClient
@@ -46,6 +45,4 @@ type RPCClient interface {
ACMEUserRPC() pb.ACMEUserServiceClient
ACMETaskRPC() pb.ACMETaskServiceClient
UserRPC() pb.UserServiceClient
UserBillRPC() pb.UserBillServiceClient
UserNodeRPC() pb.UserNodeServiceClient
}

View File

@@ -6,27 +6,28 @@ import (
"errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"strings"
)
// HumanError 格式化GRPC相关错误
func HumanError(err error) error {
func HumanError(err error, endpoints []string, configFile string) (resultErr error, isConnError bool) {
if err == nil {
return err
return err, false
}
errStatus, ok := status.FromError(err)
if !ok {
return err
return err, false
}
switch errStatus.Code() {
case codes.InvalidArgument:
return errors.New("错误的RPC参数" + err.Error())
return errors.New("错误的RPC参数" + err.Error()), false
case codes.DeadlineExceeded:
return errors.New("RPC操作超时请重试" + err.Error())
return errors.New("RPC操作超时请重试" + err.Error()), false
case codes.Unimplemented:
return errors.New("请求的RPC服务或方法不存在可能是没有升级API节点或者当前节点没有升级" + err.Error())
return errors.New("请求的RPC服务或方法不存在可能是没有升级API节点或者当前节点没有升级" + err.Error()), false
case codes.Unavailable:
return errors.New("RPC当前不可用1、请确当前节点的api.yaml配置中的地址填写正确;2、请确保API节点已启动并检查当前节点和API节点之间的网络连接是正常的。错误信息" + err.Error())
return errors.New("RPC当前不可用<br/>1、请确当前节点的api.yaml<em>" + configFile + "</em>)配置中的地址(<em>" + strings.Join(endpoints, ", ") + "</em>)是否已填写正确;<br/>2、请确保API节点已启动并检查当前节点和API节点之间的网络连接是正常的。<hr/>错误信息:" + err.Error()), true
}
return err
return err, false
}

39
pkg/rpc/jsons/hsts.md Normal file
View File

@@ -0,0 +1,39 @@
# HSTS
## 定义
~~~json
{
"isOn": "是否启用",
"maxAge": "最大有效期,单位秒",
"includeSubDomains": "可选项,是否包含子域名",
"preload": "可选项,是否预加载",
"domains": ["可选项支持的域名1", "可选项支持的域名2" ...]
}
~~~
其中:
* `maxAge` 可以填写一天86400秒或者更长时间
* 如果不填写 `domains` 则支持所有域名
## 示例
### 不限制任何域名
~~~json
{
"isOn": true,
"maxAge": 86400,
"includeSubDomains":false,
"preload":false,
"domains":[]
}
~~~
### 限制域名
~~~json
{
"isOn": true,
"maxAge": 86400,
"includeSubDomains":false,
"preload":false,
"domains":["example.com", "www.example.com"]
}
~~~

View File

@@ -0,0 +1,43 @@
# 访问日志引用
## 定义
~~~json
{
"isPrior": "是否覆盖父级应用",
"isOn": "是否启用配置",
"fields": ["字段1", "字段2", ...] // 可以留空
"status1": "是否启用状态1xx",
"status2": "是否启用状态2xx",
"status3": "是否启用状态3xx",
"status4": "是否启用状态4xx",
"status5": "是否启用状态5xx",
"enableClientClosed": "是否记录客户端关闭事件",
"firewallOnly": "是否只记录防火墙WAF相关日志"
}
~~~
### 字段值
* `1` - 请求Header
* `2` - 响应Header
* `3` - 请求URL参数
* `4` - Cookie
* `5` - 扩展信息
* `6` - Referer
* `7` - UserAgent
* `8` - 请求Body
* `9` - 响应Body目前不支持
## 示例
~~~json
{
"isPrior": true,
"isOn": true,
"fields": [],
"status1": true,
"status2": true,
"status3": true,
"status4": true,
"status5": true,
"enableClientClosed": true,
"firewallOnly": true
}
~~~

View File

@@ -0,0 +1,92 @@
# HTTP缓存配置
## 定义
~~~json
{
"isPrior": "是否覆盖上级配置",
"isOn": "是否启用配置",
"addStatusHeader": "是否增加命中状态HeaderX-Cache",
"addAgeHeader": "是否增加Age Header",
"enableCacheControlMaxAge": "是否支持Cache-Control: max-age=...",
"disablePolicyRefs": "是否停用策略中定义的条件",
"purgeIsOn": "是否允许使用Purge方法清理",
"purgeKey": "Purge时使用的X-Edge-Purge-Key",
"stale": "陈旧缓存使用策略",
"cacheRefs": ["缓存条件1", "缓存条件2", ...]
}
~~~
其中:
* `缓存条件` - 参考 {json:http_cache_ref}
## 示例
### 无缓存条件
~~~json
{
"isPrior": true,
"isOn": true,
"addStatusHeader": true,
"addAgeHeader": true,
"enableCacheControlMaxAge": true,
"disablePolicyRefs": false,
"purgeIsOn": false,
"purgeKey": "",
"stale": null,
"cacheRefs": []
}
~~~
### 加入缓存条件
~~~json
{
"isPrior": true,
"isOn": true,
"addStatusHeader": true,
"addAgeHeader": true,
"enableCacheControlMaxAge": true,
"disablePolicyRefs": false,
"purgeIsOn": false,
"purgeKey": "",
"stale": null,
"cacheRefs": [
{
"id": 0,
"isOn": true,
"key": "${scheme}://${host}${requestPath}${isArgs}${args}",
"life": {"count": 2, "unit": "hour"},
"status": [200],
"maxSize": {"count": 32, "unit": "mb"},
"minSize": {"count": 0, "unit": "kb"},
"skipCacheControlValues": ["private", "no-cache", "no-store"],
"skipSetCookie": true,
"enableRequestCachePragma": false,
"conds": {
"isOn": true,
"connector": "or",
"groups": [
{
"isOn": true,
"connector": "and",
"conds": [
{
"type": "url-extension",
"isRequest": true,
"param": "${requestPathLowerExtension}",
"operator": "in",
"value": "[\".css\",\".png\",\".js\",\".woff2\"]",
"isReverse": false,
"isCaseInsensitive": false,
"typeName": "URL扩展名"
}
],
"isReverse": false,
"description": ""
}
]
},
"allowChunkedEncoding": true,
"allowPartialContent": false,
"isReverse": false,
"methods": []
}
]
}
~~~

View File

@@ -0,0 +1,91 @@
# 缓存条件设置
## 定义
~~~json
{
"isOn": "是否启用配置",
"key": "每个缓存的Key规则里面可以有变量",
"life": "缓存时长",
"expiresTime": "客户端过期时间",
"status": ["缓存的状态码1", "缓存的状态码2", ...],
"minSize": "能够缓存的最小尺寸",
"maxSize": "能够缓存的最大尺寸",
"methods": ["支持的请求方法1", "支持的请求方法2", ...],
"skipCacheControlValues": "可以跳过的响应的Cache-Control值",
"skipSetCookie": "是否跳过响应的Set-Cookie Header",
"enableRequestCachePragma": "是否支持客户端的Pragma: no-cache",
"allowChunkedEncoding": "是否允许分片内容",
"allowPartialContent": "支持分段内容缓存",
"conds": "请求条件",
"isReverse": "是否为反向条件,反向条件的不缓存"
}
~~~
## 示例
~~~json
{
"isOn": true,
"key": "${scheme}://${host}${requestURI}",
"life": {
"count": 1,
"unit": "day"
},
"expiresTime": {
"isPrior": true,
"isOn": true,
"overwrite": true,
"autoCalculate": false,
"duration": {
"count": 1,
"unit": "day"
}
},
"status": [
200
],
"minSize": {
"count": 0,
"unit": "kb"
},
"maxSize": {
"count": 32,
"unit": "mb"
},
"methods": [],
"skipCacheControlValues": [
"private",
"no-cache",
"no-store"
],
"skipSetCookie": true,
"enableRequestCachePragma": false,
"allowChunkedEncoding": true,
"allowPartialContent": false,
"conds": {
"isOn": true,
"connector": "or",
"groups": [
{
"isOn": true,
"connector": "and",
"conds": [
{
"type": "url-extension",
"isRequest": true,
"param": "${requestPathLowerExtension}",
"operator": "in",
"value": "[\".css\",\".png\",\".js\",\".woff2\"]",
"isReverse": false,
"isCaseInsensitive": false,
"typeName": "URL扩展名"
}
],
"isReverse": false,
"description": ""
}
]
},
"cachePolicy": null,
"isReverse": false,
"id": 1
}
~~~

View File

@@ -0,0 +1,18 @@
# HTTP防火墙即WAF引用
## 定义
~~~json
{
"isPrior": "是否覆盖上级配置",
"isOn": "是否启用配置",
"firewallPolicyId": "WAF策略ID"
}
~~~
## 示例
~~~json
{
"isPrior": true,
"isOn": true,
"firewallPolicyId": 123
}
~~~

View File

@@ -0,0 +1,49 @@
# HTTP协议配置
## 定义
~~~json
{
"isOn": "是否启用",
"listen": [
{
"protocol": "协议",
"host": "主机地址,通常为空",
"portRange": "端口或者端口范围"
},
...
]
}
~~~
## 示例
### 监听80端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "http",
"host": "",
"portRange": "80"
}
]
}
~~~
### 监听80和8080端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "http",
"portRange": "80"
},
{
"protocol": "http",
"portRange": "8080"
}
]
}
~~~

View File

@@ -0,0 +1,31 @@
# HTTP获取客户端IP地址方式配置
## 定义
~~~json
{
"isPrior": "是否覆盖父级应用",
"isOn": "是否启用配置",
"value": "自定义值变量",
"isCustomized": "是否自定义"
}
~~~
## 示例
### 不启用自定义
~~~json
{
"isPrior": false,
"isOn": false,
"value": "",
"isCustomized": false
}
~~~
### 启用自定义
~~~json
{
"isPrior": true,
"isOn": true,
"value": "${remoteAddr}",
"isCustomized": true
}
~~~

View File

@@ -0,0 +1,16 @@
# 统计引用
## 定义
~~~json
{
"isPrior": "是否覆盖父级配置",
"isOn": "是否启用配置"
}
~~~
## 示例
~~~json
{
"isPrior": true,
"isOn": true
}
~~~

View File

@@ -0,0 +1,21 @@
# WebSocket引用
## 定义
~~~json
{
"isPrior": "是否覆盖上级配置true|false",
"isOn": "是否启用true|false",
"websocketId": "Websocket配置ID"
}
~~~
其中:
* `Websocket配置ID` - 需要调用 `HTTPWebsocketService.CreateHTTPWebsocketRequest()` 生成
## 示例
~~~json
{
"isPrior": true,
"isOn": true,
"websocketId": 123
}
~~~

View File

@@ -0,0 +1,67 @@
# HTTPS协议配置
## 定义
~~~json
{
"isOn": "是否启用",
"listen": [
{
"protocol": "协议",
"host": "主机地址,通常为空",
"portRange": "端口或者端口范围"
},
...
],
"sslPolicyRef": {
"isOn": "启用SSL策略",
"sslPolicyId": "SSL策略ID"
}
}
~~~
其中 `SSL策略ID` 通过 `/SSLPolicyService/createSSLPolicy` 接口创建。
## 示例
### 监听443端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "https",
"host": "",
"portRange": "443"
}
],
"sslPolicyRef": {
"isOn": true,
"sslPolicyId": 123
}
}
~~~
其中SSL策略ID `123` 通过 `/SSLPolicyService/createSSLPolicy` 接口创建。
### 监听443和8443端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "https",
"portRange": "443"
},
{
"protocol": "https",
"portRange": "8443"
}
],
"sslPolicyRef": {
"isOn": true,
"sslPolicyId": 123
}
}
~~~
其中SSL策略ID `123` 通过 `/SSLPolicyService/createSSLPolicy` 接口创建。

View File

@@ -0,0 +1,33 @@
# 源站引用列表
## 定义
~~~json
[
{
"isOn": "是否启用",
"originId": "源站ID 1"
},
{
"isOn": "是否启用",
"originId": "源站ID 2"
},
...
]
~~~
其中:
* `originId` - 源站ID可以通过 `/OriginService/createOrigin` 接口创建源站后获得
## 示例
~~~json
[
{
"isOn": true,
"originId": 1
},
{
"isOn": true,
"originId": 2,
}
]
~~~

View File

@@ -0,0 +1,19 @@
# 反向代理引用
## 定义
~~~json
{
"isOn": "是否启用",
"isPrior": "是否覆盖上级配置,用于路由规则",
"reverseProxyId": "反向代理ID"
}
~~~
其中:
* `reverseProxyId` - 反向代理ID可以通过 `/ReverseProxyService/createReverseProxy` 创建
## 示例
~~~json
{
"isOn": true,
"reverseProxyId": 123
}
~~~

View File

@@ -0,0 +1,27 @@
# 反向代理调度
## 定义
~~~json
{
"code": "调度方法代号",
"options": "调度选项"
}
~~~
其中:
* `code` 调度方法代号
* `random` - 随机
* `roundRobin` - 轮询
* `hash` - Hash算法
* `key` - 自定义Key可以使用请求变量比如 `${remoteAddr}`
* `sticky` - Sticky算法
* `type` - 类型cookie、header、argument
* `param` - 参数值
## 示例
~~~json
{
"code": "random",
"options": null
}
~~~

View File

@@ -0,0 +1,9 @@
# 域名信息
## 示例
~~~json
{
"name": "example.com",
"type": "full"
}
~~~

View File

@@ -0,0 +1,48 @@
# 域名信息列表
## 定义
~~~
[ 域名信息1, 域名信息2, ... ]
~~~
其中 `域名信息N` 等是单个域名信息定义,具体请参考 {json:server_name}
## 示例
### 示例1单个域名
~~~json
[
{
"name": "example.com",
"type": "full"
}
]
~~~
### 示例2多个域名
~~~json
[
{
"name": "example.com",
"type": "full"
},
{
"name": "google.com",
"type": "full"
},
{
"name": "facebook.com",
"type": "full"
}
]
~~~
### 示例3域名合集
域名合集效果跟多个域名是一样的,只不过在界面上以一个目录的形式呈现。
~~~json
[
{
"name": "",
"type": "full",
"subNames": ["example.com", "google.com", "facebook.com"]
}
]
~~~

View File

@@ -0,0 +1,35 @@
# SSL证书引用
可以用来引用一组证书。
## 定义
~~~json
[
{
"isOn": "是否启用",
"certId": "证书ID 1"
},
{
"isOn": "是否启用",
"certId": "证书ID 2"
},
...
]
~~~
## 示例
~~~json
[
{
"isOn": true,
"certId": 12345
},
{
"isOn": true,
"certId": 12346
}
]
~~~
其中:
* `certId` - 证书的ID

View File

@@ -0,0 +1,63 @@
# TCP协议配置
## 定义
~~~json
{
"isOn": "是否启用",
"listen": [
{
"protocol": "协议",
"host": "主机地址,通常为空",
"portRange": "端口或者端口范围"
},
...
]
}
~~~
## 示例
### 监听1234端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "tcp",
"host": "",
"portRange": "1234"
}
]
}
~~~
### 监听1234和2345端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "tcp",
"portRange": "1234"
},
{
"protocol": "tcp",
"portRange": "2345"
}
]
}
~~~
### 监听1234到1240之间的所有端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "tcp",
"host": "",
"portRange": "1234-1240"
}
]
}
~~~

View File

@@ -0,0 +1,68 @@
# TLS协议配置
## 定义
~~~json
{
"isOn": "是否启用",
"listen": [
{
"protocol": "协议",
"host": "主机地址,通常为空",
"portRange": "端口或者端口范围"
},
...
],
"sslPolicyRef": {
"isOn": "启用SSL策略",
"sslPolicyId": "SSL策略ID"
}
}
~~~
其中 `SSL策略ID` 通过 `/SSLPolicyService/createSSLPolicy` 接口创建。
## 示例
### 监听8443端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "tls",
"host": "",
"portRange": "8443"
}
],
"sslPolicyRef": {
"isOn": true,
"sslPolicyId": 123
}
}
~~~
其中SSL策略ID `123` 通过 `/SSLPolicyService/createSSLPolicy` 接口创建。
### 监听8443和8543端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "tls",
"portRange": "8443"
},
{
"protocol": "tls",
"portRange": "8543"
}
],
"sslPolicyRef": {
"isOn": true,
"sslPolicyId": 123
}
}
~~~
其中SSL策略ID `123` 通过 `/SSLPolicyService/createSSLPolicy` 接口创建。

View File

@@ -0,0 +1,63 @@
# UDP协议配置
## 定义
~~~json
{
"isOn": "是否启用",
"listen": [
{
"protocol": "协议",
"host": "主机地址,通常为空",
"portRange": "端口或者端口范围"
},
...
]
}
~~~
## 示例
### 监听1234端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "udp",
"host": "",
"portRange": "1234"
}
]
}
~~~
### 监听1234和2345端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "udp",
"portRange": "1234"
},
{
"protocol": "udp",
"portRange": "2345"
}
]
}
~~~
### 监听1234到1240之间的所有端口
~~~json
{
"isOn": true,
"listen": [
{
"protocol": "udp",
"host": "",
"portRange": "1234-1240"
}
]
}
~~~

View File

@@ -0,0 +1,176 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.19.4
// source: models/model_ad_network.proto
package pb
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// 高防线路
type ADNetwork struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
IsOn bool `protobuf:"varint,2,opt,name=isOn,proto3" json:"isOn,omitempty"`
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
}
func (x *ADNetwork) Reset() {
*x = ADNetwork{}
if protoimpl.UnsafeEnabled {
mi := &file_models_model_ad_network_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ADNetwork) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ADNetwork) ProtoMessage() {}
func (x *ADNetwork) ProtoReflect() protoreflect.Message {
mi := &file_models_model_ad_network_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ADNetwork.ProtoReflect.Descriptor instead.
func (*ADNetwork) Descriptor() ([]byte, []int) {
return file_models_model_ad_network_proto_rawDescGZIP(), []int{0}
}
func (x *ADNetwork) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *ADNetwork) GetIsOn() bool {
if x != nil {
return x.IsOn
}
return false
}
func (x *ADNetwork) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *ADNetwork) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
var File_models_model_ad_network_proto protoreflect.FileDescriptor
var file_models_model_ad_network_proto_rawDesc = []byte{
0x0a, 0x1d, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x61,
0x64, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x02, 0x70, 0x62, 0x22, 0x65, 0x0a, 0x09, 0x41, 0x44, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64,
0x12, 0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04,
0x69, 0x73, 0x4f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f,
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_models_model_ad_network_proto_rawDescOnce sync.Once
file_models_model_ad_network_proto_rawDescData = file_models_model_ad_network_proto_rawDesc
)
func file_models_model_ad_network_proto_rawDescGZIP() []byte {
file_models_model_ad_network_proto_rawDescOnce.Do(func() {
file_models_model_ad_network_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_model_ad_network_proto_rawDescData)
})
return file_models_model_ad_network_proto_rawDescData
}
var file_models_model_ad_network_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_models_model_ad_network_proto_goTypes = []interface{}{
(*ADNetwork)(nil), // 0: pb.ADNetwork
}
var file_models_model_ad_network_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_models_model_ad_network_proto_init() }
func file_models_model_ad_network_proto_init() {
if File_models_model_ad_network_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_models_model_ad_network_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ADNetwork); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_models_model_ad_network_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_models_model_ad_network_proto_goTypes,
DependencyIndexes: file_models_model_ad_network_proto_depIdxs,
MessageInfos: file_models_model_ad_network_proto_msgTypes,
}.Build()
File_models_model_ad_network_proto = out.File
file_models_model_ad_network_proto_rawDesc = nil
file_models_model_ad_network_proto_goTypes = nil
file_models_model_ad_network_proto_depIdxs = nil
}

View File

@@ -0,0 +1,250 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.19.4
// source: models/model_ad_package.proto
package pb
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// 高防产品
type ADPackage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
IsOn bool `protobuf:"varint,2,opt,name=isOn,proto3" json:"isOn,omitempty"`
AdNetworkId int64 `protobuf:"varint,3,opt,name=adNetworkId,proto3" json:"adNetworkId,omitempty"`
ProtectionBandwidthSize int32 `protobuf:"varint,4,opt,name=protectionBandwidthSize,proto3" json:"protectionBandwidthSize,omitempty"`
ProtectionBandwidthUnit string `protobuf:"bytes,5,opt,name=protectionBandwidthUnit,proto3" json:"protectionBandwidthUnit,omitempty"`
ServerBandwidthSize int32 `protobuf:"varint,6,opt,name=serverBandwidthSize,proto3" json:"serverBandwidthSize,omitempty"`
ServerBandwidthUnit string `protobuf:"bytes,7,opt,name=serverBandwidthUnit,proto3" json:"serverBandwidthUnit,omitempty"`
AdNetwork *ADNetwork `protobuf:"bytes,30,opt,name=adNetwork,proto3" json:"adNetwork,omitempty"`
Summary string `protobuf:"bytes,31,opt,name=summary,proto3" json:"summary,omitempty"` // 概述
CountIdleADPackageInstances int64 `protobuf:"varint,32,opt,name=countIdleADPackageInstances,proto3" json:"countIdleADPackageInstances,omitempty"` // 剩余可用的实例数,只有在获取可用高防产品的时候才会返回
}
func (x *ADPackage) Reset() {
*x = ADPackage{}
if protoimpl.UnsafeEnabled {
mi := &file_models_model_ad_package_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ADPackage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ADPackage) ProtoMessage() {}
func (x *ADPackage) ProtoReflect() protoreflect.Message {
mi := &file_models_model_ad_package_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ADPackage.ProtoReflect.Descriptor instead.
func (*ADPackage) Descriptor() ([]byte, []int) {
return file_models_model_ad_package_proto_rawDescGZIP(), []int{0}
}
func (x *ADPackage) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *ADPackage) GetIsOn() bool {
if x != nil {
return x.IsOn
}
return false
}
func (x *ADPackage) GetAdNetworkId() int64 {
if x != nil {
return x.AdNetworkId
}
return 0
}
func (x *ADPackage) GetProtectionBandwidthSize() int32 {
if x != nil {
return x.ProtectionBandwidthSize
}
return 0
}
func (x *ADPackage) GetProtectionBandwidthUnit() string {
if x != nil {
return x.ProtectionBandwidthUnit
}
return ""
}
func (x *ADPackage) GetServerBandwidthSize() int32 {
if x != nil {
return x.ServerBandwidthSize
}
return 0
}
func (x *ADPackage) GetServerBandwidthUnit() string {
if x != nil {
return x.ServerBandwidthUnit
}
return ""
}
func (x *ADPackage) GetAdNetwork() *ADNetwork {
if x != nil {
return x.AdNetwork
}
return nil
}
func (x *ADPackage) GetSummary() string {
if x != nil {
return x.Summary
}
return ""
}
func (x *ADPackage) GetCountIdleADPackageInstances() int64 {
if x != nil {
return x.CountIdleADPackageInstances
}
return 0
}
var File_models_model_ad_package_proto protoreflect.FileDescriptor
var file_models_model_ad_package_proto_rawDesc = []byte{
0x0a, 0x1d, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x61,
0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x02, 0x70, 0x62, 0x1a, 0x1d, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65,
0x6c, 0x5f, 0x61, 0x64, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0xb2, 0x03, 0x0a, 0x09, 0x41, 0x44, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64,
0x12, 0x12, 0x0a, 0x04, 0x69, 0x73, 0x4f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04,
0x69, 0x73, 0x4f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x64, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x64, 0x4e, 0x65, 0x74,
0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x53, 0x69, 0x7a,
0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x53, 0x69, 0x7a, 0x65,
0x12, 0x38, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61,
0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
0x09, 0x52, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x61, 0x6e,
0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x53, 0x69, 0x7a,
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42,
0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x30, 0x0a, 0x13,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55,
0x6e, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x2b,
0x0a, 0x09, 0x61, 0x64, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x1e, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x44, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x52, 0x09, 0x61, 0x64, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x73,
0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75,
0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x40, 0x0a, 0x1b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64,
0x6c, 0x65, 0x41, 0x44, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x03, 0x52, 0x1b, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x49, 0x64, 0x6c, 0x65, 0x41, 0x44, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x6e,
0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_models_model_ad_package_proto_rawDescOnce sync.Once
file_models_model_ad_package_proto_rawDescData = file_models_model_ad_package_proto_rawDesc
)
func file_models_model_ad_package_proto_rawDescGZIP() []byte {
file_models_model_ad_package_proto_rawDescOnce.Do(func() {
file_models_model_ad_package_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_model_ad_package_proto_rawDescData)
})
return file_models_model_ad_package_proto_rawDescData
}
var file_models_model_ad_package_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_models_model_ad_package_proto_goTypes = []interface{}{
(*ADPackage)(nil), // 0: pb.ADPackage
(*ADNetwork)(nil), // 1: pb.ADNetwork
}
var file_models_model_ad_package_proto_depIdxs = []int32{
1, // 0: pb.ADPackage.adNetwork:type_name -> pb.ADNetwork
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_models_model_ad_package_proto_init() }
func file_models_model_ad_package_proto_init() {
if File_models_model_ad_package_proto != nil {
return
}
file_models_model_ad_network_proto_init()
if !protoimpl.UnsafeEnabled {
file_models_model_ad_package_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ADPackage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_models_model_ad_package_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_models_model_ad_package_proto_goTypes,
DependencyIndexes: file_models_model_ad_package_proto_depIdxs,
MessageInfos: file_models_model_ad_package_proto_msgTypes,
}.Build()
File_models_model_ad_package_proto = out.File
file_models_model_ad_package_proto_rawDesc = nil
file_models_model_ad_package_proto_goTypes = nil
file_models_model_ad_package_proto_depIdxs = nil
}

View File

@@ -0,0 +1,274 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.19.4
// source: models/model_ad_package_instance.proto
package pb
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// 高防产品实例
type ADPackageInstance struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
IsOn bool `protobuf:"varint,2,opt,name=isOn,proto3" json:"isOn,omitempty"`
AdPackageId int64 `protobuf:"varint,3,opt,name=adPackageId,proto3" json:"adPackageId,omitempty"`
NodeClusterId int64 `protobuf:"varint,4,opt,name=nodeClusterId,proto3" json:"nodeClusterId,omitempty"`
NodeIds []int64 `protobuf:"varint,5,rep,packed,name=nodeIds,proto3" json:"nodeIds,omitempty"`
IpAddresses []string `protobuf:"bytes,6,rep,name=ipAddresses,proto3" json:"ipAddresses,omitempty"`
UserId int64 `protobuf:"varint,7,opt,name=userId,proto3" json:"userId,omitempty"` // 租用用户ID
UserDayTo string `protobuf:"bytes,8,opt,name=userDayTo,proto3" json:"userDayTo,omitempty"` // 租用日期
UserInstanceId int64 `protobuf:"varint,9,opt,name=userInstanceId,proto3" json:"userInstanceId,omitempty"` // 当前绑定的用户实例ID
NodeCluster *NodeCluster `protobuf:"bytes,30,opt,name=nodeCluster,proto3" json:"nodeCluster,omitempty"`
AdPackage *ADPackage `protobuf:"bytes,31,opt,name=adPackage,proto3" json:"adPackage,omitempty"`
User *User `protobuf:"bytes,32,opt,name=user,proto3" json:"user,omitempty"`
}
func (x *ADPackageInstance) Reset() {
*x = ADPackageInstance{}
if protoimpl.UnsafeEnabled {
mi := &file_models_model_ad_package_instance_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ADPackageInstance) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ADPackageInstance) ProtoMessage() {}
func (x *ADPackageInstance) ProtoReflect() protoreflect.Message {
mi := &file_models_model_ad_package_instance_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ADPackageInstance.ProtoReflect.Descriptor instead.
func (*ADPackageInstance) Descriptor() ([]byte, []int) {
return file_models_model_ad_package_instance_proto_rawDescGZIP(), []int{0}
}
func (x *ADPackageInstance) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *ADPackageInstance) GetIsOn() bool {
if x != nil {
return x.IsOn
}
return false
}
func (x *ADPackageInstance) GetAdPackageId() int64 {
if x != nil {
return x.AdPackageId
}
return 0
}
func (x *ADPackageInstance) GetNodeClusterId() int64 {
if x != nil {
return x.NodeClusterId
}
return 0
}
func (x *ADPackageInstance) GetNodeIds() []int64 {
if x != nil {
return x.NodeIds
}
return nil
}
func (x *ADPackageInstance) GetIpAddresses() []string {
if x != nil {
return x.IpAddresses
}
return nil
}
func (x *ADPackageInstance) GetUserId() int64 {
if x != nil {
return x.UserId
}
return 0
}
func (x *ADPackageInstance) GetUserDayTo() string {
if x != nil {
return x.UserDayTo
}
return ""
}
func (x *ADPackageInstance) GetUserInstanceId() int64 {
if x != nil {
return x.UserInstanceId
}
return 0
}
func (x *ADPackageInstance) GetNodeCluster() *NodeCluster {
if x != nil {
return x.NodeCluster
}
return nil
}
func (x *ADPackageInstance) GetAdPackage() *ADPackage {
if x != nil {
return x.AdPackage
}
return nil
}
func (x *ADPackageInstance) GetUser() *User {
if x != nil {
return x.User
}
return nil
}
var File_models_model_ad_package_instance_proto protoreflect.FileDescriptor
var file_models_model_ad_package_instance_proto_rawDesc = []byte{
0x0a, 0x26, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x61,
0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x1f, 0x6d, 0x6f,
0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f,
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x6d,
0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x61, 0x64, 0x5f, 0x70,
0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x6d, 0x6f,
0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x97, 0x03, 0x0a, 0x11, 0x41, 0x44, 0x50, 0x61, 0x63, 0x6b,
0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x69,
0x73, 0x4f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69, 0x73, 0x4f, 0x6e, 0x12,
0x20, 0x0a, 0x0b, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x64, 0x18, 0x03,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49,
0x64, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6c,
0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49,
0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64,
0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73,
0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x07, 0x20,
0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75,
0x73, 0x65, 0x72, 0x44, 0x61, 0x79, 0x54, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x75, 0x73, 0x65, 0x72, 0x44, 0x61, 0x79, 0x54, 0x6f, 0x12, 0x26, 0x0a, 0x0e, 0x75, 0x73, 0x65,
0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28,
0x03, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49,
0x64, 0x12, 0x31, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65,
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x09, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67,
0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x44, 0x50,
0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67,
0x65, 0x12, 0x1c, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x08, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42,
0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_models_model_ad_package_instance_proto_rawDescOnce sync.Once
file_models_model_ad_package_instance_proto_rawDescData = file_models_model_ad_package_instance_proto_rawDesc
)
func file_models_model_ad_package_instance_proto_rawDescGZIP() []byte {
file_models_model_ad_package_instance_proto_rawDescOnce.Do(func() {
file_models_model_ad_package_instance_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_model_ad_package_instance_proto_rawDescData)
})
return file_models_model_ad_package_instance_proto_rawDescData
}
var file_models_model_ad_package_instance_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_models_model_ad_package_instance_proto_goTypes = []interface{}{
(*ADPackageInstance)(nil), // 0: pb.ADPackageInstance
(*NodeCluster)(nil), // 1: pb.NodeCluster
(*ADPackage)(nil), // 2: pb.ADPackage
(*User)(nil), // 3: pb.User
}
var file_models_model_ad_package_instance_proto_depIdxs = []int32{
1, // 0: pb.ADPackageInstance.nodeCluster:type_name -> pb.NodeCluster
2, // 1: pb.ADPackageInstance.adPackage:type_name -> pb.ADPackage
3, // 2: pb.ADPackageInstance.user:type_name -> pb.User
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_models_model_ad_package_instance_proto_init() }
func file_models_model_ad_package_instance_proto_init() {
if File_models_model_ad_package_instance_proto != nil {
return
}
file_models_model_node_cluster_proto_init()
file_models_model_ad_package_proto_init()
file_models_model_user_proto_init()
if !protoimpl.UnsafeEnabled {
file_models_model_ad_package_instance_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ADPackageInstance); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_models_model_ad_package_instance_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_models_model_ad_package_instance_proto_goTypes,
DependencyIndexes: file_models_model_ad_package_instance_proto_depIdxs,
MessageInfos: file_models_model_ad_package_instance_proto_msgTypes,
}.Build()
File_models_model_ad_package_instance_proto = out.File
file_models_model_ad_package_instance_proto_rawDesc = nil
file_models_model_ad_package_instance_proto_goTypes = nil
file_models_model_ad_package_instance_proto_depIdxs = nil
}

View File

@@ -0,0 +1,186 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.19.4
// source: models/model_ad_package_period.proto
package pb
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// 高防实例有效期
type ADPackagePeriod struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
IsOn bool `protobuf:"varint,2,opt,name=isOn,proto3" json:"isOn,omitempty"`
Count int32 `protobuf:"varint,3,opt,name=count,proto3" json:"count,omitempty"`
Unit string `protobuf:"bytes,4,opt,name=unit,proto3" json:"unit,omitempty"`
Months int32 `protobuf:"varint,5,opt,name=months,proto3" json:"months,omitempty"`
}
func (x *ADPackagePeriod) Reset() {
*x = ADPackagePeriod{}
if protoimpl.UnsafeEnabled {
mi := &file_models_model_ad_package_period_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ADPackagePeriod) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ADPackagePeriod) ProtoMessage() {}
func (x *ADPackagePeriod) ProtoReflect() protoreflect.Message {
mi := &file_models_model_ad_package_period_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ADPackagePeriod.ProtoReflect.Descriptor instead.
func (*ADPackagePeriod) Descriptor() ([]byte, []int) {
return file_models_model_ad_package_period_proto_rawDescGZIP(), []int{0}
}
func (x *ADPackagePeriod) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *ADPackagePeriod) GetIsOn() bool {
if x != nil {
return x.IsOn
}
return false
}
func (x *ADPackagePeriod) GetCount() int32 {
if x != nil {
return x.Count
}
return 0
}
func (x *ADPackagePeriod) GetUnit() string {
if x != nil {
return x.Unit
}
return ""
}
func (x *ADPackagePeriod) GetMonths() int32 {
if x != nil {
return x.Months
}
return 0
}
var File_models_model_ad_package_period_proto protoreflect.FileDescriptor
var file_models_model_ad_package_period_proto_rawDesc = []byte{
0x0a, 0x24, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x61,
0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x77, 0x0a, 0x0f, 0x41, 0x44,
0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a,
0x04, 0x69, 0x73, 0x4f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x69, 0x73, 0x4f,
0x6e, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d,
0x6f, 0x6e, 0x74, 0x68, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6d, 0x6f, 0x6e,
0x74, 0x68, 0x73, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (
file_models_model_ad_package_period_proto_rawDescOnce sync.Once
file_models_model_ad_package_period_proto_rawDescData = file_models_model_ad_package_period_proto_rawDesc
)
func file_models_model_ad_package_period_proto_rawDescGZIP() []byte {
file_models_model_ad_package_period_proto_rawDescOnce.Do(func() {
file_models_model_ad_package_period_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_model_ad_package_period_proto_rawDescData)
})
return file_models_model_ad_package_period_proto_rawDescData
}
var file_models_model_ad_package_period_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_models_model_ad_package_period_proto_goTypes = []interface{}{
(*ADPackagePeriod)(nil), // 0: pb.ADPackagePeriod
}
var file_models_model_ad_package_period_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_models_model_ad_package_period_proto_init() }
func file_models_model_ad_package_period_proto_init() {
if File_models_model_ad_package_period_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_models_model_ad_package_period_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ADPackagePeriod); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_models_model_ad_package_period_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_models_model_ad_package_period_proto_goTypes,
DependencyIndexes: file_models_model_ad_package_period_proto_depIdxs,
MessageInfos: file_models_model_ad_package_period_proto_msgTypes,
}.Build()
File_models_model_ad_package_period_proto = out.File
file_models_model_ad_package_period_proto_rawDesc = nil
file_models_model_ad_package_period_proto_goTypes = nil
file_models_model_ad_package_period_proto_depIdxs = nil
}

View File

@@ -0,0 +1,170 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.19.4
// source: models/model_ad_package_price.proto
package pb
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// 高防产品价格定义
type ADPackagePrice struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AdPackageId int64 `protobuf:"varint,1,opt,name=adPackageId,proto3" json:"adPackageId,omitempty"`
AdPackagePeriodId int64 `protobuf:"varint,2,opt,name=adPackagePeriodId,proto3" json:"adPackagePeriodId,omitempty"`
Price float64 `protobuf:"fixed64,3,opt,name=price,proto3" json:"price,omitempty"`
}
func (x *ADPackagePrice) Reset() {
*x = ADPackagePrice{}
if protoimpl.UnsafeEnabled {
mi := &file_models_model_ad_package_price_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ADPackagePrice) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ADPackagePrice) ProtoMessage() {}
func (x *ADPackagePrice) ProtoReflect() protoreflect.Message {
mi := &file_models_model_ad_package_price_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ADPackagePrice.ProtoReflect.Descriptor instead.
func (*ADPackagePrice) Descriptor() ([]byte, []int) {
return file_models_model_ad_package_price_proto_rawDescGZIP(), []int{0}
}
func (x *ADPackagePrice) GetAdPackageId() int64 {
if x != nil {
return x.AdPackageId
}
return 0
}
func (x *ADPackagePrice) GetAdPackagePeriodId() int64 {
if x != nil {
return x.AdPackagePeriodId
}
return 0
}
func (x *ADPackagePrice) GetPrice() float64 {
if x != nil {
return x.Price
}
return 0
}
var File_models_model_ad_package_price_proto protoreflect.FileDescriptor
var file_models_model_ad_package_price_proto_rawDesc = []byte{
0x0a, 0x23, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x61,
0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x76, 0x0a, 0x0e, 0x41, 0x44, 0x50,
0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61,
0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0b, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a,
0x11, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64,
0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x61, 0x64, 0x50, 0x61, 0x63, 0x6b,
0x61, 0x67, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70,
0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63,
0x65, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_models_model_ad_package_price_proto_rawDescOnce sync.Once
file_models_model_ad_package_price_proto_rawDescData = file_models_model_ad_package_price_proto_rawDesc
)
func file_models_model_ad_package_price_proto_rawDescGZIP() []byte {
file_models_model_ad_package_price_proto_rawDescOnce.Do(func() {
file_models_model_ad_package_price_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_model_ad_package_price_proto_rawDescData)
})
return file_models_model_ad_package_price_proto_rawDescData
}
var file_models_model_ad_package_price_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_models_model_ad_package_price_proto_goTypes = []interface{}{
(*ADPackagePrice)(nil), // 0: pb.ADPackagePrice
}
var file_models_model_ad_package_price_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_models_model_ad_package_price_proto_init() }
func file_models_model_ad_package_price_proto_init() {
if File_models_model_ad_package_price_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_models_model_ad_package_price_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ADPackagePrice); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_models_model_ad_package_price_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_models_model_ad_package_price_proto_goTypes,
DependencyIndexes: file_models_model_ad_package_price_proto_depIdxs,
MessageInfos: file_models_model_ad_package_price_proto_msgTypes,
}.Build()
File_models_model_ad_package_price_proto = out.File
file_models_model_ad_package_price_proto_rawDesc = nil
file_models_model_ad_package_price_proto_goTypes = nil
file_models_model_ad_package_price_proto_depIdxs = nil
}

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