MTGo File Transfer
MTGo provides a complete file transfer system that handles chunked uploads, resumable downloads, streaming, progress tracking, and automatic CDN fallback for large files.
Upload Process
File uploads in MTProto work by splitting a file into chunks and sending them sequentially via the upload.SaveFile RPC. MTGo abstracts this into high-level functions.
Upload Flow
File → Split into chunks → Upload each chunk via UploadFile RPC → Receive UploadResultEach chunk is typically 512 KB. The server reassembles the chunks and returns an InputFile that you can reference when sending media.
UploadFile
Upload a file from a byte slice:
uploadResult, err := client.UploadFile(ctx, "photo.jpg", fileBytes)
if err != nil {
log.Fatal(err)
}UploadFromReader
Upload from any io.Reader, useful for streaming uploads:
file, err := os.Open("document.pdf")
if err != nil {
log.Fatal(err)
}
defer file.Close()
uploadResult, err := client.UploadFromReader(ctx, "document.pdf", file, fileSize)UploadFromFile
Upload directly from a file path. This is the simplest API:
uploadResult, err := client.UploadFromFile(ctx, "./photo.jpg")Upload with Progress
All upload functions accept optional progress callbacks:
uploadResult, err := client.UploadFromFile(ctx, "./large_video.mp4",
tg.WithProgress(func(sent, total int64) {
fmt.Printf("\rUpload: %.1f%%", float64(sent)/float64(total)*100)
}),
)Download Process
GetFileLocation
Before downloading, you need a file location. MTGo extracts this from media objects:
fileLoc := client.GetFileLocation(photo)This returns an InputFileLocation variant appropriate for the media type (photo, document, video, etc.).
DownloadFile
Download to a byte slice:
data, err := client.DownloadFile(ctx, inputFileLocation)DownloadToFile
Download directly to a file on disk:
err := client.DownloadToFile(ctx, inputFileLocation, "./downloads/photo.jpg")Streaming Downloads with StreamFile
For large files, StreamFile provides a streaming download that returns an io.Reader:
reader, err := client.StreamFile(ctx, inputFileLocation)
if err != nil {
log.Fatal(err)
}
defer reader.Close()
io.Copy(outputFile, reader)Progress Tracking
Download functions support the FileChunk callback for progress monitoring:
err := client.DownloadToFile(ctx, fileLoc, "./video.mp4",
tg.WithDownloadProgress(func(received, total int64) {
fmt.Printf("\rDownload: %.1f%%", float64(received)/float64(total)*100)
}),
)CDN Fallback
For large files, Telegram may redirect downloads to a CDN. MTGo handles this automatically:
- Client requests file from the home DC
- If the response indicates a CDN redirect, MTGo connects to the CDN DC
- The file is downloaded from the CDN using the provided CDN parameters
- The CDN file is verified against the original DC's hash
This is transparent to the caller—no special handling is required.
DC-Specific Sessions
File transfers often need to happen on a specific DC. MTGo manages this automatically via GetSession:
// GetSession creates or returns a session connected to a specific DC
// Setting isMedia=true configures the session for file transfer
mediaSession := client.GetSession(dcID, true)When you upload or download a file, MTGo:
- Determines which DC holds the file (or uses the home DC for uploads)
- Gets or creates a media session for that DC
- Performs the transfer on the appropriate session
- Returns the result to the caller
You rarely need to manage this manually—the upload/download functions handle DC routing internally.
Working with Media Types
Photos
Photos have multiple thumbnail sizes. To download a specific size:
// Download the largest size
fileLoc := photo.Sizes[len(photo.Sizes)-1].Location
data, err := client.DownloadFile(ctx, fileLoc)Documents
Documents include files, videos, audio, and other attachments:
fileLoc := document.Location
err := client.DownloadToFile(ctx, fileLoc, "./"+document.Filename)Videos
Videos are documents with a video MIME type. They may have thumbnail images:
// Download video
err := client.DownloadToFile(ctx, videoDoc.Location, "./video.mp4")
// Download thumbnail
thumbLoc := videoDoc.Thumbs[0].Location
data, err := client.DownloadFile(ctx, thumbLoc)Complete Example: Upload and Send Photo
package main
import (
"context"
"log"
tg "github.com/mtgo-labs/mtgo/telegram"
)
func main() {
client, err := tg.NewClient(apiID, apiHash, &tg.Config{
BotToken: botToken,
SessionName: "photo_bot",
})
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Upload the photo
uploadResult, err := client.UploadFromFile(ctx, "./cat.jpg")
if err != nil {
log.Fatal(err)
}
// Send the uploaded photo
_, err = client.SendMedia(ctx,
tg.ChatRef("@username"),
tg.NewPhotoMedia(uploadResult, "cat.jpg"),
"Here is a photo!",
)
if err != nil {
log.Fatal(err)
}
}Complete Example: Download Received Media
client.OnMessage(func(c *tg.Client, msg *types.Message) {
if msg.Photo == nil {
return
}
// Get the largest photo size
photo := msg.Photo
fileLoc := photo.Sizes[len(photo.Sizes)-1].Location
// Download to file
filename := fmt.Sprintf("photo_%d.jpg", msg.ID)
err := client.DownloadToFile(context.Background(), fileLoc, "./downloads/"+filename,
tg.WithDownloadProgress(func(received, total int64) {
fmt.Printf("\rDownloading %s: %.1f%%", filename, float64(received)/float64(total)*100)
}),
)
if err != nil {
log.Printf("download error: %v", err)
return
}
fmt.Printf("\nSaved %s\n", filename)
}, tg.All)