chore: refresh gramsrv public release

This commit is contained in:
A 2026-06-30 14:37:43 +08:00
parent 75cebe8dbf
commit 70b6820474
1274 changed files with 378751 additions and 59919 deletions

View file

@ -11,12 +11,17 @@ import (
"telesrv/internal/domain"
)
// registerUpload 注册 upload.* RPC handler分片上传 + 文件下载)。
// Telegram 客户端按 chunk 调 upload.getFile单次响应限制为 1MiB
// 防止异常客户端用超大/空 limit 触发整 blob 读回。
const maxUploadGetFileChunkLimit = 1 << 20
// registerUpload 注册 upload.* RPC handler分片上传 + 文件下载 + 地图 webfile
func (r *Router) registerUpload(d *tg.ServerDispatcher) {
d.OnUploadSaveFilePart(r.onUploadSaveFilePart)
d.OnUploadSaveBigFilePart(r.onUploadSaveBigFilePart)
d.OnUploadGetFile(r.onUploadGetFile)
d.OnUploadGetFileHashes(r.onUploadGetFileHashes)
r.registerUploadWebFile(d)
}
func (r *Router) onUploadSaveFilePart(ctx context.Context, req *tg.UploadSaveFilePartRequest) (bool, error) {
@ -65,6 +70,9 @@ func (r *Router) onUploadGetFile(ctx context.Context, req *tg.UploadGetFileReque
if r.deps.Files == nil {
return nil, notImplementedErr()
}
if req.Offset < 0 || req.Limit <= 0 || req.Limit > maxUploadGetFileChunkLimit {
return nil, limitInvalidErr()
}
key, ok := fileLocationKey(req.Location)
if !ok {
return nil, locationInvalidErr()
@ -100,6 +108,8 @@ func (r *Router) onUploadGetFileHashes(ctx context.Context, req *tg.UploadGetFil
// photo:<id>:<type> 照片某尺寸(头像 big→c / small→a
func fileLocationKey(location tg.InputFileLocationClass) (string, bool) {
switch loc := location.(type) {
case *tg.InputFileLocation:
return legacyVolumeLocationKey(loc.VolumeID, loc.LocalID)
case *tg.InputDocumentFileLocation:
if loc.ID == 0 {
return "", false
@ -122,12 +132,82 @@ func fileLocationKey(location tg.InputFileLocationClass) (string, bool) {
size = "c"
}
return fmt.Sprintf("photo:%d:%s", loc.PhotoID, size), true
case *tg.InputPhotoLegacyFileLocation:
photoID := loc.ID
if photoID == 0 && loc.VolumeID < 0 {
photoID = -loc.VolumeID
}
if photoID == 0 {
return "", false
}
size, ok := legacyPhotoSizeType(loc.LocalID)
if !ok {
return "", false
}
return fmt.Sprintf("photo:%d:%s", photoID, size), true
case *tg.InputPeerPhotoFileLocationLegacy:
photoID := int64(0)
if loc.VolumeID < 0 {
photoID = -loc.VolumeID
}
if photoID == 0 {
return "", false
}
size := "a"
if loc.Big {
size = "c"
}
return fmt.Sprintf("photo:%d:%s", photoID, size), true
case *tg.InputEncryptedFileLocation:
// 密聊文件P2盲 bloblocation_key "enc:<id>"。access_hash 不强校验
// (沿用现有媒体 dev 姿态,依赖不可枚举 id
if loc.ID == 0 {
return "", false
}
return fmt.Sprintf("enc:%d", loc.ID), true
default:
// InputFileLocation(legacy volume/local/secret) / InputStickerSetThumb 等本阶段不生成对应资源。
// InputStickerSetThumb / secure / takeout 等本阶段不生成对应资源。
return "", false
}
}
func legacyVolumeLocationKey(volumeID int64, localID int) (string, bool) {
if volumeID >= 0 || localID <= 0 {
return "", false
}
id := -volumeID
if size, ok := legacyPhotoSizeType(localID); ok {
return fmt.Sprintf("photo:%d:%s", id, size), true
}
if size, ok := legacyDocumentThumbSizeType(localID); ok {
return fmt.Sprintf("doc:%d:%s", id, size), true
}
return "", false
}
func legacyPhotoSizeType(localID int) (string, bool) {
if localID < 1 || localID > 127 {
return "", false
}
ch := byte(localID)
if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
return string(ch), true
}
return "", false
}
func legacyDocumentThumbSizeType(localID int) (string, bool) {
localID -= 1000
if localID < 1 || localID > 127 {
return "", false
}
ch := byte(localID)
if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
return string(ch), true
}
return "", false
}
// storageFileType 映射 storage.FileType优先信任字节魔数以兼容历史上写错 mime 的 seed blob。
func storageFileType(mime string, data []byte) tg.StorageFileTypeClass {
switch sniffImageType(data) {
@ -182,6 +262,8 @@ func fileSaveErr(err error) error {
return filePartsInvalidErr()
case errors.Is(err, domain.ErrFilePartTooBig):
return filePartTooBigErr()
case errors.Is(err, domain.ErrUploadQuotaExceeded):
return floodWaitErr(60)
default:
return internalErr()
}