From 7c2951fc78fe38cdce7523b23124c2d08d324ddf Mon Sep 17 00:00:00 2001 From: taz Date: Wed, 13 Aug 2025 23:35:56 +0200 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B8=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D1=8E=20?= =?UTF-8?q?=D1=81=20=D1=81=D0=B0=D0=B9=D1=82=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++ bridge.go | 29 ++++++++++++ main.go | 139 ++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 136 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index e24f6bc..b14bdfe 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,9 @@ TELEGRAM_CHAT_ID=-1001234567890 DISCORD_CHANNEL_ID=123456789012345678 VK_PEER_ID=2000000001 VK_GROUP_ID=2000000001 +SITE_API_URL=https://turn-guild.ru/ +SITE_API_TOKEN=website_webhook_token +WEBHOOK_API_KEY=brige_webhook_token ``` docker-compose автоматически подхватит эти переменные. diff --git a/bridge.go b/bridge.go index ceb284d..c86430d 100644 --- a/bridge.go +++ b/bridge.go @@ -5,8 +5,37 @@ import ( tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/bwmarrin/discordgo" "github.com/SevereCloud/vksdk/v2/api" + "net/http" + "net/url" + "fmt" + "io" + "os" ) +// Отправка сообщения на сайт +func (b *Bridge) SendToSite(text string) error { + apiURL := os.Getenv("SITE_API_URL") + token := os.Getenv("SITE_API_TOKEN") + if apiURL == "" || token == "" { + return fmt.Errorf("SITE_API_URL или SITE_API_TOKEN не заданы") + } + fullURL := fmt.Sprintf("%s?token=%s&text=%s", apiURL, token, url.QueryEscape(text)) + req, err := http.NewRequest("GET", fullURL, nil) + if err != nil { + return err + } + req.Header.Set("Accept", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + _, err = io.ReadAll(resp.Body) + return err +} // Получить имя пользователя VK по id func (b *Bridge) GetVKUserName(userID int) (string, error) { resp, err := b.VK.UsersGet(api.Params{"user_ids": userID}) diff --git a/main.go b/main.go index d8dde74..b23e2de 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,8 @@ import ( "log" "os" "strconv" + "net/http" + "encoding/json" ) func main() { @@ -32,42 +34,109 @@ func main() { forward := func(text string, from string, sender string) { log.Printf("[Bridge] Пересылка сообщения от %s (%s): %s", from, sender, text) - switch from { - case "telegram": - if discordChannelID != "" { - _ = bridge.SendToDiscord(discordChannelID, "[TG] "+sender+": "+text) - } - if vkPeerID != "" { - if id, err := strconv.Atoi(vkPeerID); err == nil { - _ = bridge.SendToVK(id, "[TG] "+sender+": "+text) - } - } - case "discord": - if telegramChatID != "" { - if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { - _ = bridge.SendToTelegram(id, "[DS] "+sender+": "+text) - } - } - if vkPeerID != "" { - if id, err := strconv.Atoi(vkPeerID); err == nil { - _ = bridge.SendToVK(id, "[DS] "+sender+": "+text) - } - } - case "vk": - if telegramChatID != "" { - if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { - _ = bridge.SendToTelegram(id, "[VK] "+sender+": "+text) - } - } - if discordChannelID != "" { - _ = bridge.SendToDiscord(discordChannelID, "[VK] "+sender+": "+text) - } - } + switch from { + case "telegram": + if discordChannelID != "" { + _ = bridge.SendToDiscord(discordChannelID, "[TG] "+sender+": "+text) + } + if vkPeerID != "" { + if id, err := strconv.Atoi(vkPeerID); err == nil { + _ = bridge.SendToVK(id, "[TG] "+sender+": "+text) + } + } + _ = bridge.SendToSite("[TG] " + sender + ": " + text) + case "discord": + if telegramChatID != "" { + if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { + _ = bridge.SendToTelegram(id, "[DS] "+sender+": "+text) + } + } + if vkPeerID != "" { + if id, err := strconv.Atoi(vkPeerID); err == nil { + _ = bridge.SendToVK(id, "[DS] "+sender+": "+text) + } + } + _ = bridge.SendToSite("[DS] " + sender + ": " + text) + case "vk": + if telegramChatID != "" { + if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { + _ = bridge.SendToTelegram(id, "[VK] "+sender+": "+text) + } + } + if discordChannelID != "" { + _ = bridge.SendToDiscord(discordChannelID, "[VK] "+sender+": "+text) + } + _ = bridge.SendToSite("[VK] " + sender + ": " + text) + case "site": + if telegramChatID != "" { + if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { + _ = bridge.SendToTelegram(id, "[SITE] "+sender+": "+text) + } + } + if discordChannelID != "" { + _ = bridge.SendToDiscord(discordChannelID, "[SITE] "+sender+": "+text) + } + if vkPeerID != "" { + if id, err := strconv.Atoi(vkPeerID); err == nil { + _ = bridge.SendToVK(id, "[SITE] "+sender+": "+text) + } + } + } } - bridge.StartTelegramListener(func(text, sender string) { forward(text, "telegram", sender) }) - bridge.StartDiscordListener(func(text, sender string) { forward(text, "discord", sender) }) - bridge.StartVKListener(func(text, sender string) { forward(text, "vk", sender) }) + bridge.StartTelegramListener(func(text, sender string) { forward(text, "telegram", sender) }) + bridge.StartDiscordListener(func(text, sender string) { forward(text, "discord", sender) }) + bridge.StartVKListener(func(text, sender string) { forward(text, "vk", sender) }) - select {} // Блокируем main, чтобы слушатели работали + // webhook endpoint + http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + apiKey := os.Getenv("WEBHOOK_API_KEY") + if apiKey == "" { + http.Error(w, "Webhook API key not set", http.StatusInternalServerError) + return + } + key := r.URL.Query().Get("key") + if key == "" { + // также можно принимать ключ в теле запроса + var req struct { + Key string `json:"key"` + Text string `json:"text"` + Sender string `json:"sender"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "Bad request", http.StatusBadRequest) + return + } + if req.Key != apiKey { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + forward(req.Text, "site", req.Sender) + w.WriteHeader(http.StatusOK) + w.Write([]byte("ok")) + return + } + if key != apiKey { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + var req struct { + Text string `json:"text"` + Sender string `json:"sender"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "Bad request", http.StatusBadRequest) + return + } + forward(req.Text, "site", req.Sender) + w.WriteHeader(http.StatusOK) + w.Write([]byte("ok")) + }) + + log.Println("Webhook listening on :8080 (/webhook)") + log.Fatal(http.ListenAndServe(":8080", nil)) }