chunk

package
v0.33.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

storage.go — 分片物理操作的存储接缝(chunk 域)。

写片/合并/取流/清理收口于 app 层,HTTP 适配层不直连 storage; 磁盘布局(uploads/YYYY/MM/DD/<uuid><ext>)统一走 utils.UploadObjectRelPath, 与直传分享落盘同源。未注入统一存储实例时(测试/降级路径)懒加载本地后端 兜底,参数与历史 handler 兜底一致(./data)。

token.go 分片会话令牌与归属校验的单一实现。

此前 transport/handler(multi-bind)与 gen/handler/chunk 各持一份逐字孪生 (chunkSessionToken/verifyChunkToken/ownedByCaller,注释自认"同源同语义"), 收口到本域导出函数后两处只留薄委托。

Index

Constants

View Source
const MaxTotalChunks = 10000

MaxTotalChunks 单会话分片数硬上限(2026-10-08 加固)。TotalChunks 客户端 可控且此前无上限:一次 init 可声明上亿分片刷控制行,后续每个 chunk PUT 还会按 index 逐条建行。10000 片 × 常见 4MB 分片已承载 40GB,远超常规 upload.max_file_size 配置,正常客户端不可能触顶。

Variables

View Source
var ErrSessionConflict = errors.New("上传会话已被占用,请刷新上传")

ErrSessionConflict init 撞上他人进行中(已含分片数据)的会话。 2026-10-05 审计 P1:uploadID 可为客户端自报哈希(公开文件哈希可预测), 原"最后写入者 wins"无条件重绑归属让第三方可截胡他人上传——改归属后即可 绑走已传分片(内容窃取)或覆写合并结果(内容替换)。HTTP 层映射 409。

Functions

func OwnedByCaller

func OwnedByCaller(info *model.UploadChunk, clientIP string, sessionToken string, callerUserID *uint) bool

OwnedByCaller 分片会话归属校验(治理):控制记录记有 OwnerIP 时,要求 IP 一致、同一登录用户或持有效会话令牌;老数据(OwnerIP 为空)此前无条件 放行——同网任意调用方可向他人进行中会话写分片/取消/完成(2026-10-08 加固 收紧为 fail-closed:仅令牌或同用户可通过,匿名老会话不可恢复,分片会话是 短生命周期数据,升级窗口外无存量)。 clientIP/callerUserID 由调用方按各路由的身份来源提取后传入(JWT/匿名、 ctx 值/c.Get 两种路径判定口径一致)。

func SessionToken

func SessionToken(uploadID string) string

SessionToken 分片会话令牌:HMAC("chunk-session:"+uploadID, key)。客户端从 init 响应头 X-Upload-Token 取得并在后续请求回传,即可在 IP 漂移(移动网络/ CGNAT)后仍通过归属校验。密钥复用 presign 签名密钥(conf.PresignSigningKey 单源:PB_PRESIGN_SIGNING_KEY 优先,缺省回退 jwt_secret);无密钥返回空串 (令牌通道关闭,仅 IP/用户匹配生效)。

func ValidateChunkPlan added in v0.14.9

func ValidateChunkPlan(fileSize, chunkSize int64, totalChunks int) error

ValidateChunkPlan 校验分片计划自洽性:TotalChunks 必须恰为 ⌈FileSize/ChunkSize⌉ 且不超过 MaxTotalChunks。防两类滥用:① 总数虚高(配合逐片 PUT 刷 DB 行/ 存储写);② 总数不足让 Complete 永不满足的僵尸会话占库。自家前端按 Math.ceil(file.size/chunkSize) 计算,严格相等不误伤。

func VerifySessionToken

func VerifySessionToken(uploadID, token string) bool

VerifySessionToken 客户端回传的会话令牌是否有效。

Types

type ChunkResp

type ChunkResp struct {
	ID          uint   `json:"id"`
	UploadID    string `json:"upload_id"`
	ChunkIndex  int    `json:"chunk_index"`
	ChunkHash   string `json:"chunk_hash"`
	TotalChunks int    `json:"total_chunks"`
	FileSize    int64  `json:"file_size"`
	ChunkSize   int    `json:"chunk_size"`
	FileName    string `json:"file_name"`
	Completed   bool   `json:"completed"`
	Status      string `json:"status"`
}

type InitiateUploadReq

type InitiateUploadReq struct {
	UploadID     string
	FileName     string
	TotalChunks  int
	FileSize     int64
	ChunkSize    int
	OwnerIP      string // 上传者 IP(治理归属追踪)
	UserID       *uint  // 上传者(chunk 路由当前无可选认证,恒 nil;字段就位以便接线)
	SessionToken string // 客户端回传的会话令牌(X-Upload-Token;IP 漂移后恢复会话用)
}

type ProgressResp

