This repository has been archived by the owner on May 1, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
upload.go
174 lines (136 loc) Β· 4.37 KB
/
upload.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package telegram
import (
"bytes"
"errors"
"fmt"
"io"
"mime/multipart"
"net/url"
"os"
log "github.com/kirillDanshin/dlog"
json "github.com/pquerna/ffjson/ffjson"
http "github.com/valyala/fasthttp"
)
// ErrBadFileType describes error of the unsupported file data type for uploading
var ErrBadFileType = errors.New("bad file type")
/*
Upload is a helper method which provide are three ways to send files (photos, stickers, audio,
media, etc.):
1. If the file is already stored somewhere on the Telegram servers, you don't need to reupload it:
each file object has a file_id field, simply pass this file_id as a parameter instead of uploading.
There are no limits for files sent this way.
2. Provide Telegram with an *url.URL for the file to be sent. Telegram will download and send the
file. 5 MB max size for photos and 20 MB max for other types of content.
3. Post the file using multipart/form-data in the usual way that files are uploaded via the
browser. Use []byte or io.Reader for this. 10 MB max size for photos, 50 MB for other files.
Sending by FileID
* It is not possible to change the file type when resending by file_id. I.e. a video can't be sent
as a photo, a photo can't be sent as a document, etc.
* It is not possible to resend thumbnails.
* Resending a photo by file_id will send all of its sizes.
* file_id is unique for each individual bot and can't be transferred from one bot to another.
Sending by URL
* When sending by *url.URL the target file must have the correct MIME type (e.g., audio/mpeg for
sendAudio, etc.).
* In sendDocument, sending by URL will currently only work for gif, pdf and zip files.
* To use SendVoice, the file must have the type audio/ogg and be no more than 1MB in size. 1β20MB
voice notes will be sent as files.
* Other configurations may work but we can't guarantee that they will.
*/
func (bot *Bot) Upload(method, key, name string, file InputFile, args fmt.Stringer) (*Response, error) {
buffer := bytes.NewBuffer(nil)
multi := multipart.NewWriter(buffer)
requestURI := defaultURI
requestURI.Path = fmt.Sprint("/bot", bot.AccessToken, "/", method)
query, err := url.ParseQuery(args.String())
if err != nil {
return nil, err
}
for key, val := range query {
if err = multi.WriteField(key, val[0]); err != nil {
return nil, err
}
}
if err = createFileField(multi, file, key, name); err != nil {
return nil, err
}
if err = multi.Close(); err != nil {
return nil, err
}
req := http.AcquireRequest()
defer http.ReleaseRequest(req)
req.SetBody(buffer.Bytes())
req.Header.SetContentType(multi.FormDataContentType())
req.Header.SetMethod("POST")
req.Header.SetRequestURI(requestURI.String())
req.Header.SetUserAgent(fmt.Sprint("telegram/", Version))
req.Header.SetHost(requestURI.Hostname())
log.Ln("Request:")
log.D(req)
resp := http.AcquireResponse()
defer http.ReleaseResponse(resp)
err = http.Do(req, resp)
log.Ln("Resp:")
log.D(resp)
if err != nil {
return nil, err
}
var data Response
if err = json.Unmarshal(resp.Body(), &data); err != nil {
return nil, err
}
if !data.Ok {
return nil, errors.New(data.Description)
}
return &data, nil
}
func createFileField(w *multipart.Writer, file interface{}, key, val string) error {
var err error
switch src := file.(type) {
case string: // Send FileID of file on disk path
err = createFileFieldString(w, key, src)
case *url.URL: // Send by URL
err = w.WriteField(key, src.String())
case []byte: // Upload new
err = createFileFieldRaw(w, key, val, bytes.NewReader(src))
case io.Reader: // Upload new
err = createFileFieldRaw(w, key, val, src)
default:
return ErrBadFileType
}
return err
}
func createFileFieldString(w *multipart.Writer, key, src string) error {
_, err := os.Stat(src)
switch {
case os.IsNotExist(err):
err = w.WriteField(key, src)
case os.IsExist(err):
err = uploadFromDisk(w, key, src)
}
return err
}
func uploadFromDisk(w *multipart.Writer, key, src string) error {
file, err := os.Open(src)
if err != nil {
return err
}
defer func() {
_ = file.Close()
}()
var formFile io.Writer
formFile, err = w.CreateFormFile(key, file.Name())
if err != nil {
return err
}
_, err = io.Copy(formFile, file)
return err
}
func createFileFieldRaw(w *multipart.Writer, key, value string, src io.Reader) error {
field, err := w.CreateFormFile(key, value)
if err != nil {
return err
}
_, err = io.Copy(field, src)
return err
}