Full Code of gdy666/lucky for AI

master b4cf9edc9d8f cached
186 files
2.8 MB
747.0k tokens
3714 symbols
1 requests
Download .txt
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)

 ![](https://edgeone.ai/media/34fe3a45-492d-4ea4-ae5d-ea1087ca7b4b.png)
 


 ## 注意:源码公布到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, &params)

	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
Download .txt
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
Download .txt
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.

Copied to clipboard!