initial
This commit is contained in:
commit
7c610d0477
11 changed files with 399 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.idea
|
||||
69
config/config.go
Normal file
69
config/config.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/disgoorg/snowflake/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
AppConf AppConfig
|
||||
TgConf TelegramConfig
|
||||
DsConf DiscordConfig
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
LogLvl string
|
||||
}
|
||||
|
||||
type TelegramConfig struct {
|
||||
Token string
|
||||
ChatID int64
|
||||
}
|
||||
|
||||
type DiscordConfig struct {
|
||||
Token string
|
||||
GuildID snowflake.ID
|
||||
ChannelID snowflake.ID
|
||||
}
|
||||
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
AppConfig{
|
||||
LogLvl: "info",
|
||||
},
|
||||
TelegramConfig{
|
||||
Token: getEnv("TELEGRAM_TOKEN", ""),
|
||||
ChatID: convertChatID(getEnv("TELEGRAM_CHANNEL_ID", "")),
|
||||
},
|
||||
DiscordConfig{
|
||||
Token: getEnv("DISCORD_TOKEN", ""),
|
||||
GuildID: convertID(getEnv("GUILD_ID", "")),
|
||||
ChannelID: convertID(getEnv("CHANNEL_ID", "")),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func convertID(channelIDStr string) snowflake.ID {
|
||||
channelIDUint, err := strconv.ParseUint(channelIDStr, 10, 64)
|
||||
if err != nil {
|
||||
log.Fatal("Cannot convert channel ID to snowflake ID")
|
||||
}
|
||||
return snowflake.ID(channelIDUint)
|
||||
}
|
||||
|
||||
func convertChatID(str string) int64 {
|
||||
id, err := strconv.ParseInt(str, 10, 64)
|
||||
if err != nil {
|
||||
log.Fatal("Cannot convert string to int64")
|
||||
}
|
||||
return id
|
||||
}
|
||||
35
config/logging.go
Normal file
35
config/logging.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func LogSetup(lvl string) {
|
||||
l, err := log.ParseLevel(lvl)
|
||||
if err != nil {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
|
||||
log.SetFormatter(
|
||||
&log.TextFormatter{
|
||||
FullTimestamp: true,
|
||||
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
|
||||
filename := path.Base(f.File)
|
||||
return fmt.Sprintf("%s()", f.Function), fmt.Sprintf(" %s:%d", filename, f.Line)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if l == log.DebugLevel {
|
||||
log.SetLevel(l)
|
||||
log.SetReportCaller(true)
|
||||
} else {
|
||||
log.SetLevel(l)
|
||||
}
|
||||
|
||||
log.SetOutput(os.Stdout)
|
||||
}
|
||||
69
discordBot/handler.go
Normal file
69
discordBot/handler.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package discordBot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/disgoorg/disgo"
|
||||
"github.com/disgoorg/disgo/bot"
|
||||
"github.com/disgoorg/disgo/discord"
|
||||
"github.com/disgoorg/disgo/gateway"
|
||||
"github.com/disgoorg/snowflake/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"tg-disc-bot/config"
|
||||
"tg-disc-bot/dto"
|
||||
)
|
||||
|
||||
type DiscordBot struct {
|
||||
ctx context.Context
|
||||
client bot.Client
|
||||
guildID snowflake.ID
|
||||
channelID snowflake.ID
|
||||
}
|
||||
|
||||
func NewDiscordBot(ctx context.Context, config config.DiscordConfig) (*DiscordBot, error) {
|
||||
var err error
|
||||
dsBot := &DiscordBot{ctx: ctx, channelID: config.ChannelID}
|
||||
|
||||
dsBot.client, err = disgo.New(config.Token,
|
||||
bot.WithGatewayConfigOpts(
|
||||
gateway.WithIntents(
|
||||
gateway.IntentGuilds,
|
||||
gateway.IntentGuildMessages,
|
||||
gateway.IntentDirectMessages,
|
||||
gateway.IntentMessageContent,
|
||||
),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dsBot, nil
|
||||
}
|
||||
|
||||
func (d *DiscordBot) Start(fromTelegram chan dto.TelegramDTO) chan dto.DiscordDTO {
|
||||
log.Info("Starting discord bot...")
|
||||
|
||||
msgChan := make(chan dto.DiscordDTO, 100)
|
||||
d.client.AddEventListeners(&messageHandler{msgChan: msgChan})
|
||||
|
||||
go func() {
|
||||
for msg := range fromTelegram {
|
||||
log.WithField("content", msg).Debug("DS | Message from Telegram")
|
||||
|
||||
m := discord.MessageCreate{Content: fmt.Sprintf("[%s]\n%s", msg.AuthorName, msg.Content)}
|
||||
|
||||
_, err := d.client.Rest().CreateMessage(d.channelID, m)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to send message to Discord: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
if err := d.client.OpenGateway(d.ctx); err != nil {
|
||||
log.Fatalf("Failed to open discord gateway %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return msgChan
|
||||
}
|
||||
28
discordBot/messages.go
Normal file
28
discordBot/messages.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package discordBot
|
||||
|
||||
import (
|
||||
"github.com/disgoorg/disgo/bot"
|
||||
"github.com/disgoorg/disgo/events"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"tg-disc-bot/dto"
|
||||
)
|
||||
|
||||
type messageHandler struct {
|
||||
msgChan chan dto.DiscordDTO
|
||||
}
|
||||
|
||||
func (m *messageHandler) OnEvent(event bot.Event) {
|
||||
if e, ok := event.(*events.MessageCreate); ok {
|
||||
if !e.Message.Author.Bot {
|
||||
message := dto.DiscordDTO{
|
||||
AuthorName: e.Message.Author.Username,
|
||||
Content: e.Message.Content,
|
||||
}
|
||||
|
||||
m.msgChan <- message
|
||||
} else {
|
||||
log.Debug("DS | Bot message, skipping")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
6
dto/discord.go
Normal file
6
dto/discord.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package dto
|
||||
|
||||
type DiscordDTO struct {
|
||||
AuthorName string
|
||||
Content string
|
||||
}
|
||||
6
dto/telegram.go
Normal file
6
dto/telegram.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package dto
|
||||
|
||||
type TelegramDTO struct {
|
||||
AuthorName string
|
||||
Content string
|
||||
}
|
||||
18
go.mod
Normal file
18
go.mod
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
module tg-disc-bot
|
||||
|
||||
go 1.24.1
|
||||
|
||||
require (
|
||||
github.com/disgoorg/disgo v0.18.15
|
||||
github.com/disgoorg/snowflake/v2 v2.0.3
|
||||
github.com/go-telegram/bot v1.14.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/disgoorg/json v1.2.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
)
|
||||
32
go.sum
Normal file
32
go.sum
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
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/disgoorg/disgo v0.18.15 h1:T24I/NdUUody4FDvb8YkhSxHtsgRKD8Ui5Vi5PXnIrQ=
|
||||
github.com/disgoorg/disgo v0.18.15/go.mod h1:dXYVH059d6aK7mI+Nh/3svSRWedNd09P7C2VX3RqbJY=
|
||||
github.com/disgoorg/json v1.2.0 h1:6e/j4BCfSHIvucG1cd7tJPAOp1RgnnMFSqkvZUtEd1Y=
|
||||
github.com/disgoorg/json v1.2.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA=
|
||||
github.com/disgoorg/snowflake/v2 v2.0.3 h1:3B+PpFjr7j4ad7oeJu4RlQ+nYOTadsKapJIzgvSI2Ro=
|
||||
github.com/disgoorg/snowflake/v2 v2.0.3/go.mod h1:W6r7NUA7DwfZLwr00km6G4UnZ0zcoLBRufhkFWgAc4c=
|
||||
github.com/go-telegram/bot v1.14.1 h1:ySVCITvYsvBSiChOmr6GolLUcWX2T/ugykc2rjIaaQg=
|
||||
github.com/go-telegram/bot v1.14.1/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad h1:qIQkSlF5vAUHxEmTbaqt1hkJ/t6skqEGYiMag343ucI=
|
||||
github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
65
main.go
Normal file
65
main.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"tg-disc-bot/config"
|
||||
"tg-disc-bot/discordBot"
|
||||
"tg-disc-bot/dto"
|
||||
"tg-disc-bot/tgBot"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := config.NewConfig()
|
||||
config.LogSetup(c.AppConf.LogLvl)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
shutdown := make(chan os.Signal, 1)
|
||||
signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
tgb, err := tgBot.NewTgBot(ctx, c.TgConf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
dsb, err := discordBot.NewDiscordBot(ctx, c.DsConf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fromDiscord := make(chan dto.DiscordDTO, 100)
|
||||
fromTelegram := make(chan dto.TelegramDTO, 100)
|
||||
|
||||
tgMsgs := tgb.Start(fromDiscord)
|
||||
dsMsgs := dsb.Start(fromTelegram)
|
||||
|
||||
log.Info("App is now running. Press CTRL-C to exit.")
|
||||
|
||||
for {
|
||||
select {
|
||||
case sig := <-shutdown:
|
||||
{
|
||||
log.WithField("type", sig).Info("terminating, close app")
|
||||
os.Exit(0)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
{
|
||||
log.Info("terminating, close app")
|
||||
os.Exit(0)
|
||||
}
|
||||
case tgMsg := <-tgMsgs:
|
||||
{
|
||||
fromTelegram <- tgMsg
|
||||
}
|
||||
case dsMsg := <-dsMsgs:
|
||||
{
|
||||
fromDiscord <- dsMsg
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
tgBot/handler.go
Normal file
70
tgBot/handler.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package tgBot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/go-telegram/bot"
|
||||
"github.com/go-telegram/bot/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"tg-disc-bot/config"
|
||||
"tg-disc-bot/dto"
|
||||
)
|
||||
|
||||
type TgBot struct {
|
||||
ctx context.Context
|
||||
bot *bot.Bot
|
||||
chatID int64
|
||||
}
|
||||
|
||||
func NewTgBot(ctx context.Context, config config.TelegramConfig) (*TgBot, error) {
|
||||
tgBot := &TgBot{ctx: ctx, chatID: config.ChatID}
|
||||
var err error
|
||||
|
||||
tgBot.bot, err = bot.New(config.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tgBot, nil
|
||||
}
|
||||
|
||||
func (b *TgBot) Start(fromDiscord chan dto.DiscordDTO) chan dto.TelegramDTO {
|
||||
|
||||
msgChan := make(chan dto.TelegramDTO, 100)
|
||||
|
||||
b.bot.RegisterHandler(
|
||||
bot.HandlerTypeMessageText,
|
||||
"",
|
||||
bot.MatchTypeContains,
|
||||
func(ctx context.Context, bt *bot.Bot, update *models.Update) {
|
||||
if update.Message != nil || !update.Message.From.IsBot {
|
||||
msg := dto.TelegramDTO{
|
||||
AuthorName: update.Message.From.Username,
|
||||
Content: update.Message.Text,
|
||||
}
|
||||
|
||||
fmt.Println(update.Message.Chat.ID)
|
||||
|
||||
msgChan <- msg
|
||||
}
|
||||
})
|
||||
|
||||
go func() {
|
||||
log.Info("Starting telegram bot...")
|
||||
b.bot.Start(b.ctx)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for msg := range fromDiscord {
|
||||
log.WithField("content", msg).Debug("TG | Message from Discord")
|
||||
m := fmt.Sprintf("[%s]\n%s", msg.AuthorName, msg.Content)
|
||||
|
||||
b.bot.SendMessage(b.ctx, &bot.SendMessageParams{
|
||||
ChatID: b.chatID,
|
||||
Text: m,
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
return msgChan
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue