Merge branch 'dev'
# Conflicts: # outlook.go
This commit is contained in:
commit
cc689b485c
3
.gitignore
vendored
3
.gitignore
vendored
@ -20,4 +20,5 @@ config.yml
|
|||||||
#Goreleaser
|
#Goreleaser
|
||||||
/dist
|
/dist
|
||||||
#Logs
|
#Logs
|
||||||
/log
|
/log
|
||||||
|
/.idea
|
||||||
@ -4,6 +4,7 @@ env:
|
|||||||
builds:
|
builds:
|
||||||
- env:
|
- env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
|
ldflags: -s -w
|
||||||
goos:
|
goos:
|
||||||
- linux
|
- linux
|
||||||
- windows
|
- windows
|
||||||
@ -28,6 +29,11 @@ archives:
|
|||||||
format_overrides:
|
format_overrides:
|
||||||
- goos: windows
|
- goos: windows
|
||||||
format: zip
|
format: zip
|
||||||
|
files:
|
||||||
|
- README.md
|
||||||
|
- README_zhCN.md
|
||||||
|
- config.yml.example
|
||||||
|
- LICENSE
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Tag }}-next"
|
name_template: "{{ .Tag }}-next"
|
||||||
changelog:
|
changelog:
|
||||||
|
|||||||
64
README.md
64
README.md
@ -4,20 +4,13 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
English | [简体中文](https://github.com/iyear/E5SubBot/blob/master/README_zhCN.md)
|
English | [简体中文](https://github.com/iyear/E5SubBot/blob/master/README_zhCN.md) | [交流群组](https://t.me/e5subbot)
|
||||||
|
|
||||||
A Simple Telebot for E5 Renewal
|
A Simple Telebot for E5 Renewal
|
||||||
|
|
||||||
`Golang` + `MySQL`
|
`Golang` + `MySQL`
|
||||||
|
|
||||||
DEMO: https://t.me/E5Sub_bot (all new functions will be tested in DEMO)
|
DEMO: https://t.me/E5Sub_bot
|
||||||
|
|
||||||
Communication: [Telegram Group](https://t.me/e5subbot)
|
|
||||||
|
|
||||||
## Preview
|
|
||||||
<center class="half">
|
|
||||||
<img src="https://raw.githubusercontent.com/iyear/E5SubBot/master/pics/bind.JPG" width="200"/><img src="https://raw.githubusercontent.com/iyear/E5SubBot/master/pics/my.JPG" width="200"/><img src="https://raw.githubusercontent.com/iyear/E5SubBot/master/pics/task.JPG" width="200"/>
|
|
||||||
</center>
|
|
||||||
|
|
||||||
## Feature
|
## Feature
|
||||||
|
|
||||||
@ -25,7 +18,7 @@ Communication: [Telegram Group](https://t.me/e5subbot)
|
|||||||
- Manageable Simple Account System
|
- Manageable Simple Account System
|
||||||
- Available Task Execution Feedback
|
- Available Task Execution Feedback
|
||||||
- Convenient Authorization
|
- Convenient Authorization
|
||||||
|
- Use concurrency to speed up
|
||||||
|
|
||||||
## Principle
|
## Principle
|
||||||
|
|
||||||
@ -60,15 +53,16 @@ docker-compose up -d
|
|||||||
```
|
```
|
||||||
### Binary Deployment
|
### Binary Deployment
|
||||||
|
|
||||||
Download the binary files of the corresponding system on the [Releases](https://github.com/iyear/E5SubBot/releases) page and upload it to the server
|
Download the binary files of the corresponding system on the [Releases](https://github.com/iyear/E5SubBot/releases) page
|
||||||
|
and upload it to the server
|
||||||
|
|
||||||
Windows: Start `E5SubBot.exe` in `cmd`
|
Windows: Start `E5SubBot.exe`
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
screen -S e5sub
|
screen -S e5sub
|
||||||
chmod 773 E5SubBot
|
chmod +x E5SubBot
|
||||||
./E5SubBot
|
./E5SubBot
|
||||||
(Ctrl A+D)
|
(Ctrl A+D)
|
||||||
```
|
```
|
||||||
@ -77,7 +71,7 @@ chmod 773 E5SubBot
|
|||||||
Download the source code and install the GO environment
|
Download the source code and install the GO environment
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
go build
|
git clone https://github.com/iyear/E5SubBot.git && cd E5SubBot && go build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
@ -91,6 +85,7 @@ bot_token: YOUR_BOT_TOKEN
|
|||||||
socks5: 127.0.0.1:1080
|
socks5: 127.0.0.1:1080
|
||||||
notice: "first line \n second line"
|
notice: "first line \n second line"
|
||||||
admin: 66666,77777,88888
|
admin: 66666,77777,88888
|
||||||
|
goroutine: 10
|
||||||
errlimit: 5
|
errlimit: 5
|
||||||
cron: "1 */3 * * *"
|
cron: "1 */3 * * *"
|
||||||
bindmax: 3
|
bindmax: 3
|
||||||
@ -100,21 +95,25 @@ mysql:
|
|||||||
user: e5sub
|
user: e5sub
|
||||||
password: e5sub
|
password: e5sub
|
||||||
database: e5sub
|
database: e5sub
|
||||||
|
table: users
|
||||||
```
|
```
|
||||||
|
|
||||||
`bindmax`, `notice`, `admin`, `errlimit` can be hot updated, just update `config.yml` to save.
|
`bindmax`, `notice`, `admin`,`goroutine`, `errlimit` can be hot updated, just update `config.yml` to save.
|
||||||
| Configuration | Explanation|
|
|
||||||
| ---- | ---- |
|
| Configuration | Explanation|Default|
|
||||||
| bot_token | Change to your own `BotToken` |
|
| ---- | ---- |----|
|
||||||
| socks5 | `Socks5` proxy,if you do not need ,you should delete it. For example: `127.0.0.1:1080` |
|
| bot_token | Change to your own `BotToken` |-|
|
||||||
|notice|Announcement. Merged into `/help`|
|
| socks5 | `Socks5` proxy,if you do not need ,you should delete it. For example: `127.0.0.1:1080` |-|
|
||||||
|admin|The administrator's `tgid`, go to https://t.me/userinfobot to get it, separated by `,`; Administrator permissions: manually call the task, get the total feedback of the task|
|
|notice|Announcement. Merged into `/help`|-|
|
||||||
|errlimit|The maximum number of errors for a single account, automatically unbind the single account and send a notification when it is full, without limiting the number of errors, change the value to a negative number `(-1)`; all errors will be cleared after the bot restarts|
|
|admin|The administrator's `tgid`, go to https://t.me/userinfobot to get it, separated by `,`; Administrator permissions: manually call the task, get the total feedback of the task|-|
|
||||||
|cron|API call frequency, using `cron` expression|
|
|goroutine|Concurrent number, don’t be too big|10|
|
||||||
|bindmax|Maximum number of bindable|
|
|errlimit|The maximum number of errors for a single account, automatically unbind the single account and send a notification when it is full, without limiting the number of errors, change the value to a negative number `(-1)`; all errors will be cleared after the bot restarts|5|
|
||||||
|mysql|Mysql configuration, please create database in advance|
|
|cron|API call frequency, using `cron` expression|-|
|
||||||
|
|bindmax|Maximum number of bindable|5|
|
||||||
|
|mysql|Mysql configuration, please create database in advance(If you upgrade the old version, please set table to users, otherwise the data table cannot be read)|-|
|
||||||
|
|
||||||
### Command
|
### Command
|
||||||
|
|
||||||
```
|
```
|
||||||
/my View bound account information
|
/my View bound account information
|
||||||
/bind Bind new account
|
/bind Bind new account
|
||||||
@ -141,25 +140,14 @@ Suspected memory leak. Not yet resolved, please run the daemon or restart Bot re
|
|||||||
|
|
||||||
https://t.me/e5subbot/5201
|
https://t.me/e5subbot/5201
|
||||||
|
|
||||||
## Third-Party
|
|
||||||
- [Telebot](https://gopkg.in/tucnak/telebot)
|
|
||||||
- [Mysql_driver](https://github.com/go-sql-driver/mysql)
|
|
||||||
- [Gjson](https://github.com/tidwall/gjson)
|
|
||||||
- [Cron](https://github.com/robfig/cron/)
|
|
||||||
- [Viper](https://github.com/spf13/viper)
|
|
||||||
- [Goreleaser](https://https://github.com/goreleaser/goreleaser)
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
- Provide documentation in other languages
|
- Provide documentation in other languages
|
||||||
- Provide help for code operation
|
- Provide help for code operation
|
||||||
- Suggests user interaction
|
- Suggests user interaction
|
||||||
- ……
|
- ……
|
||||||
## More Functions
|
## More Functions
|
||||||
If you still want to support new features, please use FeatHub to vote. We will consider the voting results and other factors to determine the development priority.
|
|
||||||
|
|
||||||
[](http://feathub.com/NervJS/taro)
|
If you still want to support new features, please initiate an issue.
|
||||||
|
|
||||||
[](https://feathub.com/iyear/E5SubBot)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@ -4,20 +4,14 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
[English](https://github.com/iyear/E5SubBot) | 简体中文
|
[English](https://github.com/iyear/E5SubBot) | 简体中文 | [交流群组](https://t.me/e5subbot)
|
||||||
|
|
||||||
A Simple Telebot for E5 Renewal
|
A Simple Telebot for E5 Renewal
|
||||||
|
|
||||||
`Golang` + `MySQL`
|
`Golang` + `MySQL`
|
||||||
|
|
||||||
DEMO: https://t.me/E5Sub_bot (长期运行,所有新功能会在DEMO测试)
|
DEMO: https://t.me/E5Sub_bot
|
||||||
|
|
||||||
[交流群组](https://t.me/e5subbot)
|
|
||||||
|
|
||||||
## 预览
|
|
||||||
<center class="half">
|
|
||||||
<img src="https://raw.githubusercontent.com/iyear/E5SubBot/master/pics/bind.JPG" width="200"/><img src="https://raw.githubusercontent.com/iyear/E5SubBot/master/pics/my.JPG" width="200"/><img src="https://raw.githubusercontent.com/iyear/E5SubBot/master/pics/task.JPG" width="200"/>
|
|
||||||
</center>
|
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
@ -25,6 +19,7 @@ DEMO: https://t.me/E5Sub_bot (长期运行,所有新功能会在DEMO测试)
|
|||||||
- 可管理的简易账户系统
|
- 可管理的简易账户系统
|
||||||
- 完善的任务执行反馈
|
- 完善的任务执行反馈
|
||||||
- 极为方便的授权方式
|
- 极为方便的授权方式
|
||||||
|
- 使用并发加快运行速度
|
||||||
|
|
||||||
|
|
||||||
## 原理
|
## 原理
|
||||||
@ -61,13 +56,13 @@ docker-compose up -d
|
|||||||
|
|
||||||
在[Releases](https://github.com/iyear/E5SubBot/releases)页面下载对应系统的二进制文件,上传至服务器
|
在[Releases](https://github.com/iyear/E5SubBot/releases)页面下载对应系统的二进制文件,上传至服务器
|
||||||
|
|
||||||
Windows: 在`cmd`中启动 `E5SubBot.exe`
|
Windows: 启动 `E5SubBot.exe`
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
screen -S e5sub
|
screen -S e5sub
|
||||||
chmod 773 E5SubBot
|
chmod +x E5SubBot
|
||||||
./E5SubBot
|
./E5SubBot
|
||||||
(Ctrl A+D)
|
(Ctrl A+D)
|
||||||
```
|
```
|
||||||
@ -76,7 +71,7 @@ chmod 773 E5SubBot
|
|||||||
下载源码,安装GO环境
|
下载源码,安装GO环境
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
go build
|
git clone https://github.com/iyear/E5SubBot.git && cd E5SubBot && go build
|
||||||
```
|
```
|
||||||
|
|
||||||
## 部署配置
|
## 部署配置
|
||||||
@ -90,6 +85,7 @@ bot_token: YOUR_BOT_TOKEN
|
|||||||
socks5: 127.0.0.1:1080
|
socks5: 127.0.0.1:1080
|
||||||
notice: "第一行\n第二行"
|
notice: "第一行\n第二行"
|
||||||
admin: 66666,77777,88888
|
admin: 66666,77777,88888
|
||||||
|
goroutine: 10
|
||||||
errlimit: 5
|
errlimit: 5
|
||||||
cron: "1 */3 * * *"
|
cron: "1 */3 * * *"
|
||||||
bindmax: 3
|
bindmax: 3
|
||||||
@ -99,21 +95,25 @@ mysql:
|
|||||||
user: e5sub
|
user: e5sub
|
||||||
password: e5sub
|
password: e5sub
|
||||||
database: e5sub
|
database: e5sub
|
||||||
|
table: users
|
||||||
```
|
```
|
||||||
|
|
||||||
`bindmax`,`notice`,`admin`,`errlimit`可热更新,直接更新`config.yml`保存即可
|
`bindmax`,`notice`,`admin`,`goroutine`,`errlimit`可热更新,直接更新`config.yml`保存即可
|
||||||
| 配置项 | 说明 |
|
|
||||||
| ---- | ---- |
|
| 配置项 | 说明 |默认值|
|
||||||
| bot_token | 更换为自己的`BotToken` |
|
| ---- | ---- | ---- |
|
||||||
| socks5 | `Socks5`代理,不需要删去即可.例如:`127.0.0.1:1080` |
|
| bot_token | 更换为自己的`BotToken` | -|
|
||||||
|notice|公告.合并至`/help`|
|
| socks5 | `Socks5`代理,不需要删去即可.例如:`127.0.0.1:1080` |-|
|
||||||
|admin|管理员`tgid`,前往 https://t.me/userinfobot 获取,用`,`隔开;管理员权限: 手动调用任务,获得任务总反馈|
|
|notice|公告.合并至`/help`|-|
|
||||||
|errlimit|单账户最大出错次数,满后自动解绑单账户并发送通知,不限制错误次数将值改为负数`(-1)`即可;bot重启后会清零所有错误次数|
|
|admin|管理员`tgid`,前往 https://t.me/userinfobot 获取,用`,`隔开;管理员权限: 手动调用任务,获得任务总反馈|-|
|
||||||
|cron|API调用频率,使用cron表达式|
|
|goroutine|并发数,不要过大|10|
|
||||||
|bindmax|最大可绑定数|
|
|errlimit|单账户最大出错次数,满后自动解绑单账户并发送通知,不限制错误次数将值改为负数`(-1)`即可;bot重启后会清零所有错误次数|5|
|
||||||
|mysql|mysql配置,请提前创建数据库|
|
|cron|API调用频率,使用cron表达式|-|
|
||||||
|
|bindmax|最大可绑定数|5|
|
||||||
|
|mysql|mysql配置,请提前创建数据库(旧版本升级请设置table为users,否则读不到数据表)|-|
|
||||||
|
|
||||||
### 命令
|
### 命令
|
||||||
|
|
||||||
```
|
```
|
||||||
/my 查看已绑定账户信息
|
/my 查看已绑定账户信息
|
||||||
/bind 绑定新账户
|
/bind 绑定新账户
|
||||||
@ -143,54 +143,17 @@ mysql:
|
|||||||
> 无法通过Bot创建应用程序
|
> 无法通过Bot创建应用程序
|
||||||
|
|
||||||
https://t.me/e5subbot/5201
|
https://t.me/e5subbot/5201
|
||||||
|
|
||||||
## 更多功能
|
## 更多功能
|
||||||
如果你还想支持新的特性,请使用 FeatHub 进行投票,我们将综合考虑投票结果等因素来确定开发的优先级。
|
|
||||||
|
|
||||||
[](http://feathub.com/NervJS/taro)
|
如果你还想支持新的特性,请发起issue.
|
||||||
|
|
||||||
[](https://feathub.com/iyear/E5SubBot)
|
|
||||||
## 做出贡献
|
## 做出贡献
|
||||||
|
|
||||||
- 提供其他语言的文档
|
- 提供其他语言的文档
|
||||||
- 为代码运行提供帮助
|
- 为代码运行提供帮助
|
||||||
- 对用户交互提出建议
|
- 对用户交互提出建议
|
||||||
- ……
|
- ……
|
||||||
## 小总结
|
|
||||||
#### 得到了什么?
|
|
||||||
- git的基本操作:add,commit,pull,push.但是对代码合并与冲突解决没有得到足够的实践和深入
|
|
||||||
- github版本库方面的使用(issue,pull request...),还有一些没玩过
|
|
||||||
- 体验了Docker Hub 的自动构建
|
|
||||||
- sql的CRUD,但都只是浮于表面,有时间再去琢磨
|
|
||||||
- telegram bot的golang基本框架和一些有意思的玩法
|
|
||||||
- 一些著名第三方库(viper,gjson)的基本用法
|
|
||||||
- docker以及docker-compose的基本用法
|
|
||||||
- 一些工具:gox;goreleaser的基本用法
|
|
||||||
- ……
|
|
||||||
#### 还缺点什么?
|
|
||||||
|
|
||||||
- 对`CGO`知难而退,编译各种出错。下个项目如果用到`sqlite`一定解决`CGO`交叉编译
|
|
||||||
- `DockerFile` 还不会写
|
|
||||||
- 对项目的概念和意识不太行,目录太乱,随缘写全局变量
|
|
||||||
- 看`telebot`的文档还好,看`stackflow` 只能看看代码。搜索还是习惯性带中文导致`stackflow`很难出现,降低了解决问题的效率
|
|
||||||
|
|
||||||
#### 最后
|
|
||||||
|
|
||||||
从2020.3.28开发至2020.4.12,一共经历14天,利用课余时间最终完成。
|
|
||||||
|
|
||||||
就要开学了,因为马上步入高三,学习紧迫,遂不再进行功能开发。
|
|
||||||
|
|
||||||
项目差不多就停更了,最多也就是每个星期看看issue、tg群组,修一修bug
|
|
||||||
|
|
||||||
**DEMO依旧能保持服务水平,不会因为个人问题在这段时间停止运行**
|
|
||||||
|
|
||||||
如果一年后还有人在用,一定会继续
|
|
||||||
|
|
||||||
## Third-Party
|
|
||||||
- [telebot](https://gopkg.in/tucnak/telebot)
|
|
||||||
- [mysql_driver](https://github.com/go-sql-driver/mysql)
|
|
||||||
- [gjson](https://github.com/tidwall/gjson)
|
|
||||||
- [cron](https://github.com/robfig/cron/)
|
|
||||||
- [viper](https://github.com/spf13/viper)
|
|
||||||
- [goreleaser](https://https://github.com/goreleaser/goreleaser)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
96
bots/bots.go
Normal file
96
bots/bots.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package bots
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/iyear/E5SubBot/config"
|
||||||
|
"github.com/iyear/E5SubBot/logger"
|
||||||
|
"github.com/iyear/E5SubBot/model"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
|
tb "gopkg.in/tucnak/telebot.v2"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bot *tb.Bot
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
logo = `
|
||||||
|
______ _____ _____ _ ____ _
|
||||||
|
| ____| ____/ ____| | | | _ \ | |
|
||||||
|
| |__ | |__| (___ _ _| |__ | |_) | ___ | |_
|
||||||
|
| __| |___ \\___ \| | | | '_ \| _ < / _ \| __|
|
||||||
|
| |____ ___) |___) | |_| | |_) | |_) | (_) | |_
|
||||||
|
|______|____/_____/ \__,_|_.__/|____/ \___/ \__|
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
func BotStart() {
|
||||||
|
var err error
|
||||||
|
fmt.Printf("%s\n", logo)
|
||||||
|
//read config
|
||||||
|
config.InitConfig()
|
||||||
|
//Init Logger
|
||||||
|
logger.InitLogger()
|
||||||
|
//InitDB
|
||||||
|
model.InitDB()
|
||||||
|
//Init Task
|
||||||
|
InitTask()
|
||||||
|
|
||||||
|
Poller := &tb.LongPoller{Timeout: 15 * time.Second}
|
||||||
|
spamPoller := tb.NewMiddlewarePoller(Poller, func(upd *tb.Update) bool {
|
||||||
|
if upd.Message == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !upd.Message.Private() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
botSetting := tb.Settings{
|
||||||
|
Token: config.BotToken,
|
||||||
|
Poller: spamPoller,
|
||||||
|
}
|
||||||
|
//set socks5
|
||||||
|
if config.Socks5 != "" {
|
||||||
|
fmt.Println("Proxy: " + config.Socks5)
|
||||||
|
dialer, err := proxy.SOCKS5("tcp", config.Socks5, nil, proxy.Direct)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorw("failed to get dialer",
|
||||||
|
"error", err, "proxy", config.Socks5)
|
||||||
|
}
|
||||||
|
httpTransport := &http.Transport{}
|
||||||
|
httpTransport.Dial = dialer.Dial
|
||||||
|
httpClient := &http.Client{Transport: httpTransport}
|
||||||
|
|
||||||
|
botSetting.Client = httpClient
|
||||||
|
}
|
||||||
|
//create bot
|
||||||
|
bot, err = tb.NewBot(botSetting)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorw("failed to create bot", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("Bot: " + strconv.Itoa(bot.Me.ID) + " " + bot.Me.Username)
|
||||||
|
|
||||||
|
MakeHandle()
|
||||||
|
fmt.Println("Bot Start")
|
||||||
|
fmt.Println("------------")
|
||||||
|
bot.Start()
|
||||||
|
}
|
||||||
|
func MakeHandle() {
|
||||||
|
//所有用户
|
||||||
|
bot.Handle("/start", bStart)
|
||||||
|
bot.Handle("/my", bMy)
|
||||||
|
bot.Handle("/bind", bBind1)
|
||||||
|
bot.Handle("/unbind", bUnBind)
|
||||||
|
bot.Handle("/export", bExport)
|
||||||
|
bot.Handle("/help", bHelp)
|
||||||
|
bot.Handle(tb.OnText, bOnText)
|
||||||
|
//管理员
|
||||||
|
bot.Handle("/task", bTask)
|
||||||
|
bot.Handle("/log", bLog)
|
||||||
|
}
|
||||||
73
bots/control.go
Normal file
73
bots/control.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package bots
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/iyear/E5SubBot/model"
|
||||||
|
"github.com/iyear/E5SubBot/util"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
tb "gopkg.in/tucnak/telebot.v2"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BindUser If Successfully return "",else return error information
|
||||||
|
func BindUser(m *tb.Message, ClientId, ClientSecret string) error {
|
||||||
|
tmp := strings.Split(m.Text, " ")
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
return errors.New("wrong format")
|
||||||
|
}
|
||||||
|
code := util.GetURLValue(tmp[0], "code")
|
||||||
|
Alias := tmp[1]
|
||||||
|
cli := model.NewClient(ClientId, ClientSecret)
|
||||||
|
if err := cli.GetTokenWithCode(code); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bot.Send(m.Chat, "Token获取成功!")
|
||||||
|
|
||||||
|
info, err := cli.GetUserInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var u = &model.Client{
|
||||||
|
TgId: m.Chat.ID,
|
||||||
|
RefreshToken: cli.RefreshToken,
|
||||||
|
MsId: util.Get16MD5Encode(gjson.Get(info, "id").String()),
|
||||||
|
Alias: Alias,
|
||||||
|
ClientId: ClientId,
|
||||||
|
ClientSecret: ClientSecret,
|
||||||
|
Other: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
//MS User Is Exist
|
||||||
|
if MSAppIsExist(u.TgId, u.ClientId) {
|
||||||
|
return errors.New("该应用已经绑定过了,无需重复绑定")
|
||||||
|
}
|
||||||
|
//MS information has gotten
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
fmt.Sprintf("ms_id(MD5):%s\nuserPrincipalName:%s\ndisplayName:%s",
|
||||||
|
u.MsId,
|
||||||
|
gjson.Get(info, "userPrincipalName").String(),
|
||||||
|
gjson.Get(info, "displayName").String(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if result := model.DB.Create(&u); result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBindNum get bind num
|
||||||
|
func GetBindNum(TgId int64) int {
|
||||||
|
var bindings []*model.Client
|
||||||
|
result := model.DB.Where("tg_id = ?", TgId).Find(&bindings)
|
||||||
|
return int(result.RowsAffected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSAppIsExist return true => exist
|
||||||
|
func MSAppIsExist(TgId int64, ClientId string) bool {
|
||||||
|
result := model.DB.
|
||||||
|
Where("tg_id = ? AND client_id = ?", TgId, ClientId).
|
||||||
|
First(&model.Client{})
|
||||||
|
return util.IF(result.RowsAffected == 0, false, true).(bool)
|
||||||
|
}
|
||||||
280
bots/handle.go
Normal file
280
bots/handle.go
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
package bots
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/iyear/E5SubBot/config"
|
||||||
|
"github.com/iyear/E5SubBot/model"
|
||||||
|
"github.com/iyear/E5SubBot/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
tb "gopkg.in/tucnak/telebot.v2"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UserStatus map[int64]int
|
||||||
|
UserClientId map[int64]string
|
||||||
|
UserClientSecret map[int64]string
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
USNone = iota
|
||||||
|
USBind1
|
||||||
|
USBind2
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UserStatus = make(map[int64]int)
|
||||||
|
UserClientId = make(map[int64]string)
|
||||||
|
UserClientSecret = make(map[int64]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bStart(m *tb.Message) {
|
||||||
|
bot.Send(m.Sender, config.WelcomeContent)
|
||||||
|
bHelp(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bMy(m *tb.Message) {
|
||||||
|
var data []*model.Client
|
||||||
|
model.DB.Where("tg_id = ?", m.Chat.ID).Find(&data)
|
||||||
|
var inlineKeys [][]tb.InlineButton
|
||||||
|
for _, u := range data {
|
||||||
|
inlineBtn := tb.InlineButton{
|
||||||
|
Unique: "my" + strconv.Itoa(u.ID),
|
||||||
|
Text: u.Alias,
|
||||||
|
Data: strconv.Itoa(u.ID),
|
||||||
|
}
|
||||||
|
bot.Handle(&inlineBtn, bMyInlineBtn)
|
||||||
|
inlineKeys = append(inlineKeys, []tb.InlineButton{inlineBtn})
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
fmt.Sprintf("选择一个账户查看具体信息\n\n绑定数: %d/%d", GetBindNum(m.Chat.ID), config.BindMaxNum),
|
||||||
|
&tb.ReplyMarkup{InlineKeyboard: inlineKeys})
|
||||||
|
}
|
||||||
|
func bMyInlineBtn(c *tb.Callback) {
|
||||||
|
var u *model.Client
|
||||||
|
model.DB.Where("id = ?", c.Data).First(&u)
|
||||||
|
bot.Send(c.Message.Chat,
|
||||||
|
fmt.Sprintf("信息\n别名:%s\nms_id: %s\nclient_id: %s\nclient_secret: %s\n最近更新时间: %s",
|
||||||
|
u.Alias,
|
||||||
|
u.MsId,
|
||||||
|
u.ClientId,
|
||||||
|
u.ClientSecret,
|
||||||
|
time.Unix(u.Uptime, 0).Format("2006-01-02 15:04:05"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
bot.Respond(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bBind1(m *tb.Message) {
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
fmt.Sprintf("应用注册: [点击直达](%s)", model.GetMSRegisterAppUrl()),
|
||||||
|
tb.ModeMarkdown,
|
||||||
|
)
|
||||||
|
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
"请回复 `client_id(空格)client_secret`",
|
||||||
|
&tb.SendOptions{ParseMode: tb.ModeMarkdown,
|
||||||
|
ReplyMarkup: &tb.ReplyMarkup{ForceReply: true}},
|
||||||
|
)
|
||||||
|
|
||||||
|
UserStatus[m.Chat.ID] = USBind1
|
||||||
|
UserClientId[m.Chat.ID] = m.Text
|
||||||
|
}
|
||||||
|
func bBind2(m *tb.Message) {
|
||||||
|
tmp := strings.Split(m.Text, " ")
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
bot.Send(m.Chat, "错误的格式")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ClientId := tmp[0]
|
||||||
|
ClientSecret := tmp[1]
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
"授权账户: [点击直达]("+model.GetMSAuthUrl(ClientId)+")",
|
||||||
|
tb.ModeMarkdown,
|
||||||
|
)
|
||||||
|
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
"请回复`http://localhost/……(空格)别名`(用于管理)",
|
||||||
|
&tb.SendOptions{ParseMode: tb.ModeMarkdown,
|
||||||
|
ReplyMarkup: &tb.ReplyMarkup{ForceReply: true},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
UserStatus[m.Chat.ID] = USBind2
|
||||||
|
UserClientId[m.Chat.ID] = ClientId
|
||||||
|
UserClientSecret[m.Chat.ID] = ClientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
func bUnBind(m *tb.Message) {
|
||||||
|
var data []*model.Client
|
||||||
|
model.DB.Where("tg_id = ?", m.Chat.ID).Find(&data)
|
||||||
|
var inlineKeys [][]tb.InlineButton
|
||||||
|
|
||||||
|
for _, u := range data {
|
||||||
|
inlineBtn := tb.InlineButton{
|
||||||
|
Unique: "unbind" + strconv.Itoa(u.ID),
|
||||||
|
Text: u.Alias,
|
||||||
|
Data: strconv.Itoa(u.ID),
|
||||||
|
}
|
||||||
|
bot.Handle(&inlineBtn, bUnBindInlineBtn)
|
||||||
|
inlineKeys = append(inlineKeys, []tb.InlineButton{inlineBtn})
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.Send(m.Chat,
|
||||||
|
fmt.Sprintf("选择一个账户将其解绑\n\n当前绑定数: %d/%d", GetBindNum(m.Chat.ID), config.BindMaxNum),
|
||||||
|
&tb.ReplyMarkup{InlineKeyboard: inlineKeys},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
func bUnBindInlineBtn(c *tb.Callback) {
|
||||||
|
if result := model.DB.Where("id = ?", c.Data).Delete(&model.Client{}); result.Error != nil {
|
||||||
|
zap.S().Errorw("failed to delete db data",
|
||||||
|
"error", result.Error,
|
||||||
|
"id", c.Data,
|
||||||
|
)
|
||||||
|
bot.Send(c.Message.Chat, "解绑失败!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bot.Send(c.Message.Chat, "解绑成功!")
|
||||||
|
bot.Respond(c)
|
||||||
|
}
|
||||||
|
func bExport(m *tb.Message) {
|
||||||
|
type ClientExport struct {
|
||||||
|
Alias string
|
||||||
|
ClientId string
|
||||||
|
ClientSecret string
|
||||||
|
RefreshToken string
|
||||||
|
Other string
|
||||||
|
}
|
||||||
|
var exports []ClientExport
|
||||||
|
var data []*model.Client
|
||||||
|
model.DB.Where("tg_id = ?", m.Chat.ID).Find(&data)
|
||||||
|
if len(data) == 0 {
|
||||||
|
bot.Send(m.Chat, "你还没有绑定过账户嗷~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, u := range data {
|
||||||
|
var cExport = ClientExport{
|
||||||
|
Alias: u.Alias,
|
||||||
|
ClientId: u.ClientId,
|
||||||
|
ClientSecret: u.ClientSecret,
|
||||||
|
RefreshToken: u.RefreshToken,
|
||||||
|
Other: u.Other,
|
||||||
|
}
|
||||||
|
exports = append(exports, cExport)
|
||||||
|
}
|
||||||
|
export, err := json.MarshalIndent(exports, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorw("failed to marshal json",
|
||||||
|
"error", err)
|
||||||
|
bot.Send(m.Chat, fmt.Sprintf("获取JSON失败!\n\nERROR: %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileName := fmt.Sprintf("./%d_export_tmp.json", m.Chat.ID)
|
||||||
|
if err = ioutil.WriteFile(fileName, export, 0644); err != nil {
|
||||||
|
zap.S().Errorw("failed to write file",
|
||||||
|
"error", err)
|
||||||
|
bot.Send(m.Chat, "写入临时文件失败~\n"+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exportFile := &tb.Document{
|
||||||
|
File: tb.FromDisk(fileName),
|
||||||
|
FileName: strconv.FormatInt(m.Chat.ID, 10) + ".json",
|
||||||
|
MIME: "text/plain",
|
||||||
|
}
|
||||||
|
bot.Send(m.Chat, exportFile)
|
||||||
|
|
||||||
|
if exportFile.InCloud() != true || os.Remove(fileName) != nil {
|
||||||
|
zap.S().Errorw("failed to export files")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func bHelp(m *tb.Message) {
|
||||||
|
bot.Send(
|
||||||
|
m.Sender,
|
||||||
|
config.HelpContent+"\n"+config.Notice,
|
||||||
|
&tb.SendOptions{DisableWebPagePreview: false})
|
||||||
|
}
|
||||||
|
func bOnText(m *tb.Message) {
|
||||||
|
switch UserStatus[m.Chat.ID] {
|
||||||
|
case USNone:
|
||||||
|
{
|
||||||
|
bot.Send(m.Chat, "发送 /help 获取帮助嗷")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case USBind1:
|
||||||
|
{
|
||||||
|
if !m.IsReply() {
|
||||||
|
bot.Send(m.Chat, "请通过回复方式绑定")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bBind2(m)
|
||||||
|
}
|
||||||
|
case USBind2:
|
||||||
|
{
|
||||||
|
if !m.IsReply() {
|
||||||
|
bot.Send(m.Chat, "请通过回复方式绑定")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if GetBindNum(m.Chat.ID) == config.BindMaxNum {
|
||||||
|
bot.Send(m.Chat, "已经达到最大可绑定数")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bot.Send(m.Chat, "正在绑定中……")
|
||||||
|
err := BindUser(m, UserClientId[m.Chat.ID], UserClientSecret[m.Chat.ID])
|
||||||
|
if err != nil {
|
||||||
|
bot.Send(m.Chat, err.Error())
|
||||||
|
} else {
|
||||||
|
bot.Send(m.Chat, "绑定成功!")
|
||||||
|
}
|
||||||
|
UserStatus[m.Chat.ID] = USNone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func bTask(m *tb.Message) {
|
||||||
|
for _, a := range config.Admins {
|
||||||
|
if a == m.Chat.ID {
|
||||||
|
SignTask()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bot.Send(m.Chat, "只有Bot管理员才有权限执行此操作")
|
||||||
|
}
|
||||||
|
func bLog(m *tb.Message) {
|
||||||
|
flag := 0
|
||||||
|
for _, a := range config.Admins {
|
||||||
|
if a == m.Chat.ID {
|
||||||
|
flag = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flag == 0 {
|
||||||
|
bot.Send(m.Chat, "只有Bot管理员才有权限执行此操作")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logs := util.GetRecentLogs(config.LogBasePath, 5)
|
||||||
|
var inlineKeys [][]tb.InlineButton
|
||||||
|
for _, log := range logs {
|
||||||
|
inlineBtn := tb.InlineButton{
|
||||||
|
Unique: "log" + strings.Replace(strings.TrimSuffix(filepath.Base(log), ".log"), "-", "", -1),
|
||||||
|
Text: filepath.Base(log),
|
||||||
|
Data: filepath.Base(log),
|
||||||
|
}
|
||||||
|
bot.Handle(&inlineBtn, bLogsInlineBtn)
|
||||||
|
inlineKeys = append(inlineKeys, []tb.InlineButton{inlineBtn})
|
||||||
|
}
|
||||||
|
bot.Send(m.Chat, "请选择日志", &tb.ReplyMarkup{InlineKeyboard: inlineKeys})
|
||||||
|
}
|
||||||
|
func bLogsInlineBtn(c *tb.Callback) {
|
||||||
|
logfile := &tb.Document{
|
||||||
|
File: tb.FromDisk(config.LogBasePath + c.Data),
|
||||||
|
FileName: c.Data,
|
||||||
|
MIME: "text/plain",
|
||||||
|
}
|
||||||
|
bot.Send(c.Message.Chat, logfile)
|
||||||
|
bot.Respond(c)
|
||||||
|
}
|
||||||
86
bots/sender.go
Normal file
86
bots/sender.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package bots
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/tucnak/telebot.v2"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Sender struct {
|
||||||
|
done chan struct{}
|
||||||
|
in chan *Msg
|
||||||
|
wg sync.WaitGroup
|
||||||
|
}
|
||||||
|
type Msg struct {
|
||||||
|
To telebot.Recipient
|
||||||
|
What interface{}
|
||||||
|
Options []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
//牺牲错误处理和解耦,加快发送速度
|
||||||
|
|
||||||
|
func NewSender() *Sender {
|
||||||
|
return &Sender{}
|
||||||
|
}
|
||||||
|
func (s *Sender) Init(goroutine int) {
|
||||||
|
|
||||||
|
s.done = make(chan struct{})
|
||||||
|
s.in = make(chan *Msg)
|
||||||
|
|
||||||
|
for i := 0; i < goroutine; i++ {
|
||||||
|
go func() {
|
||||||
|
s.sender()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Stop until all messages were sent
|
||||||
|
func (s *Sender) Stop() {
|
||||||
|
s.wg.Wait()
|
||||||
|
close(s.done)
|
||||||
|
fmt.Println("task finished")
|
||||||
|
}
|
||||||
|
func (s *Sender) SendMessageByID(ID int64, what interface{}, options ...interface{}) {
|
||||||
|
s.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
chat, err := bot.ChatByID(strconv.FormatInt(ID, 10))
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorw("failed to get chat",
|
||||||
|
"error", err,
|
||||||
|
"id", ID,
|
||||||
|
)
|
||||||
|
s.wg.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.SendMessage(chat, what, options...)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
func (s *Sender) SendMessage(to telebot.Recipient, what interface{}, options ...interface{}) {
|
||||||
|
s.in <- &Msg{
|
||||||
|
To: to,
|
||||||
|
What: what,
|
||||||
|
Options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *Sender) sender() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case msg, f := <-s.in:
|
||||||
|
if !f {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Println("send to " + msg.To.Recipient())
|
||||||
|
if _, err := bot.Send(msg.To, msg.What, msg.Options...); err != nil {
|
||||||
|
zap.S().Errorw("failed to send msg",
|
||||||
|
"error", err,
|
||||||
|
"id", msg.To.Recipient(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
s.wg.Done()
|
||||||
|
case <-s.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
148
bots/task.go
Normal file
148
bots/task.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package bots
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/iyear/E5SubBot/config"
|
||||||
|
"github.com/iyear/E5SubBot/model"
|
||||||
|
"github.com/iyear/E5SubBot/task"
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
tb "gopkg.in/tucnak/telebot.v2"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errorTimes map[int]int
|
||||||
|
var signErr map[int64]int
|
||||||
|
var unbindUsers []int64
|
||||||
|
var msgSender *Sender
|
||||||
|
|
||||||
|
func InitTask() {
|
||||||
|
errorTimes = make(map[int]int)
|
||||||
|
msgSender = NewSender()
|
||||||
|
|
||||||
|
c := cron.New()
|
||||||
|
c.AddFunc(config.Cron, SignTask)
|
||||||
|
c.Start()
|
||||||
|
}
|
||||||
|
func SignTask() {
|
||||||
|
msgSender.Init(config.MaxGoroutines)
|
||||||
|
|
||||||
|
signErr = make(map[int64]int)
|
||||||
|
unbindUsers = nil
|
||||||
|
|
||||||
|
var clients []*model.Client
|
||||||
|
if result := model.DB.Find(&clients); result.Error != nil {
|
||||||
|
zap.S().Errorw("failed to get all clients",
|
||||||
|
"error", result.Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("clients: %d goroutines:%d\n",
|
||||||
|
len(clients),
|
||||||
|
config.MaxGoroutines,
|
||||||
|
)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
errClients := task.Sign(clients)
|
||||||
|
|
||||||
|
for _, errClient := range errClients {
|
||||||
|
if errClient.Err != nil {
|
||||||
|
opErrorSign(errClient)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//请求一次成功清零errorTimes,避免接口的偶然错误积累导致账号被清退
|
||||||
|
errorTimes[errClient.ID] = 0
|
||||||
|
model.DB.Save(&errClient.Client)
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Println(signErr)
|
||||||
|
//fmt.Println(errorTimes)
|
||||||
|
timeSpending := time.Since(start).Seconds()
|
||||||
|
summarySignTaskForUsers(errClients)
|
||||||
|
summarySignTaskForAdmins(errClients, timeSpending)
|
||||||
|
|
||||||
|
msgSender.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func summarySignTaskForAdmins(errClients []*model.ErrClient, timeSpending float64) {
|
||||||
|
var Count = len(errClients)
|
||||||
|
var ErrCount int
|
||||||
|
var ErrUserStr string
|
||||||
|
var UnbindUserStr string
|
||||||
|
for err, count := range signErr {
|
||||||
|
ErrCount += count
|
||||||
|
ErrUserStr += fmt.Sprintf("[%d](tg://user?id=%d)\n", err, err)
|
||||||
|
}
|
||||||
|
for _, unbindUser := range unbindUsers {
|
||||||
|
UnbindUserStr += fmt.Sprintf("[%d](tg://user?id=%d)\n", unbindUser, unbindUser)
|
||||||
|
}
|
||||||
|
for _, admin := range config.Admins {
|
||||||
|
a := admin
|
||||||
|
msgSender.SendMessageByID(a, fmt.Sprintf("任务反馈(管理员)\n完成时间: %s\n用时: %.2fs\n结果: %d/%d\n错误账户: \n%s\n清退账户: \n%s",
|
||||||
|
time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
timeSpending,
|
||||||
|
Count-ErrCount, Count,
|
||||||
|
ErrUserStr, UnbindUserStr,
|
||||||
|
),
|
||||||
|
tb.ModeMarkdown,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func summarySignTaskForUsers(errClients []*model.ErrClient) {
|
||||||
|
|
||||||
|
var isSent map[int64]bool
|
||||||
|
isSent = make(map[int64]bool)
|
||||||
|
|
||||||
|
for _, errClient := range errClients {
|
||||||
|
errClient := errClient
|
||||||
|
//pending SignErrNum
|
||||||
|
if errorTimes[errClient.ID] > config.MaxErrTimes {
|
||||||
|
if result := model.DB.Delete(&errClient.Client); result.Error != nil {
|
||||||
|
zap.S().Errorw("failed to delete data",
|
||||||
|
"error", result.Error,
|
||||||
|
"id", errClient.ID,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindUsers = append(unbindUsers, errClient.TgId)
|
||||||
|
|
||||||
|
msgSender.SendMessageByID(errClient.TgId, fmt.Sprintf("您的账户因达到错误上限而被自动解绑\n后会有期!\n\n别名: %s\nclient_id: %s\nclient_secret: %s",
|
||||||
|
errClient.Alias,
|
||||||
|
errClient.ClientId,
|
||||||
|
errClient.ClientSecret,
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
if isSent[errClient.TgId] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
signOK := GetBindNum(errClient.TgId) - signErr[errClient.TgId]
|
||||||
|
|
||||||
|
msgSender.SendMessageByID(errClient.TgId,
|
||||||
|
fmt.Sprintf("任务反馈\n时间: %s\n结果:%d/%d",
|
||||||
|
time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
signOK,
|
||||||
|
signErr[errClient.TgId]+signOK,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
isSent[errClient.TgId] = true
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func opErrorSign(errClient *model.ErrClient) {
|
||||||
|
errorTimes[errClient.ID]++
|
||||||
|
signErr[errClient.TgId]++
|
||||||
|
|
||||||
|
UnBindBtn := tb.InlineButton{Unique: "un" + errClient.MsId, Text: "点击解绑", Data: strconv.Itoa(errClient.ID)}
|
||||||
|
bot.Handle(&UnBindBtn, bUnBindInlineBtn)
|
||||||
|
|
||||||
|
msgSender.SendMessageByID(errClient.TgId,
|
||||||
|
fmt.Sprintf("您的帐户 %s 在执行时出现了错误\n您可以选择解绑该用户\n错误: %s",
|
||||||
|
errClient.Alias, errClient.Err),
|
||||||
|
&tb.ReplyMarkup{InlineKeyboard: [][]tb.InlineButton{{UnBindBtn}}},
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ bot_token: xxx
|
|||||||
#socks5: 127.0.0.1:1080
|
#socks5: 127.0.0.1:1080
|
||||||
bindmax: 3
|
bindmax: 3
|
||||||
admin: 555,666,777
|
admin: 555,666,777
|
||||||
|
goroutine: 10
|
||||||
errlimit: 5
|
errlimit: 5
|
||||||
notice: "aaa\nbbb"
|
notice: "aaa\nbbb"
|
||||||
cron: "1 */3 * * *"
|
cron: "1 */3 * * *"
|
||||||
@ -11,4 +12,5 @@ mysql:
|
|||||||
port: 3306
|
port: 3306
|
||||||
user: root
|
user: root
|
||||||
password: root
|
password: root
|
||||||
database: e5sub
|
database: e5sub
|
||||||
|
table: users
|
||||||
93
config/config.go
Normal file
93
config/config.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LogBasePath string = "./log/"
|
||||||
|
WelcomeContent string = "欢迎使用E5SubBot!"
|
||||||
|
HelpContent string = `
|
||||||
|
命令:
|
||||||
|
/my 查看已绑定账户信息
|
||||||
|
/bind 绑定新账户
|
||||||
|
/unbind 解绑账户
|
||||||
|
/export 导出账户信息(JSON)
|
||||||
|
/help 帮助
|
||||||
|
源码及使用方法:https://github.com/iyear/E5SubBot
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
BotToken string
|
||||||
|
Socks5 string
|
||||||
|
BindMaxNum int
|
||||||
|
MaxGoroutines int
|
||||||
|
MaxErrTimes int
|
||||||
|
Cron string
|
||||||
|
Notice string
|
||||||
|
Admins []int64
|
||||||
|
Mysql MysqlConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
type MysqlConfig struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
DB string
|
||||||
|
Table string
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitConfig() {
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
viper.AddConfigPath(".")
|
||||||
|
err := viper.ReadInConfig()
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorw("failed to read config", "error", err)
|
||||||
|
}
|
||||||
|
BotToken = viper.GetString("bot_token")
|
||||||
|
Cron = viper.GetString("cron")
|
||||||
|
Socks5 = viper.GetString("socks5")
|
||||||
|
|
||||||
|
viper.SetDefault("errlimit", 5)
|
||||||
|
viper.SetDefault("bindmax", 5)
|
||||||
|
viper.SetDefault("goroutine", 10)
|
||||||
|
|
||||||
|
BindMaxNum = viper.GetInt("bindmax")
|
||||||
|
MaxErrTimes = viper.GetInt("errlimit")
|
||||||
|
Notice = viper.GetString("notice")
|
||||||
|
|
||||||
|
MaxGoroutines = viper.GetInt("goroutine")
|
||||||
|
Admins = getAdmins()
|
||||||
|
|
||||||
|
Mysql = MysqlConfig{
|
||||||
|
Host: viper.GetString("mysql.host"),
|
||||||
|
Port: viper.GetInt("mysql.port"),
|
||||||
|
User: viper.GetString("mysql.user"),
|
||||||
|
Password: viper.GetString("mysql.password"),
|
||||||
|
DB: viper.GetString("mysql.database"),
|
||||||
|
Table: viper.GetString("mysql.table"),
|
||||||
|
}
|
||||||
|
viper.WatchConfig()
|
||||||
|
viper.OnConfigChange(func(e fsnotify.Event) {
|
||||||
|
MaxGoroutines = viper.GetInt("goroutine")
|
||||||
|
BindMaxNum = viper.GetInt("bindmax")
|
||||||
|
MaxErrTimes = viper.GetInt("errlimit")
|
||||||
|
Notice = viper.GetString("notice")
|
||||||
|
Admins = getAdmins()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func getAdmins() []int64 {
|
||||||
|
var result []int64
|
||||||
|
admins := strings.Split(viper.GetString("admin"), ",")
|
||||||
|
for _, v := range admins {
|
||||||
|
id, _ := strconv.ParseInt(v, 10, 64)
|
||||||
|
result = append(result, id)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
225
control.go
225
control.go
@ -1,225 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
tb "gopkg.in/tucnak/telebot.v2"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var SignOk map[int64]int
|
|
||||||
|
|
||||||
//If Successfully return "",else return error information
|
|
||||||
func BindUser(m *tb.Message, cid, cse string) error {
|
|
||||||
logger.Printf("%d Begin Bind\n", m.Chat.ID)
|
|
||||||
tmp := strings.Split(m.Text, " ")
|
|
||||||
if len(tmp) != 2 {
|
|
||||||
logger.Printf("%d Bind error:Wrong Bind Format\n", m.Chat.ID)
|
|
||||||
return errors.New("绑定格式错误")
|
|
||||||
}
|
|
||||||
logger.Println("alias: " + tmp[1])
|
|
||||||
alias := tmp[1]
|
|
||||||
code := GetURLValue(tmp[0], "code")
|
|
||||||
//fmt.Println(code)
|
|
||||||
access, refresh, err := MSFirGetToken(code, cid, cse)
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("%d Bind error:GetRefreshToken %s \n", m.Chat.ID, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//token has gotten
|
|
||||||
bot.Send(m.Chat, "Token获取成功!")
|
|
||||||
info, err := MSGetUserInfo(access)
|
|
||||||
//fmt.Printf("TGID:%d Refresh Token: %s\n", m.Chat.ID, refresh)
|
|
||||||
if err != nil {
|
|
||||||
logger.Printf("%d Bind error:Getinfo %s \n", m.Chat.ID, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var u MSData
|
|
||||||
u.tgId = m.Chat.ID
|
|
||||||
u.refreshToken = refresh
|
|
||||||
//TG的Data传递最高64bytes,一些msid超过了报错BUTTON_DATA_INVALID (0),采取md5
|
|
||||||
u.msId = Get16MD5Encode(gjson.Get(info, "id").String())
|
|
||||||
u.uptime = time.Now().Unix()
|
|
||||||
logger.Println(u.uptime)
|
|
||||||
u.alias = alias
|
|
||||||
u.clientId = cid
|
|
||||||
u.clientSecret = cse
|
|
||||||
u.other = ""
|
|
||||||
//MS User Is Exist
|
|
||||||
if MSAppIsExist(u.tgId, u.clientId) {
|
|
||||||
logger.Printf("%d Bind error:MSUserHasExisted\n", m.Chat.ID)
|
|
||||||
return errors.New("该应用已经绑定过了,无需重复绑定")
|
|
||||||
}
|
|
||||||
//MS information has gotten
|
|
||||||
bot.Send(m.Chat, "MS_ID(MD5): "+u.msId+"\nuserPrincipalName: "+gjson.Get(info, "userPrincipalName").String()+"\ndisplayName: "+gjson.Get(info, "displayName").String()+"\n")
|
|
||||||
if ok, err := AddData(u); !ok {
|
|
||||||
logger.Printf("%d Bind error: %s\n", m.Chat.ID, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Printf("%d Bind Successfully!\n", m.Chat.ID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//get bind num
|
|
||||||
func GetBindNum(tgId int64) int {
|
|
||||||
data := QueryDataByTG(tgId)
|
|
||||||
return len(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
//return true => exist
|
|
||||||
func MSAppIsExist(tgId int64, clientId string) bool {
|
|
||||||
data := QueryDataByTG(tgId)
|
|
||||||
var res MSData
|
|
||||||
for _, res = range data {
|
|
||||||
if res.clientId == clientId {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//SignTask
|
|
||||||
func SignTask() {
|
|
||||||
var (
|
|
||||||
SignOk map[int64]int
|
|
||||||
SignErr []string
|
|
||||||
UnbindUser []string
|
|
||||||
num, signOk int
|
|
||||||
)
|
|
||||||
SignOk = make(map[int64]int)
|
|
||||||
fmt.Println("----Task Begin----")
|
|
||||||
fmt.Println("Time:" + time.Now().Format("2006-01-02 15:04:05"))
|
|
||||||
data := QueryDataAll()
|
|
||||||
num = len(data)
|
|
||||||
fmt.Println("Start Sign")
|
|
||||||
//签到任务
|
|
||||||
for _, u := range data {
|
|
||||||
pre := "您的账户: " + u.alias + "\n在任务执行时出现了错误!\n错误:"
|
|
||||||
chat, err := bot.ChatByID(strconv.FormatInt(u.tgId, 10))
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
//生成解绑按钮
|
|
||||||
var inlineKeys [][]tb.InlineButton
|
|
||||||
UnBindBtn := tb.InlineButton{Unique: "un" + u.msId, Text: "点击解绑该账户", Data: u.msId}
|
|
||||||
bot.Handle(&UnBindBtn, bUnBindInlineBtn)
|
|
||||||
inlineKeys = append(inlineKeys, []tb.InlineButton{UnBindBtn})
|
|
||||||
tmpBtn := &tb.ReplyMarkup{InlineKeyboard: inlineKeys}
|
|
||||||
|
|
||||||
se := u.msId + " ( @" + chat.Username + " )"
|
|
||||||
access, newRefreshToken, err := MSGetToken(u.refreshToken, u.clientId, u.clientSecret)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(u.msId+" ", err)
|
|
||||||
bot.Send(chat, pre+gjson.Get(err.Error(), "error").String(), tmpBtn)
|
|
||||||
SignErr = append(SignErr, se)
|
|
||||||
ErrorTimes[u.msId]++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok, err := OutLookGetMails(access); !ok {
|
|
||||||
logger.Println(u.msId+" ", err)
|
|
||||||
bot.Send(chat, pre+gjson.Get(err.Error(), "error").String(), tmpBtn)
|
|
||||||
ErrorTimes[u.msId]++
|
|
||||||
SignErr = append(SignErr, se)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
u.uptime = time.Now().Unix()
|
|
||||||
u.refreshToken = newRefreshToken
|
|
||||||
if ok, err := UpdateData(u); !ok {
|
|
||||||
logger.Println(u.msId+" ", err)
|
|
||||||
bot.Send(chat, pre+err.Error(), tmpBtn)
|
|
||||||
SignErr = append(SignErr, se)
|
|
||||||
ErrorTimes[u.msId]++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Println(u.msId + " Sign OK!")
|
|
||||||
SignOk[u.tgId]++
|
|
||||||
signOk++
|
|
||||||
}
|
|
||||||
fmt.Println("Sign End,Start Send")
|
|
||||||
var isSend map[int64]bool
|
|
||||||
isSend = make(map[int64]bool)
|
|
||||||
//用户任务反馈
|
|
||||||
for _, u := range data {
|
|
||||||
chat, err := bot.ChatByID(strconv.FormatInt(u.tgId, 10))
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("Send Result ERROR: ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
//错误上限账户清退
|
|
||||||
if ErrorTimes[u.msId] == ErrMaxTimes {
|
|
||||||
logger.Println(u.msId + " Error Limit")
|
|
||||||
if ok, err := DelData(u.msId); !ok {
|
|
||||||
logger.Println(err)
|
|
||||||
} else {
|
|
||||||
UnbindUser = append(UnbindUser, u.msId+" ( @"+chat.Username+" )")
|
|
||||||
_, err = bot.Send(chat, "您的账户因达到错误上限而被自动解绑\n后会有期!\n\n别名: "+u.alias+"\nclient_id: "+u.clientId+"\nclient_secret: "+u.clientSecret)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if !isSend[u.tgId] {
|
|
||||||
//静默发送,过多消息很烦
|
|
||||||
_, err = bot.Send(chat, "任务反馈\n时间: "+time.Now().Format("2006-01-02 15:04:05")+"\n结果: "+strconv.Itoa(SignOk[u.tgId])+"/"+strconv.Itoa(GetBindNum(u.tgId)), &tb.SendOptions{DisableNotification: true})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
isSend[u.tgId] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//管理员任务反馈
|
|
||||||
var ErrUserStr string
|
|
||||||
var UnbindUserStr string
|
|
||||||
for _, eu := range SignErr {
|
|
||||||
ErrUserStr = ErrUserStr + eu + "\n"
|
|
||||||
}
|
|
||||||
for _, ubu := range UnbindUser {
|
|
||||||
UnbindUserStr = UnbindUserStr + ubu + "\n"
|
|
||||||
}
|
|
||||||
for _, a := range admin {
|
|
||||||
chat, err := bot.ChatByID(strconv.FormatInt(a, 10))
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bot.Send(chat, "任务反馈(管理员)\n完成时间: "+time.Now().Format("2006-01-02 15:04:05")+"\n结果: "+strconv.Itoa(signOk)+"/"+strconv.Itoa(num)+"\n错误账户:\n"+ErrUserStr+"\n清退账户:\n"+UnbindUserStr)
|
|
||||||
}
|
|
||||||
fmt.Println("----Task End----")
|
|
||||||
}
|
|
||||||
func GetAdmin() []int64 {
|
|
||||||
var result []int64
|
|
||||||
admins := strings.Split(viper.GetString("admin"), ",")
|
|
||||||
for _, v := range admins {
|
|
||||||
id, _ := strconv.ParseInt(v, 10, 64)
|
|
||||||
result = append(result, id)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
func InitLogger() {
|
|
||||||
if !PathExists(bLogBasePath) {
|
|
||||||
os.Mkdir(bLogBasePath, 0773)
|
|
||||||
}
|
|
||||||
|
|
||||||
path := bLogBasePath + time.Now().Format("2006-01-02") + ".log"
|
|
||||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0773)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
writers := []io.Writer{
|
|
||||||
f,
|
|
||||||
os.Stdout}
|
|
||||||
faoWriter := io.MultiWriter(writers...)
|
|
||||||
logger = log.New(faoWriter, "【E5Sub】", log.Ldate|log.Ltime|log.Lshortfile)
|
|
||||||
}
|
|
||||||
9
go.mod
9
go.mod
@ -1,14 +1,19 @@
|
|||||||
module main
|
module github.com/iyear/E5SubBot
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fsnotify/fsnotify v1.4.7
|
github.com/fsnotify/fsnotify v1.4.7
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/guonaihong/gout v0.1.12
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/robfig/cron/v3 v3.0.0
|
github.com/robfig/cron/v3 v3.0.0
|
||||||
github.com/spf13/viper v1.6.2
|
github.com/spf13/viper v1.6.2
|
||||||
github.com/tidwall/gjson v1.6.0
|
github.com/tidwall/gjson v1.6.0
|
||||||
github.com/tidwall/pretty v1.0.1 // indirect
|
github.com/tidwall/pretty v1.0.1 // indirect
|
||||||
|
go.uber.org/zap v1.10.0
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
gopkg.in/tucnak/telebot.v2 v2.0.0-20200328014118-dd123e949ee1
|
gopkg.in/tucnak/telebot.v2 v2.0.0-20200328014118-dd123e949ee1
|
||||||
|
gorm.io/driver/mysql v1.1.1
|
||||||
|
gorm.io/gorm v1.21.9
|
||||||
)
|
)
|
||||||
|
|||||||
338
go.sum
338
go.sum
@ -1,60 +1,14 @@
|
|||||||
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
code.gitea.io/sdk/gitea v0.0.0-20200128061546-ea2b5af37297 h1:2jEu+HD5Hk87b8HiztAoTo+bSkerjFik3mU5z8sJycg=
|
|
||||||
code.gitea.io/sdk/gitea v0.0.0-20200128061546-ea2b5af37297/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
|
||||||
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
|
||||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
|
|
||||||
contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
|
|
||||||
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
|
|
||||||
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
|
|
||||||
github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
|
|
||||||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
|
|
||||||
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
|
||||||
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
|
||||||
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
|
|
||||||
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
|
|
||||||
github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
|
|
||||||
github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
|
|
||||||
github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
|
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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
|
||||||
github.com/apex/log v1.1.1 h1:BwhRZ0qbjYtTob0I+2M+smavV0kOC8XgcnGZcyL9liA=
|
|
||||||
github.com/apex/log v1.1.1/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA=
|
|
||||||
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
|
|
||||||
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
|
||||||
github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
|
||||||
github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
|
||||||
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
|
||||||
github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
|
||||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
|
||||||
github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw=
|
|
||||||
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
|
|
||||||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e h1:V9a67dfYqPLAvzk5hMQOXYJlZ4SLIXgyKIE+ZiHzgGQ=
|
|
||||||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
|
|
||||||
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e h1:hHg27A0RSSp2Om9lubZpiMgVbvn39bsUmW9U5h0twqc=
|
|
||||||
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
@ -63,140 +17,109 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
|
||||||
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
|
||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
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.0 h1:Lb3veSYoGaNck69fV2+Vf2juLSsHpMTf3Vk5+X+EDJg=
|
||||||
|
github.com/gin-gonic/gin v1.6.0/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
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-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
|
||||||
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
|
||||||
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0 h1:BW6OvS3kpT5UEPbCZ+KyX/OB4Ks9/MNMhWjqPPkZxsE=
|
|
||||||
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
|
|
||||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/goreleaser/goreleaser v0.129.0 h1:hJHsgxxNck3oe/MU4K+yznH2qgAVGNcxARTRP8ODSRk=
|
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||||
github.com/goreleaser/goreleaser v0.129.0/go.mod h1:tzHV+xcU9AJMYNby0QS0lHm1DRrTCBkJXW9ic2reepY=
|
|
||||||
github.com/goreleaser/nfpm v1.2.1 h1:AEnu9XVmupRDTR930Z2rAs31Mj6sLIPxFcR9ESYvgDA=
|
|
||||||
github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w=
|
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||||
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/guonaihong/gout v0.1.12 h1:PE2nJofrLpxpoHOTJ4NWcyPBU6gbjWjp5Du3DMsAv2Y=
|
||||||
github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8=
|
github.com/guonaihong/gout v0.1.12/go.mod h1:JkjNv1G2oRWvFgP/r4DUbYhoeIBB0zMP2j1ID+5CYpU=
|
||||||
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
|
||||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
|
||||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kamilsk/retry/v4 v4.7.2 h1:8C33aqTQtTSvPf7MpLZ4xSY4JZK2YCvY+hTlsbiHNq8=
|
|
||||||
github.com/kamilsk/retry/v4 v4.7.2/go.mod h1:pIQtBtycHTXScrJmpu3N2SSBT07s07Uruq2Au1aRLks=
|
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
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.1/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/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/mattn/go-zglob v0.0.1 h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY=
|
|
||||||
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
|
|
||||||
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
|
|
||||||
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
|
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
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/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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
@ -207,20 +130,18 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
|||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
|
||||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
|
||||||
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
|
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
|
||||||
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4=
|
||||||
github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I=
|
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
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/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
|
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
|
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||||
@ -235,184 +156,99 @@ github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
|
|||||||
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
|
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/techoner/gophp v0.2.0 h1:vVFoS2XC/NZariagUOhAGqC8p/Ws8R8ARYpj/9lTIAo=
|
|
||||||
github.com/techoner/gophp v0.2.0/go.mod h1:NOxB/qoTl4+G82CkQp60T18Az5rOTufCqm83x9i/u7M=
|
|
||||||
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
|
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
|
||||||
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||||
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8=
|
github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8=
|
||||||
github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
|
|
||||||
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
|
|
||||||
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
|
|
||||||
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
|
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/xanzy/go-gitlab v0.28.0 h1:nsyjDVvBrP4KRXEN4b1m1ewiqmTNL4BOWW041nKGV7k=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/xanzy/go-gitlab v0.28.0/go.mod h1:t4Bmvnxj7k37S4Y17lfLx+nLqkf/oQwT2HagfWKv5Og=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
gocloud.dev v0.19.0 h1:EDRyaRAnMGSq/QBto486gWFxMLczAfIYUmusV7XLNBM=
|
|
||||||
gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/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-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
|
|
||||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
|
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
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 h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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 h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
|
||||||
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/tucnak/telebot.v2 v2.0.0-20200301001213-9852df39ae6c h1:+7l/yyky9hchNME0hDMl+cA+wVlHQGte/5EwKHeSqoc=
|
|
||||||
gopkg.in/tucnak/telebot.v2 v2.0.0-20200301001213-9852df39ae6c/go.mod h1:+//wyPtHTeW2kfyEBwB05Hqnxev7AGrsLIyylSH++KU=
|
|
||||||
gopkg.in/tucnak/telebot.v2 v2.0.0-20200328014118-dd123e949ee1 h1:L9z5n/aaxpAjeEMHu4PfZ7GgQa0lRirKW5G+LHuNQDU=
|
gopkg.in/tucnak/telebot.v2 v2.0.0-20200328014118-dd123e949ee1 h1:L9z5n/aaxpAjeEMHu4PfZ7GgQa0lRirKW5G+LHuNQDU=
|
||||||
gopkg.in/tucnak/telebot.v2 v2.0.0-20200328014118-dd123e949ee1/go.mod h1:+//wyPtHTeW2kfyEBwB05Hqnxev7AGrsLIyylSH++KU=
|
gopkg.in/tucnak/telebot.v2 v2.0.0-20200328014118-dd123e949ee1/go.mod h1:+//wyPtHTeW2kfyEBwB05Hqnxev7AGrsLIyylSH++KU=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gorm.io/driver/mysql v1.1.1 h1:yr1bpyqiwuSPJ4aGGUX9nu46RHXlF8RASQVb1QQNcvo=
|
||||||
|
gorm.io/driver/mysql v1.1.1/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU=
|
||||||
|
gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM=
|
||||||
|
gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw=
|
||||||
|
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||||
|
gorm.io/gorm v1.21.9 h1:INieZtn4P2Pw6xPJ8MzT0G4WUOsHq3RhfuDF1M6GW0E=
|
||||||
|
gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
|
|||||||
308
handle.go
308
handle.go
@ -1,308 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
tb "gopkg.in/tucnak/telebot.v2"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
bLogBasePath string = "./log/"
|
|
||||||
bStartContent string = "欢迎使用E5SubBot!"
|
|
||||||
bHelpContent string = `
|
|
||||||
命令:
|
|
||||||
/my 查看已绑定账户信息
|
|
||||||
/bind 绑定新账户
|
|
||||||
/unbind 解绑账户
|
|
||||||
/export 导出账户信息(JSON格式)
|
|
||||||
/help 帮助
|
|
||||||
/task 手动执行一次任务(管理员)
|
|
||||||
/log 获取最近日志文件(管理员)
|
|
||||||
源码及使用方法:https://github.com/iyear/E5SubBot
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
UserStatus map[int64]int
|
|
||||||
UserCid map[int64]string
|
|
||||||
UserCSecret map[int64]string
|
|
||||||
ErrorTimes map[string]int //错误次数
|
|
||||||
BindMaxNum int
|
|
||||||
ErrMaxTimes int
|
|
||||||
notice string
|
|
||||||
admin []int64
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
USNone = iota
|
|
||||||
USBind1
|
|
||||||
USBind2
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
//read config
|
|
||||||
viper.SetConfigName("config")
|
|
||||||
viper.AddConfigPath(".")
|
|
||||||
err := viper.ReadInConfig()
|
|
||||||
CheckErr(err)
|
|
||||||
|
|
||||||
viper.SetDefault("errlimit", 5)
|
|
||||||
viper.SetDefault("bindmax", 5)
|
|
||||||
|
|
||||||
BindMaxNum = viper.GetInt("bindmax")
|
|
||||||
ErrMaxTimes = viper.GetInt("errlimit")
|
|
||||||
notice = viper.GetString("notice")
|
|
||||||
admin = GetAdmin()
|
|
||||||
|
|
||||||
viper.WatchConfig()
|
|
||||||
viper.OnConfigChange(func(e fsnotify.Event) {
|
|
||||||
BindMaxNum = viper.GetInt("bindmax")
|
|
||||||
ErrMaxTimes = viper.GetInt("errlimit")
|
|
||||||
notice = viper.GetString("notice")
|
|
||||||
admin = GetAdmin()
|
|
||||||
})
|
|
||||||
|
|
||||||
UserStatus = make(map[int64]int)
|
|
||||||
UserCid = make(map[int64]string)
|
|
||||||
UserCSecret = make(map[int64]string)
|
|
||||||
ErrorTimes = make(map[string]int)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bStart(m *tb.Message) {
|
|
||||||
bot.Send(m.Sender, bStartContent)
|
|
||||||
bHelp(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bMy(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Manager Users")
|
|
||||||
data := QueryDataByTG(m.Chat.ID)
|
|
||||||
var inlineKeys [][]tb.InlineButton
|
|
||||||
for _, u := range data {
|
|
||||||
inlineBtn := tb.InlineButton{
|
|
||||||
Unique: "my" + u.msId,
|
|
||||||
Text: u.alias,
|
|
||||||
Data: u.msId,
|
|
||||||
}
|
|
||||||
bot.Handle(&inlineBtn, bMyInlineBtn)
|
|
||||||
inlineKeys = append(inlineKeys, []tb.InlineButton{inlineBtn})
|
|
||||||
}
|
|
||||||
bot.Send(m.Chat, "选择一个账户查看具体信息\n\n绑定数: "+strconv.Itoa(GetBindNum(m.Chat.ID))+"/"+strconv.Itoa(BindMaxNum), &tb.ReplyMarkup{InlineKeyboard: inlineKeys})
|
|
||||||
}
|
|
||||||
func bMyInlineBtn(c *tb.Callback) {
|
|
||||||
logger.Println(strconv.FormatInt(c.Message.Chat.ID, 10) + " Get User Info")
|
|
||||||
r := QueryDataByMS(c.Data)
|
|
||||||
u := r[0]
|
|
||||||
bot.Send(c.Message.Chat, "信息\n别名:"+u.alias+"\nMS_ID(MD5): "+u.msId+"\nclient_id: "+u.clientId+"\nclient_secret: "+u.clientSecret+"\n最近更新时间: "+time.Unix(u.uptime, 0).Format("2006-01-02 15:04:05"))
|
|
||||||
bot.Respond(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bBind1(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Bind")
|
|
||||||
logger.Println("ReApp: " + strconv.FormatInt(m.Chat.ID, 10))
|
|
||||||
bot.Send(m.Chat, "应用注册: [点击直达]("+MSGetReAppUrl()+")", tb.ModeMarkdown)
|
|
||||||
_, err := bot.Send(m.Chat, "请回复client_id+空格+client_secret", &tb.ReplyMarkup{ForceReply: true})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
UserStatus[m.Chat.ID] = USBind1
|
|
||||||
UserCid[m.Chat.ID] = m.Text
|
|
||||||
}
|
|
||||||
func bBind2(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Bind2")
|
|
||||||
logger.Println("Auth: " + strconv.FormatInt(m.Chat.ID, 10))
|
|
||||||
tmp := strings.Split(m.Text, " ")
|
|
||||||
if len(tmp) != 2 {
|
|
||||||
logger.Printf("%d Bind error:Wrong Bind Format\n", m.Chat.ID)
|
|
||||||
bot.Send(m.Chat, "错误的格式")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.Println("client_id: " + tmp[0] + " client_secret: " + tmp[1])
|
|
||||||
cid := tmp[0]
|
|
||||||
cse := tmp[1]
|
|
||||||
bot.Send(m.Chat, "授权账户: [点击直达]("+MSGetAuthUrl(cid)+")", tb.ModeMarkdown)
|
|
||||||
_, err := bot.Send(m.Chat, "请回复http://localhost/…… + 空格 + 别名(用于管理)", &tb.ReplyMarkup{ForceReply: true})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
UserStatus[m.Chat.ID] = USBind2
|
|
||||||
UserCid[m.Chat.ID] = cid
|
|
||||||
UserCSecret[m.Chat.ID] = cse
|
|
||||||
}
|
|
||||||
|
|
||||||
func bUnBind(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Unbind")
|
|
||||||
data := QueryDataByTG(m.Chat.ID)
|
|
||||||
var inlineKeys [][]tb.InlineButton
|
|
||||||
for _, u := range data {
|
|
||||||
inlineBtn := tb.InlineButton{
|
|
||||||
Unique: "unbind" + u.msId,
|
|
||||||
Text: u.alias,
|
|
||||||
Data: u.msId,
|
|
||||||
}
|
|
||||||
bot.Handle(&inlineBtn, bUnBindInlineBtn)
|
|
||||||
inlineKeys = append(inlineKeys, []tb.InlineButton{inlineBtn})
|
|
||||||
}
|
|
||||||
bot.Send(m.Chat, "选择一个账户将其解绑\n\n当前绑定数: "+strconv.Itoa(GetBindNum(m.Chat.ID))+"/"+strconv.Itoa(BindMaxNum), &tb.ReplyMarkup{InlineKeyboard: inlineKeys})
|
|
||||||
}
|
|
||||||
func bUnBindInlineBtn(c *tb.Callback) {
|
|
||||||
logger.Println(strconv.FormatInt(c.Message.Chat.ID, 10) + " Unbind: " + c.Data)
|
|
||||||
r := QueryDataByMS(c.Data)
|
|
||||||
u := r[0]
|
|
||||||
if ok, _ := DelData(u.msId); !ok {
|
|
||||||
logger.Println(u.msId + " UnBind ERROR")
|
|
||||||
bot.Send(c.Message.Chat, "解绑失败!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.Println(u.msId + " UnBind Success")
|
|
||||||
bot.Send(c.Message.Chat, "解绑成功!")
|
|
||||||
bot.Respond(c)
|
|
||||||
}
|
|
||||||
func bExport(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Export")
|
|
||||||
type MsMiniData struct {
|
|
||||||
Alias string
|
|
||||||
ClientId string
|
|
||||||
ClientSecret string
|
|
||||||
RefreshToken string
|
|
||||||
Other string
|
|
||||||
}
|
|
||||||
var MsMini []MsMiniData
|
|
||||||
data := QueryDataByTG(m.Chat.ID)
|
|
||||||
if len(data) == 0 {
|
|
||||||
bot.Send(m.Chat, "你还没有绑定过账户嗷~")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, u := range data {
|
|
||||||
var ms MsMiniData
|
|
||||||
ms.RefreshToken = u.refreshToken
|
|
||||||
ms.Alias = u.alias
|
|
||||||
ms.ClientId = u.clientId
|
|
||||||
ms.ClientSecret = u.clientSecret
|
|
||||||
ms.Other = u.other
|
|
||||||
MsMini = append(MsMini, ms)
|
|
||||||
}
|
|
||||||
//MarshalIndent是为json+美化,/t表缩进
|
|
||||||
export, err := json.MarshalIndent(MsMini, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
bot.Send(m.Chat, "获取JSON失败~\n"+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//fmt.Println(string(export))
|
|
||||||
fileName := "./" + strconv.FormatInt(m.Chat.ID, 10) + "_export_tmp.json"
|
|
||||||
if err = ioutil.WriteFile(fileName, export, 0644); err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
bot.Send(m.Chat, "写入临时文件失败~\n"+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
exportFile := &tb.Document{File: tb.FromDisk(fileName), FileName: strconv.FormatInt(m.Chat.ID, 10) + ".json", MIME: "text/plain"}
|
|
||||||
_, err = bot.Send(m.Chat, exportFile)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//不遗留本地文件
|
|
||||||
if exportFile.InCloud() == true && os.Remove(fileName) == nil {
|
|
||||||
logger.Println(fileName + " Has Removed")
|
|
||||||
} else {
|
|
||||||
logger.Println(fileName + " Removed ERROR")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func bHelp(m *tb.Message) {
|
|
||||||
bot.Send(m.Sender, bHelpContent+"\n"+notice, &tb.SendOptions{DisableWebPagePreview: false})
|
|
||||||
}
|
|
||||||
func bOnText(m *tb.Message) {
|
|
||||||
switch UserStatus[m.Chat.ID] {
|
|
||||||
case USNone:
|
|
||||||
{
|
|
||||||
bot.Send(m.Chat, "发送/help获取帮助嗷")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case USBind1:
|
|
||||||
{
|
|
||||||
if !m.IsReply() {
|
|
||||||
bot.Send(m.Chat, "请通过回复方式绑定")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bBind2(m)
|
|
||||||
}
|
|
||||||
case USBind2:
|
|
||||||
{
|
|
||||||
if !m.IsReply() {
|
|
||||||
bot.Send(m.Chat, "请通过回复方式绑定")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if GetBindNum(m.Chat.ID) == BindMaxNum {
|
|
||||||
bot.Send(m.Chat, "已经达到最大可绑定数")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bot.Send(m.Chat, "正在绑定中……")
|
|
||||||
err := BindUser(m, UserCid[m.Chat.ID], UserCSecret[m.Chat.ID])
|
|
||||||
if err != nil {
|
|
||||||
bot.Send(m.Chat, err.Error())
|
|
||||||
} else {
|
|
||||||
bot.Send(m.Chat, "绑定成功!")
|
|
||||||
}
|
|
||||||
UserStatus[m.Chat.ID] = USNone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func bTask(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start SignTask")
|
|
||||||
for _, a := range admin {
|
|
||||||
if a == m.Chat.ID {
|
|
||||||
SignTask()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bot.Send(m.Chat, "您没有权限执行此操作~")
|
|
||||||
}
|
|
||||||
func bLog(m *tb.Message) {
|
|
||||||
logger.Println(strconv.FormatInt(m.Chat.ID, 10) + " Start Get Logs")
|
|
||||||
flag := 0
|
|
||||||
for _, a := range admin {
|
|
||||||
if a == m.Chat.ID {
|
|
||||||
flag = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if flag == 0 {
|
|
||||||
bot.Send(m.Chat, "您没有权限执行此操作~")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logs := GetRecentLogs(bLogBasePath, 5)
|
|
||||||
var inlineKeys [][]tb.InlineButton
|
|
||||||
for _, log := range logs {
|
|
||||||
inlineBtn := tb.InlineButton{
|
|
||||||
Unique: "log" + strings.Replace(strings.TrimSuffix(filepath.Base(log), ".log"), "-", "", -1),
|
|
||||||
Text: filepath.Base(log),
|
|
||||||
Data: filepath.Base(log),
|
|
||||||
}
|
|
||||||
bot.Handle(&inlineBtn, bLogsInlineBtn)
|
|
||||||
inlineKeys = append(inlineKeys, []tb.InlineButton{inlineBtn})
|
|
||||||
}
|
|
||||||
_, err := bot.Send(m.Chat, "选择一个日志", &tb.ReplyMarkup{InlineKeyboard: inlineKeys})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func bLogsInlineBtn(c *tb.Callback) {
|
|
||||||
logger.Println(strconv.FormatInt(c.Message.Chat.ID, 10) + " Get Logs: " + c.Data)
|
|
||||||
//fmt.Println(c.Data)
|
|
||||||
//logger.Println(bLogBasePath + c.Data + ".log")
|
|
||||||
logfile := &tb.Document{File: tb.FromDisk(bLogBasePath + c.Data), FileName: c.Data, MIME: "text/plain"}
|
|
||||||
_, err := bot.Send(c.Message.Chat, logfile)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bot.Respond(c)
|
|
||||||
}
|
|
||||||
37
logger/logger.go
Normal file
37
logger/logger.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 日志切割设置
|
||||||
|
func getLogWriter() zapcore.WriteSyncer {
|
||||||
|
lumberJackLogger := &lumberjack.Logger{
|
||||||
|
Filename: "./log/latest.log", // 日志文件位置
|
||||||
|
MaxSize: 1, // 日志文件最大大小(MB)
|
||||||
|
MaxBackups: 5, // 保留旧文件最大数量
|
||||||
|
MaxAge: 30, // 保留旧文件最长天数
|
||||||
|
Compress: true, // 是否压缩旧文件
|
||||||
|
}
|
||||||
|
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(lumberJackLogger))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编码器
|
||||||
|
func getEncoder() zapcore.Encoder {
|
||||||
|
// 使用默认的JSON编码
|
||||||
|
encoderConfig := zap.NewDevelopmentEncoderConfig()
|
||||||
|
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||||
|
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||||
|
return zapcore.NewJSONEncoder(encoderConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitLogger 初始化Logger
|
||||||
|
func InitLogger() {
|
||||||
|
writeSyncer := getLogWriter()
|
||||||
|
encoder := getEncoder()
|
||||||
|
core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
|
||||||
|
zap.ReplaceGlobals(zap.New(core, zap.AddCaller()))
|
||||||
|
}
|
||||||
132
main.go
132
main.go
@ -1,135 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "github.com/iyear/E5SubBot/bots"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"golang.org/x/net/proxy"
|
|
||||||
tb "gopkg.in/tucnak/telebot.v2"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
BotToken string
|
|
||||||
Socks5 string
|
|
||||||
bot *tb.Bot
|
|
||||||
logger *log.Logger
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
dbDriverName = "mysql"
|
|
||||||
logo = `
|
|
||||||
______ _____ _____ _ ____ _
|
|
||||||
| ____| ____/ ____| | | | _ \ | |
|
|
||||||
| |__ | |__| (___ _ _| |__ | |_) | ___ | |_
|
|
||||||
| __| |___ \\___ \| | | | '_ \| _ < / _ \| __|
|
|
||||||
| |____ ___) |___) | |_| | |_) | |_) | (_) | |_
|
|
||||||
|______|____/_____/ \__,_|_.__/|____/ \___/ \__|
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
var dbPath string
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
BotStart()
|
bots.BotStart()
|
||||||
}
|
|
||||||
func BotStart() {
|
|
||||||
MakeHandle()
|
|
||||||
TaskLaunch()
|
|
||||||
logger.Println("Bot Start")
|
|
||||||
fmt.Println("------------")
|
|
||||||
bot.Start()
|
|
||||||
}
|
|
||||||
func MakeHandle() {
|
|
||||||
logger.Println("Make Handle……")
|
|
||||||
//所有用户
|
|
||||||
bot.Handle("/start", bStart)
|
|
||||||
bot.Handle("/my", bMy)
|
|
||||||
bot.Handle("/bind", bBind1)
|
|
||||||
bot.Handle("/unbind", bUnBind)
|
|
||||||
bot.Handle("/export", bExport)
|
|
||||||
bot.Handle("/help", bHelp)
|
|
||||||
bot.Handle(tb.OnText, bOnText)
|
|
||||||
//管理员
|
|
||||||
bot.Handle("/task", bTask)
|
|
||||||
bot.Handle("/log", bLog)
|
|
||||||
}
|
|
||||||
func TaskLaunch() {
|
|
||||||
task := cron.New()
|
|
||||||
//每三小时执行一次
|
|
||||||
task.AddFunc(viper.GetString("cron"), SignTask)
|
|
||||||
//log分为每天
|
|
||||||
task.AddFunc(" 0 0 * * *", InitLogger)
|
|
||||||
// */1 * * * * 1 */3 * * *
|
|
||||||
logger.Println("Cron Task Start……")
|
|
||||||
task.Start()
|
|
||||||
}
|
|
||||||
func init() {
|
|
||||||
fmt.Println(logo)
|
|
||||||
InitLogger()
|
|
||||||
//read config
|
|
||||||
logger.Println("Read Config……")
|
|
||||||
viper.SetConfigName("config")
|
|
||||||
viper.AddConfigPath(".")
|
|
||||||
err := viper.ReadInConfig()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
host := viper.GetString("mysql.host")
|
|
||||||
user := viper.GetString("mysql.user")
|
|
||||||
port := viper.GetString("mysql.port")
|
|
||||||
pwd := viper.GetString("mysql.password")
|
|
||||||
database := viper.GetString("mysql.database")
|
|
||||||
dbPath = strings.Join([]string{user, ":", pwd, "@tcp(", host, ":", port, ")/", database, "?charset=utf8"}, "")
|
|
||||||
//fmt.Println(path)
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
logger.Println("Connect MySQL Success!")
|
|
||||||
if ok, err := CreateTB(); !ok {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
BotToken = viper.GetString("bot_token")
|
|
||||||
Socks5 = viper.GetString("socks5")
|
|
||||||
//set bot
|
|
||||||
logger.Println("Bot Settings……")
|
|
||||||
Poller := &tb.LongPoller{Timeout: 15 * time.Second}
|
|
||||||
spamProtected := tb.NewMiddlewarePoller(Poller, func(upd *tb.Update) bool {
|
|
||||||
if upd.Message == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if !upd.Message.Private() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
botsettings := tb.Settings{
|
|
||||||
Token: BotToken,
|
|
||||||
Poller: spamProtected,
|
|
||||||
}
|
|
||||||
//set socks5
|
|
||||||
if Socks5 != "" {
|
|
||||||
logger.Println("Proxy:" + Socks5)
|
|
||||||
dialer, err := proxy.SOCKS5("tcp", Socks5, nil, proxy.Direct)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
httpTransport := &http.Transport{}
|
|
||||||
httpClient := &http.Client{Transport: httpTransport}
|
|
||||||
httpTransport.Dial = dialer.Dial
|
|
||||||
botsettings.Client = httpClient
|
|
||||||
}
|
|
||||||
//create bot
|
|
||||||
bot, err = tb.NewBot(botsettings)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
logger.Println("Bot: " + strconv.Itoa(bot.Me.ID) + " " + bot.Me.Username)
|
|
||||||
}
|
}
|
||||||
|
|||||||
151
model/client.go
Normal file
151
model/client.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guonaihong/gout"
|
||||||
|
"github.com/iyear/E5SubBot/config"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
ID int `gorm:"unique;primaryKey;not null"`
|
||||||
|
TgId int64 `gorm:"not null"`
|
||||||
|
RefreshToken string `gorm:"not null"`
|
||||||
|
MsId string `gorm:"not null"`
|
||||||
|
Uptime int64 `gorm:"autoUpdateTime;not null"`
|
||||||
|
Alias string `gorm:"not null"`
|
||||||
|
ClientId string `gorm:"not null"`
|
||||||
|
ClientSecret string `gorm:"not null"`
|
||||||
|
Other string
|
||||||
|
}
|
||||||
|
type ErrClient struct {
|
||||||
|
*Client
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
msApiUrl string = "https://login.microsoftonline.com"
|
||||||
|
msGraUrl string = "https://graph.microsoft.com"
|
||||||
|
redirectUri string = "http://localhost/e5sub"
|
||||||
|
scope string = "openid offline_access mail.read user.read"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) TableName() string {
|
||||||
|
return config.Mysql.Table
|
||||||
|
}
|
||||||
|
func NewClient(clientId string, clientSecret string) *Client {
|
||||||
|
return &Client{
|
||||||
|
ClientId: clientId,
|
||||||
|
ClientSecret: clientSecret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func GetMSAuthUrl(clientId string) string {
|
||||||
|
return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" + clientId + "&response_type=code&redirect_uri=" + url.QueryEscape(redirectUri) + "&response_mode=query&scope=" + url.QueryEscape(scope)
|
||||||
|
}
|
||||||
|
func GetMSRegisterAppUrl() string {
|
||||||
|
ru := "https://developer.microsoft.com/en-us/graph/quick-start?appID=_appId_&appName=_appName_&redirectUrl=http://localhost:8000&platform=option-windowsuniversal"
|
||||||
|
deeplink := "/quickstart/graphIO?publicClientSupport=false&appName=e5sub&redirectUrl=http://localhost/e5sub&allowImplicitFlow=false&ru=" + url.QueryEscape(ru)
|
||||||
|
appUrl := "https://apps.dev.microsoft.com/?deepLink=" + url.QueryEscape(deeplink)
|
||||||
|
return appUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetTokenWithCode(code string) error {
|
||||||
|
var content string
|
||||||
|
err := gout.POST(msApiUrl + "/common/oauth2/v2.0/token").
|
||||||
|
SetWWWForm(gout.H{
|
||||||
|
"client_id": c.ClientId,
|
||||||
|
"client_secret": c.ClientSecret,
|
||||||
|
"grant_type": "authorization_code",
|
||||||
|
"scope": scope,
|
||||||
|
"code": code,
|
||||||
|
"redirect_uri": redirectUri,
|
||||||
|
}).
|
||||||
|
BindBody(&content).Do()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gjson.Get(content, "token_type").String() == "Bearer" {
|
||||||
|
c.RefreshToken = gjson.Get(content, "refresh_token").String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
//getToken return accessToken and error
|
||||||
|
func (c *Client) getToken() (string, error) {
|
||||||
|
|
||||||
|
var content string
|
||||||
|
err := gout.POST(msApiUrl + "/common/oauth2/v2.0/token").
|
||||||
|
SetWWWForm(gout.H{
|
||||||
|
"client_id": c.ClientId,
|
||||||
|
"client_secret": c.ClientSecret,
|
||||||
|
"grant_type": "refresh_token",
|
||||||
|
"scope": scope,
|
||||||
|
"refresh_token": c.RefreshToken,
|
||||||
|
"redirect_uri": redirectUri,
|
||||||
|
}).
|
||||||
|
BindBody(&content).
|
||||||
|
Do()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gjson.Get(content, "token_type").String() == "Bearer" {
|
||||||
|
c.RefreshToken = gjson.Get(content, "refresh_token").String()
|
||||||
|
return gjson.Get(content, "access_token").String(), nil
|
||||||
|
}
|
||||||
|
return "", errors.New(gjson.Get(content, "error").String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserInfo return infoJSON and error
|
||||||
|
func (c *Client) GetUserInfo() (string, error) {
|
||||||
|
var (
|
||||||
|
content string
|
||||||
|
err error
|
||||||
|
accessToken string
|
||||||
|
)
|
||||||
|
if accessToken, err = c.getToken(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = gout.GET(msGraUrl + "/v1.0/me").
|
||||||
|
SetHeader(gout.H{
|
||||||
|
"Authorization": accessToken,
|
||||||
|
}).
|
||||||
|
BindBody(&content).
|
||||||
|
Do()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gjson.Get(content, "id").String() != "" {
|
||||||
|
return content, nil
|
||||||
|
}
|
||||||
|
return "", errors.New(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetOutlookMails() error {
|
||||||
|
|
||||||
|
var content string
|
||||||
|
var err error
|
||||||
|
var accessToken string
|
||||||
|
if accessToken, err = c.getToken(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = gout.GET(msGraUrl + "/v1.0/me/messages").
|
||||||
|
SetHeader(gout.H{
|
||||||
|
"Authorization": accessToken,
|
||||||
|
}).
|
||||||
|
BindBody(&content).
|
||||||
|
Do()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//这里的.需要转义,否则会按路径的方式解析
|
||||||
|
if gjson.Get(content, "@odata\\.context").String() != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(gjson.Get(content, "error").String())
|
||||||
|
}
|
||||||
32
model/db.go
Normal file
32
model/db.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/iyear/E5SubBot/config"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DB *gorm.DB
|
||||||
|
|
||||||
|
func InitDB() {
|
||||||
|
var err error
|
||||||
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
config.Mysql.User,
|
||||||
|
config.Mysql.Password,
|
||||||
|
config.Mysql.Host,
|
||||||
|
config.Mysql.Port,
|
||||||
|
config.Mysql.DB,
|
||||||
|
)
|
||||||
|
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||||
|
NowFunc: func() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorw("failed to open db", "error", err)
|
||||||
|
}
|
||||||
|
DB.AutoMigrate(&Client{})
|
||||||
|
}
|
||||||
152
mysql.go
152
mysql.go
@ -1,152 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MSData struct {
|
|
||||||
tgId int64
|
|
||||||
refreshToken string
|
|
||||||
msId string
|
|
||||||
uptime int64
|
|
||||||
alias string
|
|
||||||
clientId string
|
|
||||||
clientSecret string
|
|
||||||
other string
|
|
||||||
}
|
|
||||||
|
|
||||||
//update data by msId
|
|
||||||
func UpdateData(u MSData) (bool, error) {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
sqlString := `UPDATE users set tg_id=?,refresh_token=?,uptime=?,alias=?,client_id=?,client_secret=?,other=? where ms_id=?`
|
|
||||||
stmt, err := db.Prepare(sqlString)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
_, err = stmt.Exec(u.tgId, u.refreshToken, u.uptime, u.alias, u.clientId, u.clientSecret, u.other, u.msId)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//add data
|
|
||||||
func AddData(u MSData) (bool, error) {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
sqlString := `
|
|
||||||
INSERT INTO users (tg_id, refresh_token,ms_id, uptime,alias,client_id,client_secret,other)
|
|
||||||
VALUES (?,?,?,?,?,?,?,?)`
|
|
||||||
stmt, err := db.Prepare(sqlString)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
_, err = stmt.Exec(u.tgId, u.refreshToken, u.msId, u.uptime, u.alias, u.clientId, u.clientSecret, u.other)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//del data by ms_id
|
|
||||||
func DelData(msId string) (bool, error) {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
sqlString := `delete from users where ms_id=?`
|
|
||||||
stmt, err := db.Prepare(sqlString)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
res, err := stmt.Exec(msId)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
_, err = res.RowsAffected()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
func QueryData(rows *sql.Rows) []MSData {
|
|
||||||
|
|
||||||
var result = make([]MSData, 0)
|
|
||||||
defer rows.Close()
|
|
||||||
for rows.Next() {
|
|
||||||
var (
|
|
||||||
tgIdt, uptimet int64
|
|
||||||
refresht, othert, msidt, aliast, clientIdt, clientSet string
|
|
||||||
)
|
|
||||||
rows.Scan(&tgIdt, &refresht, &msidt, &uptimet, &aliast, &clientIdt, &clientSet, &othert)
|
|
||||||
//fmt.Println(string(tgNamet) + "=>" + uptimet.Format("2006-01-02 15:04:05"))
|
|
||||||
result = append(result, MSData{tgIdt, refresht, msidt, uptimet, aliast, clientIdt, clientSet, othert})
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
func QueryDataByMS(msId string) []MSData {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
rows, err := db.Query("select * from users where ms_id = ?", msId)
|
|
||||||
CheckErr(err)
|
|
||||||
return QueryData(rows)
|
|
||||||
}
|
|
||||||
|
|
||||||
func QueryDataAll() []MSData {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
rows, err := db.Query("select * from users ")
|
|
||||||
CheckErr(err)
|
|
||||||
return QueryData(rows)
|
|
||||||
}
|
|
||||||
|
|
||||||
//query data by tg_id
|
|
||||||
func QueryDataByTG(tgId int64) []MSData {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
rows, err := db.Query("select * from users where tg_id = ?", tgId)
|
|
||||||
CheckErr(err)
|
|
||||||
return QueryData(rows)
|
|
||||||
}
|
|
||||||
func CreateTB() (bool, error) {
|
|
||||||
db, err := sql.Open(dbDriverName, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
sqltable := `
|
|
||||||
create table if not exists users
|
|
||||||
(
|
|
||||||
tg_id INTEGER,
|
|
||||||
refresh_token TEXT,
|
|
||||||
ms_id VARCHAR(255),
|
|
||||||
uptime INTEGER,
|
|
||||||
alias VARCHAR(255),
|
|
||||||
client_id VARCHAR(255),
|
|
||||||
client_secret VARCHAR(255),
|
|
||||||
other TEXT
|
|
||||||
);`
|
|
||||||
_, err = db.Exec(sqltable)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
@ -43,7 +43,6 @@ func MSFirGetToken(code, cid, cse string) (access string, refresh string, Error
|
|||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
req.Close = true
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
@ -79,7 +78,6 @@ func MSGetToken(refreshtoken, cid, cse string) (access string, newRefreshToken s
|
|||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
req.Close = true
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
@ -107,7 +105,6 @@ func MSGetUserInfo(accesstoken string) (json string, Error error) {
|
|||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
req.Close = true
|
|
||||||
req.Header.Set("Authorization", accesstoken)
|
req.Header.Set("Authorization", accesstoken)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -134,7 +131,6 @@ func OutLookGetMails(accesstoken string) (bool, error) {
|
|||||||
logger.Println(err)
|
logger.Println(err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
req.Close = true
|
|
||||||
req.Header.Set("Authorization", accesstoken)
|
req.Header.Set("Authorization", accesstoken)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
59
task/sign.go
Normal file
59
task/sign.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/iyear/E5SubBot/config"
|
||||||
|
"github.com/iyear/E5SubBot/model"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Sign(clients []*model.Client) []*model.ErrClient {
|
||||||
|
var errClients []*model.ErrClient
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
in := make(chan *model.ErrClient, 5)
|
||||||
|
out := make(chan *model.ErrClient, 5)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, client := range clients {
|
||||||
|
in <- &model.ErrClient{
|
||||||
|
Client: client,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(in)
|
||||||
|
}()
|
||||||
|
for i := 0; i < config.MaxGoroutines; i++ {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case errCli, f := <-in:
|
||||||
|
if !f {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := errCli.GetOutlookMails()
|
||||||
|
errCli.Err = err
|
||||||
|
out <- errCli
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
for i := 0; i < len(clients); i++ {
|
||||||
|
errClient := <-out
|
||||||
|
if errClient.Err == nil {
|
||||||
|
fmt.Printf("%s OK\n", errClient.MsId)
|
||||||
|
} else {
|
||||||
|
zap.S().Errorw("failed to sign",
|
||||||
|
"error", errClient.Err,
|
||||||
|
"id", errClient.ID,
|
||||||
|
)
|
||||||
|
//fmt.Printf("%s %s\n",errClient.MsId,errClient.Err)
|
||||||
|
}
|
||||||
|
errClients = append(errClients, errClient)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
return errClients
|
||||||
|
}
|
||||||
@ -1,33 +1,21 @@
|
|||||||
package main
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//true=>no error
|
// Min true=>no error
|
||||||
func Min(x, y int) int {
|
func Min(x, y int) int {
|
||||||
if x < y {
|
if x < y {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
func CheckErr(err error) bool {
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
fmt.Println("ERROR")
|
|
||||||
panic(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
func PathExists(path string) bool {
|
func PathExists(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -38,21 +26,6 @@ func PathExists(path string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func GetBetweenStr(str, start, end string) string {
|
|
||||||
n := strings.Index(str, start)
|
|
||||||
if n == -1 {
|
|
||||||
n = 0
|
|
||||||
} else {
|
|
||||||
n = n + len(start)
|
|
||||||
}
|
|
||||||
str = string([]byte(str)[n:])
|
|
||||||
m := strings.Index(str, end)
|
|
||||||
if m == -1 {
|
|
||||||
m = len(str)
|
|
||||||
}
|
|
||||||
str = string([]byte(str)[:m])
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
func GetURLValue(Url, key string) string {
|
func GetURLValue(Url, key string) string {
|
||||||
u, _ := url.Parse(Url)
|
u, _ := url.Parse(Url)
|
||||||
query := u.Query()
|
query := u.Query()
|
||||||
@ -60,19 +33,17 @@ func GetURLValue(Url, key string) string {
|
|||||||
return query.Get(key)
|
return query.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回一个32位md5加密后的字符串
|
|
||||||
func GetMD5Encode(data string) string {
|
func GetMD5Encode(data string) string {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
h.Write([]byte(data))
|
h.Write([]byte(data))
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
//返回一个16位md5加密后的字符串
|
|
||||||
func Get16MD5Encode(data string) string {
|
func Get16MD5Encode(data string) string {
|
||||||
return GetMD5Encode(data)[8:24]
|
return GetMD5Encode(data)[8:24]
|
||||||
}
|
}
|
||||||
|
|
||||||
//只返回文件名
|
// GetPathFiles only return file name
|
||||||
func GetPathFiles(path string) []string {
|
func GetPathFiles(path string) []string {
|
||||||
files, _ := ioutil.ReadDir(path)
|
files, _ := ioutil.ReadDir(path)
|
||||||
var t []string
|
var t []string
|
||||||
@ -86,13 +57,12 @@ func GetPathFiles(path string) []string {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
//输入文件夹路径,返回最近n个log的路径,不到n个返回所有
|
|
||||||
func GetRecentLogs(path string, n int) []string {
|
func GetRecentLogs(path string, n int) []string {
|
||||||
var paths []string
|
var paths []string
|
||||||
if !PathExists(path) {
|
if !PathExists(path) {
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
//path末尾检查/
|
|
||||||
if path[len(path)-1:] != "/" {
|
if path[len(path)-1:] != "/" {
|
||||||
path += "/"
|
path += "/"
|
||||||
}
|
}
|
||||||
@ -100,7 +70,6 @@ func GetRecentLogs(path string, n int) []string {
|
|||||||
d, _ := time.ParseDuration("-24h")
|
d, _ := time.ParseDuration("-24h")
|
||||||
//不到n个返回所有
|
//不到n个返回所有
|
||||||
nt := Min(n, len(GetPathFiles(path)))
|
nt := Min(n, len(GetPathFiles(path)))
|
||||||
//fmt.Println(nt)
|
|
||||||
for i := 1; i <= nt; {
|
for i := 1; i <= nt; {
|
||||||
if PathExists(path + data.Format("2006-01-02") + ".log") {
|
if PathExists(path + data.Format("2006-01-02") + ".log") {
|
||||||
paths = append(paths, data.Format("2006-01-02")+".log")
|
paths = append(paths, data.Format("2006-01-02")+".log")
|
||||||
@ -110,3 +79,9 @@ func GetRecentLogs(path string, n int) []string {
|
|||||||
}
|
}
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
func IF(f bool, a interface{}, b interface{}) interface{} {
|
||||||
|
if f {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user