Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
655d5facaa | ||
|
|
51f6f9f953 | ||
|
|
ffda71e641 | ||
|
|
2b22846028 | ||
|
|
526487be04 | ||
|
|
8ca93891ff | ||
|
|
32c07bcd60 | ||
|
|
42035022c6 | ||
|
|
2e9a2b4281 | ||
|
|
4ee01fbc6d | ||
|
|
dfa76a0255 | ||
|
|
03604fa900 | ||
|
|
7e1dd60837 | ||
|
|
a52e63cf65 | ||
|
|
71b9af384c | ||
|
|
095733101b | ||
|
|
579a5dc750 | ||
|
|
03a9795ae2 | ||
|
|
1936ef319e | ||
|
|
20b6066c6a | ||
|
|
53813e71b2 | ||
|
|
1ea57c65f5 | ||
|
|
fe6c8e603b | ||
|
|
45275bc2d3 | ||
|
|
e6d0f19c0a |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ['https://blog.lgf.im/donate/']# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
@@ -9,7 +9,7 @@ RUN go mod download && \
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
RUN apk add --no-cache ca-certificates tzdata
|
||||
WORKDIR /proxypool-src
|
||||
COPY ./assets /proxypool-src/assets
|
||||
COPY --from=builder /proxypool /proxypool-src/
|
||||
|
||||
34
README.md
34
README.md
@@ -16,18 +16,14 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
 来都来了,不点个Star再走?
