Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish to telegram #15

Merged
merged 25 commits into from
Dec 6, 2019
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d938e0f
Add telegram client, for send notification
sgaynetdinov Nov 16, 2019
908cda8
Send message telegram if get new item RSS
sgaynetdinov Nov 16, 2019
3ae8267
Add new package in vendor
sgaynetdinov Nov 16, 2019
d8fb331
Not raise error if telegram token empty
sgaynetdinov Nov 18, 2019
c741b89
Add 'TestSendIfChannelIDEmpty'
sgaynetdinov Nov 18, 2019
ee439da
Fix: 'NewTelegramClient' return 'TelegramClient' not 'nil'
sgaynetdinov Nov 18, 2019
635a674
Add in environment 'TELEGRAM_TOKEN'
sgaynetdinov Nov 18, 2019
80ca198
Refactoring test
sgaynetdinov Nov 18, 2019
be4eeb7
Add test for 'TelegramClient.tagLinkOnlySupport'
sgaynetdinov Nov 18, 2019
117ef40
Add test for 'TelegramClient.getMessageHTML'
sgaynetdinov Nov 18, 2019
bec8544
Rename 'html_expected' -> 'htmlExpected'
sgaynetdinov Nov 18, 2019
010a331
Pretty log, if error send telegram message
sgaynetdinov Nov 19, 2019
d3d0adb
dd prefix "@" for "channel" if not found
sgaynetdinov Nov 19, 2019
b8312f0
Add interface 'Notification'
sgaynetdinov Nov 19, 2019
69f08f9
Set timeout for telegram
sgaynetdinov Nov 20, 2019
2b98130
Revert "Set timeout for telegram"
sgaynetdinov Nov 26, 2019
336fa15
Use timeout from http.Client without context timeout
sgaynetdinov Nov 26, 2019
c5a94a5
Pretty log
sgaynetdinov Dec 4, 2019
c2f5de1
Send audio if file size less 50 Mb or send only text
sgaynetdinov Dec 4, 2019
727df45
Add const 'maxTelegramFileSize'
sgaynetdinov Dec 5, 2019
395831a
Refactoring, message error
sgaynetdinov Dec 5, 2019
ec63f0e
Get filename audio file from url
sgaynetdinov Dec 5, 2019
588a63f
Fix: []byte is a slice backed by pointer already
sgaynetdinov Dec 5, 2019
e27a045
Telegram timeout moved to opts
sgaynetdinov Dec 5, 2019
7193518
Not reads file content to memory
sgaynetdinov Dec 5, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 86 additions & 4 deletions app/proc/telegram.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package proc

import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
@@ -26,7 +29,7 @@ func NewTelegramClient(token string) (*TelegramClient, error) {

bot, err := tb.NewBot(tb.Settings{
Token: token,
Client: &http.Client{Timeout: 10 * time.Second},
Client: &http.Client{Timeout: 60 * 10 * time.Second},
})
if err != nil {
return nil, err
@@ -48,18 +51,97 @@ func (client TelegramClient) Send(channelID string, item feed.Item) error {
return nil
}

contentLength, err := getContentLength(item.Enclosure.URL)
if err != nil {
return err
}

var message *tb.Message

if contentLength < 50_000_000 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving 50_000_000 to a const and naming it logically, like maxTelegramFileSize or smth like this will be nice

message, err = client.sendAudio(channelID, item)
} else {
message, err = client.sendText(channelID, item)
}

if err != nil {
return err
}

log.Printf("[DEBUG] send telegram message: \n%s", message.Text)
return err
}

func getContentLength(url string) (int64, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@umputun how mocking http response?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see httptest. You can run test server and provide whatever response you need

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an example of httptest.Server use in real life, from one of my projects https://github.com/go-pkgz/rest/blob/master/httperrors_test.go#L16

resp, err := http.Head(url) //nolint:gosec
if err != nil {
return 0, err
}

defer resp.Body.Close()

if resp.StatusCode != 200 {
return 0, errors.New("status code != 200")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably include the code in error will be useful

}

log.Printf("[DEBUG] Content-Length: %d, url: %s", resp.ContentLength, url)
return resp.ContentLength, err
}

func (client TelegramClient) sendText(channelID string, item feed.Item) (*tb.Message, error) {
message, err := client.Bot.Send(
recipient{chatID: channelID},
client.getMessageHTML(item),
tb.ModeHTML,
tb.NoPreview,
)

return message, err
}

func (client TelegramClient) sendAudio(channelID string, item feed.Item) (*tb.Message, error) {
file, err := client.downloadAudio(item.Enclosure.URL)
if err != nil {
return err
return nil, err
}

log.Printf("[DEBUG] send telegram message: \n%s", message.Text)
return err
audio := tb.Audio{
File: tb.FromReader(bytes.NewReader(*file)),
FileName: "1.mp3",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.mp3 ? probably should be the file name from the feed?

MIME: "audio/mpeg",
Caption: client.getMessageHTML(item),
Title: item.Title,
}

message, err := audio.Send(
client.Bot,
recipient{chatID: channelID},
&tb.SendOptions{
ParseMode: tb.ModeHTML,
},
)

return message, err
}

func (client TelegramClient) downloadAudio(url string) (*[]byte, error) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need in pointer return here, []byte is a slice backed by pointer already

clientHTTP := &http.Client{Timeout: 60 * 10 * time.Second}
Copy link
Contributor Author

@sgaynetdinov sgaynetdinov Dec 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@umputun I set big timeout, it is OK ?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hard-coded timeout is something to avoid. But I can add it to opts and pass in latter on


resp, err := clientHTTP.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()

log.Printf("[DEBUG] start download audio: %s", url)

file, err := ioutil.ReadAll(resp.Body)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code reads file content to memory. For 50M file it is not too bad, but running multiple feeds at the same time can make it way too big. I don't even see why you need to read it to memory at all. Looks like all you need in your consumer is io.Reader, i.e. resp.Body can be passed to tb.FromReader directly

if err != nil {
return nil, err
}

log.Printf("[DEBUG] finish download audio: %s", url)
return &file, err
}

// https://core.telegram.org/bots/api#html-style