diff --git a/NTFServer.go b/NTFServer.go index 103c159..f24144a 100644 --- a/NTFServer.go +++ b/NTFServer.go @@ -27,6 +27,8 @@ type NTFServer struct { conns map[string]*libnmdc.HubConnection // hubnick -> hubconn verbose bool + callOnMainThread chan func() + contentedMaxBytes int64 // Except the coalesce buffer, that requires a background worker. @@ -42,11 +44,12 @@ type upstreamMessage struct { func NewNTFServer(configFile string, verbose bool) (*NTFServer, error) { ret := NTFServer{ - configFile: configFile, - hubMessages: make(chan upstreamMessage, 0), - conns: make(map[string]*libnmdc.HubConnection), - coalesceBuffer: make(map[string]time.Time), - verbose: verbose, + configFile: configFile, + hubMessages: make(chan upstreamMessage, 0), + callOnMainThread: make(chan func(), 0), + conns: make(map[string]*libnmdc.HubConnection), + coalesceBuffer: make(map[string]time.Time), + verbose: verbose, } // Config @@ -215,6 +218,12 @@ func (this *NTFServer) Run() error { log.Fatalf("Upstream update channel closed unexpectedly") } this.HandleHubMessage(hubMsg) + + case mtfn, ok := <-this.callOnMainThread: + if !ok { + log.Fatalf("Synchronisation channel closed unexpectedly") + } + mtfn() } } @@ -427,25 +436,33 @@ func (this *NTFServer) HandleGroupMessage(update telegram.Update) error { return this.HandleTelegramUserParted(int64(update.Message.LeftChatMember.ID), update) } + // + + userID := int64(update.Message.From.ID) + + if update.Message.Sticker != nil && this.contentedMaxBytes > 0 { + // Sticker + go this.uploadStickerWorker(userID, update.Message.Sticker) + } + if len(update.Message.Text) > 0 { - // Find the responsible user's upstream connection - userID := int64(update.Message.From.ID) - hubNick, ok := this.config.KnownUsers[userID] - if !ok { - return fmt.Errorf("Couldn't send public message for user '%d' unexpectedly missing hub nick!", userID) - } - - conn, ok := this.conns[hubNick] - if !ok { - return fmt.Errorf("Couldn't send public message for user '%d' (%s) unexpectedly missing upstream connection!", userID, hubNick) - } - // Intercept some bot commands if update.Message.Text == "/userlist" || update.Message.Text == "/userlist@"+this.botName { // Display native userlist inside the groupchat + // Find the responsible user's upstream connection + hubNick, ok := this.config.KnownUsers[userID] + if !ok { + return fmt.Errorf("Couldn't send public message for user '%d' unexpectedly missing hub nick!", userID) + } + + conn, ok := this.conns[hubNick] + if !ok { + return fmt.Errorf("Couldn't send public message for user '%d' (%s) unexpectedly missing upstream connection!", userID, hubNick) + } + usernames, err := this.getUserlistText(conn) if err != nil { this.GroupChatSayHTML("Can't get userlist for you (internal error)") @@ -482,20 +499,37 @@ func (this *NTFServer) HandleGroupMessage(update telegram.Update) error { } - // Also add it to the coalesce buffer so that we don't replay it from someone else's NMDC connection - this.Coalesce(hubNick, sendMsg) - - // Submit to NMDC - err := conn.SayPublic(sendMsg) - if err != nil { - log.Printf("Failed to deliver message '%s': %s", sendMsg, err.Error()) - this.GroupChatSayHTML(fmt.Sprintf("Couldn't sync message '%s' because: %s", html.EscapeString(sendMsg), html.EscapeString(err.Error()))) - } + return this.HubSay(userID, sendMsg) } } // TODO probably a file/image upload??? // TODO support "editing messages" by re-sending them with a ** suffix + return nil +} + +func (this *NTFServer) HubSay(userID int64, sendMsg string) error { + + // Find the responsible user's upstream connection + hubNick, ok := this.config.KnownUsers[userID] + if !ok { + return fmt.Errorf("Couldn't send public message for user '%d' unexpectedly missing hub nick!", userID) + } + + conn, ok := this.conns[hubNick] + if !ok { + return fmt.Errorf("Couldn't send public message for user '%d' (%s) unexpectedly missing upstream connection!", userID, hubNick) + } + + // Also add it to the coalesce buffer so that we don't replay it from someone else's NMDC connection + this.Coalesce(hubNick, sendMsg) + + // Submit to NMDC + err := conn.SayPublic(sendMsg) + if err != nil { + log.Printf("Failed to deliver message '%s': %s", sendMsg, err.Error()) + this.GroupChatSayHTML(fmt.Sprintf("Couldn't sync message '%s' because: %s", html.EscapeString(sendMsg), html.EscapeString(err.Error()))) + } return nil } diff --git a/contented.go b/contented.go index 4da198f..f647d5c 100644 --- a/contented.go +++ b/contented.go @@ -57,6 +57,11 @@ func (this *NTFServer) ContentedUploadFromSync(main *telegram.File, thumbs *[]te func (this *NTFServer) ContentedUploadSync(fileId string, expectSizeBytes int64) (string, error) { + // If file fits under size limit, take it + if expectSizeBytes > this.contentedMaxBytes { + return "", errors.New("The file was too large for the image host server (and no smaller thumbnail is available)") + } + // Prepare to download the file from telegram url, err := this.bot.GetFileDirectURL(fileId) if err != nil { diff --git a/upload.go b/upload.go new file mode 100644 index 0000000..1b27cc3 --- /dev/null +++ b/upload.go @@ -0,0 +1,43 @@ +package main + +import ( + "errors" + "html" + "log" + + telegram "github.com/go-telegram-bot-api/telegram-bot-api" +) + +func (this *NTFServer) uploadStickerWorker(userID int64, s *telegram.Sticker) { + var conUrl string + var err error + + if int64(s.FileSize) < this.contentedMaxBytes { + conUrl, err = this.ContentedUploadSync(s.FileID, int64(s.FileSize)) + + } else if s.Thumbnail != nil && int64(s.Thumbnail.FileSize) < this.contentedMaxBytes { + conUrl, err = this.ContentedUploadSync(s.Thumbnail.FileID, int64(s.Thumbnail.FileSize)) + + } else { + err = errors.New("File too big and/or bad thumbnail") + + } + + // + + if err != nil { + log.Printf("Sticker upload failed: %s", err.Error()) + this.callOnMainThread <- func() { + this.GroupChatSayHTML("Can't upload sticker for native users: " + html.EscapeString(err.Error()) + "") + } + return + } + + // Sticker upload success + this.callOnMainThread <- func() { + // n.b. this will fail if the user has disconnected by the time the upload completed + + this.HubSay(userID, s.Emoji+" "+conUrl) + } + +}