|
||||
|
||||
## 支持
|
||||
|
||||
- 支持ss、ssr、vmess、trojan节点链接与订阅
|
||||
- 任意 Telegram 频道抓取
|
||||
- 机场订阅地址抓取解析
|
||||
- 支持ss、ssr、vmess、trojan多种类型
|
||||
- Telegram频道抓取
|
||||
- 订阅地址抓取解析
|
||||
- 公开互联网页面模糊抓取
|
||||
- 翻墙党论坛新节点信息
|
||||
- 其他节点分享网站
|
||||
- 定时抓取更新
|
||||
- 使用配置文件提供抓取源
|
||||
- 定时抓取自动更新
|
||||
- 通过配置文件设置抓取源
|
||||
- 自动检测节点可用性
|
||||
|
||||
## 安装
|
||||
@@ -36,6 +32,10 @@
|
||||
|
||||
点击按钮进入部署页面,填写基本信息然后运行
|
||||
|
||||
其中 `DOMAIN` 需要填写为你需要绑定的域名,`CONFIG_FILE` 需要填写你的配置文件路径,配置文件模板见 config/config.yaml 文件
|
||||
|
||||
`CF` 开头的选项暂不需要填写,不影响程序运行
|
||||
|
||||
[](https://heroku.com/deploy)
|
||||
|
||||
> 因为爬虫程序需要持续运行,所以至少选择 $7/月 的配置
|
||||
@@ -53,6 +53,8 @@ $ go get -u -v github.com/zu1k/proxypool
|
||||
|
||||
从这里下载预编译好的程序 [release](https://github.com/zu1k/proxypool/releases)
|
||||
|
||||
除了编译好的二进制程序,你还需要下载仓库 `assets` 文件夹,放置在可执行文件同目录
|
||||
|
||||
### 使用docker
|
||||
|
||||
```sh
|
||||
@@ -63,20 +65,18 @@ docker pull docker.pkg.github.com/zu1k/proxypool/proxypool:latest
|
||||
|
||||
### 修改配置文件
|
||||
|
||||
首先修改 source.yaml 中的必要配置信息,其中域名修改为你自己的域名,cf开头的配置信息可以留空
|
||||
首先修改 config.yaml 中的必要配置信息,cf开头的选项不需要填写
|
||||
|
||||
source.yaml 文件中定义了抓取源,需要定期手动维护更新
|
||||
|
||||
### 启动程序
|
||||
|
||||
使用 `-c` 参数指定配置文件路径,支持http链接
|
||||
|
||||
```shell
|
||||
proxypool -c source.yaml
|
||||
proxypool -c config.yaml
|
||||
```
|
||||
|
||||
### 用户使用
|
||||
|
||||
目前公开版本: https://proxy.tgbot.co
|
||||
|
||||
访问页面,按照相关指导进行使用
|
||||
|
||||
## 截图
|
||||
|
||||

|
||||
|
||||
@@ -1,67 +1,71 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/zu1k/proxypool/config"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
_ "github.com/heroku/x/hmetrics/onload"
|
||||
"github.com/zu1k/proxypool/config"
|
||||
"github.com/zu1k/proxypool/internal/cache"
|
||||
"github.com/zu1k/proxypool/pkg/provider"
|
||||
)
|
||||
|
||||
const version = "v0.3.1"
|
||||
|
||||
var router *gin.Engine
|
||||
var domain = "proxy.tgbot.co"
|
||||
|
||||
func setupRouter() {
|
||||
domain = config.SourceConfig.Domain
|
||||
fmt.Println("Domain:", domain)
|
||||
|
||||
router = gin.Default()
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
router = gin.New()
|
||||
router.Use(gin.Recovery())
|
||||
router.LoadHTMLGlob("assets/html/*")
|
||||
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{
|
||||
"domain": domain,
|
||||
"domain": config.Config.Domain,
|
||||
"getters_count": cache.GettersCount,
|
||||
"all_proxies_count": cache.AllProxiesCount,
|
||||
"ss_proxies_count": cache.SSProxiesCount,
|
||||
"ssr_proxies_count": cache.SSRProxiesCount,
|
||||
"vmess_proxies_count": cache.VmessProxiesCount,
|
||||
"trojan_proxies_count": cache.TrojanProxiesCount,
|
||||
"useful_proxies_count": cache.UsefullProxiesCount,
|
||||
"last_crawl_time": cache.LastCrawlTime,
|
||||
"version": version,
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/clash", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "clash.html", gin.H{
|
||||
"domain": domain,
|
||||
"domain": config.Config.Domain,
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/surge", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "surge.html", gin.H{
|
||||
"domain": domain,
|
||||
"domain": config.Config.Domain,
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/clash/config", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "clash-config.yaml", gin.H{
|
||||
"domain": domain,
|
||||
"domain": config.Config.Domain,
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/surge/config", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "surge.conf", gin.H{
|
||||
"domain": domain,
|
||||
"domain": config.Config.Domain,
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/clash/proxies", func(c *gin.Context) {
|
||||
proxyTypes := c.DefaultQuery("type", "")
|
||||
proxyCountry := c.DefaultQuery("c", "")
|
||||
text := ""
|
||||
if proxyTypes == "" {
|
||||
if proxyTypes == "" && proxyCountry == "" {
|
||||
text = cache.GetString("clashproxies")
|
||||
if text == "" {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
@@ -71,11 +75,11 @@ func setupRouter() {
|
||||
}
|
||||
} else if proxyTypes == "all" {
|
||||
proxies := cache.GetProxies("allproxies")
|
||||
clash := provider.Clash{Proxies: proxies, Types: proxyTypes}
|
||||
clash := provider.Clash{Proxies: proxies, Types: proxyTypes, Country: proxyCountry}
|
||||
text = clash.Provide()
|
||||
} else {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
clash := provider.Clash{Proxies: proxies, Types: proxyTypes}
|
||||
clash := provider.Clash{Proxies: proxies, Types: proxyTypes, Country: proxyCountry}
|
||||
text = clash.Provide()
|
||||
}
|
||||
c.String(200, text)
|
||||
|
||||
6
app.json
6
app.json
@@ -4,8 +4,8 @@
|
||||
"website": "https://proxy.tgbot.co/",
|
||||
"repository": "https://github.com/zu1k/proxypool",
|
||||
"success_url": "/",
|
||||
"logo": "https://raw.githubusercontent.com/zu1k/proxypool/master/assets/proxy.jpg",
|
||||
"keywords": ["golang", "ss", "ssr", "vmess", "shadowsocks", "shadowsocksr"],
|
||||
"logo": "https://raw.githubusercontent.com/zu1k/proxypool/heroku/assets/proxy.jpg",
|
||||
"keywords": ["golang", "ss", "ssr", "vmess", "shadowsocks", "shadowsocksr", "trojan"],
|
||||
"env": {
|
||||
"CONFIG_FILE": {
|
||||
"description": "Path to config file, could be a url."
|
||||
@@ -22,4 +22,4 @@
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,19 @@ proxy-groups:
|
||||
- provider
|
||||
url: 'http://www.gstatic.com/generate_204'
|
||||
interval: 300
|
||||
- name: 网址 https://proxy.tgbot.co
|
||||
type: select
|
||||
proxies:
|
||||
- DIRECT
|
||||
- name: 欢迎Star https://github.com/zu1k/proxypool
|
||||
type: select
|
||||
proxies:
|
||||
- DIRECT
|
||||
- name: TG频道 @peekfun
|
||||
type: select
|
||||
proxies:
|
||||
- DIRECT
|
||||
|
||||
|
||||
proxy-providers:
|
||||
provider:
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
<p>Clash proxy-provider(Shadowrocket添加订阅方式可用):<a href="https://{{ .domain }}/clash/proxies">https://{{ .domain }}/clash/proxies</a></p>
|
||||
<br>
|
||||
<p>筛选代理类型(此种方式你只能自己维护配置文件):https://{{ .domain }}/clash/proxies?type=ss,ssr,vmess</p>
|
||||
<p>筛选国家(此种方式你只能自己维护配置文件):https://{{ .domain }}/clash/proxies?type=ss,ssr,vmess&c=HK,TW,US</p>
|
||||
<p>所有节点的Provider(不是都可以用):<a href="https://{{ .domain }}/clash/proxies?type=all">https://{{ .domain }}/clash/proxies?type=all</a></p>
|
||||
<br>
|
||||
<p>抓取程序已开源:<a href="https://github.com/zu1k/proxypool">https://github.com/zu1k/proxypool</a></p>
|
||||
|
||||
@@ -106,30 +106,32 @@
|
||||
<div class='section friendly'>
|
||||
<h1><strong>免费节点</strong></h1>
|
||||
<div class='article'>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess、trojan节点信息,聚合去重后提供节点列表,每15分钟更新</p>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess、trojan节点信息,聚合去重后提供节点列表,每15分钟更新,目前共有{{.getters_count}}个抓取源</p>
|
||||
<p>汇总节点数量:{{ .all_proxies_count }}</p>
|
||||
<p>ss节点数量:{{ .ss_proxies_count }}</p>
|
||||
<p>ssr节点数量:{{ .ssr_proxies_count }}</p>
|
||||
<p>vmess节点数量:{{ .vmess_proxies_count }}</p>
|
||||
<p>trojan节点数量:{{ .trojan_proxies_count }}</p>
|
||||
<p>可用节点数量:{{ .useful_proxies_count }}</p>
|
||||
<p>最后更新时间:{{ .last_crawl_time }}</p>
|
||||
<br>
|
||||
<h5><a href="/clash">Clash</a></h5>
|
||||
<h4><a href="/clash">Clash</a></h4>
|
||||
<p>Clash配置文件:https://{{ .domain }}/clash/config <a
|
||||
href="clash://install-config?url=https://{{ .domain }}/clash/config">一键导入</a></p>
|
||||
<p>Clash proxy-provider(Shadowrocket添加订阅方式可用):<a href="https://{{ .domain }}/clash/proxies">https://{{ .domain }}/clash/proxies</a>
|
||||
</p>
|
||||
<p>所有节点的Provider(不是都可以用):<a href="https://{{ .domain }}/clash/proxies?type=all">https://{{ .domain }}/clash/proxies?type=all</a>
|
||||
</p>
|
||||
<p>筛选代理类型:https://{{ .domain }}/clash/proxies?type=ss,ssr,vmess</p>
|
||||
<p>筛选国家:https://{{ .domain }}/clash/proxies?c=HK,TW,US</p>
|
||||
<br>
|
||||
<h5><a href="/surge">Surge</a></h5>
|
||||
<h4><a href="/surge">Surge</a></h4>
|
||||
<p>Surge配置文件:https://{{ .domain }}/surge/config <a
|
||||
href="surge3:///install-config?url=https://{{ .domain }}/surge/config">一键导入</a></p>
|
||||
<p>Surge proxy list:<a href="https://{{ .domain }}/surge/proxies">https://{{ .domain }}/surge/proxies</a>
|
||||
</p>
|
||||
<br>
|
||||
{{- /* 所有使用本代码提供服务的禁止删除该行*/}}
|
||||
<p>抓取程序已开源:<a href="https://github.com/zu1k/proxypool">https://github.com/zu1k/proxypool</a></p>
|
||||
<p>欢迎关注tg频道:<a href="https://t.me/peekfun">@peekfun</a></p>
|
||||
<p>抓取程序已开源:<a href="https://github.com/zu1k/proxypool">https://github.com/zu1k/proxypool</a> {{ .version }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,67 +1,71 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/zu1k/proxypool/pkg/tool"
|
||||
)
|
||||
|
||||
var (
|
||||
NeedFetch = true
|
||||
Url = "source.yaml"
|
||||
)
|
||||
var configFilePath = "config.yaml"
|
||||
|
||||
type Source struct {
|
||||
Type string `json:"type" yaml:"type"`
|
||||
Options tool.Options `json:"options" yaml:"options"`
|
||||
type ConfigOptions struct {
|
||||
Domain string `json:"domain" yaml:"domain"`
|
||||
CFEmail string `json:"cf_email" yaml:"cf_email"`
|
||||
CFKey string `json:"cf_key" yaml:"cf_key"`
|
||||
SourceFiles []string `json:"source-files" yaml:"source-files"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Domain string `json:"domain" yaml:"domain"`
|
||||
CFEmail string `json:"cf_email" yaml:"cf_email"`
|
||||
CFKey string `json:"cf_key" yaml:"cf_key"`
|
||||
Sources []Source `json:"sources" yaml:"sources"`
|
||||
}
|
||||
// Config 配置
|
||||
var Config ConfigOptions
|
||||
|
||||
var SourceConfig = Config{}
|
||||
// Parse 解析配置文件,支持本地文件系统和网络链接
|
||||
func Parse(path string) error {
|
||||
if path == "" {
|
||||
path = configFilePath
|
||||
} else {
|
||||
configFilePath = path
|
||||
}
|
||||
fileData, err := ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Config = ConfigOptions{}
|
||||
err = yaml.Unmarshal(fileData, &Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func Parse(path string) (*Config, error) {
|
||||
fileData, err := readFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
SourceConfig = Config{}
|
||||
err = yaml.Unmarshal(fileData, &SourceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 部分配置环境变量优先
|
||||
if domain := os.Getenv("DOMAIN"); domain != "" {
|
||||
SourceConfig.Domain = domain
|
||||
Config.Domain = domain
|
||||
}
|
||||
if cfEmail := os.Getenv("CF_API_EMAIL"); cfEmail != "" {
|
||||
SourceConfig.CFEmail = cfEmail
|
||||
Config.CFEmail = cfEmail
|
||||
}
|
||||
if cfKey := os.Getenv("CF_API_KEY"); cfKey != "" {
|
||||
SourceConfig.CFKey = cfKey
|
||||
Config.CFKey = cfKey
|
||||
}
|
||||
return &SourceConfig, nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readFile(path string) ([]byte, error) {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil, err
|
||||
// 从本地文件或者http链接读取配置文件内容
|
||||
func ReadFile(path string) ([]byte, error) {
|
||||
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
|
||||
resp, err := tool.GetHttpClient().Get(path)
|
||||
if err != nil {
|
||||
return nil, errors.New("config file http get fail")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
} else {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadFile(path)
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf("Configuration file %s is empty", path)
|
||||
}
|
||||
|
||||
return data, err
|
||||
}
|
||||
|
||||
6
config/config.yaml
Normal file
6
config/config.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
domain: example.com
|
||||
cf_email: ""
|
||||
cf_key: ""
|
||||
source-files:
|
||||
- ./source.yaml
|
||||
- https://example.com/source.yaml
|
||||
8
config/source.go
Normal file
8
config/source.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
import "github.com/zu1k/proxypool/pkg/tool"
|
||||
|
||||
type Source struct {
|
||||
Type string `json:"type" yaml:"type"`
|
||||
Options tool.Options `json:"options" yaml:"options"`
|
||||
}
|
||||
@@ -1,33 +1,29 @@
|
||||
domain: proxy.tgbot.co
|
||||
cf_email: ""
|
||||
cf_key: ""
|
||||
sources:
|
||||
# 模糊抓取订阅链接
|
||||
- type: webfuzzsub
|
||||
options:
|
||||
url: https://raw.githubusercontent.com/du5/free/master/sub.list
|
||||
# 模糊抓取订阅链接
|
||||
- type: webfuzzsub
|
||||
options:
|
||||
url: https://raw.githubusercontent.com/du5/free/master/sub.list
|
||||
|
||||
# 订阅链接
|
||||
- type: subscribe
|
||||
options:
|
||||
url: https://raw.githubusercontent.com/ssrsub/ssr/master/v2ray
|
||||
# 订阅链接
|
||||
- type: subscribe
|
||||
options:
|
||||
url: https://raw.githubusercontent.com/ssrsub/ssr/master/v2ray
|
||||
|
||||
# 网页模糊抓取
|
||||
- type: webfuzz
|
||||
options:
|
||||
url: https://merlinblog.xyz/wiki/freess.html
|
||||
# 网页模糊抓取
|
||||
- type: webfuzz
|
||||
options:
|
||||
url: https://merlinblog.xyz/wiki/freess.html
|
||||
|
||||
# tg频道抓取
|
||||
- type: tgchannel
|
||||
options:
|
||||
channel: ssrList
|
||||
num: 200
|
||||
# tg频道抓取
|
||||
- type: tgchannel
|
||||
options:
|
||||
channel: ssrList
|
||||
num: 200
|
||||
|
||||
# 翻墙党论坛抓取
|
||||
- type: web-fanqiangdang-rss
|
||||
options:
|
||||
url: https://fanqiangdang.com/forum.php?mod=rss&fid=50&auth=0
|
||||
# 翻墙党论坛抓取
|
||||
- type: web-fanqiangdang-rss
|
||||
options:
|
||||
url: https://fanqiangdang.com/forum.php?mod=rss&fid=50&auth=0
|
||||
|
||||
# 某个网站抓取
|
||||
- type: web-freessrxyz
|
||||
options:
|
||||
# 某个网站抓取
|
||||
- type: web-freessrxyz
|
||||
options:
|
||||
|
||||
4
go.mod
4
go.mod
@@ -17,17 +17,16 @@ require (
|
||||
github.com/gocolly/colly v1.2.0
|
||||
github.com/golang/protobuf v1.4.2 // indirect
|
||||
github.com/heroku/x v0.0.25
|
||||
github.com/ivpusic/grpool v1.0.0
|
||||
github.com/jasonlvhit/gocron v0.0.1
|
||||
github.com/json-iterator/go v1.1.10 // indirect
|
||||
github.com/kennygrant/sanitize v1.2.4 // indirect
|
||||
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/oschwald/geoip2-golang v1.4.0
|
||||
github.com/oschwald/maxminddb-golang v1.7.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible // indirect
|
||||
github.com/temoto/robotstxt v1.1.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc // indirect
|
||||
@@ -36,5 +35,4 @@ require (
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
||||
36
go.sum
36
go.sum
@@ -10,8 +10,6 @@ github.com/Dreamacro/go-shadowsocks2 v0.1.6-0.20200722122336-8e5c7db4f96a/go.mod
|
||||
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
|
||||
@@ -36,12 +34,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
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/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -49,25 +45,19 @@ 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.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
|
||||
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/cors v1.1.1 h1:eHuqxsIw89iXcWnWUN8R72JMibABJTN/4IOYI5WERvw=
|
||||
github.com/go-chi/cors v1.1.1/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I=
|
||||
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
|
||||
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
|
||||
github.com/go-ini/ini v1.33.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-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.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o=
|
||||
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
@@ -117,8 +107,6 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
|
||||
@@ -132,11 +120,12 @@ github.com/heroku/x v0.0.25/go.mod h1:qE/I0jp6rIeTBBosrPYV4ygRX3OMhqmC/A6x8ewodJ
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/ivpusic/grpool v1.0.0 h1:+FCiCo3GhfsvzfXuJWnpJUNb/VaqyYVgG8C+qvh07Rc=
|
||||
github.com/ivpusic/grpool v1.0.0/go.mod h1:WPmiAI5ExAn06vg+0JzyPzXMQutJmpb7TrBtyLJkOHQ=
|
||||
github.com/jasonlvhit/gocron v0.0.1 h1:qTt5qF3b3srDjeOIR4Le1LfeyvoYzJlYpqvG7tJX5YU=
|
||||
github.com/jasonlvhit/gocron v0.0.1/go.mod h1:k9a3TV8VcU73XZxfVHCHWMWF9SOqgoku0/QlY2yvlA4=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/joeshaw/envdecode v0.0.0-20180129163420-d5f34bca07f3/go.mod h1:Q+alOFAXgW5SrcfMPt/G4B2oN+qEcQRJjkn/f4mKL04=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -151,7 +140,6 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -167,15 +155,10 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615 h1:/mD+ABZyXD39BzJI2XyRJlqdZG11gXFo0SSynL+OFeU=
|
||||
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
@@ -187,7 +170,6 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/oschwald/geoip2-golang v1.4.0 h1:5RlrjCgRyIGDz/mBmPfnAF4h8k0IAcRv9PvrpOfz+Ug=
|
||||
github.com/oschwald/geoip2-golang v1.4.0/go.mod h1:8QwxJvRImBH+Zl6Aa6MaIcs5YdlZSTKtzmPGzQqi9ng=
|
||||
github.com/oschwald/maxminddb-golang v1.6.0 h1:KAJSjdHQ8Kv45nFIbtoLGrGWqHFajOIm7skTyz/+Dls=
|
||||
github.com/oschwald/maxminddb-golang v1.6.0/go.mod h1:DUJFucBg2cvqx42YmDa/+xHvb0elJtOm3o4aFQ/nb/w=
|
||||
github.com/oschwald/maxminddb-golang v1.7.0 h1:JmU4Q1WBv5Q+2KZy5xJI+98aUwTIrPPxZUkd5Cwr8Zc=
|
||||
github.com/oschwald/maxminddb-golang v1.7.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
||||
@@ -209,15 +191,9 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
|
||||
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4=
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible h1:Ymv4OD12d6zm+2yONe39VSmp2XooJe8za7ngOLW/o/w=
|
||||
github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
@@ -254,7 +230,6 @@ golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@@ -300,7 +275,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -314,17 +288,14 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -343,7 +314,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
@@ -365,7 +335,6 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -389,7 +358,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/eapache/channels.v1 v1.1.0 h1:5bGAyKKvyCTWjSj7mhefG6Lc68VyN4MH1v8/7OoeeB4=
|
||||
gopkg.in/eapache/channels.v1 v1.1.0/go.mod h1:BHIBujSvu9yMTrTYbTCjDD43gUhtmaOtTWDe7sTv1js=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
||||
@@ -4,6 +4,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/zu1k/proxypool/internal/cache"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/zu1k/proxypool/config"
|
||||
"github.com/zu1k/proxypool/pkg/getter"
|
||||
)
|
||||
@@ -11,25 +15,40 @@ import (
|
||||
var Getters = make([]getter.Getter, 0)
|
||||
|
||||
func InitConfigAndGetters(path string) (err error) {
|
||||
c, err := config.Parse(path)
|
||||
err = config.Parse(path)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
if c == nil {
|
||||
if s := config.Config.SourceFiles; len(s) == 0 {
|
||||
return errors.New("no sources")
|
||||
} else {
|
||||
initGetters(s)
|
||||
}
|
||||
InitGetters(c.Sources)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func InitGetters(sources []config.Source) {
|
||||
func initGetters(sourceFiles []string) {
|
||||
Getters = make([]getter.Getter, 0)
|
||||
for _, source := range sources {
|
||||
g, err := getter.NewGetter(source.Type, source.Options)
|
||||
if err == nil && g != nil {
|
||||
Getters = append(Getters, g)
|
||||
fmt.Println("init getter:", source.Type, source.Options)
|
||||
for _, path := range sourceFiles {
|
||||
data, err := config.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Errorf("Init SourceFile Error: %s\n", err.Error())
|
||||
continue
|
||||
}
|
||||
sourceList := make([]config.Source, 0)
|
||||
err = yaml.Unmarshal(data, &sourceList)
|
||||
if err != nil {
|
||||
fmt.Errorf("Init SourceFile Error: %s\n", err.Error())
|
||||
continue
|
||||
}
|
||||
for _, source := range sourceList {
|
||||
g, err := getter.NewGetter(source.Type, source.Options)
|
||||
if err == nil && g != nil {
|
||||
Getters = append(Getters, g)
|
||||
fmt.Println("init getter:", source.Type, source.Options)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("Getter count:", len(Getters))
|
||||
cache.GettersCount = len(Getters)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/zu1k/proxypool/config"
|
||||
"github.com/zu1k/proxypool/internal/cache"
|
||||
"github.com/zu1k/proxypool/pkg/provider"
|
||||
"github.com/zu1k/proxypool/pkg/proxy"
|
||||
"github.com/zu1k/proxypool/pkg/tool"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var location, _ = time.LoadLocation("PRC")
|
||||
|
||||
func CrawlGo() {
|
||||
if config.NeedFetch {
|
||||
FetchNewConfigFileThenInit()
|
||||
}
|
||||
wg := &sync.WaitGroup{}
|
||||
var pc = make(chan proxy.Proxy)
|
||||
for _, g := range Getters {
|
||||
@@ -38,37 +33,31 @@ func CrawlGo() {
|
||||
proxies = proxies.Deduplication()
|
||||
log.Println("CrawlGo node count:", len(proxies))
|
||||
proxies = provider.Clash{Proxies: proxies}.CleanProxies()
|
||||
proxies.NameAddCounrty().Sort().NameAddIndex()
|
||||
log.Println("CrawlGo cleaned node count:", len(proxies))
|
||||
proxies.NameAddCounrty().Sort().NameAddIndex().NameAddTG()
|
||||
log.Println("Proxy rename DONE!")
|
||||
|
||||
cache.SetProxies("allproxies", proxies)
|
||||
cache.AllProxiesCount = proxies.Len()
|
||||
log.Println("AllProxiesCount:", cache.AllProxiesCount)
|
||||
cache.SSProxiesCount = proxies.TypeLen("ss")
|
||||
log.Println("SSProxiesCount:", cache.SSProxiesCount)
|
||||
cache.SSRProxiesCount = proxies.TypeLen("ssr")
|
||||
log.Println("SSRProxiesCount:", cache.SSRProxiesCount)
|
||||
cache.VmessProxiesCount = proxies.TypeLen("vmess")
|
||||
log.Println("VmessProxiesCount:", cache.VmessProxiesCount)
|
||||
cache.TrojanProxiesCount = proxies.TypeLen("trojan")
|
||||
log.Println("TrojanProxiesCount:", cache.TrojanProxiesCount)
|
||||
cache.LastCrawlTime = time.Now().In(location).Format("2006-01-02 15:04:05")
|
||||
|
||||
// 可用性检测
|
||||
proxies = proxy.CleanBadProxies(proxies)
|
||||
log.Println("CrawlGo clash useable node count:", len(proxies))
|
||||
proxies.NameAddCounrty().Sort().NameAddIndex()
|
||||
log.Println("Now check proxy health...")
|
||||
proxies = proxy.CleanBadProxiesWithGrpool(proxies)
|
||||
log.Println("CrawlGo clash usefull node count:", len(proxies))
|
||||
proxies.NameReIndex()
|
||||
cache.SetProxies("proxies", proxies)
|
||||
cache.UsefullProxiesCount = proxies.Len()
|
||||
|
||||
cache.SetString("clashproxies", provider.Clash{Proxies: proxies}.Provide())
|
||||
cache.SetString("surgeproxies", provider.Surge{Proxies: proxies}.Provide())
|
||||
}
|
||||
|
||||
func FetchNewConfigFileThenInit() {
|
||||
fmt.Println("fetch new config file...")
|
||||
resp, err := tool.GetHttpClient().Get(config.Url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
err = yaml.Unmarshal(body, &config.SourceConfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
InitGetters(config.SourceConfig.Sources)
|
||||
}
|
||||
|
||||
3
internal/cache/cache.go
vendored
3
internal/cache/cache.go
vendored
@@ -1,7 +1,6 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
@@ -13,10 +12,8 @@ var c = cache.New(cache.NoExpiration, 10*time.Minute)
|
||||
func GetProxies(key string) proxy.ProxyList {
|
||||
result, found := c.Get(key)
|
||||
if found {
|
||||
log.Println("found cache for:", key, "length:", len(result.(proxy.ProxyList)))
|
||||
return result.(proxy.ProxyList)
|
||||
}
|
||||
log.Println("cache not found:", key)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
4
internal/cache/vars.go
vendored
4
internal/cache/vars.go
vendored
@@ -1,6 +1,8 @@
|
||||
package cache
|
||||
|
||||
var (
|
||||
GettersCount = 0
|
||||
|
||||
AllProxiesCount = 0
|
||||
SSRProxiesCount = 0
|
||||
SSProxiesCount = 0
|
||||
@@ -8,4 +10,6 @@ var (
|
||||
TrojanProxiesCount = 0
|
||||
|
||||
UsefullProxiesCount = 0
|
||||
|
||||
LastCrawlTime = "程序刚升级完成,正在爬取中..."
|
||||
)
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func test() {
|
||||
api, err := cloudflare.New(config.SourceConfig.CFKey, config.SourceConfig.CFKey)
|
||||
api, err := cloudflare.New(config.Config.CFKey, config.Config.CFKey)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Fetch the zone ID
|
||||
id, err := api.ZoneIDByName(config.SourceConfig.Domain)
|
||||
id, err := api.ZoneIDByName(config.Config.Domain)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ import (
|
||||
)
|
||||
|
||||
func Cron() {
|
||||
_ = gocron.Every(15).Minutes().Do(app.CrawlGo)
|
||||
_ = gocron.Every(15).Minutes().Do(crawlTask)
|
||||
<-gocron.Start()
|
||||
}
|
||||
|
||||
func crawlTask() {
|
||||
_ = app.InitConfigAndGetters("")
|
||||
app.CrawlGo()
|
||||
}
|
||||
|
||||
59
main.go
59
main.go
@@ -3,71 +3,34 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/zu1k/proxypool/config"
|
||||
|
||||
"github.com/zu1k/proxypool/internal/cron"
|
||||
|
||||
_ "github.com/mkevac/debugcharts"
|
||||
"github.com/zu1k/proxypool/api"
|
||||
"github.com/zu1k/proxypool/internal/app"
|
||||
"github.com/zu1k/proxypool/internal/cron"
|
||||
"github.com/zu1k/proxypool/pkg/proxy"
|
||||
)
|
||||
|
||||
var (
|
||||
debugMode = false
|
||||
configFilePath = ""
|
||||
)
|
||||
var configFilePath = ""
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&configFilePath, "c", "", "path to config file: source.yaml")
|
||||
flag.BoolVar(&debugMode, "d", false, "debug mode")
|
||||
flag.StringVar(&configFilePath, "c", "", "path to config file: config.yaml")
|
||||
flag.Parse()
|
||||
|
||||
if debugMode {
|
||||
go pprof()
|
||||
if configFilePath == "" {
|
||||
configFilePath = os.Getenv("CONFIG_FILE")
|
||||
}
|
||||
|
||||
envConfigFilePath := os.Getenv("CONFIG_FILE")
|
||||
if envConfigFilePath == "" {
|
||||
envConfigFilePath = "source.yaml"
|
||||
if configFilePath == "" {
|
||||
configFilePath = "config.yaml"
|
||||
}
|
||||
|
||||
if configFilePath != "" {
|
||||
initConfigFile(configFilePath)
|
||||
} else {
|
||||
initConfigFile(envConfigFilePath)
|
||||
err := app.InitConfigAndGetters(configFilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
proxy.InitGeoIpDB()
|
||||
|
||||
go cron.Cron()
|
||||
fmt.Println("Do the first crawl...")
|
||||
go app.CrawlGo()
|
||||
go cron.Cron()
|
||||
api.Run()
|
||||
}
|
||||
|
||||
func initConfigFile(path string) {
|
||||
if strings.HasPrefix(path, "http") {
|
||||
config.Url = path
|
||||
config.NeedFetch = true
|
||||
app.FetchNewConfigFileThenInit()
|
||||
} else {
|
||||
err := app.InitConfigAndGetters(configFilePath)
|
||||
if err != nil {
|
||||
fmt.Errorf("Config file not found")
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pprof() {
|
||||
ip := "127.0.0.1:6060"
|
||||
if err := http.ListenAndServe(ip, nil); err != nil {
|
||||
fmt.Printf("start pprof failed on %s\n", ip)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func NewTGChannelGetter(options tool.Options) (getter Getter, err error) {
|
||||
return nil, err
|
||||
}
|
||||
return &TGChannelGetter{
|
||||
c: colly.NewCollector(),
|
||||
c: tool.GetColly(),
|
||||
NumNeeded: t,
|
||||
Url: "https://t.me/s/" + url,
|
||||
}, nil
|
||||
|
||||
@@ -16,9 +16,9 @@ func init() {
|
||||
}
|
||||
|
||||
type WebFanqiangdang struct {
|
||||
c *colly.Collector
|
||||
Url string
|
||||
results proxy.ProxyList
|
||||
c *colly.Collector
|
||||
Url string
|
||||
results proxy.ProxyList
|
||||
}
|
||||
|
||||
func NewWebFanqiangdangGetter(options tool.Options) (getter Getter, err error) {
|
||||
@@ -29,8 +29,8 @@ func NewWebFanqiangdangGetter(options tool.Options) (getter Getter, err error) {
|
||||
return nil, err
|
||||
}
|
||||
return &WebFanqiangdang{
|
||||
c: colly.NewCollector(),
|
||||
Url: url,
|
||||
c: colly.NewCollector(),
|
||||
Url: url,
|
||||
}, nil
|
||||
}
|
||||
return nil, ErrorUrlNotFound
|
||||
@@ -70,11 +70,10 @@ func (w *WebFanqiangdang) Get2Chan(pc chan proxy.Proxy, wg *sync.WaitGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type WebFanqiangdangRSS struct {
|
||||
c *colly.Collector
|
||||
Url string
|
||||
results []string
|
||||
c *colly.Collector
|
||||
Url string
|
||||
results []string
|
||||
}
|
||||
|
||||
func NewWebFanqiangdangRSSGetter(options tool.Options) (getter Getter, err error) {
|
||||
@@ -85,8 +84,8 @@ func NewWebFanqiangdangRSSGetter(options tool.Options) (getter Getter, err error
|
||||
return nil, err
|
||||
}
|
||||
return &WebFanqiangdangRSS{
|
||||
c: colly.NewCollector(),
|
||||
Url: url,
|
||||
c: tool.GetColly(),
|
||||
Url: url,
|
||||
}, nil
|
||||
}
|
||||
return nil, ErrorUrlNotFound
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
type Clash struct {
|
||||
Proxies proxy.ProxyList `yaml:"proxies"`
|
||||
Types string `yaml:"type"`
|
||||
Country string `yaml:"country"`
|
||||
}
|
||||
|
||||
func (c Clash) CleanProxies() (proxies proxy.ProxyList) {
|
||||
@@ -25,23 +26,44 @@ func (c Clash) Provide() string {
|
||||
var resultBuilder strings.Builder
|
||||
resultBuilder.WriteString("proxies:\n")
|
||||
|
||||
noNeedFilterType := false
|
||||
noNeedFilterCountry := false
|
||||
if c.Types == "" || c.Types == "all" {
|
||||
for _, p := range c.Proxies {
|
||||
if checkClashSupport(p) {
|
||||
resultBuilder.WriteString(p.ToClash() + "\n")
|
||||
}
|
||||
noNeedFilterType = true
|
||||
}
|
||||
if c.Country == "" || c.Country == "all" {
|
||||
noNeedFilterCountry = true
|
||||
}
|
||||
types := strings.Split(c.Types, ",")
|
||||
countries := strings.Split(c.Country, ",")
|
||||
|
||||
for _, p := range c.Proxies {
|
||||
if !checkClashSupport(p) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
types := strings.Split(c.Types, ",")
|
||||
for _, p := range c.Proxies {
|
||||
if checkClashSupport(p) {
|
||||
for _, t := range types {
|
||||
if p.TypeName() == t {
|
||||
resultBuilder.WriteString(p.ToClash() + "\n")
|
||||
}
|
||||
|
||||
typeOk := false
|
||||
countryOk := false
|
||||
if !noNeedFilterType {
|
||||
for _, t := range types {
|
||||
if p.TypeName() == t {
|
||||
typeOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !noNeedFilterCountry {
|
||||
for _, c := range countries {
|
||||
if strings.HasPrefix(p.BaseInfo().Name, c) {
|
||||
countryOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noNeedFilterType || typeOk) && (noNeedFilterCountry || countryOk) {
|
||||
resultBuilder.WriteString(p.ToClash() + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
return resultBuilder.String()
|
||||
|
||||
@@ -19,6 +19,10 @@ func (b *Base) SetName(name string) {
|
||||
b.Name = name
|
||||
}
|
||||
|
||||
func (b *Base) SetIP(ip string) {
|
||||
b.Server = ip
|
||||
}
|
||||
|
||||
func (b *Base) BaseInfo() *Base {
|
||||
return b
|
||||
}
|
||||
@@ -34,6 +38,7 @@ type Proxy interface {
|
||||
ToSurge() string
|
||||
Identifier() string
|
||||
SetName(name string)
|
||||
SetIP(ip string)
|
||||
TypeName() string
|
||||
BaseInfo() *Base
|
||||
Clone() Proxy
|
||||
|
||||
@@ -4,8 +4,11 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ivpusic/grpool"
|
||||
|
||||
"github.com/Dreamacro/clash/adapters/outbound"
|
||||
)
|
||||
|
||||
@@ -35,21 +38,75 @@ func testDelay(p Proxy) (delay uint16, err error) {
|
||||
return delay, err
|
||||
}
|
||||
|
||||
func CleanBadProxiesWithGrpool(proxies []Proxy) (cproxies []Proxy) {
|
||||
pool := grpool.NewPool(500, 200)
|
||||
|
||||
c := make(chan checkResult)
|
||||
defer close(c)
|
||||
|
||||
pool.WaitCount(len(proxies))
|
||||
go func() {
|
||||
for _, p := range proxies {
|
||||
pp := p
|
||||
pool.JobQueue <- func() {
|
||||
defer pool.JobDone()
|
||||
delay, err := testDelay(pp)
|
||||
if err == nil {
|
||||
c <- checkResult{
|
||||
name: pp.Identifier(),
|
||||
delay: delay,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
go func() {
|
||||
pool.WaitAll()
|
||||
pool.Release()
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
okMap := make(map[string]struct{})
|
||||
for {
|
||||
select {
|
||||
case r := <-c:
|
||||
if r.delay > 0 {
|
||||
okMap[r.name] = struct{}{}
|
||||
}
|
||||
case <-done:
|
||||
cproxies = make(ProxyList, 0, 500)
|
||||
for _, p := range proxies {
|
||||
if _, ok := okMap[p.Identifier()]; ok {
|
||||
cproxies = append(cproxies, p.Clone())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CleanBadProxies(proxies []Proxy) (cproxies []Proxy) {
|
||||
c := make(chan checkResult, 40)
|
||||
defer close(c)
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(len(proxies))
|
||||
for _, p := range proxies {
|
||||
go testProxyDelayToChan(p, c)
|
||||
go testProxyDelayToChan(p, c, wg)
|
||||
}
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(c)
|
||||
}()
|
||||
|
||||
okMap := make(map[string]struct{})
|
||||
size := len(proxies)
|
||||
for i := 0; i < size; i++ {
|
||||
r := <-c
|
||||
for r := range c {
|
||||
if r.delay > 0 {
|
||||
okMap[r.name] = struct{}{}
|
||||
}
|
||||
}
|
||||
cproxies = make([]Proxy, 0)
|
||||
cproxies = make(ProxyList, 0, 500)
|
||||
for _, p := range proxies {
|
||||
if _, ok := okMap[p.Identifier()]; ok {
|
||||
cproxies = append(cproxies, p.Clone())
|
||||
@@ -63,17 +120,13 @@ type checkResult struct {
|
||||
delay uint16
|
||||
}
|
||||
|
||||
func testProxyDelayToChan(p Proxy, c chan checkResult) {
|
||||
func testProxyDelayToChan(p Proxy, c chan checkResult, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
delay, err := testDelay(p)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
c <- checkResult{
|
||||
name: p.Identifier(),
|
||||
delay: 0,
|
||||
delay: delay,
|
||||
}
|
||||
return
|
||||
}
|
||||
c <- checkResult{
|
||||
name: p.Identifier(),
|
||||
delay: delay,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,15 +37,15 @@ func NewGeoIP(filePath string) (geoip GeoIP) {
|
||||
}
|
||||
|
||||
// find ip info
|
||||
func (g GeoIP) Find(ipORdomain string) (country string, err error) {
|
||||
func (g GeoIP) Find(ipORdomain string) (ip, country string, err error) {
|
||||
ips, err := net.LookupIP(ipORdomain)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
ipData := net.ParseIP(ips[0].String())
|
||||
record, err := g.db.City(ipData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
return record.Country.IsoCode, nil
|
||||
return ips[0].String(), record.Country.IsoCode, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package proxy
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ProxyList []Proxy
|
||||
@@ -21,8 +22,21 @@ func (ps ProxyList) TypeLen(t string) int {
|
||||
return l
|
||||
}
|
||||
|
||||
var sortType = make(map[string]int)
|
||||
|
||||
func init() {
|
||||
sortType["ss"] = 1
|
||||
sortType["ssr"] = 2
|
||||
sortType["vmess"] = 3
|
||||
sortType["trojan"] = 4
|
||||
}
|
||||
|
||||
func (ps ProxyList) Less(i, j int) bool {
|
||||
return ps[i].BaseInfo().Name < ps[j].BaseInfo().Name
|
||||
if ps[i].BaseInfo().Name == ps[j].BaseInfo().Name {
|
||||
return sortType[ps[i].BaseInfo().Type] < sortType[ps[j].BaseInfo().Type]
|
||||
} else {
|
||||
return ps[i].BaseInfo().Name < ps[j].BaseInfo().Name
|
||||
}
|
||||
}
|
||||
|
||||
func (ps ProxyList) Swap(i, j int) {
|
||||
@@ -50,13 +64,21 @@ func (ps ProxyList) Sort() ProxyList {
|
||||
|
||||
func (ps ProxyList) NameAddCounrty() ProxyList {
|
||||
num := len(ps)
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(num)
|
||||
for i := 0; i < num; i++ {
|
||||
country, err := geoIp.Find(ps[i].BaseInfo().Server)
|
||||
if err != nil || country == "" {
|
||||
country = "Earth"
|
||||
}
|
||||
ps[i].SetName(fmt.Sprintf("%s", country))
|
||||
ii := i
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_, country, err := geoIp.Find(ps[ii].BaseInfo().Server)
|
||||
if err != nil || country == "" {
|
||||
country = "ZZ"
|
||||
}
|
||||
ps[ii].SetName(fmt.Sprintf("%s", country))
|
||||
//ps[ii].SetIP(ip)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
return ps
|
||||
}
|
||||
|
||||
@@ -68,6 +90,24 @@ func (ps ProxyList) NameAddIndex() ProxyList {
|
||||
return ps
|
||||
}
|
||||
|
||||
func (ps ProxyList) NameReIndex() ProxyList {
|
||||
num := len(ps)
|
||||
for i := 0; i < num; i++ {
|
||||
originName := ps[i].BaseInfo().Name
|
||||
country := string([]rune(originName)[:2])
|
||||
ps[i].SetName(fmt.Sprintf("%s_%d", country, i+1))
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
func (ps ProxyList) NameAddTG() ProxyList {
|
||||
num := len(ps)
|
||||
for i := 0; i < num; i++ {
|
||||
ps[i].SetName(fmt.Sprintf("%s %s", ps[i].BaseInfo().Name, "@peekfun"))
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
func Deduplication(src ProxyList) ProxyList {
|
||||
result := make(ProxyList, 0, len(src))
|
||||
temp := map[string]struct{}{}
|
||||
|
||||
@@ -34,7 +34,7 @@ type ShadowsocksR struct {
|
||||
}
|
||||
|
||||
func (ssr ShadowsocksR) Identifier() string {
|
||||
return net.JoinHostPort(ssr.Server, strconv.Itoa(ssr.Port)) + ssr.ProtocolParam
|
||||
return net.JoinHostPort(ssr.Server, strconv.Itoa(ssr.Port)) + ssr.Password + ssr.ProtocolParam
|
||||
}
|
||||
|
||||
func (ssr ShadowsocksR) String() string {
|
||||
|
||||
27
pkg/tool/colly.go
Normal file
27
pkg/tool/colly.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package tool
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gocolly/colly"
|
||||
)
|
||||
|
||||
func GetColly() *colly.Collector {
|
||||
c := colly.NewCollector(
|
||||
colly.UserAgent(UserAgent),
|
||||
)
|
||||
c.WithTransport(&http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 10 * time.Second, // 超时时间
|
||||
KeepAlive: 10 * time.Second, // keepAlive 超时时间
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100, // 最大空闲连接数
|
||||
IdleConnTimeout: 20 * time.Second, // 空闲连接超时
|
||||
TLSHandshakeTimeout: 10 * time.Second, // TLS 握手超时
|
||||
ExpectContinueTimeout: 10 * time.Second,
|
||||
})
|
||||
return c
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
|
||||
|
||||
type HttpClient struct {
|
||||
*http.Client
|
||||
}
|
||||
@@ -28,7 +30,7 @@ func (c *HttpClient) Get(url string) (resp *http.Response, err error) {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36")
|
||||
req.Header.Set("User-Agent", UserAgent)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
@@ -38,6 +40,6 @@ func (c *HttpClient) Post(url string, body io.Reader) (resp *http.Response, err
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36")
|
||||
req.Header.Set("User-Agent", UserAgent)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user