chat actions and file uploading; v0.3.7

This commit is contained in:
2026-02-04 11:13:26 +03:00
parent c71aad0c79
commit 913fa20e19
7 changed files with 360 additions and 29 deletions

View File

@@ -2,12 +2,12 @@ package laniakea
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"strconv"
"path/filepath"
)
type Uploader struct {
@@ -17,43 +17,120 @@ type Uploader struct {
func NewUploader(bot *Bot) *Uploader {
return &Uploader{bot: bot}
}
func (u *Uploader) UploadPhoto(chatId int, data []byte) error {
url := fmt.Sprintf("https://api.telegram.org/bot%s/sendPhoto", u.bot.token)
type UploaderFileType string
const (
UploaderPhotoType UploaderFileType = "photo"
UploaderVideoType UploaderFileType = "video"
UploaderAudioType UploaderFileType = "audio"
UploaderDocumentType UploaderFileType = "document"
UploaderVoiceType UploaderFileType = "voice"
UploaderVideoNoteType UploaderFileType = "video_note"
)
type UploaderFile struct {
filename string
data []byte
t UploaderFileType
}
func NewUploaderFile(name string, data []byte) UploaderFile {
t := uploaderTypeByExt(name)
return UploaderFile{filename: name, data: data, t: t}
}
// SetType used when auto-detect failed. I.e. you sending a voice message, but it detects as audio
func (f UploaderFile) SetType(t UploaderFileType) UploaderFile {
f.t = t
return f
}
type UploaderRequest[R, P any] struct {
method string
file UploaderFile
params P
}
func NewUploaderRequest[R, P any](method string, file UploaderFile, params P) UploaderRequest[R, P] {
return UploaderRequest[R, P]{method, file, params}
}
func (u UploaderRequest[R, P]) Do(bot *Bot) (*R, error) {
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", bot.token, u.method)
buf := bytes.NewBuffer(nil)
w := multipart.NewWriter(buf)
defer w.Close()
err := w.WriteField("chat_id", strconv.Itoa(chatId))
fw, err := w.CreateFormFile(string(u.file.t), u.file.filename)
if err != nil {
return err
w.Close()
return nil, err
}
fw, err := w.CreateFormFile("photo", "photo.jpg")
_, err = fw.Write(u.file.data)
if err != nil {
return err
w.Close()
return nil, err
}
_, err = fw.Write(data)
err = Encode(w, u.params)
if err != nil {
return err
w.Close()
return nil, err
}
err = w.Close()
if err != nil {
return err
return nil, err
}
req, err := http.NewRequest("POST", url, buf)
if err != nil {
return err
return nil, err
}
req.Header.Set("Content-Type", w.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
bot.logger.Debugln("UPLOADER REQ", u.method)
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return err
return nil, err
}
bot.logger.Debugln("UPLOADER RES", u.method, string(body))
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%d] %s", res.StatusCode, string(body))
}
response := new(ApiResponse[*R])
err = json.Unmarshal(body, response)
if err != nil {
return nil, err
}
if !response.Ok {
return nil, fmt.Errorf("[%d] %s", response.ErrorCode, response.Description)
}
return response.Result, nil
}
func (u *Uploader) UploadPhoto(file UploaderFile, params SendPhotoBaseP) (*Message, error) {
req := NewUploaderRequest[Message]("sendPhoto", file, params)
return req.Do(u.bot)
}
func uploaderTypeByExt(filename string) UploaderFileType {
ext := filepath.Ext(filename)
switch ext {
case ".jpg", ".jpeg", ".png", ".webp", ".bmp":
return UploaderPhotoType
case ".mp4":
return UploaderVideoType
case ".mp3", ".m4a":
return UploaderAudioType
case ".ogg":
return UploaderVoiceType
default:
return UploaderDocumentType
}
log.Println("upload", string(body))
return nil
}