Keep It Simple Stupid Stats (KISSS)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

143 lines
3.8 KiB

package main
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"path"
"strconv"
)
type telegram struct {
botToken string
}
type telegramUpdate struct {
Message struct {
Chat struct {
Id int `json:"id"`
} `json:"chat"`
Id int `json:"message_id"`
Text string `json:"text"`
} `json:"message"`
}
func initTelegram() {
if appConfig.TGBotToken == "" {
fmt.Println("Telegram not configured.")
return
}
tg := &telegram{
botToken: appConfig.TGBotToken,
}
username, err := tg.getBotUsername()
if err != nil {
fmt.Println("Failed to setup Telegram:", err)
return
}
err = tg.setTelegramHook()
if err != nil {
fmt.Println("Failed to setup Telegram webhook:", err)
return
}
fmt.Println("Authorized Telegram bot on account", username)
app.telegram = tg
}
func initTelegramRouter() {
app.router.HandleFunc(path.Join("/telegramHook", appConfig.TGHookSecret), TelegramHookHandler)
}
func TelegramHookHandler(w http.ResponseWriter, r *http.Request) {
tgUpdate := &telegramUpdate{}
err := json.NewDecoder(r.Body).Decode(tgUpdate)
if err != nil {
http.Error(w, "Failed to decode body", http.StatusBadRequest)
return
}
go respondToTelegramUpdate(tgUpdate)
return
}
var telegramBaseUrl = "https://api.telegram.org/bot"
func (t *telegram) getBotUsername() (string, error) {
tgUrl, err := url.Parse(telegramBaseUrl + t.botToken + "/getMe")
if err != nil {
return "", errors.New("failed to create Telegram request")
}
req, _ := http.NewRequest(http.MethodPost, tgUrl.String(), nil)
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode != 200 {
return "", errors.New("failed to get Telegram bot info")
}
tgBotInfo := &struct {
Ok bool `json:"ok"`
Result struct {
Id int `json:"id"`
Username string `json:"username"`
} `json:"result"`
}{}
err = json.NewDecoder(resp.Body).Decode(tgBotInfo)
_ = resp.Body.Close()
if err != nil || !tgBotInfo.Ok {
return "", errors.New("failed to parse Telegram bot info")
}
// If getMe returns no username, but only an ID for whatever reason
if len(tgBotInfo.Result.Username) == 0 {
tgBotInfo.Result.Username = strconv.Itoa(tgBotInfo.Result.Id)
}
return tgBotInfo.Result.Username, nil
}
func (t *telegram) setTelegramHook() error {
if len(appConfig.BaseUrl) < 1 {
return errors.New("base URL not configured")
}
hookUrl, e := url.Parse(appConfig.BaseUrl)
if e != nil {
return errors.New("failed to parse base URL")
}
hookUrl.Path = path.Join(hookUrl.Path, path.Join("telegramHook", appConfig.TGHookSecret))
params := url.Values{}
params.Add("url", hookUrl.String())
params.Add("allowed_updates", "[\"message\"]")
tgUrl, err := url.Parse(telegramBaseUrl + t.botToken + "/setWebhook")
if err != nil {
return errors.New("failed to create Telegram request")
}
tgUrl.RawQuery = params.Encode()
req, _ := http.NewRequest(http.MethodPost, tgUrl.String(), nil)
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode != 200 {
return errors.New("failed to set Telegram webhook")
}
fmt.Println("Telegram webhook URL:", hookUrl.String())
return nil
}
func (t *telegram) sendMessage(chat int, message string) error {
return t.replyToMessage(chat, message, 0)
}
func (t *telegram) replyToMessage(chat int, message string, replyTo int) error {
params := url.Values{}
params.Add("chat_id", strconv.Itoa(chat))
if replyTo != 0 {
params.Add("reply_to_message_id", strconv.Itoa(replyTo))
}
params.Add("text", message)
tgUrl, err := url.Parse(telegramBaseUrl + t.botToken + "/sendMessage")
if err != nil {
return errors.New("failed to create Telegram request")
}
tgUrl.RawQuery = params.Encode()
req, _ := http.NewRequest(http.MethodPost, tgUrl.String(), nil)
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode != 200 {
return errors.New("failed to send Telegram message")
}
return nil
}