Showing preview only (2,984K chars total). Download the full file or copy to clipboard to get everything.
Repository: gdy666/lucky
Branch: master
Commit: b4cf9edc9d8f
Files: 186
Total size: 2.8 MB
Directory structure:
gitextract_wc7gf33_/
├── .gitattributes
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── berforebuild.bat
├── config/
│ ├── appinfo.go
│ ├── blacklist.go
│ ├── config.go
│ ├── ddns.go
│ ├── portforward.go
│ ├── reverseproxy.go
│ ├── safecheck.go
│ ├── sslcertficate.go
│ ├── whitelist.go
│ └── wol.go
├── ddns/
│ ├── alidns.go
│ ├── baidu.go
│ ├── callback.go
│ ├── cloudflare.go
│ ├── dns.go
│ ├── dnscommon.go
│ ├── dnspod.go
│ ├── godaddy.go
│ ├── huawei.go
│ ├── porkbun.go
│ └── worker.go
├── ddnscore.go/
│ ├── cache.go
│ ├── domain.go
│ ├── taskinfo.go
│ ├── taskstate.go
│ └── webhook.go
├── debug.go
├── go.mod
├── go.sum
├── goports
├── main.go
├── module/
│ ├── ddns/
│ │ ├── conf/
│ │ │ └── ddns.go
│ │ ├── ddnscore.go/
│ │ │ ├── cache.go
│ │ │ ├── domain.go
│ │ │ ├── taskinfo.go
│ │ │ ├── taskstate.go
│ │ │ └── webhook.go
│ │ ├── ddnsgo/
│ │ │ └── ddns.go
│ │ ├── providers/
│ │ │ ├── alidns.go
│ │ │ ├── baidu.go
│ │ │ ├── callback.go
│ │ │ ├── cloudflare.go
│ │ │ ├── dnspod.go
│ │ │ ├── godaddy.go
│ │ │ ├── huawei.go
│ │ │ ├── porkbun.go
│ │ │ ├── provider.go
│ │ │ └── providercommon.go
│ │ └── worker.go
│ ├── portforward/
│ │ ├── conf/
│ │ │ └── portforward.go
│ │ ├── portforward.go
│ │ └── socketproxy/
│ │ ├── baseproxyconf.go
│ │ ├── proxy.go
│ │ ├── socketproxy.go
│ │ ├── tcpproxy.go
│ │ ├── tcpudpcommon.go
│ │ └── udpproxy.go
│ ├── reverseproxy/
│ │ ├── conf/
│ │ │ └── reverseproxy.go
│ │ ├── proxy.go
│ │ └── reverseproxy.go
│ ├── safe/
│ │ ├── blacklist.go
│ │ ├── conf/
│ │ │ ├── black.go
│ │ │ └── white.go
│ │ ├── safe.go
│ │ ├── safecheck.go
│ │ └── whitelist.go
│ ├── service/
│ │ └── service.go
│ ├── sslcertficate/
│ │ ├── conf/
│ │ │ └── sslconf.go
│ │ ├── ssl.go
│ │ └── sslcertficate.go
│ ├── weblog/
│ │ └── weblog.go
│ └── wol/
│ ├── client.go
│ ├── conf/
│ │ ├── device.go
│ │ └── service.go
│ ├── ctl.go
│ ├── device.go
│ ├── httpapi/
│ │ └── api.go
│ ├── module.go
│ ├── msg.go
│ ├── service.go
│ └── websocketcommon.go
├── reverseproxy/
│ └── proxy.go
├── scripts/
│ ├── lucky.service
│ ├── luckyservice
│ └── misnap_init.sh
├── socketproxy/
│ ├── baseproxyconf.go
│ ├── proxy.go
│ ├── tcpproxy.go
│ ├── tcpudpcommon.go
│ └── udpproxy.go
├── thirdlib/
│ ├── fatedier/
│ │ └── golib/
│ │ └── json/
│ │ ├── msg.go
│ │ ├── pack.go
│ │ └── process.go
│ ├── gdylib/
│ │ ├── bemfa/
│ │ │ ├── device.go
│ │ │ └── global.go
│ │ ├── blinker/
│ │ │ ├── VoiceAssistant.go
│ │ │ ├── device.go
│ │ │ └── global.go
│ │ ├── dnsutils/
│ │ │ └── resolve.go
│ │ ├── fileutils/
│ │ │ ├── fileutils.go
│ │ │ ├── run_linux.go
│ │ │ └── run_windows.go
│ │ ├── ginutils/
│ │ │ ├── basicAuth.go
│ │ │ ├── jwt.go
│ │ │ ├── staticFilesHandler.go
│ │ │ └── utils.go
│ │ ├── httputils/
│ │ │ ├── common.go
│ │ │ ├── goututils.go
│ │ │ └── httpclient.go
│ │ ├── logsbuffer/
│ │ │ └── logsbuffer.go
│ │ ├── netinterfaces/
│ │ │ └── netInterface.go
│ │ ├── pool/
│ │ │ └── buf.go
│ │ ├── recoverutil/
│ │ │ └── recoverutil.go
│ │ ├── service/
│ │ │ └── service.go
│ │ ├── slice/
│ │ │ └── options.go
│ │ ├── stderrredirect/
│ │ │ ├── stderrredirect_linux.go
│ │ │ └── stderrredirect_windows.go
│ │ ├── stringsp/
│ │ │ ├── binary.go
│ │ │ ├── randomutils.go
│ │ │ ├── stringsp.go
│ │ │ └── url.go
│ │ └── websocketController/
│ │ └── controller.go
│ ├── go-wol/
│ │ ├── magic_packet.go
│ │ └── wol.go
│ └── jeessy2/
│ └── ddns-go/
│ └── util/
│ ├── aliyun_signer.go
│ ├── aliyun_signer_util.go
│ ├── baidu_signer.go
│ ├── escape.go
│ ├── huawei_signer.go
│ └── net.go
├── web/
│ ├── adminviews/
│ │ ├── .gitignore
│ │ ├── .vscode/
│ │ │ └── extensions.json
│ │ ├── README.md
│ │ ├── auto-imports.d.ts
│ │ ├── components.d.ts
│ │ ├── dist/
│ │ │ ├── assets/
│ │ │ │ ├── index.0c84c960.js
│ │ │ │ ├── index.abda1f8d.css
│ │ │ │ ├── index.e5c8aec2.js
│ │ │ │ └── index.f23c7bd8.css
│ │ │ └── index.html
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.vue
│ │ │ ├── apis/
│ │ │ │ ├── storage.js
│ │ │ │ └── utils.js
│ │ │ ├── assets/
│ │ │ │ ├── appbase.css
│ │ │ │ ├── base.css
│ │ │ │ └── common-layout.scss
│ │ │ ├── components/
│ │ │ │ ├── About.vue
│ │ │ │ ├── BlackLists.vue
│ │ │ │ ├── DDNS.vue
│ │ │ │ ├── DDNSSet.vue
│ │ │ │ ├── Log.vue
│ │ │ │ ├── Login.vue
│ │ │ │ ├── PSet.vue
│ │ │ │ ├── Pmenu.vue
│ │ │ │ ├── PortForward.vue
│ │ │ │ ├── PortForwardSet.vue
│ │ │ │ ├── ReverseProxy.vue
│ │ │ │ ├── SSL.vue
│ │ │ │ ├── Status.vue
│ │ │ │ ├── WhiteListSet.vue
│ │ │ │ ├── WhiteLists.vue
│ │ │ │ └── tools/
│ │ │ │ ├── WOL.vue
│ │ │ │ └── WOLServiceSet.vue
│ │ │ ├── main.js
│ │ │ ├── request/
│ │ │ │ └── index.js
│ │ │ └── utils/
│ │ │ ├── ui.ts
│ │ │ └── utils.ts
│ │ └── vite.config.js
│ ├── blackwhitelist.go
│ ├── common.go
│ ├── configure.go
│ ├── ddns.go
│ ├── portforward.go
│ ├── reverseproxy.go
│ ├── ssl.go
│ ├── web.go
│ └── wol.go
└── web.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.* linguist-language=Go
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
relayports
lucky
# Test binary, built with `go test -c`
*.test
.goreleaser.yaml
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.log
*.upx
*.pem
*.crt
*.key
lucky.conf
# Dependency directories (remove the comment below to include it)
# vendor/
/dist/
config.json
================================================
FILE: Dockerfile
================================================
FROM scratch
COPY lucky /
EXPOSE 16601
WORKDIR /goodluck
ENTRYPOINT ["/lucky"]
CMD ["-c", "/goodluck/lucky.conf"]
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 gdy , 272288813@qq.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Lucky(万吉)
本项目 CDN 加速及安全防护由 Tencent EdgeOne 赞助
[亚洲最佳CDN、边缘和安全解决方案 - Tencent EdgeOne](https://edgeone.ai/zh?from=github)

## 注意:源码公布到1.4.10版本,后续暂无继续开源计划。
## 麻烦各位大佬发表lucky相关教程的时候不要加上“开源”神器,开源二字我不配,lucky后续也没开源打算。
1.开源并不等于安全,闭源并不等于不安全。闭源软件开发也会受到安全人员的审查。无论是开源还是闭源软件,都有可能会受到各种安全人员的审查和研究。安全人员可以使用各种技术手段来检测软件的安全性和漏洞。
2. 个人观点lucky这种应用类软件更多只是体力活,毫无技术含量,开源的优势在于透明度和社区参与,更多劳动力参与,但也可能导致功能过多、复杂度增加的问题。闭源软件的优势在于我想怎么写就怎么写,即使还未能从lucky中获利,lucky对我也有更深的特殊含义。
3. 我对lucky的规划还有一大部分未实现,不想被人当免费劳动力使唤,不解释太多,就这样。
## 如果您是第一次使用Lucky,请务必先访问 https://lucky666.cn ,并仔细阅读相关的文档,以获得必要的信息和答案。在这些文档中,您可以了解到Lucky的基本功能和特性,掌握Lucky的使用方法,以及解决常见的问题和疑惑。
<!-- TOC -->
- [Lucky(万吉)](#)
- [特性](#特性)
- [一键安装](#一键安装)
- [OpenwrtIPK包安装](#OpenwrtIPK包安装)
- [使用](#使用)
- [Docker中使用](#docker中使用)
- [后台界面](#后台界面)
- [开发编译](#开发编译)
- [更新日志](#更新日志)
- [使用注意与常见问题](#使用注意与常见问题)
<!-- /TOC -->
## 特性
Lucky最初是作为一个小工具,由开发者为自己的个人使用而开发,用于替代socat,在小米路由AX6000官方系统上实现公网IPv6转内网IPv4的功能。Lucky的设计始终致力于让更多的Linux嵌入式设备运行,以实现或集成个人用户常用功能,降低用户的硬件和软件操作学习成本,同时引导使用者注意网络安全。随着版本更新和网友反馈,Lucky不断迭代改进,拥有更多功能和更好的性能,成为用户值得信赖的工具。
Lucky 的核心程序完全采用 Golang 实现,具有高效、稳定、跨平台等优点。其后台前端则采用 Vue3.2 技术进行开发,具有良好的用户体验和响应速度。此外,Lucky 的管理后台采用前后端分离的架构,第三方开发者也可以自由使用OpenToken轻松调用Lucky的各种功能接口。
## 功能模块
目前已经实现/集成的主要功能模块有
- 端口转发
- 动态域名(DDNS)
- Web服务
- Stun内网穿透
- 网络唤醒
- 计划任务
- ACME自动证书
- 网络存储
### 端口转发
1. 主要用于实现公网 IPv6 转内网 IPv4 的 TCP/UDP 端口转发。
2. 支持界面化的管理转发规则,用户可以通过 web 后台轻松地进行规则的添加、删除、修改等操作。
3. 单条转发规则支持设置多个转发端口,这样可以实现多个内网服务端口的转发。
4. 提供了一键开关和定时开关功能,用户可以根据自己的需求设置转发规则的开启和关闭时间,还可以使用计划任务模块进行定时开关。
5. 单条规则支持黑白名单安全模式切换,用户可以根据需要选择使用白名单模式或黑名单模式。
6. 白名单模式可以让没有安全验证的内网服务端口稍微安全一点暴露到公网,提高服务可用性。
7. 实时记录最新的访问日志,方便用户了解转发情况。
8. 规则列表日志一目了然,用户可以方便地追踪转发异常,及时进行排查和处理。
### 动态域名(DDNS)
1. 支持接入多个不同的 DNS 服务商。
2. 支持全功能自定义回调(Callback),包括设置 BasicAuth,方便接入任意 DNS 服务商。
3. Webhook 支持自定义 headers。
4. 内置常用免费 DNS 服务商设置模板(每步、No-IP、Dynv6、Dynu),通过自定义回调进行快速接入,仅需修改相应用户密码或 token 即可一键填充。
5. 支持 阿里云,百度云,华为云,京东云,腾讯云,火山引擎,帝恩爱斯-DNS.LA,Cloudflare,deSEC,DNSPod.CN,DNSPod.COM,Dynadot,Dynv6,Freemyip ,GoDaddy,Name.com,NameSilo,Porkbun,Vercel等服务商。
### Web服务
1. 支持反向代理、重定向和 URL 跳转。
2. 支持 HTTP 基本认证。
3. 支持 IP 黑白名单模式。
4. 支持 UserAgent 黑白名单。
5. 规则日志清晰易懂,便于追踪异常。
6. 支持一键开关规则和定时开关规则。
### Stun内网穿透
1. 实现内网穿透,无需公网IPv4地址。
2. 适合于国内运营商级NAT1宽带网络.
### 网络唤醒
1. 支持远程控制唤醒和关机操作
2. 支持接入第三方物联网平台(点灯科技 巴法云),可通过各大平台的语音助手控制设备唤醒和关机.
### 计划任务
1. 不依赖 Linux 系统的 Cron,支持 Windows 系统。
2. 操作简便,可视化编辑。
3. 可操作控制 Lucky 框架内的其他模块开关。
### ACME自动证书
1. 支持 ACME 自动证书的申请和续签。
2. 支持 阿里云,百度云,华为云,京东云,腾讯云,火山引擎,帝恩爱斯-DNS.LA,Cloudflare,deSEC,DNSPod.CN,DNSPod.COM,Dynadot,Dynv6,Freemyip ,GoDaddy,Name.com,NameSilo,Porkbun,Vercel等服务商.
### 网络存储
1. 网络存储模块是一个应用范围广泛的模块,它提供了将本地存储、WebDAV和阿里云盘挂载到Lucky内部的各个文件类服务功能。
2. 通过网络存储模块,你可以将添加的存储挂载到Web服务的文件服务、WebDAV、FTP和FileBrowser模块,实现更加便捷的文件管理和访问。
## 一键安装
- [一键安装详看这里](https://github.com/gdy666/lucky-files)
## OpenwrtIPK包安装
- [Openwrt IPK包](https://github.com/gdy666/luci-app-lucky)
## 使用
- 默认后台管理地址 http://<运行设备IP>:16601
默认登录账号: 666
默认登录密码: 666
- 常规使用请用 -cd <配置文件夹路径> 指定配置文件夹的方式运行
```bash
#仅指定配置文件夹路径(如果配置文件夹不存在会自动创建),建议使用绝对路径
lucky -cd luckyconf
```
## Docker中使用
- 不挂载主机目录, 删除容器同时会删除配置
```bash
# host模式, 同时支持IPv4/IPv6, Liunx系统推荐
docker run -d --name lucky --restart=always --net=host gdy666/lucky
# 桥接模式, 只支持IPv4, Mac/Windows推荐,windows 不推荐使用docker版本
docker run -d --name lucky --restart=always -p 16601:16601 gdy666/lucky
```
- 在浏览器中打开`http://主机IP:16601`,修改你的配置,成功
- [可选] 挂载主机目录, 删除容器后配置不会丢失。可替换 `/root/luckyconf` 为主机目录, 配置文件夹为lucky
```bash
docker run -d --name lucky --restart=always --net=host -v /root/luckyconf:/goodluck gdy666/lucky
```
## 宝塔Docker安装
1. 安装宝塔面板 (9.2.0版本及以上),前往 [宝塔面板](https://www.bt.cn/new/download.html) 官网,选择正式版的脚本下载安装
2. 安装后登录宝塔面板,在菜单栏中点击 Docker ,首次进入会提示安装 Docker 服务,点击立即安装,按提示完成安装
3. 安装完成后在应用商店中找到 lucky ,点击安装,配置基本选项 即可完成安装
#开发编译
```bash
go build -v -tags "adminweb nomsgpack" -ldflags="-s -w"
```
# 更新日志
2026-02-01 v2.27.2
1. 重构并优化文件服务/WebDav 前端显示。
2. CorazaWAF:
内置规则集更新至 v4.22.0。
新增每条规则的功能提示。
新增出入站阈值自定义功能。
注:WAF 建议按需开启,请勿全选规则,避免误判正常访问。
如何验证 WAF 是否生效?
在已开启防护的域名后面加上测试后缀,例如:
https://你的域名.com/?test=../../../
生效表现:页面被拦截(显示 403 Forbidden ,Lucky/WAF)。
未生效表现:页面能正常打开或显示 404。
2026-01-31 Lucky v2.27.1
1. 修复已知Bug。
2. 网页认证页面重构优化
2026-01-30 Lucky v2.27.1 beta1
1. IP 地址库:更新 ip2region 解析引擎
2. Cloudflared:同步官方最新源码
3. Rclone 同步官方最新源码
4. 轻面板
内置面板源:
现已提供 4 种主题风格切换
站点页面新增“搜索引擎”显示设置,支持快捷搜索
新增前端静态源自定义默认参数功能。支持预设背景、主题及默认标签页等默认参数。
5.修复了已知的部分 Bug。
2026-01-28 Lucky v2.27.0 Beta1 | 轻导航体验版,全版本支持。
本次更新带来了全新的 “轻导航” 功能,旨在通过极简的配置实现高效的面板管理。
提供美观、响应式的站点导航内外网识别、多链接支持,Docker 容器监控、Lucky 服务状态展示等功能。
快速上手:进入 Web服务 -> 子规则 -> 选择“轻面板”服务类型 ,填写前端域名编辑轻面板设置即可。
配置建议:
初次体验:无需修改“前端静态源”、“全局设置”及“图标源”,维持默认配置即可秒速开通。
深度定制:支持自行部署前端源码,打造个性化导航界面。
🛠 相关资源
内置面板前端源码:https://github.com/gdy666/LuckyLightPanel
内置图标库:icons.666666.host
进阶技巧:非前端开发者如需深度定制,推荐结合 qoder IDE 使用 AI 辅助修改。
Qoder注册下载地址:https://qoder.com/referral?referral_code=uaJw7kR25Ed4hiHfjRroImw6eoVfmXqj
⚠️ 注意事项
Alpha 阶段:当前为体验版本,正式版发布时可能存在配置兼容性调整。
持续关注:建议密切关注群公告,以便及时获取配置迁移或更新通知。
[更多日志请查看](https://lucky666.cn/docs/category/%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97)
。
================================================
FILE: berforebuild.bat
================================================
cd ./web/adminviews
npm run build
================================================
FILE: config/appinfo.go
================================================
package config
import (
"runtime"
"time"
)
type AppInfo struct {
AppName string
Version string
OS string
ARCH string
Date string
RunTime string
GoVersion string
}
var appInfo AppInfo
func GetAppInfo() *AppInfo {
return &appInfo
}
func InitAppInfo(version, date string) {
appInfo.AppName = "Lucky"
appInfo.Version = version
appInfo.Date = date
appInfo.OS = runtime.GOOS
appInfo.ARCH = runtime.GOARCH
appInfo.RunTime = time.Now().Format("2006-01-02 15:04:05")
appInfo.GoVersion = runtime.Version()
time.Now().Format("2006-01-02T15:04:05Z")
buildTime, err := time.Parse("2006-01-02T15:04:05Z", date)
if err != nil {
return
}
appInfo.Date = buildTime.Local().Format("2006-01-02 15:04:05")
}
================================================
FILE: config/blacklist.go
================================================
// Copyright 2022 gdy, 272288813@qq.com
package config
import (
"fmt"
"net"
"strings"
"time"
)
type BlackListItem WhiteListItem
func (w *BlackListItem) Contains(ip string) bool {
netIP := net.ParseIP(ip)
if netIP == nil {
return false
}
if w.NetIP != nil {
return w.NetIP.Equal(netIP)
}
if w.Cidr != nil {
return w.Cidr.Contains(netIP)
}
return false
}
type BlackListConfigure struct {
BlackList []BlackListItem `json:"BlackList"` //黑名单列表
}
func GetBlackList() []BlackListItem {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
BlackListFlush(false)
var resList []BlackListItem
if programConfigure == nil {
return resList
}
for i := range programConfigure.BlackListConfigure.BlackList {
resList = append(resList, programConfigure.BlackListConfigure.BlackList[i])
}
return resList
}
func BlackListInit() {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var netIP net.IP
var cidr *net.IPNet
for i := range programConfigure.BlackListConfigure.BlackList {
netIP = nil
cidr = nil
if strings.Contains(programConfigure.BlackListConfigure.BlackList[i].IP, "/") {
_, cidr, _ = net.ParseCIDR(programConfigure.BlackListConfigure.BlackList[i].IP)
} else {
netIP = net.ParseIP(programConfigure.BlackListConfigure.BlackList[i].IP)
}
programConfigure.BlackListConfigure.BlackList[i].Cidr = cidr
programConfigure.BlackListConfigure.BlackList[i].NetIP = netIP
}
}
func BlackListAdd(ip string, activelifeDuration int32) (string, error) {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
var err error
var netIP net.IP = nil
var cidr *net.IPNet = nil
if strings.Contains(ip, "/") {
_, cidr, err = net.ParseCIDR(ip)
if err != nil {
return "", fmt.Errorf("网段格式有误,转换出错:%s", err.Error())
}
} else {
netIP = net.ParseIP(ip)
if netIP == nil {
return "", fmt.Errorf("IP格式有误")
}
}
if activelifeDuration <= 0 {
activelifeDuration = 666666
}
EffectiveTimeStr := time.Now().Add(time.Hour * time.Duration(activelifeDuration)).Format("2006-01-02 15:04:05")
for i, ipr := range programConfigure.BlackListConfigure.BlackList {
if ipr.IP == ip {
programConfigure.BlackListConfigure.BlackList[i].EffectiveTime = EffectiveTimeStr
return EffectiveTimeStr, Save()
}
}
item := BlackListItem{IP: ip, EffectiveTime: EffectiveTimeStr, NetIP: netIP, Cidr: cidr}
programConfigure.BlackListConfigure.BlackList = append(programConfigure.BlackListConfigure.BlackList, item)
return EffectiveTimeStr, Save()
}
func BlackListDelete(ip string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
removeCount := 0
CONTINUECHECK:
removeIndex := -1
for i, ipr := range programConfigure.BlackListConfigure.BlackList {
if ipr.IP == ip {
removeIndex = i
break
}
}
if removeIndex >= 0 {
removeCount++
programConfigure.BlackListConfigure.BlackList = DeleteBlackListlice(programConfigure.BlackListConfigure.BlackList, removeIndex)
goto CONTINUECHECK
}
if removeCount == 0 {
return nil
}
return Save()
}
func BlackListFlush(lock bool) error {
if lock {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
}
removeCount := 0
CONTINUECHECK:
removeIndex := -1
for i, ipr := range programConfigure.BlackListConfigure.BlackList {
ipat, err := time.ParseInLocation("2006-01-02 15:04:05", ipr.EffectiveTime, time.Local)
if err != nil { //有效时间格式有误,当失效处理
removeIndex = i
break
}
if time.Since(ipat) > 0 {
removeIndex = i
break
}
}
if removeIndex >= 0 {
removeCount++
programConfigure.BlackListConfigure.BlackList = DeleteBlackListlice(programConfigure.BlackListConfigure.BlackList, removeIndex)
goto CONTINUECHECK
}
if removeCount == 0 {
return nil
}
return Save()
}
func DeleteBlackListlice(a []BlackListItem, deleteIndex int) []BlackListItem {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
================================================
FILE: config/config.go
================================================
// Copyright 2022 gdy, 272288813@qq.com
package config
import (
"encoding/json"
"fmt"
"log"
"net"
"runtime"
"strings"
"sync"
"github.com/gdy666/lucky/socketproxy"
"github.com/gdy666/lucky/thirdlib/gdylib/fileutils"
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
)
const defaultAdminAccount = "666"
const defaultAdminPassword = "666"
const defaultAdminListenPort = 16601
const defaultLogSize = 2048
const minLogSize = 1024
const maxLogSize = 40960
var runMode = "prod"
var version = "0.0.0"
func SetVersion(v string) {
version = v
}
func GetVersion() string {
return version
}
var loginRandomkey = ""
func GetLoginRandomKey() string {
return loginRandomkey
}
func FlushLoginRandomKey() {
loginRandomkey = stringsp.GetRandomString(16)
}
type BaseConfigure struct {
AdminWebListenPort int `json:"AdminWebListenPort"` //管理后台端口
AdminWebListenTLS bool `json:"AdminWebListenTLS"` //启用TLS监听端口
AdminWebListenHttpsPort int `json:"AdminWebListenHttpsPort"` //管理后台Https端口
//ProxyCountLimit int64 `json:"ProxyCountLimit"` //全局代理数量限制
AdminAccount string `json:"AdminAccount"` //登录账号
AdminPassword string `json:"AdminPassword"` //登录密码
AllowInternetaccess bool `json:"AllowInternetaccess"` //允许外网访问
//GlobalMaxConnections int64 `json:"GlobalMaxConnections"` //全局最大连接数
LogMaxSize int `json:"LogMaxSize"` //日志记录最大条数
}
type ProgramConfigure struct {
BaseConfigure BaseConfigure `json:"BaseConfigure"`
WhiteListConfigure WhiteListConfigure `json:"WhiteListConfigure"`
BlackListConfigure BlackListConfigure `json:"BlackListConfigure"`
DDNSConfigure DDNSConfigure `json:"DDNSConfigure"` //DDNS 参数设置
DDNSTaskList []DDNSTask `json:"DDNSTaskList"` //DDNS任务列表
ReverseProxyRuleList []ReverseProxyRule `json:"ReverseProxyRuleList"` //反向代理规则列表
SSLCertficateList []SSLCertficate `json:"SSLCertficateList"` //SSL证书列表
PortForwardsRuleList []PortForwardsRule `json:"PortForwardsRuleList"` //端口转发规则列表
PortForwardsConfigure PortForwardsConfigure `json:"PortForwardsConfigure"` //端口转发设置
WOLDeviceList []WOLDevice `json:"WOLDeviceList"` //网络唤醒设备列表
}
var programConfigureMutex sync.RWMutex
var programConfigure *ProgramConfigure
var configurePath string
// var readConfigureFileOnce sync.Once
var checkConfigureFileOnce sync.Once
var configureFileSign int8 = -1
// func GetConfigMutex() *sync.RWMutex {
// return &programConfigureMutex
// }
func GetAuthAccount() map[string]string {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
accountInfo := make(map[string]string)
accountInfo[programConfigure.BaseConfigure.AdminAccount] = programConfigure.BaseConfigure.AdminPassword
return accountInfo
}
func GetRunMode() string {
return runMode
}
func SetRunMode(mode string) {
runMode = mode
}
func SetConfig(p *ProgramConfigure) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
programConfigure = p
return Save()
}
func GetConfig() *ProgramConfigure {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
conf := *programConfigure
return &conf
}
func GetConfigureBytes() []byte {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
if programConfigure == nil {
return []byte("{}")
}
//JSON.Pars
res, err := json.MarshalIndent(*programConfigure, "", "\t")
if err != nil {
return []byte("{}")
}
return res
}
func GetBaseConfigure() BaseConfigure {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
baseConf := programConfigure.BaseConfigure
return baseConf
}
func GetDDNSConfigure() DDNSConfigure {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
conf := programConfigure.DDNSConfigure
return conf
}
func GetPortForwardsConfigure() PortForwardsConfigure {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
conf := programConfigure.PortForwardsConfigure
return conf
}
func SetPortForwardsConfigure(conf *PortForwardsConfigure) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
if conf.PortForwardsLimit < 0 {
conf.PortForwardsLimit = 0
} else if conf.PortForwardsLimit > 1024 {
conf.PortForwardsLimit = 1024
}
if conf.TCPPortforwardMaxConnections < 0 {
conf.TCPPortforwardMaxConnections = 0
} else if conf.TCPPortforwardMaxConnections > 4096 {
conf.TCPPortforwardMaxConnections = 4096
}
if conf.UDPReadTargetDataMaxgoroutineCount < 0 {
conf.UDPReadTargetDataMaxgoroutineCount = 0
} else if conf.UDPReadTargetDataMaxgoroutineCount > 4096 {
conf.UDPReadTargetDataMaxgoroutineCount = 4096
}
programConfigure.PortForwardsConfigure = *conf
socketproxy.SetGlobalMaxPortForwardsCountLimit(conf.PortForwardsLimit)
socketproxy.SetGlobalTCPPortforwardMaxConnections(conf.TCPPortforwardMaxConnections)
socketproxy.SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(conf.UDPReadTargetDataMaxgoroutineCount)
return Save()
}
// 保存基础配置
func SetBaseConfigure(conf *BaseConfigure) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
programConfigure.BaseConfigure = *conf
//socketproxy.SetGlobalMaxConnections(conf.GlobalMaxConnections)
//socketproxy.SetGlobalMaxPortForwardsCount(conf.ProxyCountLimit)
if conf.LogMaxSize < minLogSize {
conf.LogMaxSize = minLogSize
} else if conf.LogMaxSize > maxLogSize {
conf.LogMaxSize = maxLogSize
}
return Save()
}
func SetDDNSConfigure(conf *DDNSConfigure) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
if conf.Intervals < 30 {
conf.Intervals = 30
}
if conf.Intervals > 3600 {
conf.Intervals = 3600
}
if conf.FirstCheckDelay < 0 {
conf.FirstCheckDelay = 0
}
if conf.FirstCheckDelay > 3600 {
conf.FirstCheckDelay = 3600
}
programConfigure.DDNSConfigure = *conf
return Save()
}
func Read(filePath string) (err error) {
if runtime.GOOS == "windows" && filePath == "" {
filePath = "lucky.conf"
log.Printf("未指定配置文件路径,使用默认路径lucky所在位置,默认配置文件名lucky.conf")
}
pc, err := readProgramConfigure(filePath)
if err != nil {
return err
}
if pc.PortForwardsConfigure.PortForwardsLimit <= 0 {
pc.PortForwardsConfigure.PortForwardsLimit = socketproxy.DEFAULT_MAX_PORTFORWARDS_LIMIT
}
if pc.PortForwardsConfigure.TCPPortforwardMaxConnections <= 0 {
pc.PortForwardsConfigure.TCPPortforwardMaxConnections = socketproxy.DEFAULT_GLOBAL_MAX_CONNECTIONS
}
if pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount <= 0 {
pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount = socketproxy.DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount
}
socketproxy.SetGlobalMaxPortForwardsCountLimit(pc.PortForwardsConfigure.PortForwardsLimit)
socketproxy.SetGlobalTCPPortforwardMaxConnections(pc.PortForwardsConfigure.TCPPortforwardMaxConnections)
socketproxy.SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount)
if pc.BaseConfigure.AdminWebListenPort <= 0 {
pc.BaseConfigure.AdminWebListenPort = 16601
}
if pc.BaseConfigure.AdminWebListenHttpsPort <= 0 {
pc.BaseConfigure.AdminWebListenHttpsPort = 16626
}
if pc.BaseConfigure.LogMaxSize < minLogSize {
pc.BaseConfigure.LogMaxSize = minLogSize
} else if pc.BaseConfigure.LogMaxSize > maxLogSize {
pc.BaseConfigure.LogMaxSize = maxLogSize
}
programConfigure = pc
return nil
}
func LoadDefault(adminWebListenPort int) {
programConfigure = loadDefaultConfigure(adminWebListenPort)
}
func Save() (err error) {
//log.Printf("Save配置\n")
if configureFileSign == 0 {
return fmt.Errorf("配置文件不存在,不作保存")
}
defer func() {
checkConfigureFileOnce.Do(func() {
if err == nil {
configureFileSign = 1
} else {
configureFileSign = 0
}
})
}()
err = saveProgramConfig(programConfigure, configurePath)
return
}
//------------------------------------------------------------------------------------
func readProgramConfigure(filePath string) (conf *ProgramConfigure, err error) {
if filePath == "" {
return nil, fmt.Errorf("未指定配置文件路径")
}
if !strings.HasPrefix(filePath, "/") {
filePath = fmt.Sprintf("%s/%s", fileutils.GetCurrentDirectory(), filePath)
}
configurePath = filePath
//fmt.Printf("filePath:%s\n", configurePath)
fileContent, err := fileutils.ReadTextFromFile(configurePath)
if err != nil {
return nil, fmt.Errorf("读取配置文件出错:%s", err.Error())
}
var pc ProgramConfigure
err = json.Unmarshal([]byte(fileContent), &pc)
if err != nil {
log.Fatalf("解析配置文件出错:%s", err.Error())
return nil, fmt.Errorf("解析配置文件出错:%s", err.Error())
}
return &pc, nil
}
func loadDefaultConfigure(
adminWebListenPort int) *ProgramConfigure {
baseConfigure := BaseConfigure{AdminWebListenPort: adminWebListenPort,
AdminAccount: defaultAdminAccount,
AdminPassword: defaultAdminPassword,
AllowInternetaccess: false,
LogMaxSize: defaultLogSize}
whiteListConfigure := WhiteListConfigure{BaseConfigure: WhiteListBaseConfigure{ActivelifeDuration: 36, BasicAccount: defaultAdminAccount, BasicPassword: defaultAdminPassword}}
var pc ProgramConfigure
pc.BaseConfigure = baseConfigure
pc.WhiteListConfigure = whiteListConfigure
if pc.PortForwardsConfigure.PortForwardsLimit <= 0 {
pc.PortForwardsConfigure.PortForwardsLimit = socketproxy.DEFAULT_MAX_PORTFORWARDS_LIMIT
}
socketproxy.SetGlobalMaxPortForwardsCountLimit(pc.PortForwardsConfigure.PortForwardsLimit)
if pc.PortForwardsConfigure.TCPPortforwardMaxConnections <= 0 {
pc.PortForwardsConfigure.TCPPortforwardMaxConnections = socketproxy.TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS
}
socketproxy.SetGlobalTCPPortforwardMaxConnections(pc.PortForwardsConfigure.TCPPortforwardMaxConnections)
if pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount <= 0 {
pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount = socketproxy.DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount
}
socketproxy.SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(pc.PortForwardsConfigure.UDPReadTargetDataMaxgoroutineCount)
if pc.BaseConfigure.AdminWebListenPort <= 0 {
pc.BaseConfigure.AdminWebListenPort = defaultAdminListenPort
}
if pc.DDNSConfigure.Intervals < 30 {
pc.DDNSConfigure.Intervals = 30
}
if pc.DDNSConfigure.FirstCheckDelay <= 0 {
pc.DDNSConfigure.FirstCheckDelay = 0
}
return &pc
}
func saveProgramConfig(programConfigure *ProgramConfigure, filePath string) error {
resBytes, err := json.MarshalIndent(*programConfigure, "", "\t")
if err != nil {
return fmt.Errorf("json.Marshal:%s", err.Error())
}
return fileutils.SaveTextToFile(string(resBytes), filePath)
}
func CheckTCPPortAvalid(port int) bool {
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
return false
}
ln.Close()
return true
}
================================================
FILE: config/ddns.go
================================================
package config
import (
"fmt"
"log"
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
)
type DDNSConfigure struct {
Enable bool `json:"Enable"`
HttpClientSecureVerify bool `json:"HttpClientSecureVerify"`
FirstCheckDelay int `json:"FirstCheckDelay"` //首次检查延迟时间
Intervals int `json:"Intervals"`
}
type DDNSTask struct {
TaskName string `json:"TaskName"`
TaskKey string `json:"TaskKey"` //添加任务时随机生成,方便管理任务(修改删除)
//规则类型 IPv4/IPv6
TaskType string `json:"TaskType"`
Enable bool
// 获取IP类型 url/netInterface
GetType string `json:"GetType"`
URL []string `json:"URL"`
NetInterface string `json:"NetInterface"`
IPReg string `json:"IPReg"`
Domains []string `json:"Domains"`
DNS DNSConfig `json:"DNS"`
Webhook
TTL string `json:"TTL"`
HttpClientTimeout int `json:"HttpClientTimeout"`
}
type Webhook struct {
WebhookEnable bool `json:"WebhookEnable"` //Webhook开关
WebhookCallOnGetIPfail bool `json:"WebhookCallOnGetIPfail"` //获取IP失败时触发Webhook 开关
WebhookURL string `json:"WebhookURL"`
WebhookMethod string `json:"WebhookMethod"`
WebhookHeaders []string `json:"WebhookHeaders"`
WebhookRequestBody string `json:"WebhookRequestBody"`
WebhookDisableCallbackSuccessContentCheck bool `json:"WebhookDisableCallbackSuccessContentCheck"` //禁用成功调用返回检测
WebhookSuccessContent []string `json:"WebhookSuccessContent"` //接口调用成功包含的内容
WebhookProxy string `json:"WebhookProxy"` //使用DNS代理设置 ""表示禁用,"dns"表示使用dns的代理设置
WebhookProxyAddr string `json:"WebhookProxyAddr"` //代理服务器IP
WebhookProxyUser string `json:"WebhookProxyUser"` //代理用户
WebhookProxyPassword string `json:"WebhookProxyPassword"` //代理密码
}
// DNSConfig DNS配置
type DNSConfig struct {
// 名称。如:alidns,webhook
Name string `json:"Name"`
ID string `json:"ID"`
Secret string `json:"Secret"`
ForceInterval int `json:"ForceInterval"` //(秒)即使IP没有变化,到一定时间后依然强制更新或先DNS解析比较IP再更新
ResolverDoaminCheck bool `json:"ResolverDoaminCheck"` //调用callback同步前先解析一次域名,如果IP相同就不同步
DNSServerList []string `json:"DNSServerList"` //DNS服务器列表
CallAPINetwork string `json:"CallAPINetwork"` //空代理tcp, tcp4,tcp6
Callback DNSCallback `json:"Callback"`
HttpClientProxyType string `json:"HttpClientProxyType"` //http client代理服务器设置
HttpClientProxyAddr string `json:"HttpClientProxyAddr"` //代理服务器IP
HttpClientProxyUser string `json:"HttpClientProxyUser"` //代理用户
HttpClientProxyPassword string `json:"HttpClientProxyPassword"` //代理密码
}
func (d *DNSConfig) GetCallAPINetwork() string {
switch d.CallAPINetwork {
case "tcp4", "tcp6":
return d.CallAPINetwork
default:
return "tcp"
}
}
type DNSCallback struct {
URL string `json:"URL"` //请求地址
Method string `json:"Method"` //请求方法
Headers []string `json:"Headers"`
RequestBody string `json:"RequestBody"`
Server string `json:"Server"` //预设服务商
DisableCallbackSuccessContentCheck bool `json:"DisableCallbackSuccessContentCheck"` //禁用成功调用返回检测
CallbackSuccessContent []string `json:"CallbackSuccessContent"` //接口调用成功包含内容
}
var checkIPv4URLList = []string{"https://4.ipw.cn", "http://v4.ip.zxinc.org/getip", "https://myip4.ipip.net", "https://www.taobao.com/help/getip.php", "https://ddns.oray.com/checkip", "https://ip.3322.net", "https://v4.myip.la"}
var checkIPv6URLList = []string{"https://6.ipw.cn", "https://ipv6.ddnspod.com", "http://v6.ip.zxinc.org/getip", "https://speed.neu6.edu.cn/getIP.php", "https://v6.ident.me", "https://v6.myip.la"}
var DefaultIPv6DNSServerList = []string{
"[2001:4860:4860::8888]:53", //谷歌
"[2001:4860:4860::8844]:53", //谷歌
"[2606:4700:4700::64]:53", //cloudflare
"[2606:4700:4700::6400]:53", //cloudflare
"[240C::6666]:53", //下一代互联网北京研究中心
"[240C::6644]:53", //下一代互联网北京研究中心
"[2402:4e00::]:53", //dnspod
//"[2400:3200::1]:53", //阿里
// "[2400:3200:baba::1]:53", //阿里
"[240e:4c:4008::1]:53", //中国电信
"[240e:4c:4808::1]:53", //中国电信
"[2408:8899::8]:53", //中国联通
"[2408:8888::8]:53", //中国联通
"[2409:8088::a]:53", //中国移动
"[2409:8088::b]:53", //中国移动
"[2001:dc7:1000::1]:53", //CNNIC
"[2400:da00::6666]:53", //百度
}
var DefaultIPv4DNSServerList = []string{
"1.1.1.1:53",
"1.2.4.8:53",
"8.8.8.8:53",
"9.9.9.9:53",
"8.8.4.4:53",
"114.114.114.114:53",
"223.5.5.5:53",
"223.6.6.6:53",
"101.226.4.6:53",
"218.30.118.6:53",
"119.28.28.28:53",
}
// func SetDDNSTaskIpCacheForceCompareByTaskKey(taskKey string, force bool) {
// programConfigureMutex.Lock()
// defer programConfigureMutex.Unlock()
// taskIndex := -1
// for i := range programConfigure.DDNSTaskList {
// if programConfigure.DDNSTaskList[i].TaskKey == taskKey {
// taskIndex = i
// break
// }
// }
// if taskIndex == -1 {
// return
// }
// programConfigure.DDNSTaskList[taskIndex].IpCache.ForceCompare = force
// }
func DDNSTaskListConfigureCheck() {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
for i := range programConfigure.DDNSTaskList {
if programConfigure.DDNSTaskList[i].DNS.ForceInterval < 60 {
programConfigure.DDNSTaskList[i].DNS.ForceInterval = 60
} else if programConfigure.DDNSTaskList[i].DNS.ForceInterval > 360000 {
programConfigure.DDNSTaskList[i].DNS.ForceInterval = 360000
}
if programConfigure.DDNSTaskList[i].HttpClientTimeout < 3 {
programConfigure.DDNSTaskList[i].HttpClientTimeout = 3
} else if programConfigure.DDNSTaskList[i].HttpClientTimeout > 60 {
programConfigure.DDNSTaskList[i].HttpClientTimeout = 60
}
}
}
func DDNSTaskSetWebhookCallResult(taskKey string, result bool, message string) {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
taskIndex := -1
for i := range programConfigure.DDNSTaskList {
if programConfigure.DDNSTaskList[i].TaskKey == taskKey {
taskIndex = i
break
}
}
if taskIndex == -1 {
return
}
log.Printf("DDNSTaskSetWebhookCallResult %s", taskKey)
}
func GetDDNSTaskConfigureList() []*DDNSTask {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var resList []*DDNSTask
for i := range programConfigure.DDNSTaskList {
task := programConfigure.DDNSTaskList[i]
resList = append(resList, &task)
}
return resList
}
func GetDDNSTaskByKey(taskKey string) *DDNSTask {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
taskIndex := -1
for i := range programConfigure.DDNSTaskList {
if programConfigure.DDNSTaskList[i].TaskKey == taskKey {
taskIndex = i
break
}
}
if taskIndex == -1 {
return nil
}
res := programConfigure.DDNSTaskList[taskIndex]
return &res
}
func DDNSTaskListAdd(task *DDNSTask) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
task.TaskKey = stringsp.GetRandomString(16)
programConfigure.DDNSTaskList = append(programConfigure.DDNSTaskList, *task)
return Save()
}
func DDNSTaskListDelete(taskKey string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
taskIndex := -1
for i := range programConfigure.DDNSTaskList {
if programConfigure.DDNSTaskList[i].TaskKey == taskKey {
taskIndex = i
break
}
}
if taskIndex == -1 {
return fmt.Errorf("找不到需要删除的DDNS任务")
}
programConfigure.DDNSTaskList = DeleteDDNSTaskListlice(programConfigure.DDNSTaskList, taskIndex)
return Save()
}
func CheckDDNSTaskAvalid(task *DDNSTask) error {
if len(task.URL) == 0 {
if task.TaskType == "IPv6" {
task.URL = checkIPv6URLList
} else {
task.URL = checkIPv4URLList
}
}
switch task.DNS.Name {
case "cloudflare":
if task.DNS.Secret == "" {
return fmt.Errorf("cloudflare token不能为空")
}
case "callback":
if task.DNS.Callback.URL == "" {
return fmt.Errorf("callback URL不能为空")
}
if task.DNS.Callback.Method == "" {
return fmt.Errorf("请选择callback method")
}
default:
if task.DNS.ID == "" || task.DNS.Secret == "" {
return fmt.Errorf("dns服务商相关参数不能为空")
}
}
if len(task.Domains) <= 0 {
return fmt.Errorf("域名列表不能为空")
}
return nil
}
func EnableDDNSTaskByKey(taskKey string, enable bool) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
taskIndex := -1
for i := range programConfigure.DDNSTaskList {
if programConfigure.DDNSTaskList[i].TaskKey == taskKey {
taskIndex = i
break
}
}
if taskIndex == -1 {
return fmt.Errorf("开关DDNS任务失败,TaskKey不存在")
}
programConfigure.DDNSTaskList[taskIndex].Enable = enable
return Save()
}
func UpdateTaskToDDNSTaskList(taskKey string, task DDNSTask) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
taskIndex := -1
for i := range programConfigure.DDNSTaskList {
if programConfigure.DDNSTaskList[i].TaskKey == taskKey {
taskIndex = i
break
}
}
if taskIndex == -1 {
return fmt.Errorf("找不到需要更新的DDNS任务")
}
programConfigure.DDNSTaskList[taskIndex].TaskName = task.TaskName
programConfigure.DDNSTaskList[taskIndex].TaskType = task.TaskType
programConfigure.DDNSTaskList[taskIndex].Enable = task.Enable
programConfigure.DDNSTaskList[taskIndex].GetType = task.GetType
programConfigure.DDNSTaskList[taskIndex].URL = task.URL
programConfigure.DDNSTaskList[taskIndex].NetInterface = task.NetInterface
programConfigure.DDNSTaskList[taskIndex].IPReg = task.IPReg
programConfigure.DDNSTaskList[taskIndex].Domains = task.Domains
programConfigure.DDNSTaskList[taskIndex].DNS = task.DNS
programConfigure.DDNSTaskList[taskIndex].Webhook = task.Webhook
programConfigure.DDNSTaskList[taskIndex].TTL = task.TTL
programConfigure.DDNSTaskList[taskIndex].HttpClientTimeout = task.HttpClientTimeout
return Save()
}
func DeleteDDNSTaskListlice(a []DDNSTask, deleteIndex int) []DDNSTask {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
//****************************
================================================
FILE: config/portforward.go
================================================
package config
import (
"fmt"
"log"
"strconv"
"strings"
"github.com/gdy666/lucky/socketproxy"
"github.com/gdy666/lucky/thirdlib/gdylib/logsbuffer"
"github.com/sirupsen/logrus"
)
type PortForwardsConfigure struct {
PortForwardsLimit int64 `json:"PortForwardsLimit"` //全局端口转发数量限制
TCPPortforwardMaxConnections int64 `json:"TCPPortforwardMaxConnections"` //端口转发全局TCP并发链接数限制
UDPReadTargetDataMaxgoroutineCount int64 `json:"UDPReadTargetDataMaxgoroutineCount"` //端口转发全局UDP读取目标地址数据协程数限制
}
type PortForwardsRule struct {
Name string `json:"Name"`
Key string `json:"Key"`
Enable bool `json:"Enable"`
ForwardTypes []string `json:"ForwardTypes"`
ListenAddress string `json:"ListenAddress"`
ListenPorts string `json:"ListenPorts"`
TargetAddressList []string `json:"TargetAddressList"`
TargetPorts string `json:"TargetPorts"`
Options socketproxy.RelayRuleOptions `json:"Options"`
ReverseProxyList *[]socketproxy.Proxy `json:"-"`
logsBuffer *logsbuffer.LogsBuffer
logrus *logrus.Logger
LogLevel int `json:"LogLevel"` //日志输出级别
LogOutputToConsole bool `json:"LogOutputToConsole"` //日志输出到终端
AccessLogMaxNum int `json:"AccessLogMaxNum"`
WebListShowLastLogMaxCount int `json:"WebListShowLastLogMaxCount"` //前端列表显示最新日志最大条数
}
func (r *PortForwardsRule) ProxyCount() int {
if r.ReverseProxyList == nil {
return 0
}
return len(*r.ReverseProxyList)
}
func (r *PortForwardsRule) StartAllProxys() {
if r.ReverseProxyList == nil {
return
}
for i := range *r.ReverseProxyList {
(*r.ReverseProxyList)[i].StartProxy()
}
}
func (r *PortForwardsRule) GetLastLogs(maxCount int) []any {
return r.GetLogsBuffer().GetLastLogs(WebLogConvert, maxCount)
}
func (r *PortForwardsRule) Fire(entry *logrus.Entry) error {
if !r.LogOutputToConsole {
return nil
}
s, _ := entry.String()
log.Print(s)
return nil
}
func (r *PortForwardsRule) Levels() []logrus.Level {
return logrus.AllLevels
}
func (r *PortForwardsRule) GetLogrus() *logrus.Logger {
if r.logrus == nil {
r.logrus = logrus.New()
r.logrus.SetLevel(logrus.Level(r.LogLevel))
r.logrus.SetOutput(r.GetLogsBuffer())
r.logrus.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
DisableTimestamp: true,
DisableHTMLEscape: true,
DataKey: "ExtInfo",
})
r.logrus.AddHook(r)
}
return r.logrus
}
func (r *PortForwardsRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
if r.logsBuffer == nil {
r.logsBuffer = logsbuffer.CreateLogbuffer("portforward:"+r.Key, r.AccessLogMaxNum)
}
return r.logsBuffer
}
func (r *PortForwardsRule) StopAllProxys() {
if r.ReverseProxyList == nil {
return
}
for i := range *r.ReverseProxyList {
(*r.ReverseProxyList)[i].StopProxy()
}
}
// TidyReverseProxyCache 整理端口转发日志缓存
func TidyPortforwardLogsCache() {
ruleList := GetPortForwardsRuleList()
var keyListBuffer strings.Builder
for _, rule := range ruleList {
keyListBuffer.WriteString(rule.Key)
keyListBuffer.WriteString(",")
}
keyListStr := keyListBuffer.String()
logsbuffer.LogsBufferStoreMu.Lock()
defer logsbuffer.LogsBufferStoreMu.Unlock()
var needDeleteKeys []string
for k := range logsbuffer.LogsBufferStore {
if !strings.HasPrefix(k, "portforward:") {
continue
}
if len(k) <= 13 {
continue
}
if !strings.Contains(keyListStr, k[12:]) {
needDeleteKeys = append(needDeleteKeys, k)
}
}
for i := range needDeleteKeys {
delete(logsbuffer.LogsBufferStore, needDeleteKeys[i])
}
}
func (r *PortForwardsRule) InitProxyList() error {
listenPorts, err := PortsStrToIList(r.ListenPorts)
if err != nil {
return err
}
targetPorts, err := PortsStrToIList(r.TargetPorts)
if err != nil {
return err
}
if len(listenPorts) != len(targetPorts) {
return fmt.Errorf("端口个数不一致")
}
var proxyList []socketproxy.Proxy
for i := range r.ForwardTypes {
for j := range listenPorts {
p, err := socketproxy.CreateProxy(r.GetLogrus(), r.ForwardTypes[i],
r.ListenAddress,
r.TargetAddressList,
listenPorts[j],
targetPorts[j],
&r.Options)
if err != nil {
return err
}
proxyList = append(proxyList, p)
}
}
r.ReverseProxyList = &proxyList
return nil
}
func PortsCheck(ports1Str, ports2Str string) (bool, error) {
ports1, err := PortsStrToIList(ports1Str)
if err != nil {
return false, err
}
ports2, err := PortsStrToIList(ports2Str)
if err != nil {
return false, err
}
if len(ports1) != len(ports2) {
return false, fmt.Errorf("端口个数不一致")
}
return true, nil
}
// portsStrToIList
func PortsStrToIList(portsStr string) (ports []int, err error) {
if portsStr == "" {
return
}
if strings.Contains(portsStr, ",") {
tmpStrList := strings.Split(portsStr, ",")
for i := range tmpStrList {
tps, e := PortsStrToIList(tmpStrList[i])
if e != nil {
err = fmt.Errorf("端口字符串处理出错:%s", e.Error())
return
}
ports = append(ports, tps...)
}
return
}
portsStrList := strings.Split(portsStr, "-")
if len(portsStrList) > 2 {
err = fmt.Errorf("端口%s格式有误", portsStr)
return
}
if len(portsStrList) == 1 { //single listen port
listenPort, e := portStrToi(portsStrList[0])
if e != nil {
err = fmt.Errorf("端口格式有误!%s", e.Error())
return
}
ports = append(ports, listenPort)
}
if len(portsStrList) == 2 {
minListenPort, e := portStrToi(portsStrList[0])
if e != nil {
err = fmt.Errorf("端口格式有误!%s", portsStrList[0])
return
}
maxListenPort, e := portStrToi(portsStrList[1])
if e != nil {
err = fmt.Errorf("端口格式有误!%s", portsStrList[1])
return
}
if maxListenPort <= minListenPort {
err = fmt.Errorf("前一个端口[%d]要小于后一个端口[%d]", minListenPort, maxListenPort)
return
}
i := minListenPort
for {
if i > maxListenPort {
break
}
ports = append(ports, i)
i++
}
}
return
}
func portStrToi(portStr string) (int, error) {
port, err := strconv.Atoi(portStr)
if err != nil {
return 0, fmt.Errorf("端口格式有误:%s", err.Error())
}
if port < 1 || port > 65535 {
return 0, fmt.Errorf("端口[%d]超出范围", port)
}
return port, nil
}
func PortForwardsRuleListInit() {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var err error
for i := range programConfigure.PortForwardsRuleList {
err = programConfigure.PortForwardsRuleList[i].InitProxyList()
if err != nil {
log.Printf("InitProxyList error:%s\n", err.Error())
}
if programConfigure.PortForwardsRuleList[i].Enable {
programConfigure.PortForwardsRuleList[i].StartAllProxys()
}
}
}
func GetPortForwardsRuleList() []PortForwardsRule {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var resList []PortForwardsRule
for i := range programConfigure.PortForwardsRuleList {
r := programConfigure.PortForwardsRuleList[i]
resList = append(resList, r)
}
return resList
}
func GetPortForwardsGlobalProxyCount() int {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
count := 0
for i := range programConfigure.PortForwardsRuleList {
count += programConfigure.PortForwardsRuleList[i].ProxyCount()
}
return count
}
func GetPortForwardsGlobalProxyCountExcept(key string) int {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
count := 0
for i := range programConfigure.PortForwardsRuleList {
if key == programConfigure.PortForwardsRuleList[i].Key {
continue
}
count += programConfigure.PortForwardsRuleList[i].ProxyCount()
}
return count
}
func GetPortForwardsRuleByKey(key string) *PortForwardsRule {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
index := -1
for i := range programConfigure.PortForwardsRuleList {
if programConfigure.PortForwardsRuleList[i].Key == key {
index = i
break
}
}
if index == -1 {
return nil
}
res := programConfigure.PortForwardsRuleList[index]
return &res
}
func StopAllSocketProxysByRuleKey(key string) error {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
index := -1
for i := range programConfigure.PortForwardsRuleList {
if programConfigure.PortForwardsRuleList[i].Key == key {
index = i
break
}
}
if index == -1 {
return fmt.Errorf("找不到key:%s对应的规则", key)
}
programConfigure.PortForwardsRuleList[index].StopAllProxys()
return nil
}
func StartAllSocketProxysByRuleKey(key string) error {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
index := -1
for i := range programConfigure.PortForwardsRuleList {
if programConfigure.PortForwardsRuleList[i].Key == key {
index = i
break
}
}
if index == -1 {
return fmt.Errorf("找不到key:%s对应的规则", key)
}
programConfigure.PortForwardsRuleList[index].StartAllProxys()
return nil
}
func PortForwardsRuleListAdd(r *PortForwardsRule) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
r.Enable = true
programConfigure.PortForwardsRuleList = append(programConfigure.PortForwardsRuleList, *r)
return Save()
}
func PortForwardsRuleListDelete(key string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.PortForwardsRuleList {
if programConfigure.PortForwardsRuleList[i].Key == key {
index = i
break
}
}
if index == -1 {
return fmt.Errorf("找不到需要删除的端口转发规则")
}
programConfigure.PortForwardsRuleList[index].StopAllProxys()
programConfigure.PortForwardsRuleList = DeletePortForwardsRuleListSlice(programConfigure.PortForwardsRuleList, index)
return Save()
}
func EnablePortForwardsRuleByKey(key string, enable bool) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.DDNSTaskList {
if programConfigure.PortForwardsRuleList[i].Key == key {
index = i
break
}
}
if index == -1 {
return fmt.Errorf("开关端口转发规则失败,key查找失败")
}
if enable {
programConfigure.PortForwardsRuleList[index].StartAllProxys()
} else {
programConfigure.PortForwardsRuleList[index].StopAllProxys()
}
programConfigure.PortForwardsRuleList[index].Enable = enable
return Save()
}
func UpdatePortForwardsRuleToPortForwardsRuleList(key string, r *PortForwardsRule) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.PortForwardsRuleList {
if programConfigure.PortForwardsRuleList[i].Key == key {
index = i
break
}
}
if index == -1 {
return fmt.Errorf("找不到需要更新的端口转发规则")
}
programConfigure.PortForwardsRuleList[index] = *r
return Save()
}
func DeletePortForwardsRuleListSlice(a []PortForwardsRule, deleteIndex int) []PortForwardsRule {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
================================================
FILE: config/reverseproxy.go
================================================
package config
import (
"crypto/tls"
"fmt"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"strings"
"sync"
"time"
"github.com/gdy666/lucky/thirdlib/gdylib/ginutils"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/gdylib/logsbuffer"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
var reverseProxyServerStore sync.Map
var reverseProxyServerStoreMu sync.Mutex
func init() {
}
// TidyReverseProxyCache 整理反向代理日志缓存
func TidyReverseProxyCache() {
ruleList := GetReverseProxyRuleList()
var keyListBuffer strings.Builder
for _, rule := range ruleList {
keyListBuffer.WriteString(rule.DefaultProxy.Key)
keyListBuffer.WriteString(",")
for _, sr := range rule.ProxyList {
keyListBuffer.WriteString(sr.Key)
keyListBuffer.WriteString(",")
}
}
keyListStr := keyListBuffer.String()
logsbuffer.LogsBufferStoreMu.Lock()
defer logsbuffer.LogsBufferStoreMu.Unlock()
var needDeleteKeys []string
for k := range logsbuffer.LogsBufferStore {
if !strings.HasPrefix(k, "reverseproxy:") {
continue
}
if len(k) <= 13 {
continue
}
if !strings.Contains(keyListStr, k[13:]) {
needDeleteKeys = append(needDeleteKeys, k)
}
}
for i := range needDeleteKeys {
delete(logsbuffer.LogsBufferStore, needDeleteKeys[i])
reverseProxyServerStore.Delete(needDeleteKeys[i])
}
}
type SubReverProxyRule struct {
Key string `json:"Key"`
initOnce sync.Once
Locations []string `json:"Locations"` //长度大于1时均衡负载
locationMutex *sync.Mutex `json:"-"`
locationsCount int `json:"-"`
locationIndex uint64 `json:"-"`
EnableAccessLog bool `json:"EnableAccessLog"` //开启日志
LogLevel int `json:"LogLevel"` //日志输出级别
LogOutputToConsole bool `json:"LogOutputToConsole"` //日志输出到终端
AccessLogMaxNum int `json:"AccessLogMaxNum"` //最大条数
WebListShowLastLogMaxCount int `json:"WebListShowLastLogMaxCount"` //前端列表显示最新日志最大条数
ForwardedByClientIP bool `json:"ForwardedByClientIP"`
TrustedCIDRsStrList []string `json:"TrustedCIDRsStrList"`
RemoteIPHeaders []string `json:"RemoteIPHeaders"` //识别客户端原始IP的Http请求头
TrustedProxyCIDRs []*net.IPNet `json:"-"`
AddRemoteIPToHeader bool `json:"AddRemoteIPToHeader"` //追加客户端连接IP到指定Header
AddRemoteIPHeaderKey string `json:"AddRemoteIPHeaderKey"`
EnableBasicAuth bool `json:"EnableBasicAuth"` //启用BasicAuth认证
BasicAuthUser string `json:"BasicAuthUser"` //如果配置此参数,暴露出去的 HTTP 服务需要采用 Basic Auth 的鉴权才能访问
BasicAuthPasswd string `json:"BasicAuthPasswd"` //结合 BasicAuthUser 使用
SafeIPMode string `json:"SafeIPMode"` //IP过滤模式 黑白名单
SafeUserAgentMode string `json:"SafeUserAgentMode"` //UserAgent 过滤模式 黑白名单
UserAgentfilter []string `json:"UserAgentfilter"` //UserAgent 过滤内容
CustomRobotTxt bool `json:"CustomRobotTxt"`
RobotTxt string `json:"RobotTxt"`
//------------------
logsBuffer *logsbuffer.LogsBuffer
logrus *logrus.Logger
logger *log.Logger
}
type ReverseProxyRule struct {
RuleName string `json:"RuleName"`
RuleKey string `json:"RuleKey"`
Enable bool `json:"Enable"`
ListenIP string `json:"ListenIP"`
ListenPort int `json:"ListenPort"`
EnableTLS bool `json:"EnableTLS"`
Network string `json:"Network"`
DefaultProxy struct {
SubReverProxyRule
} `json:"DefaultProxy"`
ProxyList []ReverseProxy `json:"ProxyList"`
domainsMap *sync.Map
initOnec sync.Once
}
func (r *ReverseProxyRule) Init() {
r.initOnec.Do(func() {
r.initDomainsMap()
})
}
func (r *SubReverProxyRule) Logf(level logrus.Level, c *gin.Context, format string, v ...any) {
clientIP := r.ClientIP(c)
remoteIP := c.RemoteIP()
method := c.Request.Method
host := c.Request.Host
//hostname, hostport := httputils.SplitHostPort(c.Request.Host)
url := c.Request.URL.String()
//path := c.Request.URL.Path
r.GetLogrus().WithFields(logrus.Fields{
"ClientIP": clientIP,
"RemoteIP": remoteIP,
"Method": method,
"Host": host,
// "Hostname": hostname,
// "Hostport": hostport,
"URL": url,
//"path": path,
"UserAgent": c.Request.UserAgent(),
}).Logf(level, format, v...)
}
func (r *SubReverProxyRule) HandlerReverseProxy(remote *url.URL, host, path string, c *gin.Context) {
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.Director = func(req *http.Request) {
req.Header = c.Request.Header
req.Host = host //remote.Host
//req.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.URL.Host = remote.Host
req.URL.Path = path
if r.AddRemoteIPToHeader && r.AddRemoteIPHeaderKey != "" {
cip := r.ClientIP(c)
req.Header.Add(r.AddRemoteIPHeaderKey, cip)
}
}
proxy.ErrorLog = r.GetLogger()
proxy.ServeHTTP(c.Writer, c.Request)
}
func (r *SubReverProxyRule) Fire(entry *logrus.Entry) error {
if !r.LogOutputToConsole {
return nil
}
s, _ := entry.String()
log.Print(s)
return nil
}
func (r *SubReverProxyRule) Levels() []logrus.Level {
return logrus.AllLevels
}
func (r *SubReverProxyRule) GetLogrus() *logrus.Logger {
if r.logrus == nil {
r.logrus = logrus.New()
r.logrus.SetLevel(logrus.Level(r.LogLevel))
r.logrus.SetOutput(r.GetLogsBuffer())
r.logrus.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
DisableTimestamp: true,
DisableHTMLEscape: true,
DataKey: "ExtInfo",
})
r.logrus.AddHook(r)
}
return r.logrus
}
func (r *SubReverProxyRule) GetLogger() *log.Logger {
if r.logger == nil {
r.logger = log.New(r.GetLogsBuffer(), "", log.LstdFlags)
}
return r.logger
}
func (r *SubReverProxyRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
if r.logsBuffer == nil {
r.logsBuffer = logsbuffer.CreateLogbuffer("reverseproxy:"+r.Key, r.AccessLogMaxNum)
}
return r.logsBuffer
}
func (r *SubReverProxyRule) checkupClientIP(ip string) bool {
return SafeCheck(r.SafeIPMode, ip)
}
func (r *SubReverProxyRule) checkupUserAgent(ua string) bool {
isContains := false
for _, c := range r.UserAgentfilter {
if strings.Contains(ua, c) {
isContains = true
break
}
}
switch r.SafeUserAgentMode {
case "whitelist":
return isContains
case "blacklist":
return !isContains
default:
return false
}
}
func (r *ReverseProxyRule) ReverseProxyHandler(c *gin.Context) {
path := c.Param("proxyPath")
hostName, _ := httputils.SplitHostPort(c.Request.Host)
rule, ok := r.GetSubRuleByDomain(hostName)
var subRule *SubReverProxyRule = nil
if ok && rule.Enable {
subRule = &rule.SubReverProxyRule
} else {
subRule = &r.DefaultProxy.SubReverProxyRule
}
if !subRule.checkupClientIP(subRule.ClientIP(c)) { //IP检查
subRule.Logf(logrus.WarnLevel, c, "IP[%s]禁止访问,当前Ip检查模式[%s]", subRule.ClientIP(c), subRule.SafeIPMode)
c.Abort()
return
}
if !subRule.checkupUserAgent(c.Request.UserAgent()) {
subRule.Logf(logrus.WarnLevel, c, "IP[%s]UA[%s]禁止访问,当前UA检查模式[%s]", subRule.ClientIP(c), c.Request.UserAgent(), subRule.SafeUserAgentMode)
c.Abort()
return
}
if !subRule.BasicAuthHandler(c) {
subRule.Logf(logrus.WarnLevel, c, "BasicAuth认证不通过")
c.Abort()
return
}
if subRule.CustomRobotTxt && c.Request.RequestURI == "/robots.txt" {
if c.Request.Method != "GET" && c.Request.Method != "HEAD" {
status := http.StatusOK
if c.Request.Method != "OPTIONS" {
status = http.StatusMethodNotAllowed
}
c.Header("Allow", "GET,HEAD,OPTIONS")
c.AbortWithStatus(status)
return
}
c.Data(http.StatusOK, "text/plain", []byte(subRule.RobotTxt))
subRule.Logf(logrus.InfoLevel, c, "触发自定义robots.txt")
return
}
location := subRule.GetLocation()
if location == "" && subRule.Key == r.RuleKey {
subRule.Logf(logrus.InfoLevel, c, "域名[%s]没有对应后端地址,默认后端地址没有设置", hostName)
c.Abort()
return
}
if subRule.Key == r.RuleKey {
subRule.Logf(logrus.InfoLevel, c, "[%s] 指向默认后端地址[%s%s]", hostName, location, c.Request.URL.String())
} else {
subRule.Logf(logrus.InfoLevel, c, "[%s] 指向后端地址[%s%s]", hostName, location, c.Request.URL.String())
}
remote, err := url.Parse(location)
if err != nil {
subRule.Logf(logrus.ErrorLevel, c, "后端地址转换出错:%s", err.Error())
c.JSON(http.StatusBadGateway, gin.H{"ret": 1, "msg": fmt.Sprintf("后端地址[%s] 转换出错:%s", location, err.Error())})
return
}
subRule.HandlerReverseProxy(remote, hostName, path, c)
}
func (r *ReverseProxyRule) GetSubRuleByDomain(domain string) (*ReverseProxy, bool) {
val, ok := r.domainsMap.Load(domain)
if !ok {
return nil, false
}
return val.(*ReverseProxy), true
}
type ReverseProxy struct {
SubReverProxyRule
Enable bool `json:"Enable"`
Remark string `json:"Remark"`
Domains []string `json:"Domains"` //自定义域名
}
func GetSubRuleByKey(ruleKey, proxyKey string) *SubReverProxyRule {
//rule := getSubRuleByKey()
rule := GetReverseProxyRuleByKey(ruleKey)
if rule == nil {
return nil
}
//fmt.Printf("FFF ruleKey:%s proxyKey:%s\n", ruleKey, proxyKey)
if proxyKey == "default" {
return &rule.DefaultProxy.SubReverProxyRule
}
for i := range rule.ProxyList {
if rule.ProxyList[i].Key == proxyKey {
return &rule.ProxyList[i].SubReverProxyRule
}
}
return nil
}
func (r *ReverseProxyRule) GetServer() *http.Server {
s, loaded := reverseProxyServerStore.Load(r.RuleKey)
if !loaded {
return nil
}
return s.(*http.Server)
}
func (r *ReverseProxyRule) SetServer(s *http.Server) {
if s == nil {
reverseProxyServerStore.Delete(r.RuleKey)
return
}
reverseProxyServerStore.Store(r.RuleKey, s)
}
func (r *ReverseProxyRule) ServerStart() error {
// r.smu.Lock()
// defer r.smu.Unlock()
reverseProxyServerStoreMu.Lock()
defer reverseProxyServerStoreMu.Unlock()
server := r.GetServer()
if server != nil {
return fmt.Errorf("RuleServer[%s]已经启动,请勿重复启动", r.Addr())
}
ginR := gin.New()
ginR.Any("/*proxyPath", r.ReverseProxyHandler)
server = &http.Server{
Addr: r.Addr(),
Handler: ginR,
}
//***************************
var err error
server.TLSConfig = &tls.Config{}
if r.EnableTLS {
certList := GetValidSSLCertficateList()
server.TLSConfig.Certificates = certList
}
//server.TLSConfig.Certificates = make([]tls.Certificate, 3)
//****************************
ln, err := net.Listen(r.Network, r.Addr())
if err != nil {
return err
}
var serveResult error
go func() {
if !r.EnableTLS {
serveResult = server.Serve(ln)
return
}
if len(server.TLSConfig.Certificates) <= 0 {
log.Printf("可用证书列表为空,%s 未能启用TLS", r.Addr())
serveResult = server.Serve(ln)
return
}
log.Printf("%s 已启用TLS", r.Addr())
serveResult = server.ServeTLS(ln, "", "")
}()
<-time.After(time.Millisecond * 300)
defer func() {
if serveResult == nil {
r.SetServer(server)
}
}()
return serveResult
}
func (r *ReverseProxyRule) ServerStop() {
reverseProxyServerStoreMu.Lock()
defer reverseProxyServerStoreMu.Unlock()
server := r.GetServer()
if server == nil {
return
}
server.Close()
r.SetServer(nil)
}
func (r *ReverseProxyRule) initDomainsMap() error {
r.domainsMap = &sync.Map{}
for i := range r.ProxyList {
for j := range r.ProxyList[i].Domains {
_, loaded := r.domainsMap.LoadOrStore(r.ProxyList[i].Domains[j], &r.ProxyList[i])
if loaded {
return fmt.Errorf("前端域名[%s]冲突", r.ProxyList[i].Domains[j])
}
}
}
return nil
}
func (r *SubReverProxyRule) initOnceExec() {
r.initOnce.Do(func() {
r.locationsCount = len(r.Locations)
r.InitTrustedProxyCIDRs()
r.locationMutex = &sync.Mutex{}
})
}
func (r *SubReverProxyRule) GetLocation() string {
r.initOnceExec()
r.locationMutex.Lock()
defer func() {
r.locationIndex++
r.locationMutex.Unlock()
}()
if r.locationsCount == 0 {
return ""
}
return r.Locations[r.locationIndex%uint64(r.locationsCount)]
}
func (r *SubReverProxyRule) BasicAuthHandler(c *gin.Context) bool {
if !r.EnableBasicAuth || r.BasicAuthUser == "" {
return true
}
realm := "Basic realm=" + strconv.Quote("Authorization Required")
pairs := ginutils.ProcessAccounts(gin.Accounts{r.BasicAuthUser: r.BasicAuthPasswd})
user, found := pairs.SearchCredential(c.GetHeader("Authorization"))
if !found {
// Credentials doesn't match, we return 401 and abort handlers chain.
c.Header("WWW-Authenticate", realm)
c.AbortWithStatus(http.StatusUnauthorized)
return false
}
c.Set("user", user)
return true
}
func (r *SubReverProxyRule) InitTrustedProxyCIDRs() error {
var res []*net.IPNet
for i := range r.TrustedCIDRsStrList {
if strings.TrimSpace(r.TrustedCIDRsStrList[i]) == "" {
continue
}
_, cidr, err := net.ParseCIDR(r.TrustedCIDRsStrList[i])
if err != nil {
return fmt.Errorf("[%s]网段格式有误", r.TrustedCIDRsStrList[i])
}
res = append(res, cidr)
}
r.TrustedProxyCIDRs = res
return nil
}
func (r *SubReverProxyRule) ClientIP(c *gin.Context) string {
remoteIP := net.ParseIP(c.RemoteIP())
if remoteIP == nil {
return ""
}
trusted := r.isTrustedProxy(remoteIP)
if trusted && r.ForwardedByClientIP && r.RemoteIPHeaders != nil {
for _, headerName := range r.RemoteIPHeaders {
ip, valid := r.validateHeader(c.Request.Header.Get(headerName))
if valid {
return ip
}
}
}
return remoteIP.String()
}
func (r *SubReverProxyRule) validateHeader(header string) (clientIP string, valid bool) {
if header == "" {
return "", false
}
items := strings.Split(header, ",")
for i := len(items) - 1; i >= 0; i-- {
ipStr := strings.TrimSpace(items[i])
ip := net.ParseIP(ipStr)
if ip == nil {
break
}
if (i == 0) || (!r.isTrustedProxy(ip)) {
return ipStr, true
}
}
return "", false
}
func (r *SubReverProxyRule) isTrustedProxy(ip net.IP) bool {
r.initOnceExec()
if r.TrustedProxyCIDRs == nil {
return false
}
for _, cidr := range r.TrustedProxyCIDRs {
if cidr.Contains(ip) {
return true
}
}
return false
}
func (r *ReverseProxyRule) Addr() string {
return fmt.Sprintf("%s:%d", r.ListenIP, r.ListenPort)
}
type LogItem struct {
ProxyKey string
ClientIP string
LogContent string
LogTime string
}
// 2006-01-02 15:04:05
func WebLogConvert(lg *logsbuffer.LogItem) any {
l := LogItem{
LogContent: lg.Content,
LogTime: time.Unix(lg.Timestamp/int64(time.Second), 0).Format("2006-01-02 15:04:05")}
return l
}
func (r *ReverseProxyRule) GetLastLogs() map[string][]any {
res := make(map[string][]any)
res["default"] = r.DefaultProxy.GetLogsBuffer().GetLastLogs(WebLogConvert, r.DefaultProxy.WebListShowLastLogMaxCount)
for i := range r.ProxyList {
res[r.ProxyList[i].Key] = r.ProxyList[i].GetLogsBuffer().GetLastLogs(
WebLogConvert, r.ProxyList[i].WebListShowLastLogMaxCount)
}
return res
}
//------------------------------------------------------------
func GetReverseProxyRuleList() []*ReverseProxyRule {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var resList []*ReverseProxyRule
for i := range programConfigure.ReverseProxyRuleList {
programConfigure.ReverseProxyRuleList[i].Init()
rule := programConfigure.ReverseProxyRuleList[i]
resList = append(resList, &rule)
}
return resList
}
func GetReverseProxyRuleByKey(ruleKey string) *ReverseProxyRule {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
ruleIndex := -1
for i := range programConfigure.ReverseProxyRuleList {
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
ruleIndex = i
break
}
}
if ruleIndex == -1 {
return nil
}
res := programConfigure.ReverseProxyRuleList[ruleIndex]
return &res
}
func ReverseProxyRuleListAdd(rule *ReverseProxyRule) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
programConfigure.ReverseProxyRuleList = append(programConfigure.ReverseProxyRuleList, *rule)
return Save()
}
func ReverseProxyRuleListDelete(ruleKey string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
ruleIndex := -1
for i := range programConfigure.ReverseProxyRuleList {
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
ruleIndex = i
break
}
}
if ruleIndex == -1 {
return fmt.Errorf("找不到需要删除的反向代理任务")
}
programConfigure.ReverseProxyRuleList = DeleteReverseProxyRuleListlice(programConfigure.ReverseProxyRuleList, ruleIndex)
return Save()
}
func EnableReverseProxyRuleByKey(ruleKey string, enable bool) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
ruleIndex := -1
for i := range programConfigure.ReverseProxyRuleList {
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
ruleIndex = i
break
}
}
if ruleIndex == -1 {
return fmt.Errorf("开关反向代理规则失败,ruleKey %s 未找到", ruleKey)
}
programConfigure.ReverseProxyRuleList[ruleIndex].Enable = enable
return Save()
}
func EnableReverseProxySubRule(ruleKey, proxyKey string, enable bool) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
ruleIndex := -1
for i := range programConfigure.ReverseProxyRuleList {
if programConfigure.ReverseProxyRuleList[i].RuleKey == ruleKey {
ruleIndex = i
break
}
}
if ruleIndex == -1 {
return fmt.Errorf("开关反向代理子规则失败,ruleKey %s 未找到", ruleKey)
}
proxyIndex := -1
for i := range programConfigure.ReverseProxyRuleList[ruleIndex].ProxyList {
if programConfigure.ReverseProxyRuleList[ruleIndex].ProxyList[i].Key == proxyKey {
proxyIndex = i
break
}
}
if proxyIndex == -1 {
return fmt.Errorf("开关反向代理子规则失败,proxyKey %s 未找到", proxyKey)
}
programConfigure.ReverseProxyRuleList[ruleIndex].ProxyList[proxyIndex].Enable = enable
return Save()
}
func UpdateReverseProxyRulet(rule ReverseProxyRule) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
ruleIndex := -1
for i := range programConfigure.ReverseProxyRuleList {
if programConfigure.ReverseProxyRuleList[i].RuleKey == rule.RuleKey {
ruleIndex = i
break
}
}
if ruleIndex == -1 {
return fmt.Errorf("找不到需要更新的反向代理规则")
}
// rule.RuleKey = programConfigure.ReverseProxyRuleList[ruleIndex].RuleKey
programConfigure.ReverseProxyRuleList[ruleIndex] = rule
return Save()
}
func DeleteReverseProxyRuleListlice(a []ReverseProxyRule, deleteIndex int) []ReverseProxyRule {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
================================================
FILE: config/safecheck.go
================================================
// Copyright 2022 gdy, 272288813@qq.com
package config
import (
"time"
)
func SafeCheck(mode, ip string) bool {
switch mode {
case "whitelist":
//log.Printf("whitelist")
return whiteListCheck(ip)
case "blacklist":
//log.Printf("blacklist")
return blackListCheck(ip)
default:
return false
}
}
func whiteListCheck(ip string) bool {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
if programConfigure == nil {
return false
}
for _, item := range programConfigure.WhiteListConfigure.WhiteList {
if !item.Contains(ip) {
continue
}
itemEffectiveTime, err := time.ParseInLocation("2006-01-02 15:04:05", item.EffectiveTime, time.Local)
if err != nil {
return false
}
if time.Since(itemEffectiveTime) < 0 {
//log.Printf("CCC")
return true
}
return false
}
//log.Printf("DDDD")
return false
}
func blackListCheck(ip string) bool {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
if programConfigure == nil {
return true
}
for _, item := range programConfigure.BlackListConfigure.BlackList {
if !item.Contains(ip) {
continue
}
itemEffectiveTime, err := time.ParseInLocation("2006-01-02 15:04:05", item.EffectiveTime, time.Local)
if err != nil {
return true
}
if time.Since(itemEffectiveTime) < 0 {
return false
}
return true
}
return true
}
================================================
FILE: config/sslcertficate.go
================================================
package config
import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"fmt"
"log"
"strings"
"time"
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
)
type SSLCertficate struct {
Key string `json:"Key"`
Enable bool `json:"Enable"`
Remark string `json:"Remark"` //备注
CertBase64 string `json:"CertBase64"`
KeyBase64 string `json:"KeyBase64"`
AddTime string `json:"AddTime"` //添加时间
CertsInfo *[]CertInfo `json:"-"`
//---------------------
Certificate *tls.Certificate `json:"-"`
}
func (s *SSLCertficate) Init() error {
tc, err := CreateX509KeyPairByBase64Str(s.CertBase64, s.KeyBase64)
if err != nil {
return fmt.Errorf("CreateX509KeyPairByBase64Str error:%s", err.Error())
}
domainsInfo, err := GetCertDomainInfo(tc)
if err != nil {
return fmt.Errorf("GetCertDomainInfo error:%s", err.Error())
}
s.Certificate = tc
s.CertsInfo = domainsInfo
return nil
}
// GetOnlyDomain 返回证书第一条域名
func (s *SSLCertficate) GetFirstDomain() string {
if s.CertsInfo == nil {
return ""
}
if len(*s.CertsInfo) <= 0 {
return ""
}
if len((*s.CertsInfo)[0].Domains) <= 0 {
return ""
}
return (*s.CertsInfo)[0].Domains[0]
}
func CreateX509KeyPairByBase64Str(certBase64, keyBase64 string) (*tls.Certificate, error) {
crtBytes, err := base64.StdEncoding.DecodeString(certBase64)
if err != nil {
return nil, fmt.Errorf("certBase64 decode error:%s", err.Error())
}
keyBytes, err := base64.StdEncoding.DecodeString(keyBase64)
if err != nil {
return nil, fmt.Errorf("keyBase64 decode error:%s", err.Error())
}
cert, err := tls.X509KeyPair(crtBytes, keyBytes)
if err != nil {
return nil, fmt.Errorf("create X509KeyPair error:%s", err.Error())
}
return &cert, nil
}
type CertInfo struct {
Domains []string
NotBeforeTime string `json:"NotBeforeTime"` //time.Time
NotAfterTime string `json:"NotAfterTime"` //time.Time
}
func GetCertDomainInfo(cert *tls.Certificate) (*[]CertInfo, error) {
if cert == nil {
return nil, fmt.Errorf("cert == nil")
}
var res []CertInfo
for i := range cert.Certificate {
xx, err := x509.ParseCertificate(cert.Certificate[i])
if err != nil {
continue
}
ds := GetDomainsTrimSpace(xx.DNSNames)
if len(ds) == 0 {
continue
}
info := CertInfo{Domains: ds, NotBeforeTime: xx.NotBefore.Format("2006-01-02 15:04:05"), NotAfterTime: xx.NotAfter.Format("2006-01-02 15:04:05")}
res = append(res, info)
}
return &res, nil
}
func GetCertDomains(cert *tls.Certificate) []string {
var res []string
if cert == nil {
return res
}
for i := range cert.Certificate {
xx, err := x509.ParseCertificate(cert.Certificate[i])
if err != nil {
continue
}
for j := range xx.DNSNames {
d := strings.TrimSpace(xx.DNSNames[j])
if d == "" {
continue
}
res = append(res, d)
}
}
return res
}
// 除去空域名
func GetDomainsTrimSpace(dst []string) []string {
var res []string
for i := range dst {
if strings.TrimSpace(dst[i]) == "" {
continue
}
res = append(res, strings.TrimSpace(dst[i]))
}
return res
}
func GetDomainsStrByDomains(dst []string) string {
var res strings.Builder
for i := range dst {
d := strings.TrimSpace(dst[i])
if d == "" {
continue
}
if res.Len() > 0 {
res.WriteString(",")
}
res.WriteString(d)
}
return res.String()
}
//---------------------------------
func SSLCertficateListInit() {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var err error
for i := range programConfigure.SSLCertficateList {
err = programConfigure.SSLCertficateList[i].Init()
if err != nil {
log.Printf("SSLCertficateListInit [%s]err:%s", programConfigure.SSLCertficateList[i].Key, err.Error())
}
}
}
func GetSSLCertficateList() []SSLCertficate {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var res []SSLCertficate
if programConfigure == nil {
return res
}
for i := range programConfigure.SSLCertficateList {
res = append(res, programConfigure.SSLCertficateList[i])
}
return res
}
func SSLCertficateListAdd(s *SSLCertficate) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
//************
//重复检测
for i := range programConfigure.SSLCertficateList {
if programConfigure.SSLCertficateList[i].CertBase64 == s.CertBase64 {
return fmt.Errorf("绑定域名[%s]的相同证书已存在,请勿重复添加", (*s.CertsInfo)[0].Domains[0])
}
if programConfigure.SSLCertficateList[i].GetFirstDomain() != "" &&
programConfigure.SSLCertficateList[i].GetFirstDomain() == s.GetFirstDomain() {
return fmt.Errorf("绑定域名[%s]的证书已存在,如果要添加新证书请先手动删除旧证书", (*s.CertsInfo)[0].Domains[0])
}
}
//************
if s.Key == "" {
s.Key = stringsp.GetRandomString(8)
}
s.AddTime = time.Now().Format("2006-01-02 15:04:05")
s.Enable = true
programConfigure.SSLCertficateList = append(programConfigure.SSLCertficateList, *s)
return Save()
}
func SSLCertficateListDelete(key string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
deleteIndex := -1
for i := range programConfigure.SSLCertficateList {
if programConfigure.SSLCertficateList[i].Key == key {
deleteIndex = i
break
}
}
if deleteIndex < 0 {
return fmt.Errorf("key:%s 不存在", key)
}
programConfigure.SSLCertficateList = DeleteSSLCertficateListslice(programConfigure.SSLCertficateList, deleteIndex)
return Save()
}
func SSLCertficateEnable(key string, enable bool) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.SSLCertficateList {
if programConfigure.SSLCertficateList[i].Key == key {
index = i
break
}
}
if index < 0 {
return fmt.Errorf("key:%s 不存在", key)
}
programConfigure.SSLCertficateList[index].Enable = enable
return Save()
}
func SSLCertficateAlterRemark(key, remark string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.SSLCertficateList {
if programConfigure.SSLCertficateList[i].Key == key {
index = i
break
}
}
if index < 0 {
return fmt.Errorf("key:%s 不存在", key)
}
programConfigure.SSLCertficateList[index].Remark = remark
return Save()
}
func DeleteSSLCertficateListslice(a []SSLCertficate, deleteIndex int) []SSLCertficate {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
func GetValidSSLCertficateList() []tls.Certificate {
var res []tls.Certificate
var gdnRes []tls.Certificate
sslListCache := GetSSLCertficateList()
for _, s := range sslListCache {
if !s.Enable {
continue
}
if strings.HasPrefix(s.GetFirstDomain(), "*.") {
gdnRes = append(gdnRes, *s.Certificate)
continue
}
res = append(res, *s.Certificate)
}
res = append(res, gdnRes...)
return res
}
================================================
FILE: config/whitelist.go
================================================
// Copyright 2022 gdy, 272288813@qq.com
package config
import (
"fmt"
"net"
"strings"
"time"
)
type WhiteListConfigure struct {
BaseConfigure WhiteListBaseConfigure `json:"BaseConfigure"`
WhiteList []WhiteListItem `json:"WhiteList"` //白名单列表
}
type WhiteListItem struct {
IP string `json:"IP"`
EffectiveTime string `json:"Effectivetime"` //有效时间
NetIP net.IP `json:"-"`
Cidr *net.IPNet `json:"-"`
}
func (w *WhiteListItem) Contains(ip string) bool {
netIP := net.ParseIP(ip)
if netIP == nil {
return false
}
if w.NetIP != nil {
return w.NetIP.Equal(netIP)
}
if w.Cidr != nil {
return w.Cidr.Contains(netIP)
}
return false
}
type WhiteListBaseConfigure struct {
URL string `json:"URL"`
ActivelifeDuration int32 `json:"ActivelifeDuration"` //有效期限,小时
BasicAccount string `json:"BasicAccount"`
BasicPassword string `json:"BasicPassword"`
}
func GetWhiteListBaseConfigure() WhiteListBaseConfigure {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
return programConfigure.WhiteListConfigure.BaseConfigure
}
func SetWhiteListBaseConfigure(activelifeDuration int32, url, account, password string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
programConfigure.WhiteListConfigure.BaseConfigure.URL = url
programConfigure.WhiteListConfigure.BaseConfigure.ActivelifeDuration = activelifeDuration
programConfigure.WhiteListConfigure.BaseConfigure.BasicAccount = account
programConfigure.WhiteListConfigure.BaseConfigure.BasicPassword = password
return Save()
}
func GetWhiteList() []WhiteListItem {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
WhiteListFlush(false)
var resList []WhiteListItem
if programConfigure == nil {
return resList
}
for i := range programConfigure.WhiteListConfigure.WhiteList {
resList = append(resList, programConfigure.WhiteListConfigure.WhiteList[i])
}
return resList
}
func WhiteListInit() {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var netIP net.IP
var cidr *net.IPNet
for i := range programConfigure.WhiteListConfigure.WhiteList {
netIP = nil
cidr = nil
if strings.Contains(programConfigure.WhiteListConfigure.WhiteList[i].IP, "/") {
_, cidr, _ = net.ParseCIDR(programConfigure.WhiteListConfigure.WhiteList[i].IP)
} else {
netIP = net.ParseIP(programConfigure.WhiteListConfigure.WhiteList[i].IP)
}
programConfigure.WhiteListConfigure.WhiteList[i].Cidr = cidr
programConfigure.WhiteListConfigure.WhiteList[i].NetIP = netIP
}
}
func WhiteListAdd(ip string, activelifeDuration int32) (string, error) {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
var err error
var netIP net.IP = nil
var cidr *net.IPNet = nil
if strings.Contains(ip, "/") {
_, cidr, err = net.ParseCIDR(ip)
if err != nil {
return "", fmt.Errorf("网段格式有误,转换出错:%s", err.Error())
}
} else {
netIP = net.ParseIP(ip)
if netIP == nil {
return "", fmt.Errorf("IP格式有误")
}
}
if activelifeDuration <= 0 {
activelifeDuration = programConfigure.WhiteListConfigure.BaseConfigure.ActivelifeDuration
}
EffectiveTimeStr := time.Now().Add(time.Hour * time.Duration(activelifeDuration)).Format("2006-01-02 15:04:05")
for i, ipr := range programConfigure.WhiteListConfigure.WhiteList {
if ipr.IP == ip {
programConfigure.WhiteListConfigure.WhiteList[i].EffectiveTime = EffectiveTimeStr
return EffectiveTimeStr, Save()
}
}
item := WhiteListItem{IP: ip, EffectiveTime: EffectiveTimeStr, NetIP: netIP, Cidr: cidr}
programConfigure.WhiteListConfigure.WhiteList = append(programConfigure.WhiteListConfigure.WhiteList, item)
return EffectiveTimeStr, Save()
}
func WhiteListDelete(ip string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
removeCount := 0
CONTINUECHECK:
removeIndex := -1
for i, ipr := range programConfigure.WhiteListConfigure.WhiteList {
if ipr.IP == ip {
removeIndex = i
break
}
}
if removeIndex >= 0 {
removeCount++
programConfigure.WhiteListConfigure.WhiteList = DeleteWhiteListlice(programConfigure.WhiteListConfigure.WhiteList, removeIndex)
goto CONTINUECHECK
}
if removeCount == 0 {
return nil
}
return Save()
}
func WhiteListFlush(lock bool) error {
if lock {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
}
removeCount := 0
CONTINUECHECK:
removeIndex := -1
for i, ipr := range programConfigure.WhiteListConfigure.WhiteList {
ipat, err := time.ParseInLocation("2006-01-02 15:04:05", ipr.EffectiveTime, time.Local)
if err != nil { //有效时间格式有误,当失效处理
removeIndex = i
break
}
if time.Since(ipat) > 0 {
removeIndex = i
break
}
}
if removeIndex >= 0 {
removeCount++
programConfigure.WhiteListConfigure.WhiteList = DeleteWhiteListlice(programConfigure.WhiteListConfigure.WhiteList, removeIndex)
goto CONTINUECHECK
}
if removeCount == 0 {
return nil
}
return Save()
}
func DeleteWhiteListlice(a []WhiteListItem, deleteIndex int) []WhiteListItem {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
================================================
FILE: config/wol.go
================================================
package config
import (
"fmt"
"github.com/gdy666/lucky/thirdlib/gdylib/netinterfaces"
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
"github.com/gdy666/lucky/thirdlib/go-wol"
)
type WOLDevice struct {
Key string
DeviceName string
MacList []string
BroadcastIPs []string
Port int
Relay bool //交给中继设备发送
Repeat int //重复发送次数
}
func (d *WOLDevice) WakeUp() error {
return WakeOnLan(d.MacList, d.BroadcastIPs, d.Port, d.Repeat)
}
func WakeOnLan(macList []string, broadcastIps []string, port, repeat int) (err error) {
globalBroadcastList := netinterfaces.GetGlobalIPv4BroadcastList()
matchCount := 0
defer func() {
if matchCount <= 0 {
err = fmt.Errorf("找不到匹配的局域网广播IP,未能发送唤醒指令")
}
}()
if len(broadcastIps) > 0 {
for _, bcst := range broadcastIps {
bcstOk := stringsp.StrIsInList(bcst, globalBroadcastList)
if !bcstOk {
continue
}
matchCount++
for _, mac := range macList {
wol.WakeUpRepeat(mac, bcst, "", port, repeat)
}
}
return
}
for _, bcst := range globalBroadcastList {
matchCount++
for _, mac := range macList {
wol.WakeUpRepeat(mac, bcst, "", port, repeat)
}
}
return
}
//----------------------------------------
func GetWOLDeviceByKey(key string) *WOLDevice {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.WOLDeviceList {
if programConfigure.WOLDeviceList[i].Key == key {
index = i
break
}
}
if index < 0 {
return nil
}
device := programConfigure.WOLDeviceList[index]
return &device
}
func GetWOLDeviceList() []WOLDevice {
programConfigureMutex.RLock()
defer programConfigureMutex.RUnlock()
var res []WOLDevice
if programConfigure == nil {
return res
}
for i := range programConfigure.WOLDeviceList {
res = append(res, programConfigure.WOLDeviceList[i])
}
return res
}
func WOLDeviceListAdd(d *WOLDevice) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
if d.Key == "" {
d.Key = stringsp.GetRandomString(8)
}
programConfigure.WOLDeviceList = append(programConfigure.WOLDeviceList, *d)
return Save()
}
func WOLDeviceListAlter(d *WOLDevice) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
index := -1
for i := range programConfigure.WOLDeviceList {
if programConfigure.WOLDeviceList[i].Key == d.Key {
index = i
break
}
}
if index < 0 {
return fmt.Errorf("key:%s 不存在", d.Key)
}
programConfigure.WOLDeviceList[index] = *d
return Save()
}
func WOLDeviceListDelete(key string) error {
programConfigureMutex.Lock()
defer programConfigureMutex.Unlock()
deleteIndex := -1
for i := range programConfigure.WOLDeviceList {
if programConfigure.WOLDeviceList[i].Key == key {
deleteIndex = i
break
}
}
if deleteIndex < 0 {
return fmt.Errorf("key:%s 不存在", key)
}
programConfigure.WOLDeviceList = DeleteWOLDeviceListslice(programConfigure.WOLDeviceList, deleteIndex)
return Save()
}
func DeleteWOLDeviceListslice(a []WOLDevice, deleteIndex int) []WOLDevice {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
================================================
FILE: ddns/alidns.go
================================================
package ddns
import (
"bytes"
"fmt"
"log"
"net/http"
"net/url"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/jeessy2/ddns-go/util"
)
const (
alidnsEndpoint string = "https://alidns.aliyuncs.com/"
)
// https://help.aliyun.com/document_detail/29776.html?spm=a2c4g.11186623.6.672.715a45caji9dMA
// Alidns Alidns
type Alidns struct {
DNSCommon
TTL string
}
// AlidnsRecord record
type AlidnsRecord struct {
DomainName string
RecordID string
Value string
}
// AlidnsSubDomainRecords 记录
type AlidnsSubDomainRecords struct {
TotalCount int
DomainRecords struct {
Record []AlidnsRecord
}
}
// AlidnsResp 修改/添加返回结果
type AlidnsResp struct {
RecordID string
RequestID string
}
// Init 初始化
func (ali *Alidns) Init(task *ddnscore.DDNSTaskInfo) {
ali.DNSCommon.Init(task)
if task.TTL == "" {
// 默认600s
ali.TTL = "600"
} else {
ali.TTL = task.TTL
}
ali.SetCreateUpdateDomainFunc(ali.createUpdateDomain)
}
func (ali *Alidns) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
var records AlidnsSubDomainRecords
// 获取当前域名信息
params := domain.GetCustomParams()
params.Set("Action", "DescribeSubDomainRecords")
params.Set("DomainName", domain.DomainName)
params.Set("SubDomain", domain.GetFullDomain())
params.Set("Type", recordType)
err := ali.request(params, &records)
if err != nil {
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, err.Error())
return
}
if records.TotalCount > 0 {
// 默认第一个
recordSelected := records.DomainRecords.Record[0]
if params.Has("RecordId") {
for i := 0; i < len(records.DomainRecords.Record); i++ {
if records.DomainRecords.Record[i].RecordID == params.Get("RecordId") {
recordSelected = records.DomainRecords.Record[i]
}
}
}
// 存在,更新
ali.modify(recordSelected, domain, recordType, ipAddr)
} else {
// 不存在,创建
ali.create(domain, recordType, ipAddr)
}
}
// 创建
func (ali *Alidns) create(domain *ddnscore.Domain, recordType string, ipAddr string) {
params := domain.GetCustomParams()
params.Set("Action", "AddDomainRecord")
params.Set("DomainName", domain.DomainName)
params.Set("RR", domain.GetSubDomain())
params.Set("Type", recordType)
params.Set("Value", ipAddr)
params.Set("TTL", ali.TTL)
var result AlidnsResp
err := ali.request(params, &result)
if err == nil && result.RecordID != "" {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("创建域名失败:\n%v\n", result)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// 修改
func (ali *Alidns) modify(recordSelected AlidnsRecord, domain *ddnscore.Domain, recordType string, ipAddr string) {
// 相同不修改
if recordSelected.Value == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
return
}
params := domain.GetCustomParams()
params.Set("Action", "UpdateDomainRecord")
params.Set("RR", domain.GetSubDomain())
params.Set("RecordId", recordSelected.RecordID)
params.Set("Type", recordType)
params.Set("Value", ipAddr)
params.Set("TTL", ali.TTL)
var result AlidnsResp
err := ali.request(params, &result)
if err == nil && result.RecordID != "" {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("更新域名解析失败:%v\n", result)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// request 统一请求接口
func (ali *Alidns) request(params url.Values, result interface{}) (err error) {
util.AliyunSigner(ali.task.DNS.ID, ali.task.DNS.Secret, ¶ms)
req, err := http.NewRequest(
"GET",
alidnsEndpoint,
bytes.NewBuffer(nil),
)
req.URL.RawQuery = params.Encode()
if err != nil {
log.Println("http.NewRequest失败. Error: ", err)
return
}
client, err := ali.CreateHTTPClient()
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
return httputils.GetAndParseJSONResponseFromHttpResponse(resp, result)
}
================================================
FILE: ddns/baidu.go
================================================
package ddns
import (
"bytes"
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/jeessy2/ddns-go/util"
)
// https://cloud.baidu.com/doc/BCD/s/4jwvymhs7
const (
baiduEndpoint = "https://bcd.baidubce.com"
)
type BaiduCloud struct {
DNSCommon
TTL int
}
// BaiduRecord 单条解析记录
type BaiduRecord struct {
RecordId uint `json:"recordId"`
Domain string `json:"domain"`
View string `json:"view"`
Rdtype string `json:"rdtype"`
TTL int `json:"ttl"`
Rdata string `json:"rdata"`
ZoneName string `json:"zoneName"`
Status string `json:"status"`
}
// BaiduRecordsResp 获取解析列表拿到的结果
type BaiduRecordsResp struct {
TotalCount int `json:"totalCount"`
Result []BaiduRecord `json:"result"`
}
// BaiduListRequest 获取解析列表请求的body json
type BaiduListRequest struct {
Domain string `json:"domain"`
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
}
// BaiduModifyRequest 修改解析请求的body json
type BaiduModifyRequest struct {
RecordId uint `json:"recordId"`
Domain string `json:"domain"`
View string `json:"view"`
RdType string `json:"rdType"`
TTL int `json:"ttl"`
Rdata string `json:"rdata"`
ZoneName string `json:"zoneName"`
}
// BaiduCreateRequest 创建新解析请求的body json
type BaiduCreateRequest struct {
Domain string `json:"domain"`
RdType string `json:"rdType"`
TTL int `json:"ttl"`
Rdata string `json:"rdata"`
ZoneName string `json:"zoneName"`
}
func (baidu *BaiduCloud) Init(task *ddnscore.DDNSTaskInfo) {
baidu.DNSCommon.Init(task)
if task.TTL == "" {
// 默认300s
baidu.TTL = 300
} else {
ttl, err := strconv.Atoi(task.TTL)
if err != nil {
baidu.TTL = 300
} else {
baidu.TTL = ttl
}
}
baidu.SetCreateUpdateDomainFunc(baidu.createUpdateDomain)
}
func (baidu *BaiduCloud) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
var records BaiduRecordsResp
requestBody := BaiduListRequest{
Domain: domain.DomainName,
PageNum: 1,
PageSize: 1000,
}
err := baidu.request("POST", baiduEndpoint+"/v1/domain/resolve/list", requestBody, &records)
if err != nil {
errMsg := "更新失败[001]:\n"
errMsg += err.Error()
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
return
}
find := false
for _, record := range records.Result {
if record.Domain == domain.GetSubDomain() {
//存在就去更新
baidu.modify(record, domain, recordType, ipAddr)
find = true
break
}
}
if !find {
//没找到,去创建
baidu.create(domain, recordType, ipAddr)
}
}
// create 创建新的解析
func (baidu *BaiduCloud) create(domain *ddnscore.Domain, recordType string, ipAddr string) {
var baiduCreateRequest = BaiduCreateRequest{
Domain: domain.GetSubDomain(), //处理一下@
RdType: recordType,
TTL: baidu.TTL,
Rdata: ipAddr,
ZoneName: domain.DomainName,
}
var result BaiduRecordsResp
err := baidu.request("POST", baiduEndpoint+"/v1/domain/resolve/add", baiduCreateRequest, &result)
if err == nil {
//log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
//log.Printf("新增域名解析 %s 失败!", domain)
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, err.Error())
}
}
// modify 更新解析
func (baidu *BaiduCloud) modify(record BaiduRecord, domain *ddnscore.Domain, rdType string, ipAddr string) {
//没有变化直接跳过
if record.Rdata == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
return
}
var baiduModifyRequest = BaiduModifyRequest{
RecordId: record.RecordId,
Domain: record.Domain,
View: record.View,
RdType: rdType,
TTL: record.TTL,
Rdata: ipAddr,
ZoneName: record.ZoneName,
}
var result BaiduRecordsResp
err := baidu.request("POST", baiduEndpoint+"/v1/domain/resolve/edit", baiduModifyRequest, &result)
if err == nil {
//log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
//log.Printf("更新域名解析 %s 失败!", domain)
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, err.Error())
}
}
// request 统一请求接口
func (baidu *BaiduCloud) request(method string, url string, data interface{}, result interface{}) (err error) {
jsonStr := make([]byte, 0)
if data != nil {
jsonStr, _ = json.Marshal(data)
}
req, err := http.NewRequest(
method,
url,
bytes.NewBuffer(jsonStr),
)
if err != nil {
log.Println("http.NewRequest失败. Error: ", err)
return
}
util.BaiduSigner(baidu.task.DNS.ID, baidu.task.DNS.Secret, req)
client, err := baidu.CreateHTTPClient()
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
return httputils.GetAndParseJSONResponseFromHttpResponse(resp, result)
}
================================================
FILE: ddns/callback.go
================================================
package ddns
import (
"fmt"
"net/http"
"strings"
"time"
"github.com/gdy666/lucky/config"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
type Callback struct {
DNSCommon
TTL string
}
// Init 初始化
func (cb *Callback) Init(task *ddnscore.DDNSTaskInfo) {
cb.DNSCommon.Init(task)
if task.TTL == "" {
// 默认600
cb.TTL = "600"
} else {
cb.TTL = task.TTL
}
cb.SetCreateUpdateDomainFunc(cb.createUpdateDomain)
}
func CopyHeadersMap(sm map[string]string) map[string]string {
dm := make(map[string]string)
for k, v := range sm {
dm[k] = v
}
return dm
}
func (cb *Callback) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
url := replacePara(cb.task.DNS.Callback.URL, ipAddr, domain, recordType, cb.TTL)
requestBody := replacePara(cb.task.DNS.Callback.RequestBody, ipAddr, domain, recordType, cb.TTL)
//headersStr := cb.task.DNS.Callback.Headers
var headerStrList []string
for i := range cb.task.DNS.Callback.Headers {
header := replacePara(cb.task.DNS.Callback.Headers[i], ipAddr, domain, recordType, cb.TTL)
headerStrList = append(headerStrList, header)
}
headers := httputils.CreateHeadersMap(headerStrList)
succcssCotentList := []string{}
for i := range cb.task.DNS.Callback.CallbackSuccessContent {
content := replacePara(cb.task.DNS.Callback.CallbackSuccessContent[i], ipAddr, domain, recordType, cb.TTL)
succcssCotentList = append(succcssCotentList, content)
}
callErr := cb.CallbackHttpClientDo(cb.task.DNS.Callback.Method, url, requestBody, headers, succcssCotentList)
if callErr != nil {
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, callErr.Error())
return
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
}
// replacePara 替换参数
func replacePara(orgPara, ipAddr string, domain *ddnscore.Domain, recordType string, ttl string) (newPara string) {
orgPara = strings.ReplaceAll(orgPara, "#{ip}", ipAddr)
orgPara = strings.ReplaceAll(orgPara, "#{domain}", domain.String())
orgPara = strings.ReplaceAll(orgPara, "#{recordType}", recordType)
orgPara = strings.ReplaceAll(orgPara, "#{ttl}", ttl)
for k, v := range domain.GetCustomParams() {
if len(v) == 1 {
orgPara = strings.ReplaceAll(orgPara, "#{"+k+"}", v[0])
}
}
return orgPara
}
func (cb *Callback) CallbackHttpClientDo(method, url, requestBody string, headers map[string]string, callbackSuccessContent []string) error {
globalDDNSConf := config.GetDDNSConfigure()
dnsConf := cb.task.DNS
statusCode, respStr, err := httputils.GetStringGoutDoHttpRequest(
"tcp",
"",
method,
url,
requestBody,
dnsConf.HttpClientProxyType,
dnsConf.HttpClientProxyAddr,
dnsConf.HttpClientProxyUser,
dnsConf.HttpClientProxyPassword,
headers,
!globalDDNSConf.HttpClientSecureVerify,
time.Duration(cb.task.HttpClientTimeout)*time.Second)
if err != nil {
return fmt.Errorf("Callback 调用接口[%s]出错:%s", url, err.Error())
}
if cb.task.DNS.Callback.DisableCallbackSuccessContentCheck {
if statusCode == http.StatusOK {
return nil
}
return fmt.Errorf("调用接口失败:\n statusCode:%d\n%s", statusCode, respStr)
}
//log.Printf("接口[%s]调用响应:%s\n", url, respStr)
//fmt.Printf("statusCode:%d\n", statusCode)
for _, successContent := range callbackSuccessContent {
if strings.Contains(respStr, successContent) {
return nil
}
}
return fmt.Errorf("调用接口失败:\n%s", respStr)
}
================================================
FILE: ddns/cloudflare.go
================================================
package ddns
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
const (
zonesAPI string = "https://api.cloudflare.com/client/v4/zones"
)
// Cloudflare Cloudflare实现
type Cloudflare struct {
DNSCommon
TTL int
}
// CloudflareZonesResp cloudflare zones返回结果
type CloudflareZonesResp struct {
CloudflareStatus
Result []struct {
ID string
Name string
Status string
Paused bool
}
}
// CloudflareRecordsResp records
type CloudflareRecordsResp struct {
CloudflareStatus
Result []CloudflareRecord
}
// CloudflareRecord 记录实体
type CloudflareRecord struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Content string `json:"content"`
Proxied bool `json:"proxied"`
TTL int `json:"ttl"`
}
// CloudflareStatus 公共状态
type CloudflareStatus struct {
Success bool
Messages []string
}
// Init 初始化
func (cf *Cloudflare) Init(task *ddnscore.DDNSTaskInfo) {
cf.DNSCommon.Init(task)
if task.TTL == "" {
// 默认1 auto ttl
cf.TTL = 1
} else {
ttl, err := strconv.Atoi(task.TTL)
if err != nil {
cf.TTL = 1
} else {
cf.TTL = ttl
}
}
cf.SetCreateUpdateDomainFunc(cf.createUpdateDomain)
}
func (cf *Cloudflare) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
result, err := cf.getZones(domain)
if err != nil || len(result.Result) != 1 {
errMsg := "更新失败[001]:\n"
if err != nil {
errMsg += err.Error()
} else {
errMsg += fmt.Sprintf("%v", result)
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
return
}
zoneID := result.Result[0].ID
var records CloudflareRecordsResp
// getDomains 最多更新前50条
err = cf.request(
"GET",
fmt.Sprintf(zonesAPI+"/%s/dns_records?type=%s&name=%s&per_page=50", zoneID, recordType, domain),
nil,
&records,
)
if err != nil || !records.Success {
errMsg := "更新失败[002]:\n"
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
return
}
if len(records.Result) > 0 {
// 更新
cf.modify(records, zoneID, domain, recordType, ipAddr)
} else {
// 新增
cf.create(zoneID, domain, recordType, ipAddr)
}
}
// 创建
func (cf *Cloudflare) create(zoneID string, domain *ddnscore.Domain, recordType string, ipAddr string) {
record := &CloudflareRecord{
Type: recordType,
Name: domain.String(),
Content: ipAddr,
Proxied: false,
TTL: cf.TTL,
}
var status CloudflareStatus
err := cf.request(
"POST",
fmt.Sprintf(zonesAPI+"/%s/dns_records", zoneID),
record,
&status,
)
if err == nil && status.Success {
//log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("创建域名失败:\n%v\n", status)
if err != nil {
errMsg += fmt.Sprintf(":%s", err.Error())
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// 修改
func (cf *Cloudflare) modify(result CloudflareRecordsResp, zoneID string, domain *ddnscore.Domain, recordType string, ipAddr string) {
for _, record := range result.Result {
// 相同不修改
if record.Content == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
continue
}
var status CloudflareStatus
record.Content = ipAddr
record.TTL = cf.TTL
err := cf.request(
"PUT",
fmt.Sprintf(zonesAPI+"/%s/dns_records/%s", zoneID, record.ID),
record,
&status,
)
if err == nil && status.Success {
//log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
//log.Printf("更新域名解析 %s 失败!Messages: %s", domain, status.Messages)
errMsg := fmt.Sprintf("更新域名解析失败:%v\n", status)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
}
// 获得域名记录列表
func (cf *Cloudflare) getZones(domain *ddnscore.Domain) (result CloudflareZonesResp, err error) {
err = cf.request(
"GET",
fmt.Sprintf(zonesAPI+"?name=%s&status=%s&per_page=%s", domain.DomainName, "active", "50"),
nil,
&result,
)
return
}
// request 统一请求接口
func (cf *Cloudflare) request(method string, url string, data interface{}, result interface{}) (err error) {
jsonStr := make([]byte, 0)
if data != nil {
jsonStr, _ = json.Marshal(data)
}
req, err := http.NewRequest(
method,
url,
bytes.NewBuffer(jsonStr),
)
if err != nil {
log.Println("http.NewRequest失败. Error: ", err)
return
}
req.Header.Set("Authorization", "Bearer "+cf.task.DNS.Secret)
req.Header.Set("Content-Type", "application/json")
client, err := cf.CreateHTTPClient()
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
return httputils.GetAndParseJSONResponseFromHttpResponse(resp, result)
}
================================================
FILE: ddns/dns.go
================================================
package ddns
import "github.com/gdy666/lucky/ddnscore.go"
// DNS interface
type DNS interface {
Init(task *ddnscore.DDNSTaskInfo)
// 添加或更新IPv4/IPv6记录
AddUpdateDomainRecords() string
}
================================================
FILE: ddns/dnscommon.go
================================================
package ddns
import (
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/gdy666/lucky/config"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/gdylib/stringsp"
"github.com/miekg/dns"
"golang.org/x/net/idna"
)
type DNSCommon struct {
//Domains *config.Domains
createUpdateDomainFunc func(recordType, ipaddr string, domain *ddnscore.Domain)
task *ddnscore.DDNSTaskInfo
}
func (d *DNSCommon) SetCreateUpdateDomainFunc(f func(recordType, ipaddr string, domain *ddnscore.Domain)) {
d.createUpdateDomainFunc = f
}
func (d *DNSCommon) Init(task *ddnscore.DDNSTaskInfo) {
d.task = task
}
// 添加或更新IPv4/IPv6记录
func (d *DNSCommon) AddUpdateDomainRecords() string {
if d.task.TaskType == "IPv6" {
return d.addUpdateDomainRecords("AAAA")
}
return d.addUpdateDomainRecords("A")
}
func (d *DNSCommon) addUpdateDomainRecords(recordType string) string {
ipAddr, change := d.task.CheckIPChange()
defer ddnscore.DDNSTaskInfoMapUpdateDomainInfo(d.task)
d.task.TaskState.SetIPAddr(ipAddr)
//及时刷新IP地址显示
ddnscore.DDNSTaskInfoMapUpdateIPInfo(d.task)
if ipAddr == "" {
d.task.TaskState.SetDomainUpdateStatus(ddnscore.UpdatePause, "获取公网IP失败")
return ipAddr
}
//var preFaildDomains []ddnscore.Domain
checkDoamins := d.task.TaskState.Domains
//log.Printf("时间间隔:%d秒", time.Since(d.task.TaskState.LastSyncTime)/time.Second)
if time.Since(d.task.TaskState.LastSyncTime) > time.Second*time.Duration(d.task.DNS.ForceInterval-1) {
//log.Printf("DDNS任务[%s]强制更新", d.task.TaskName)
change = true
goto sync
}
//设置原先状态成功的为继续成功
//不成功的就更新
if !change { //公网IP没有改变
checkDoamins = []ddnscore.Domain{}
for i := range d.task.TaskState.Domains { //如果原先状态成功或不改变就刷新时间
if d.task.TaskState.Domains[i].UpdateStatus == ddnscore.UpdatedNothing ||
d.task.TaskState.Domains[i].UpdateStatus == ddnscore.UpdatedSuccess {
d.task.TaskState.Domains[i].SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
ddnscore.DDNSTaskInfoMapUpdateDomainInfo(d.task)
continue
}
checkDoamins = append(checkDoamins, d.task.TaskState.Domains[i])
}
if len(checkDoamins) == 0 {
return ipAddr
}
}
sync:
if change {
syncTime := time.Now()
defer func() {
//记录最近一次同步操作时间
d.task.TaskState.LastSyncTime = syncTime
}()
}
for i := range checkDoamins {
if d.createUpdateDomainFunc == nil {
log.Printf("ddns createUpdateDomainFunc undefine")
break
}
domain := getDomainItem(checkDoamins[i].String(), &d.task.TaskState.Domains)
if domain == nil {
log.Printf("getDomainItem nil")
continue
}
if d.task.DNS.ResolverDoaminCheck {
//<-time.After(time.Second)
domainResolverIPaddr, _ := ResolveDomainAtServerList(recordType, domain.String(), d.task.DNS.DNSServerList)
//log.Printf("domain:%s domainResolverIPaddr:%s ,ipaddr:%s", domain.String(), domainResolverIPaddr, ipAddr)
if domainResolverIPaddr == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
ddnscore.DDNSTaskInfoMapUpdateDomainInfo(d.task)
continue
}
}
//*********
// params := domain.GetCustomParams()
// if params.Has("recordType") {
// recordType = params.Get("recordType")
// }
// if params.Has("recordContent") {
// //ipAddr = params.Get("recordContent")
// recordContent := params.Get("recordContent")
// recordContent = strings.Replace(recordContent, "#{ip}", ipAddr, -1)
// ipAddr = recordContent
// log.Printf("recordType[%s]recordContent[%s]", recordType, recordContent)
// }
//*********
d.createUpdateDomainFunc(recordType, ipAddr, domain)
ddnscore.DDNSTaskInfoMapUpdateDomainInfo(d.task)
}
return ipAddr
}
func getDomainItem(fullDomain string, domains *[]ddnscore.Domain) *ddnscore.Domain {
if domains == nil {
return nil
}
for i, domain := range *domains {
if domain.String() == fullDomain {
return &(*domains)[i]
}
}
return nil
}
//--------------------------------------------------------------------------------------------------
func (d *DNSCommon) CreateHTTPClient() (*http.Client, error) {
ddnsGlobalConf := config.GetDDNSConfigure()
return httputils.CreateHttpClient(
d.task.DNS.GetCallAPINetwork(),
"",
!ddnsGlobalConf.HttpClientSecureVerify,
d.task.DNS.HttpClientProxyType,
d.task.DNS.HttpClientProxyAddr,
d.task.DNS.HttpClientProxyUser,
d.task.DNS.HttpClientProxyPassword,
time.Duration(d.task.HttpClientTimeout)*time.Second)
}
// ---------------------------------------------------------------------------------------------------
func ResolveDomainAtServerList(queryType, domain string, dnsServerList []string) (string, error) {
if len(dnsServerList) == 0 {
if queryType == "AAAA" {
dnsServerList = config.DefaultIPv6DNSServerList
} else {
dnsServerList = config.DefaultIPv4DNSServerList
}
}
//some name that ought to exist, does not exist (NXDOMAIN)
querytype, querytypeOk := dns.StringToType[strings.ToUpper(queryType)]
if !querytypeOk {
return "", fmt.Errorf("queryType error:%s", queryType)
}
if strings.HasPrefix(domain, "*.") {
randomStr := stringsp.GetRandomString(8)
domain = strings.Replace(domain, "*", randomStr, 1)
}
domain = dns.Fqdn(domain)
domain, err := idna.ToASCII(domain)
if err != nil {
return "", fmt.Errorf(` idna.ToASCII(domain) error:%s`, err.Error())
}
m := new(dns.Msg)
m.SetQuestion(domain, querytype)
m.MsgHdr.RecursionDesired = true
c := new(dns.Client)
noExistTimes := 0
for _, dnsServer := range dnsServerList {
c.Net = ""
ipaddr, err := resolveDomain(m, c, dnsServer)
if err != nil {
//log.Printf("[%s]===>[%s][%s] ResolveDomain error:%s", dnsServer, queryType, domain, err.Error())
if strings.Contains(err.Error(), "some name that ought to exist, does not exist (NXDOMAIN)") {
noExistTimes++
if noExistTimes >= 4 {
return "", fmt.Errorf("解析域名[%s][%s]IP失败:noExistTimes", queryType, domain)
}
}
continue
}
return ipaddr, nil
}
return "", fmt.Errorf("解析域名[%s][%s]IP失败", queryType, domain)
}
func resolveDomain(msg *dns.Msg, client *dns.Client, dnsServer string) (string, error) {
Redo:
if in, _, err := client.Exchange(msg, dnsServer); err == nil { // Second return value is RTT, not used for now
if in.MsgHdr.Truncated {
client.Net = "tcp"
goto Redo
}
switch in.MsgHdr.Rcode {
case dns.RcodeServerFailure:
return "", fmt.Errorf("the name server encountered an internal failure while processing this request (SERVFAIL)")
case dns.RcodeNameError:
return "", fmt.Errorf("some name that ought to exist, does not exist (NXDOMAIN)")
case dns.RcodeRefused:
return "", fmt.Errorf("the name server refuses to perform the specified operation for policy or security reasons (REFUSED)")
default:
//fmt.Printf("in.Answer len:%d\n", len(in.Answer))
for _, rr := range in.Answer {
//fmt.Printf("rr.String :%s\n", rr.String())
return strings.Replace(rr.String(), rr.Header().String(), "", -1), nil
}
}
}
return "", fmt.Errorf("DNS server could not be reached")
}
================================================
FILE: ddns/dnspod.go
================================================
package ddns
import (
"fmt"
"net/url"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
const (
recordListAPI string = "https://dnsapi.cn/Record.List"
recordModifyURL string = "https://dnsapi.cn/Record.Modify"
recordCreateAPI string = "https://dnsapi.cn/Record.Create"
)
// https://cloud.tencent.com/document/api/302/8516
// Dnspod 腾讯云dns实现
type Dnspod struct {
DNSCommon
TTL string
}
// DnspodRecordListResp recordListAPI结果
type DnspodRecordListResp struct {
DnspodStatus
Records []struct {
ID string
Name string
Type string
Value string
Enabled string
}
}
// DnspodStatus DnspodStatus
type DnspodStatus struct {
Status struct {
Code string
Message string
}
}
// Init 初始化
func (dnspod *Dnspod) Init(task *ddnscore.DDNSTaskInfo) {
dnspod.DNSCommon.Init(task)
if task.TTL == "" {
// 默认600s
dnspod.TTL = "600"
} else {
dnspod.TTL = task.TTL
}
dnspod.SetCreateUpdateDomainFunc(dnspod.createUpdateDomain)
}
func (dnspod *Dnspod) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
result, err := dnspod.getRecordList(domain, recordType)
if err != nil {
errMsg := "更新失败[001]:\n"
errMsg += err.Error()
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
return
}
if len(result.Records) > 0 {
// 更新
dnspod.modify(result, domain, recordType, ipAddr)
} else {
// 新增
dnspod.create(result, domain, recordType, ipAddr)
}
}
// 创建
func (dnspod *Dnspod) create(result DnspodRecordListResp, domain *ddnscore.Domain, recordType string, ipAddr string) {
params := domain.GetCustomParams()
params.Add("login_token", dnspod.task.DNS.ID+","+dnspod.task.DNS.Secret)
params.Add("domain", domain.DomainName)
params.Add("sub_domain", domain.GetSubDomain())
params.Add("record_type", recordType)
params.Add("value", ipAddr)
params.Add("ttl", dnspod.TTL)
params.Add("format", "json")
if !params.Has("record_line") {
params.Add("record_line", "默认")
}
status, err := dnspod.commonRequest(recordCreateAPI, params, domain)
if err == nil && status.Status.Code == "1" {
//log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("创建域名失败:%v\n", status)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// 修改
func (dnspod *Dnspod) modify(result DnspodRecordListResp, domain *ddnscore.Domain, recordType string, ipAddr string) {
for _, record := range result.Records {
// 相同不修改
if record.Value == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
continue
}
params := domain.GetCustomParams()
params.Add("login_token", dnspod.task.DNS.ID+","+dnspod.task.DNS.Secret)
params.Add("domain", domain.DomainName)
params.Add("sub_domain", domain.GetSubDomain())
params.Add("record_type", recordType)
params.Add("value", ipAddr)
params.Add("ttl", dnspod.TTL)
params.Add("format", "json")
params.Add("record_id", record.ID)
if !params.Has("record_line") {
params.Add("record_line", "默认")
}
status, err := dnspod.commonRequest(recordModifyURL, params, domain)
if err == nil && status.Status.Code == "1" {
//log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("更新域名解析失败:%v\n", status)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
}
// 公共
func (dnspod *Dnspod) commonRequest(apiAddr string, values url.Values, domain *ddnscore.Domain) (status DnspodStatus, err error) {
client, e := dnspod.CreateHTTPClient()
if e != nil {
err = e
return
}
resp, e := client.PostForm(
apiAddr,
values,
)
if e != nil {
err = e
return
}
err = httputils.GetAndParseJSONResponseFromHttpResponse(resp, &status)
return
}
// 获得域名记录列表
func (dnspod *Dnspod) getRecordList(domain *ddnscore.Domain, typ string) (result DnspodRecordListResp, err error) {
params := domain.GetCustomParams()
params.Add("login_token", dnspod.task.DNS.ID+","+dnspod.task.DNS.Secret)
params.Add("domain", domain.DomainName)
params.Add("record_type", typ)
params.Add("sub_domain", domain.GetSubDomain())
params.Add("format", "json")
if !params.Has("record_line") {
params.Add("record_line", "默认")
}
client, e := dnspod.CreateHTTPClient()
if e != nil {
err = e
return
}
resp, err := client.PostForm(
recordListAPI,
params,
)
if err != nil {
err = e
return
}
err = httputils.GetAndParseJSONResponseFromHttpResponse(resp, &result)
return
}
================================================
FILE: ddns/godaddy.go
================================================
package ddns
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
type godaddyRecord struct {
Data string `json:"data"`
Name string `json:"name"`
TTL int `json:"ttl"`
Type string `json:"type"`
}
type godaddyRecords []godaddyRecord
type GoDaddy struct {
DNSCommon
TTL int
header http.Header
client *http.Client
}
// Init 初始化
func (gd *GoDaddy) Init(task *ddnscore.DDNSTaskInfo) {
gd.DNSCommon.Init(task)
// if task.TTL == "" {
// // 默认600s
// gd.TTL = 600
// } else {
// gd.TTL = task.TTL
// }
if task.TTL == "" {
// 默认300s
gd.TTL = 600
} else {
ttl, err := strconv.Atoi(task.TTL)
if err != nil {
gd.TTL = 600
} else {
gd.TTL = ttl
}
}
gd.header = map[string][]string{
"Authorization": {fmt.Sprintf("sso-key %s:%s", task.DNS.ID, task.DNS.Secret)},
"Content-Type": {"application/json"},
}
//g.throttle, _ = util.GetThrottle(55)
gd.client, _ = gd.CreateHTTPClient()
gd.SetCreateUpdateDomainFunc(gd.createUpdateDomain)
}
func (gd *GoDaddy) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
_, err := gd.sendReq(http.MethodPut, recordType, domain, &godaddyRecords{godaddyRecord{
Data: ipAddr,
Name: domain.SubDomain,
TTL: gd.TTL,
Type: recordType,
}})
if err != nil {
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, err.Error())
}
}
func (gd *GoDaddy) sendReq(method string, rType string, domain *ddnscore.Domain, data any) (*godaddyRecords, error) {
var body *bytes.Buffer
if data != nil {
if buffer, err := json.Marshal(data); err != nil {
return nil, err
} else {
body = bytes.NewBuffer(buffer)
}
}
path := fmt.Sprintf("https://api.godaddy.com/v1/domains/%s/records/%s/%s",
domain.DomainName, rType, domain.SubDomain)
req, err := http.NewRequest(method, path, body)
if err != nil {
return nil, err
}
req.Header = gd.header
resp, err := gd.client.Do(req)
if err != nil {
return nil, err
}
result := &godaddyRecords{}
httputils.GetAndParseJSONResponseFromHttpResponse(resp, result)
return result, nil
}
================================================
FILE: ddns/huawei.go
================================================
package ddns
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/jeessy2/ddns-go/util"
)
const (
huaweicloudEndpoint string = "https://dns.myhuaweicloud.com"
)
// https://support.huaweicloud.com/api-dns/dns_api_64001.html
// Huaweicloud Huaweicloud
type Huaweicloud struct {
DNSCommon
TTL int
}
// HuaweicloudZonesResp zones response
type HuaweicloudZonesResp struct {
Zones []struct {
ID string
Name string
Recordsets []HuaweicloudRecordsets
}
}
// HuaweicloudRecordsResp 记录返回结果
type HuaweicloudRecordsResp struct {
Recordsets []HuaweicloudRecordsets
}
// HuaweicloudRecordsets 记录
type HuaweicloudRecordsets struct {
ID string
Name string `json:"name"`
ZoneID string `json:"zone_id"`
Status string
Type string `json:"type"`
TTL int `json:"ttl"`
Records []string `json:"records"`
}
// Init 初始化
func (hw *Huaweicloud) Init(task *ddnscore.DDNSTaskInfo) {
hw.DNSCommon.Init(task)
if task.TTL == "" {
// 默认300s
hw.TTL = 300
} else {
ttl, err := strconv.Atoi(task.TTL)
if err != nil {
hw.TTL = 300
} else {
hw.TTL = ttl
}
}
hw.SetCreateUpdateDomainFunc(hw.createUpdateDomain)
}
func (hw *Huaweicloud) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
var records HuaweicloudRecordsResp
err := hw.request(
"GET",
fmt.Sprintf(huaweicloudEndpoint+"/v2/recordsets?type=%s&name=%s", recordType, domain),
nil,
&records,
)
if err != nil {
errMsg := "更新失败[001]:\n"
errMsg += err.Error()
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
return
}
find := false
for _, record := range records.Recordsets {
// 名称相同才更新。华为云默认是模糊搜索
if record.Name == domain.String()+"." {
// 更新
hw.modify(record, domain, recordType, ipAddr)
find = true
break
}
}
if !find {
// 新增
hw.create(domain, recordType, ipAddr)
}
}
// 创建
func (hw *Huaweicloud) create(domain *ddnscore.Domain, recordType string, ipAddr string) {
zone, err := hw.getZones(domain)
if err != nil {
return
}
if len(zone.Zones) == 0 {
log.Println("未能找到公网域名, 请检查域名是否添加")
return
}
zoneID := zone.Zones[0].ID
for _, z := range zone.Zones {
if z.Name == domain.DomainName+"." {
zoneID = z.ID
break
}
}
record := &HuaweicloudRecordsets{
Type: recordType,
Name: domain.String() + ".",
Records: []string{ipAddr},
TTL: hw.TTL,
}
var result HuaweicloudRecordsets
err = hw.request(
"POST",
fmt.Sprintf(huaweicloudEndpoint+"/v2/zones/%s/recordsets", zoneID),
record,
&result,
)
if err == nil && (len(result.Records) > 0 && result.Records[0] == ipAddr) {
//log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("新增域名失败:%v\n", result)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// 修改
func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *ddnscore.Domain, recordType string, ipAddr string) {
// 相同不修改
if len(record.Records) > 0 && record.Records[0] == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
return
}
var request map[string]interface{} = make(map[string]interface{})
request["records"] = []string{ipAddr}
request["ttl"] = hw.TTL
var result HuaweicloudRecordsets
err := hw.request(
"PUT",
fmt.Sprintf(huaweicloudEndpoint+"/v2/zones/%s/recordsets/%s", record.ZoneID, record.ID),
&request,
&result,
)
if err == nil && (len(result.Records) > 0 && result.Records[0] == ipAddr) {
//log.Printf("更新域名解析 %s 成功!IP: %s, 状态: %s", domain, ipAddr, result.Status)
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("更新域名解析:%v\n", result)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// 获得域名记录列表
func (hw *Huaweicloud) getZones(domain *ddnscore.Domain) (result HuaweicloudZonesResp, err error) {
err = hw.request(
"GET",
fmt.Sprintf(huaweicloudEndpoint+"/v2/zones?name=%s", domain.DomainName),
nil,
&result,
)
return
}
// request 统一请求接口
func (hw *Huaweicloud) request(method string, url string, data interface{}, result interface{}) (err error) {
jsonStr := make([]byte, 0)
if data != nil {
jsonStr, _ = json.Marshal(data)
}
req, err := http.NewRequest(
method,
url,
bytes.NewBuffer(jsonStr),
)
if err != nil {
log.Println("http.NewRequest失败. Error: ", err)
return
}
s := util.Signer{
Key: hw.task.DNS.ID,
Secret: hw.task.DNS.Secret,
}
s.Sign(req)
req.Header.Add("content-type", "application/json")
client, err := hw.CreateHTTPClient()
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
return httputils.GetAndParseJSONResponseFromHttpResponse(resp, result)
}
================================================
FILE: ddns/porkbun.go
================================================
package ddns
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
const (
porkbunEndpoint string = "https://porkbun.com/api/json/v3/dns"
)
type Porkbun struct {
DNSCommon
TTL string
}
type PorkbunDomainRecord struct {
Name string `json:"name"` // subdomain
Type string `json:"type"` // record type, e.g. A AAAA CNAME
Content string `json:"content"` // value
Ttl string `json:"ttl"` // default 300
}
type PorkbunResponse struct {
Status string `json:"status"`
}
type PorkbunDomainQueryResponse struct {
*PorkbunResponse
Records []PorkbunDomainRecord `json:"records"`
}
type PorkbunApiKey struct {
AccessKey string `json:"apikey"`
SecretKey string `json:"secretapikey"`
}
type PorkbunDomainCreateOrUpdateVO struct {
*PorkbunApiKey
*PorkbunDomainRecord
}
// Init 初始化
func (pb *Porkbun) Init(task *ddnscore.DDNSTaskInfo) {
pb.DNSCommon.Init(task)
if task.TTL == "" {
// 默认600s
pb.TTL = "600"
} else {
pb.TTL = task.TTL
}
pb.SetCreateUpdateDomainFunc(pb.createUpdateDomain)
}
func (pb *Porkbun) createUpdateDomain(recordType, ipAddr string, domain *ddnscore.Domain) {
var record PorkbunDomainQueryResponse
// 获取当前域名信息
err := pb.request(
porkbunEndpoint+fmt.Sprintf("/retrieveByNameType/%s/%s/%s", domain.DomainName, recordType, domain.SubDomain),
&PorkbunApiKey{
AccessKey: pb.task.DNS.ID,
SecretKey: pb.task.DNS.Secret,
},
&record,
)
if err != nil {
return
}
if record.Status == "SUCCESS" {
if len(record.Records) > 0 {
// 存在,更新
pb.modify(&record, domain, recordType, ipAddr)
} else {
// 不存在,创建
pb.create(domain, recordType, ipAddr)
}
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, "查询现有域名记录失败")
}
}
// 创建
func (pb *Porkbun) create(domain *ddnscore.Domain, recordType string, ipAddr string) {
var response PorkbunResponse
err := pb.request(
porkbunEndpoint+fmt.Sprintf("/create/%s", domain.DomainName),
&PorkbunDomainCreateOrUpdateVO{
PorkbunApiKey: &PorkbunApiKey{
AccessKey: pb.task.DNS.ID,
SecretKey: pb.task.DNS.Secret,
},
PorkbunDomainRecord: &PorkbunDomainRecord{
Name: domain.SubDomain,
Type: recordType,
Content: ipAddr,
Ttl: pb.TTL,
},
},
&response,
)
if err == nil && response.Status == "SUCCESS" {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("新增域名失败:%v\n", response)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// 修改
func (pb *Porkbun) modify(record *PorkbunDomainQueryResponse, domain *ddnscore.Domain, recordType string, ipAddr string) {
// 相同不修改
if len(record.Records) > 0 && record.Records[0].Content == ipAddr {
if domain.UpdateStatus == ddnscore.UpdatedFailed {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
domain.SetDomainUpdateStatus(ddnscore.UpdatedNothing, "")
}
return
}
var response PorkbunResponse
err := pb.request(
porkbunEndpoint+fmt.Sprintf("/editByNameType/%s/%s/%s", domain.DomainName, recordType, domain.SubDomain),
&PorkbunDomainCreateOrUpdateVO{
PorkbunApiKey: &PorkbunApiKey{
AccessKey: pb.task.DNS.ID,
SecretKey: pb.task.DNS.Secret,
},
PorkbunDomainRecord: &PorkbunDomainRecord{
Content: ipAddr,
Ttl: pb.TTL,
},
},
&response,
)
if err == nil && response.Status == "SUCCESS" {
domain.SetDomainUpdateStatus(ddnscore.UpdatedSuccess, "")
} else {
errMsg := fmt.Sprintf("更新域名解析失败:%v\n", response)
if err != nil {
errMsg += err.Error()
}
domain.SetDomainUpdateStatus(ddnscore.UpdatedFailed, errMsg)
}
}
// request 统一请求接口
func (pb *Porkbun) request(url string, data interface{}, result interface{}) (err error) {
jsonStr := make([]byte, 0)
if data != nil {
jsonStr, _ = json.Marshal(data)
}
req, err := http.NewRequest(
"POST",
url,
bytes.NewBuffer(jsonStr),
)
if err != nil {
log.Println("http.NewRequest失败. Error: ", err)
return
}
req.Header.Set("Content-Type", "application/json")
client, e := pb.CreateHTTPClient()
if e != nil {
err = e
return
}
resp, err := client.Do(req)
if err != nil {
return err
}
return httputils.GetAndParseJSONResponseFromHttpResponse(resp, result)
}
================================================
FILE: ddns/worker.go
================================================
package ddns
import (
"log"
"runtime/debug"
"sync"
"time"
"github.com/gdy666/lucky/config"
"github.com/gdy666/lucky/ddnscore.go"
"github.com/gdy666/lucky/thirdlib/gdylib/service"
)
var DDNSService *service.Service
func init() {
DDNSService, _ = service.NewService("ddns")
DDNSService.SetTimerFunc(syncAllDomainsOnce)
DDNSService.SetEventFunc(syncTaskDomainsOnce)
}
// Run 定时运行
func Run(firstDelay time.Duration, delay time.Duration) {
log.Printf("DDNS 第一次运行将等待 %d 秒后运行 (等待网络)", int(firstDelay.Seconds()))
<-time.After(firstDelay)
DDNSService.Start()
}
var wg sync.WaitGroup
// RunOnce RunOnce
func syncAllDomainsOnce(params ...any) {
ddnsTaskList := ddnscore.GetDDNSTaskInfoList()
ddnscore.CleanIPUrlAddrMap()
ddnsConf := config.GetDDNSConfigure()
//log.Printf("批量执行DDNS任务")
taskBeginTime := time.Now()
//fmt.Printf("ddnsTaskList:%v\n", ddnsTaskList)
for index := range ddnsTaskList {
task := ddnsTaskList[index]
if !task.Enable {
continue
}
if time.Since(task.TaskState.LastWorkTime) < time.Second*15 {
//log.Printf("[%s]太接近,忽略", task.TaskName)
continue
}
//log.Printf("task[%s] enable\n", task.TaskName)
wg.Add(1)
go func() {
defer func() {
wg.Done()
recoverErr := recover()
if recoverErr == nil {
return
}
log.Printf("syncDDNSTask[%s]panic:\n%v", task.TaskName, recoverErr)
log.Printf("%s", debug.Stack())
}()
syncDDNSTask(task)
}()
<-time.After(time.Millisecond * 600)
}
wg.Wait()
taskEndTime := time.Now()
usedTime := taskEndTime.Sub(taskBeginTime)
nextTaskTimer := time.Second*time.Duration(ddnsConf.Intervals) - usedTime
//debug.FreeOSMemory()
//log.Printf("syncAllDomainsOnce 任务完成")
DDNSService.Timer = time.NewTimer(nextTaskTimer)
}
func syncTaskDomainsOnce(params ...any) {
serverMsg := (params[1]).(service.ServiceMsg)
taskKey := serverMsg.Params[0].(string)
switch serverMsg.Type {
case "syncDDNSTask":
{
//log.Printf("syncTaskDomainsOnce 单DDNS任务更新:%s", taskKey)
ddnscore.CleanIPUrlAddrMap()
task := ddnscore.GetDDNSTaskInfoByKey(taskKey)
syncDDNSTask(task)
}
default:
return
}
}
func syncDDNSTask(task *ddnscore.DDNSTaskInfo) {
if task == nil {
return
}
var dnsSelected DNS
switch task.DNS.Name {
case "alidns":
dnsSelected = &Alidns{}
case "dnspod":
dnsSelected = &Dnspod{}
case "cloudflare":
dnsSelected = &Cloudflare{}
case "huaweicloud":
dnsSelected = &Huaweicloud{}
case "callback":
dnsSelected = &Callback{}
case "baiducloud":
dnsSelected = &BaiduCloud{}
case "porkbun":
dnsSelected = &Porkbun{}
default:
return
}
dnsSelected.Init(task)
dnsSelected.AddUpdateDomainRecords()
task.ExecWebhook(&task.TaskState)
ddnscore.DDNSTaskInfoMapUpdate(task)
task.TaskState.LastWorkTime = time.Now() //记录最近一次检测时间,防止批量检测和单个检测时间间隔过于接近
//
}
================================================
FILE: ddnscore.go/cache.go
================================================
package ddnscore
import (
"fmt"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/gdy666/lucky/config"
)
var taskInfoMap sync.Map
var taskInfoMapMutex sync.RWMutex
var webLastAccessDDNSTaskListLastTime int64
// 记录最后的前端请求DDNS任务列表时间
func FLushWebLastAccessDDNSTaskListLastTime() {
atomic.StoreInt64(&webLastAccessDDNSTaskListLastTime, time.Now().Unix())
}
// webAccessAvalid 判断前端访问是否处于活跃时间内
func webAccessAvalid() bool {
lastTime := atomic.LoadInt64(&webLastAccessDDNSTaskListLastTime)
return time.Now().Unix()-lastTime <= 5
}
func EnableDDNSTaskByKey(key string, enable bool) error {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
taskInfo, ok := taskInfoMap.Load(key)
if !ok {
return fmt.Errorf("DDNSTaskInfoMap key[%s] no found", key)
}
if enable {
taskInfo.(*DDNSTaskState).SetDomainUpdateStatus(UpdateWaiting, "")
} else {
taskInfo.(*DDNSTaskState).SetDomainUpdateStatus(UpdateStop, "")
}
return config.EnableDDNSTaskByKey(key, enable)
}
func DDNSTaskInfoMapUpdate(task *DDNSTaskInfo) {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
preInfo, ok := taskInfoMap.Load(task.TaskKey)
if ok {
var checkDomains []Domain
//防止有域名被删除
for i, new := range task.TaskState.Domains {
for _, pre := range preInfo.(*DDNSTaskState).Domains {
if strings.Compare(new.String(), pre.String()) == 0 {
checkDomains = append(checkDomains, task.TaskState.Domains[i])
break
}
}
}
task.TaskState.Domains = checkDomains
if len(preInfo.(*DDNSTaskState).Domains) > 0 && preInfo.(*DDNSTaskState).Domains[0].UpdateStatus == UpdateStop {
task.TaskState.SetDomainUpdateStatus(UpdateStop, "")
}
taskInfoMap.Store(task.TaskKey, &task.TaskState)
return
}
}
// 即时更新IP相关数据信息
func DDNSTaskInfoMapUpdateIPInfo(task *DDNSTaskInfo) {
if !webAccessAvalid() {
//log.Printf("前端没有访问,不即时更新")
return
}
//log.Printf("前端没有访问,不即时更新")
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
state, ok := taskInfoMap.Load(task.TaskKey)
if !ok {
return
}
state.(*DDNSTaskState).IpAddr = task.TaskState.IpAddr
state.(*DDNSTaskState).IPAddrHistory = task.TaskState.IPAddrHistory
}
func DDNSTaskInfoMapUpdateDomainInfo(task *DDNSTaskInfo) {
if !webAccessAvalid() {
//log.Printf("前端没有访问,不即时更新")
return
}
//log.Printf("前端有访问,即时更新")
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
state, ok := taskInfoMap.Load(task.TaskKey)
if !ok {
return
}
state.(*DDNSTaskState).Domains = task.TaskState.Domains
}
func DDNSTaskInfoMapDelete(key string) {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
taskInfoMap.Delete(key)
}
func UpdateDomainsStateByTaskKey(key, status, message string) {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
preInfo, ok := taskInfoMap.Load(key)
if !ok {
return
}
preInfo.(*DDNSTaskState).SetDomainUpdateStatus(status, message)
}
func GetDDNSTaskInfoList() []*DDNSTaskInfo {
taskInfoMapMutex.RLock()
defer taskInfoMapMutex.RUnlock()
ddnsTaskList := config.GetDDNSTaskConfigureList()
var res []*DDNSTaskInfo
for i := range ddnsTaskList {
ti := CreateDDNSTaskInfo(ddnsTaskList[i])
res = append(res, ti)
}
return res
}
func GetDDNSTaskInfoByKey(key string) *DDNSTaskInfo {
taskInfoMapMutex.RLock()
defer taskInfoMapMutex.RUnlock()
ddnsConf := config.GetDDNSTaskByKey(key)
if ddnsConf == nil {
return nil
}
info := CreateDDNSTaskInfo(ddnsConf)
return info
}
func CreateDDNSTaskInfo(task *config.DDNSTask) *DDNSTaskInfo {
var res DDNSTaskInfo
res.DDNSTask = *task
info, ok := taskInfoMap.Load(task.TaskKey)
if ok {
res.TaskState = *info.(*DDNSTaskState)
} else {
res.TaskState.Init(res.Domains)
if task.Enable {
res.TaskState.SetDomainUpdateStatus(UpdateWaiting, "")
} else {
res.TaskState.SetDomainUpdateStatus(UpdateStop, "")
}
taskInfoMap.Store(task.TaskKey, &res.TaskState)
}
return &res
}
================================================
FILE: ddnscore.go/domain.go
================================================
package ddnscore
import (
"net/url"
"time"
)
const (
// UpdatedNothing 未改变
UpdatedNothing string = "域名IP和公网IP一致"
// UpdatedFailed 更新失败
UpdatedFailed = "失败"
// UpdatedSuccess 更新成功
UpdatedSuccess = "成功"
// UpdateStop 暂停
UpdateStop = "停止同步"
//UpdatePause 暂停 获取IP失败时暂停
UpdatePause = "暂停同步"
// UpdateWaiting
UpdateWaiting = "等待更新"
)
// Domain 域名实体
type Domain struct {
DomainName string
SubDomain string
CustomParams string
UpdateStatus string // 更新状态
LastUpdateStatusTime string //最后更新状态的时间
Message string
UpdateHistroy []any
}
type UpdateHistroyItem struct {
UpdateStatus string
UpdateTime string
}
func (d *Domain) String() string {
if d.SubDomain != "" {
return d.SubDomain + "." + d.DomainName
}
return d.DomainName
}
// GetFullDomain 返回完整子域名
func (d *Domain) GetFullDomain() string {
if d.SubDomain != "" {
return d.SubDomain + "." + d.DomainName
}
return "@" + "." + d.DomainName
}
// GetCustomParams not be nil
func (d *Domain) GetCustomParams() url.Values {
if d.CustomParams != "" {
q, err := url.ParseQuery(d.CustomParams)
if err == nil {
return q
}
}
return url.Values{}
}
// GetSubDomain 获得子域名,为空返回@
// 阿里云,dnspod需要
func (d *Domain) GetSubDomain() string {
if d.SubDomain != "" {
return d.SubDomain
}
return "@"
}
func (d *Domain) SetDomainUpdateStatus(status string, message string) {
if status != UpdateWaiting {
if status != UpdateStop || d.UpdateStatus != UpdateStop {
d.LastUpdateStatusTime = time.Now().Format("2006-01-02 15:04:05")
// 状态更新历史记录
hi := UpdateHistroyItem{UpdateStatus: string(status), UpdateTime: d.LastUpdateStatusTime}
d.UpdateHistroy = append(d.UpdateHistroy, hi)
if len(d.UpdateHistroy) > 10 {
d.UpdateHistroy = DeleteAnyListlice(d.UpdateHistroy, 0)
}
}
}
d.UpdateStatus = status
d.Message = message
}
================================================
FILE: ddnscore.go/taskinfo.go
================================================
package ddnscore
import (
"io"
"log"
"regexp"
"strings"
"sync"
"time"
"github.com/gdy666/lucky/config"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/gdylib/netinterfaces"
)
// Ipv4Reg IPv4正则
const Ipv4Reg = `((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])`
// Ipv6Reg IPv6正则
const Ipv6Reg = `((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))`
var ipUrlAddrMap sync.Map
type DDNSTaskInfo struct {
config.DDNSTask
TaskState DDNSTaskState `json:"TaskState"`
}
func (d *DDNSTaskInfo) getIpAddr() (result string) {
if d.TaskType == "IPv6" {
return d.getIpv6Addr()
}
return d.getIpv4Addr()
}
// CheckIPChange 检测公网IP是否改变
func (d *DDNSTaskInfo) CheckIPChange() (ipAddr string, change bool) {
ipAddr = d.getIpAddr()
checkIPChange := d.TaskState.IPChangeCheck(ipAddr)
if checkIPChange {
return ipAddr, true
}
//IP没变化
return ipAddr, false
}
// getIpv4Addr 获得IPv4地址
func (d *DDNSTaskInfo) getIpv4Addr() (result string) {
// 判断从哪里获取IP
if d.GetType == "netInterface" {
result = netinterfaces.GetIPFromNetInterface("IPv4", d.NetInterface, d.IPReg)
return
}
ddnsGlobalConf := config.GetDDNSConfigure()
client, err := httputils.CreateHttpClient(
"tcp4",
"",
ddnsGlobalConf.HttpClientSecureVerify,
"",
"",
"",
"",
time.Duration(d.HttpClientTimeout)*time.Second)
if err != nil {
log.Printf("%s", err.Error())
return
}
for _, url := range d.URL {
url = strings.TrimSpace(url)
mapIp, ok := ipUrlAddrMap.Load(url)
if ok {
//log.Printf("URL[%s]已缓存IP[%s]", url, mapIp)
result = mapIp.(string)
return
}
resp, err := client.Get(url)
if err != nil {
//log.Printf("连接失败!%s查看接口能否返回IPv4地址</a>,", url)
continue
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("读取IPv4结果失败! 接口:%s", url)
continue
}
comp := regexp.MustCompile(Ipv4Reg)
result = comp.FindString(string(body))
if result != "" {
ipUrlAddrMap.Store(url, result)
return
}
// else {
// log.Printf("获取IPv4结果失败! 接口: %s ,返回值: %s\n", url, result)
// }
}
log.Printf("所有查询公网IPv4的接口均获取IPv4结果失败,请检查接口或当前网络情况")
return
}
// getIpv6Addr 获得IPv6地址
func (d *DDNSTaskInfo) getIpv6Addr() (result string) {
// 判断从哪里获取IP
if d.GetType == "netInterface" {
result = netinterfaces.GetIPFromNetInterface("IPv6", d.NetInterface, d.IPReg)
return
}
ddnsGlobalConf := config.GetDDNSConfigure()
client, err := httputils.CreateHttpClient(
"tcp6",
"",
!ddnsGlobalConf.HttpClientSecureVerify,
"",
"",
"",
"",
time.Duration(d.HttpClientTimeout)*time.Second)
if err != nil {
log.Printf("%s", err.Error())
return
}
for _, url := range d.URL {
url = strings.TrimSpace(url)
mapIp, ok := ipUrlAddrMap.Load(url)
if ok {
//log.Printf("URL[%s]已缓存IP[%s]", url, mapIp)
result = mapIp.(string)
return
}
resp, err := client.Get(url)
if err != nil {
//log.Printf("连接失败! %s查看接口能否返回IPv6地址 ", url)
continue
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Println("读取IPv6结果失败! 接口: ", url)
continue
}
comp := regexp.MustCompile(Ipv6Reg)
result = comp.FindString(string(body))
if result != "" {
ipUrlAddrMap.Store(url, result)
return
}
}
log.Printf("所有查询公网IPv6的接口均获取IPv6结果失败,请检查接口或当前网络情况")
return
}
func CleanIPUrlAddrMap() {
keys := []string{}
ipUrlAddrMap.Range(func(key, value any) bool {
keys = append(keys, key.(string))
return true
})
for _, k := range keys {
ipUrlAddrMap.Delete(k)
}
}
================================================
FILE: ddnscore.go/taskstate.go
================================================
package ddnscore
import (
"log"
"net/url"
"strings"
"time"
)
// 固定的主域名
var staticMainDomains = []string{"com.cn", "org.cn", "net.cn", "ac.cn", "eu.org"}
// 获取ip失败的次数
// Domains Ipv4/Ipv6 DDNSTaskState
type DDNSTaskState struct {
IpAddr string
Domains []Domain
WebhookCallTime string `json:"WebhookCallTime"` //最后触发时间
WebhookCallResult bool `json:"WebhookCallResult"` //触发结果
WebhookCallErrorMsg string `json:"WebhookCallErrorMsg"` //触发错误信息
LastSyncTime time.Time `json:"-"` //记录最新一次同步操作时间
LastWorkTime time.Time `json:"-"`
IPAddrHistory []any `json:"IPAddrHistory"`
WebhookCallHistroy []any `json:"WebhookCallHistroy"`
}
type IPAddrHistoryItem struct {
IPaddr string
RecordTime string
}
type WebhookCallHistroyItem struct {
CallTime string
CallResult string
}
func (d *DDNSTaskState) SetIPAddr(ipaddr string) {
if d.IpAddr == ipaddr {
return
}
d.IpAddr = ipaddr
hi := IPAddrHistoryItem{IPaddr: ipaddr, RecordTime: time.Now().Local().Format("2006-01-02 15:04:05")}
d.IPAddrHistory = append(d.IPAddrHistory, hi)
if len(d.IPAddrHistory) > 10 {
d.IPAddrHistory = DeleteAnyListlice(d.IPAddrHistory, 0)
}
}
func DeleteAnyListlice(a []any, deleteIndex int) []any {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
func (d *DDNSTaskState) SetDomainUpdateStatus(status string, message string) {
for i := range d.Domains {
d.Domains[i].SetDomainUpdateStatus(status, message)
}
}
func (d *DDNSTaskState) SetWebhookResult(result bool, errMsg string) {
d.WebhookCallResult = result
d.WebhookCallErrorMsg = errMsg
d.WebhookCallTime = time.Now().Format("2006-01-02 15:04:05")
cr := "成功"
if !result {
cr = "出错"
}
hi := WebhookCallHistroyItem{CallResult: cr, CallTime: time.Now().Local().Format("2006-01-02 15:04:05")}
d.WebhookCallHistroy = append(d.WebhookCallHistroy, hi)
if len(d.WebhookCallHistroy) > 10 {
d.WebhookCallHistroy = DeleteAnyListlice(d.WebhookCallHistroy, 0)
}
}
func (d *DDNSTaskState) Init(domains []string) {
d.Domains = d.checkParseDomains(domains)
}
// checkParseDomains 校验并解析用户输入的域名
func (d *DDNSTaskState) checkParseDomains(domainArr []string) (domains []Domain) {
for _, domainStr := range domainArr {
domainStr = strings.TrimSpace(domainStr)
if domainStr != "" {
domain := &Domain{}
dp := strings.Split(domainStr, ":")
dplen := len(dp)
if dplen == 1 { // 自动识别域名
sp := strings.Split(domainStr, ".")
length := len(sp)
if length <= 1 {
log.Println(domainStr, "域名不正确")
continue
}
// 处理域名
domain.DomainName = sp[length-2] + "." + sp[length-1]
// 如包含在org.cn等顶级域名下,后三个才为用户主域名
for _, staticMainDomain := range staticMainDomains {
if staticMainDomain == domain.DomainName {
domain.DomainName = sp[length-3] + "." + domain.DomainName
break
}
}
domainLen := len(domainStr) - len(domain.DomainName)
if domainLen > 0 {
domain.SubDomain = domainStr[:domainLen-1]
} else {
domain.SubDomain = domainStr[:domainLen]
}
} else if dplen == 2 { // 主机记录:域名 格式
sp := strings.Split(dp[1], ".")
length := len(sp)
if length <= 1 {
log.Println(domainStr, "域名不正确")
continue
}
domain.DomainName = dp[1]
domain.SubDomain = dp[0]
} else {
log.Println(domainStr, "域名不正确")
continue
}
// 参数条件
if strings.Contains(domain.DomainName, "?") {
u, err := url.Parse("http://" + domain.DomainName)
if err != nil {
log.Println(domainStr, "域名解析失败")
continue
}
domain.DomainName = u.Host
domain.CustomParams = u.Query().Encode()
}
domains = append(domains, *domain)
}
}
return
}
// Check 检测IP是否有改变
func (state *DDNSTaskState) IPChangeCheck(newAddr string) bool {
if newAddr == "" {
return true
}
// 地址改变
if state.IpAddr != newAddr {
//log.Printf("公网地址改变:[%s]===>[%s]", d.DomainsInfo.IpAddr, newAddr)
//domains.IpAddr = newAddr
return true
}
return false
}
================================================
FILE: ddnscore.go/webhook.go
================================================
package ddnscore
import (
"fmt"
"net/http"
"strings"
"time"
"github.com/gdy666/lucky/config"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
// ExecWebhook 添加或更新IPv4/IPv6记录
func (d *DDNSTaskInfo) ExecWebhook(state *DDNSTaskState) {
if !d.WebhookEnable {
return
}
if state.IpAddr == "" && !d.WebhookCallOnGetIPfail {
return
}
hasUpdate := hasDomainTryToUpdate(&state.Domains)
if d.WebhookURL != "" && (hasUpdate || (state.IpAddr == "" && d.WebhookCallOnGetIPfail)) {
//log.Printf("DDNS任务【%s】触发Webhook", d.TaskName)
nowTime := time.Now().Format("2006-01-02 15:04:05")
url := d.replaceWebhookPara(nowTime, d.WebhookURL)
requestBody := d.replaceWebhookPara(nowTime, d.WebhookRequestBody)
//headersStr := cb.task.DNS.Callback.Headers
var headerStrList []string
for i := range d.WebhookHeaders {
header := d.replaceWebhookPara(nowTime, d.WebhookHeaders[i])
headerStrList = append(headerStrList, header)
}
headers := httputils.CreateHeadersMap(headerStrList)
succcssCotentList := []string{}
for i := range d.WebhookSuccessContent {
content := d.replaceWebhookPara(nowTime, d.WebhookSuccessContent[i])
succcssCotentList = append(succcssCotentList, content)
}
callErr := d.webhookHttpClientDo(d.WebhookMethod, url, requestBody, headers, succcssCotentList)
if callErr != nil {
//log.Printf("WebHook 调用出错:%s", callErr.Error())
state.SetWebhookResult(false, callErr.Error())
return
}
//log.Printf("Webhook 调用成功")
state.SetWebhookResult(true, "")
}
}
func WebhookTest(d *DDNSTaskInfo, url, method, WebhookRequestBody, proxy, addr, user, passwd string, headerList, successContentListraw []string) (string, error) {
nowTime := time.Now().Format("2006-01-02 15:04:05")
url = replaceWebhookTestPara(url, nowTime)
requestBody := replaceWebhookTestPara(WebhookRequestBody, nowTime)
//log.Printf("requestBody:\n%s", requestBody)
//headersStr := cb.task.DNS.Callback.Headers
var headerStrList []string
for i := range headerList {
header := replaceWebhookTestPara(headerList[i], nowTime)
headerStrList = append(headerStrList, header)
}
headers := httputils.CreateHeadersMap(headerStrList)
succcssCotentList := []string{}
for i := range successContentListraw {
content := replaceWebhookTestPara(successContentListraw[i], nowTime)
succcssCotentList = append(succcssCotentList, content)
}
globalDDNSConf := config.GetDDNSConfigure()
proxyType := ""
proxyAddr := ""
proxyUser := ""
proxyPasswd := ""
switch proxy {
case "dns":
{
if d.DNS.HttpClientProxyType != "" && d.DNS.HttpClientProxyAddr != "" {
proxyType = d.DNS.HttpClientProxyType
proxyAddr = d.DNS.HttpClientProxyAddr
proxyUser = d.DNS.HttpClientProxyUser
proxyPasswd = d.DNS.HttpClientProxyPassword
}
}
case "http", "https", "socks5":
{
proxyType = proxy
proxyAddr = addr
proxyUser = user
proxyPasswd = passwd
}
default:
}
//fmt.Printf("proxyType:%s\taddr:%s\t,user[%s]passwd[%s]\n", proxyType, proxyAddr, proxyUser, proxyPasswd)
//dnsConf := cb.task.DNS
_, respStr, err := httputils.GetStringGoutDoHttpRequest(
"tcp",
"",
method,
url,
requestBody,
proxyType,
proxyAddr,
proxyUser,
proxyPasswd,
headers,
!globalDDNSConf.HttpClientSecureVerify,
time.Second*20)
if err != nil {
return "", fmt.Errorf("webhookTest 调用接口[%s]出错:%s", url, err.Error())
}
for _, successContent := range succcssCotentList {
if strings.Contains(respStr, successContent) {
return respStr, nil
}
}
return respStr, fmt.Errorf("接口调用出错,未匹配预设成功返回的字符串")
}
func (d *DDNSTaskInfo) webhookHttpClientDo(method, url, requestBody string, headers map[string]string, callbackSuccessContent []string) error {
globalDDNSConf := config.GetDDNSConfigure()
proxyType := ""
proxyAddr := ""
proxyUser := ""
proxyPasswd := ""
switch d.WebhookProxy {
case "dns":
{
if d.DNS.HttpClientProxyType != "" && d.DNS.HttpClientProxyAddr != "" {
proxyType = d.DNS.HttpClientProxyType
proxyAddr = d.DNS.HttpClientProxyAddr
proxyUser = d.DNS.HttpClientProxyUser
proxyPasswd = d.DNS.HttpClientProxyPassword
}
}
case "http", "https", "socks5":
{
proxyType = d.WebhookProxy
proxyAddr = d.WebhookProxyAddr
proxyUser = d.WebhookProxyUser
proxyPasswd = d.WebhookProxyPassword
}
default:
}
//dnsConf := cb.task.DNS
statusCode, respStr, err := httputils.GetStringGoutDoHttpRequest(
"tcp",
"",
method,
url,
requestBody,
proxyType,
proxyAddr,
proxyUser,
proxyPasswd,
headers,
!globalDDNSConf.HttpClientSecureVerify,
time.Second*20)
if err != nil {
return fmt.Errorf("webhook 调用接口[%s]出错:%s", url, err.Error())
}
if d.WebhookDisableCallbackSuccessContentCheck {
if statusCode == http.StatusOK {
return nil
}
return fmt.Errorf("webhook调用接口失败:\n statusCode:%d\n%s", statusCode, respStr)
}
for _, successContent := range callbackSuccessContent {
if strings.Contains(respStr, successContent) {
return nil
}
}
return fmt.Errorf("webhook 调用接口失败:\n%s", respStr)
}
// DomainsIsChange
func hasDomainTryToUpdate(domains *[]Domain) bool {
for _, v46 := range *domains {
switch v46.UpdateStatus {
case UpdatedFailed:
return true
case UpdatedSuccess:
return true
default:
}
}
return false
}
// replaceWebhookTestPara WebhookTest替换参数 #{successDomains},#{failedDomains}
func replaceWebhookTestPara(orgPara, nowTime string) (newPara string) {
orgPara = strings.ReplaceAll(orgPara, "#{ipAddr}", "66.66.66.66")
successDomains := "www1.google.com,www2.google.com,www3.google.com,www4.google.com"
failedDomains := "www1.github.com,www2.github.com,www3.github.com,www4.github.com"
successDomainsLine := strings.Replace(successDomains, ",", `\n`, -1)
failedDomainsLine := strings.Replace(failedDomains, ",", `\n`, -1)
orgPara = strings.ReplaceAll(orgPara, "#{successDomains}", successDomains)
orgPara = strings.ReplaceAll(orgPara, "#{failedDomains}", failedDomains)
orgPara = strings.ReplaceAll(orgPara, "#{successDomainsLine}", successDomainsLine)
orgPara = strings.ReplaceAll(orgPara, "#{failedDomainsLine}", failedDomainsLine)
orgPara = strings.ReplaceAll(orgPara, "#{time}", nowTime)
return orgPara
}
// replacePara 替换参数 #{successDomains},#{failedDomains}
func (d *DDNSTaskInfo) replaceWebhookPara(nowTime, orgPara string) (newPara string) {
ipAddrText := d.TaskState.IpAddr
successDomains, failedDomains := d.getDomainsStr(&d.TaskState.Domains)
if ipAddrText == "" {
ipAddrText = "获取IP失败"
successDomains = ""
failedDomains = ""
}
successDomainsLine := strings.Replace(successDomains, ",", `\n`, -1)
failedDomainsLine := strings.Replace(failedDomains, ",", `\n`, -1)
orgPara = strings.ReplaceAll(orgPara, "#{ipAddr}", ipAddrText)
orgPara = strings.ReplaceAll(orgPara, "#{successDomains}", successDomains)
orgPara = strings.ReplaceAll(orgPara, "#{failedDomains}", failedDomains)
orgPara = strings.ReplaceAll(orgPara, "#{successDomainsLine}", successDomainsLine)
orgPara = strings.ReplaceAll(orgPara, "#{failedDomainsLine}", failedDomainsLine)
orgPara = strings.ReplaceAll(orgPara, "#{time}", nowTime)
return orgPara
}
// getDomainsStr 用逗号分割域名,分类域名返回,成功和失败的
func (d *DDNSTaskInfo) getDomainsStr(domains *[]Domain) (string, string) {
var successDomainBuf strings.Builder
var failedDomainsBuf strings.Builder
for _, v46 := range *domains {
if v46.UpdateStatus == UpdatedFailed || (d.Webhook.WebhookCallOnGetIPfail && v46.UpdateStatus == UpdatePause) {
if failedDomainsBuf.Len() > 0 {
failedDomainsBuf.WriteString(",")
}
failedDomainsBuf.WriteString(v46.String())
continue
}
//if v46.UpdateStatus == UpdatedNothing || v46.UpdateStatus == UpdatedSuccess {
if v46.UpdateStatus == UpdatedSuccess {
if successDomainBuf.Len() > 0 {
successDomainBuf.WriteString(",")
}
successDomainBuf.WriteString(v46.String())
}
}
return successDomainBuf.String(), failedDomainsBuf.String()
}
================================================
FILE: debug.go
================================================
//go:build debug
// +build debug
package main
import (
"fmt"
"github.com/gdy666/lucky/thirdlib/gdylib/recoverutil"
)
func init() {
defer func() {
recoverErr := recover()
if recoverErr == nil {
return
}
panicFile := fmt.Sprintf("闪退.log")
recoverutil.RecoverHandler(recoverErr, true, true, panicFile)
}()
}
================================================
FILE: go.mod
================================================
module github.com/gdy666/lucky
go 1.18
require (
github.com/buger/jsonparser v1.1.1
github.com/eclipse/paho.mqtt.golang v1.4.1
github.com/fatedier/golib v0.2.0
github.com/gin-contrib/gzip v0.0.6
github.com/gin-gonic/gin v1.8.1
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/guonaihong/gout v0.3.1
github.com/miekg/dns v1.1.50
github.com/shirou/gopsutil/v3 v3.22.9
github.com/sirupsen/logrus v1.9.0
golang.org/x/net v0.0.0-20221004154528-8021a29435af
)
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.5.0 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect
golang.org/x/text v0.3.8 // indirect
golang.org/x/tools v0.1.12 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
================================================
FILE: go.sum
================================================
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI=
github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
github.com/fatedier/golib v0.2.0 h1:8BxiUcjleBlXBYlTNUllD8KZZHaFU/NP/vP0Yu1Fkpg=
github.com/fatedier/golib v0.2.0/go.mod h1:e2NPpBGUFsHDjXrfP1B5aK3S0+yUeVxgqfc3go3KNj0=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/guonaihong/gout v0.3.1 h1:pj/44Jw0TTmcHF2RjMaCWhKPwCH98YuQejbN15Hts/o=
github.com/guonaihong/gout v0.3.1/go.mod h1:lhje0jRkh/gcIogrG22ENPITo9tylQa3kwD9eVxcDrk=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/shirou/gopsutil/v3 v3.22.9 h1:yibtJhIVEMcdw+tCTbOPiF1VcsuDeTE4utJ8Dm4c5eA=
github.com/shirou/gopsutil/v3 v3.22.9/go.mod h1:bBYl1kjgEJpWpxeHmLI+dVHWtyAwfcmSBLDsp2TNT8A=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A=
github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: main.go
================================================
//Copyright 2022 gdy, 272288813@qq.com
package main
import (
"flag"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/gdy666/lucky/config"
"github.com/gdy666/lucky/ddns"
"github.com/gdy666/lucky/reverseproxy"
"github.com/gdy666/lucky/socketproxy"
)
var (
listenPort = flag.Int("p", 16601, "http Admin Web listen port ")
configureFileURL = flag.String("c", "", "configure file url")
)
var (
runMode = "prod"
version = "dev"
commit = "none"
date = "2022-07-27T17:54:45Z"
)
var runTime time.Time
func init() {
var cstZone = time.FixedZone("CST", 8*3600) // 东八
time.Local = cstZone
}
func main() {
flag.Parse()
config.InitAppInfo(version, date)
err := config.Read(*configureFileURL)
if err != nil {
log.Printf("%s", err.Error())
log.Printf("载入默认配置以及命令行设定的参数")
config.LoadDefault(*listenPort)
if len(*configureFileURL) > 0 {
err = config.Save()
if err != nil {
log.Printf("保存配置到%s出错:%s", *configureFileURL, err.Error())
}
}
}
gcf := config.GetConfig()
config.BlackListInit()
config.WhiteListInit()
config.SSLCertficateListInit()
//fmt.Printf("*gcf:%v\n", *gcf)
socketproxy.SetSafeCheck(config.SafeCheck)
//socketproxy.SetGlobalMaxConnections(gcf.BaseConfigure.GlobalMaxConnections)
//socketproxy.SetGlobalMaxProxyCount(gcf.BaseConfigure.ProxyCountLimit)
config.SetRunMode(runMode)
config.SetVersion(version)
log.Printf("RunMode:%s\n", runMode)
log.Printf("version:%s\tcommit %s, built at %s\n", version, commit, date)
RunAdminWeb(&gcf.BaseConfigure)
runTime = time.Now()
//LoadRuleFromConfigFile(gcf)
config.PortForwardsRuleListInit()
//config.DDNSTaskListTaskDetailsInit()
config.DDNSTaskListConfigureCheck()
ddnsConf := config.GetDDNSConfigure()
if ddnsConf.Enable {
go ddns.Run(time.Duration(ddnsConf.FirstCheckDelay)*time.Second, time.Duration(ddnsConf.Intervals)*time.Second)
}
reverseproxy.InitReverseProxyServer()
//ddns.RunTimer(time.Second, time.Second*30)
//initProxyList()
//*****************
// time.Sleep(time.Microsecond * 50)
// cruuentPath, _ := fileutils.GetCurrentDirectory()
// panicFile := fmt.Sprintf("%s/relayport_panic.log", cruuentPath)
// fileutils.PanicRedirect(panicFile)
//*****************
//main goroutine wait
sigs := make(chan os.Signal, 1)
exit := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
exit <- true
}()
<-exit
}
// func LoadRuleFromConfigFile(pc *config.ProgramConfigure) {
// if pc == nil {
// return
// }
// for i := range pc.RelayRuleList {
// relayRule, err := rule.CreateRuleByConfigureAndOptions(
// pc.RelayRuleList[i].Name,
// pc.RelayRuleList[i].Configurestr,
// pc.RelayRuleList[i].Options)
// if err != nil {
// continue
// }
// relayRule.From = "configureFile" //规则来源
// relayRule.IsEnable = pc.RelayRuleList[i].Enable
// _, e := rule.AddRuleToGlobalRuleList(false, *relayRule)
// if e != nil {
// log.Printf("%s\n", e)
// }
// }
// }
================================================
FILE: module/ddns/conf/ddns.go
================================================
package ddnsconf
import (
"fmt"
"io"
"log"
"regexp"
"strings"
"sync"
"time"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
"github.com/gdy666/lucky/thirdlib/gdylib/netinterfaces"
)
var getDDNSConfigureFunc func() DDNSConfigure
func SetGetDDNSConfigureFunc(f func() DDNSConfigure) {
getDDNSConfigureFunc = f
}
type DDNSConfigure struct {
Enable bool `json:"Enable"`
HttpClientSecureVerify bool `json:"HttpClientSecureVerify"`
FirstCheckDelay int `json:"FirstCheckDelay"` //首次检查延迟时间
Intervals int `json:"Intervals"`
}
type DDNSTask struct {
TaskName string `json:"TaskName"`
TaskKey string `json:"TaskKey"` //添加任务时随机生成,方便管理任务(修改删除)
//规则类型 IPv4/IPv6
TaskType string `json:"TaskType"`
Enable bool
// 获取IP类型 url/netInterface
GetType string `json:"GetType"` //IP获取方式
URL []string `json:"URL"`
NetInterface string `json:"NetInterface"`
IPReg string `json:"IPReg"`
Domains []string `json:"Domains"`
DNS DNSConfig `json:"DNS"`
Webhook
TTL string `json:"TTL"`
HttpClientTimeout int `json:"HttpClientTimeout"`
ModifyTime int64 `json:"ModifyTime"`
}
type Webhook struct {
WebhookEnable bool `json:"WebhookEnable"` //Webhook开关
WebhookCallOnGetIPfail bool `json:"WebhookCallOnGetIPfail"` //获取IP失败时触发Webhook 开关
WebhookURL string `json:"WebhookURL"`
WebhookMethod string `json:"WebhookMethod"`
WebhookHeaders []string `json:"WebhookHeaders"`
WebhookRequestBody string `json:"WebhookRequestBody"`
WebhookDisableCallbackSuccessContentCheck bool `json:"WebhookDisableCallbackSuccessContentCheck"` //禁用成功调用返回检测
WebhookSuccessContent []string `json:"WebhookSuccessContent"` //接口调用成功包含的内容
WebhookProxy string `json:"WebhookProxy"` //使用DNS代理设置 ""表示禁用,"dns"表示使用dns的代理设置
WebhookProxyAddr string `json:"WebhookProxyAddr"` //代理服务器IP
WebhookProxyUser string `json:"WebhookProxyUser"` //代理用户
WebhookProxyPassword string `json:"WebhookProxyPassword"` //代理密码
}
// DNSConfig DNS配置
type DNSConfig struct {
// 名称。如:alidns,webhook
Name string `json:"Name"`
ID string `json:"ID"`
Secret string `json:"Secret"`
ForceInterval int `json:"ForceInterval"` //(秒)即使IP没有变化,到一定时间后依然强制更新或先DNS解析比较IP再更新
ResolverDoaminCheck bool `json:"ResolverDoaminCheck"` //调用callback同步前先解析一次域名,如果IP相同就不同步
DNSServerList []string `json:"DNSServerList"` //DNS服务器列表
CallAPINetwork string `json:"CallAPINetwork"` //空代理tcp, tcp4,tcp6
Callback DNSCallback `json:"Callback"`
HttpClientProxyType string `json:"HttpClientProxyType"` //http client代理服务器设置
HttpClientProxyAddr string `json:"HttpClientProxyAddr"` //代理服务器IP
HttpClientProxyUser string `json:"HttpClientProxyUser"` //代理用户
HttpClientProxyPassword string `json:"HttpClientProxyPassword"` //代理密码
}
func (d *DNSConfig) GetCallAPINetwork() string {
switch d.CallAPINetwork {
case "tcp4", "tcp6":
return d.CallAPINetwork
default:
return "tcp"
}
}
type DNSCallback struct {
URL string `json:"URL"` //请求地址
Method string `json:"Method"` //请求方法
Headers []string `json:"Headers"`
RequestBody string `json:"RequestBody"`
Server string `json:"Server"` //预设服务商
DisableCallbackSuccessContentCheck bool `json:"DisableCallbackSuccessContentCheck"` //禁用成功调用返回检测
CallbackSuccessContent []string `json:"CallbackSuccessContent"` //接口调用成功包含内容
}
// Ipv4Reg IPv4正则
const Ipv4Reg = `((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])`
// Ipv6Reg IPv6正则
const Ipv6Reg = `((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))`
var ipUrlAddrMap sync.Map
func (d *DDNSTask) GetIpAddr() (result string) {
if d.TaskType == "IPv6" {
return d.getIpv6Addr()
}
return d.getIpv4Addr()
}
// getIpv4Addr 获取IPv4地址
func (d *DDNSTask) getIpv4Addr() (result string) {
// 判断从哪里获取IP
if d.GetType == "netInterface" {
result = netinterfaces.GetIPFromNetInterface("IPv4", d.NetInterface, d.IPReg)
return
}
ddnsGlobalConf := getDDNSConfigureFunc()
client, err := httputils.CreateHttpClient(
"tcp4",
"",
ddnsGlobalConf.HttpClientSecureVerify,
"",
"",
"",
"",
time.Duration(d.HttpClientTimeout)*time.Second)
if err != nil {
log.Printf("%s", err.Error())
return
}
for _, url := range d.URL {
url = strings.TrimSpace(url)
mapIp, ok := ipUrlAddrMap.Load(url)
if ok {
//log.Printf("URL[%s]已缓存IP[%s]", url, mapIp)
result = mapIp.(string)
return
}
resp, err := client.Get(url)
if err != nil {
//log.Printf("连接失败!%s查看接口能否返回IPv4地址</a>,", url)
continue
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("读取IPv4结果失败! 接口:%s", url)
continue
}
comp := regexp.MustCompile(Ipv4Reg)
result = comp.FindString(string(body))
if result != "" {
ipUrlAddrMap.Store(url, result)
return
}
// else {
// log.Printf("获取IPv4结果失败! 接口: %s ,返回值: %s\n", url, result)
// }
}
log.Printf("所有查询公网IPv4的接口均获取IPv4结果失败,请检查接口或当前网络情况")
return
}
// getIpv6Addr 获得IPv6地址
func (d *DDNSTask) getIpv6Addr() (result string) {
// 判断从哪里获取IP
if d.GetType == "netInterface" {
result = netinterfaces.GetIPFromNetInterface("IPv6", d.NetInterface, d.IPReg)
return
}
ddnsGlobalConf := getDDNSConfigureFunc()
client, err := httputils.CreateHttpClient(
"tcp6",
"",
!ddnsGlobalConf.HttpClientSecureVerify,
"",
"",
"",
"",
time.Duration(d.HttpClientTimeout)*time.Second)
if err != nil {
log.Printf("%s", err.Error())
return
}
for _, url := range d.URL {
url = strings.TrimSpace(url)
mapIp, ok := ipUrlAddrMap.Load(url)
if ok {
//log.Printf("URL[%s]已缓存IP[%s]", url, mapIp)
result = mapIp.(string)
return
}
resp, err := client.Get(url)
if err != nil {
//log.Printf("连接失败! %s查看接口能否返回IPv6地址 ", url)
continue
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Println("读取IPv6结果失败! 接口: ", url)
continue
}
comp := regexp.MustCompile(Ipv6Reg)
result = comp.FindString(string(body))
if result != "" {
ipUrlAddrMap.Store(url, result)
return
}
}
log.Printf("所有查询公网IPv6的接口均获取IPv6结果失败,请检查接口或当前网络情况")
return
}
func CleanIPUrlAddrMap() {
keys := []string{}
ipUrlAddrMap.Range(func(key, value any) bool {
keys = append(keys, key.(string))
return true
})
for _, k := range keys {
ipUrlAddrMap.Delete(k)
}
}
var checkIPv4URLList = []string{"https://4.ipw.cn", "http://v4.ip.zxinc.org/getip", "https://myip4.ipip.net", "https://www.taobao.com/help/getip.php", "https://ddns.oray.com/checkip", "https://ip.3322.net", "https://v4.myip.la"}
var checkIPv6URLList = []string{"https://6.ipw.cn", "https://ipv6.ddnspod.com", "http://v6.ip.zxinc.org/getip", "https://speed.neu6.edu.cn/getIP.php", "https://v6.ident.me", "https://v6.myip.la"}
func CheckDDNSTaskAvalid(task *DDNSTask) error {
if len(task.URL) == 0 {
if task.TaskType == "IPv6" {
task.URL = checkIPv6URLList
} else {
task.URL = checkIPv4URLList
}
}
switch task.DNS.Name {
case "cloudflare":
if task.DNS.Secret == "" {
return fmt.Errorf("cloudflare token不能为空")
}
case "callback":
if task.DNS.Callback.URL == "" {
return fmt.Errorf("callback URL不能为空")
}
if task.DNS.Callback.Method == "" {
return fmt.Errorf("请选择callback method")
}
default:
if task.DNS.ID == "" || task.DNS.Secret == "" {
return fmt.Errorf("dns服务商相关参数不能为空")
}
}
if len(task.Domains) <= 0 {
return fmt.Errorf("域名列表不能为空")
}
return nil
}
================================================
FILE: module/ddns/ddnscore.go/cache.go
================================================
package ddnscore
import (
"fmt"
"sync"
"sync/atomic"
"time"
ddnsconf "github.com/gdy666/lucky/module/ddns/conf"
"github.com/gdy666/lucky/module/ddns/ddnsgo"
)
var taskInfoMap sync.Map
var taskInfoMapMutex sync.RWMutex
var webLastAccessDDNSTaskListLastTime int64
// 记录最后的前端请求DDNS任务列表时间
func FLushWebLastAccessDDNSTaskListLastTime() {
atomic.StoreInt64(&webLastAccessDDNSTaskListLastTime, time.Now().Unix())
}
// webAccessAvalid 判断前端访问是否处于活跃时间内
func webAccessAvalid() bool {
lastTime := atomic.LoadInt64(&webLastAccessDDNSTaskListLastTime)
return time.Now().Unix()-lastTime <= 5
}
func EnableDDNSTaskByKey(key string, enable bool) error {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
taskInfo, ok := taskInfoMap.Load(key)
if !ok {
return fmt.Errorf("DDNSTaskInfoMap key[%s] no found", key)
}
if enable {
taskInfo.(*DDNSTaskState).SetDomainUpdateStatus(UpdateWaiting, "")
} else {
taskInfo.(*DDNSTaskState).SetDomainUpdateStatus(UpdateStop, "")
}
return ddnsgo.EnableDDNSTaskByKey(key, enable)
}
func DDNSTaskInfoMapUpdate(task *DDNSTaskInfo) bool {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
t := ddnsgo.GetDDNSTaskByKey(task.TaskKey)
if t == nil {
return false
}
if t.ModifyTime > task.ModifyTime {
//fmt.Printf("失效,不刷新\n")
return false
}
task.TaskState.LastWorkTime = time.Now()
taskInfoMap.Store(task.TaskKey, &task.TaskState)
// preInfo, ok := taskInfoMap.Load(task.TaskKey)
// if ok {
// var checkDomains []Domain
// //防止有域名被删除
// for i, new := range task.TaskState.Domains {
// for _, pre := range preInfo.(*DDNSTaskState).Domains {
// if strings.Compare(new.String(), pre.String()) == 0 {
// checkDomains = append(checkDomains, task.TaskState.Domains[i])
// break
// }
// }
// }
// task.TaskState.Domains = checkDomains
// if len(preInfo.(*DDNSTaskState).Domains) > 0 && preInfo.(*DDNSTaskState).Domains[0].UpdateStatus == UpdateStop {
// task.TaskState.SetDomainUpdateStatus(UpdateStop, "")
// }
// task.TaskState.LastWorkTime = time.Now()
// taskInfoMap.Store(task.TaskKey, &task.TaskState)
// return true
// }
return false
}
// 即时更新IP相关数据信息
func DDNSTaskInfoMapUpdateIPInfo(task *DDNSTaskInfo) {
if !webAccessAvalid() {
//log.Printf("前端没有访问,不即时更新")
return
}
//log.Printf("前端没有访问,不即时更新")
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
state, ok := taskInfoMap.Load(task.TaskKey)
if !ok {
return
}
state.(*DDNSTaskState).IpAddr = task.TaskState.IpAddr
state.(*DDNSTaskState).IPAddrHistory = task.TaskState.IPAddrHistory
}
func DDNSTaskInfoMapUpdateDomainInfo(task *DDNSTaskInfo) {
if !webAccessAvalid() {
//log.Printf("前端没有访问,不即时更新")
return
}
//log.Printf("前端有访问,即时更新")
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
state, ok := taskInfoMap.Load(task.TaskKey)
if !ok {
return
}
state.(*DDNSTaskState).Domains = task.TaskState.Domains
}
func DDNSTaskInfoMapDelete(key string) {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
taskInfoMap.Delete(key)
}
func UpdateDomainsStateByTaskKey(key, status, message string) {
taskInfoMapMutex.Lock()
defer taskInfoMapMutex.Unlock()
preInfo, ok := taskInfoMap.Load(key)
if !ok {
return
}
preInfo.(*DDNSTaskState).SetDomainUpdateStatus(status, message)
}
func GetDDNSTaskInfoList() []*DDNSTaskInfo {
taskInfoMapMutex.RLock()
defer taskInfoMapMutex.RUnlock()
ddnsTaskList := ddnsgo.GetDDNSTaskConfigureList()
var res []*DDNSTaskInfo
for i := range ddnsTaskList {
ti := GetDDNSTaskState(ddnsTaskList[i])
//ti.syncDomains()
res = append(res, ti)
}
return res
}
func GetDDNSTaskInfoByKey(key string) *DDNSTaskInfo {
taskInfoMapMutex.RLock()
defer taskInfoMapMutex.RUnlock()
ddnsConf := ddnsgo.GetDDNSTaskByKey(key)
if ddnsConf == nil {
return nil
}
info := GetDDNSTaskState(ddnsConf)
return info
}
func GetDDNSTaskState(task *ddnsconf.DDNSTask) *DDNSTaskInfo {
var d DDNSTaskInfo
d.DDNSTask = *task
info, ok := taskInfoMap.Load(task.TaskKey)
if ok {
d.TaskState = *info.(*DDNSTaskState)
} else {
var state DDNSTaskState
state.Init(d.Domains, d.ModifyTime)
if task.Enable {
state.SetDomainUpdateStatus(UpdateWaiting, "")
} else {
state.SetDomainUpdateStatus(UpdateStop, "")
}
d.TaskState = state
taskInfoMap.Store(task.TaskKey, &state)
}
return &d
}
================================================
FILE: module/ddns/ddnscore.go/domain.go
================================================
package ddnscore
import (
"log"
"net/url"
"strings"
"time"
)
const (
// UpdatedNothing 未改变
UpdatedNothing string = "域名IP和公网IP一致"
// UpdatedFailed 更新失败
UpdatedFailed = "失败"
// UpdatedSuccess 更新成功
UpdatedSuccess = "成功"
// UpdateStop 暂停
UpdateStop = "停止同步"
//UpdatePause 暂停 获取IP失败时暂停
UpdatePause = "暂停同步"
// UpdateWaiting
UpdateWaiting = "等待更新"
)
// Domain 域名实体
type Domain struct {
RawStr string
DomainName string
SubDomain string
CustomParams string
UpdateStatus string // 更新状态
LastUpdateStatusTime string //最后更新状态的时间
Message string
UpdateHistroy []any
}
type UpdateHistroyItem struct {
UpdateStatus string
UpdateTime string
}
func (d *Domain) String() string {
if d.SubDomain != "" {
return d.SubDomain + "." + d.DomainName
}
return d.DomainName
}
// GetFullDomain 返回完整子域名
func (d *Domain) GetFullDomain() string {
if d.SubDomain != "" {
return d.SubDomain + "." + d.DomainName
}
return "@" + "." + d.DomainName
}
// GetCustomParams not be nil
func (d *Domain) GetCustomParams() url.Values {
if d.CustomParams != "" {
q, err := url.ParseQuery(d.CustomParams)
if err == nil {
return q
}
}
return url.Values{}
}
// GetSubDomain 获得子域名,为空返回@
// 阿里云,dnspod需要
func (d *Domain) GetSubDomain() string {
if d.SubDomain != "" {
return d.SubDomain
}
return "@"
}
func (d *Domain) SetDomainUpdateStatus(status string, message string) {
if status != UpdateWaiting {
if status != UpdateStop || d.UpdateStatus != UpdateStop {
d.LastUpdateStatusTime = time.Now().Format("2006-01-02 15:04:05")
// 状态更新历史记录
hi := UpdateHistroyItem{UpdateStatus: string(status), UpdateTime: d.LastUpdateStatusTime}
d.UpdateHistroy = append(d.UpdateHistroy, hi)
if len(d.UpdateHistroy) > 10 {
d.UpdateHistroy = DeleteAnyListlice(d.UpdateHistroy, 0)
}
}
}
d.UpdateStatus = status
d.Message = message
}
func checkParseDomains(domainArr []string) (domains []Domain, domainsRawStrList []string) {
for _, domainStr := range domainArr {
domainStr = strings.TrimSpace(domainStr)
if domainStr == "" {
continue
}
domain := Domain{}
domain.RawStr = domainStr
dp := strings.Split(domainStr, ":")
dplen := len(dp)
switch dplen {
case 1:
{
sp := strings.Split(domainStr, ".")
length := len(sp)
if length <= 1 {
log.Println(domainStr, "域名不正确")
continue
}
// 处理域名
domain.DomainName = sp[length-2] + "." + sp[length-1]
// 如包含在org.cn等顶级域名下,后三个才为用户主域名
for _, staticMainDomain := range staticMainDomains {
if staticMainDomain == domain.DomainName {
domain.DomainName = sp[length-3] + "." + domain.DomainName
break
}
}
domainLen := len(domainStr) - len(domain.DomainName)
if domainLen > 0 {
domain.SubDomain = domainStr[:domainLen-1]
} else {
domain.SubDomain = domainStr[:domainLen]
}
}
case 2:
{
sp := strings.Split(dp[1], ".")
length := len(sp)
if length <= 1 {
log.Println(domainStr, "域名不正确")
continue
}
domain.DomainName = dp[1]
domain.SubDomain = dp[0]
}
default:
{
log.Println(domainStr, "域名不正确")
continue
}
}
if strings.Contains(domain.DomainName, "?") {
u, err := url.Parse("http://" + domain.DomainName)
if err != nil {
log.Println(domainStr, "域名解析失败")
continue
}
domain.DomainName = u.Host
domain.CustomParams = u.Query().Encode()
}
domains = append(domains, domain)
domainsRawStrList = append(domainsRawStrList, domainStr)
}
return
}
================================================
FILE: module/ddns/ddnscore.go/taskinfo.go
================================================
package ddnscore
import (
ddnsconf "github.com/gdy666/lucky/module/ddns/conf"
)
type DDNSTaskInfo struct {
ddnsconf.DDNSTask
TaskState DDNSTaskState `json:"TaskState"`
}
// CheckIPChange 检测公网IP是否改变
func (d *DDNSTaskInfo) CheckIPChange() (ipAddr string, change bool) {
ipAddr = d.GetIpAddr()
checkIPChange := d.TaskState.IPChanged(ipAddr)
if checkIPChange {
return ipAddr, true
}
//IP没变化
return ipAddr, false
}
func (d *DDNSTaskInfo) SyncDomains() {
if d.ModifyTime == d.TaskState.ModifyTime {
//fmt.Printf("不需要syncDomains\n")
return
}
//fmt.Printf("需要syncDomains\n")
domains, _ := checkParseDomains(d.Domains)
for i := range domains {
index := getDomainIndex(d.TaskState.Domains, &domains[i])
if index < 0 {
continue
}
domains[i] = d.TaskState.Domains[index]
}
d.TaskState.Domains = domains
d.TaskState.ModifyTime = d.ModifyTime
taskInfoMap.Store(d.TaskKey, &d.TaskState)
}
func getDomainIndex(domains []Domain, domain *Domain) (index int) {
index = -1
for i := range domains {
if domains[i].RawStr == domain.RawStr {
index = i
return
}
}
return
}
================================================
FILE: module/ddns/ddnscore.go/taskstate.go
================================================
package ddnscore
import (
"time"
)
// 固定的主域名
var staticMainDomains = []string{"com.cn", "org.cn", "net.cn", "ac.cn", "eu.org"}
// 获取ip失败的次数
// Domains Ipv4/Ipv6 DDNSTaskState
type DDNSTaskState struct {
IpAddr string
Domains []Domain
domainsRawStrList []string
WebhookCallTime string `json:"WebhookCallTime"` //最后触发时间
WebhookCallResult bool `json:"WebhookCallResult"` //触发结果
WebhookCallErrorMsg string `json:"WebhookCallErrorMsg"` //触发错误信息
LastSyncTime time.Time `json:"-"` //记录最新一次同步操作时间
LastWorkTime time.Time `json:"-"`
IPAddrHistory []any `json:"IPAddrHistory"`
WebhookCallHistroy []any `json:"WebhookCallHistroy"`
ModifyTime int64
}
type IPAddrHistoryItem struct {
IPaddr string
RecordTime string
}
type WebhookCallHistroyItem struct {
CallTime string
CallResult string
}
func (d *DDNSTaskState) SetIPAddr(ipaddr string) {
if d.IpAddr == ipaddr {
return
}
d.IpAddr = ipaddr
hi := IPAddrHistoryItem{IPaddr: ipaddr, RecordTime: time.Now().Local().Format("2006-01-02 15:04:05")}
d.IPAddrHistory = append(d.IPAddrHistory, hi)
if len(d.IPAddrHistory) > 10 {
d.IPAddrHistory = DeleteAnyListlice(d.IPAddrHistory, 0)
}
}
func DeleteAnyListlice(a []any, deleteIndex int) []any {
j := 0
for i := range a {
if i != deleteIndex {
a[j] = a[i]
j++
}
}
return a[:j]
}
func (d *DDNSTaskState) SetDomainUpdateStatus(status string, message string) {
for i := range d.Domains {
d.Domains[i].SetDomainUpdateStatus(status, message)
}
}
func (d *DDNSTaskState) SetWebhookResult(result bool, errMsg string) {
d.WebhookCallResult = result
d.WebhookCallErrorMsg = errMsg
d.WebhookCallTime = time.Now().Format("2006-01-02 15:04:05")
cr := "成功"
if !result {
cr = "出错"
}
hi := WebhookCallHistroyItem{CallResult: cr, CallTime: time.Now().Local().Format("2006-01-02 15:04:05")}
d.WebhookCallHistroy = append(d.WebhookCallHistroy, hi)
if len(d.WebhookCallHistroy) > 10 {
d.WebhookCallHistroy = DeleteAnyListlice(d.WebhookCallHistroy, 0)
}
}
func (d *DDNSTaskState) Init(domains []string, mt int64) {
d.Domains, d.domainsRawStrList = checkParseDomains(domains)
d.ModifyTime = mt
}
// Check 检测IP是否有改变
func (d *DDNSTaskState) IPChanged(newAddr string) bool {
if newAddr == "" {
return true
}
// 地址改变
if d.IpAddr != newAddr {
//log.Printf("公网地址改变:[%s]===>[%s]", d.DomainsInfo.IpAddr, newAddr)
//domains.IpAddr = newAddr
return true
}
return false
}
================================================
FILE: module/ddns/ddnscore.go/webhook.go
================================================
package ddnscore
import (
"fmt"
"net/http"
"strings"
"time"
"github.com/gdy666/lucky/module/ddns/ddnsgo"
"github.com/gdy666/lucky/thirdlib/gdylib/httputils"
)
// ExecWebhook 添加或更新IPv4/IPv6记录
func (d *DDNSTaskInfo) ExecWebhook(state *DDNSTaskState) {
if !d.WebhookEnable {
return
}
if state.IpAddr == "" && !d.WebhookCallOnGetIPfail {
return
}
hasUpdate := hasDomainTryToUpdate(&state.Domains)
if d.WebhookURL != "" && (hasUpdate || (state.IpAddr == "" && d.WebhookCallOnGetIPfail)) {
//log.Printf("DDNS任务【%s】触发Webhook", d.TaskName)
nowTime := time.Now().Format("2006-01-02 15:04:05")
url := d.replaceWebhookPara(nowTime, d.WebhookURL)
requestBody := d.replaceWebhookPara(nowTime, d.WebhookRequestBody)
//headersStr := cb.task.DNS.Callback.Headers
var headerStrList []string
for i := range d.WebhookHeaders {
header := d.replaceWebhookPara(nowTime, d.WebhookHeaders[i])
headerStrList = append(headerStrList, header)
}
headers := httputils.CreateHeadersMap(headerStrList)
succcssCotentList := []string{}
for i := range d.WebhookSuccessContent {
content := d.replaceWebhookPara(nowTime, d.WebhookSuccessContent[i])
succcssCotentList = append(succcssCotentList, content)
}
callErr := d.webhookHttpClientDo(d.WebhookMethod, url, requestBody, headers, succcssCotentList)
if callErr != nil {
state.SetWebhookResult(false, callErr.Error())
return
}
state.SetWebhookResult(true, "")
}
}
func WebhookTest(d *DDNSTaskInfo, url, method, WebhookRequestBody, proxy, addr, user, passwd string, headerList, successContentListraw []string) (string, error) {
nowTime := time.Now().Format("2006-01-02 15:04:05")
url = replaceWebhookTestPara(url, nowTime)
requestBody := replaceWebhookTestPara(WebhookRequestBody, nowTime)
var headerStrList []string
for i := range headerList {
header := replaceWebhookTestPara(headerList[i], nowTime)
headerStrList = append(headerStrList, header)
}
headers := httputils.CreateHeadersMap(headerStrList)
succcssCotentList := []string{}
for i := range successContentListraw {
content := replaceWebhookTestPara(successContentListraw[i], nowTime)
succcssCotentList = append(succcssCotentList, content)
}
globalDDNSConf := ddnsgo.GetDDNSConfigure()
proxyType := ""
proxyAddr := ""
proxyUser := ""
proxyPasswd := ""
switch proxy {
case "dns":
{
if d.DNS.HttpClientProxyType != "" && d.DNS.HttpClientProxyAddr != "" {
proxyType = d.DNS.HttpClientProxyType
proxyAddr = d.DNS.HttpClientProxyAddr
proxyUser = d.DNS.HttpClientProxyUser
proxyPasswd = d.DNS.HttpClientProxyPassword
}
}
case "http", "https", "socks5":
{
proxyType = proxy
proxyAddr = addr
proxyUser = user
proxyPasswd = passwd
}
default:
}
//fmt.Printf("proxyType:%s\taddr:%s\t,user[%s]passwd[%s]\n", proxyType, proxyAddr, proxyUser, proxyPasswd)
//dnsConf := cb.task.DNS
_, respStr, err := httputils.GetStringGoutDoHttpRequest(
"tcp",
"",
method,
url,
requestBody,
proxyType,
proxyAddr,
proxyUser,
proxyPasswd,
headers,
!globalDDNSConf.HttpClientSecureVerify,
time.Second*20)
if err != nil {
return "", fmt.Errorf("webhookTest 调用接口[%s]出错:%s", url, err.Error())
}
for _, successContent := range succcssCotentList {
if strings.Contains(respStr, successContent) {
return respStr, nil
}
}
return respStr, fmt.Errorf("接口调用出错,未匹配预设成功返回的字符串")
}
func (d *DDNSTaskInfo) webhookHttpClientDo(method, url, requestBody string, headers map[string]string, callbackSuccessContent []string) error {
globalDDNSConf := ddnsgo.GetDDNSConfigure()
proxyType := ""
proxyAddr := ""
proxyUser := ""
proxyPasswd := ""
switch d.WebhookProxy {
case "dns":
{
if d.DNS.HttpClientProxyType != "" && d.DNS.HttpClientProxyAddr != "" {
proxyType = d.DNS.HttpClientProxyType
proxyAddr = d.DNS.HttpClientProxyAddr
proxyUser = d.DNS.HttpClientProxyUser
proxyPasswd = d.DNS.HttpClientProxyPassword
}
}
case "http", "https", "socks5":
{
proxyType = d.WebhookProxy
proxyAddr = d.WebhookProxyAddr
proxyUser = d.WebhookProxyUser
proxyPasswd = d.WebhookProxyPassword
}
default:
}
//dnsConf := cb.task.DNS
statusCode, respStr, err := httputils.GetStringGoutDoHttpRequest(
"tcp",
"",
method,
url,
requestBody,
proxyType,
proxyAddr,
proxyUser,
proxyPasswd,
headers,
!globalDDNSConf.HttpClientSecureVerify,
time.Second*20)
if err != nil {
return fmt.Errorf("webhook 调用接口[%s]出错:%s", url, err.Error())
}
if d.WebhookDisableCallbackSuccessContentCheck {
if statusCode == http.StatusOK {
return nil
}
return fmt.Errorf("webhook调用接口失败:\n statusCode:%d\n%s", statusCode, respStr)
}
for _, successContent := range callbackSuccessContent {
if strings.Contains(respStr, successContent) {
return nil
}
}
return fmt.Errorf("webhook 调用接口失败:\n%s", respStr)
}
// DomainsIsChange
func hasDomainTryToUpdate(domains *[]Domain) bool {
for _, v46 := range *domains {
switch v46.UpdateStatus {
case UpdatedFailed:
return true
case UpdatedSuccess:
return true
default:
}
}
return false
}
// replaceWebhookTestPara WebhookTest替换参数 #{successDomains},#{failedDomains}
func replaceWebhookTestPara(orgPara, nowTime string) (newPara string) {
orgPara = strings.ReplaceAll(orgPara, "#{ipAddr}", "66.66.66.66")
successDomains := "www1.google.com,www2.google.com,www3.google.com,www4.google.com"
failedDomains := "www1.github.com,www2.github.com,www3.github.com,www4.github.com"
successDomainsLine := strings.Replace(successDomains, ",", `\n`, -1)
failedDomainsLine := strings.Replace(failedDomains, ",", `\n`, -1)
orgPara = strings.ReplaceAll(orgPara, "#{successDomains}", successDomains)
orgPara = strings.ReplaceAll(orgPara, "#{failedDomains}", failedDomains)
orgPara = strings.ReplaceAll(orgPara, "#{successDomainsLine}", successDomainsLine)
o
gitextract_wc7gf33_/ ├── .gitattributes ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── berforebuild.bat ├── config/ │ ├── appinfo.go │ ├── blacklist.go │ ├── config.go │ ├── ddns.go │ ├── portforward.go │ ├── reverseproxy.go │ ├── safecheck.go │ ├── sslcertficate.go │ ├── whitelist.go │ └── wol.go ├── ddns/ │ ├── alidns.go │ ├── baidu.go │ ├── callback.go │ ├── cloudflare.go │ ├── dns.go │ ├── dnscommon.go │ ├── dnspod.go │ ├── godaddy.go │ ├── huawei.go │ ├── porkbun.go │ └── worker.go ├── ddnscore.go/ │ ├── cache.go │ ├── domain.go │ ├── taskinfo.go │ ├── taskstate.go │ └── webhook.go ├── debug.go ├── go.mod ├── go.sum ├── goports ├── main.go ├── module/ │ ├── ddns/ │ │ ├── conf/ │ │ │ └── ddns.go │ │ ├── ddnscore.go/ │ │ │ ├── cache.go │ │ │ ├── domain.go │ │ │ ├── taskinfo.go │ │ │ ├── taskstate.go │ │ │ └── webhook.go │ │ ├── ddnsgo/ │ │ │ └── ddns.go │ │ ├── providers/ │ │ │ ├── alidns.go │ │ │ ├── baidu.go │ │ │ ├── callback.go │ │ │ ├── cloudflare.go │ │ │ ├── dnspod.go │ │ │ ├── godaddy.go │ │ │ ├── huawei.go │ │ │ ├── porkbun.go │ │ │ ├── provider.go │ │ │ └── providercommon.go │ │ └── worker.go │ ├── portforward/ │ │ ├── conf/ │ │ │ └── portforward.go │ │ ├── portforward.go │ │ └── socketproxy/ │ │ ├── baseproxyconf.go │ │ ├── proxy.go │ │ ├── socketproxy.go │ │ ├── tcpproxy.go │ │ ├── tcpudpcommon.go │ │ └── udpproxy.go │ ├── reverseproxy/ │ │ ├── conf/ │ │ │ └── reverseproxy.go │ │ ├── proxy.go │ │ └── reverseproxy.go │ ├── safe/ │ │ ├── blacklist.go │ │ ├── conf/ │ │ │ ├── black.go │ │ │ └── white.go │ │ ├── safe.go │ │ ├── safecheck.go │ │ └── whitelist.go │ ├── service/ │ │ └── service.go │ ├── sslcertficate/ │ │ ├── conf/ │ │ │ └── sslconf.go │ │ ├── ssl.go │ │ └── sslcertficate.go │ ├── weblog/ │ │ └── weblog.go │ └── wol/ │ ├── client.go │ ├── conf/ │ │ ├── device.go │ │ └── service.go │ ├── ctl.go │ ├── device.go │ ├── httpapi/ │ │ └── api.go │ ├── module.go │ ├── msg.go │ ├── service.go │ └── websocketcommon.go ├── reverseproxy/ │ └── proxy.go ├── scripts/ │ ├── lucky.service │ ├── luckyservice │ └── misnap_init.sh ├── socketproxy/ │ ├── baseproxyconf.go │ ├── proxy.go │ ├── tcpproxy.go │ ├── tcpudpcommon.go │ └── udpproxy.go ├── thirdlib/ │ ├── fatedier/ │ │ └── golib/ │ │ └── json/ │ │ ├── msg.go │ │ ├── pack.go │ │ └── process.go │ ├── gdylib/ │ │ ├── bemfa/ │ │ │ ├── device.go │ │ │ └── global.go │ │ ├── blinker/ │ │ │ ├── VoiceAssistant.go │ │ │ ├── device.go │ │ │ └── global.go │ │ ├── dnsutils/ │ │ │ └── resolve.go │ │ ├── fileutils/ │ │ │ ├── fileutils.go │ │ │ ├── run_linux.go │ │ │ └── run_windows.go │ │ ├── ginutils/ │ │ │ ├── basicAuth.go │ │ │ ├── jwt.go │ │ │ ├── staticFilesHandler.go │ │ │ └── utils.go │ │ ├── httputils/ │ │ │ ├── common.go │ │ │ ├── goututils.go │ │ │ └── httpclient.go │ │ ├── logsbuffer/ │ │ │ └── logsbuffer.go │ │ ├── netinterfaces/ │ │ │ └── netInterface.go │ │ ├── pool/ │ │ │ └── buf.go │ │ ├── recoverutil/ │ │ │ └── recoverutil.go │ │ ├── service/ │ │ │ └── service.go │ │ ├── slice/ │ │ │ └── options.go │ │ ├── stderrredirect/ │ │ │ ├── stderrredirect_linux.go │ │ │ └── stderrredirect_windows.go │ │ ├── stringsp/ │ │ │ ├── binary.go │ │ │ ├── randomutils.go │ │ │ ├── stringsp.go │ │ │ └── url.go │ │ └── websocketController/ │ │ └── controller.go │ ├── go-wol/ │ │ ├── magic_packet.go │ │ └── wol.go │ └── jeessy2/ │ └── ddns-go/ │ └── util/ │ ├── aliyun_signer.go │ ├── aliyun_signer_util.go │ ├── baidu_signer.go │ ├── escape.go │ ├── huawei_signer.go │ └── net.go ├── web/ │ ├── adminviews/ │ │ ├── .gitignore │ │ ├── .vscode/ │ │ │ └── extensions.json │ │ ├── README.md │ │ ├── auto-imports.d.ts │ │ ├── components.d.ts │ │ ├── dist/ │ │ │ ├── assets/ │ │ │ │ ├── index.0c84c960.js │ │ │ │ ├── index.abda1f8d.css │ │ │ │ ├── index.e5c8aec2.js │ │ │ │ └── index.f23c7bd8.css │ │ │ └── index.html │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.vue │ │ │ ├── apis/ │ │ │ │ ├── storage.js │ │ │ │ └── utils.js │ │ │ ├── assets/ │ │ │ │ ├── appbase.css │ │ │ │ ├── base.css │ │ │ │ └── common-layout.scss │ │ │ ├── components/ │ │ │ │ ├── About.vue │ │ │ │ ├── BlackLists.vue │ │ │ │ ├── DDNS.vue │ │ │ │ ├── DDNSSet.vue │ │ │ │ ├── Log.vue │ │ │ │ ├── Login.vue │ │ │ │ ├── PSet.vue │ │ │ │ ├── Pmenu.vue │ │ │ │ ├── PortForward.vue │ │ │ │ ├── PortForwardSet.vue │ │ │ │ ├── ReverseProxy.vue │ │ │ │ ├── SSL.vue │ │ │ │ ├── Status.vue │ │ │ │ ├── WhiteListSet.vue │ │ │ │ ├── WhiteLists.vue │ │ │ │ └── tools/ │ │ │ │ ├── WOL.vue │ │ │ │ └── WOLServiceSet.vue │ │ │ ├── main.js │ │ │ ├── request/ │ │ │ │ └── index.js │ │ │ └── utils/ │ │ │ ├── ui.ts │ │ │ └── utils.ts │ │ └── vite.config.js │ ├── blackwhitelist.go │ ├── common.go │ ├── configure.go │ ├── ddns.go │ ├── portforward.go │ ├── reverseproxy.go │ ├── ssl.go │ ├── web.go │ └── wol.go └── web.go
Showing preview only (336K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3714 symbols across 140 files)
FILE: config/appinfo.go
type AppInfo (line 8) | type AppInfo struct
function GetAppInfo (line 20) | func GetAppInfo() *AppInfo {
function InitAppInfo (line 24) | func InitAppInfo(version, date string) {
FILE: config/blacklist.go
type BlackListItem (line 11) | type BlackListItem
method Contains (line 13) | func (w *BlackListItem) Contains(ip string) bool {
type BlackListConfigure (line 28) | type BlackListConfigure struct
function GetBlackList (line 32) | func GetBlackList() []BlackListItem {
function BlackListInit (line 48) | func BlackListInit() {
function BlackListAdd (line 67) | func BlackListAdd(ip string, activelifeDuration int32) (string, error) {
function BlackListDelete (line 103) | func BlackListDelete(ip string) error {
function BlackListFlush (line 129) | func BlackListFlush(lock bool) error {
function DeleteBlackListlice (line 166) | func DeleteBlackListlice(a []BlackListItem, deleteIndex int) []BlackList...
FILE: config/config.go
constant defaultAdminAccount (line 18) | defaultAdminAccount = "666"
constant defaultAdminPassword (line 19) | defaultAdminPassword = "666"
constant defaultAdminListenPort (line 20) | defaultAdminListenPort = 16601
constant defaultLogSize (line 21) | defaultLogSize = 2048
constant minLogSize (line 22) | minLogSize = 1024
constant maxLogSize (line 23) | maxLogSize = 40960
function SetVersion (line 28) | func SetVersion(v string) {
function GetVersion (line 32) | func GetVersion() string {
function GetLoginRandomKey (line 38) | func GetLoginRandomKey() string {
function FlushLoginRandomKey (line 42) | func FlushLoginRandomKey() {
type BaseConfigure (line 46) | type BaseConfigure struct
type ProgramConfigure (line 59) | type ProgramConfigure struct
function GetAuthAccount (line 84) | func GetAuthAccount() map[string]string {
function GetRunMode (line 92) | func GetRunMode() string {
function SetRunMode (line 96) | func SetRunMode(mode string) {
function SetConfig (line 100) | func SetConfig(p *ProgramConfigure) error {
function GetConfig (line 107) | func GetConfig() *ProgramConfigure {
function GetConfigureBytes (line 114) | func GetConfigureBytes() []byte {
function GetBaseConfigure (line 128) | func GetBaseConfigure() BaseConfigure {
function GetDDNSConfigure (line 135) | func GetDDNSConfigure() DDNSConfigure {
function GetPortForwardsConfigure (line 142) | func GetPortForwardsConfigure() PortForwardsConfigure {
function SetPortForwardsConfigure (line 149) | func SetPortForwardsConfigure(conf *PortForwardsConfigure) error {
function SetBaseConfigure (line 180) | func SetBaseConfigure(conf *BaseConfigure) error {
function SetDDNSConfigure (line 197) | func SetDDNSConfigure(conf *DDNSConfigure) error {
function Read (line 221) | func Read(filePath string) (err error) {
function LoadDefault (line 267) | func LoadDefault(adminWebListenPort int) {
function Save (line 271) | func Save() (err error) {
function readProgramConfigure (line 293) | func readProgramConfigure(filePath string) (conf *ProgramConfigure, err ...
function loadDefaultConfigure (line 321) | func loadDefaultConfigure(
function saveProgramConfig (line 367) | func saveProgramConfig(programConfigure *ProgramConfigure, filePath stri...
function CheckTCPPortAvalid (line 375) | func CheckTCPPortAvalid(port int) bool {
FILE: config/ddns.go
type DDNSConfigure (line 10) | type DDNSConfigure struct
type DDNSTask (line 17) | type DDNSTask struct
type Webhook (line 36) | type Webhook struct
type DNSConfig (line 52) | type DNSConfig struct
method GetCallAPINetwork (line 68) | func (d *DNSConfig) GetCallAPINetwork() string {
type DNSCallback (line 77) | type DNSCallback struct
function DDNSTaskListConfigureCheck (line 141) | func DDNSTaskListConfigureCheck() {
function DDNSTaskSetWebhookCallResult (line 159) | func DDNSTaskSetWebhookCallResult(taskKey string, result bool, message s...
function GetDDNSTaskConfigureList (line 178) | func GetDDNSTaskConfigureList() []*DDNSTask {
function GetDDNSTaskByKey (line 191) | func GetDDNSTaskByKey(taskKey string) *DDNSTask {
function DDNSTaskListAdd (line 210) | func DDNSTaskListAdd(task *DDNSTask) error {
function DDNSTaskListDelete (line 218) | func DDNSTaskListDelete(taskKey string) error {
function CheckDDNSTaskAvalid (line 239) | func CheckDDNSTaskAvalid(task *DDNSTask) error {
function EnableDDNSTaskByKey (line 274) | func EnableDDNSTaskByKey(taskKey string, enable bool) error {
function UpdateTaskToDDNSTaskList (line 293) | func UpdateTaskToDDNSTaskList(taskKey string, task DDNSTask) error {
function DeleteDDNSTaskListlice (line 325) | func DeleteDDNSTaskListlice(a []DDNSTask, deleteIndex int) []DDNSTask {
FILE: config/portforward.go
type PortForwardsConfigure (line 14) | type PortForwardsConfigure struct
type PortForwardsRule (line 20) | type PortForwardsRule struct
method ProxyCount (line 40) | func (r *PortForwardsRule) ProxyCount() int {
method StartAllProxys (line 47) | func (r *PortForwardsRule) StartAllProxys() {
method GetLastLogs (line 57) | func (r *PortForwardsRule) GetLastLogs(maxCount int) []any {
method Fire (line 61) | func (r *PortForwardsRule) Fire(entry *logrus.Entry) error {
method Levels (line 70) | func (r *PortForwardsRule) Levels() []logrus.Level {
method GetLogrus (line 74) | func (r *PortForwardsRule) GetLogrus() *logrus.Logger {
method GetLogsBuffer (line 90) | func (r *PortForwardsRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
method StopAllProxys (line 97) | func (r *PortForwardsRule) StopAllProxys() {
method InitProxyList (line 141) | func (r *PortForwardsRule) InitProxyList() error {
function TidyPortforwardLogsCache (line 107) | func TidyPortforwardLogsCache() {
function PortsCheck (line 173) | func PortsCheck(ports1Str, ports2Str string) (bool, error) {
function PortsStrToIList (line 189) | func PortsStrToIList(portsStr string) (ports []int, err error) {
function portStrToi (line 251) | func portStrToi(portStr string) (int, error) {
function PortForwardsRuleListInit (line 262) | func PortForwardsRuleListInit() {
function GetPortForwardsRuleList (line 277) | func GetPortForwardsRuleList() []PortForwardsRule {
function GetPortForwardsGlobalProxyCount (line 290) | func GetPortForwardsGlobalProxyCount() int {
function GetPortForwardsGlobalProxyCountExcept (line 300) | func GetPortForwardsGlobalProxyCountExcept(key string) int {
function GetPortForwardsRuleByKey (line 313) | func GetPortForwardsRuleByKey(key string) *PortForwardsRule {
function StopAllSocketProxysByRuleKey (line 331) | func StopAllSocketProxysByRuleKey(key string) error {
function StartAllSocketProxysByRuleKey (line 349) | func StartAllSocketProxysByRuleKey(key string) error {
function PortForwardsRuleListAdd (line 367) | func PortForwardsRuleListAdd(r *PortForwardsRule) error {
function PortForwardsRuleListDelete (line 375) | func PortForwardsRuleListDelete(key string) error {
function EnablePortForwardsRuleByKey (line 398) | func EnablePortForwardsRuleByKey(key string, enable bool) error {
function UpdatePortForwardsRuleToPortForwardsRuleList (line 423) | func UpdatePortForwardsRuleToPortForwardsRuleList(key string, r *PortFor...
function DeletePortForwardsRuleListSlice (line 443) | func DeletePortForwardsRuleListSlice(a []PortForwardsRule, deleteIndex i...
FILE: config/reverseproxy.go
function init (line 26) | func init() {
function TidyReverseProxyCache (line 31) | func TidyReverseProxyCache() {
type SubReverProxyRule (line 69) | type SubReverProxyRule struct
method Logf (line 133) | func (r *SubReverProxyRule) Logf(level logrus.Level, c *gin.Context, f...
method HandlerReverseProxy (line 155) | func (r *SubReverProxyRule) HandlerReverseProxy(remote *url.URL, host,...
method Fire (line 175) | func (r *SubReverProxyRule) Fire(entry *logrus.Entry) error {
method Levels (line 184) | func (r *SubReverProxyRule) Levels() []logrus.Level {
method GetLogrus (line 188) | func (r *SubReverProxyRule) GetLogrus() *logrus.Logger {
method GetLogger (line 205) | func (r *SubReverProxyRule) GetLogger() *log.Logger {
method GetLogsBuffer (line 212) | func (r *SubReverProxyRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
method checkupClientIP (line 219) | func (r *SubReverProxyRule) checkupClientIP(ip string) bool {
method checkupUserAgent (line 223) | func (r *SubReverProxyRule) checkupUserAgent(ua string) bool {
method initOnceExec (line 457) | func (r *SubReverProxyRule) initOnceExec() {
method GetLocation (line 465) | func (r *SubReverProxyRule) GetLocation() string {
method BasicAuthHandler (line 480) | func (r *SubReverProxyRule) BasicAuthHandler(c *gin.Context) bool {
method InitTrustedProxyCIDRs (line 498) | func (r *SubReverProxyRule) InitTrustedProxyCIDRs() error {
method ClientIP (line 514) | func (r *SubReverProxyRule) ClientIP(c *gin.Context) string {
method validateHeader (line 534) | func (r *SubReverProxyRule) validateHeader(header string) (clientIP st...
method isTrustedProxy (line 553) | func (r *SubReverProxyRule) isTrustedProxy(ip net.IP) bool {
type ReverseProxyRule (line 108) | type ReverseProxyRule struct
method Init (line 126) | func (r *ReverseProxyRule) Init() {
method ReverseProxyHandler (line 243) | func (r *ReverseProxyRule) ReverseProxyHandler(c *gin.Context) {
method GetSubRuleByDomain (line 311) | func (r *ReverseProxyRule) GetSubRuleByDomain(domain string) (*Reverse...
method GetServer (line 350) | func (r *ReverseProxyRule) GetServer() *http.Server {
method SetServer (line 358) | func (r *ReverseProxyRule) SetServer(s *http.Server) {
method ServerStart (line 366) | func (r *ReverseProxyRule) ServerStart() error {
method ServerStop (line 432) | func (r *ReverseProxyRule) ServerStop() {
method initDomainsMap (line 444) | func (r *ReverseProxyRule) initDomainsMap() error {
method Addr (line 567) | func (r *ReverseProxyRule) Addr() string {
method GetLastLogs (line 586) | func (r *ReverseProxyRule) GetLastLogs() map[string][]any {
type ReverseProxy (line 319) | type ReverseProxy struct
function GetSubRuleByKey (line 327) | func GetSubRuleByKey(ruleKey, proxyKey string) *SubReverProxyRule {
type LogItem (line 571) | type LogItem struct
function WebLogConvert (line 579) | func WebLogConvert(lg *logsbuffer.LogItem) any {
function GetReverseProxyRuleList (line 599) | func GetReverseProxyRuleList() []*ReverseProxyRule {
function GetReverseProxyRuleByKey (line 613) | func GetReverseProxyRuleByKey(ruleKey string) *ReverseProxyRule {
function ReverseProxyRuleListAdd (line 633) | func ReverseProxyRuleListAdd(rule *ReverseProxyRule) error {
function ReverseProxyRuleListDelete (line 641) | func ReverseProxyRuleListDelete(ruleKey string) error {
function EnableReverseProxyRuleByKey (line 662) | func EnableReverseProxyRuleByKey(ruleKey string, enable bool) error {
function EnableReverseProxySubRule (line 681) | func EnableReverseProxySubRule(ruleKey, proxyKey string, enable bool) er...
function UpdateReverseProxyRulet (line 714) | func UpdateReverseProxyRulet(rule ReverseProxyRule) error {
function DeleteReverseProxyRuleListlice (line 736) | func DeleteReverseProxyRuleListlice(a []ReverseProxyRule, deleteIndex in...
FILE: config/safecheck.go
function SafeCheck (line 8) | func SafeCheck(mode, ip string) bool {
function whiteListCheck (line 21) | func whiteListCheck(ip string) bool {
function blackListCheck (line 50) | func blackListCheck(ip string) bool {
FILE: config/sslcertficate.go
type SSLCertficate (line 15) | type SSLCertficate struct
method Init (line 27) | func (s *SSLCertficate) Init() error {
method GetFirstDomain (line 42) | func (s *SSLCertficate) GetFirstDomain() string {
function CreateX509KeyPairByBase64Str (line 55) | func CreateX509KeyPairByBase64Str(certBase64, keyBase64 string) (*tls.Ce...
type CertInfo (line 73) | type CertInfo struct
function GetCertDomainInfo (line 79) | func GetCertDomainInfo(cert *tls.Certificate) (*[]CertInfo, error) {
function GetCertDomains (line 104) | func GetCertDomains(cert *tls.Certificate) []string {
function GetDomainsTrimSpace (line 126) | func GetDomainsTrimSpace(dst []string) []string {
function GetDomainsStrByDomains (line 137) | func GetDomainsStrByDomains(dst []string) string {
function SSLCertficateListInit (line 154) | func SSLCertficateListInit() {
function GetSSLCertficateList (line 166) | func GetSSLCertficateList() []SSLCertficate {
function SSLCertficateListAdd (line 180) | func SSLCertficateListAdd(s *SSLCertficate) error {
function SSLCertficateListDelete (line 208) | func SSLCertficateListDelete(key string) error {
function SSLCertficateEnable (line 227) | func SSLCertficateEnable(key string, enable bool) error {
function SSLCertficateAlterRemark (line 244) | func SSLCertficateAlterRemark(key, remark string) error {
function DeleteSSLCertficateListslice (line 261) | func DeleteSSLCertficateListslice(a []SSLCertficate, deleteIndex int) []...
function GetValidSSLCertficateList (line 272) | func GetValidSSLCertficateList() []tls.Certificate {
FILE: config/whitelist.go
type WhiteListConfigure (line 11) | type WhiteListConfigure struct
type WhiteListItem (line 16) | type WhiteListItem struct
method Contains (line 23) | func (w *WhiteListItem) Contains(ip string) bool {
type WhiteListBaseConfigure (line 38) | type WhiteListBaseConfigure struct
function GetWhiteListBaseConfigure (line 45) | func GetWhiteListBaseConfigure() WhiteListBaseConfigure {
function SetWhiteListBaseConfigure (line 51) | func SetWhiteListBaseConfigure(activelifeDuration int32, url, account, p...
function GetWhiteList (line 61) | func GetWhiteList() []WhiteListItem {
function WhiteListInit (line 77) | func WhiteListInit() {
function WhiteListAdd (line 96) | func WhiteListAdd(ip string, activelifeDuration int32) (string, error) {
function WhiteListDelete (line 132) | func WhiteListDelete(ip string) error {
function WhiteListFlush (line 158) | func WhiteListFlush(lock bool) error {
function DeleteWhiteListlice (line 195) | func DeleteWhiteListlice(a []WhiteListItem, deleteIndex int) []WhiteList...
FILE: config/wol.go
type WOLDevice (line 11) | type WOLDevice struct
method WakeUp (line 21) | func (d *WOLDevice) WakeUp() error {
function WakeOnLan (line 25) | func WakeOnLan(macList []string, broadcastIps []string, port, repeat int...
function GetWOLDeviceByKey (line 62) | func GetWOLDeviceByKey(key string) *WOLDevice {
function GetWOLDeviceList (line 82) | func GetWOLDeviceList() []WOLDevice {
function WOLDeviceListAdd (line 96) | func WOLDeviceListAdd(d *WOLDevice) error {
function WOLDeviceListAlter (line 107) | func WOLDeviceListAlter(d *WOLDevice) error {
function WOLDeviceListDelete (line 124) | func WOLDeviceListDelete(key string) error {
function DeleteWOLDeviceListslice (line 143) | func DeleteWOLDeviceListslice(a []WOLDevice, deleteIndex int) []WOLDevice {
FILE: ddns/alidns.go
constant alidnsEndpoint (line 16) | alidnsEndpoint string = "https://alidns.aliyuncs.com/"
type Alidns (line 21) | type Alidns struct
method Init (line 48) | func (ali *Alidns) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 60) | func (ali *Alidns) createUpdateDomain(recordType, ipAddr string, domai...
method create (line 94) | func (ali *Alidns) create(domain *ddnscore.Domain, recordType string, ...
method modify (line 118) | func (ali *Alidns) modify(recordSelected AlidnsRecord, domain *ddnscor...
method request (line 153) | func (ali *Alidns) request(params url.Values, result interface{}) (err...
type AlidnsRecord (line 27) | type AlidnsRecord struct
type AlidnsSubDomainRecords (line 34) | type AlidnsSubDomainRecords struct
type AlidnsResp (line 42) | type AlidnsResp struct
FILE: ddns/baidu.go
constant baiduEndpoint (line 18) | baiduEndpoint = "https://bcd.baidubce.com"
type BaiduCloud (line 21) | type BaiduCloud struct
method Init (line 71) | func (baidu *BaiduCloud) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 88) | func (baidu *BaiduCloud) createUpdateDomain(recordType, ipAddr string,...
method create (line 121) | func (baidu *BaiduCloud) create(domain *ddnscore.Domain, recordType st...
method modify (line 142) | func (baidu *BaiduCloud) modify(record BaiduRecord, domain *ddnscore.D...
method request (line 174) | func (baidu *BaiduCloud) request(method string, url string, data inter...
type BaiduRecord (line 27) | type BaiduRecord struct
type BaiduRecordsResp (line 39) | type BaiduRecordsResp struct
type BaiduListRequest (line 45) | type BaiduListRequest struct
type BaiduModifyRequest (line 52) | type BaiduModifyRequest struct
type BaiduCreateRequest (line 63) | type BaiduCreateRequest struct
FILE: ddns/callback.go
type Callback (line 14) | type Callback struct
method Init (line 20) | func (cb *Callback) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 42) | func (cb *Callback) createUpdateDomain(recordType, ipAddr string, doma...
method CallbackHttpClientDo (line 87) | func (cb *Callback) CallbackHttpClientDo(method, url, requestBody stri...
function CopyHeadersMap (line 32) | func CopyHeadersMap(sm map[string]string) map[string]string {
function replacePara (line 72) | func replacePara(orgPara, ipAddr string, domain *ddnscore.Domain, record...
FILE: ddns/cloudflare.go
constant zonesAPI (line 16) | zonesAPI string = "https://api.cloudflare.com/client/v4/zones"
type Cloudflare (line 20) | type Cloudflare struct
method Init (line 59) | func (cf *Cloudflare) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 76) | func (cf *Cloudflare) createUpdateDomain(recordType, ipAddr string, do...
method create (line 118) | func (cf *Cloudflare) create(zoneID string, domain *ddnscore.Domain, r...
method modify (line 148) | func (cf *Cloudflare) modify(result CloudflareRecordsResp, zoneID stri...
method getZones (line 186) | func (cf *Cloudflare) getZones(domain *ddnscore.Domain) (result Cloudf...
method request (line 198) | func (cf *Cloudflare) request(method string, url string, data interfac...
type CloudflareZonesResp (line 26) | type CloudflareZonesResp struct
type CloudflareRecordsResp (line 37) | type CloudflareRecordsResp struct
type CloudflareRecord (line 43) | type CloudflareRecord struct
type CloudflareStatus (line 53) | type CloudflareStatus struct
FILE: ddns/dns.go
type DNS (line 6) | type DNS interface
FILE: ddns/dnscommon.go
type DNSCommon (line 18) | type DNSCommon struct
method SetCreateUpdateDomainFunc (line 24) | func (d *DNSCommon) SetCreateUpdateDomainFunc(f func(recordType, ipadd...
method Init (line 28) | func (d *DNSCommon) Init(task *ddnscore.DDNSTaskInfo) {
method AddUpdateDomainRecords (line 33) | func (d *DNSCommon) AddUpdateDomainRecords() string {
method addUpdateDomainRecords (line 41) | func (d *DNSCommon) addUpdateDomainRecords(recordType string) string {
method CreateHTTPClient (line 162) | func (d *DNSCommon) CreateHTTPClient() (*http.Client, error) {
function getDomainItem (line 148) | func getDomainItem(fullDomain string, domains *[]ddnscore.Domain) *ddnsc...
function ResolveDomainAtServerList (line 177) | func ResolveDomainAtServerList(queryType, domain string, dnsServerList [...
function resolveDomain (line 230) | func resolveDomain(msg *dns.Msg, client *dns.Client, dnsServer string) (...
FILE: ddns/dnspod.go
constant recordListAPI (line 12) | recordListAPI string = "https://dnsapi.cn/Record.List"
constant recordModifyURL (line 13) | recordModifyURL string = "https://dnsapi.cn/Record.Modify"
constant recordCreateAPI (line 14) | recordCreateAPI string = "https://dnsapi.cn/Record.Create"
type Dnspod (line 19) | type Dnspod struct
method Init (line 45) | func (dnspod *Dnspod) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 57) | func (dnspod *Dnspod) createUpdateDomain(recordType, ipAddr string, do...
method create (line 76) | func (dnspod *Dnspod) create(result DnspodRecordListResp, domain *ddns...
method modify (line 104) | func (dnspod *Dnspod) modify(result DnspodRecordListResp, domain *ddns...
method commonRequest (line 143) | func (dnspod *Dnspod) commonRequest(apiAddr string, values url.Values,...
method getRecordList (line 165) | func (dnspod *Dnspod) getRecordList(domain *ddnscore.Domain, typ strin...
type DnspodRecordListResp (line 25) | type DnspodRecordListResp struct
type DnspodStatus (line 37) | type DnspodStatus struct
FILE: ddns/godaddy.go
type godaddyRecord (line 14) | type godaddyRecord struct
type godaddyRecords (line 21) | type godaddyRecords
type GoDaddy (line 23) | type GoDaddy struct
method Init (line 31) | func (gd *GoDaddy) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 60) | func (gd *GoDaddy) createUpdateDomain(recordType, ipAddr string, domai...
method sendReq (line 73) | func (gd *GoDaddy) sendReq(method string, rType string, domain *ddnsco...
FILE: ddns/huawei.go
constant huaweicloudEndpoint (line 17) | huaweicloudEndpoint string = "https://dns.myhuaweicloud.com"
type Huaweicloud (line 22) | type Huaweicloud struct
method Init (line 53) | func (hw *Huaweicloud) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 70) | func (hw *Huaweicloud) createUpdateDomain(recordType, ipAddr string, d...
method create (line 105) | func (hw *Huaweicloud) create(domain *ddnscore.Domain, recordType stri...
method modify (line 149) | func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *dd...
method getZones (line 187) | func (hw *Huaweicloud) getZones(domain *ddnscore.Domain) (result Huawe...
method request (line 199) | func (hw *Huaweicloud) request(method string, url string, data interfa...
type HuaweicloudZonesResp (line 28) | type HuaweicloudZonesResp struct
type HuaweicloudRecordsResp (line 37) | type HuaweicloudRecordsResp struct
type HuaweicloudRecordsets (line 42) | type HuaweicloudRecordsets struct
FILE: ddns/porkbun.go
constant porkbunEndpoint (line 16) | porkbunEndpoint string = "https://porkbun.com/api/json/v3/dns"
type Porkbun (line 19) | type Porkbun struct
method Init (line 50) | func (pb *Porkbun) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 61) | func (pb *Porkbun) createUpdateDomain(recordType, ipAddr string, domai...
method create (line 91) | func (pb *Porkbun) create(domain *ddnscore.Domain, recordType string, ...
method modify (line 123) | func (pb *Porkbun) modify(record *PorkbunDomainQueryResponse, domain *...
method request (line 164) | func (pb *Porkbun) request(url string, data interface{}, result interf...
type PorkbunDomainRecord (line 23) | type PorkbunDomainRecord struct
type PorkbunResponse (line 30) | type PorkbunResponse struct
type PorkbunDomainQueryResponse (line 34) | type PorkbunDomainQueryResponse struct
type PorkbunApiKey (line 39) | type PorkbunApiKey struct
type PorkbunDomainCreateOrUpdateVO (line 44) | type PorkbunDomainCreateOrUpdateVO struct
FILE: ddns/worker.go
function init (line 16) | func init() {
function Run (line 23) | func Run(firstDelay time.Duration, delay time.Duration) {
function syncAllDomainsOnce (line 33) | func syncAllDomainsOnce(params ...any) {
function syncTaskDomainsOnce (line 87) | func syncTaskDomainsOnce(params ...any) {
function syncDDNSTask (line 104) | func syncDDNSTask(task *ddnscore.DDNSTaskInfo) {
FILE: ddnscore.go/cache.go
function FLushWebLastAccessDDNSTaskListLastTime (line 18) | func FLushWebLastAccessDDNSTaskListLastTime() {
function webAccessAvalid (line 23) | func webAccessAvalid() bool {
function EnableDDNSTaskByKey (line 28) | func EnableDDNSTaskByKey(key string, enable bool) error {
function DDNSTaskInfoMapUpdate (line 43) | func DDNSTaskInfoMapUpdate(task *DDNSTaskInfo) {
function DDNSTaskInfoMapUpdateIPInfo (line 71) | func DDNSTaskInfoMapUpdateIPInfo(task *DDNSTaskInfo) {
function DDNSTaskInfoMapUpdateDomainInfo (line 88) | func DDNSTaskInfoMapUpdateDomainInfo(task *DDNSTaskInfo) {
function DDNSTaskInfoMapDelete (line 104) | func DDNSTaskInfoMapDelete(key string) {
function UpdateDomainsStateByTaskKey (line 110) | func UpdateDomainsStateByTaskKey(key, status, message string) {
function GetDDNSTaskInfoList (line 120) | func GetDDNSTaskInfoList() []*DDNSTaskInfo {
function GetDDNSTaskInfoByKey (line 132) | func GetDDNSTaskInfoByKey(key string) *DDNSTaskInfo {
function CreateDDNSTaskInfo (line 143) | func CreateDDNSTaskInfo(task *config.DDNSTask) *DDNSTaskInfo {
FILE: ddnscore.go/domain.go
constant UpdatedNothing (line 10) | UpdatedNothing string = "域名IP和公网IP一致"
constant UpdatedFailed (line 12) | UpdatedFailed = "失败"
constant UpdatedSuccess (line 14) | UpdatedSuccess = "成功"
constant UpdateStop (line 16) | UpdateStop = "停止同步"
constant UpdatePause (line 18) | UpdatePause = "暂停同步"
constant UpdateWaiting (line 20) | UpdateWaiting = "等待更新"
type Domain (line 24) | type Domain struct
method String (line 40) | func (d *Domain) String() string {
method GetFullDomain (line 48) | func (d *Domain) GetFullDomain() string {
method GetCustomParams (line 56) | func (d *Domain) GetCustomParams() url.Values {
method GetSubDomain (line 68) | func (d *Domain) GetSubDomain() string {
method SetDomainUpdateStatus (line 75) | func (d *Domain) SetDomainUpdateStatus(status string, message string) {
type UpdateHistroyItem (line 35) | type UpdateHistroyItem struct
FILE: ddnscore.go/taskinfo.go
constant Ipv4Reg (line 17) | Ipv4Reg = `((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[...
constant Ipv6Reg (line 20) | Ipv6Reg = `((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1...
type DDNSTaskInfo (line 24) | type DDNSTaskInfo struct
method getIpAddr (line 29) | func (d *DDNSTaskInfo) getIpAddr() (result string) {
method CheckIPChange (line 37) | func (d *DDNSTaskInfo) CheckIPChange() (ipAddr string, change bool) {
method getIpv4Addr (line 51) | func (d *DDNSTaskInfo) getIpv4Addr() (result string) {
method getIpv6Addr (line 112) | func (d *DDNSTaskInfo) getIpv6Addr() (result string) {
function CleanIPUrlAddrMap (line 169) | func CleanIPUrlAddrMap() {
FILE: ddnscore.go/taskstate.go
type DDNSTaskState (line 16) | type DDNSTaskState struct
method SetIPAddr (line 39) | func (d *DDNSTaskState) SetIPAddr(ipaddr string) {
method SetDomainUpdateStatus (line 65) | func (d *DDNSTaskState) SetDomainUpdateStatus(status string, message s...
method SetWebhookResult (line 71) | func (d *DDNSTaskState) SetWebhookResult(result bool, errMsg string) {
method Init (line 88) | func (d *DDNSTaskState) Init(domains []string) {
method checkParseDomains (line 94) | func (d *DDNSTaskState) checkParseDomains(domainArr []string) (domains...
method IPChangeCheck (line 157) | func (state *DDNSTaskState) IPChangeCheck(newAddr string) bool {
type IPAddrHistoryItem (line 29) | type IPAddrHistoryItem struct
type WebhookCallHistroyItem (line 34) | type WebhookCallHistroyItem struct
function DeleteAnyListlice (line 54) | func DeleteAnyListlice(a []any, deleteIndex int) []any {
FILE: ddnscore.go/webhook.go
method ExecWebhook (line 14) | func (d *DDNSTaskInfo) ExecWebhook(state *DDNSTaskState) {
function WebhookTest (line 63) | func WebhookTest(d *DDNSTaskInfo, url, method, WebhookRequestBody, proxy...
method webhookHttpClientDo (line 140) | func (d *DDNSTaskInfo) webhookHttpClientDo(method, url, requestBody stri...
function hasDomainTryToUpdate (line 204) | func hasDomainTryToUpdate(domains *[]Domain) bool {
function replaceWebhookTestPara (line 218) | func replaceWebhookTestPara(orgPara, nowTime string) (newPara string) {
method replaceWebhookPara (line 234) | func (d *DDNSTaskInfo) replaceWebhookPara(nowTime, orgPara string) (newP...
method getDomainsStr (line 258) | func (d *DDNSTaskInfo) getDomainsStr(domains *[]Domain) (string, string) {
FILE: debug.go
function init (line 12) | func init() {
FILE: main.go
function init (line 33) | func init() {
function main (line 38) | func main() {
FILE: module/ddns/conf/ddns.go
function SetGetDDNSConfigureFunc (line 18) | func SetGetDDNSConfigureFunc(f func() DDNSConfigure) {
type DDNSConfigure (line 22) | type DDNSConfigure struct
type DDNSTask (line 29) | type DDNSTask struct
method GetIpAddr (line 108) | func (d *DDNSTask) GetIpAddr() (result string) {
method getIpv4Addr (line 116) | func (d *DDNSTask) getIpv4Addr() (result string) {
method getIpv6Addr (line 176) | func (d *DDNSTask) getIpv6Addr() (result string) {
type Webhook (line 49) | type Webhook struct
type DNSConfig (line 65) | type DNSConfig struct
method GetCallAPINetwork (line 81) | func (d *DNSConfig) GetCallAPINetwork() string {
type DNSCallback (line 90) | type DNSCallback struct
constant Ipv4Reg (line 101) | Ipv4Reg = `((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[...
constant Ipv6Reg (line 104) | Ipv6Reg = `((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1...
function CleanIPUrlAddrMap (line 233) | func CleanIPUrlAddrMap() {
function CheckDDNSTaskAvalid (line 247) | func CheckDDNSTaskAvalid(task *DDNSTask) error {
FILE: module/ddns/ddnscore.go/cache.go
function FLushWebLastAccessDDNSTaskListLastTime (line 18) | func FLushWebLastAccessDDNSTaskListLastTime() {
function webAccessAvalid (line 23) | func webAccessAvalid() bool {
function EnableDDNSTaskByKey (line 28) | func EnableDDNSTaskByKey(key string, enable bool) error {
function DDNSTaskInfoMapUpdate (line 43) | func DDNSTaskInfoMapUpdate(task *DDNSTaskInfo) bool {
function DDNSTaskInfoMapUpdateIPInfo (line 87) | func DDNSTaskInfoMapUpdateIPInfo(task *DDNSTaskInfo) {
function DDNSTaskInfoMapUpdateDomainInfo (line 104) | func DDNSTaskInfoMapUpdateDomainInfo(task *DDNSTaskInfo) {
function DDNSTaskInfoMapDelete (line 120) | func DDNSTaskInfoMapDelete(key string) {
function UpdateDomainsStateByTaskKey (line 126) | func UpdateDomainsStateByTaskKey(key, status, message string) {
function GetDDNSTaskInfoList (line 136) | func GetDDNSTaskInfoList() []*DDNSTaskInfo {
function GetDDNSTaskInfoByKey (line 149) | func GetDDNSTaskInfoByKey(key string) *DDNSTaskInfo {
function GetDDNSTaskState (line 160) | func GetDDNSTaskState(task *ddnsconf.DDNSTask) *DDNSTaskInfo {
FILE: module/ddns/ddnscore.go/domain.go
constant UpdatedNothing (line 12) | UpdatedNothing string = "域名IP和公网IP一致"
constant UpdatedFailed (line 14) | UpdatedFailed = "失败"
constant UpdatedSuccess (line 16) | UpdatedSuccess = "成功"
constant UpdateStop (line 18) | UpdateStop = "停止同步"
constant UpdatePause (line 20) | UpdatePause = "暂停同步"
constant UpdateWaiting (line 22) | UpdateWaiting = "等待更新"
type Domain (line 26) | type Domain struct
method String (line 43) | func (d *Domain) String() string {
method GetFullDomain (line 51) | func (d *Domain) GetFullDomain() string {
method GetCustomParams (line 59) | func (d *Domain) GetCustomParams() url.Values {
method GetSubDomain (line 71) | func (d *Domain) GetSubDomain() string {
method SetDomainUpdateStatus (line 78) | func (d *Domain) SetDomainUpdateStatus(status string, message string) {
type UpdateHistroyItem (line 38) | type UpdateHistroyItem struct
function checkParseDomains (line 95) | func checkParseDomains(domainArr []string) (domains []Domain, domainsRaw...
FILE: module/ddns/ddnscore.go/taskinfo.go
type DDNSTaskInfo (line 7) | type DDNSTaskInfo struct
method CheckIPChange (line 13) | func (d *DDNSTaskInfo) CheckIPChange() (ipAddr string, change bool) {
method SyncDomains (line 23) | func (d *DDNSTaskInfo) SyncDomains() {
function getDomainIndex (line 43) | func getDomainIndex(domains []Domain, domain *Domain) (index int) {
FILE: module/ddns/ddnscore.go/taskstate.go
type DDNSTaskState (line 13) | type DDNSTaskState struct
method SetIPAddr (line 38) | func (d *DDNSTaskState) SetIPAddr(ipaddr string) {
method SetDomainUpdateStatus (line 64) | func (d *DDNSTaskState) SetDomainUpdateStatus(status string, message s...
method SetWebhookResult (line 70) | func (d *DDNSTaskState) SetWebhookResult(result bool, errMsg string) {
method Init (line 87) | func (d *DDNSTaskState) Init(domains []string, mt int64) {
method IPChanged (line 93) | func (d *DDNSTaskState) IPChanged(newAddr string) bool {
type IPAddrHistoryItem (line 28) | type IPAddrHistoryItem struct
type WebhookCallHistroyItem (line 33) | type WebhookCallHistroyItem struct
function DeleteAnyListlice (line 53) | func DeleteAnyListlice(a []any, deleteIndex int) []any {
FILE: module/ddns/ddnscore.go/webhook.go
method ExecWebhook (line 14) | func (d *DDNSTaskInfo) ExecWebhook(state *DDNSTaskState) {
function WebhookTest (line 61) | func WebhookTest(d *DDNSTaskInfo, url, method, WebhookRequestBody, proxy...
method webhookHttpClientDo (line 135) | func (d *DDNSTaskInfo) webhookHttpClientDo(method, url, requestBody stri...
function hasDomainTryToUpdate (line 199) | func hasDomainTryToUpdate(domains *[]Domain) bool {
function replaceWebhookTestPara (line 213) | func replaceWebhookTestPara(orgPara, nowTime string) (newPara string) {
method replaceWebhookPara (line 229) | func (d *DDNSTaskInfo) replaceWebhookPara(nowTime, orgPara string) (newP...
method getDomainsStr (line 253) | func (d *DDNSTaskInfo) getDomainsStr(domains *[]Domain) (string, string) {
FILE: module/ddns/ddnsgo/ddns.go
function init (line 13) | func init() {
function DDNSTaskListConfigureCheck (line 17) | func DDNSTaskListConfigureCheck() {
function DDNSTaskSetWebhookCallResult (line 35) | func DDNSTaskSetWebhookCallResult(taskKey string, result bool, message s...
function GetDDNSTaskConfigureList (line 54) | func GetDDNSTaskConfigureList() []*ddnsconf.DDNSTask {
function GetDDNSTaskByKey (line 67) | func GetDDNSTaskByKey(taskKey string) *ddnsconf.DDNSTask {
function DDNSTaskListAdd (line 86) | func DDNSTaskListAdd(task *ddnsconf.DDNSTask) error {
function DDNSTaskListDelete (line 95) | func DDNSTaskListDelete(taskKey string) error {
function EnableDDNSTaskByKey (line 116) | func EnableDDNSTaskByKey(taskKey string, enable bool) error {
function UpdateTaskToDDNSTaskList (line 135) | func UpdateTaskToDDNSTaskList(taskKey string, task ddnsconf.DDNSTask) er...
function DeleteDDNSTaskListlice (line 169) | func DeleteDDNSTaskListlice(a []ddnsconf.DDNSTask, deleteIndex int) []dd...
function GetDDNSConfigure (line 180) | func GetDDNSConfigure() ddnsconf.DDNSConfigure {
function SetDDNSConfigure (line 187) | func SetDDNSConfigure(conf *ddnsconf.DDNSConfigure) error {
FILE: module/ddns/providers/alidns.go
constant alidnsEndpoint (line 16) | alidnsEndpoint string = "https://alidns.aliyuncs.com/"
type Alidns (line 21) | type Alidns struct
method Init (line 48) | func (ali *Alidns) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 60) | func (ali *Alidns) createUpdateDomain(recordType, ipAddr string, domai...
method create (line 94) | func (ali *Alidns) create(domain *ddnscore.Domain, recordType string, ...
method modify (line 118) | func (ali *Alidns) modify(recordSelected AlidnsRecord, domain *ddnscor...
method request (line 153) | func (ali *Alidns) request(params url.Values, result interface{}) (err...
type AlidnsRecord (line 27) | type AlidnsRecord struct
type AlidnsSubDomainRecords (line 34) | type AlidnsSubDomainRecords struct
type AlidnsResp (line 42) | type AlidnsResp struct
FILE: module/ddns/providers/baidu.go
constant baiduEndpoint (line 18) | baiduEndpoint = "https://bcd.baidubce.com"
type BaiduCloud (line 21) | type BaiduCloud struct
method Init (line 71) | func (baidu *BaiduCloud) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 88) | func (baidu *BaiduCloud) createUpdateDomain(recordType, ipAddr string,...
method create (line 121) | func (baidu *BaiduCloud) create(domain *ddnscore.Domain, recordType st...
method modify (line 142) | func (baidu *BaiduCloud) modify(record BaiduRecord, domain *ddnscore.D...
method request (line 174) | func (baidu *BaiduCloud) request(method string, url string, data inter...
type BaiduRecord (line 27) | type BaiduRecord struct
type BaiduRecordsResp (line 39) | type BaiduRecordsResp struct
type BaiduListRequest (line 45) | type BaiduListRequest struct
type BaiduModifyRequest (line 52) | type BaiduModifyRequest struct
type BaiduCreateRequest (line 63) | type BaiduCreateRequest struct
FILE: module/ddns/providers/callback.go
type Callback (line 14) | type Callback struct
method Init (line 20) | func (cb *Callback) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 42) | func (cb *Callback) createUpdateDomain(recordType, ipAddr string, doma...
method CallbackHttpClientDo (line 87) | func (cb *Callback) CallbackHttpClientDo(method, url, requestBody stri...
function CopyHeadersMap (line 32) | func CopyHeadersMap(sm map[string]string) map[string]string {
function replacePara (line 72) | func replacePara(orgPara, ipAddr string, domain *ddnscore.Domain, record...
FILE: module/ddns/providers/cloudflare.go
constant zonesAPI (line 16) | zonesAPI string = "https://api.cloudflare.com/client/v4/zones"
type Cloudflare (line 20) | type Cloudflare struct
method Init (line 59) | func (cf *Cloudflare) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 76) | func (cf *Cloudflare) createUpdateDomain(recordType, ipAddr string, do...
method create (line 118) | func (cf *Cloudflare) create(zoneID string, domain *ddnscore.Domain, r...
method modify (line 148) | func (cf *Cloudflare) modify(result CloudflareRecordsResp, zoneID stri...
method getZones (line 186) | func (cf *Cloudflare) getZones(domain *ddnscore.Domain) (result Cloudf...
method request (line 198) | func (cf *Cloudflare) request(method string, url string, data interfac...
type CloudflareZonesResp (line 26) | type CloudflareZonesResp struct
type CloudflareRecordsResp (line 37) | type CloudflareRecordsResp struct
type CloudflareRecord (line 43) | type CloudflareRecord struct
type CloudflareStatus (line 53) | type CloudflareStatus struct
FILE: module/ddns/providers/dnspod.go
constant recordListAPI (line 12) | recordListAPI string = "https://dnsapi.cn/Record.List"
constant recordModifyURL (line 13) | recordModifyURL string = "https://dnsapi.cn/Record.Modify"
constant recordCreateAPI (line 14) | recordCreateAPI string = "https://dnsapi.cn/Record.Create"
type Dnspod (line 19) | type Dnspod struct
method Init (line 45) | func (dnspod *Dnspod) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 56) | func (dnspod *Dnspod) createUpdateDomain(recordType, ipAddr string, do...
method create (line 75) | func (dnspod *Dnspod) create(result DnspodRecordListResp, domain *ddns...
method modify (line 103) | func (dnspod *Dnspod) modify(result DnspodRecordListResp, domain *ddns...
method commonRequest (line 142) | func (dnspod *Dnspod) commonRequest(apiAddr string, values url.Values,...
method getRecordList (line 164) | func (dnspod *Dnspod) getRecordList(domain *ddnscore.Domain, typ strin...
type DnspodRecordListResp (line 25) | type DnspodRecordListResp struct
type DnspodStatus (line 37) | type DnspodStatus struct
FILE: module/ddns/providers/godaddy.go
type godaddyRecord (line 14) | type godaddyRecord struct
type godaddyRecords (line 21) | type godaddyRecords
type GoDaddy (line 23) | type GoDaddy struct
method Init (line 31) | func (gd *GoDaddy) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 60) | func (gd *GoDaddy) createUpdateDomain(recordType, ipAddr string, domai...
method sendReq (line 73) | func (gd *GoDaddy) sendReq(method string, rType string, domain *ddnsco...
FILE: module/ddns/providers/huawei.go
constant huaweicloudEndpoint (line 17) | huaweicloudEndpoint string = "https://dns.myhuaweicloud.com"
type Huaweicloud (line 22) | type Huaweicloud struct
method Init (line 53) | func (hw *Huaweicloud) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 70) | func (hw *Huaweicloud) createUpdateDomain(recordType, ipAddr string, d...
method create (line 105) | func (hw *Huaweicloud) create(domain *ddnscore.Domain, recordType stri...
method modify (line 149) | func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *dd...
method getZones (line 187) | func (hw *Huaweicloud) getZones(domain *ddnscore.Domain) (result Huawe...
method request (line 199) | func (hw *Huaweicloud) request(method string, url string, data interfa...
type HuaweicloudZonesResp (line 28) | type HuaweicloudZonesResp struct
type HuaweicloudRecordsResp (line 37) | type HuaweicloudRecordsResp struct
type HuaweicloudRecordsets (line 42) | type HuaweicloudRecordsets struct
FILE: module/ddns/providers/porkbun.go
constant porkbunEndpoint (line 16) | porkbunEndpoint string = "https://porkbun.com/api/json/v3/dns"
type Porkbun (line 19) | type Porkbun struct
method Init (line 50) | func (pb *Porkbun) Init(task *ddnscore.DDNSTaskInfo) {
method createUpdateDomain (line 61) | func (pb *Porkbun) createUpdateDomain(recordType, ipAddr string, domai...
method create (line 91) | func (pb *Porkbun) create(domain *ddnscore.Domain, recordType string, ...
method modify (line 123) | func (pb *Porkbun) modify(record *PorkbunDomainQueryResponse, domain *...
method request (line 164) | func (pb *Porkbun) request(url string, data interface{}, result interf...
type PorkbunDomainRecord (line 23) | type PorkbunDomainRecord struct
type PorkbunResponse (line 30) | type PorkbunResponse struct
type PorkbunDomainQueryResponse (line 34) | type PorkbunDomainQueryResponse struct
type PorkbunApiKey (line 39) | type PorkbunApiKey struct
type PorkbunDomainCreateOrUpdateVO (line 44) | type PorkbunDomainCreateOrUpdateVO struct
FILE: module/ddns/providers/provider.go
type Provider (line 6) | type Provider interface
FILE: module/ddns/providers/providercommon.go
type ProviderCommon (line 14) | type ProviderCommon struct
method SetCreateUpdateDomainFunc (line 20) | func (d *ProviderCommon) SetCreateUpdateDomainFunc(f func(recordType, ...
method Init (line 24) | func (d *ProviderCommon) Init(task *ddnscore.DDNSTaskInfo) {
method AddUpdateDomainRecords (line 30) | func (d *ProviderCommon) AddUpdateDomainRecords() string {
method addUpdateDomainRecords (line 38) | func (d *ProviderCommon) addUpdateDomainRecords(recordType string) str...
method CreateHTTPClient (line 155) | func (d *ProviderCommon) CreateHTTPClient() (*http.Client, error) {
function getDomainItem (line 141) | func getDomainItem(fullDomain string, domains *[]ddnscore.Domain) *ddnsc...
FILE: module/ddns/worker.go
function init (line 18) | func init() {
function Run (line 25) | func Run(firstDelay time.Duration, delay time.Duration) {
function syncAllDomainsOnce (line 35) | func syncAllDomainsOnce(params ...any) {
function syncTaskDomainsOnce (line 89) | func syncTaskDomainsOnce(params ...any) {
function syncDDNSTask (line 106) | func syncDDNSTask(task *ddnscore.DDNSTaskInfo) {
FILE: module/portforward/conf/portforward.go
type PortForwardsConfigure (line 15) | type PortForwardsConfigure struct
type PortForwardsRule (line 21) | type PortForwardsRule struct
method ProxyCount (line 41) | func (r *PortForwardsRule) ProxyCount() int {
method StartAllProxys (line 48) | func (r *PortForwardsRule) StartAllProxys() {
method GetLastLogs (line 58) | func (r *PortForwardsRule) GetLastLogs(maxCount int) []any {
method Fire (line 62) | func (r *PortForwardsRule) Fire(entry *logrus.Entry) error {
method Levels (line 71) | func (r *PortForwardsRule) Levels() []logrus.Level {
method GetLogrus (line 75) | func (r *PortForwardsRule) GetLogrus() *logrus.Logger {
method GetLogsBuffer (line 91) | func (r *PortForwardsRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
method StopAllProxys (line 98) | func (r *PortForwardsRule) StopAllProxys() {
method InitProxyList (line 107) | func (r *PortForwardsRule) InitProxyList() error {
function PortsStrToIList (line 140) | func PortsStrToIList(portsStr string) (ports []int, err error) {
function portStrToi (line 202) | func portStrToi(portStr string) (int, error) {
function PortsCheck (line 213) | func PortsCheck(ports1Str, ports2Str string) (bool, error) {
FILE: module/portforward/portforward.go
function Init (line 14) | func Init() {
function TidyPortforwardLogsCache (line 19) | func TidyPortforwardLogsCache() {
function PortForwardsRuleListInit (line 53) | func PortForwardsRuleListInit() {
function GetPortForwardsRuleList (line 68) | func GetPortForwardsRuleList() []portforwardconf.PortForwardsRule {
function GetPortForwardsGlobalProxyCount (line 81) | func GetPortForwardsGlobalProxyCount() int {
function GetPortForwardsGlobalProxyCountExcept (line 91) | func GetPortForwardsGlobalProxyCountExcept(key string) int {
function GetPortForwardsRuleByKey (line 104) | func GetPortForwardsRuleByKey(key string) *portforwardconf.PortForwardsR...
function StopAllSocketProxysByRuleKey (line 122) | func StopAllSocketProxysByRuleKey(key string) error {
function StartAllSocketProxysByRuleKey (line 140) | func StartAllSocketProxysByRuleKey(key string) error {
function PortForwardsRuleListAdd (line 158) | func PortForwardsRuleListAdd(r *portforwardconf.PortForwardsRule) error {
function PortForwardsRuleListDelete (line 166) | func PortForwardsRuleListDelete(key string) error {
function EnablePortForwardsRuleByKey (line 189) | func EnablePortForwardsRuleByKey(key string, enable bool) error {
function UpdatePortForwardsRuleToPortForwardsRuleList (line 214) | func UpdatePortForwardsRuleToPortForwardsRuleList(key string, r *portfor...
function DeletePortForwardsRuleListSlice (line 234) | func DeletePortForwardsRuleListSlice(a []portforwardconf.PortForwardsRul...
function GetPortForwardsConfigure (line 245) | func GetPortForwardsConfigure() portforwardconf.PortForwardsConfigure {
function SetPortForwardsConfigure (line 252) | func SetPortForwardsConfigure(conf *portforwardconf.PortForwardsConfigur...
FILE: module/portforward/socketproxy/baseproxyconf.go
type BaseProxyConf (line 8) | type BaseProxyConf struct
method GetProxyType (line 16) | func (p *BaseProxyConf) GetProxyType() string {
method GetStatus (line 20) | func (p *BaseProxyConf) GetStatus() string {
method ReceiveDataCallback (line 24) | func (p *BaseProxyConf) ReceiveDataCallback(nw int64) {
method SendDataCallback (line 28) | func (p *BaseProxyConf) SendDataCallback(nw int64) {
method GetTrafficIn (line 32) | func (p *BaseProxyConf) GetTrafficIn() int64 {
method GetTrafficOut (line 36) | func (p *BaseProxyConf) GetTrafficOut() int64 {
FILE: module/portforward/socketproxy/proxy.go
type Proxy (line 15) | type Proxy interface
type RelayRuleOptions (line 34) | type RelayRuleOptions struct
method relayData (line 44) | func (p *BaseProxyConf) relayData(targetServer io.ReadWriteCloser, clien...
method CopyBuffer (line 75) | func (p *BaseProxyConf) CopyBuffer(dst io.Writer, src io.Reader, buf []b...
method copyBuffer (line 84) | func (p *BaseProxyConf) copyBuffer(dst io.Writer, src io.Reader, buf []b...
function formatFileSize (line 143) | func formatFileSize(fileSize int64) (size string) {
function CreateProxy (line 161) | func CreateProxy(log *logrus.Logger, proxyType, listenIP string, targetA...
function GetProxyKey (line 178) | func GetProxyKey(proxyType, listenIP string, listenPort int) string {
FILE: module/portforward/socketproxy/tcpproxy.go
type TCPProxy (line 14) | type TCPProxy struct
method GetStatus (line 40) | func (p *TCPProxy) GetStatus() string {
method CheckConnectionsLimit (line 44) | func (p *TCPProxy) CheckConnectionsLimit() error {
method StartProxy (line 58) | func (p *TCPProxy) StartProxy() {
method StopProxy (line 131) | func (p *TCPProxy) StopProxy() {
method handle (line 152) | func (p *TCPProxy) handle(conn net.Conn) {
function CreateTCPProxy (line 25) | func CreateTCPProxy(log *logrus.Logger, proxyType, listenIP string, targ...
FILE: module/portforward/socketproxy/tcpudpcommon.go
constant TCP_DEFAULT_STREAM_BUFFERSIZE (line 14) | TCP_DEFAULT_STREAM_BUFFERSIZE = 128
constant DEFAULT_GLOBAL_MAX_CONNECTIONS (line 15) | DEFAULT_GLOBAL_MAX_CONNECTIONS = int64(1024)
constant DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount (line 16) | DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount = int64(1024)
constant TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS (line 17) | TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS = int64(256)
constant DEFAULT_MAX_PORTFORWARDS_LIMIT (line 19) | DEFAULT_MAX_PORTFORWARDS_LIMIT = int64(128)
function SetSafeCheck (line 31) | func SetSafeCheck(f func(mode, ip string) bool) {
function SetGlobalUDPReadTargetDataMaxgoroutineCountLimit (line 35) | func SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(max int64) {
function GetGlobalUDPReadTargetDataMaxgoroutineCountLimit (line 39) | func GetGlobalUDPReadTargetDataMaxgoroutineCountLimit() int64 {
function SetGlobalMaxPortForwardsCountLimit (line 43) | func SetGlobalMaxPortForwardsCountLimit(max int64) {
function GetGlobalMaxPortForwardsCountLimit (line 47) | func GetGlobalMaxPortForwardsCountLimit() int64 {
function SetGlobalTCPPortforwardMaxConnections (line 51) | func SetGlobalTCPPortforwardMaxConnections(max int64) {
function GetGlobalTCPPortforwardMaxConnections (line 55) | func GetGlobalTCPPortforwardMaxConnections() int64 {
function GetGlobalTCPPortForwardConnections (line 59) | func GetGlobalTCPPortForwardConnections() int64 {
function GloBalTCPPortForwardConnectionsAdd (line 63) | func GloBalTCPPortForwardConnectionsAdd(add int64) int64 {
function GetGlobalUDPPortForwardGroutineCount (line 67) | func GetGlobalUDPPortForwardGroutineCount() int64 {
function GloBalUDPPortForwardGroutineCountAdd (line 71) | func GloBalUDPPortForwardGroutineCountAdd(add int64) int64 {
type TCPUDPProxyCommonConf (line 75) | type TCPUDPProxyCommonConf struct
method SetMaxConnections (line 98) | func (p *TCPUDPProxyCommonConf) SetMaxConnections(max int64) {
method AddCurrentConnections (line 106) | func (p *TCPUDPProxyCommonConf) AddCurrentConnections(a int64) {
method GetCurrentConnections (line 120) | func (p *TCPUDPProxyCommonConf) GetCurrentConnections() int64 {
method GetListentAddress (line 124) | func (p *TCPUDPProxyCommonConf) GetListentAddress() string {
method GetKey (line 135) | func (p *TCPUDPProxyCommonConf) GetKey() string {
method GetListenIP (line 142) | func (p *TCPUDPProxyCommonConf) GetListenIP() string {
method GetListenPort (line 146) | func (p *TCPUDPProxyCommonConf) GetListenPort() int {
method GetTargetAddress (line 150) | func (p *TCPUDPProxyCommonConf) GetTargetAddress() string {
method String (line 162) | func (p *TCPUDPProxyCommonConf) String() string {
method SafeCheck (line 166) | func (p *TCPUDPProxyCommonConf) SafeCheck(remodeAddr string) bool {
FILE: module/portforward/socketproxy/udpproxy.go
constant UDP_DEFAULT_PACKAGE_SIZE (line 17) | UDP_DEFAULT_PACKAGE_SIZE = 1500
type UDPProxy (line 21) | type UDPProxy struct
method getHandlegoroutineNum (line 72) | func (p *UDPProxy) getHandlegoroutineNum() int {
method SetUDPPacketSize (line 79) | func (p *UDPProxy) SetUDPPacketSize(size int) {
method GetUDPPacketSize (line 91) | func (p *UDPProxy) GetUDPPacketSize() int {
method StartProxy (line 96) | func (p *UDPProxy) StartProxy() {
method StopProxy (line 153) | func (p *UDPProxy) StopProxy() {
method ReadFromTargetOnce (line 179) | func (p *UDPProxy) ReadFromTargetOnce() bool {
method ListenHandler (line 190) | func (p *UDPProxy) ListenHandler(ln *net.UDPConn) {
method handlerDataFromTargetAddress (line 234) | func (p *UDPProxy) handlerDataFromTargetAddress(raddr *net.UDPAddr, tg...
method Forwarder (line 311) | func (p *UDPProxy) Forwarder(kk int, replych chan *udpPackge) {
method replyDataToRemotAddress (line 380) | func (p *UDPProxy) replyDataToRemotAddress() {
method CheckReadTargetDataGoroutineLimit (line 392) | func (p *UDPProxy) CheckReadTargetDataGoroutineLimit() error {
method CheckTargetUDPConnectSessions (line 403) | func (p *UDPProxy) CheckTargetUDPConnectSessions() {
type udpPackge (line 42) | type udpPackge struct
type udpTagetConSession (line 48) | type udpTagetConSession struct
function CreateUDPProxy (line 53) | func CreateUDPProxy(log *logrus.Logger, proxyType, listenIP string, targ...
FILE: module/reverseproxy/conf/reverseproxy.go
type SubReverProxyRule (line 32) | type SubReverProxyRule struct
method Logf (line 96) | func (r *SubReverProxyRule) Logf(level logrus.Level, c *gin.Context, f...
method HandlerReverseProxy (line 118) | func (r *SubReverProxyRule) HandlerReverseProxy(remote *url.URL, host,...
method Fire (line 138) | func (r *SubReverProxyRule) Fire(entry *logrus.Entry) error {
method Levels (line 147) | func (r *SubReverProxyRule) Levels() []logrus.Level {
method GetLogrus (line 151) | func (r *SubReverProxyRule) GetLogrus() *logrus.Logger {
method GetLogger (line 168) | func (r *SubReverProxyRule) GetLogger() *log.Logger {
method GetLogsBuffer (line 175) | func (r *SubReverProxyRule) GetLogsBuffer() *logsbuffer.LogsBuffer {
method checkupClientIP (line 182) | func (r *SubReverProxyRule) checkupClientIP(ip string) bool {
method checkupUserAgent (line 186) | func (r *SubReverProxyRule) checkupUserAgent(ua string) bool {
method initOnceExec (line 398) | func (r *SubReverProxyRule) initOnceExec() {
method GetLocation (line 406) | func (r *SubReverProxyRule) GetLocation() string {
method BasicAuthHandler (line 421) | func (r *SubReverProxyRule) BasicAuthHandler(c *gin.Context) bool {
method InitTrustedProxyCIDRs (line 439) | func (r *SubReverProxyRule) InitTrustedProxyCIDRs() error {
method ClientIP (line 455) | func (r *SubReverProxyRule) ClientIP(c *gin.Context) string {
method validateHeader (line 475) | func (r *SubReverProxyRule) validateHeader(header string) (clientIP st...
method isTrustedProxy (line 494) | func (r *SubReverProxyRule) isTrustedProxy(ip net.IP) bool {
type ReverseProxyRule (line 71) | type ReverseProxyRule struct
method Init (line 89) | func (r *ReverseProxyRule) Init() {
method ReverseProxyHandler (line 206) | func (r *ReverseProxyRule) ReverseProxyHandler(c *gin.Context) {
method GetSubRuleByDomain (line 274) | func (r *ReverseProxyRule) GetSubRuleByDomain(domain string) (*Reverse...
method GetServer (line 290) | func (r *ReverseProxyRule) GetServer() *http.Server {
method SetServer (line 298) | func (r *ReverseProxyRule) SetServer(s *http.Server) {
method ServerStart (line 306) | func (r *ReverseProxyRule) ServerStart() error {
method ServerStop (line 373) | func (r *ReverseProxyRule) ServerStop() {
method initDomainsMap (line 385) | func (r *ReverseProxyRule) initDomainsMap() error {
method Addr (line 508) | func (r *ReverseProxyRule) Addr() string {
method GetLastLogs (line 512) | func (r *ReverseProxyRule) GetLastLogs() map[string][]any {
type ReverseProxy (line 282) | type ReverseProxy struct
FILE: module/reverseproxy/proxy.go
function InitReverseProxyServer (line 11) | func InitReverseProxyServer() {
function EnableRuleByKey (line 25) | func EnableRuleByKey(key string, enable bool) error {
type RuleInfo (line 49) | type RuleInfo struct
function GetProxyRuleListInfo (line 54) | func GetProxyRuleListInfo() *[]RuleInfo {
function GetAccessLogs (line 67) | func GetAccessLogs(ruleKey, proxyKey string, pageSize, page int) (int, [...
FILE: module/reverseproxy/reverseproxy.go
function init (line 14) | func init() {
function TidyReverseProxyCache (line 20) | func TidyReverseProxyCache() {
function GetReverseProxyRuleList (line 60) | func GetReverseProxyRuleList() []*reverseproxyconf.ReverseProxyRule {
function GetReverseProxyRuleByKey (line 74) | func GetReverseProxyRuleByKey(ruleKey string) *reverseproxyconf.ReverseP...
function ReverseProxyRuleListAdd (line 94) | func ReverseProxyRuleListAdd(rule *reverseproxyconf.ReverseProxyRule) er...
function ReverseProxyRuleListDelete (line 102) | func ReverseProxyRuleListDelete(ruleKey string) error {
function EnableReverseProxyRuleByKey (line 123) | func EnableReverseProxyRuleByKey(ruleKey string, enable bool) error {
function EnableReverseProxySubRule (line 142) | func EnableReverseProxySubRule(ruleKey, proxyKey string, enable bool) er...
function UpdateReverseProxyRulet (line 175) | func UpdateReverseProxyRulet(rule reverseproxyconf.ReverseProxyRule) err...
function DeleteReverseProxyRuleListlice (line 197) | func DeleteReverseProxyRuleListlice(a []reverseproxyconf.ReverseProxyRul...
function GetSubRuleByKey (line 208) | func GetSubRuleByKey(ruleKey, proxyKey string) *reverseproxyconf.SubReve...
FILE: module/safe/blacklist.go
function GetBlackList (line 14) | func GetBlackList() []safeconf.BlackListItem {
function BlackListInit (line 30) | func BlackListInit() {
function BlackListAdd (line 49) | func BlackListAdd(ip string, activelifeDuration int32) (string, error) {
function BlackListDelete (line 85) | func BlackListDelete(ip string) error {
function BlackListFlush (line 111) | func BlackListFlush(lock bool) error {
function DeleteBlackListlice (line 148) | func DeleteBlackListlice(a []safeconf.BlackListItem, deleteIndex int) []...
FILE: module/safe/conf/black.go
type BlackListItem (line 5) | type BlackListItem
method Contains (line 11) | func (w *BlackListItem) Contains(ip string) bool {
type BlackListConfigure (line 7) | type BlackListConfigure struct
FILE: module/safe/conf/white.go
type WhiteListBaseConfigure (line 5) | type WhiteListBaseConfigure struct
type WhiteListConfigure (line 12) | type WhiteListConfigure struct
type WhiteListItem (line 17) | type WhiteListItem struct
method Contains (line 24) | func (w *WhiteListItem) Contains(ip string) bool {
FILE: module/safe/safe.go
function Init (line 3) | func Init() {
FILE: module/safe/safecheck.go
function SafeCheck (line 10) | func SafeCheck(mode, ip string) bool {
function whiteListCheck (line 23) | func whiteListCheck(ip string) bool {
function blackListCheck (line 52) | func blackListCheck(ip string) bool {
FILE: module/safe/whitelist.go
function GetWhiteListBaseConfigure (line 14) | func GetWhiteListBaseConfigure() safeconf.WhiteListBaseConfigure {
function SetWhiteListBaseConfigure (line 20) | func SetWhiteListBaseConfigure(activelifeDuration int32, url, account, p...
function GetWhiteList (line 30) | func GetWhiteList() []safeconf.WhiteListItem {
function WhiteListInit (line 46) | func WhiteListInit() {
function WhiteListAdd (line 65) | func WhiteListAdd(ip string, activelifeDuration int32) (string, error) {
function WhiteListDelete (line 101) | func WhiteListDelete(ip string) error {
function WhiteListFlush (line 127) | func WhiteListFlush(lock bool) error {
function DeleteWhiteListlice (line 164) | func DeleteWhiteListlice(a []safeconf.WhiteListItem, deleteIndex int) []...
FILE: module/service/service.go
function RegisterStartFunc (line 17) | func RegisterStartFunc(f func()) {
function SetListenPort (line 21) | func SetListenPort(port int) {
function SetConfigureFile (line 25) | func SetConfigureFile(f string) {
type Service (line 29) | type Service struct
method Start (line 32) | func (p *Service) Start(s kservice.Service) error {
method run (line 37) | func (p *Service) run() {
method Stop (line 44) | func (p *Service) Stop(s kservice.Service) error {
function GetServiceState (line 48) | func GetServiceState() int {
function GetService (line 58) | func GetService() (kservice.Service, error) {
function UninstallService (line 84) | func UninstallService() error {
function InstallService (line 94) | func InstallService() error {
function Stop (line 114) | func Stop() error {
function Start (line 122) | func Start() error {
function Restart (line 130) | func Restart() error {
FILE: module/sslcertficate/conf/sslconf.go
type SSLCertficate (line 11) | type SSLCertficate struct
method Init (line 29) | func (s *SSLCertficate) Init() error {
method GetFirstDomain (line 44) | func (s *SSLCertficate) GetFirstDomain() string {
type CertInfo (line 23) | type CertInfo struct
function CreateX509KeyPairByBase64Str (line 57) | func CreateX509KeyPairByBase64Str(certBase64, keyBase64 string) (*tls.Ce...
function GetCertDomainInfo (line 75) | func GetCertDomainInfo(cert *tls.Certificate) (*[]CertInfo, error) {
function GetDomainsTrimSpace (line 101) | func GetDomainsTrimSpace(dst []string) []string {
FILE: module/sslcertficate/ssl.go
function Init (line 3) | func Init() {
FILE: module/sslcertficate/sslcertficate.go
function GetCertDomains (line 16) | func GetCertDomains(cert *tls.Certificate) []string {
function GetDomainsStrByDomains (line 37) | func GetDomainsStrByDomains(dst []string) string {
function SSLCertficateListInit (line 54) | func SSLCertficateListInit() {
function GetSSLCertficateList (line 66) | func GetSSLCertficateList() []sslconf.SSLCertficate {
function SSLCertficateListAdd (line 80) | func SSLCertficateListAdd(s *sslconf.SSLCertficate) error {
function SSLCertficateListDelete (line 108) | func SSLCertficateListDelete(key string) error {
function SSLCertficateEnable (line 127) | func SSLCertficateEnable(key string, enable bool) error {
function SSLCertficateAlterRemark (line 144) | func SSLCertficateAlterRemark(key, remark string) error {
function DeleteSSLCertficateListslice (line 161) | func DeleteSSLCertficateListslice(a []sslconf.SSLCertficate, deleteIndex...
function GetValidSSLCertficateList (line 172) | func GetValidSSLCertficateList() []tls.Certificate {
FILE: module/weblog/weblog.go
type LogItem (line 9) | type LogItem struct
function WebLogConvert (line 17) | func WebLogConvert(lg *logsbuffer.LogItem) any {
FILE: module/wol/client.go
function init (line 21) | func init() {
function GetClientState (line 26) | func GetClientState() string {
function GetClientStateMsg (line 30) | func GetClientStateMsg() string {
function ClientDisconnect (line 34) | func ClientDisconnect() {
function WOLClientInit (line 43) | func WOLClientInit(logger *logrus.Logger, c *wolconf.WOLClientConfigure) {
function receiveMessageCallback (line 68) | func receiveMessageCallback(c *websocketcontroller.Controller, msgBytes ...
function clientStop (line 109) | func clientStop(cc *websocketcontroller.Controller) {
function clientReady (line 115) | func clientReady(cc *websocketcontroller.Controller) {
function handlerLoginResp (line 123) | func handlerLoginResp(m *LoginResp, c *websocketcontroller.Controller) {
function synsClientConfigureToClient (line 137) | func synsClientConfigureToClient(m *SyncClientConfigure) {
FILE: module/wol/conf/device.go
function GetHttpClientSecureVerify (line 17) | func GetHttpClientSecureVerify() bool {
function SetHttpClientSecureVerify (line 21) | func SetHttpClientSecureVerify(b bool) {
function SetHttpClientTimeout (line 25) | func SetHttpClientTimeout(t int) {
type WOLDevice (line 29) | type WOLDevice struct
method SetShutDownFunc (line 54) | func (d *WOLDevice) SetShutDownFunc(f func(d *WOLDevice) int) {
method GetDianDengClientState (line 58) | func (d *WOLDevice) GetDianDengClientState() string {
method GetBemfaClientState (line 73) | func (d *WOLDevice) GetBemfaClientState() string {
method BemfaClientStart (line 88) | func (d *WOLDevice) BemfaClientStart() {
method BemfaClientStop (line 105) | func (d *WOLDevice) BemfaClientStop() {
method SetBemfaClientMsg (line 113) | func (d *WOLDevice) SetBemfaClientMsg(msg string) {
method GetBemfaClient (line 117) | func (d *WOLDevice) GetBemfaClient() *bemfa.Device {
method SetBemfaClient (line 121) | func (d *WOLDevice) SetBemfaClient(dd *bemfa.Device) {
method DianDengClientStart (line 127) | func (d *WOLDevice) DianDengClientStart() {
method DianDengClientStop (line 144) | func (d *WOLDevice) DianDengClientStop() {
method powerChange (line 152) | func (d *WOLDevice) powerChange(state string) {
method SetDianDengClientMsg (line 163) | func (d *WOLDevice) SetDianDengClientMsg(msg string) {
method GetDianDengClient (line 167) | func (d *WOLDevice) GetDianDengClient() *blinker.Device {
method SetDianDengClient (line 171) | func (d *WOLDevice) SetDianDengClient(dd *blinker.Device) {
method GetIdentKey (line 175) | func (d *WOLDevice) GetIdentKey() string {
method WakeUp (line 179) | func (d *WOLDevice) WakeUp(finishedCallback func(relay bool, macList [...
function WakeOnLan (line 183) | func WakeOnLan(relay bool, macList []string, broadcastIps []string, port...
FILE: module/wol/conf/service.go
type WOLServerConfigure (line 9) | type WOLServerConfigure struct
type WOLClientConfigure (line 14) | type WOLClientConfigure struct
method Init (line 61) | func (c *WOLClientConfigure) Init(logger *logrus.Logger) {
method ClientDisconnect (line 67) | func (c *WOLClientConfigure) ClientDisconnect() {
type WOLServiceConfigure (line 30) | type WOLServiceConfigure struct
function SetClientInitFunc (line 40) | func SetClientInitFunc(f func(logger *logrus.Logger, c *WOLClientConfigu...
function SetClientDisconnectFunc (line 44) | func SetClientDisconnectFunc(f func()) {
function GetWOLServiceConfigure (line 48) | func GetWOLServiceConfigure() WOLServiceConfigure {
function StoreWOLServiceConfigure (line 55) | func StoreWOLServiceConfigure(con *WOLServiceConfigure) {
FILE: module/wol/ctl.go
function init (line 17) | func init() {
function SendMessageEncryptionFunc (line 24) | func SendMessageEncryptionFunc(messageBytesPtr []byte) ([]byte, error) {
function ReceiveMessageDecryptionFunc (line 32) | func ReceiveMessageDecryptionFunc(messageBytes []byte) ([]byte, error) {
FILE: module/wol/device.go
function WOLClientConfigureInit (line 18) | func WOLClientConfigureInit(l *logrus.Logger) {
function GetWOLServiceConfigure (line 31) | func GetWOLServiceConfigure() wolconf.WOLServiceConfigure {
function AlterWOLClientConfigure (line 38) | func AlterWOLClientConfigure(conf *wolconf.WOLServiceConfigure, logger *...
function handlerWOLServerURL (line 78) | func handlerWOLServerURL(l string) string {
function CheckWOLServiceConfigure (line 104) | func CheckWOLServiceConfigure(conf *wolconf.WOLServiceConfigure) error {
function GetWOLDeviceByKey (line 134) | func GetWOLDeviceByKey(key string) *wolconf.WOLDevice {
function GetWOLDeviceByMac (line 153) | func GetWOLDeviceByMac(mac string) *wolconf.WOLDevice {
function GetWOLDeviceList (line 172) | func GetWOLDeviceList() []wolconf.WOLDevice {
function GetDeviceStateDetail (line 186) | func GetDeviceStateDetail(d *wolconf.WOLDevice) (state string, onlineMac...
function WOLDeviceListAdd (line 249) | func WOLDeviceListAdd(d *wolconf.WOLDevice) error {
function WOLDeviceListAlter (line 270) | func WOLDeviceListAlter(d *wolconf.WOLDevice) error {
function WOLDeviceListReplace (line 296) | func WOLDeviceListReplace(key string, d *wolconf.WOLDevice) error {
function WOLDeviceListDelete (line 313) | func WOLDeviceListDelete(key string) error {
function DeleteWOLDeviceListslice (line 334) | func DeleteWOLDeviceListslice(a []wolconf.WOLDevice, deleteIndex int) []...
FILE: module/wol/httpapi/api.go
function SetLogger (line 21) | func SetLogger(l *logrus.Logger) {
function RegisterAPI (line 26) | func RegisterAPI(r *gin.Engine, authorized *gin.RouterGroup) {
function AddWOLDevice (line 47) | func AddWOLDevice(c *gin.Context) {
type DeviceInfo (line 71) | type DeviceInfo struct
function GetWOLDeviceList (line 79) | func GetWOLDeviceList(c *gin.Context) {
function AlterWOLDevice (line 97) | func AlterWOLDevice(c *gin.Context) {
function DeleteWOLDevice (line 122) | func DeleteWOLDevice(c *gin.Context) {
function WOLDeviceWakeUp (line 132) | func WOLDeviceWakeUp(c *gin.Context) {
function WOLDeviceShutDown (line 148) | func WOLDeviceShutDown(c *gin.Context) {
function checkWolDevice (line 167) | func checkWolDevice(d *wolconf.WOLDevice) error {
function WOLServiceConfigure (line 213) | func WOLServiceConfigure(c *gin.Context) {
function GetIPv4Interface (line 224) | func GetIPv4Interface(c *gin.Context) {
function WOLAlterServiceConfigure (line 233) | func WOLAlterServiceConfigure(c *gin.Context) {
function WOLWebsocketHandler (line 248) | func WOLWebsocketHandler(c *gin.Context) {
FILE: module/wol/module.go
function Init (line 8) | func Init(log *logrus.Logger) {
function deviceInit (line 14) | func deviceInit(log *logrus.Logger) {
FILE: module/wol/msg.go
constant TypeLogin (line 8) | TypeLogin = '0'
constant TypeLoginResp (line 9) | TypeLoginResp = '1'
constant TypeSyncClientConfigure (line 10) | TypeSyncClientConfigure = '2'
constant TypeReplyWakeUp (line 11) | TypeReplyWakeUp = '3'
constant TypeShutDown (line 12) | TypeShutDown = '4'
type Login (line 25) | type Login struct
type LoginResp (line 31) | type LoginResp struct
type SyncClientConfigure (line 36) | type SyncClientConfigure struct
type ReplyWakeUp (line 40) | type ReplyWakeUp struct
type ShutDown (line 47) | type ShutDown struct
FILE: module/wol/service.go
function ReceiveMsgFromWOLClient (line 14) | func ReceiveMsgFromWOLClient(c *websocketcontroller.Controller, msgBytes...
function SyncClientConfigureToClient (line 28) | func SyncClientConfigureToClient(d *wolconf.WOLDevice) {
function WOLClientDisconnect (line 46) | func WOLClientDisconnect(c *websocketcontroller.Controller) {
function WOLClientConnected (line 59) | func WOLClientConnected(c *websocketcontroller.Controller) {
function WakeUpFinishedCallback (line 63) | func WakeUpFinishedCallback(reply bool, macList []string, broadcastIps [...
function hanlderWOLDeviceClientLogin (line 81) | func hanlderWOLDeviceClientLogin(m *Login, c *websocketcontroller.Contro...
function ExecShutDown (line 202) | func ExecShutDown(d *wolconf.WOLDevice) int {
FILE: module/wol/websocketcommon.go
function SendMessage (line 9) | func SendMessage(c *websocketcontroller.Controller, msg any) error {
function Pack (line 19) | func Pack(msg interface{}) ([]byte, error) {
function UnPack (line 23) | func UnPack(bytes []byte) (msg Message, err error) {
FILE: reverseproxy/proxy.go
function InitReverseProxyServer (line 10) | func InitReverseProxyServer() {
function EnableRuleByKey (line 24) | func EnableRuleByKey(key string, enable bool) error {
type RuleInfo (line 48) | type RuleInfo struct
function GetProxyRuleListInfo (line 53) | func GetProxyRuleListInfo() *[]RuleInfo {
function GetAccessLogs (line 66) | func GetAccessLogs(ruleKey, proxyKey string, pageSize, page int) (int, [...
FILE: socketproxy/baseproxyconf.go
type BaseProxyConf (line 8) | type BaseProxyConf struct
method GetProxyType (line 16) | func (p *BaseProxyConf) GetProxyType() string {
method GetStatus (line 20) | func (p *BaseProxyConf) GetStatus() string {
method ReceiveDataCallback (line 24) | func (p *BaseProxyConf) ReceiveDataCallback(nw int64) {
method SendDataCallback (line 28) | func (p *BaseProxyConf) SendDataCallback(nw int64) {
method GetTrafficIn (line 32) | func (p *BaseProxyConf) GetTrafficIn() int64 {
method GetTrafficOut (line 36) | func (p *BaseProxyConf) GetTrafficOut() int64 {
FILE: socketproxy/proxy.go
type Proxy (line 15) | type Proxy interface
type RelayRuleOptions (line 34) | type RelayRuleOptions struct
method relayData (line 44) | func (p *BaseProxyConf) relayData(targetServer io.ReadWriteCloser, clien...
method CopyBuffer (line 75) | func (p *BaseProxyConf) CopyBuffer(dst io.Writer, src io.Reader, buf []b...
method copyBuffer (line 84) | func (p *BaseProxyConf) copyBuffer(dst io.Writer, src io.Reader, buf []b...
function formatFileSize (line 143) | func formatFileSize(fileSize int64) (size string) {
function CreateProxy (line 161) | func CreateProxy(log *logrus.Logger, proxyType, listenIP string, targetA...
function GetProxyKey (line 178) | func GetProxyKey(proxyType, listenIP string, listenPort int) string {
FILE: socketproxy/tcpproxy.go
type TCPProxy (line 14) | type TCPProxy struct
method GetStatus (line 40) | func (p *TCPProxy) GetStatus() string {
method CheckConnectionsLimit (line 44) | func (p *TCPProxy) CheckConnectionsLimit() error {
method StartProxy (line 58) | func (p *TCPProxy) StartProxy() {
method StopProxy (line 131) | func (p *TCPProxy) StopProxy() {
method handle (line 152) | func (p *TCPProxy) handle(conn net.Conn) {
function CreateTCPProxy (line 25) | func CreateTCPProxy(log *logrus.Logger, proxyType, listenIP string, targ...
FILE: socketproxy/tcpudpcommon.go
constant TCP_DEFAULT_STREAM_BUFFERSIZE (line 14) | TCP_DEFAULT_STREAM_BUFFERSIZE = 128
constant DEFAULT_GLOBAL_MAX_CONNECTIONS (line 15) | DEFAULT_GLOBAL_MAX_CONNECTIONS = int64(1024)
constant DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount (line 16) | DEFAULT_GLOBAL_UDPReadTargetDataMaxgoroutineCount = int64(1024)
constant TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS (line 17) | TCPUDP_DEFAULT_SINGLE_PROXY_MAX_CONNECTIONS = int64(256)
constant DEFAULT_MAX_PORTFORWARDS_LIMIT (line 19) | DEFAULT_MAX_PORTFORWARDS_LIMIT = int64(128)
function SetSafeCheck (line 31) | func SetSafeCheck(f func(mode, ip string) bool) {
function SetGlobalUDPReadTargetDataMaxgoroutineCountLimit (line 35) | func SetGlobalUDPReadTargetDataMaxgoroutineCountLimit(max int64) {
function GetGlobalUDPReadTargetDataMaxgoroutineCountLimit (line 39) | func GetGlobalUDPReadTargetDataMaxgoroutineCountLimit() int64 {
function SetGlobalMaxPortForwardsCountLimit (line 43) | func SetGlobalMaxPortForwardsCountLimit(max int64) {
function GetGlobalMaxPortForwardsCountLimit (line 47) | func GetGlobalMaxPortForwardsCountLimit() int64 {
function SetGlobalTCPPortforwardMaxConnections (line 51) | func SetGlobalTCPPortforwardMaxConnections(max int64) {
function GetGlobalTCPPortforwardMaxConnections (line 55) | func GetGlobalTCPPortforwardMaxConnections() int64 {
function GetGlobalTCPPortForwardConnections (line 59) | func GetGlobalTCPPortForwardConnections() int64 {
function GloBalTCPPortForwardConnectionsAdd (line 63) | func GloBalTCPPortForwardConnectionsAdd(add int64) int64 {
function GetGlobalUDPPortForwardGroutineCount (line 67) | func GetGlobalUDPPortForwardGroutineCount() int64 {
function GloBalUDPPortForwardGroutineCountAdd (line 71) | func GloBalUDPPortForwardGroutineCountAdd(add int64) int64 {
type TCPUDPProxyCommonConf (line 75) | type TCPUDPProxyCommonConf struct
method SetMaxConnections (line 98) | func (p *TCPUDPProxyCommonConf) SetMaxConnections(max int64) {
method AddCurrentConnections (line 106) | func (p *TCPUDPProxyCommonConf) AddCurrentConnections(a int64) {
method GetCurrentConnections (line 120) | func (p *TCPUDPProxyCommonConf) GetCurrentConnections() int64 {
method GetListentAddress (line 124) | func (p *TCPUDPProxyCommonConf) GetListentAddress() string {
method GetKey (line 135) | func (p *TCPUDPProxyCommonConf) GetKey() string {
method GetListenIP (line 142) | func (p *TCPUDPProxyCommonConf) GetListenIP() string {
method GetListenPort (line 146) | func (p *TCPUDPProxyCommonConf) GetListenPort() int {
method GetTargetAddress (line 150) | func (p *TCPUDPProxyCommonConf) GetTargetAddress() string {
method String (line 162) | func (p *TCPUDPProxyCommonConf) String() string {
method SafeCheck (line 166) | func (p *TCPUDPProxyCommonConf) SafeCheck(remodeAddr string) bool {
FILE: socketproxy/udpproxy.go
constant UDP_DEFAULT_PACKAGE_SIZE (line 17) | UDP_DEFAULT_PACKAGE_SIZE = 1500
type UDPProxy (line 21) | type UDPProxy struct
method getHandlegoroutineNum (line 72) | func (p *UDPProxy) getHandlegoroutineNum() int {
method SetUDPPacketSize (line 79) | func (p *UDPProxy) SetUDPPacketSize(size int) {
method GetUDPPacketSize (line 91) | func (p *UDPProxy) GetUDPPacketSize() int {
method StartProxy (line 96) | func (p *UDPProxy) StartProxy() {
method StopProxy (line 153) | func (p *UDPProxy) StopProxy() {
method ReadFromTargetOnce (line 179) | func (p *UDPProxy) ReadFromTargetOnce() bool {
method ListenHandler (line 190) | func (p *UDPProxy) ListenHandler(ln *net.UDPConn) {
method handlerDataFromTargetAddress (line 234) | func (p *UDPProxy) handlerDataFromTargetAddress(raddr *net.UDPAddr, tg...
method Forwarder (line 311) | func (p *UDPProxy) Forwarder(kk int, replych chan *udpPackge) {
method replyDataToRemotAddress (line 380) | func (p *UDPProxy) replyDataToRemotAddress() {
method CheckReadTargetDataGoroutineLimit (line 392) | func (p *UDPProxy) CheckReadTargetDataGoroutineLimit() error {
method CheckTargetUDPConnectSessions (line 403) | func (p *UDPProxy) CheckTargetUDPConnectSessions() {
type udpPackge (line 42) | type udpPackge struct
type udpTagetConSession (line 48) | type udpTagetConSession struct
function CreateUDPProxy (line 53) | func CreateUDPProxy(log *logrus.Logger, proxyType, listenIP string, targ...
FILE: thirdlib/fatedier/golib/json/msg.go
type Message (line 26) | type Message interface
type MsgCtl (line 28) | type MsgCtl struct
method RegisterMsg (line 43) | func (msgCtl *MsgCtl) RegisterMsg(typeByte byte, msg interface{}) {
method SetMaxMsgLength (line 48) | func (msgCtl *MsgCtl) SetMaxMsgLength(length int64) {
function NewMsgCtl (line 35) | func NewMsgCtl() *MsgCtl {
FILE: thirdlib/fatedier/golib/json/pack.go
method unpack (line 24) | func (msgCtl *MsgCtl) unpack(typeByte byte, buffer []byte, msgIn Message...
method UnPackInto (line 41) | func (msgCtl *MsgCtl) UnPackInto(buffer []byte, msg Message) (err error) {
method UnPack (line 46) | func (msgCtl *MsgCtl) UnPack(typeByte byte, buffer []byte) (msg Message,...
method Pack (line 50) | func (msgCtl *MsgCtl) Pack(msg Message) ([]byte, error) {
FILE: thirdlib/fatedier/golib/json/process.go
method readMsg (line 30) | func (msgCtl *MsgCtl) readMsg(c io.Reader) (typeByte byte, buffer []byte...
method ReadMsg (line 67) | func (msgCtl *MsgCtl) ReadMsg(c io.Reader) (msg Message, err error) {
method ReadMsgInto (line 75) | func (msgCtl *MsgCtl) ReadMsgInto(c io.Reader, msg Message) (err error) {
method WriteMsg (line 83) | func (msgCtl *MsgCtl) WriteMsg(c io.Writer, msg interface{}) (err error) {
FILE: thirdlib/gdylib/bemfa/device.go
constant bemfaHost (line 15) | bemfaHost = "bemfa.com"
constant mqttsPort (line 17) | mqttsPort = 9503
constant Disconnected (line 21) | Disconnected uint32 = iota
constant Connecting (line 22) | Connecting
constant Reconnecting (line 23) | Reconnecting
constant Connected (line 24) | Connected
type Device (line 27) | type Device struct
method OnLine (line 47) | func (d *Device) OnLine() bool {
method IsDisconnected (line 52) | func (d *Device) IsDisconnected() bool {
method ResigsterPowerChangeCallbackFunc (line 57) | func (d *Device) ResigsterPowerChangeCallbackFunc(subTopic, key string...
method UnRegisterPowerChangeCallbackFunc (line 74) | func (d *Device) UnRegisterPowerChangeCallbackFunc(subTopic, key strin...
method StoreExtData (line 89) | func (d *Device) StoreExtData(key any, val any) {
method GetExtData (line 93) | func (d *Device) GetExtData(key any) (val any, ok bool) {
method Login (line 98) | func (d *Device) Login() error {
method Stop (line 137) | func (d *Device) Stop() {
method closeMQTTClient (line 141) | func (d *Device) closeMQTTClient() {
method SubTopicOption (line 152) | func (d *Device) SubTopicOption() {
method ReceiveMessageHandler (line 169) | func (d *Device) ReceiveMessageHandler(c MQTT.Client, m MQTT.Message) {
method handlerReceivemessage (line 182) | func (d *Device) handlerReceivemessage(topic, msg string) {
function CreateDevice (line 40) | func CreateDevice(secretKey string, secureVerify bool, httpClientTimeout...
FILE: thirdlib/gdylib/bemfa/global.go
function GetBemfaDevice (line 12) | func GetBemfaDevice(secretKey string, httpClientSecureVerify bool, httpC...
function UnRegisterPowerChangeCallback (line 81) | func UnRegisterPowerChangeCallback(d *Device, topic, key string) {
FILE: thirdlib/gdylib/blinker/VoiceAssistant.go
constant VA_TYPE_LIGHT (line 6) | VA_TYPE_LIGHT = "light"
constant VA_TYPE_OUTLET (line 7) | VA_TYPE_OUTLET = "outlet"
constant VA_TYPE_MULTI_OUTLET (line 8) | VA_TYPE_MULTI_OUTLET = "multi_outlet"
constant VA_TYPE_SENSOR (line 9) | VA_TYPE_SENSOR = "sensor"
constant VA_TYPE_FAN (line 10) | VA_TYPE_FAN = "fan"
constant VA_TYPE_AIRCONDITION (line 11) | VA_TYPE_AIRCONDITION = "aircondition"
type VoiceAssistant (line 14) | type VoiceAssistant struct
method GetSKey (line 21) | func (v *VoiceAssistant) GetSKey() string {
method PowerChangeReply (line 34) | func (v *VoiceAssistant) PowerChangeReply(msgid, st string) {
method QueryDeviceState (line 53) | func (v *VoiceAssistant) QueryDeviceState(msgid string) {
method GetToDevice (line 66) | func (v *VoiceAssistant) GetToDevice() string {
function CreateVoiceAssistant (line 73) | func CreateVoiceAssistant(deviceType, vaType string) *VoiceAssistant {
FILE: thirdlib/gdylib/blinker/device.go
constant HOST (line 20) | HOST = "https://iot.diandeng.tech"
constant API_AUTH (line 21) | API_AUTH = HOST + "/api/v1/user/device/diy/auth"
constant API_HEARTBEAT (line 22) | API_HEARTBEAT = HOST + "/api/v1/user/device/heartbeat"
constant API_VOICE_ASSISTANT (line 23) | API_VOICE_ASSISTANT = HOST + "/api/v1/user/device/voice_assistant"
type BlinkerDevice (line 26) | type BlinkerDevice struct
method AddVoiceAssistant (line 60) | func (d *BlinkerDevice) AddVoiceAssistant(v *VoiceAssistant) {
method SyncAssistants (line 65) | func (d *BlinkerDevice) SyncAssistants() error {
method RunSenderMessageService (line 88) | func (d *BlinkerDevice) RunSenderMessageService() {
method RunHeartBearTimer (line 100) | func (d *BlinkerDevice) RunHeartBearTimer() {
method Init (line 115) | func (d *BlinkerDevice) Init() error {
method Login (line 157) | func (d *BlinkerDevice) Login() error {
method heartBeat (line 208) | func (d *BlinkerDevice) heartBeat() error {
method ReceiveMessageHandler (line 227) | func (d *BlinkerDevice) ReceiveMessageHandler(c MQTT.Client, m MQTT.Me...
method voiceAssistantMessageHandler (line 257) | func (d *BlinkerDevice) voiceAssistantMessageHandler(from string, msg ...
method powerChange (line 288) | func (d *BlinkerDevice) powerChange(va *VoiceAssistant, msgId, state s...
method ownAppMessagehandler (line 295) | func (d *BlinkerDevice) ownAppMessagehandler(msg []byte) {
method formatMess2assistant (line 328) | func (d *BlinkerDevice) formatMess2assistant(targetType, toDevice, msg...
method formatMess2Device (line 343) | func (d *BlinkerDevice) formatMess2Device(targetType, toDevice string,...
method SendMessage (line 348) | func (d *BlinkerDevice) SendMessage(targetType, todevice, msgid string...
method sendMessage (line 353) | func (d *BlinkerDevice) sendMessage(targetType, todevice, msgid string...
type message (line 46) | type message struct
function CreateBlinkerDevice (line 53) | func CreateBlinkerDevice(ak string) *BlinkerDevice {
type mess2device (line 313) | type mess2device struct
type mess2assistant (line 320) | type mess2assistant struct
type BlinkerDetailInfo (line 390) | type BlinkerDetailInfo struct
type BlinkerInfoRes (line 401) | type BlinkerInfoRes struct
function GetBytesFromHttpResponse (line 407) | func GetBytesFromHttpResponse(resp *http.Response) ([]byte, error) {
function GetAndParseJSONResponseFromHttpResponse (line 426) | func GetAndParseJSONResponseFromHttpResponse(resp *http.Response, result...
FILE: thirdlib/gdylib/blinker/global.go
function GetBlinkerDevice (line 12) | func GetBlinkerDevice(authKey string, httpClientSecureVerify bool, httpC...
function UnRegisterPowerChangeCallback (line 101) | func UnRegisterPowerChangeCallback(d *Device, key string) {
FILE: thirdlib/gdylib/dnsutils/resolve.go
function ResolveDomainAtServerList (line 46) | func ResolveDomainAtServerList(queryType, domain string, dnsServerList [...
function resolveDomain (line 99) | func resolveDomain(msg *dns.Msg, client *dns.Client, dnsServer string) (...
FILE: thirdlib/gdylib/fileutils/fileutils.go
function GetCurrentDirectory (line 13) | func GetCurrentDirectory() string {
function SaveBase64AsFile (line 22) | func SaveBase64AsFile(base64Str *string, fileURL string) (err error) {
function FileExists (line 29) | func FileExists(path string) (bool, error) {
function SaveTextToFile (line 41) | func SaveTextToFile(text, fileURL string) error {
function ReadTextFromFile (line 53) | func ReadTextFromFile(path string) (string, error) {
FILE: thirdlib/gdylib/fileutils/run_linux.go
function OpenProgramOrFile (line 8) | func OpenProgramOrFile(argv []string) error {
FILE: thirdlib/gdylib/fileutils/run_windows.go
function OpenProgramOrFile (line 6) | func OpenProgramOrFile(argv []string) error {
FILE: thirdlib/gdylib/ginutils/basicAuth.go
type BasicAuthPair (line 11) | type BasicAuthPair struct
type BasicAuthPairs (line 16) | type BasicAuthPairs
method SearchCredential (line 53) | func (a BasicAuthPairs) SearchCredential(authValue string) (string, bo...
function ProcessAccounts (line 18) | func ProcessAccounts(accounts gin.Accounts) BasicAuthPairs {
function authorizationHeader (line 33) | func authorizationHeader(user, password string) string {
function assert1 (line 38) | func assert1(guard bool, text string) {
function StringToBytes (line 44) | func StringToBytes(s string) []byte {
FILE: thirdlib/gdylib/ginutils/jwt.go
function GetJWTToken (line 11) | func GetJWTToken(tokenString, tokenKey string) (t *jwt.Token, e error) {
function GetJWTTokenString (line 45) | func GetJWTTokenString(info map[string]interface{}, key string, exp time...
FILE: thirdlib/gdylib/ginutils/staticFilesHandler.go
function HandlerStaticFiles (line 11) | func HandlerStaticFiles(files fs.FS) gin.HandlerFunc {
function isStaticFile (line 24) | func isStaticFile(fs http.FileSystem, name string, redirect bool) (isFil...
FILE: thirdlib/gdylib/ginutils/utils.go
function Cors (line 11) | func Cors(params ...interface{}) gin.HandlerFunc {
function GetChildDomain (line 31) | func GetChildDomain(host string) string {
FILE: thirdlib/gdylib/httputils/common.go
function init (line 24) | func init() {
function SplitHostPort (line 28) | func SplitHostPort(hostPort string) (host, port string) {
function validOptionalPort (line 43) | func validOptionalPort(port string) bool {
function GetAndParseJSONResponseFromHttpResponse (line 58) | func GetAndParseJSONResponseFromHttpResponse(resp *http.Response, result...
function GetBytesFromHttpResponse (line 74) | func GetBytesFromHttpResponse(resp *http.Response) ([]byte, error) {
function GetStringFromHttpResponse (line 94) | func GetStringFromHttpResponse(resp *http.Response) (string, error) {
type transportIt (line 102) | type transportIt struct
method String (line 112) | func (t *transportIt) String() string {
function NewTransport (line 119) | func NewTransport(transportNetwork,
function CreateHeadersMap (line 274) | func CreateHeadersMap(headers []string) map[string]string {
FILE: thirdlib/gdylib/httputils/goututils.go
function NewGout (line 13) | func NewGout(transportNetwork, localAddr string, secureSkipVerify bool, ...
function GetAndParseJSONResponseFromGoutDoHttpRequest (line 22) | func GetAndParseJSONResponseFromGoutDoHttpRequest(transportNetwork, loca...
function GetStringGoutDoHttpRequest (line 44) | func GetStringGoutDoHttpRequest(transportNetwork, localAddr, method, url...
function GetBytesFromGoutDoHttpRequest (line 53) | func GetBytesFromGoutDoHttpRequest(transportNetwork, localAddr, method, ...
FILE: thirdlib/gdylib/httputils/httpclient.go
function CreateHttpClient (line 8) | func CreateHttpClient(transportNetwork, localAddr string, secureSkipVeri...
FILE: thirdlib/gdylib/logsbuffer/logsbuffer.go
type LogsBuffer (line 12) | type LogsBuffer struct
method AddLog (line 27) | func (l *LogsBuffer) AddLog(t time.Time, msg string, data map[string]a...
method Fire (line 45) | func (l *LogsBuffer) Fire(entry *logrus.Entry) error {
method SetFireCallback (line 61) | func (l *LogsBuffer) SetFireCallback(f func(entry *logrus.Entry) error) {
method Levels (line 65) | func (l *LogsBuffer) Levels() []logrus.Level {
method Write (line 69) | func (l *LogsBuffer) Write(p []byte) (n int, err error) {
method GetLogs (line 76) | func (l *LogsBuffer) GetLogs(logItemConvertFunc func(*LogItem) any, fT...
method GetLastLogs (line 91) | func (l *LogsBuffer) GetLastLogs(logItemConvertFunc func(*LogItem) any...
method GetLogsByLimit (line 109) | func (l *LogsBuffer) GetLogsByLimit(logItemConvertFunc func(*LogItem) ...
method getLogItem (line 134) | func (l *LogsBuffer) getLogItem(logItemConvertFunc func(*LogItem) any,...
method ClearLog (line 144) | func (l *LogsBuffer) ClearLog() {
method SetBufferSize (line 153) | func (l *LogsBuffer) SetBufferSize(size int) {
method GetBufferSize (line 162) | func (l *LogsBuffer) GetBufferSize() int {
method GetLogCount (line 168) | func (l *LogsBuffer) GetLogCount() int {
type LogItem (line 21) | type LogItem struct
function Create (line 148) | func Create(size int) *LogsBuffer {
function init (line 179) | func init() {
function CreateLogbuffer (line 183) | func CreateLogbuffer(key string, buffSize int) *LogsBuffer {
FILE: thirdlib/gdylib/netinterfaces/netInterface.go
type NetInterface (line 12) | type NetInterface struct
function GetNetInterface (line 19) | func GetNetInterface() (ipv4NetInterfaces []NetInterface, ipv6NetInterfa...
function GetIPFromNetInterface (line 75) | func GetIPFromNetInterface(ipType, netinterface, ipreg string) string {
function GetGlobalIPv4BroadcastList (line 156) | func GetGlobalIPv4BroadcastList() []string {
function GetBroadcast (line 187) | func GetBroadcast(ip net.IP, mask net.IPMask) string {
FILE: thirdlib/gdylib/pool/buf.go
constant k16 (line 17) | k16 = 16 * 1024
constant k8 (line 18) | k8 = 8 * 1024
constant k4 (line 19) | k4 = 4 * 1024
constant k2 (line 20) | k2 = 2 * 1024
constant k1 (line 21) | k1 = 1024
function GetBuf (line 24) | func GetBuf(size int) []byte {
function PutBuf (line 50) | func PutBuf(buf interface{}) {
FILE: thirdlib/gdylib/recoverutil/recoverutil.go
function RecoverHandler (line 15) | func RecoverHandler(recoverErr interface{}, exit, reboot bool, panicFile...
function outputPanic (line 46) | func outputPanic(panicFileURL string, recoverErr interface{}) {
function outputPanicV2 (line 97) | func outputPanicV2(panicFileURL string, recoverErr interface{}) {
FILE: thirdlib/gdylib/service/service.go
constant StateStop (line 14) | StateStop = 0
constant StateRunning (line 16) | StateRunning = 1
constant StateStopping (line 18) | StateStopping = 2
type ServiceMsg (line 22) | type ServiceMsg struct
type Service (line 37) | type Service struct
method SetDefaultAction (line 75) | func (s *Service) SetDefaultAction(action string) *Service {
method SetTimerFunc (line 81) | func (s *Service) SetTimerFunc(timerFunc func(...any)) *Service {
method SetEventFunc (line 87) | func (s *Service) SetEventFunc(eventFunc func(...any)) *Service {
method SetStopFinishedCallback (line 93) | func (s *Service) SetStopFinishedCallback(f func(...any)) *Service {
method Start (line 99) | func (s *Service) Start(vs ...any) error {
method Stop (line 122) | func (s *Service) Stop() error {
method loop (line 143) | func (s *Service) loop(params ...any) {
method Restart (line 205) | func (s *Service) Restart(params ...any) error {
method Message (line 232) | func (s *Service) Message(t string, params ...any) error {
function NewService (line 56) | func NewService(name string) (*Service, error) {
function GetService (line 255) | func GetService(name string) (*Service, error) {
function Message (line 266) | func Message(serviceName string, msgType string, params ...any) error {
function Stop (line 275) | func Stop(serviceName string) error {
function Restart (line 284) | func Restart(serviceName string) error {
function Start (line 293) | func Start(serviceName string) error {
FILE: thirdlib/gdylib/slice/options.go
function DeleteAnyListlice (line 3) | func DeleteAnyListlice(a []any, deleteIndex int) []any {
FILE: thirdlib/gdylib/stderrredirect/stderrredirect_linux.go
function PanicRedirect (line 18) | func PanicRedirect(fileURL string) {
FILE: thirdlib/gdylib/stderrredirect/stderrredirect_windows.go
function PanicRedirect (line 21) | func PanicRedirect(fileURL string) {
FILE: thirdlib/gdylib/stringsp/binary.go
constant KB (line 6) | KB = uint(1024)
constant MB (line 7) | MB = uint64(1024 * 1024)
constant GB (line 8) | GB = uint64(1024 * 1024 * 1024)
constant TB (line 9) | TB = uint64(1024 * 1024 * 1024 * 1024)
constant EB (line 10) | EB = uint64(1024 * 1024 * 1024 * 1024 * 1024)
function BinaryUnitToStr (line 13) | func BinaryUnitToStr(binaryUnit uint64) (size string) {
FILE: thirdlib/gdylib/stringsp/randomutils.go
function GetRandomString (line 21) | func GetRandomString(len int) string {
function GetRandomStringNum (line 30) | func GetRandomStringNum(len int) string {
function GetTimeStampID (line 43) | func GetTimeStampID() int64 {
FILE: thirdlib/gdylib/stringsp/stringsp.go
function StrIsInList (line 3) | func StrIsInList(str string, strList []string) bool {
FILE: thirdlib/gdylib/stringsp/url.go
function GetHostAndPathFromURL (line 8) | func GetHostAndPathFromURL(urlstr string) (string, string, string, strin...
FILE: thirdlib/gdylib/websocketController/controller.go
constant disconnected (line 18) | disconnected uint32 = iota
constant connecting (line 19) | connecting
constant reconnecting (line 20) | reconnecting
constant connected (line 21) | connected
constant writeWait (line 26) | writeWait = 5 * time.Second
constant pongWait (line 28) | pongWait = 9 * time.Second
constant pingPeriod (line 30) | pingPeriod = 1500 * time.Millisecond
constant maxMessageSize (line 32) | maxMessageSize = 4096 * 4
constant handshakeTimeout (line 34) | handshakeTimeout = 10 * time.Second
constant readTimeout (line 36) | readTimeout = 9 * time.Second
type Controller (line 39) | type Controller struct
method SetSendMessageEncryptionFunc (line 73) | func (c *Controller) SetSendMessageEncryptionFunc(f func(messageBytes ...
method SetReceiveMessageDecryptionFunc (line 77) | func (c *Controller) SetReceiveMessageDecryptionFunc(f func(messageByt...
method StoreExtData (line 81) | func (c *Controller) StoreExtData(key any, data any) {
method GetExtData (line 86) | func (c *Controller) GetExtData(key any) (any, bool) {
method disconnect (line 90) | func (c *Controller) disconnect() {
method SetServerURL (line 122) | func (c *Controller) SetServerURL(url string) {
method ScureSkipVerify (line 127) | func (c *Controller) ScureSkipVerify(b bool) {
method SetConnectRetry (line 131) | func (c *Controller) SetConnectRetry(b bool) {
method SetConnectRetryInterval (line 135) | func (c *Controller) SetConnectRetryInterval(t time.Duration) {
method SetConnectRetryCount (line 139) | func (c *Controller) SetConnectRetryCount(count int) {
method SetReadDeadline (line 143) | func (c *Controller) SetReadDeadline(d time.Duration) {
method init (line 147) | func (c *Controller) init() {
method Disconnect (line 184) | func (c *Controller) Disconnect() {
method SendMessage (line 201) | func (c *Controller) SendMessage(messageBytes []byte) {
method writePump (line 225) | func (c *Controller) writePump(ctx context.Context, conn *websocket.Co...
method readPump (line 289) | func (c *Controller) readPump(cancelFunc context.CancelFunc, conn *web...
method Connect (line 340) | func (c *Controller) Connect() error {
method ConnectReady (line 379) | func (c *Controller) ConnectReady(connect *websocket.Conn) {
method GetRemoteAddr (line 388) | func (c *Controller) GetRemoteAddr() string {
method monitor (line 392) | func (c *Controller) monitor(connect *websocket.Conn) {
FILE: thirdlib/go-wol/magic_packet.go
type MACAddress (line 23) | type MACAddress
type MagicPacket (line 27) | type MagicPacket struct
method Marshal (line 67) | func (mp *MagicPacket) Marshal() ([]byte, error) {
function New (line 33) | func New(mac string) (*MagicPacket, error) {
FILE: thirdlib/go-wol/wol.go
function WakeUpRepeat (line 8) | func WakeUpRepeat(macAddr, broadcastIP, bcastInterface string, port, rep...
function WakeUp (line 19) | func WakeUp(macAddr, broadcastIP, bcastInterface string, port int) error {
function ipFromInterface (line 68) | func ipFromInterface(iface string) (*net.UDPAddr, error) {
FILE: thirdlib/jeessy2/ddns-go/util/aliyun_signer.go
function HmacSign (line 25) | func HmacSign(signMethod string, httpMethod string, appKeySecret string,...
function HmacSignToB64 (line 38) | func HmacSignToB64(signMethod string, httpMethod string, appKeySecret st...
type strToEnc (line 42) | type strToEnc struct
function makeDataToSign (line 47) | func makeDataToSign(w io.Writer, httpMethod string, vals url.Values) {
function specialUrlEncode (line 67) | func specialUrlEncode(in <-chan *strToEnc, w io.Writer) {
FILE: thirdlib/jeessy2/ddns-go/util/aliyun_signer_util.go
function AliyunSigner (line 10) | func AliyunSigner(accessKeyID, accessSecret string, params *url.Values) {
FILE: thirdlib/jeessy2/ddns-go/util/baidu_signer.go
constant BaiduDateFormat (line 16) | BaiduDateFormat = "2006-01-02T15:04:05Z"
constant expirationPeriod (line 17) | expirationPeriod = "1800"
function HmacSha256Hex (line 20) | func HmacSha256Hex(secret, message string) string {
function BaiduCanonicalURI (line 29) | func BaiduCanonicalURI(r *http.Request) string {
function BaiduSigner (line 43) | func BaiduSigner(accessKeyID, accessSecret string, r *http.Request) {
FILE: thirdlib/jeessy2/ddns-go/util/escape.go
function shouldEscape (line 8) | func shouldEscape(c byte) bool {
function escape (line 14) | func escape(s string) string {
FILE: thirdlib/jeessy2/ddns-go/util/huawei_signer.go
constant BasicDateFormat (line 20) | BasicDateFormat = "20060102T150405Z"
constant Algorithm (line 21) | Algorithm = "SDK-HMAC-SHA256"
constant HeaderXDate (line 22) | HeaderXDate = "X-Sdk-Date"
constant HeaderHost (line 23) | HeaderHost = "host"
constant HeaderAuthorization (line 24) | HeaderAuthorization = "Authorization"
constant HeaderContentSha256 (line 25) | HeaderContentSha256 = "X-Sdk-Content-Sha256"
function hmacsha256 (line 28) | func hmacsha256(key []byte, data string) ([]byte, error) {
function CanonicalRequest (line 45) | func CanonicalRequest(r *http.Request, signedHeaders []string) (string, ...
function CanonicalURI (line 64) | func CanonicalURI(r *http.Request) string {
function CanonicalQueryString (line 78) | func CanonicalQueryString(r *http.Request) string {
function CanonicalHeaders (line 100) | func CanonicalHeaders(r *http.Request, signerHeaders []string) string {
function SignedHeaders (line 120) | func SignedHeaders(r *http.Request) []string {
function RequestPayload (line 130) | func RequestPayload(r *http.Request) ([]byte, error) {
function StringToSign (line 143) | func StringToSign(canonicalRequest string, t time.Time) (string, error) {
function SignStringToSign (line 154) | func SignStringToSign(stringToSign string, signingKey []byte) (string, e...
function HexEncodeSHA256Hash (line 160) | func HexEncodeSHA256Hash(body []byte) (string, error) {
function AuthHeaderValue (line 170) | func AuthHeaderValue(signature, accessKey string, signedHeaders []string...
type Signer (line 175) | type Signer struct
method Sign (line 181) | func (s *Signer) Sign(r *http.Request) error {
FILE: thirdlib/jeessy2/ddns-go/util/net.go
function IsPrivateNetwork (line 10) | func IsPrivateNetwork(remoteAddr string) bool {
FILE: web.go
function RunAdminWeb (line 8) | func RunAdminWeb(conf *config.BaseConfigure) {
FILE: web/adminviews/components.d.ts
type GlobalComponents (line 7) | interface GlobalComponents {
FILE: web/adminviews/dist/assets/index.0c84c960.js
function n (line 1) | function n(l){const u={};return l.integrity&&(u.integrity=l.integrity),l...
function o (line 1) | function o(l){if(l.ep)return;l.ep=!0;const u=n(l);fetch(l.href,u)}
function xi (line 1) | function xi(e,t){const n=Object.create(null),o=e.split(",");for(let l=0;...
function jd (line 1) | function jd(e){return!!e||e===""}
function ut (line 1) | function ut(e){if(qe(e)){const t={};for(let n=0;n<e.length;n++){const o=...
function dp (line 1) | function dp(e){const t={};return e.split(ip).forEach(n=>{if(n){const o=n...
function K (line 1) | function K(e){let t="";if(tt(e))t=e;else if(qe(e))for(let n=0;n<e.length...
function fp (line 1) | function fp(e,t){if(e.length!==t.length)return!1;let n=!0;for(let o=0;n&...
function Jl (line 1) | function Jl(e,t){if(e===t)return!0;let n=l2(e),o=l2(t);if(n||o)return n&...
function Kd (line 1) | function Kd(e,t){return e.findIndex(n=>Jl(n,t))}
class bp (line 1) | class bp{constructor(t=!1){this.detached=t,this.active=!0,this.effects=[...
method constructor (line 1) | constructor(t=!1){this.detached=t,this.active=!0,this.effects=[],this....
method run (line 1) | run(t){if(this.active){const n=yn;try{return yn=this,t()}finally{yn=n}}}
method on (line 1) | on(){yn=this}
method off (line 1) | off(){yn=this.parent}
method stop (line 1) | stop(t){if(this.active){let n,o;for(n=0,o=this.effects.length;n<o;n++)...
function yp (line 1) | function yp(e,t=yn){t&&t.active&&t.effects.push(e)}
function wp (line 1) | function wp(){return yn}
function Jd (line 1) | function Jd(e){yn&&yn.cleanups.push(e)}
class Li (line 1) | class Li{constructor(t,n=null,o){this.fn=t,this.scheduler=n,this.active=...
method constructor (line 1) | constructor(t,n=null,o){this.fn=t,this.scheduler=n,this.active=!0,this...
method run (line 1) | run(){if(!this.active)return this.fn();let t=Wn,n=Qo;for(;t;){if(t===t...
method stop (line 1) | stop(){Wn===this?this.deferStop=!0:this.active&&(a2(this),this.onStop&...
function a2 (line 1) | function a2(e){const{deps:t}=e;if(t.length){for(let n=0;n<t.length;n++)t...
function kl (line 1) | function kl(){e1.push(Qo),Qo=!1}
function Pl (line 1) | function Pl(){const e=e1.pop();Qo=e===void 0?!0:e}
function Fn (line 1) | function Fn(e,t,n){if(Qo&&Wn){let o=zs.get(e);o||zs.set(e,o=new Map);let...
function t1 (line 1) | function t1(e,t){let n=!1;zu<=Ms?Zd(e)||(e.n|=el,n=!Qd(e)):n=!e.has(Wn),...
function xo (line 1) | function xo(e,t,n,o,l,u){const a=zs.get(e);if(!a)return;let r=[];if(t===...
function Is (line 1) | function Is(e,t){const n=qe(e)?e:[...e];for(const o of n)o.computed&&r2(...
function r2 (line 1) | function r2(e,t){(e!==Wn||e.allowRecurse)&&(e.scheduler?e.scheduler():e....
function xp (line 1) | function xp(){const e={};return["includes","indexOf","lastIndexOf"].forE...
function Ti (line 1) | function Ti(e=!1,t=!1){return function(o,l,u){if(l==="__v_isReactive")re...
function o1 (line 1) | function o1(e=!1){return function(n,o,l,u){let a=n[o];if(Ql(a)&&yt(a)&&!...
function kp (line 1) | function kp(e,t){const n=st(e,t);e[t];const o=Reflect.deleteProperty(e,t...
function Pp (line 1) | function Pp(e,t){const n=Reflect.has(e,t);return(!ju(t)||!n1.has(t))&&Fn...
function Lp (line 1) | function Lp(e){return Fn(e,"iterate",qe(e)?"length":El),Reflect.ownKeys(e)}
method set (line 1) | set(e,t){return!0}
method deleteProperty (line 1) | deleteProperty(e,t){return!0}
function Da (line 1) | function Da(e,t,n=!1,o=!1){e=e.__v_raw;const l=ct(e),u=ct(t);n||(t!==u&&...
function Ba (line 1) | function Ba(e,t=!1){const n=this.__v_raw,o=ct(n),l=ct(e);return t||(e!==...
function xa (line 1) | function xa(e,t=!1){return e=e.__v_raw,!t&&Fn(ct(e),"iterate",El),Reflec...
function i2 (line 1) | function i2(e){e=ct(e);const t=ct(this);return Lr(t).has.call(t,e)||(t.a...
function c2 (line 1) | function c2(e,t){t=ct(t);const n=ct(this),{has:o,get:l}=Lr(n);let u=o.ca...
function d2 (line 1) | function d2(e){const t=ct(this),{has:n,get:o}=Lr(t);let l=n.call(t,e);l|...
function f2 (line 1) | function f2(){const e=ct(this),t=e.size!==0,n=e.clear();return t&&xo(e,"...
function $a (line 1) | function $a(e,t){return function(o,l){const u=this,a=u.__v_raw,r=ct(a),s...
function Sa (line 1) | function Sa(e,t,n){return function(...o){const l=this.__v_raw,u=ct(l),a=...
function Ro (line 1) | function Ro(e){return function(...t){return e==="delete"?!1:this}}
function Mp (line 1) | function Mp(){const e={get(u){return Da(this,u)},get size(){return xa(th...
function Mi (line 1) | function Mi(e,t){const n=t?e?Rp:Hp:e?Ip:Vp;return(o,l,u)=>l==="__v_isRea...
function qp (line 1) | function qp(e){switch(e){case"Object":case"Array":return 1;case"Map":cas...
function jp (line 1) | function jp(e){return e.__v_skip||!Object.isExtensible(e)?0:qp(qa(e))}
function Rt (line 1) | function Rt(e){return Ql(e)?e:Ii(e,!1,l1,Np,u1)}
function s1 (line 1) | function s1(e){return Ii(e,!1,zp,Op,a1)}
function Vi (line 1) | function Vi(e){return Ii(e,!0,Tp,Up,r1)}
function Ii (line 1) | function Ii(e,t,n,o,l){if(!dt(e)||e.__v_raw&&!(t&&e.__v_isReactive))retu...
function Yl (line 1) | function Yl(e){return Ql(e)?Yl(e.__v_raw):!!(e&&e.__v_isReactive)}
function Ql (line 1) | function Ql(e){return!!(e&&e.__v_isReadonly)}
function vr (line 1) | function vr(e){return!!(e&&e.__v_isShallow)}
function i1 (line 1) | function i1(e){return Yl(e)||Ql(e)}
function ct (line 1) | function ct(e){const t=e&&e.__v_raw;return t?ct(t):e}
function c1 (line 1) | function c1(e){return fr(e,"__v_skip",!0),e}
function d1 (line 1) | function d1(e){Qo&&Wn&&(e=ct(e),t1(e.dep||(e.dep=Pi())))}
function Ri (line 1) | function Ri(e,t){e=ct(e),e.dep&&Is(e.dep)}
function yt (line 1) | function yt(e){return!!(e&&e.__v_isRef===!0)}
function L (line 1) | function L(e){return f1(e,!1)}
function Kn (line 1) | function Kn(e){return f1(e,!0)}
function f1 (line 1) | function f1(e,t){return yt(e)?e:new Kp(e,t)}
class Kp (line 1) | class Kp{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_...
method constructor (line 1) | constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!...
method value (line 1) | get value(){return d1(this),this._value}
method value (line 1) | set value(t){const n=this.__v_isShallow||vr(t)||Ql(t);t=n?t:ct(t),Ku(t...
function xu (line 1) | function xu(e){Ri(e)}
function h (line 1) | function h(e){return yt(e)?e.value:e}
function p1 (line 1) | function p1(e){return Yl(e)?e:new Proxy(e,Gp)}
function ho (line 1) | function ho(e){const t=qe(e)?new Array(e.length):{};for(const n in e)t[n...
class Yp (line 1) | class Yp{constructor(t,n,o){this._object=t,this._key=n,this._defaultValu...
method constructor (line 1) | constructor(t,n,o){this._object=t,this._key=n,this._defaultValue=o,thi...
method value (line 1) | get value(){const t=this._object[this._key];return t===void 0?this._de...
method value (line 1) | set value(t){this._object[this._key]=t}
function Tn (line 1) | function Tn(e,t,n){const o=e[t];return yt(o)?o:new Yp(e,t,n)}
class Xp (line 1) | class Xp{constructor(t,n,o,l){this._setter=n,this.dep=void 0,this.__v_is...
method constructor (line 1) | constructor(t,n,o,l){this._setter=n,this.dep=void 0,this.__v_isRef=!0,...
method value (line 1) | get value(){const t=ct(this);return d1(t),(t._dirty||!t._cacheable)&&(...
method value (line 1) | set value(t){this._setter(t)}
function h1 (line 1) | function h1(e,t,n=!1){let o,l;const u=Ge(e);return u?(o=e,l=vt):(o=e.get...
function Jp (line 1) | function Jp(e,...t){kl();const n=Vu.length?Vu[Vu.length-1].component:nul...
function Qp (line 3) | function Qp(){let e=Vu[Vu.length-1];if(!e)return[];const t=[];for(;e;){c...
function Zp (line 3) | function Zp(e){const t=[];return e.forEach((n,o)=>{t.push(...o===0?[]:[`
function e3 (line 4) | function e3({vnode:e,recurseCount:t}){const n=t>0?`... (${t} recursive c...
function t3 (line 4) | function t3(e){const t=[],n=Object.keys(e);return n.slice(0,3).forEach(o...
function _1 (line 4) | function _1(e,t,n){return tt(t)?(t=JSON.stringify(t),n?t:[`${e}=${t}`]):...
function Ao (line 4) | function Ao(e,t,n,o){let l;try{l=o?e(...o):e()}catch(u){Tr(u,t,n)}return l}
function Sn (line 4) | function Sn(e,t,n,o){if(Ge(e)){const u=Ao(e,t,n,o);return u&&dr(u)&&u.ca...
function Tr (line 4) | function Tr(e,t,n,o=!0){const l=t?t.vnode:null;if(t){let u=t.parent;cons...
function n3 (line 4) | function n3(e,t,n,o=!0){console.error(e)}
function at (line 4) | function at(e){const t=Ni||m1;return e?t.then(this?e.bind(this):e):t}
function o3 (line 4) | function o3(e){let t=uo+1,n=jt.length;for(;t<n;){const o=t+n>>>1;Xu(jt[o...
function Oi (line 4) | function Oi(e){(!jt.length||!jt.includes(e,Yu&&e.allowRecurse?uo+1:uo))&...
function g1 (line 4) | function g1(){!Yu&&!Hs&&(Hs=!0,Ni=m1.then(y1))}
function l3 (line 4) | function l3(e){const t=jt.indexOf(e);t>uo&&jt.splice(t,1)}
function u3 (line 4) | function u3(e){qe(e)?Xl.push(...e):(!wo||!wo.includes(e,e.allowRecurse?v...
function p2 (line 4) | function p2(e,t=Yu?uo+1:0){for(;t<jt.length;t++){const n=jt[t];n&&n.pre&...
function b1 (line 4) | function b1(e){if(Xl.length){const t=[...new Set(Xl)];if(Xl.length=0,wo)...
function y1 (line 4) | function y1(e){Hs=!1,Yu=!0,jt.sort(a3);const t=vt;try{for(uo=0;uo<jt.len...
function r3 (line 4) | function r3(e,t,...n){if(e.isUnmounted)return;const o=e.vnode.props||wt;...
function w1 (line 4) | function w1(e,t,n=!1){const o=t.emitsCache,l=o.get(e);if(l!==void 0)retu...
function zr (line 4) | function zr(e,t){return!e||!$r(t)?!1:(t=t.slice(2).replace(/Once$/,""),s...
function hr (line 4) | function hr(e){const t=Kt;return Kt=e,Mr=e&&e.type.__scopeId||null,t}
function gu (line 4) | function gu(e){Mr=e}
function bu (line 4) | function bu(){Mr=null}
function d (line 4) | function d(e,t=Kt,n){if(!t||e._n)return e;const o=(...l)=>{o._d&&A2(-1);...
function is (line 4) | function is(e){const{type:t,vnode:n,proxy:o,withProxy:l,props:u,propsOpt...
function c3 (line 4) | function c3(e,t,n){const{props:o,children:l,component:u}=e,{props:a,chil...
function v2 (line 4) | function v2(e,t,n){const o=Object.keys(t);if(o.length!==Object.keys(e).l...
function d3 (line 4) | function d3({vnode:e,parent:t},n){for(;t&&t.subTree===e;)(e=t.vnode).el=...
function p3 (line 4) | function p3(e,t){t&&t.pendingBranch?qe(e)?t.effects.push(...e):t.effects...
function Dt (line 4) | function Dt(e,t){if(It){let n=It.provides;const o=It.parent&&It.parent.p...
function Xe (line 4) | function Xe(e,t,n=!1){const o=It||Kt;if(o){const l=o.parent==null?o.vnod...
function Do (line 4) | function Do(e,t){return Ui(e,null,t)}
function Me (line 4) | function Me(e,t,n){return Ui(e,t,n)}
function Ui (line 4) | function Ui(e,t,{immediate:n,deep:o,flush:l,onTrack:u,onTrigger:a}=wt){c...
function v3 (line 4) | function v3(e,t,n){const o=this.proxy,l=tt(e)?e.includes(".")?C1(o,e):()...
function C1 (line 4) | function C1(e,t){const n=t.split(".");return()=>{let o=e;for(let l=0;l<n...
function gl (line 4) | function gl(e,t){if(!dt(e)||e.__v_skip||(t=t||new Set,t.has(e)))return e...
function E1 (line 4) | function E1(){const e={isMounted:!1,isLeaving:!1,isUnmounting:!1,leaving...
method setup (line 4) | setup(e,{slots:t}){const n=pt(),o=E1();let l;return()=>{const u=t.defaul...
function A1 (line 4) | function A1(e,t){const{leavingVNodes:n}=e;let o=n.get(t.type);return o||...
function Ju (line 4) | function Ju(e,t,n,o){const{appear:l,mode:u,persisted:a=!1,onBeforeEnter:...
function cs (line 4) | function cs(e){if(Vr(e))return e=$o(e),e.children=null,e}
function _2 (line 4) | function _2(e){return Vr(e)?e.children?e.children[0]:void 0:e}
function Qu (line 4) | function Qu(e,t){e.shapeFlag&6&&e.component?Qu(e.component.subTree,t):e....
function Wi (line 4) | function Wi(e,t=!1,n){let o=[],l=0;for(let u=0;u<e.length;u++){let a=e[u...
function le (line 4) | function le(e){return Ge(e)?{setup:e,name:e.name}:e}
function _3 (line 4) | function _3(e,t){B1(e,"a",t)}
function D1 (line 4) | function D1(e,t){B1(e,"da",t)}
function B1 (line 4) | function B1(e,t,n=It){const o=e.__wdc||(e.__wdc=()=>{let l=n;for(;l;){if...
function m3 (line 4) | function m3(e,t,n,o){const l=Ir(t,e,o,!0);In(()=>{Si(o[t],l)},n)}
function Ir (line 4) | function Ir(e,t,n=It,o=!1){if(n){const l=n[e]||(n[e]=[]),u=t.__weh||(t._...
function C3 (line 4) | function C3(e,t=It){Ir("ec",e,t)}
function fe (line 4) | function fe(e,t){const n=Kt;if(n===null)return e;const o=Nr(n)||n.proxy,...
function sl (line 4) | function sl(e,t,n,o){const l=e.dirs,u=t&&t.dirs;for(let a=0;a<l.length;a...
function lt (line 4) | function lt(e,t){return Ki(qi,e,!0,t)||e}
function Ct (line 4) | function Ct(e){return tt(e)?Ki(qi,e,!1)||e:e||x1}
function ji (line 4) | function ji(e){return Ki(E3,e)}
function Ki (line 4) | function Ki(e,t,n=!0,o=!1){const l=Kt||It;if(l){const u=l.type;if(e===qi...
function m2 (line 4) | function m2(e,t){return e&&(e[t]||e[Ln(t)]||e[Pr(Ln(t))])}
function it (line 4) | function it(e,t,n,o){let l;const u=n&&n[o];if(qe(e)||tt(e)){l=new Array(...
function Zl (line 4) | function Zl(e,t){for(let n=0;n<t.length;n++){const o=t[n];if(qe(o))for(l...
function ze (line 4) | function ze(e,t,n={},o,l){if(Kt.isCE||Kt.parent&&Iu(Kt.parent)&&Kt.paren...
function $1 (line 4) | function $1(e){return e.some(t=>cn(t)?!(t.type===an||t.type===Oe&&!$1(t....
function F3 (line 4) | function F3(e,t){const n={};for(const o in e)n[t&&/[A-Z]/.test(o)?`on:${...
method get (line 4) | get({_:e},t){const{ctx:n,setupState:o,data:l,props:u,accessCache:a,type:...
method set (line 4) | set({_:e},t,n){const{data:o,setupState:l,ctx:u}=e;return l!==wt&&st(l,t)...
method has (line 4) | has({_:{data:e,setupState:t,accessCache:n,ctx:o,appContext:l,propsOption...
method defineProperty (line 4) | defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:st(n,"valu...
function D3 (line 4) | function D3(e){const t=Gi(e),n=e.proxy,o=e.ctx;Ns=!1,t.beforeCreate&&g2(...
function B3 (line 4) | function B3(e,t,n=vt,o=!1){qe(e)&&(e=Os(e));for(const l in e){const u=e[...
function g2 (line 4) | function g2(e,t,n){Sn(qe(e)?e.map(o=>o.bind(t.proxy)):e.bind(t.proxy),t,n)}
function S1 (line 4) | function S1(e,t,n,o){const l=o.includes(".")?C1(n,o):()=>n[o];if(tt(e)){...
function Gi (line 4) | function Gi(e){const t=e.type,{mixins:n,extends:o}=t,{mixins:l,optionsCa...
function mr (line 4) | function mr(e,t,n,o=!1){const{mixins:l,extends:u}=t;u&&mr(e,u,n,!0),l&&l...
function b2 (line 4) | function b2(e,t){return t?e?function(){return Ht(Ge(e)?e.call(this,this)...
function $3 (line 4) | function $3(e,t){return fl(Os(e),Os(t))}
function Os (line 4) | function Os(e){if(qe(e)){const t={};for(let n=0;n<e.length;n++)t[e[n]]=e...
function Zt (line 4) | function Zt(e,t){return e?[...new Set([].concat(e,t))]:t}
function fl (line 4) | function fl(e,t){return e?Ht(Ht(Object.create(null),e),t):t}
function S3 (line 4) | function S3(e,t){if(!e)return t;if(!t)return e;const n=Ht(Object.create(...
function k3 (line 4) | function k3(e,t,n,o=!1){const l={},u={};fr(u,Rr,1),e.propsDefaults=Objec...
function P3 (line 4) | function P3(e,t,n,o){const{props:l,attrs:u,vnode:{patchFlag:a}}=e,r=ct(l...
function k1 (line 4) | function k1(e,t,n,o){const[l,u]=e.propsOptions;let a=!1,r;if(t)for(let s...
function Us (line 4) | function Us(e,t,n,o,l,u){const a=e[n];if(a!=null){const r=st(a,"default"...
function P1 (line 4) | function P1(e,t,n=!1){const o=t.propsCache,l=o.get(e);if(l)return l;cons...
function y2 (line 4) | function y2(e){return e[0]!=="$"}
function w2 (line 4) | function w2(e){const t=e&&e.toString().match(/^\s*function (\w+)/);retur...
function C2 (line 4) | function C2(e,t){return w2(e)===w2(t)}
function E2 (line 4) | function E2(e,t){return qe(t)?t.findIndex(n=>C2(n,e)):Ge(t)&&C2(t,e)?0:-1}
function M1 (line 4) | function M1(){return{app:null,config:{isNativeTag:pp,performance:!1,glob...
function V3 (line 4) | function V3(e,t){return function(o,l=null){Ge(o)||(o=Object.assign({},o)...
function Ws (line 4) | function Ws(e,t,n,o,l=!1){if(qe(e)){e.forEach((v,_)=>Ws(v,t&&(qe(t)?t[_]...
function I3 (line 4) | function I3(e){return H3(e)}
function H3 (line 4) | function H3(e,t){const n=gp();n.__VUE__=!0;const{insert:o,remove:l,patch...
function il (line 4) | function il({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}
function Xi (line 4) | function Xi(e,t,n=!1){const o=e.children,l=t.children;if(qe(o)&&qe(l))fo...
function R3 (line 4) | function R3(e){const t=e.slice(),n=[0];let o,l,u,a,r;const s=e.length;fo...
method process (line 4) | process(e,t,n,o,l,u,a,r,s,i){const{mc:p,pc:m,pbc:v,o:{insert:_,querySele...
method remove (line 4) | remove(e,t,n,o,{um:l,o:{remove:u}},a){const{shapeFlag:r,children:s,ancho...
function ka (line 4) | function ka(e,t,n,{o:{insert:o},m:l},u=2){u===0&&o(e.targetAnchor,t,n);c...
function U3 (line 4) | function U3(e,t,n,o,l,u,{o:{nextSibling:a,parentNode:r,querySelector:s}}...
function b (line 4) | function b(e=!1){Ru.push(qn=e?null:[])}
function W3 (line 4) | function W3(){Ru.pop(),qn=Ru[Ru.length-1]||null}
function A2 (line 4) | function A2(e){Zu+=e}
function I1 (line 4) | function I1(e){return e.dynamicChildren=Zu>0?qn||Kl:null,W3(),Zu>0&&qn&&...
function F (line 4) | function F(e,t,n,o,l,u){return I1(f(e,t,n,o,l,u,!0))}
function ae (line 4) | function ae(e,t,n,o,l){return I1(c(e,t,n,o,l,!0))}
function cn (line 4) | function cn(e){return e?e.__v_isVNode===!0:!1}
function hl (line 4) | function hl(e,t){return e.type===t.type&&e.key===t.key}
function f (line 4) | function f(e,t=null,n=null,o=0,l=null,u=e===Oe?0:1,a=!1,r=!1){const s={_...
function q3 (line 4) | function q3(e,t=null,n=null,o=0,l=null,u=!1){if((!e||e===x1)&&(e=an),cn(...
function j3 (line 4) | function j3(e){return e?i1(e)||Rr in e?Ht({},e):e:null}
function $o (line 4) | function $o(e,t,n=!1){const{props:o,ref:l,patchFlag:u,children:a}=e,r=t?...
function A (line 4) | function A(e=" ",t=0){return c(fa,null,e,t)}
function K3 (line 4) | function K3(e,t){const n=c(Ya,null,e);return n.staticCount=t,n}
function oe (line 4) | function oe(e="",t=!1){return t?(b(),ae(an,null,e)):c(an,null,e)}
function lo (line 4) | function lo(e){return e==null||typeof e=="boolean"?c(an):qe(e)?c(Oe,null...
function Ko (line 4) | function Ko(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:$o(e)}
function Ji (line 4) | function Ji(e,t){let n=0;const{shapeFlag:o}=e;if(t==null)t=null;else if(...
function kn (line 4) | function kn(...e){const t={};for(let n=0;n<e.length;n++){const o=e[n];fo...
function oo (line 4) | function oo(e,t,n,o=null){Sn(e,t,7,[n,o])}
function X3 (line 4) | function X3(e,t,n){const o=e.type,l=(t?t.appContext:e.appContext)||G3,u=...
function R1 (line 4) | function R1(e){return e.vnode.shapeFlag&4}
function J3 (line 4) | function J3(e,t=!1){ea=t;const{props:n,children:o}=e.vnode,l=R1(e);k3(e,...
function Q3 (line 4) | function Q3(e,t){const n=e.type;e.accessCache=Object.create(null),e.prox...
function D2 (line 4) | function D2(e,t,n){Ge(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render...
function N1 (line 4) | function N1(e,t,n){const o=e.type;if(!e.render){if(!t&&B2&&!o.render){co...
function Z3 (line 4) | function Z3(e){return new Proxy(e.attrs,{get(t,n){return Fn(e,"get","$at...
function O1 (line 4) | function O1(e){const t=o=>{e.exposed=o||{}};let n;return{get attrs(){ret...
function Nr (line 4) | function Nr(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Pro...
function U1 (line 4) | function U1(e,t=!0){return Ge(e)?e.displayName||e.name:e.name||t&&e.__name}
function W1 (line 4) | function W1(e,t,n=!1){let o=U1(t);if(!o&&t.__file){const l=t.__file.matc...
function n8 (line 4) | function n8(e){return Ge(e)&&"__vccOpts"in e}
function To (line 4) | function To(){return q1().slots}
function o8 (line 4) | function o8(){return q1().attrs}
function q1 (line 4) | function q1(){const e=pt();return e.setupContext||(e.setupContext=O1(e))}
function Re (line 4) | function Re(e,t,n){const o=arguments.length;return o===2?dt(t)&&!qe(t)?c...
method setScopeId (line 4) | setScopeId(e,t){e.setAttribute(t,"")}
method insertStaticContent (line 4) | insertStaticContent(e,t,n,o,l,u){const a=n?n.previousSibling:t.lastChild...
function r8 (line 4) | function r8(e,t,n){const o=e._vtc;o&&(t=(t?[t,...o]:[...o]).join(" ")),t...
function s8 (line 4) | function s8(e,t,n){const o=e.style,l=tt(n);if(n&&!l){for(const u in n)js...
function js (line 4) | function js(e,t,n){if(qe(n))n.forEach(o=>js(e,t,o));else if(n==null&&(n=...
function i8 (line 4) | function i8(e,t){const n=ds[t];if(n)return n;let o=Ln(t);if(o!=="filter"...
function c8 (line 4) | function c8(e,t,n,o,l){if(o&&t.startsWith("xlink:"))n==null?e.removeAttr...
function d8 (line 4) | function d8(e,t,n,o,l,u,a){if(t==="innerHTML"||t==="textContent"){o&&a(o...
function Xo (line 4) | function Xo(e,t,n,o){e.addEventListener(t,n,o)}
function f8 (line 4) | function f8(e,t,n,o){e.removeEventListener(t,n,o)}
function p8 (line 4) | function p8(e,t,n,o,l=null){const u=e._vei||(e._vei={}),a=u[t];if(o&&a)a...
function v8 (line 4) | function v8(e){let t;if(P2.test(e)){t={};let o;for(;o=e.match(P2);)e=e.s...
function m8 (line 4) | function m8(e,t){const n=o=>{if(!o._vts)o._vts=Date.now();else if(o._vts...
function g8 (line 4) | function g8(e,t){if(qe(t)){const n=e.stopImmediatePropagation;return e.s...
function y8 (line 4) | function y8(e,t,n,o){return o?!!(t==="innerHTML"||t==="textContent"||t i...
function K1 (line 4) | function K1(e){const t={};for(const W in e)W in j1||(t[W]=e[W]);if(e.css...
function C8 (line 4) | function C8(e){if(e==null)return null;if(dt(e))return[ps(e.enter),ps(e.l...
function ps (line 4) | function ps(e){return pr(e)}
function bo (line 4) | function bo(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vt...
function Uo (line 4) | function Uo(e,t){t.split(/\s+/).forEach(o=>o&&e.classList.remove(o));con...
function z2 (line 4) | function z2(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}
function M2 (line 4) | function M2(e,t,n,o){const l=e._endId=++E8,u=()=>{l===e._endId&&o()};if(...
function G1 (line 4) | function G1(e,t){const n=window.getComputedStyle(e),o=g=>(n[g]||"").spli...
function V2 (line 4) | function V2(e,t){for(;e.length<t.length;)e=e.concat(e);return Math.max(....
function I2 (line 4) | function I2(e){return Number(e.slice(0,-1).replace(",","."))*1e3}
function Y1 (line 4) | function Y1(){return document.body.offsetHeight}
method setup (line 4) | setup(e,{slots:t}){const n=pt(),o=E1();let l,u;return Ll(()=>{if(!l.leng...
function D8 (line 4) | function D8(e){const t=e.el;t._moveCb&&t._moveCb(),t._enterCb&&t._enterC...
function B8 (line 4) | function B8(e){J1.set(e,e.el.getBoundingClientRect())}
function x8 (line 4) | function x8(e){const t=X1.get(e),n=J1.get(e),o=t.left-n.left,l=t.top-n.t...
function $8 (line 4) | function $8(e,t,n){const o=e.cloneNode();e._vtc&&e._vtc.forEach(a=>{a.sp...
function S8 (line 4) | function S8(e){e.target.composing=!0}
function H2 (line 4) | function H2(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchE...
method created (line 4) | created(e,{modifiers:{lazy:t,trim:n,number:o}},l){e._assign=tu(l);const ...
method mounted (line 4) | mounted(e,{value:t}){e.value=t==null?"":t}
method beforeUpdate (line 4) | beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:o,number:l}},u){if(e._ass...
method created (line 4) | created(e,t,n){e._assign=tu(n),Xo(e,"change",()=>{const o=e._modelValue,...
method beforeUpdate (line 4) | beforeUpdate(e,t,n){e._assign=tu(n),R2(e,t,n)}
function R2 (line 4) | function R2(e,{value:t,oldValue:n},o){e._modelValue=t,qe(t)?e.checked=Kd...
method created (line 4) | created(e,{value:t},n){e.checked=Jl(t,n.props.value),e._assign=tu(n),Xo(...
method beforeUpdate (line 4) | beforeUpdate(e,{value:t,oldValue:n},o){e._assign=tu(o),t!==n&&(e.checked...
function Z1 (line 4) | function Z1(e){return"_value"in e?e._value:e.value}
function ef (line 4) | function ef(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}
method beforeMount (line 4) | beforeMount(e,{value:t},{transition:n}){e._vod=e.style.display==="none"?...
method mounted (line 4) | mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)}
method updated (line 4) | updated(e,{value:t,oldValue:n},{transition:o}){!t!=!n&&(o?t?(o.beforeEnt...
method beforeUnmount (line 4) | beforeUnmount(e,{value:t}){Su(e,t)}
function Su (line 4) | function Su(e,t){e.style.display=t?e._vod:"none"}
function tf (line 4) | function tf(){return N2||(N2=I3(z8))}
function M8 (line 4) | function M8(e){return tt(e)?document.querySelector(e):e}
function U8 (line 4) | function U8(e){var t=N8.call(e,ku),n=e[ku];try{e[ku]=void 0;var o=!0}cat...
function j8 (line 4) | function j8(e){return q8.call(e)}
function yu (line 4) | function yu(e){return e==null?e===void 0?G8:K8:O2&&O2 in Object(e)?U8(e)...
function tl (line 4) | function tl(e){return e!=null&&typeof e=="object"}
function Or (line 4) | function Or(e){return typeof e=="symbol"||tl(e)&&yu(e)==Y8}
function X8 (line 4) | function X8(e,t){for(var n=-1,o=e==null?0:e.length,l=Array(o);++n<o;)l[n...
function uf (line 4) | function uf(e){if(typeof e=="string")return e;if(Yn(e))return X8(e,uf)+"...
function e5 (line 4) | function e5(e){for(var t=e.length;t--&&Z8.test(e.charAt(t)););return t}
function n5 (line 4) | function n5(e){return e&&e.slice(0,e5(e)+1).replace(t5,"")}
function fo (line 4) | function fo(e){var t=typeof e;return e!=null&&(t=="object"||t=="function")}
function j2 (line 4) | function j2(e){if(typeof e=="number")return e;if(Or(e))return q2;if(fo(e...
function r5 (line 4) | function r5(e){return e}
function af (line 4) | function af(e){if(!fo(e))return!1;var t=yu(e);return t==i5||t==c5||t==s5...
function p5 (line 4) | function p5(e){return!!K2&&K2 in e}
function Tl (line 4) | function Tl(e){if(e!=null){try{return h5.call(e)}catch{}try{return e+""}...
function E5 (line 4) | function E5(e){if(!fo(e)||p5(e))return!1;var t=af(e)?C5:m5;return t.test...
function F5 (line 4) | function F5(e,t){return e==null?void 0:e[t]}
function zl (line 4) | function zl(e,t){var n=F5(e,t);return E5(n)?n:void 0}
function e (line 4) | function e(){}
function x5 (line 4) | function x5(e,t,n){switch(n.length){case 0:return e.call(t);case 1:retur...
function $5 (line 4) | function $5(e,t){var n=-1,o=e.length;for(t||(t=Array(o));++n<o;)t[n]=e[n...
function L5 (line 4) | function L5(e){var t=0,n=0;return function(){var o=P5(),l=k5-(o-n);if(n=...
function T5 (line 4) | function T5(e){return function(){return e}}
function R5 (line 4) | function R5(e,t){for(var n=-1,o=e==null?0:e.length;++n<o&&t(e[n],n,e)!==...
function Qi (line 4) | function Qi(e,t){var n=typeof e;return t=t==null?N5:t,!!t&&(n=="number"|...
function rf (line 4) | function rf(e,t,n){t=="__proto__"&&br?br(e,t,{configurable:!0,enumerable...
function Zi (line 4) | function Zi(e,t){return e===t||e!==e&&t!==t}
function ec (line 4) | function ec(e,t,n){var o=e[t];(!(W5.call(e,t)&&Zi(o,n))||n===void 0&&!(t...
function Ur (line 4) | function Ur(e,t,n,o){var l=!n;n||(n={});for(var u=-1,a=t.length;++u<a;){...
function q5 (line 4) | function q5(e,t,n){return t=Y2(t===void 0?e.length-1:t,0),function(){for...
function tc (line 4) | function tc(e){return typeof e=="number"&&e>-1&&e%1==0&&e<=j5}
function sf (line 4) | function sf(e){return e!=null&&tc(e.length)&&!af(e)}
function nc (line 4) | function nc(e){var t=e&&e.constructor,n=typeof t=="function"&&t.prototyp...
function G5 (line 4) | function G5(e,t){for(var n=-1,o=Array(e);++n<e;)o[n]=t(n);return o}
function X2 (line 4) | function X2(e){return tl(e)&&yu(e)==Y5}
function Z5 (line 4) | function Z5(){return!1}
function Bv (line 4) | function Bv(e){return tl(e)&&tc(e.length)&&!!At[yu(e)]}
function lc (line 4) | function lc(e){return function(t){return e(t)}}
function vf (line 4) | function vf(e,t){var n=Yn(e),o=!n&&oc(e),l=!n&&!o&&yr(e),u=!n&&!o&&!l&&p...
function hf (line 4) | function hf(e,t){return function(n){return e(t(n))}}
function Vv (line 4) | function Vv(e){if(!nc(e))return Tv(e);var t=[];for(var n in Object(e))Mv...
function uc (line 4) | function uc(e){return sf(e)?vf(e):Vv(e)}
function Iv (line 4) | function Iv(e){var t=[];if(e!=null)for(var n in Object(e))t.push(n);retu...
function Nv (line 4) | function Nv(e){if(!fo(e))return Iv(e);var t=nc(e),n=[];for(var o in e)o=...
function ac (line 4) | function ac(e){return sf(e)?vf(e,!0):Nv(e)}
function Wv (line 4) | function Wv(e,t){if(Yn(e))return!1;var n=typeof e;return n=="number"||n=...
function jv (line 4) | function jv(){this.__data__=ta?ta(null):{},this.size=0}
function Kv (line 4) | function Kv(e){var t=this.has(e)&&delete this.__data__[e];return this.si...
function Jv (line 4) | function Jv(e){var t=this.__data__;if(ta){var n=t[e];return n===Gv?void ...
function eh (line 4) | function eh(e){var t=this.__data__;return ta?t[e]!==void 0:Zv.call(t,e)}
function nh (line 4) | function nh(e,t){var n=this.__data__;return this.size+=this.has(e)?0:1,n...
function xl (line 4) | function xl(e){var t=-1,n=e==null?0:e.length;for(this.clear();++t<n;){va...
function oh (line 4) | function oh(){this.__data__=[],this.size=0}
function Wr (line 4) | function Wr(e,t){for(var n=e.length;n--;)if(Zi(e[n][0],t))return n;retur...
function ah (line 4) | function ah(e){var t=this.__data__,n=Wr(t,e);if(n<0)return!1;var o=t.len...
function rh (line 4) | function rh(e){var t=this.__data__,n=Wr(t,e);return n<0?void 0:t[n][1]}
function sh (line 4) | function sh(e){return Wr(this.__data__,e)>-1}
function ih (line 4) | function ih(e,t){var n=this.__data__,o=Wr(n,e);return o<0?(++this.size,n...
function zo (line 4) | function zo(e){var t=-1,n=e==null?0:e.length;for(this.clear();++t<n;){va...
function dh (line 4) | function dh(){this.size=0,this.__data__={hash:new xl,map:new(na||zo),str...
function fh (line 4) | function fh(e){var t=typeof e;return t=="string"||t=="number"||t=="symbo...
function qr (line 4) | function qr(e,t){var n=e.__data__;return fh(t)?n[typeof t=="string"?"str...
function ph (line 4) | function ph(e){var t=qr(this,e).delete(e);return this.size-=t?1:0,t}
function vh (line 4) | function vh(e){return qr(this,e).get(e)}
function hh (line 4) | function hh(e){return qr(this,e).has(e)}
function _h (line 4) | function _h(e,t){var n=qr(this,e),o=n.size;return n.set(e,t),this.size+=...
function Mo (line 4) | function Mo(e){var t=-1,n=e==null?0:e.length;for(this.clear();++t<n;){va...
function rc (line 4) | function rc(e,t){if(typeof e!="function"||t!=null&&typeof t!="function")...
function bh (line 4) | function bh(e){var t=rc(e,function(o){return n.size===gh&&n.clear(),o}),...
function Fh (line 4) | function Fh(e){return e==null?"":uf(e)}
function jr (line 4) | function jr(e,t){return Yn(e)?e:Wv(e,t)?[e]:Eh(Fh(e))}
function sc (line 4) | function sc(e){if(typeof e=="string"||Or(e))return e;var t=e+"";return t...
function _f (line 4) | function _f(e,t){t=jr(t,e);for(var n=0,o=t.length;e!=null&&n<o;)e=e[sc(t...
function en (line 4) | function en(e,t,n){var o=e==null?void 0:_f(e,t);return o===void 0?n:o}
function ic (line 4) | function ic(e,t){for(var n=-1,o=t.length,l=e.length;++n<o;)e[l+n]=t[n];r...
function Dh (line 4) | function Dh(e){return Yn(e)||oc(e)||!!(e0&&e&&e[e0])}
function mf (line 4) | function mf(e,t,n,o,l){var u=-1,a=e.length;for(n||(n=Dh),l||(l=[]);++u<a...
function Bh (line 4) | function Bh(e){var t=e==null?0:e.length;return t?mf(e,1):[]}
function xh (line 4) | function xh(e){return H5(q5(e,void 0,Bh),e+"")}
function oa (line 4) | function oa(){if(!arguments.length)return[];var e=arguments[0];return Yn...
function Sh (line 4) | function Sh(){this.__data__=new zo,this.size=0}
function kh (line 4) | function kh(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n}
function Ph (line 4) | function Ph(e){return this.__data__.get(e)}
function Lh (line 4) | function Lh(e){return this.__data__.has(e)}
function zh (line 4) | function zh(e,t){var n=this.__data__;if(n instanceof zo){var o=n.__data_...
function Bo (line 4) | function Bo(e){var t=this.__data__=new zo(e);this.size=t.size}
function Mh (line 4) | function Mh(e,t){return e&&Ur(t,uc(t),e)}
function Vh (line 4) | function Vh(e,t){return e&&Ur(t,ac(t),e)}
function Hh (line 4) | function Hh(e,t){if(t)return e.slice();var n=e.length,o=o0?o0(n):new e.c...
function Rh (line 4) | function Rh(e,t){for(var n=-1,o=e==null?0:e.length,l=0,u=[];++n<o;){var ...
function yf (line 4) | function yf(){return[]}
function Wh (line 4) | function Wh(e,t){return Ur(e,cc(e),t)}
function Kh (line 4) | function Kh(e,t){return Ur(e,wf(e),t)}
function Cf (line 4) | function Cf(e,t,n){var o=t(e);return Yn(e)?o:ic(o,n(e))}
function Gs (line 4) | function Gs(e){return Cf(e,uc,cc)}
function Gh (line 4) | function Gh(e){return Cf(e,ac,wf)}
function a_ (line 4) | function a_(e){var t=e.length,n=new e.constructor(t);return t&&typeof e[...
function dc (line 4) | function dc(e){var t=new e.constructor(e.byteLength);return new wr(t).se...
function s_ (line 4) | function s_(e,t){var n=t?dc(e.buffer):e.buffer;return new e.constructor(...
function c_ (line 4) | function c_(e){var t=new e.constructor(e.source,i_.exec(e));return t.las...
function d_ (line 4) | function d_(e){return d0?Object(d0.call(e)):{}}
function f_ (line 4) | function f_(e,t){var n=t?dc(e.buffer):e.buffer;return new e.constructor(...
function P_ (line 4) | function P_(e,t,n){var o=e.constructor;switch(t){case w_:return dc(e);ca...
function L_ (line 4) | function L_(e){return typeof e.constructor=="function"&&!nc(e)?B5(gf(e))...
function z_ (line 4) | function z_(e){return tl(e)&&la(e)==T_}
function H_ (line 4) | function H_(e){return tl(e)&&la(e)==I_}
function Ja (line 4) | function Ja(e,t,n,o,l,u){var a,r=t&O_,s=t&U_,i=t&W_;if(n&&(a=l?n(e,o,l,u...
function v0 (line 4) | function v0(e){return Ja(e,vm)}
function _m (line 4) | function _m(e){return this.__data__.set(e,hm),this}
function mm (line 4) | function mm(e){return this.__data__.has(e)}
function Cr (line 4) | function Cr(e){var t=-1,n=e==null?0:e.length;for(this.__data__=new Mo;++...
function gm (line 4) | function gm(e,t){for(var n=-1,o=e==null?0:e.length;++n<o;)if(t(e[n],n,e)...
function bm (line 4) | function bm(e,t){return e.has(t)}
function Df (line 4) | function Df(e,t,n,o,l,u){var a=n&ym,r=e.length,s=t.length;if(r!=s&&!(a&&...
function Cm (line 4) | function Cm(e){var t=-1,n=Array(e.size);return e.forEach(function(o,l){n...
function Em (line 4) | function Em(e){var t=-1,n=Array(e.size);return e.forEach(function(o){n[+...
function Vm (line 4) | function Vm(e,t,n,o,l,u,a){switch(n){case Mm:if(e.byteLength!=t.byteLeng...
function Nm (line 4) | function Nm(e,t,n,o,l,u){var a=n&Im,r=Gs(e),s=r.length,i=Gs(t),p=i.lengt...
function Wm (line 4) | function Wm(e,t,n,o,l,u){var a=Yn(e),r=Yn(t),s=a?m0:la(e),i=r?m0:la(t);s...
function Bf (line 4) | function Bf(e,t,n,o,l){return e===t?!0:e==null||t==null||!tl(e)&&!tl(t)?...
function qm (line 4) | function qm(e,t){return e!=null&&t in Object(e)}
function jm (line 4) | function jm(e,t,n){t=jr(t,e);for(var o=-1,l=t.length,u=!1;++o<l;){var a=...
function Km (line 4) | function Km(e,t){return e!=null&&jm(e,t,qm)}
function lu (line 4) | function lu(e,t,n){var o,l,u,a,r,s,i=0,p=!1,m=!1,v=!0;if(typeof e!="func...
function xf (line 4) | function xf(e){for(var t=-1,n=e==null?0:e.length,o={};++t<n;){var l=e[t]...
function Qs (line 4) | function Qs(e,t){return Bf(e,t)}
function io (line 4) | function io(e){return e==null}
function $f (line 4) | function $f(e,t,n,o){if(!fo(e))return e;t=jr(t,e);for(var l=-1,u=t.lengt...
function Qm (line 4) | function Qm(e,t,n){for(var o=-1,l=t.length,u={};++o<l;){var a=t[o],r=_f(...
function Zm (line 4) | function Zm(e,t){return Qm(e,t,function(n,o){return Km(e,o)})}
function n9 (line 4) | function n9(e,t,n){return e==null?e:$f(e,t,n)}
function Er (line 4) | function Er(e){return typeof e=="function"?e():h(e)}
function i9 (line 4) | function i9(e,t){function n(...o){e(()=>t.apply(this,o),{fn:t,thisArg:th...
function c9 (line 4) | function c9(e,t={}){let n,o;return u=>{const a=Er(e),r=Er(t.maxWait);if(...
function d9 (line 4) | function d9(e){return e}
function Kr (line 4) | function Kr(e){return wp()?(Jd(e),!0):!1}
function f9 (line 4) | function f9(e,t=200,n={}){return i9(c9(t,n),e)}
function p9 (line 4) | function p9(e,t=200,n={}){if(t<=0)return e;const o=L(e.value),l=f9(()=>{...
function fc (line 4) | function fc(e,t=!0){pt()?ot(e):t?e():at(e)}
function uu (line 4) | function uu(e,t,n={}){const{immediate:o=!0}=n,l=L(!1);let u=null;functio...
function ao (line 4) | function ao(e){var t;const n=Er(e);return(t=n==null?void 0:n.$el)!=null?...
function Gt (line 4) | function Gt(...e){let t,n,o,l;if(s9(e[0])?([n,o,l]=e,t=Gr):[t,n,o,l]=e,!...
function v9 (line 4) | function v9(e,t,n={}){const{window:o=Gr,ignore:l,capture:u=!0,detectIfra...
function h9 (line 4) | function h9(e,t=!1){const n=L(),o=()=>n.value=Boolean(e());return o(),fc...
function _9 (line 4) | function _9(e){return JSON.parse(JSON.stringify(e))}
function po (line 4) | function po(e,t,n={}){const o=n,{window:l=Gr}=o,u=b9(o,["window"]);let a...
function C0 (line 4) | function C0(e,t={}){const{reset:n=!0,windowResize:o=!0,windowScroll:l=!0...
function A9 (line 4) | function A9(e,t,n,o={}){var l,u,a;const{clone:r=!1,passive:s=!1,eventNam...
function D9 (line 4) | function D9(e={}){const{window:t=Gr,initialWidth:n=1/0,initialHeight:o=1...
method value (line 4) | get value(){return en(e,t,n)}
method value (line 4) | set value(o){n9(e,t,o)}
class $9 (line 4) | class $9 extends Error{constructor(t){super(t),this.name="ElementPlusErr...
method constructor (line 4) | constructor(t){super(t),this.name="ElementPlusError"}
function An (line 4) | function An(e,t){throw new $9(`[${e}] ${t}`)}
function Xn (line 4) | function Xn(e,t="px"){if(!e)return"";if(tt(e))return e;if(gt(e))return`$...
function L9 (line 4) | function L9(e,t){if(!_t)return;if(!t){e.scrollTop=0;return}const n=[];le...
function R9 (line 4) | function R9(e,t,n,o,l,u){return b(),F("svg",z9,H9)}
function K9 (line 4) | function K9(e,t,n,o,l,u){return b(),F("svg",U9,j9)}
function eg (line 4) | function eg(e,t,n,o,l,u){return b(),F("svg",X9,Z9)}
function ag (line 4) | function ag(e,t,n,o,l,u){return b(),F("svg",og,ug)}
function fg (line 4) | function fg(e,t,n,o,l,u){return b(),F("svg",ig,dg)}
function gg (line 4) | function gg(e,t,n,o,l,u){return b(),F("svg",hg,mg)}
function Eg (line 4) | function Eg(e,t,n,o,l,u){return b(),F("svg",yg,Cg)}
function $g (line 4) | function $g(e,t,n,o,l,u){return b(),F("svg",Dg,xg)}
function Tg (line 4) | function Tg(e,t,n,o,l,u){return b(),F("svg",kg,Lg)}
function Rg (line 4) | function Rg(e,t,n,o,l,u){return b(),F("svg",Vg,Hg)}
function qg (line 4) | function qg(e,t,n,o,l,u){return b(),F("svg",Og,Wg)}
function Jg (line 4) | function Jg(e,t,n,o,l,u){return b(),F("svg",Gg,Xg)}
function n7 (line 4) | function n7(e,t,n,o,l,u){return b(),F("svg",Zg,t7)}
function i7 (line 4) | function i7(e,t,n,o,l,u){return b(),F("svg",u7,s7)}
function _7 (line 4) | function _7(e,t,n,o,l,u){return b(),F("svg",f7,h7)}
function C7 (line 4) | function C7(e,t,n,o,l,u){return b(),F("svg",b7,w7)}
function x7 (line 4) | function x7(e,t,n,o,l,u){return b(),F("svg",A7,B7)}
function M7 (line 4) | function M7(e,t,n,o,l,u){return b(),F("svg",k7,z7)}
function O7 (line 4) | function O7(e,t,n,o,l,u){return b(),F("svg",H7,N7)}
function Y7 (line 4) | function Y7(e,t,n,o,l,u){return b(),F("svg",q7,G7)}
function nb (line 4) | function nb(e,t,n,o,l,u){return b(),F("svg",Q7,tb)}
function sb (line 4) | function sb(e,t,n,o,l,u){return b(),F("svg",ub,rb)}
function vb (line 4) | function vb(e,t,n,o,l,u){return b(),F("svg",db,pb)}
function Cb (line 4) | function Cb(e,t,n,o,l,u){return b(),F("svg",mb,wb)}
function xb (line 4) | function xb(e,t,n,o,l,u){return b(),F("svg",Ab,Bb)}
function Tb (line 4) | function Tb(e,t,n,o,l,u){return b(),F("svg",kb,Lb)}
function Rb (line 4) | function Rb(e,t,n,o,l,u){return b(),F("svg",Vb,Hb)}
function jb (line 4) | function jb(e,t,n,o,l,u){return b(),F("svg",Ub,qb)}
function Qb (line 4) | function Qb(e,t,n,o,l,u){return b(),F("svg",Yb,Jb)}
function ly (line 4) | function ly(e,t,n,o,l,u){return b(),F("svg",ty,oy)}
function cy (line 4) | function cy(e,t,n,o,l,u){return b(),F("svg",ry,iy)}
function _y (line 4) | function _y(e,t,n,o,l,u){return b(),F("svg",py,hy)}
function Cy (line 4) | function Cy(e,t,n,o,l,u){return b(),F("svg",by,wy)}
function xy (line 4) | function xy(e,t,n,o,l,u){return b(),F("svg",Ay,By)}
function Ty (line 4) | function Ty(e,t,n,o,l,u){return b(),F("svg",ky,Ly)}
function Ry (line 4) | function Ry(e,t,n,o,l,u){return b(),F("svg",Vy,Hy)}
function Ky (line 4) | function Ky(e,t,n,o,l,u){return b(),F("svg",Uy,jy)}
function ew (line 4) | function ew(e,t,n,o,l,u){return b(),F("svg",Xy,Zy)}
function rw (line 4) | function rw(e,t,n,o,l,u){return b(),F("svg",ow,aw)}
function vw (line 4) | function vw(e,t,n,o,l,u){return b(),F("svg",cw,pw)}
function yw (line 4) | function yw(e,t,n,o,l,u){return b(),F("svg",mw,bw)}
function Dw (line 4) | function Dw(e,t,n,o,l,u){return b(),F("svg",Ew,Aw)}
function Pw (line 4) | function Pw(e,t,n,o,l,u){return b(),F("svg",$w,kw)}
function Vw (line 4) | function Vw(e,t,n,o,l,u){return b(),F("svg",Tw,Mw)}
function Uw (line 4) | function Uw(e,t,n,o,l,u){return b(),F("svg",Rw,Ow)}
function Yw (line 4) | function Yw(e,t,n,o,l,u){return b(),F("svg",jw,Gw)}
function oC (line 4) | function oC(e,t,n,o,l,u){return b(),F("svg",Qw,nC)}
function iC (line 4) | function iC(e,t,n,o,l,u){return b(),F("svg",aC,sC)}
function _C (line 4) | function _C(e,t,n,o,l,u){return b(),F("svg",fC,hC)}
function wC (line 4) | function wC(e,t,n,o,l,u){return b(),F("svg",gC,yC)}
function BC (line 4) | function BC(e,t,n,o,l,u){return b(),F("svg",EC,DC)}
function PC (line 4) | function PC(e,t,n,o,l,u){return b(),F("svg",$C,kC)}
function RC (line 4) | function RC(e,t,n,o,l,u){return b(),F("svg",zC,HC)}
function GC (line 4) | function GC(e,t,n,o,l,u){return b(),F("svg",UC,KC)}
function eE (line 4) | function eE(e,t,n,o,l,u){return b(),F("svg",JC,ZC)}
function aE (line 4) | function aE(e,t,n,o,l,u){return b(),F("svg",oE,uE)}
function dE (line 4) | function dE(e,t,n,o,l,u){return b(),F("svg",sE,cE)}
function mE (line 4) | function mE(e,t,n,o,l,u){return b(),F("svg",vE,_E)}
function EE (line 4) | function EE(e,t,n,o,l,u){return b(),F("svg",yE,CE)}
function kE (line 4) | function kE(e,t,n,o,l,u){return b(),F("svg",DE,SE)}
function VE (line 4) | function VE(e,t,n,o,l,u){return b(),F("svg",TE,ME)}
function UE (line 4) | function UE(e,t,n,o,l,u){return b(),F("svg",RE,OE)}
function XE (line 4) | function XE(e,t,n,o,l,u){return b(),F("svg",jE,YE)}
function nF (line 4) | function nF(e,t,n,o,l,u){return b(),F("svg",ZE,tF)}
function iF (line 4) | function iF(e,t,n,o,l,u){return b(),F("svg",uF,sF)}
function _F (line 4) | function _F(e,t,n,o,l,u){return b(),F("svg",fF,hF)}
function EF (line 4) | function EF(e,t,n,o,l,u){return b(),F("svg",bF,CF)}
function SF (line 4) | function SF(e,t,n,o,l,u){return b(),F("svg",DF,$F)}
function VF (line 4) | function VF(e,t,n,o,l,u){return b(),F("svg",LF,MF)}
function WF (line 4) | function WF(e,t,n,o,l,u){return b(),F("svg",RF,UF)}
function JF (line 4) | function JF(e,t,n,o,l,u){return b(),F("svg",KF,XF)}
function oA (line 4) | function oA(e,t,n,o,l,u){return b(),F("svg",eA,nA)}
function sA (line 4) | function sA(e,t,n,o,l,u){return b(),F("svg",uA,rA)}
function pA (line 4) | function pA(e,t,n,o,l,u){return b(),F("svg",cA,fA)}
function bA (line 4) | function bA(e,t,n,o,l,u){return b(),F("svg",_A,gA)}
function BA (line 4) | function BA(e,t,n,o,l,u){return b(),F("svg",CA,DA)}
function LA (line 4) | function LA(e,t,n,o,l,u){return b(),F("svg",SA,PA)}
function HA (line 4) | function HA(e,t,n,o,l,u){return b(),F("svg",MA,IA)}
function KA (line 4) | function KA(e,t,n,o,l,u){return b(),F("svg",OA,jA)}
function ZA (line 4) | function ZA(e,t,n,o,l,u){return b(),F("svg",XA,QA)}
function lD (line 4) | function lD(e,t,n,o,l,u){return b(),F("svg",tD,oD)}
function dD (line 4) | function dD(e,t,n,o,l,u){return b(),F("svg",rD,cD)}
function mD (line 4) | function mD(e,t,n,o,l,u){return b(),F("svg",vD,_D)}
function ED (line 4) | function ED(e,t,n,o,l,u){return b(),F("svg",yD,CD)}
function $D (line 4) | function $D(e,t,n,o,l,u){return b(),F("svg",DD,xD)}
function zD (line 4) | function zD(e,t,n,o,l,u){return b(),F("svg",PD,TD)}
function ND (line 4) | function ND(e,t,n,o,l,u){return b(),F("svg",ID,RD)}
function KD (line 4) | function KD(e,t,n,o,l,u){return b(),F("svg",WD,jD)}
function ZD (line 4) | function ZD(e,t,n,o,l,u){return b(),F("svg",XD,QD)}
function uB (line 4) | function uB(e,t,n,o,l,u){return b(),F("svg",nB,lB)}
function cB (line 4) | function cB(e,t,n,o,l,u){return b(),F("svg",rB,iB)}
function _B (line 4) | function _B(e,t,n,o,l,u){return b(),F("svg",pB,hB)}
function CB (line 4) | function CB(e,t,n,o,l,u){return b(),F("svg",bB,wB)}
function $B (line 4) | function $B(e,t,n,o,l,u){return b(),F("svg",AB,xB)}
function zB (line 4) | function zB(e,t,n,o,l,u){return b(),F("svg",PB,TB)}
function NB (line 4) | function NB(e,t,n,o,l,u){return b(),F("svg",IB,RB)}
function KB (line 4) | function KB(e,t,n,o,l,u){return b(),F("svg",WB,jB)}
function ZB (line 4) | function ZB(e,t,n,o,l,u){return b(),F("svg",XB,QB)}
function ux (line 4) | function ux(e,t,n,o,l,u){return b(),F("svg",nx,lx)}
function px (line 4) | function px(e,t,n,o,l,u){return b(),F("svg",sx,fx)}
function bx (line 4) | function bx(e,t,n,o,l,u){return b(),F("svg",_x,gx)}
function Dx (line 4) | function Dx(e,t,n,o,l,u){return b(),F("svg",Cx,Ax)}
function Px (line 4) | function Px(e,t,n,o,l,u){return b(),F("svg",$x,kx)}
function Ix (line 4) | function Ix(e,t,n,o,l,u){return b(),F("svg",zx,Vx)}
function qx (line 4) | function qx(e,t,n,o,l,u){return b(),F("svg",Nx,Wx)}
function Jx (line 4) | function Jx(e,t,n,o,l,u){return b(),F("svg",Gx,Xx)}
function o$ (line 4) | function o$(e,t,n,o,l,u){return b(),F("svg",e$,n$)}
function i$ (line 4) | function i$(e,t,n,o,l,u){return b(),F("svg",a$,s$)}
function h$ (line 4) | function h$(e,t,n,o,l,u){return b(),F("svg",f$,v$)}
function w$ (line 4) | function w$(e,t,n,o,l,u){return b(),F("svg",g$,y$)}
function B$ (line 4) | function B$(e,t,n,o,l,u){return b(),F("svg",F$,D$)}
function L$ (line 4) | function L$(e,t,n,o,l,u){return b(),F("svg",S$,P$)}
function H$ (line 4) | function H$(e,t,n,o,l,u){return b(),F("svg",M$,I$)}
function q$ (line 4) | function q$(e,t,n,o,l,u){return b(),F("svg",O$,W$)}
function Q$ (line 4) | function Q$(e,t,n,o,l,u){return b(),F("svg",G$,J$)}
function lS (line 4) | function lS(e,t,n,o,l,u){return b(),F("svg",tS,oS)}
function cS (line 4) | function cS(e,t,n,o,l,u){return b(),F("svg",rS,iS)}
function _S (line 4) | function _S(e,t,n,o,l,u){return b(),F("svg",pS,hS)}
function CS (line 4) | function CS(e,t,n,o,l,u){return b(),F("svg",bS,wS)}
function xS (line 4) | function xS(e,t,n,o,l,u){return b(),F("svg",AS,BS)}
function TS (line 4) | function TS(e,t,n,o,l,u){return b(),F("svg",kS,LS)}
function RS (line 4) | function RS(e,t,n,o,l,u){return b(),F("svg",VS,HS)}
function KS (line 4) | function KS(e,t,n,o,l,u){return b(),F("svg",US,jS)}
function ZS (line 4) | function ZS(e,t,n,o,l,u){return b(),F("svg",XS,QS)}
function uk (line 4) | function uk(e,t,n,o,l,u){return b(),F("svg",nk,lk)}
function dk (line 4) | function dk(e,t,n,o,l,u){return b(),F("svg",sk,ck)}
function mk (line 4) | function mk(e,t,n,o,l,u){return b(),F("svg",vk,_k)}
function Fk (line 4) | function Fk(e,t,n,o,l,u){return b(),F("svg",yk,Ek)}
function Sk (line 4) | function Sk(e,t,n,o,l,u){return b(),F("svg",Bk,$k)}
function Mk (line 4) | function Mk(e,t,n,o,l,u){return b(),F("svg",Lk,zk)}
function Ok (line 4) | function Ok(e,t,n,o,l,u){return b(),F("svg",Hk,Nk)}
function Gk (line 4) | function Gk(e,t,n,o,l,u){return b(),F("svg",qk,Kk)}
function tP (line 4) | function tP(e,t,n,o,l,u){return b(),F("svg",Jk,eP)}
function aP (line 4) | function aP(e,t,n,o,l,u){return b(),F("svg",oP,uP)}
function fP (line 4) | function fP(e,t,n,o,l,u){return b(),F("svg",iP,dP)}
function gP (line 4) | function gP(e,t,n,o,l,u){return b(),F("svg",hP,mP)}
function FP (line 4) | function FP(e,t,n,o,l,u){return b(),F("svg",wP,EP)}
function SP (line 4) | function SP(e,t,n,o,l,u){return b(),F("svg",BP,$P)}
function MP (line 4) | function MP(e,t,n,o,l,u){return b(),F("svg",LP,zP)}
function OP (line 4) | function OP(e,t,n,o,l,u){return b(),F("svg",HP,NP)}
function GP (line 4) | function GP(e,t,n,o,l,u){return b(),F("svg",qP,KP)}
function eL (line 4) | function eL(e,t,n,o,l,u){return b(),F("svg",JP,ZP)}
function aL (line 4) | function aL(e,t,n,o,l,u){return b(),F("svg",oL,uL)}
function dL (line 4) | function dL(e,t,n,o,l,u){return b(),F("svg",sL,cL)}
function mL (line 4) | function mL(e,t,n,o,l,u){return b(),F("svg",vL,_L)}
function EL (line 4) | function EL(e,t,n,o,l,u){return b(),F("svg",yL,CL)}
function SL (line 4) | function SL(e,t,n,o,l,u){return b(),F("svg",DL,$L)}
function ML (line 4) | function ML(e,t,n,o,l,u){return b(),F("svg",LL,zL)}
function OL (line 4) | function OL(e,t,n,o,l,u){return b(),F("svg",HL,NL)}
function GL (line 4) | function GL(e,t,n,o,l,u){return b(),F("svg",qL,KL)}
function ZL (line 4) | function ZL(e,t,n,o,l,u){return b(),F("svg",XL,QL)}
function rT (line 4) | function rT(e,t,n,o,l,u){return b(),F("svg",nT,aT)}
function vT (line 4) | function vT(e,t,n,o,l,u){return b(),F("svg",cT,pT)}
function wT (line 4) | function wT(e,t,n,o,l,u){return b(),F("svg",mT,yT)}
function BT (line 4) | function BT(e,t,n,o,l,u){return b(),F("svg",FT,DT)}
function LT (line 4) | function LT(e,t,n,o,l,u){return b(),F("svg",ST,PT)}
function HT (line 4) | function HT(e,t,n,o,l,u){return b(),F("svg",MT,IT)}
function KT (line 4) | function KT(e,t,n,o,l,u){return b(),F("svg",OT,jT)}
function ZT (line 4) | function ZT(e,t,n,o,l,u){return b(),F("svg",XT,QT)}
function az (line 4) | function az(e,t,n,o,l,u){return b(),F("svg",nz,uz)}
function pz (line 4) | function pz(e,t,n,o,l,u){return b(),F("svg",iz,fz)}
function wz (line 4) | function wz(e,t,n,o,l,u){return b(),F("svg",_z,yz)}
function Bz (line 4) | function Bz(e,t,n,o,l,u){return b(),F("svg",Fz,Dz)}
function Lz (line 4) | function Lz(e,t,n,o,l,u){return b(),F("svg",Sz,Pz)}
function Rz (line 4) | function Rz(e,t,n,o,l,u){return b(),F("svg",Mz,Hz)}
function jz (line 4) | function jz(e,t,n,o,l,u){return b(),F("svg",Uz,qz)}
function Qz (line 4) | function Qz(e,t,n,o,l,u){return b(),F("svg",Yz,Jz)}
function lM (line 4) | function lM(e,t,n,o,l,u){return b(),F("svg",tM,oM)}
function cM (line 4) | function cM(e,t,n,o,l,u){return b(),F("svg",rM,iM)}
function mM (line 4) | function mM(e,t,n,o,l,u){return b(),F("svg",fM,_M)}
function EM (line 4) | function EM(e,t,n,o,l,u){return b(),F("svg",yM,CM)}
function SM (line 4) | function SM(e,t,n,o,l,u){return b(),F("svg",DM,$M)}
function MM (line 4) | function MM(e,t,n,o,l,u){return b(),F("svg",LM,zM)}
function OM (line 4) | function OM(e,t,n,o,l,u){return b(),F("svg",HM,NM)}
function KM (line 4) | function KM(e,t,n,o,l,u){return b(),F("svg",WM,jM)}
function QM (line 4) | function QM(e,t,n,o,l,u){return b(),F("svg",YM,JM)}
function uV (line 4) | function uV(e,t,n,o,l,u){return b(),F("svg",tV,lV)}
function dV (line 4) | function dV(e,t,n,o,l,u){return b(),F("svg",sV,cV)}
function gV (line 4) | function gV(e,t,n,o,l,u){return b(),F("svg",vV,mV)}
function AV (line 4) | function AV(e,t,n,o,l,u){return b(),F("svg",wV,FV)}
function kV (line 4) | function kV(e,t,n,o,l,u){return b(),F("svg",xV,SV)}
function IV (line 4) | function IV(e,t,n,o,l,u){return b(),F("svg",TV,VV)}
function qV (line 4) | function qV(e,t,n,o,l,u){return b(),F("svg",NV,WV)}
function ZV (line 4) | function ZV(e,t,n,o,l,u){return b(),F("svg",GV,QV)}
function rI (line 4) | function rI(e,t,n,o,l,u){return b(),F("svg",nI,aI)}
function vI (line 4) | function vI(e,t,n,o,l,u){return b(),F("svg",cI,pI)}
function yI (line 4) | function yI(e,t,n,o,l,u){return b(),F("svg",mI,bI)}
function DI (line 4) | function DI(e,t,n,o,l,u){return b(),F("svg",EI,AI)}
function PI (line 4) | function PI(e,t,n,o,l,u){return b(),F("svg",$I,kI)}
function II (line 4) | function II(e,t,n,o,l,u){return b(),F("svg",zI,VI)}
function qI (line 4) | function qI(e,t,n,o,l,u){return b(),F("svg",NI,WI)}
function JI (line 4) | function JI(e,t,n,o,l,u){return b(),F("svg",GI,XI)}
function oH (line 4) | function oH(e,t,n,o,l,u){return b(),F("svg",eH,nH)}
function iH (line 4) | function iH(e,t,n,o,l,u){return b(),F("svg",aH,sH)}
function hH (line 4) | function hH(e,t,n,o,l,u){return b(),F("svg",fH,vH)}
function CH (line 4) | function CH(e,t,n,o,l,u){return b(),F("svg",gH,wH)}
function $H (line 4) | function $H(e,t,n,o,l,u){return b(),F("svg",AH,xH)}
function MH (line 4) | function MH(e,t,n,o,l,u){return b(),F("svg",PH,zH)}
function WH (line 4) | function WH(e,t,n,o,l,u){return b(),F("svg",HH,UH)}
function XH (line 4) | function XH(e,t,n,o,l,u){return b(),F("svg",KH,YH)}
function nR (line 4) | function nR(e,t,n,o,l,u){return b(),F("svg",ZH,tR)}
function rR (line 4) | function rR(e,t,n,o,l,u){return b(),F("svg",lR,aR)}
function pR (line 4) | function pR(e,t,n,o,l,u){return b(),F("svg",cR,fR)}
function yR (line 4) | function yR(e,t,n,o,l,u){return b(),F("svg",_R,bR)}
function DR (line 4) | function DR(e,t,n,o,l,u){return b(),F("svg",ER,AR)}
function zR (line 4) | function zR(e,t,n,o,l,u){return b(),F("svg",$R,TR)}
function OR (line 4) | function OR(e,t,n,o,l,u){return b(),F("svg",IR,NR)}
function GR (line 4) | function GR(e,t,n,o,l,u){return b(),F("svg",qR,KR)}
function eN (line 4) | function eN(e,t,n,o,l,u){return b(),F("svg",JR,ZR)}
function sN (line 4) | function sN(e,t,n,o,l,u){return b(),F("svg",oN,rN)}
function vN (line 4) | function vN(e,t,n,o,l,u){return b(),F("svg",dN,pN)}
function yN (line 4) | function yN(e,t,n,o,l,u){return b(),F("svg",mN,bN)}
function BN (line 4) | function BN(e,t,n,o,l,u){return b(),F("svg",EN,DN)}
function TN (line 4) | function TN(e,t,n,o,l,u){return b(),F("svg",SN,LN)}
function RN (line 4) | function RN(e,t,n,o,l,u){return b(),F("svg",VN,HN)}
function jN (line 4) | function jN(e,t,n,o,l,u){return b(),F("svg",UN,qN)}
function QN (line 4) | function QN(e,t,n,o,l,u){return b(),F("svg",YN,JN)}
function lO (line 4) | function lO(e,t,n,o,l,u){return b(),F("svg",tO,oO)}
function cO (line 4) | function cO(e,t,n,o,l,u){return b(),F("svg",rO,iO)}
function mO (line 4) | function mO(e,t,n,o,l,u){return b(),F("svg",pO,_O)}
function EO (line 4) | function EO(e,t,n,o,l,u){return b(),F("svg",yO,CO)}
function $O (line 4) | function $O(e,t,n,o,l,u){return b(),F("svg",DO,xO)}
function VO (line 4) | function VO(e,t,n,o,l,u){return b(),F("svg",PO,MO)}
function UO (line 4) | function UO(e,t,n,o,l,u){return b(),F("svg",RO,OO)}
function YO (line 4) | function YO(e,t,n,o,l,u){return b(),F("svg",jO,GO)}
function tU (line 4) | function tU(e,t,n,o,l,u){return b(),F("svg",QO,eU)}
function rU (line 4) | function rU(e,t,n,o,l,u){return b(),F("svg",lU,aU)}
function pU (line 4) | function pU(e,t,n,o,l,u){return b(),F("svg",cU,fU)}
function bU (line 4) | function bU(e,t,n,o,l,u){return b(),F("svg",_U,gU)}
function xU (line 4) | function xU(e,t,n,o,l,u){return b(),F("svg",CU,BU)}
function TU (line 4) | function TU(e,t,n,o,l,u){return b(),F("svg",kU,LU)}
function RU (line 4) | function RU(e,t,n,o,l,u){return b(),F("svg",VU,HU)}
function jU (line 4) | function jU(e,t,n,o,l,u){return b(),F("svg",UU,qU)}
function QU (line 4) | function QU(e,t,n,o,l,u){return b(),F("svg",YU,JU)}
function uW (line 4) | function uW(e,t,n,o,l,u){return b(),F("svg",tW,lW)}
function fW (line 4) | function fW(e,t,n,o,l,u){return b(),F("svg",sW,dW)}
function gW (line 4) | function gW(e,t,n,o,l,u){return b(),F("svg",hW,mW)}
function FW (line 4) | function FW(e,t,n,o,l,u){return b(),F("svg",wW,EW)}
function kW (line 4) | function kW(e,t,n,o,l,u){return b(),F("svg",BW,SW)}
function VW (line 4) | function VW(e,t,n,o,l,u){return b(),F("svg",TW,MW)}
function UW (line 4) | function UW(e,t,n,o,l,u){return b(),F("svg",RW,OW)}
function YW (line 4) | function YW(e,t,n,o,l,u){return b(),F("svg",jW,GW)}
function tq (line 4) | function tq(e,t,n,o,l,u){return b(),F("svg",QW,eq)}
function rq (line 4) | function rq(e,t,n,o,l,u){return b(),F("svg",lq,aq)}
function pq (line 4) | function pq(e,t,n,o,l,u){return b(),F("svg",cq,fq)}
function bq (line 4) | function bq(e,t,n,o,l,u){return b(),F("svg",_q,gq)}
function Aq (line 4) | function Aq(e,t,n,o,l,u){return b(),F("svg",Cq,Fq)}
function Pq (line 4) | function Pq(e,t,n,o,l,u){return b(),F("svg",xq,kq)}
function Iq (line 4) | function Iq(e,t,n,o,l,u){return b(),F("svg",zq,Vq)}
function Uq (line 4) | function Uq(e,t,n,o,l,u){return b(),F("svg",Rq,Oq)}
function Yq (line 4) | function Yq(e,t,n,o,l,u){return b(),F("svg",jq,Gq)}
function nj (line 4) | function nj(e,t,n,o,l,u){return b(),F("svg",Qq,tj)}
function sj (line 4) | function sj(e,t,n,o,l,u){return b(),F("svg",uj,rj)}
function vj (line 4) | function vj(e,t,n,o,l,u){return b(),F("svg",dj,pj)}
function yj (line 4) | function yj(e,t,n,o,l,u){return b(),F("svg",mj,bj)}
function Bj (line 4) | function Bj(e,t,n,o,l,u){return b(),F("svg",Ej,Dj)}
function Tj (line 4) | function Tj(e,t,n,o,l,u){return b(),F("svg",Sj,Lj)}
function Rj (line 4) | function Rj(e,t,n,o,l,u){return b(),F("svg",Vj,Hj)}
function jj (line 4) | function jj(e,t,n,o,l,u){return b(),F("svg",Uj,qj)}
function Qj (line 4) | function Qj(e,t,n,o,l,u){return b(),F("svg",Yj,Jj)}
function lK (line 4) | function lK(e,t,n,o,l,u){return b(),F("svg",tK,oK)}
function fK (line 4) | function fK(e,t,n,o,l,u){return b(),F("svg",rK,dK)}
function bK (line 4) | function bK(e,t,n,o,l,u){return b(),F("svg",hK,gK)}
function AK (line 4) | function AK(e,t,n,o,l,u){return b(),F("svg",CK,FK)}
function PK (line 4) | function PK(e,t,n,o,l,u){return b(),F("svg",xK,kK)}
function HK (line 4) | function HK(e,t,n,o,l,u){return b(),F("svg",zK,IK)}
function qK (line 4) | function qK(e,t,n,o,l,u){return b(),F("svg",OK,WK)}
function JK (line 4) | function JK(e,t,n,o,l,u){return b(),F("svg",GK,XK)}
function oG (line 4) | function oG(e,t,n,o,l,u){return b(),F("svg",eG,nG)}
function iG (line 4) | function iG(e,t,n,o,l,u){return b(),F("svg",aG,sG)}
function _G (line 4) | function _G(e,t,n,o,l,u){return b(),F("svg",fG,hG)}
function CG (line 4) | function CG(e,t,n,o,l,u){return b(),F("svg",bG,wG)}
function $G (line 4) | function $G(e,t,n,o,l,u){return b(),F("svg",AG,xG)}
function zG (line 4) | function zG(e,t,n,o,l,u){return b(),F("svg",PG,TG)}
function NG (line 4) | function NG(e,t,n,o,l,u){return b(),F("svg",IG,RG)}
function KG (line 4) | function KG(e,t,n,o,l,u){return b(),F("svg",WG,jG)}
function ZG (line 4) | function ZG(e,t,n,o,l,u){return b(),F("svg",XG,QG)}
function uY (line 4) | function uY(e,t,n,o,l,u){return b(),F("svg",nY,lY)}
function dY (line 4) | function dY(e,t,n,o,l,u){return b(),F("svg",sY,cY)}
function mY (line 4) | function mY(e,t,n,o,l,u){return b(),F("svg",vY,_Y)}
function EY (line 4) | function EY(e,t,n,o,l,u){return b(),F("svg",yY,CY)}
function $Y (line 4) | function $Y(e,t,n,o,l,u){return b(),F("svg",DY,xY)}
function zY (line 4) | function zY(e,t,n,o,l,u){return b(),F("svg",PY,TY)}
function RY (line 4) | function RY(e,t,n,o,l,u){return b(),F("svg",VY,HY)}
function GY (line 4) | function GY(e,t,n,o,l,u){return b(),F("svg",UY,KY)}
function eX (line 4) | function eX(e,t,n,o,l,u){return b(),F("svg",JY,ZY)}
function aX (line 4) | function aX(e,t,n,o,l,u){return b(),F("svg",oX,uX)}
function dX (line 4) | function dX(e,t,n,o,l,u){return b(),F("svg",sX,cX)}
function bX (line 4) | function bX(e,t,n,o,l,u){return b(),F("svg",vX,gX)}
function AX (line 4) | function AX(e,t,n,o,l,u){return b(),F("svg",CX,FX)}
function kX (line 4) | function kX(e,t,n,o,l,u){return b(),F("svg",xX,SX)}
function VX (line 4) | function VX(e,t,n,o,l,u){return b(),F("svg",TX,MX)}
function OX (line 4) | function OX(e,t,n,o,l,u){return b(),F("svg",HX,NX)}
function Vo (line 4) | function Vo(e,t=void 0){const n=pt()?Xe(Yf,Ar):Ar;return e?U(()=>{var o,...
function pJ (line 4) | function pJ(){let e;const t=(o,l)=>{n(),e=window.setTimeout(o,l)},n=()=>...
method mounted (line 4) | mounted(t){e(t)}
method updated (line 4) | updated(t){e(t)}
method unmounted (line 4) | unmounted(){e(null)}
function CJ (line 4) | function CJ(e){const t=L();function n(){if(e.value==null)return;const{se...
method setup (line 4) | setup(e,{expose:t,emit:n}){const o=e,l=Ve("affix"),u=Kn(),a=Kn(),r=Kn(),...
method setup (line 4) | setup(e){const t=e,n=Ve("icon"),o=U(()=>{const{size:l,color:u}=t;return!...
function TJ (line 12) | function TJ(e){const t=window.getComputedStyle(e),n=t.getPropertyValue("...
function k0 (line 12) | function k0(e,t=1,n){var o;Nn||(Nn=document.createElement("textarea"),do...
method setup (line 12) | setup(e,{expose:t,emit:n}){const o=e,l={suffix:"append",prefix:"prepend"...
method setup (line 12) | setup(e){const t=e,n=Xe(Zf),o=Ve("scrollbar");n||An(jJ,"can not inject s...
method setup (line 12) | setup(e,{expose:t}){const n=e,o=L(0),l=L(0);return t({handleScroll:a=>{i...
method setup (line 12) | setup(e,{expose:t,emit:n}){const o=e,l=Ve("scrollbar");let u,a;const r=L...
method setup (line 12) | setup(e,{expose:t}){const n=e,o=L(),l=L(),u=L(),a=L(),r=U(()=>n.role),s=...
method setup (line 12) | setup(e,{expose:t}){const n=e,o=Ve("popper"),{arrowOffset:l,arrowRef:u}=...
method setup (line 12) | setup(e,{slots:t,attrs:n}){var o;const l=Xe(r4),u=wJ((o=l==null?void 0:l...
function d4 (line 12) | function d4(e){if(!e)return null;const t=e;for(const n of t){if(dt(n))sw...
function L0 (line 12) | function L0(e){const t=Ve("only-child");return c("span",{class:t.e("cont...
method setup (line 12) | setup(e,{expose:t}){const n=e,{role:o,triggerRef:l}=Xe(yc,void 0);yJ(l);...
function vo (line 12) | function vo(e){return e?(e.nodeName||"").toLowerCase():null}
function Zn (line 12) | function Zn(e){if(e==null)return window;if(e.toString()!=="[object Windo...
function su (line 12) | function su(e){var t=Zn(e).Element;return e instanceof t||e instanceof E...
function Pn (line 12) | function Pn(e){var t=Zn(e).HTMLElement;return e instanceof t||e instance...
function Fc (line 12) | function Fc(e){if(typeof ShadowRoot=="undefined")return!1;var t=Zn(e).Sh...
function BQ (line 12) | function BQ(e){var t=e.state;Object.keys(t.elements).forEach(function(n)...
function xQ (line 12) | function xQ(e){var t=e.state,n={popper:{position:t.options.strategy,left...
function co (line 12) | function co(e){return e.split("-")[0]}
function cu (line 12) | function cu(e,t){t===void 0&&(t=!1);var n=e.getBoundingClientRect(),o=1,...
function Ac (line 12) | function Ac(e){var t=cu(e),n=e.offsetWidth,o=e.offsetHeight;return Math....
function h4 (line 12) | function h4(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))r...
function ko (line 12) | function ko(e){return Zn(e).getComputedStyle(e)}
function $Q (line 12) | function $Q(e){return["table","td","th"].indexOf(vo(e))>=0}
function al (line 12) | function al(e){return((su(e)?e.ownerDocument:e.document)||window.documen...
function es (line 12) | function es(e){return vo(e)==="html"?e:e.assignedSlot||e.parentNode||(Fc...
function z0 (line 12) | function z0(e){return!Pn(e)||ko(e).position==="fixed"?null:e.offsetParent}
function SQ (line 12) | function SQ(e){var t=navigator.userAgent.toLowerCase().indexOf("firefox"...
function ga (line 12) | function ga(e){for(var t=Zn(e),n=z0(e);n&&$Q(n)&&ko(n).position==="stati...
function Dc (line 12) | function Dc(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}
function Ou (line 12) | function Ou(e,t,n){return Bl(e,Dr(t,n))}
function kQ (line 12) | function kQ(e,t,n){var o=Ou(e,t,n);return o>n?n:o}
function _4 (line 12) | function _4(){return{top:0,right:0,bottom:0,left:0}}
function m4 (line 12) | function m4(e){return Object.assign({},_4(),e)}
function g4 (line 12) | function g4(e,t){return t.reduce(function(n,o){return n[o]=e,n},{})}
function LQ (line 12) | function LQ(e){var t,n=e.state,o=e.name,l=e.options,u=n.elements.arrow,a...
function TQ (line 12) | function TQ(e){var t=e.state,n=e.options,o=n.element,l=o===void 0?"[data...
function du (line 12) | function du(e){return e.split("-")[1]}
function VQ (line 12) | function VQ(e){var t=e.x,n=e.y,o=window,l=o.devicePixelRatio||1;return{x...
function M0 (line 12) | function M0(e){var t,n=e.popper,o=e.popperRect,l=e.placement,u=e.variati...
function IQ (line 12) | function IQ(e){var t=e.state,n=e.options,o=n.gpuAcceleration,l=o===void ...
function HQ (line 12) | function HQ(e){var t=e.state,n=e.instance,o=e.options,l=o.scroll,u=l===v...
function tr (line 12) | function tr(e){return e.replace(/left|right|bottom|top/g,function(t){ret...
function V0 (line 12) | function V0(e){return e.replace(/start|end/g,function(t){return NQ[t]})}
function Bc (line 12) | function Bc(e){var t=Zn(e),n=t.pageXOffset,o=t.pageYOffset;return{scroll...
function xc (line 12) | function xc(e){return cu(al(e)).left+Bc(e).scrollLeft}
function OQ (line 12) | function OQ(e){var t=Zn(e),n=al(e),o=t.visualViewport,l=n.clientWidth,u=...
function UQ (line 12) | function UQ(e){var t,n=al(e),o=Bc(e),l=(t=e.ownerDocument)==null?void 0:...
function $c (line 12) | function $c(e){var t=ko(e),n=t.overflow,o=t.overflowX,l=t.overflowY;retu...
function w4 (line 12) | function w4(e){return["html","body","#document"].indexOf(vo(e))>=0?e.own...
function Uu (line 12) | function Uu(e,t){var n;t===void 0&&(t=[]);var o=w4(e),l=o===((n=e.ownerD...
function ni (line 12) | function ni(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.w...
function WQ (line 12) | function WQ(e){var t=cu(e);return t.top=t.top+e.clientTop,t.left=t.left+...
function I0 (line 12) | function I0(e,t){return t===p4?ni(OQ(e)):su(t)?WQ(t):ni(UQ(al(e)))}
function qQ (line 12) | function qQ(e){var t=Uu(es(e)),n=["absolute","fixed"].indexOf(ko(e).posi...
function jQ (line 12) | function jQ(e,t,n){var o=t==="clippingParents"?qQ(e):[].concat(t),l=[].c...
function C4 (line 12) | function C4(e){var t=e.reference,n=e.element,o=e.placement,l=o?co(o):nul...
function ra (line 12) | function ra(e,t){t===void 0&&(t={});var n=t,o=n.placement,l=o===void 0?e...
function KQ (line 12) | function KQ(e,t){t===void 0&&(t={});var n=t,o=n.placement,l=n.boundary,u...
function GQ (line 12) | function GQ(e){if(co(e)===Ec)return[];var t=tr(e);return[V0(e),t,V0(t)]}
function YQ (line 12) | function YQ(e){var t=e.state,n=e.options,o=e.name;if(!t.modifiersData[o]...
function H0 (line 12) | function H0(e,t,n){return n===void 0&&(n={x:0,y:0}),{top:e.top-t.height-...
function R0 (line 12) | function R0(e){return[rn,Vn,Mn,sn].some(function(t){return e[t]>=0})}
function JQ (line 12) | function JQ(e){var t=e.state,n=e.name,o=t.rects.reference,l=t.rects.popp...
function ZQ (line 12) | function ZQ(e,t,n){var o=co(e),l=[sn,rn].indexOf(o)>=0?-1:1,u=typeof n==...
function eZ (line 12) | function eZ(e){var t=e.state,n=e.options,o=e.name,l=n.offset,u=l===void ...
function nZ (line 12) | function nZ(e){var t=e.state,n=e.name;t.modifiersData[n]=C4({reference:t...
function oZ (line 12) | function oZ(e){return e==="x"?"y":"x"}
function lZ (line 12) | function lZ(e){var t=e.state,n=e.options,o=e.name,l=n.mainAxis,u=l===voi...
function aZ (line 12) | function aZ(e){return{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}}
function rZ (line 12) | function rZ(e){return e===Zn(e)||!Pn(e)?Bc(e):aZ(e)}
function sZ (line 12) | function sZ(e){var t=e.getBoundingClientRect(),n=iu(t.width)/e.offsetWid...
function iZ (line 12) | function iZ(e,t,n){n===void 0&&(n=!1);var o=Pn(t),l=Pn(t)&&sZ(t),u=al(t)...
function cZ (line 12) | function cZ(e){var t=new Map,n=new Set,o=[];e.forEach(function(u){t.set(...
function dZ (line 12) | function dZ(e){var t=cZ(e);return DQ.reduce(function(n,o){return n.conca...
function fZ (line 12) | function fZ(e){var t;return function(){return t||(t=new Promise(function...
function pZ (line 12) | function pZ(e){var t=e.reduce(function(n,o){var l=n[o.name];return n[o.n...
function O0 (line 12) | function O0(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]...
function Sc (line 12) | function Sc(e){e===void 0&&(e={});var t=e,n=t.defaultModifiers,o=n===voi...
function K0 (line 12) | function K0(e,t){const n=[...e],o=e.indexOf(t);return o!==-1&&n.splice(o...
method setup (line 12) | setup(e,{emit:t}){const n=L();let o,l;const{focusReason:u}=FZ();vJ(g=>{e...
function DZ (line 12) | function DZ(e,t,n,o,l,u){return ze(e.$slots,"default",{handleKeydown:e.o...
function kZ (line 12) | function kZ(e){const{offset:t,gpuAcceleration:n,fallbackPlacements:o}=e;...
function PZ (line 12) | function PZ(e,{arrowEl:t,arrowOffset:n}){e.modifiers.push({name:"arrow",...
function LZ (line 12) | function LZ(e,t){t&&(e.modifiers=[...e.modifiers,...t!=null?t:[]])}
method setup (line 12) | setup(e,{expose:t,emit:n}){const o=e,{popperInstanceRef:l,contentRef:u,t...
method setup (line 12) | setup(e,{expose:t}){const n=e,o=Ve("tooltip"),{controlled:l,id:u,open:a,...
method setup (line 12) | setup(e,{expose:t}){const n=e,o=L(null),l=L(!1),{controlled:u,id:a,open:...
method setup (line 12) | setup(e,{expose:t,emit:n}){const o=e;mJ();const l=U(()=>(jn(o.openDelay)...
method setup (line 12) | setup(e,{expose:t}){const n=e,o=Ve("badge"),l=U(()=>n.isDot?"":gt(n.valu...
function Wt (line 12) | function Wt(e,t){dee(e)&&(e="100%");var n=fee(e);return e=t===360?e:Math...
function Ia (line 12) | function Ia(e){return Math.min(1,Math.max(0,e))}
function dee (line 12) | function dee(e){return typeof e=="string"&&e.indexOf(".")!==-1&&parseFlo...
function fee (line 12) | function fee(e){return typeof e=="string"&&e.indexOf("%")!==-1}
function $4 (line 12) | function $4(e){return e=parseFloat(e),(isNaN(e)||e<0||e>1)&&(e=1),e}
function Ha (line 12) | function Ha(e){return e<=1?"".concat(Number(e)*100,"%"):e}
function bl (line 12) | function bl(e){return e.length===1?"0"+e:String(e)}
function pee (line 12) | function pee(e,t,n){return{r:Wt(e,255)*255,g:Wt(t,255)*255,b:Wt(n,255)*2...
function J0 (line 12) | function J0(e,t,n){e=Wt(e,255),t=Wt(t,255),n=Wt(n,255);var o=Math.max(e,...
function ws (line 12) | function ws(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+(t-e)*(6*n):n<...
function vee (line 12) | function vee(e,t,n){var o,l,u;if(e=Wt(e,360),t=Wt(t,100),n=Wt(n,100),t==...
function Q0 (line 12) | function Q0(e,t,n){e=Wt(e,255),t=Wt(t,255),n=Wt(n,255);var o=Math.max(e,...
function hee (line 12) | function hee(e,t,n){e=Wt(e,360)*6,t=Wt(t,100),n=Wt(n,100);var o=Math.flo...
function Z0 (line 12) | function Z0(e,t,n,o){var l=[bl(Math.round(e).toString(16)),bl(Math.round...
function _ee (line 12) | function _ee(e,t,n,o,l){var u=[bl(Math.round(e).toString(16)),bl(Math.ro...
function mee (line 12) | function mee(e){return Math.round(parseFloat(e)*255).toString(16)}
function ed (line 12) | function ed(e){return bn(e)/255}
function bn (line 12) | function bn(e){return parseInt(e,16)}
function gee (line 12) | function gee(e){return{r:e>>16,g:(e&65280)>>8,b:e&255}}
function bee (line 12) | function bee(e){var t={r:0,g:0,b:0},n=1,o=null,l=null,u=null,a=!1,r=!1;r...
function Cee (line 12) | function Cee(e){if(e=e.trim().toLowerCase(),e.length===0)return!1;var t=...
function mo (line 12) | function mo(e){return Boolean(Un.CSS_UNIT.exec(String(e)))}
function e (line 12) | function e(t,n){t===void 0&&(t=""),n===void 0&&(n={});var o;if(t instanc...
function Oo (line 12) | function Oo(e,t=20){return e.mix("#141414",t).toString()}
function Eee (line 12) | function Eee(e){const t=ul(),n=Ve("button");return U(()=>{let o={};const...
method setup (line 12) | setup(e,{expose:t,emit:n}){const o=e,l=To();ua({from:"type.text",replace...
method setup (line 12) | setup(e){const t=e;Dt(Kf,Rt({size:Tn(t,"size"),type:Tn(t,"type")}));cons...
function kee (line 12) | function kee(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty....
function nd (line 12) | function nd(e,t){let n=[];return Array.isArray(t.arg)?n=t.arg:nl(t.arg)&...
method beforeMount (line 12) | beforeMount(e,t){qo.has(e)||qo.set(e,[]),qo.get(e).push({documentHandler...
method updated (line 12) | updated(e,t){qo.has(e)||qo.set(e,[]);const n=qo.get(e),o=n.findIndex(u=>...
method unmounted (line 12) | unmounted(e){qo.delete(e)}
method beforeMount (line 12) | beforeMount(e,t){const n=t.value,{interval:o=Pee,delay:l=Lee}=Ge(n)?{}:n...
method beforeMount (line 12) | beforeMount(e){e[ui]=b0(e),yl.push(e),yl.length<=1&&document.addEventLis...
method updated (line 12) | updated(e){at(()=>{e[ui]=b0(e)})}
method unmounted (line 12) | unmounted(){yl.shift(),yl.length===0&&document.removeEventListener("keyd...
function on (line 12) | function on(){if(!ud){ud=!0;var e=navigator.userAgent,t=/(?:MSIE.(\d+\.\...
function Vee (line 12) | function Vee(e,t){if(!V4.canUseDOM||t&&!("addEventListener"in document))...
function H4 (line 12) | function H4(e){var t=0,n=0,o=0,l=0;return"detail"in e&&(n=e.detail),"whe...
method beforeMount (line 25) | beforeMount(e,t){Ree(e,t.value)}
function i (line 25) | function i(g){var y,w;return g===e.trueLabel||g===!0?(y=e.trueLabel)!=nu...
function p (line 25) | function p(g,y){s("change",i(g),y)}
function m (line 25) | function m(g){if(n.value)return;const y=g.target;s("change",i(y.checked)...
function v (line 25) | async function v(g){n.value||!o.value&&!l.value&&u.value&&(g.composedPat...
method get (line 25) | get(){var r,s;return l.value?(r=o==null?void 0:o.modelValue)==null?void ...
method set (line 25) | set(r){var s,i;l.value&&qe(r)?(u.value=((s=o==null?void 0:o.max)==null?v...
function n (line 25) | function n(){qe(t.value)&&!t.value.includes(e.label)?t.value.push(e.labe...
method setup (line 25) | setup(e){const t=e,n=To(),{inputId:o,isLabeledByFormItem:l,isChecked:u,i...
method setup (line 25) | setup(e){const t=e,n=To(),{isFocused:o,isChecked:l,isDisabled:u,checkbox...
method setup (line 25) | setup(e,{emit:t}){const n=e,o=Ve("checkbox"),{formItem:l}=Ho(),{inputId:...
method get (line 25) | get(){return l.value?o.modelValue:e.modelValue}
method set (line 25) | set(p){l.value?o.changeEvent(p):t&&t(bt,p),n.value.checked=e.modelValue=...
method setup (line 25) | setup(e,{emit:t}){const n=e,o=Ve("radio"),{radioRef:l,radioGroup:u,focus...
method setup (line 25) | setup(e){const t=e,n=Ve("radio"),{radioRef:o,focus:l,size:u,disabled:a,m...
method setup (line 25) | setup(e,{emit:t}){const n=e,o=Ve("radio"),l=ol(),u=L(),{formItem:a}=Ho()...
method setup (line 25) | setup(e,{emit:t}){const n=e,o=dn(),l=Ve("tag"),u=U(()=>{const{type:s,hit...
method setup (line 25) | setup(e,{expose:t,emit:n}){const o=e,l=Ve("collapse"),u=L(oa(o.modelValu...
method setup (line 25) | setup(e){const t=Ve("collapse-transition"),n={beforeEnter(o){o.dataset||...
method setup (line 25) | setup(e,{expose:t}){const n=e,o=Xe(Gf),l=Ve("collapse"),u=L(!1),a=L(!1),...
method setup (line 25) | setup(e,{slots:t}){Me(()=>e.message,o=>{Object.assign(vi,o!=null?o:{})},...
method setup (line 25) | setup(e){const t=e,n=To(),o=Ve("container"),l=U(()=>t.direction==="verti...
method setup (line 25) | setup(e){const t=e,n=Ve("aside"),o=U(()=>t.width?n.cssVarBlock({width:t....
method setup (line 25) | setup(e){const t=e,n=Ve("footer"),o=U(()=>t.height?n.cssVarBlock({height...
method setup (line 25) | setup(e){const t=e,n=Ve("header"),o=U(()=>t.height?n.cssVarBlock({height...
method setup (line 25) | setup(e){const t=Ve("main");return(n,o)=>(b(),F("main",{class:K(h(t).b()...
method setup (line 25) | setup(){return{descriptions:Xe(Vc,{})}}
method render (line 25) | render(){var e,t,n,o,l,u;const a=YX(this.cell),{border:r,direction:s}=th...
method setup (line 25) | setup(e){const t=Xe(Vc,{});return(n,o)=>h(t).direction==="vertical"?(b()...
method setup (line 25) | setup(e){const t=e,n=Ve("descriptions"),o=dn(),l=To();Dt(Vc,t);const u=U...
method setup (line 25) | setup(e,{slots:t,emit:n}){const o=Ve("overlay"),l=s=>{n("click",s)},{onC...
method setup (line 25) | setup(e){const t=e,{t:n}=Dn(),{Close:o}=Uf,{dialogRef:l,headerRef:u,body...
function E (line 25) | function E(){o("opened")}
function D (line 25) | function D(){o("closed"),o(bt,!1),e.destroyOnClose&&(p.value=!1)}
function C (line 25) | function C(){o("close")}
function B (line 25) | function B(){_==null||_(),v==null||v(),e.openDelay&&e.openDelay>0?{stop:...
function $ (line 25) | function $(){v==null||v(),_==null||_(),e.closeDelay&&e.closeDelay>0?{sto...
function k (line 25) | function k(){function N(J){J||(i.value=!0,s.value=!1)}e.beforeClose?e.be...
function P (line 25) | function P(){e.closeOnClickModal&&k()}
function T (line 25) | function T(){!_t||(s.value=!0)}
function H (line 25) | function H(){s.value=!1}
function j (line 25) | function j(){o("openAutoFocus")}
function X (line 25) | function X(){o("closeAutoFocus")}
function W (line 25) | function W(){e.closeOnPressEscape&&k()}
method setup (line 25) | setup(e,{expose:t}){const n=e,o=To();ua({scope:"el-dialog",from:"the tit...
method setup (line 25) | setup(e){const t=e,n=Ve("divider"),o=U(()=>n.cssVar({"border-style":t.bo...
function Lne (line 25) | function Lne(){const e=L([]),t=U(()=>{if(!e.value.length)return"0";const...
method setup (line 25) | setup(e,{expose:t,emit:n}){const o=e,l=[],u=dn(),a=Ve("form"),r=U(()=>{c...
function wl (line 25) | function wl(){return wl=Object.assign?Object.assign.bind():function(e){f...
function Ine (line 25) | function Ine(e,t){e.prototype=Object.create(t.prototype),e.prototype.con...
function hi (line 25) | function hi(e){return hi=Object.setPrototypeOf?Object.getPrototypeOf.bin...
function sa (line 25) | function sa(e,t){return sa=Object.setPrototypeOf?Object.setPrototypeOf.b...
function Hne (line 25) | function Hne(){if(typeof Reflect=="undefined"||!Reflect.construct||Refle...
function ar (line 25) | function ar(e,t,n){return Hne()?ar=Reflect.construct.bind():ar=function(...
function Rne (line 25) | function Rne(e){return Function.toString.call(e).indexOf("[native code]"...
function _i (line 25) | function _i(e){var t=typeof Map=="function"?new Map:void 0;return _i=fun...
function mi (line 25) | function mi(e){if(!e||!e.length)return null;var t={};return e.forEach(fu...
function wn (line 25) | function wn(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t...
function Une (line 25) | function Une(e){return e==="string"||e==="url"||e==="hex"||e==="email"||...
function zt (line 25) | function zt(e,t){return!!(e==null||t==="array"&&Array.isArray(e)&&!e.len...
function Wne (line 25) | function Wne(e,t,n){var o=[],l=0,u=e.length;function a(r){o.push.apply(o...
function cd (line 25) | function cd(e,t,n){var o=0,l=e.length;function u(a){if(a&&a.length){n(a)...
function qne (line 25) | function qne(e){var t=[];return Object.keys(e).forEach(function(n){t.pus...
function t (line 25) | function t(n,o){var l;return l=e.call(this,"Async Validation Error")||th...
function jne (line 25) | function jne(e,t,n,o,l){if(t.first){var u=new Promise(function(v,_){var ...
function Kne (line 25) | function Kne(e){return!!(e&&e.message!==void 0)}
function Gne (line 25) | function Gne(e,t){for(var n=e,o=0;o<t.length;o++){if(n==null)return n;n=...
function fd (line 25) | function fd(e,t){return function(n){var o;return e.fullFields?o=Gne(t,e....
function pd (line 25) | function pd(e,t){if(t){for(var n in t)if(t.hasOwnProperty(n)){var o=t[n]...
function gi (line 36) | function gi(){return{default:"Validation error on field %s",required:"%s...
function e (line 36) | function e(n){this.rules=null,this._messages=bi,this.define(n)}
function p (line 36) | function p(y){var w=[],E={};function D(B){if(Array.isArray(B)){var $;w=(...
function C (line 36) | function C(k,P){return wl({},P,{fullField:E.fullField+"."+k,fullFields:E...
function B (line 36) | function B(k){k===void 0&&(k=[]);var P=Array.isArray(k)?k:[k];!s.suppres...
method setup (line 36) | setup(e,{slots:t}){const n=Xe(Fu,void 0),o=Xe(Sl);o||An(hd,"usage: <el-f...
method setup (line 36) | setup(e,{expose:t}){const n=e,o=To(),l=Xe(Fu,void 0),u=Xe(Sl,void 0),a=d...
method setup (line 36) | setup(e,{expose:t,emit:n}){const o=e,{t:l}=Dn(),u=Ve("input-number"),a=L...
method setup (line 36) | setup(e,{emit:t}){const n=e,o=Ve("link");function l(u){n.disabled||t("cl...
class zoe (line 36) | class zoe{constructor(t,n){this.parent=t,this.domNode=n,this.subIndex=0,...
method constructor (line 36) | constructor(t,n){this.parent=t,this.domNode=n,this.subIndex=0,this.sub...
method init (line 36) | init(){this.subMenuItems=this.domNode.querySelectorAll("li"),this.addL...
method gotoSubIndex (line 36) | gotoSubIndex(t){t===this.subMenuItems.length?t=0:t<0&&(t=this.subMenuI...
method addListeners (line 36) | addListeners(){const t=this.parent.domNode;Array.prototype.forEach.cal...
class Moe (line 36) | class Moe{constructor(t,n){this.domNode=t,this.submenu=null,this.submenu...
method constructor (line 36) | constructor(t,n){this.domNode=t,this.submenu=null,this.submenu=null,th...
method init (line 36) | init(t){this.domNode.setAttribute("tabindex","0");const n=this.domNode...
method addListeners (line 36) | addListeners(){this.domNode.addEventListener("keydown",t=>{let n=!1;sw...
class Voe (line 36) | class Voe{constructor(t,n){this.domNode=t,this.init(n)}init(t){const n=t...
method constructor (line 36) | constructor(t,n){this.domNode=t,this.init(n)}
method init (line 36) | init(t){const n=this.domNode.childNodes;Array.from(n).forEach(o=>{o.no...
method setup (line 36) | setup(){const e=Ve("menu");return{listeners:{onBeforeEnter:n=>n.style.op...
function Hoe (line 36) | function Hoe(e,t,n,o,l,u){return b(),ae(tn,kn({mode:"out-in"},e.listener...
function c6 (line 36) | function c6(e,t){const n=U(()=>{let l=e.parent;const u=[t.value];for(;l....
function Noe (line 36) | function Noe(e){return U(()=>{const n=e.backgroundColor;return n?new S4(...
method setup (line 36) | setup(e,{slots:t,expose:n}){const o=pt(),{indexPath:l,parentMenu:u}=c6(o...
method setup (line 36) | setup(e,{emit:t,slots:n,expose:o}){const l=pt(),u=l.appContext.config.gl...
method setup (line 36) | setup(e,{emit:t}){const n=pt(),o=Xe("rootMenu"),l=Ve("menu"),u=Ve("menu-...
function Yoe (line 36) | function Yoe(e,t,n,o,l,u){const a=lt("el-tooltip");return b(),F("li",{cl...
method setup (line 36) | setup(){return{ns:Ve("menu-item-group")}}
function Zoe (line 36) | function Zoe(e,t,n,o,l,u){return b(),F("li",{class:K(e.ns.b())},[f("div"...
method setup (line 36) | setup(e){const t=e,n=U(()=>t.disabled||t.currentPage<=1);return(o,l)=>(b...
method setup (line 36) | setup(e){const t=e,n=U(()=>t.disabled||t.currentPage===t.pageCount||t.pa...
function _le (line 36) | function _le(e,t){const n=Xe(ns),o=Xe(v6,{disabled:!1}),l=U(()=>Object.p...
method setup (line 36) | setup(e){const t=Ve("select"),n=Rt({index:-1,groupDisabled:!1,visible:!0...
function gle (line 36) | function gle(e,t,n,o,l,u){return fe((b(),F("li",{class:K([e.ns.be("dropd...
method setup (line 36) | setup(){const e=Xe(ns),t=Ve("select"),n=U(()=>e.props.popperClass),o=U((...
function yle (line 36) | function yle(e,t,n,o,l,u){return b(),F("div",{class:K([e.ns.b("dropdown"...
function Cle (line 36) | function Cle(e){const{t}=Dn();return Rt({options:new Map,cachedOptions:n...
method get (line 36) | get(){return t.visible&&k.value!==!1}
method set (line 36) | set(M){t.visible=M}
method setup (line 36) | setup(e,t){const n=Ve("select"),o=Ve("input"),{t:l}=Dn(),u=Cle(e),{optio...
function Ble (line 36) | function Ble(e,t,n,o,l,u){const a=lt("el-tag"),r=lt("el-tooltip"),s=lt("...
method setup (line 36) | setup(e){const t=Ve("select"),n=L(!0),o=pt(),l=L([]);Dt(v6,Rt({...ho(e)}...
function Sle (line 36) | function Sle(e,t,n,o,l,u){return fe((b(),F("ul",{class:K(e.ns.be("group"...
method setup (line 36) | setup(e,{emit:t}){const n=e,{t:o}=Dn(),l=Ve("pagination"),u=Nc(),a=L(n.p...
method setup (line 36) | setup(e){const{t}=Dn(),n=Ve("pagination"),{pageCount:o,disabled:l,curren...
method setup (line 36) | setup(e){const{t}=Dn(),n=Ve("pagination"),{disabled:o}=Nc();return(l,u)=...
method setup (line 36) | setup(e,{emit:t}){const n=e,o=Ve("pager"),l=Ve("icon"),u=L(!1),a=L(!1),r...
method setup (line 36) | setup(e,{emit:t,slots:n}){const{t:o}=Dn(),l=Ve("pagination"),u=pt().vnod...
method setup (line 36) | setup(e){const t=e,n={success:"#13ce66",exception:"#ff4949",warning:"#e6...
method setup (line 41) | setup(e,{expose:t,emit:n}){const o=e,l=pt(),{formItem:u}=Ho(),a=dn(),r=V...
function Due (line 47) | function Due(e){var t=""+e,n=Fue.exec(t);if(!n)return t;var o,l="",u=0,a...
function $ue (line 47) | function $ue(e,t){const n={};let o;for(o in e)n[o]=e[o];for(o in t)if(st...
function Oc (line 47) | function Oc(e){return e===""||e!==void 0&&(e=Number.parseInt(e,10),Numbe...
function g6 (line 47) | function g6(e){return e===""||e!==void 0&&(e=Oc(e),Number.isNaN(e)&&(e=8...
function Sue (line 47) | function Sue(e){return typeof e=="number"?e:typeof e=="string"?/^\d+(?:p...
function kue (line 47) | function kue(...e){return e.length===0?t=>t:e.length===1?e[0]:e.reduce((...
function rr (line 47) | function rr(e,t,n){let o=!1;const l=e.indexOf(t),u=l!==-1,a=()=>{e.push(...
function Pue (line 47) | function Pue(e,t,n="children",o="hasChildren"){const l=a=>!(Array.isArra...
function Lue (line 47) | function Lue(e,t,n,o,l){const{nextZIndex:u}=Ml(),a=e==null?void 0:e.data...
function yd (line 47) | function yd(e,t){return e+(t.realWidth===null||Number.isNaN(t.realWidth)...
function Tue (line 47) | function Tue(e){const t=pt(),n=L(!1),o=L([]);return{updateExpandRows:()=...
function zue (line 47) | function zue(e){const t=pt(),n=L(null),o=L(null),l=i=>{t.store.assertRow...
function Mue (line 47) | function Mue(e){const t=L([]),n=L({}),o=L(16),l=L(!1),u=L({}),a=L("hasCh...
function Iue (line 47) | function Iue(){var e;const t=pt(),{size:n}=ho((e=t.proxy)==null?void 0:e...
function wi (line 47) | function wi(e,t){return e.map(n=>{var o;return n.id===t.id?t:((o=n.child...
function y6 (line 47) | function y6(e){e.forEach(t=>{var n,o;t.no=(n=t.getColumnIndex)==null?voi...
function Hue (line 47) | function Hue(){const e=pt(),t=Iue();return{ns:Ve("table"),...t,mutations...
function Rue (line 47) | function Rue(e,t){if(!e)throw new Error("Table is required.");const n=Hu...
function Nue (line 47) | function Nue(e,t){Object.keys(qu).forEach(n=>{Me(()=>C6(t,n),o=>{w6(o,n,...
function w6 (line 47) | function w6(e,t,n){let o=e,l=qu[t];typeof qu[t]=="object"&&(l=l.key,o=o|...
function C6 (line 47) | function C6(e,t){if(t.includes(".")){const n=t.split(".");let o=e;return...
class Oue (line 47) | class Oue{constructor(t){this.observers=[],this.table=null,this.store=nu...
method constructor (line 47) | constructor(t){this.observers=[],this.table=null,this.store=null,this....
method updateScrollY (line 47) | updateScrollY(){if(this.height.value===null)return!1;const n=this.tabl...
method setHeight (line 47) | setHeight(t,n="height"){if(!_t)return;const o=this.table.vnode.el;if(t...
method setMaxHeight (line 47) | setMaxHeight(t){this.setHeight(t,"max-height")}
method getFlattenColumns (line 47) | getFlattenColumns(){const t=[];return this.table.store.states.columns....
method updateElsHeight (line 47) | updateElsHeight(){this.updateScrollY(),this.notifyObservers("scrollabl...
method headerDisplayNone (line 47) | headerDisplayNone(t){if(!t)return!0;let n=t;for(;n.tagName!=="DIV";){i...
method updateColumnsWidth (line 47) | updateColumnsWidth(){if(!_t)return;const t=this.fit,n=this.table.vnode...
method addObserver (line 47) | addObserver(t){this.observers.push(t)}
method removeObserver (line 47) | removeObserver(t){const n=this.observers.indexOf(t);n!==-1&&this.obser...
method notifyObservers (line 47) | notifyObservers(t){this.observers.forEach(o=>{var l,u;switch(t){case"c...
method setup (line 47) | setup(e){const t=pt(),{t:n}=Dn(),o=Ve("table-filter"),l=t==null?void 0:t...
function Gue (line 47) | function Gue(e,t,n,o,l,u){const a=lt("el-checkbox"),r=lt("el-checkbox-gr...
function E6 (line 47) | function E6(e){const t=pt();Hr(()=>{n.value.addObserver(t)}),ot(()=>{o(n...
function Xue (line 47) | function Xue(e,t){const n=pt(),o=Xe(_o),l=y=>{y.stopPropagation()},u=(y,...
function Jue (line 47) | function Jue(e){const t=Xe(_o),n=Ve("table");return{getHeaderRowStyle:r=...
function Zue (line 47) | function Zue(e){const t=Xe(_o),n=U(()=>Que(e.store.states.originColumns....
method setup (line 47) | setup(e,{emit:t}){const n=pt(),o=Xe(_o),l=Ve("table"),u=L({}),{onColumns...
method render (line 47) | render(){const{ns:e,isGroup:t,columnRows:n,getHeaderCellStyle:o,getHeade...
function tae (line 47) | function tae(e){const t=Xe(_o),n=L(""),o=L(Re("div")),l=(v,_,g)=>{var y;...
function nae (line 47) | function nae(e){const t=Xe(_o),n=Ve("table");return{getRowStyle:(i,p)=>{...
function oae (line 47) | function oae(e){const t=Xe(_o),n=Ve("table"),{handleDoubleClick:o,handle...
method setup (line 47) | setup(e){const t=pt(),n=Xe(_o),o=Ve("table"),{wrappedRowRender:l,tooltip...
method render (line 47) | render(){const{wrappedRowRender:e,store:t}=this,n=t.states.data.value||[...
function qc (line 47) | function qc(e){const t=e.tableLayout==="auto";let n=e.columns||[];t&&n.e...
function aae (line 47) | function aae(){const e=Xe(_o),t=e==null?void 0:e.store,n=U(()=>t.states....
function rae (line 47) | function rae(e){const{columns:t}=aae(),n=Ve("table");return{getCellClass...
method setup (line 47) | setup(e){const{getCellClasses:t,getCellStyles:n,columns:o}=rae(e);return...
method render (line 47) | render(){const{columns:e,getCellStyles:t,getCellClasses:n,summaryMethod:...
function iae (line 47) | function iae(e){return{setCurrentRow:p=>{e.commit("setCurrentRow",p)},ge...
function cae (line 47) | function cae(e,t,n,o){const l=L(!1),u=L(null),a=L(!1),r=te=>{a.value=te}...
method setup (line 47) | setup(e){const{t}=Dn(),n=Ve("table"),o=pt();Dt(_o,o);const l=Rue(o,e);o....
function mae (line 47) | function mae(e,t,n,o,l,u){const a=lt("hColgroup"),r=lt("table-header"),s...
method renderHeader (line 47) | renderHeader({store:e}){function t(){return e.states.data.value&&e.state...
method renderCell (line 47) | renderCell({row:e,column:t,store:n,$index:o}){return Re(Po,{disabled:t.s...
method renderHeader (line 47) | renderHeader({column:e}){return e.label||"#"}
method renderCell (line 47) | renderCell({column:e,$index:t}){let n=t+1;const o=e.index;return typeof ...
method renderHeader (line 47) | renderHeader({column:e}){return e.label||""}
method renderCell (line 47) | renderCell({row:e,store:t,expanded:n}){const{ns:o}=t,l=[o.e("expand-icon...
function Eae (line 47) | function Eae({row:e,column:t,$index:n}){var o;const l=t.property,u=l&&Za...
function Fae (line 47) | function Fae({row:e,treeNode:t,store:n},o=!1){const{ns:l}=n;if(!t)return...
function wd (line 47) | function wd(e,t){return e.reduce((n,o)=>(n[o]=o,n),t)}
function Aae (line 47) | function Aae(e,t){const n=pt();return{registerComplexWatchers:()=>{const...
function Dae (line 47) | function Dae(e,t,n){const o=pt(),l=L(""),u=L(!1),a=L(),r=L(),s=Ve("table...
method setup (line 47) | setup(e,{slots:t}){const n=pt(),o=L({}),l=U(()=>{let D=n.parent;for(;D&&...
method render (line 47) | render(){var e,t,n;try{const o=(t=(e=this.$slots).default)==null?void 0:...
class Sae (line 47) | class Sae extends Error{constructor(t,n,o,l){super(t),this.name="UploadA...
method constructor (line 47) | constructor(t,n,o,l){super(t),this.name="UploadAjaxError",this.status=...
function Cd (line 47) | function Cd(e,t,n){let o;return n.response?o=`${n.response.error||n.resp...
function kae (line 47) | function kae(e){const t=e.responseText||e.response;if(!t)return t;try{re...
method setup (line 47) | setup(e,{emit:t}){const{t:n}=Dn(),o=Ve("upload"),l=Ve("icon"),u=Ve("list...
method setup (line 47) | setup(e,{emit:t}){const n=e,o=Xe(e4);o||An(k6,"usage: <el-upload><el-upl...
method setup (line 47) | setup(e,{expose:t}){const n=e,o=Ve("upload"),l=Kn({}),u=Kn(),a=_=>{if(_....
function l (line 47) | function l(v){var _;(_=t.value)==null||_.abort(v)}
function u (line 47) | function u(v=["ready","uploading","success","fail"]){n.value=n.value.fil...
function m (line 47) | function m(){n.value.filter(({status:v})=>v==="ready").forEach(({raw:v})...
method setup (line 47) | setup(e,{expose:t}){const n=e,o=To(),l=ul(),u=Kn(),{abort:a,submit:r,cle...
function are (line 47) | function are(e){let t;const n=Ve("loading"),o=L(!1),l=Rt({...e,originalP...
method mounted (line 47) | mounted(e,t){t.value&&Bd(e,t)}
method updated (line 47) | updated(e,t){const n=e[Ci];t.oldValue!==t.value&&(t.value&&!t.oldValue?B...
method unmounted (line 47) | unmounted(e){var t;(t=e[Ci])==null||t.instance.close()}
method setup (line 47) | setup(e,{expose:t}){const n=e,{Close:o}=Wf,l=Ve("message"),u=L(),a=L(!1)...
function Ere (line 47) | function Ere(e){for(const t of ro)(!e||e===t.props.type)&&t.handler.clos...
method setup (line 47) | setup(e,{emit:t}){const{t:n}=Dn(),o=Ve("message-box"),l=L(!1),{nextZInde...
function $re (line 47) | function $re(e,t,n,o,l,u){const a=lt("el-icon"),r=lt("close"),s=lt("el-i...
function Au (line 47) | function Au(e,t=null){if(!_t)return Promise.reject();let n;return tt(e)|...
function Mre (line 47) | function Mre(e){return(t,n,o,l)=>{let u="";return dt(n)?(o=n,u=""):jn(n)...
method setup (line 47) | setup(e,{expose:t}){const n=e,o=Ve("notification"),{Close:l}=Uf,u=L(!1);...
function Kre (line 47) | function Kre(e,t,n){const o=Br[t],l=o.findIndex(({vm:i})=>{var p;return(...
function Gre (line 47) | function Gre(){for(const e of Object.values(Br))e.forEach(({vm:t})=>{t.c...
function Hl (line 47) | function Hl(e){return e=e.toLowerCase(),function(n){return Gc(n)===e}}
function Yc (line 47) | function Yc(e){return Array.isArray(e)}
function xr (line 47) | function xr(e){return typeof e=="undefined"}
function Jre (line 47) | function Jre(e){return e!==null&&!xr(e)&&e.constructor!==null&&!xr(e.con...
function Qre (line 47) | function Qre(e){var t;return typeof ArrayBuffer!="undefined"&&ArrayBuffe...
function Zre (line 47) | function Zre(e){return typeof e=="string"}
function ese (line 47) | function ese(e){return typeof e=="number"}
function I6 (line 47) | function I6(e){return e!==null&&typeof e=="object"}
function ir (line 47) | function ir(e){if(Gc(e)!=="object")return!1;var t=Object.getPrototypeOf(...
function Xc (line 47) | function Xc(e){return Kc.call(e)==="[object Function]"}
function use (line 47) | function use(e){return I6(e)&&Xc(e.pipe)}
function ase (line 47) | function ase(e){var t="[object FormData]";return e&&(typeof FormData=="f...
function sse (line 47) | function sse(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}
function ise (line 47) | function ise(){return typeof navigator!="undefined"&&(navigator.product=...
function Jc (line 47) | function Jc(e,t){if(!(e===null||typeof e=="undefined"))if(typeof e!="obj...
function Fi (line 47) | function Fi(){var e={};function t(l,u){ir(e[u])&&ir(l)?e[u]=Fi(e[u],l):i...
function cse (line 47) | function cse(e,t,n){return Jc(t,function(l,u){n&&typeof l=="function"?e[...
function dse (line 47) | function dse(e){return e.charCodeAt(0)===65279&&(e=e.slice(1)),e}
function fse (line 47) | function fse(e,t,n,o){e.prototype=Object.create(t.prototype,o),e.prototy...
function pse (line 47) | function pse(e,t,n){var o,l,u,a={};t=t||{};do{for(o=Object.getOwnPropert...
function vse (line 47) | function vse(e,t,n){e=String(e),(n===void 0||n>e.length)&&(n=e.length),n...
function hse (line 47) | function hse(e){if(!e)return null;var t=e.length;if(xr(t))return null;fo...
function xd (line 47) | function xd(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace...
function ls (line 47) | function ls(){this.handlers=[]}
function hu (line 47) | function hu(e,t,n,o,l){Error.call(this),this.message=e,this.name="AxiosE...
function wse (line 47) | function wse(e,t){t=t||new FormData;var n=[];function o(u){return u===nu...
function l (line 48) | function l(u){var a=u;return t&&(n.setAttribute("href",a),a=n.href),n.se...
function j6 (line 48) | function j6(e){Ai.call(this,e==null?"canceled":e,Ai.ERR_CANCELED),this.n...
function i (line 48) | functio
Condensed preview — 186 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,108K chars).
[
{
"path": ".gitattributes",
"chars": 24,
"preview": "*.* linguist-language=Go"
},
{
"path": ".gitignore",
"chars": 363,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\nrelayports\nlucky\n# Test binary, built with `go test "
},
{
"path": "Dockerfile",
"chars": 113,
"preview": "FROM scratch\nCOPY lucky /\nEXPOSE 16601\nWORKDIR /goodluck\nENTRYPOINT [\"/lucky\"]\nCMD [\"-c\", \"/goodluck/lucky.conf\"]"
},
{
"path": "LICENSE",
"chars": 1078,
"preview": "MIT License\n\nCopyright (c) 2022 gdy , 272288813@qq.com\n\nPermission is hereby granted, free of charge, to any person obta"
},
{
"path": "README.md",
"chars": 5651,
"preview": "# Lucky(万吉)\n \n 本项目 CDN 加速及安全防护由 Tencent EdgeOne 赞助\n [亚洲最佳CDN、边缘和安全解决方案 - Tencent EdgeOne](https://edgeone.ai/zh?from=git"
},
{
"path": "berforebuild.bat",
"chars": 33,
"preview": "cd ./web/adminviews\nnpm run build"
},
{
"path": "config/appinfo.go",
"chars": 742,
"preview": "package config\n\nimport (\n\t\"runtime\"\n\t\"time\"\n)\n\ntype AppInfo struct {\n\tAppName string\n\tVersion string\n\tOS stri"
},
{
"path": "config/blacklist.go",
"chars": 3971,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage config\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype BlackListItem "
},
{
"path": "config/config.go",
"chars": 10862,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"runtime\"\n\t\"stri"
},
{
"path": "config/ddns.go",
"chars": 10584,
"preview": "package config\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/stringsp\"\n)\n\ntype DDNSConfigure struct"
},
{
"path": "config/portforward.go",
"chars": 11029,
"preview": "package config\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/socketproxy\"\n\t\"github.com/gdy666"
},
{
"path": "config/reverseproxy.go",
"chars": 18250,
"preview": "package config\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"str"
},
{
"path": "config/safecheck.go",
"chars": 1370,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage config\n\nimport (\n\t\"time\"\n)\n\nfunc SafeCheck(mode, ip string) bool {\n\tswit"
},
{
"path": "config/sslcertficate.go",
"chars": 6793,
"preview": "package config\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/"
},
{
"path": "config/whitelist.go",
"chars": 5187,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage config\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype WhiteListConfi"
},
{
"path": "config/wol.go",
"chars": 3173,
"preview": "package config\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/netinterfaces\"\n\t\"github.com/gdy666/lucky/thir"
},
{
"path": "ddns/alidns.go",
"chars": 4206,
"preview": "package ddns\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/gdy666/lucky/ddnscore.go\"\n\t\"github.co"
},
{
"path": "ddns/baidu.go",
"chars": 4940,
"preview": "package ddns\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/ddnscore.go\"\n\t"
},
{
"path": "ddns/callback.go",
"chars": 3401,
"preview": "package ddns\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/luck"
},
{
"path": "ddns/cloudflare.go",
"chars": 4986,
"preview": "package ddns\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/ddnscor"
},
{
"path": "ddns/dns.go",
"chars": 189,
"preview": "package ddns\n\nimport \"github.com/gdy666/lucky/ddnscore.go\"\n\n// DNS interface\ntype DNS interface {\n\tInit(task *ddnscore.D"
},
{
"path": "ddns/dnscommon.go",
"chars": 7227,
"preview": "package ddns\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy6"
},
{
"path": "ddns/dnspod.go",
"chars": 4802,
"preview": "package ddns\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/gdy666/lucky/ddnscore.go\"\n\t\"github.com/gdy666/lucky/thirdlib/gdyl"
},
{
"path": "ddns/godaddy.go",
"chars": 2150,
"preview": "package ddns\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/ddnscore.go\"\n\t"
},
{
"path": "ddns/huawei.go",
"chars": 5118,
"preview": "package ddns\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/ddnscor"
},
{
"path": "ddns/porkbun.go",
"chars": 4346,
"preview": "package ddns\n\nimport (\n\t\"bytes\"\n\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/gdy666/lucky/ddnscore.go\"\n\t\"gi"
},
{
"path": "ddns/worker.go",
"chars": 2826,
"preview": "package ddns\n\nimport (\n\t\"log\"\n\t\"runtime/debug\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/lu"
},
{
"path": "ddnscore.go/cache.go",
"chars": 3872,
"preview": "package ddnscore\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n)\n\nvar ta"
},
{
"path": "ddnscore.go/domain.go",
"chars": 1861,
"preview": "package ddnscore\n\nimport (\n\t\"net/url\"\n\t\"time\"\n)\n\nconst (\n\t// UpdatedNothing 未改变\n\tUpdatedNothing string = \"域名IP和公网IP一致\"\n\t"
},
{
"path": "ddnscore.go/taskinfo.go",
"chars": 4594,
"preview": "package ddnscore\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github"
},
{
"path": "ddnscore.go/taskstate.go",
"chars": 4053,
"preview": "package ddnscore\n\nimport (\n\t\"log\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n)\n\n// 固定的主域名\nvar staticMainDomains = []string{\"com.cn\", "
},
{
"path": "ddnscore.go/webhook.go",
"chars": 7944,
"preview": "package ddnscore\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/"
},
{
"path": "debug.go",
"chars": 326,
"preview": "//go:build debug\n// +build debug\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/recoverutil\"\n"
},
{
"path": "go.mod",
"chars": 2009,
"preview": "module github.com/gdy666/lucky\n\ngo 1.18\n\nrequire (\n\tgithub.com/buger/jsonparser v1.1.1\n\tgithub.com/eclipse/paho.mqtt.gol"
},
{
"path": "go.sum",
"chars": 17049,
"preview": "github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=\ngithub.com/buger/jsonparser v1.1.1/go"
},
{
"path": "main.go",
"chars": 2992,
"preview": "//Copyright 2022 gdy, 272288813@qq.com\n\npackage main\n\nimport (\n\t\"flag\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"g"
},
{
"path": "module/ddns/conf/ddns.go",
"chars": 9260,
"preview": "package ddnsconf\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/thirdlib/"
},
{
"path": "module/ddns/ddnscore.go/cache.go",
"chars": 4345,
"preview": "package ddnscore\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\tddnsconf \"github.com/gdy666/lucky/module/ddns/conf\"\n\t"
},
{
"path": "module/ddns/ddnscore.go/domain.go",
"chars": 3547,
"preview": "package ddnscore\n\nimport (\n\t\"log\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\t// UpdatedNothing 未改变\n\tUpdatedNothing string"
},
{
"path": "module/ddns/ddnscore.go/taskinfo.go",
"chars": 1103,
"preview": "package ddnscore\n\nimport (\n\tddnsconf \"github.com/gdy666/lucky/module/ddns/conf\"\n)\n\ntype DDNSTaskInfo struct {\n\tddnsconf."
},
{
"path": "module/ddns/ddnscore.go/taskstate.go",
"chars": 2514,
"preview": "package ddnscore\n\nimport (\n\t\"time\"\n)\n\n// 固定的主域名\nvar staticMainDomains = []string{\"com.cn\", \"org.cn\", \"net.cn\", \"ac.cn\", "
},
{
"path": "module/ddns/ddnscore.go/webhook.go",
"chars": 7779,
"preview": "package ddnscore\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/module/ddns/ddnsgo\"\n\t\"github"
},
{
"path": "module/ddns/ddnsgo/ddns.go",
"chars": 5295,
"preview": "package ddnsgo\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\tddnsconf \"github.com/gdy666/lucky/mod"
},
{
"path": "module/ddns/providers/alidns.go",
"chars": 4233,
"preview": "package providers\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/gdy666/lucky/module/ddns/ddnscor"
},
{
"path": "module/ddns/providers/baidu.go",
"chars": 4967,
"preview": "package providers\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/module/dd"
},
{
"path": "module/ddns/providers/callback.go",
"chars": 3440,
"preview": "package providers\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/module/ddns/ddnscore.go\"\n\t\""
},
{
"path": "module/ddns/providers/cloudflare.go",
"chars": 5013,
"preview": "package providers\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/mo"
},
{
"path": "module/ddns/providers/dnspod.go",
"chars": 4828,
"preview": "package providers\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/gdy666/lucky/module/ddns/ddnscore.go\"\n\t\"github.com/gdy666/lu"
},
{
"path": "module/ddns/providers/godaddy.go",
"chars": 2177,
"preview": "package providers\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/module/dd"
},
{
"path": "module/ddns/providers/huawei.go",
"chars": 5145,
"preview": "package providers\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/mo"
},
{
"path": "module/ddns/providers/porkbun.go",
"chars": 4373,
"preview": "package providers\n\nimport (\n\t\"bytes\"\n\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/gdy666/lucky/module/ddns/"
},
{
"path": "module/ddns/providers/provider.go",
"chars": 216,
"preview": "package providers\n\nimport \"github.com/gdy666/lucky/module/ddns/ddnscore.go\"\n\n// Provider interface\ntype Provider interfa"
},
{
"path": "module/ddns/providers/providercommon.go",
"chars": 4526,
"preview": "package providers\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/module/ddns/ddnscore.go\"\n\t\"github.com/"
},
{
"path": "module/ddns/worker.go",
"chars": 3128,
"preview": "package ddns\n\nimport (\n\t\"log\"\n\t\"runtime/debug\"\n\t\"sync\"\n\t\"time\"\n\n\tddnsconf \"github.com/gdy666/lucky/module/ddns/conf\"\n\t\"g"
},
{
"path": "module/portforward/conf/portforward.go",
"chars": 5723,
"preview": "package portforwardconf\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/module/portforward/sock"
},
{
"path": "module/portforward/portforward.go",
"chars": 7066,
"preview": "package portforward\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/config\"\n\tportforwardconf \"github.com/g"
},
{
"path": "module/portforward/socketproxy/baseproxyconf.go",
"chars": 729,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"sync/atomic\"\n)\n\ntype BaseProxyConf struct {\n\tTra"
},
{
"path": "module/portforward/socketproxy/proxy.go",
"chars": 4827,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"githu"
},
{
"path": "module/portforward/socketproxy/socketproxy.go",
"chars": 20,
"preview": "package socketproxy\n"
},
{
"path": "module/portforward/socketproxy/tcpproxy.go",
"chars": 4224,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github."
},
{
"path": "module/portforward/socketproxy/tcpudpcommon.go",
"chars": 4781,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t"
},
{
"path": "module/portforward/socketproxy/udpproxy.go",
"chars": 10007,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time"
},
{
"path": "module/reverseproxy/conf/reverseproxy.go",
"chars": 13248,
"preview": "package reverseproxyconf\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\t\"strc"
},
{
"path": "module/reverseproxy/proxy.go",
"chars": 1860,
"preview": "package reverseproxy\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\treverseproxyconf \"github.com/gdy666/lucky/module/reverseproxy/conf\"\n\t\"git"
},
{
"path": "module/reverseproxy/reverseproxy.go",
"chars": 5624,
"preview": "package reverseproxy\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/config\"\n\treverseproxyconf \"github.com/gdy666"
},
{
"path": "module/safe/blacklist.go",
"chars": 3765,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage safe\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/luc"
},
{
"path": "module/safe/conf/black.go",
"chars": 396,
"preview": "package safeconf\n\nimport \"net\"\n\ntype BlackListItem WhiteListItem\n\ntype BlackListConfigure struct {\n\tBlackList []BlackLis"
},
{
"path": "module/safe/conf/white.go",
"chars": 877,
"preview": "package safeconf\n\nimport \"net\"\n\ntype WhiteListBaseConfigure struct {\n\tURL string `json:\"URL\"`\n\tActivelife"
},
{
"path": "module/safe/safe.go",
"chars": 64,
"preview": "package safe\n\nfunc Init() {\n\tBlackListInit()\n\tWhiteListInit()\n}\n"
},
{
"path": "module/safe/safecheck.go",
"chars": 1403,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage safe\n\nimport (\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n)\n\nfunc SafeCh"
},
{
"path": "module/safe/whitelist.go",
"chars": 4516,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage safe\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/luc"
},
{
"path": "module/service/service.go",
"chars": 2264,
"preview": "package service\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"time\"\n\n\tkservice \"github.com/kardianos/service\"\n)\n\n// var globalService Se"
},
{
"path": "module/sslcertficate/conf/sslconf.go",
"chars": 2621,
"preview": "package sslconf\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype SSLCertficate struct"
},
{
"path": "module/sslcertficate/ssl.go",
"chars": 54,
"preview": "package ssl\n\nfunc Init() {\n\tSSLCertficateListInit()\n}\n"
},
{
"path": "module/sslcertficate/sslcertficate.go",
"chars": 4407,
"preview": "package ssl\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t"
},
{
"path": "module/weblog/weblog.go",
"chars": 408,
"preview": "package weblog\n\nimport (\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/logsbuffer\"\n)\n\ntype LogItem struct {\n\tProxyK"
},
{
"path": "module/wol/client.go",
"chars": 3672,
"preview": "package wol\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\twolconf \"github.com/gdy666/lucky/module/wol/conf\"\n\t"
},
{
"path": "module/wol/conf/device.go",
"chars": 5111,
"preview": "package wolconf\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/bemfa\"\n\t\"github.com/gdy666/lucky/thir"
},
{
"path": "module/wol/conf/service.go",
"chars": 1476,
"preview": "package wolconf\n\nimport (\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\ntype WOLServerConfigure struct {\n\tEnable bool\n\tToken"
},
{
"path": "module/wol/ctl.go",
"chars": 989,
"preview": "package wol\n\nimport (\n\t\"encoding/base64\"\n\n\tjsonMsg \"github.com/gdy666/lucky/thirdlib/fatedier/golib/json\"\n\t\"github.com/g"
},
{
"path": "module/wol/device.go",
"chars": 8648,
"preview": "package wol\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\"\n\twolconf \"github.com/gdy66"
},
{
"path": "module/wol/httpapi/api.go",
"chars": 6890,
"preview": "package wolhttpapi\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/module/service\"\n\t\"github.co"
},
{
"path": "module/wol/module.go",
"chars": 550,
"preview": "package wol\n\nimport (\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/sirupsen/logrus\"\n)\n\nfunc Init(log *logrus.Logger) {"
},
{
"path": "module/wol/msg.go",
"chars": 858,
"preview": "package wol\n\nimport (\n\twolconf \"github.com/gdy666/lucky/module/wol/conf\"\n)\n\nconst (\n\tTypeLogin = '0'\n\tType"
},
{
"path": "module/wol/service.go",
"chars": 4974,
"preview": "package wol\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\twolconf \"github.com/gdy666/lucky/module/wol/conf\"\n\twebsocketcontroller \"g"
},
{
"path": "module/wol/websocketcommon.go",
"chars": 573,
"preview": "package wol\n\nimport (\n\t\"fmt\"\n\n\twebsocketcontroller \"github.com/gdy666/lucky/thirdlib/gdylib/websocketController\"\n)\n\nfunc"
},
{
"path": "reverseproxy/proxy.go",
"chars": 1816,
"preview": "package reverseproxy\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/gdy666/lucky/config\"\n)\n\nfunc InitReverseProxyServer() {\n\trule"
},
{
"path": "scripts/lucky.service",
"chars": 233,
"preview": "[Unit]\nDescription=lucky\nAfter=network.target\n\n[Service]\nType=simple\nUser=root\nExecStart=/etc/lucky/lucky -c /etc/lucky/"
},
{
"path": "scripts/luckyservice",
"chars": 438,
"preview": "#!/bin/sh /etc/rc.common\n# Copyright (C) 2006-2011 OpenWrt.org\n\nSTART=99\nSERVICE_USE_PID=1\nSERVICE_WRITE_PID=1\nSERVICE_D"
},
{
"path": "scripts/misnap_init.sh",
"chars": 597,
"preview": "#!/bin/sh\n# Copyright (C) gdy\n\nluckydir=/data/lucky.daji\nprofile=/etc/profile\n\nsed -i '/alias lucky=*/'d $profile\nsed -i"
},
{
"path": "socketproxy/baseproxyconf.go",
"chars": 729,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"sync/atomic\"\n)\n\ntype BaseProxyConf struct {\n\tTra"
},
{
"path": "socketproxy/proxy.go",
"chars": 4827,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"githu"
},
{
"path": "socketproxy/tcpproxy.go",
"chars": 4224,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github."
},
{
"path": "socketproxy/tcpudpcommon.go",
"chars": 4781,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t"
},
{
"path": "socketproxy/udpproxy.go",
"chars": 10007,
"preview": "// Copyright 2022 gdy, 272288813@qq.com\npackage socketproxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time"
},
{
"path": "thirdlib/fatedier/golib/json/msg.go",
"chars": 1336,
"preview": "// Copyright 2018 fatedier, fatedier@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// "
},
{
"path": "thirdlib/fatedier/golib/json/pack.go",
"chars": 1681,
"preview": "// Copyright 2018 fatedier, fatedier@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// "
},
{
"path": "thirdlib/fatedier/golib/json/process.go",
"chars": 2119,
"preview": "// Copyright 2018 fatedier, fatedier@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// "
},
{
"path": "thirdlib/gdylib/bemfa/device.go",
"chars": 4508,
"preview": "package bemfa\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\tMQTT \"github.com/eclipse/paho.mqtt."
},
{
"path": "thirdlib/gdylib/bemfa/global.go",
"chars": 1532,
"preview": "package bemfa\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar bemfaStore sync.Map\nvar bemfaStroeMu sync.Mutex\n\nfunc GetBemfaDevi"
},
{
"path": "thirdlib/gdylib/blinker/VoiceAssistant.go",
"chars": 2247,
"preview": "package blinker\n\nimport \"fmt\"\n\nconst (\n\tVA_TYPE_LIGHT = \"light\"\n\tVA_TYPE_OUTLET = \"outlet\"\n\tVA_TYPE_MULTI_O"
},
{
"path": "thirdlib/gdylib/blinker/device.go",
"chars": 11527,
"preview": "package blinker\n\nimport (\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\""
},
{
"path": "thirdlib/gdylib/blinker/global.go",
"chars": 2349,
"preview": "package blinker\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar blinkerDeviceStore sync.Map\nvar blinkerdeviceStroeMu sync.Mutex\n"
},
{
"path": "thirdlib/gdylib/dnsutils/resolve.go",
"chars": 3528,
"preview": "package dnsutils\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/stringsp\"\n\t\"github.com/miekg/dns"
},
{
"path": "thirdlib/gdylib/fileutils/fileutils.go",
"chars": 1163,
"preview": "package fileutils\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n//获取当前路径\nfunc GetCur"
},
{
"path": "thirdlib/gdylib/fileutils/run_linux.go",
"chars": 486,
"preview": "package fileutils\n\nimport (\n\t\"os/exec\"\n)\n\n//OpenProgramOrFile 启动程序\nfunc OpenProgramOrFile(argv []string) error {\n\n\tvar s"
},
{
"path": "thirdlib/gdylib/fileutils/run_windows.go",
"chars": 329,
"preview": "package fileutils\n\nimport \"os/exec\"\n\n//OpenProgramOrFile 启动程序\nfunc OpenProgramOrFile(argv []string) error {\n\n\tvar startA"
},
{
"path": "thirdlib/gdylib/ginutils/basicAuth.go",
"chars": 1279,
"preview": "package ginutils\n\nimport (\n\t\"crypto/subtle\"\n\t\"encoding/base64\"\n\t\"unsafe\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\ntype BasicAuthP"
},
{
"path": "thirdlib/gdylib/ginutils/jwt.go",
"chars": 1537,
"preview": "package ginutils\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt\"\n)\n\nfunc GetJWTToken(tokenString, token"
},
{
"path": "thirdlib/gdylib/ginutils/staticFilesHandler.go",
"chars": 692,
"preview": "package ginutils\n\nimport (\n\t\"io/fs\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc HandlerStaticFiles(files"
},
{
"path": "thirdlib/gdylib/ginutils/utils.go",
"chars": 1155,
"preview": "package ginutils\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\n// Cors 处理跨域请求,支持options访问\nfunc Cors(p"
},
{
"path": "thirdlib/gdylib/httputils/common.go",
"chars": 7485,
"preview": "package httputils\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"net/"
},
{
"path": "thirdlib/gdylib/httputils/goututils.go",
"chars": 3229,
"preview": "package httputils\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/guonaihong/gout\"\n\t\"github.com/guona"
},
{
"path": "thirdlib/gdylib/httputils/httpclient.go",
"chars": 477,
"preview": "package httputils\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc CreateHttpClient(transportNetwork, localAddr string, secureSkipV"
},
{
"path": "thirdlib/gdylib/logsbuffer/logsbuffer.go",
"chars": 4169,
"preview": "package logsbuffer\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\ntype LogsBuffer struct "
},
{
"path": "thirdlib/gdylib/netinterfaces/netInterface.go",
"chars": 4173,
"preview": "package netinterfaces\n\nimport (\n\t\"log\"\n\t\"net\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// NetInterface 本机网络\ntype NetInterface "
},
{
"path": "thirdlib/gdylib/pool/buf.go",
"chars": 999,
"preview": "package pool\n\nimport (\n\t\"sync\"\n)\n\nvar (\n\tbufPool sync.Pool\n\tbufPool1k sync.Pool\n\tbufPool2k sync.Pool\n\tbufPool4k sy"
},
{
"path": "thirdlib/gdylib/recoverutil/recoverutil.go",
"chars": 4043,
"preview": "package recoverutil\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdyli"
},
{
"path": "thirdlib/gdylib/service/service.go",
"chars": 6284,
"preview": "package service\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"runtime/debug\"\n\t\"sync\"\n\t\"time\"\n)\n\nconst (\n\t//StateStop 未启动\n\tStateSt"
},
{
"path": "thirdlib/gdylib/slice/options.go",
"chars": 169,
"preview": "package slice\n\nfunc DeleteAnyListlice(a []any, deleteIndex int) []any {\n\tj := 0\n\tfor i := range a {\n\t\tif i != deleteInde"
},
{
"path": "thirdlib/gdylib/stderrredirect/stderrredirect_linux.go",
"chars": 909,
"preview": "package stderrredirect\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/f"
},
{
"path": "thirdlib/gdylib/stderrredirect/stderrredirect_windows.go",
"chars": 1219,
"preview": "package stderrredirect\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\n\t\"github.com/gdy666/lucky/thirdlib/gdylib/f"
},
{
"path": "thirdlib/gdylib/stringsp/binary.go",
"chars": 882,
"preview": "package stringsp\n\nimport \"fmt\"\n\nconst (\n\tKB = uint(1024)\n\tMB = uint64(1024 * 1024)\n\tGB = uint64(1024 * 1024 * 1024)\n\tTB "
},
{
"path": "thirdlib/gdylib/stringsp/randomutils.go",
"chars": 1216,
"preview": "package stringsp\n\nimport (\n\t\"math/rand\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar strModel = \"0123456789abcdefghijklmnopqrstuvwx"
},
{
"path": "thirdlib/gdylib/stringsp/stringsp.go",
"chars": 230,
"preview": "package stringsp\n\nfunc StrIsInList(str string, strList []string) bool {\n\tcheckMap := make(map[string]uint8)\n\tfor i := ra"
},
{
"path": "thirdlib/gdylib/stringsp/url.go",
"chars": 344,
"preview": "package stringsp\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n)\n\nfunc GetHostAndPathFromURL(urlstr string) (string, string, string, s"
},
{
"path": "thirdlib/gdylib/websocketController/controller.go",
"chars": 8984,
"preview": "package websocketcontroller\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"runtime/debug\"\n\t\"sync\"\n\t\"sync/atomic"
},
{
"path": "thirdlib/go-wol/magic_packet.go",
"chars": 1845,
"preview": "package wol\n\n////////////////////////////////////////////////////////////////////////////////\n\nimport (\n\t\"bytes\"\n\t\"encod"
},
{
"path": "thirdlib/go-wol/wol.go",
"chars": 1968,
"preview": "package wol\n\nimport (\n\t\"fmt\"\n\t\"net\"\n)\n\nfunc WakeUpRepeat(macAddr, broadcastIP, bcastInterface string, port, repeat int) "
},
{
"path": "thirdlib/jeessy2/ddns-go/util/aliyun_signer.go",
"chars": 1870,
"preview": "package util\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/md5\"\n\t\"crypto/sha1\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"hash\"\n\t\""
},
{
"path": "thirdlib/jeessy2/ddns-go/util/aliyun_signer_util.go",
"chars": 593,
"preview": "package util\n\nimport (\n\t\"net/url\"\n\t\"strconv\"\n\t\"time\"\n)\n\n// AliyunSigner AliyunSigner\nfunc AliyunSigner(accessKeyID, acce"
},
{
"path": "thirdlib/jeessy2/ddns-go/util/baidu_signer.go",
"chars": 1674,
"preview": "package util\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\n// https"
},
{
"path": "thirdlib/jeessy2/ddns-go/util/escape.go",
"chars": 885,
"preview": "// based on https://github.com/golang/go/blob/master/src/net/url/url.go\n// Copyright 2009 The Go Authors. All rights res"
},
{
"path": "thirdlib/jeessy2/ddns-go/util/huawei_signer.go",
"chars": 5230,
"preview": "// HWS API Gateway Signature\n// based on https://github.com/datastream/aws/blob/master/signv4.go\n// Copyright (c) 2014, "
},
{
"path": "thirdlib/jeessy2/ddns-go/util/net.go",
"chars": 723,
"preview": "package util\n\nimport (\n\t\"net\"\n\t\"strings\"\n)\n\n// IsPrivateNetwork 是否为私有地址\n// https://en.wikipedia.org/wiki/Private_network"
},
{
"path": "web/adminviews/.gitignore",
"chars": 298,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\n.DS_Stor"
},
{
"path": "web/adminviews/.vscode/extensions.json",
"chars": 75,
"preview": "{\n \"recommendations\": [\"Vue.volar\", \"Vue.vscode-typescript-vue-plugin\"]\n}\n"
},
{
"path": "web/adminviews/README.md",
"chars": 640,
"preview": "# lucky-adminviews\n\nThis template should help get you started developing with Vue 3 in Vite.\n\n## Recommended IDE Setup\n\n"
},
{
"path": "web/adminviews/auto-imports.d.ts",
"chars": 69,
"preview": "// Generated by 'unplugin-auto-import'\nexport {}\ndeclare global {\n\n}\n"
},
{
"path": "web/adminviews/components.d.ts",
"chars": 3517,
"preview": "// generated by unplugin-vue-components\n// We suggest you to commit this file into source control\n// Read more: https://"
},
{
"path": "web/adminviews/dist/assets/index.0c84c960.js",
"chars": 886052,
"preview": "var up=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Dpe=up((Cn,En)=>{const ap=function(){const t=document"
},
{
"path": "web/adminviews/dist/assets/index.abda1f8d.css",
"chars": 168394,
"preview": "@charset \"UTF-8\";:root{--el-color-white:#ffffff;--el-color-black:#000000;--el-color-primary-rgb:64,158,255;--el-color-su"
},
{
"path": "web/adminviews/dist/assets/index.e5c8aec2.js",
"chars": 846814,
"preview": "var U6=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Ufe=U6((vn,hn)=>{const W6=function(){const t=document"
},
{
"path": "web/adminviews/dist/assets/index.f23c7bd8.css",
"chars": 169161,
"preview": "@charset \"UTF-8\";:root{--el-color-white:#ffffff;--el-color-black:#000000;--el-color-primary-rgb:64,158,255;--el-color-su"
},
{
"path": "web/adminviews/dist/index.html",
"chars": 508,
"preview": "<!DOCTYPE html>\n<html lang=\"zh-cn\">\n <head>\n <meta charset=\"UTF-8\" />\n \n <link rel=\"icon\" href=\"/favicon.ico\" "
},
{
"path": "web/adminviews/index.html",
"chars": 416,
"preview": "<!DOCTYPE html>\n<html lang=\"zh-cn\">\n <head>\n <meta charset=\"UTF-8\" />\n \n <link rel=\"icon\" href=\"/favicon.ico\" "
},
{
"path": "web/adminviews/package.json",
"chars": 634,
"preview": "{\n \"name\": \"lucky-adminviews\",\n \"version\": \"0.1.0\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \""
},
{
"path": "web/adminviews/src/App.vue",
"chars": 3694,
"preview": "<template>\n\n <div class=\"common-layout\">\n <el-container>\n <el-header class=\"header\" id=\"header\" >\n <!-- "
},
{
"path": "web/adminviews/src/apis/storage.js",
"chars": 1368,
"preview": "\n/**\n * 使用方式\n * * * main.js挂载全局\n * import storage from './utils/storage';\n const app = createApp(App);\n app.confi"
},
{
"path": "web/adminviews/src/apis/utils.js",
"chars": 11719,
"preview": "// 导入axios实例\nimport httpRequest from '@/request/index'\nimport storage from './storage.js'\n\n// 获取锚点\nexport function Get"
},
{
"path": "web/adminviews/src/assets/appbase.css",
"chars": 160,
"preview": "\n\n.PageRadius {\n height: 90vh;\n width: 100%;\n max-width: 1300px;\n border: 1px solid var(--el-border-color);\n"
},
{
"path": "web/adminviews/src/assets/base.css",
"chars": 2037,
"preview": "/* color palette from <https://github.com/vuejs/theme> */\n:root {\n --vt-c-white: #ffffff;\n --vt-c-white-soft: #f8f8f8;"
},
{
"path": "web/adminviews/src/assets/common-layout.scss",
"chars": 663,
"preview": ".common-layout {\n .el-header,\n .el-footer,\n .el-main,\n .el-aside {\n display: flex;\n justify-conten"
},
{
"path": "web/adminviews/src/components/About.vue",
"chars": 2464,
"preview": "<template>\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n \n <div class=\"InfoDivRadi"
},
{
"path": "web/adminviews/src/components/BlackLists.vue",
"chars": 6300,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <el-affix position=\"top"
},
{
"path": "web/adminviews/src/components/DDNS.vue",
"chars": 99822,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n\n\n <el-scrollbar height="
},
{
"path": "web/adminviews/src/components/DDNSSet.vue",
"chars": 4490,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\" v-loading=\"logLoading\" element-lo"
},
{
"path": "web/adminviews/src/components/Log.vue",
"chars": 2093,
"preview": "<template>\n <!-- <div class=\"logterm\">\n {{weblogsContent}}\n </div> -->\n <el-scrollbar max-height=\"95vh\""
},
{
"path": "web/adminviews/src/components/Login.vue",
"chars": 3444,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <div class=\"formradius\""
},
{
"path": "web/adminviews/src/components/PSet.vue",
"chars": 11137,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <el-scrollbar height=\"1"
},
{
"path": "web/adminviews/src/components/Pmenu.vue",
"chars": 7912,
"preview": " <template>\n <el-menu :default-active=\"activeIndex\" class=\"el-menu-demo menu\" mode=\"horizontal\" :ellipsis=\"false\"\n "
},
{
"path": "web/adminviews/src/components/PortForward.vue",
"chars": 36687,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <el-scrollbar height=\"1"
},
{
"path": "web/adminviews/src/components/PortForwardSet.vue",
"chars": 5877,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\" v-loading=\"logLoading\" element-lo"
},
{
"path": "web/adminviews/src/components/ReverseProxy.vue",
"chars": 82580,
"preview": "<template>\n\n <div class=\"ReverseProxyPageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <el-scrollb"
},
{
"path": "web/adminviews/src/components/SSL.vue",
"chars": 13616,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <!-- <el-affix position"
},
{
"path": "web/adminviews/src/components/Status.vue",
"chars": 2203,
"preview": "<template>\n <div id=\"status\" v-loading=\"logLoading\" element-loading-background=\"transparent\">\n <p class=\"statu"
},
{
"path": "web/adminviews/src/components/WhiteListSet.vue",
"chars": 5349,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n <el-scrollbar height=\"10"
},
{
"path": "web/adminviews/src/components/WhiteLists.vue",
"chars": 6496,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <el-af"
},
{
"path": "web/adminviews/src/components/tools/WOL.vue",
"chars": 12913,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n <el-scrollbar height=\"10"
},
{
"path": "web/adminviews/src/components/tools/WOLServiceSet.vue",
"chars": 19109,
"preview": "<template>\n\n <div class=\"PageRadius\" :style=\"{\n borderRadius: 'base',\n }\">\n\n <el-scrollbar height=\"1"
},
{
"path": "web/adminviews/src/main.js",
"chars": 1574,
"preview": "import { createApp,ref } from 'vue'\nimport App from './App.vue'\nimport './assets/common-layout.scss'\nimport './assets/ap"
},
{
"path": "web/adminviews/src/request/index.js",
"chars": 1507,
"preview": "import axios from 'axios'\n\nconsole.log(\"vue run mode \"+process.env.NODE_ENV)\n\nvar baseURL = \"/\" //\nif (process.env.NODE_"
},
{
"path": "web/adminviews/src/utils/ui.ts",
"chars": 708,
"preview": "import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'\n\n\n// ElMessageBox.alert(message, {\n// confi"
},
{
"path": "web/adminviews/src/utils/utils.ts",
"chars": 3059,
"preview": "import useClipboard from 'vue-clipboard3'\nimport { ref } from 'vue'\n\nexport function CopyTotoClipboard(data: string) {\n "
},
{
"path": "web/adminviews/vite.config.js",
"chars": 601,
"preview": "import { fileURLToPath, URL } from 'url'\n\nimport { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimpor"
},
{
"path": "web/blackwhitelist.go",
"chars": 3477,
"preview": "package web\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/lu"
},
{
"path": "web/common.go",
"chars": 790,
"preview": "package web\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc getFileBase64(c *"
},
{
"path": "web/configure.go",
"chars": 2666,
"preview": "package web\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gdy666/lucky/config\""
},
{
"path": "web/ddns.go",
"chars": 7109,
"preview": "package web\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/lucky/ddnscor"
},
{
"path": "web/portforward.go",
"chars": 5125,
"preview": "package web\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/lucky/"
},
{
"path": "web/reverseproxy.go",
"chars": 6495,
"preview": "package web\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gd"
},
{
"path": "web/ssl.go",
"chars": 2282,
"preview": "package web\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc a"
},
{
"path": "web/web.go",
"chars": 14207,
"preview": "package web\n\nimport (\n\t\"crypto/tls\"\n\t\"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"runtime\"\n\t\"strconv\""
},
{
"path": "web/wol.go",
"chars": 2316,
"preview": "package web\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc a"
},
{
"path": "web.go",
"chars": 210,
"preview": "package main\n\nimport (\n\t\"github.com/gdy666/lucky/config\"\n\t\"github.com/gdy666/lucky/web\"\n)\n\nfunc RunAdminWeb(conf *config"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the gdy666/lucky GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 186 files (2.8 MB), approximately 747.0k tokens, and a symbol index with 3714 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.