package main import ( "context" "errors" "fmt" "log" "code.ivysaur.me/libnmdc" telegram "github.com/go-telegram-bot-api/telegram-bot-api" ) // NTFServer methods all run on the same thread, so no mutexes are needed for field access type NTFServer struct { bot *telegram.BotAPI upstream chan upstreamMessage chatName string inviteLink string configFile string config NTFConfig } type upstreamMessage struct { telegramUserId int64 evt libnmdc.HubEvent } func NewNTFServer(configFile string) (*NTFServer, error) { ret := NTFServer{ configFile: configFile, } cfg, err := LoadConfig(configFile) if err != nil { return nil, err } ret.config = cfg if len(cfg.BotAPIKey) == 0 { return nil, errors.New("No bot API key supplied (register with BotFather first)") } bot, err := telegram.NewBotAPI(cfg.BotAPIKey) if err != nil { return nil, fmt.Errorf("Connecting to Telegram: %s", err.Error()) } ret.bot = bot bot.Debug = true log.Printf("Connected to telegram as '%s'", bot.Self.UserName) if ret.IsSetupMode() { log.Println("Group chat ID unknown, running in setup mode only - find the groupchat ID then re-run") } else { chatInfo, err := bot.GetChat(telegram.ChatConfig{ChatID: ret.config.GroupChatID}) if err != nil { return nil, fmt.Errorf("Couldn't get supergroup properties: %s", err.Error()) } inviteLink, err := bot.GetInviteLink(telegram.ChatConfig{ChatID: ret.config.GroupChatID}) if err != nil { return nil, fmt.Errorf("Couldn't get supergroup invite link: %s", err.Error()) } log.Printf("Group chat: %s", chatInfo.Title) log.Printf("Invite link: %s", inviteLink) ret.chatName = chatInfo.Title ret.inviteLink = inviteLink } // Spawn upstream connections for all known users ret.upstream = make(chan upstreamMessage, 0) for k, v := range ret.config.KnownUsers { ret.LaunchUpstreamWorker(k, v) } return &ret, nil } func (this *NTFServer) LaunchUpstreamWorker(telegramUserId int64, hubUsername string) { ctx := context.Background() // Open NMDC connection go upstreamWorker() } func (this *NTFServer) IsSetupMode() bool { return this.config.GroupChatID == 0 } func (this *NTFServer) Run() error { updateProps := telegram.NewUpdate(0) updateProps.Timeout = 60 // seconds updateChan, err := this.bot.GetUpdatesChan(updateProps) if err != nil { return err } for update := range updateChan { this.HandleMessage(update) } return nil // Update channel was closed } func (this *NTFServer) HandleMessage(update telegram.Update) { if update.Message == nil { return } if this.IsSetupMode() { log.Printf("Message from '%s': '%s', chat ID '%d'\n", update.Message.From.UserName, update.Message.Text, update.Message.Chat.ID) } else if update.Message.Chat.ID == this.config.GroupChatID { err := this.HandleGroupMessage(update) if err != nil { log.Printf("Handling group message: %s", err.Error()) } } else if update.Message.Chat.IsPrivate() { err := this.HandleDirectMessage(update) if err != nil { log.Printf("Handling private message: %s", err.Error()) } } else { log.Printf("Message from unknown chat %d (not our supergroup, not a PM, ...)", update.Message.Chat.ID) } fmt.Printf("%#v\n", update.Message) log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) } func (this *NTFServer) HandleGroupMessage(update telegram.Update) error { // Joins: ???? if update.Message.NewChatMembers != nil && len(*update.Message.NewChatMembers) > 0 { // Users joining // Ensure that they have a valid user mapping // Create upstream NMDC connection for them } if update.Message.LeftChatMember != nil { // User parted // Close upstream NMDC connection for them } // Parts: /* &tgbotapi.Message{ MessageID:9, From:(*tgbotapi.User)(0xc420304000), Date:1527989178, Chat:(*tgbotapi.Chat)(0xc4201dc120), [...] NewChatMembers:(*[]tgbotapi.User)(nil), LeftChatMember:(*tgbotapi.User)(0xc420304050), } */ return nil } func (this *NTFServer) HandleDirectMessage(update telegram.Update) error { // Registration workflow // Find out the current status for this chat ID... etc. msg := telegram.NewMessage(update.Message.Chat.ID, "Hi user, join the group chat at "+this.inviteLink) msg.ReplyToMessageID = update.Message.MessageID this.bot.Send(msg) return nil }