type ProgressResp struct {
	UploadID        string  `json:"upload_id"`
	TotalChunks     int     `json:"total_chunks"`
	CompletedChunks int64   `json:"completed_chunks"`
	Progress        float64 `json:"progress"`
	Status          string  `json:"status"`
}

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(gormDB *gorm.DB) *Service

func (*Service) CheckUploadProgress

func (s *Service) CheckUploadProgress(ctx context.Context, uploadID string) (*ProgressResp, error)

CheckUploadProgress 检查上传进度

func (*Service) CleanSessionFiles

func (s *Service) CleanSessionFiles(ctx context.Context, uploadID string) error

CleanSessionFiles 清理上传会话的全部临时分片。

func (*Service) CompleteUpload

func (s *Service) CompleteUpload(ctx context.Context, uploadID string) error

CompleteUpload 完成上传

func (*Service) DeleteMergedFile

func (s *Service) DeleteMergedFile(ctx context.Context, relPath string)

DeleteMergedFile 尽力删除合并对象(校验失败清理路径;删除失败不阻断主流程, 与历史 `_ = DeleteFile` 语义一致)。

func (*Service) DeleteUpload

func (s *Service) DeleteUpload(ctx context.Context, uploadID string) error

DeleteUpload 删除上传

func (*Service) FindQuickUploadSource added in v0.17.0

func (s *Service) FindQuickUploadSource(ctx context.Context, userID uint, fileHash string, fileSize int64) (*model.FileCode, error)

FindQuickUploadSource 秒传源检索(2026-10-12,D1=A 同用户内去重): 返回调用者自己历史同 hash+size 的最新可用分享;命中后由 handler 按**本次 元数据**建新分享引用其存储对象(与 presign 通道同语义,2026-10-12 起 chunk init 契约携带 expire/password 元数据)。

此前"命中复用自己旧码"语义已废弃:旧分享的过期/密码/名称与本次请求意图 不符(静默丢弃本次元数据);全库跨用户匹配更早废弃——存在性 oracle。

func (*Service) GetUploadInfo

func (s *Service) GetUploadInfo(ctx context.Context, uploadID string) (*model.UploadChunk, error)

GetUploadInfo 获取上传信息(包括文件名、大小等)

func (*Service) GetUploadList

func (s *Service) GetUploadList(ctx context.Context, page, pageSize int) ([]*ChunkResp, int64, error)

GetUploadList 获取上传列表

func (*Service) GetUploadedChunkIndexes

func (s *Service) GetUploadedChunkIndexes(ctx context.Context, uploadID string) ([]int, error)

GetUploadedChunkIndexes 获取已上传分片的索引列表

func (*Service) InitiateUpload

func (s *Service) InitiateUpload(ctx context.Context, req *InitiateUploadReq) (*ChunkResp, error)

InitiateUpload 初始化分片上传

func (*Service) MergeUpload

func (s *Service) MergeUpload(ctx context.Context, uploadID string, totalChunks int, fileName string) (string, error)

MergeUpload 合并全部分片为正式上传对象,返回统一布局下的相对路径。 文件名仅用于扩展名推导,磁盘名由 UploadObjectRelPath 生成(UUID)。

func (*Service) OpenMerged

func (s *Service) OpenMerged(ctx context.Context, relPath string) (io.ReadCloser, int64, error)

OpenMerged 打开合并后的对象读取流(哈希计算/魔数复检用),返回读取器与实际大小。

func (*Service) SaveChunkData

func (s *Service) SaveChunkData(ctx context.Context, uploadID string, chunkIndex int, data []byte) error

SaveChunkData 写入单个分片。

func (*Service) SetStorage

func (s *Service) SetStorage(st storage.StorageInterface)

SetStorage 注入统一存储实例(bootstrap 调用)。回归要点:chunk 与 share 必须共用同一实例——此前两个懒加载单例路径基不一致(./data 与 ./data/uploads), 分片合并写入 data/uploads/<rel>、下载却找 data/uploads/uploads/<rel>。

func (*Service) SetUploadSizeCap added in v0.26.0

func (s *Service) SetUploadSizeCap(p UploadSizeCapProvider)

SetUploadSizeCap 注入上限查询方(bootstrap 接线)。

func (*Service) UploadChunk

func (s *Service) UploadChunk(ctx context.Context, req *UploadChunkReq) (*ChunkResp, error)

UploadChunk 上传单个分片

type UploadChunkReq

type UploadChunkReq struct {
	UploadID   string
	ChunkIndex int
	ChunkHash  string
	ChunkSize  int
}

type UploadSizeCapProvider added in v0.26.0

type UploadSizeCapProvider interface {
	GetUploadSizeCap(ctx context.Context, userID uint) int64
}

UploadSizeCapProvider 登录用户单次上传大小上限(字节,0 = 不限)。 user.Service 以同签名满足本接口,不产生 chunk→user 域依赖。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL