(new): v1.2 release
Golang lint / lint (push) Successful in 11m32s

This commit is contained in:
2026-08-19 14:58:25 +03:00
parent f03a081ed6
commit 29b208eeec
79 changed files with 7301 additions and 2060 deletions
+35 -27
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
"net/http"
"path/filepath"
@@ -133,6 +134,7 @@ func (r UploaderRequest[R, P]) doRequest(ctx context.Context, up *Uploader) (R,
}
url := fmt.Sprintf("%s/bot%s%s/%s", up.api.apiURL, up.api.token, methodPrefix, r.method)
retries := 0
for {
if up.api.Limiter != nil {
if err := up.api.Limiter.Check(ctx, up.api.dropOverflowLimit, r.chatID); err != nil {
@@ -140,23 +142,21 @@ func (r UploaderRequest[R, P]) doRequest(ctx context.Context, up *Uploader) (R,
}
}
buf, contentType, err := prepareMultipart(r.files, r.params)
requestBody, contentType := prepareMultipartStream(r.files, r.params)
req, err := http.NewRequestWithContext(ctx, "POST", url, requestBody)
if err != nil {
return zero, err
}
req, err := http.NewRequestWithContext(ctx, "POST", url, buf)
if err != nil {
return zero, err
_ = requestBody.Close()
return zero, fmt.Errorf("failed to create upload request: %w", err)
}
req.Header.Set("Content-Type", contentType)
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString))
req.ContentLength = int64(buf.Len())
up.logger.Debugln("UPLOADER REQ", url)
resp, err := up.api.client.Do(req)
_ = requestBody.Close()
if err != nil {
return zero, err
return zero, fmt.Errorf("HTTP upload request failed: %w", err)
}
body, err := readBody(resp.Body)
@@ -172,6 +172,11 @@ func (r UploaderRequest[R, P]) doRequest(ctx context.Context, up *Uploader) (R,
}
if !response.Ok {
responseErr := &ResponseError{
Code: response.ErrorCode,
Description: response.Description,
Parameters: response.Parameters,
}
if response.ErrorCode == 429 && response.Parameters != nil && response.Parameters.RetryAfter != nil {
after := *response.Parameters.RetryAfter
up.logger.Warnf("Rate limited, retry after %d seconds (chat: %d)", after, r.chatID)
@@ -182,19 +187,19 @@ func (r UploaderRequest[R, P]) doRequest(ctx context.Context, up *Uploader) (R,
up.api.Limiter.SetGlobalLock(after)
}
}
if retries >= up.api.maxRetries {
return zero, fmt.Errorf("%w after %d retries: %w", ErrRetryLimit, retries, responseErr)
}
retries++
select {
case <-ctx.Done():
return zero, ctx.Err()
case <-time.After(time.Duration(after) * time.Second):
case <-time.After(retryDelay(after)):
continue
}
}
return zero, &ResponseError{
Code: response.ErrorCode,
Description: response.Description,
Parameters: response.Parameters,
}
return zero, responseErr
}
return response.Result, nil
}
@@ -232,36 +237,39 @@ func (r UploaderRequest[R, P]) Do(up *Uploader) (R, error) {
return r.DoWithContext(context.Background(), up)
}
func prepareMultipart[P any](files []UploaderFile, params P) (*bytes.Buffer, string, error) {
buf := bytes.NewBuffer(nil)
w := multipart.NewWriter(buf)
func prepareMultipartStream[P any](files []UploaderFile, params P) (io.ReadCloser, string) {
reader, writer := io.Pipe()
multipartWriter := multipart.NewWriter(writer)
contentType := multipartWriter.FormDataContentType()
go func() {
err := writeMultipart(multipartWriter, files, params)
_ = writer.CloseWithError(err)
}()
return reader, contentType
}
func writeMultipart[P any](w *multipart.Writer, files []UploaderFile, params P) error {
for _, file := range files {
fw, err := w.CreateFormFile(string(file.field), file.filename)
if err != nil {
_ = w.Close()
return nil, "", err
return err
}
_, err = fw.Write(file.data)
_, err = io.Copy(fw, bytes.NewReader(file.data))
if err != nil {
_ = w.Close()
return nil, "", err
return err
}
}
err := utils.Encode(w, params)
if err != nil {
_ = w.Close()
return nil, "", err
return err
}
err = w.Close()
if err != nil {
return nil, "", err
}
return buf, w.FormDataContentType(), nil
return w.Close()
}
func uploaderTypeByExt(filename string) UploaderFileType {