forked from ngoduykhanh/wireguard-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.go
More file actions
161 lines (137 loc) · 3.76 KB
/
Copy pathbot.go
File metadata and controls
161 lines (137 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package telegram
import (
"fmt"
"sync"
"time"
"github.com/NicoNex/echotron/v3"
"github.com/labstack/gommon/log"
"github.com/ngoduykhanh/wireguard-ui/store"
)
type SendRequestedConfigsToTelegram func(db store.IStore, userid int64) []string
type TgBotInitDependencies struct {
DB store.IStore
SendRequestedConfigsToTelegram SendRequestedConfigsToTelegram
}
var (
Token string
AllowConfRequest bool
FloodWait int
LogLevel log.Lvl
Bot *echotron.API
BotMutex sync.RWMutex
floodWait = make(map[int64]int64)
floodMessageSent = make(map[int64]struct{})
)
func Start(initDeps TgBotInitDependencies) (err error) {
ticker := time.NewTicker(time.Minute)
defer func() {
if err != nil {
BotMutex.Lock()
Bot = nil
BotMutex.Unlock()
ticker.Stop()
}
if r := recover(); r != nil {
err = fmt.Errorf("[PANIC] recovered from panic: %v", r)
}
}()
token := Token
if token == "" || len(token) < 30 {
return
}
bot := echotron.NewAPI(token)
res, err := bot.GetMe()
if !res.Ok || err != nil {
log.Warnf("[Telegram] Unable to connect to bot.\n%v\n%v", res.Description, err)
return
}
BotMutex.Lock()
Bot = &bot
BotMutex.Unlock()
if LogLevel <= log.INFO {
fmt.Printf("[Telegram] Authorized as %s\n", res.Result.Username)
}
go func() {
for range ticker.C {
updateFloodWait()
}
}()
if !AllowConfRequest {
return
}
updatesChan := echotron.PollingUpdatesOptions(token, false, echotron.UpdateOptions{AllowedUpdates: []echotron.UpdateType{echotron.MessageUpdate}})
for update := range updatesChan {
if update.Message != nil {
userid := update.Message.Chat.ID
if _, wait := floodWait[userid]; wait {
if _, notified := floodMessageSent[userid]; notified {
continue
}
floodMessageSent[userid] = struct{}{}
_, err := bot.SendMessage(
fmt.Sprintf("You can only request your configs once per %d minutes", FloodWait),
userid,
&echotron.MessageOptions{
ReplyToMessageID: update.Message.ID,
})
if err != nil {
log.Errorf("Failed to send telegram message. Error %v", err)
}
continue
}
floodWait[userid] = time.Now().Unix()
failed := initDeps.SendRequestedConfigsToTelegram(initDeps.DB, userid)
if len(failed) > 0 {
messageText := "Failed to send configs:\n"
for _, f := range failed {
messageText += f + "\n"
}
_, err := bot.SendMessage(
messageText,
userid,
&echotron.MessageOptions{
ReplyToMessageID: update.Message.ID,
})
if err != nil {
log.Errorf("Failed to send telegram message. Error %v", err)
}
}
}
}
return err
}
func SendConfig(userid int64, clientName string, confData, qrData []byte, ignoreFloodWait bool) error {
BotMutex.RLock()
defer BotMutex.RUnlock()
if Bot == nil {
return fmt.Errorf("telegram bot is not configured or not available")
}
if _, wait := floodWait[userid]; wait && !ignoreFloodWait {
return fmt.Errorf("this client already got their config less than %d minutes ago", FloodWait)
}
if !ignoreFloodWait {
floodWait[userid] = time.Now().Unix()
}
qrAttachment := echotron.NewInputFileBytes("qr.png", qrData)
_, err := Bot.SendPhoto(qrAttachment, userid, &echotron.PhotoOptions{Caption: clientName})
if err != nil {
log.Error(err)
return fmt.Errorf("unable to send qr picture")
}
confAttachment := echotron.NewInputFileBytes(clientName+".conf", confData)
_, err = Bot.SendDocument(confAttachment, userid, nil)
if err != nil {
log.Error(err)
return fmt.Errorf("unable to send conf file")
}
return nil
}
func updateFloodWait() {
thresholdTS := time.Now().Unix() - 60*int64(FloodWait)
for userid, ts := range floodWait {
if ts < thresholdTS {
delete(floodWait, userid)
delete(floodMessageSent, userid)
}
}
}