From a5b5ca5897aefaa40aed255b8d5ef1ccea1be4f2 Mon Sep 17 00:00:00 2001 From: taz Date: Sun, 10 Aug 2025 23:50:40 +0300 Subject: [PATCH] first commit --- bridge.go | 63 ++++++++++++++++++++++++++++++++++++ discord_listener.go | 17 ++++++++++ go.mod | 3 ++ main.go | 77 ++++++++++++++++++++++++++++++++++++++++++++ telegram_listener.go | 23 +++++++++++++ vk_listener.go | 17 ++++++++++ 6 files changed, 200 insertions(+) create mode 100644 bridge.go create mode 100644 discord_listener.go create mode 100644 go.mod create mode 100644 main.go create mode 100644 telegram_listener.go create mode 100644 vk_listener.go diff --git a/bridge.go b/bridge.go new file mode 100644 index 0000000..4c27bac --- /dev/null +++ b/bridge.go @@ -0,0 +1,63 @@ +package main + +import ( + "log" + "os" + + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "github.com/bwmarrin/discordgo" + "github.com/SevereCloud/vksdk/v2/api" +) + +// Структура для хранения клиентов +type Bridge struct { + Telegram *tgbotapi.BotAPI + Discord *discordgo.Session + VK *api.VK +} + +func NewBridge(telegramToken, discordToken, vkToken string) (*Bridge, error) { + // Telegram + tgBot, err := tgbotapi.NewBotAPI(telegramToken) + if err != nil { + return nil, err + } + + // Discord + dg, err := discordgo.New("Bot " + discordToken) + if err != nil { + return nil, err + } + + // VK + vk := api.NewVK(vkToken) + + return &Bridge{ + Telegram: tgBot, + Discord: dg, + VK: vk, + }, nil +} + + // Отправка сообщения в Telegram + func (b *Bridge) SendToTelegram(chatID int64, text string) error { + msg := tgbotapi.NewMessage(chatID, text) + _, err := b.Telegram.Send(msg) + return err + } + + // Отправка сообщения в Discord + func (b *Bridge) SendToDiscord(channelID, text string) error { + _, err := b.Discord.ChannelMessageSend(channelID, text) + return err + } + + // Отправка сообщения в VK + func (b *Bridge) SendToVK(peerID int, text string) error { + _, err := b.VK.MessagesSend(api.Params{ + "peer_id": peerID, + "message": text, + "random_id": 0, + }) + return err + } diff --git a/discord_listener.go b/discord_listener.go new file mode 100644 index 0000000..a0cc192 --- /dev/null +++ b/discord_listener.go @@ -0,0 +1,17 @@ +package main + +import ( + "log" + "github.com/bwmarrin/discordgo" +) + +func (b *Bridge) StartDiscordListener(forward func(text string, from string)) { + b.Discord.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.Bot { + return + } + log.Printf("[Discord] %s: %s", m.Author.Username, m.Content) + forward(m.Content, m.Author.Username) + }) + _ = b.Discord.Open() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fff2b5f --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module go-chat-bridge + +go 1.22 diff --git a/main.go b/main.go new file mode 100644 index 0000000..c270b0b --- /dev/null +++ b/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "log" + "os" +) + +func main() { + log.Println("Go Chat Bridge запущен.") + + telegramToken := os.Getenv("TELEGRAM_TOKEN") + discordToken := os.Getenv("DISCORD_TOKEN") + vkToken := os.Getenv("VK_TOKEN") + + if telegramToken == "" || discordToken == "" || vkToken == "" { + log.Fatal("Необходимо задать переменные окружения TELEGRAM_TOKEN, DISCORD_TOKEN, VK_TOKEN") + } + + bridge, err := NewBridge(telegramToken, discordToken, vkToken) + if err != nil { + log.Fatalf("Ошибка инициализации Bridge: %v", err) + } + + log.Println("Bridge успешно инициализирован:", bridge) + + // Получаем ID чатов/каналов из переменных окружения + telegramChatID := os.Getenv("TELEGRAM_CHAT_ID") // int64 + discordChannelID := os.Getenv("DISCORD_CHANNEL_ID") // string + vkPeerID := os.Getenv("VK_PEER_ID") // int + + forward := func(text string, from string) { + log.Printf("[Bridge] Пересылка сообщения от %s: %s", from, text) + + // Определяем источник и рассылаем в остальные платформы + switch { + case from == "telegram": + // В Discord и VK + if discordChannelID != "" { + _ = bridge.SendToDiscord(discordChannelID, "[TG] "+text) + } + if vkPeerID != "" { + // конвертация vkPeerID в int + if id, err := strconv.Atoi(vkPeerID); err == nil { + _ = bridge.SendToVK(id, "[TG] "+text) + } + } + case from == "discord": + // В Telegram и VK + if telegramChatID != "" { + if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { + _ = bridge.SendToTelegram(id, "[DS] "+text) + } + } + if vkPeerID != "" { + if id, err := strconv.Atoi(vkPeerID); err == nil { + _ = bridge.SendToVK(id, "[DS] "+text) + } + } + case from == "vk": + // В Telegram и Discord + if telegramChatID != "" { + if id, err := strconv.ParseInt(telegramChatID, 10, 64); err == nil { + _ = bridge.SendToTelegram(id, "[VK] "+text) + } + } + if discordChannelID != "" { + _ = bridge.SendToDiscord(discordChannelID, "[VK] "+text) + } + } + } + + bridge.StartTelegramListener(func(text, _ string) { forward(text, "telegram") }) + bridge.StartDiscordListener(func(text, _ string) { forward(text, "discord") }) + bridge.StartVKListener(func(text, _ string) { forward(text, "vk") }) + + select {} // Блокируем main, чтобы слушатели работали +} diff --git a/telegram_listener.go b/telegram_listener.go new file mode 100644 index 0000000..830e8a8 --- /dev/null +++ b/telegram_listener.go @@ -0,0 +1,23 @@ +package main + +import ( + "log" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +func (b *Bridge) StartTelegramListener(forward func(text string, from string)) { + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 + + updates := b.Telegram.GetUpdatesChan(u) + + go func() { + for update := range updates { + if update.Message == nil { + continue + } + log.Printf("[Telegram] %s: %s", update.Message.From.UserName, update.Message.Text) + forward(update.Message.Text, update.Message.From.UserName) + } + }() +} diff --git a/vk_listener.go b/vk_listener.go new file mode 100644 index 0000000..35c7805 --- /dev/null +++ b/vk_listener.go @@ -0,0 +1,17 @@ +package main + +import ( + "log" + "context" + "github.com/SevereCloud/vksdk/v2/events" + "github.com/SevereCloud/vksdk/v2/api" +) + +func (b *Bridge) StartVKListener(forward func(text string, from string)) { + ctx := context.Background() + b.VK.OnMessageNew(func(_ context.Context, obj events.MessageNewObject) { + log.Printf("[VK] %s: %s", obj.Message.FromID, obj.Message.Text) + forward(obj.Message.Text, "vk:"+string(rune(obj.Message.FromID))) + }) + go b.VK.RunLongPoll(ctx) +}