package resumable import ( "context" "errors" "github.com/Tencent/WeKnora/internal/types" "time" ) const MaxFileSize int64 = 20 << 30 const ChunkSize int64 = 4 << 20 const UserQuota int64 = 40 << 30 const TenantQuota int64 = 100 << 30 const MaxActive = 20 var ErrInvalid = errors.New("上传参数或校验和无效") var ErrConflict = errors.New("上传状态或分块偏移已变化,请刷新后继续") var ErrQuota = errors.New("上传暂存配额不足,请取消其他上传或等待过期清理") var ErrForbidden = errors.New("没有此上传或目标资源的权限") // UserError contains only an intentionally public explanation written by the // upload implementation. Driver, filesystem and provider errors are never // promoted to this type and remain confined to server logs. type UserError string func (e UserError) Error() string { return string(e) } func publicError(err error) string { var public UserError if errors.As(err, &public) { return public.Error() } var input *types.DigitalHumanInputError if errors.As(err, &input) { return input.Error() } for _, sentinel := range []error{ErrInvalid, ErrConflict, ErrQuota, ErrForbidden} { if errors.Is(err, sentinel) { return sentinel.Error() } } return "文件处理暂不可用,请稍后重试或联系管理员检查服务日志" } type Upload struct { ID string `json:"id" gorm:"primaryKey;type:varchar(36)"` TenantID uint64 `json:"-" gorm:"index"` OwnerID string `json:"-" gorm:"type:varchar(36);index"` Kind string `json:"kind"` TargetID string `json:"target_id"` Name string `json:"name"` Size int64 `json:"size"` Offset int64 `json:"offset"` ChunkSize int64 `json:"chunk_size"` SHA256 string `json:"sha256"` Fingerprint string `json:"fingerprint"` State string `json:"state" gorm:"index"` Error string `json:"error,omitempty"` Options types.JSON `json:"options" gorm:"type:jsonb"` Result types.JSON `json:"result,omitempty" gorm:"type:jsonb"` IngestOffset int64 `json:"ingest_offset"` Part int `json:"part"` ExpiresAt time.Time `json:"expires_at" gorm:"index"` LeaseUntil *time.Time `json:"-"` LeaseToken string `json:"-"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } func (Upload) TableName() string { return "resumable_uploads" } type Chunk struct { UploadID string `json:"-" gorm:"primaryKey;type:varchar(36)"` Offset int64 `json:"offset" gorm:"primaryKey"` Size int64 `json:"size"` SHA256 string `json:"sha256"` } func (Chunk) TableName() string { return "resumable_upload_chunks" } type CreateInput struct { Kind string `json:"kind"` TargetID string `json:"target_id"` Name string `json:"name"` Size int64 `json:"size"` SHA256 string `json:"sha256"` Fingerprint string `json:"fingerprint"` Options types.JSON `json:"options"` } // Import processes one bounded unit, returning a durable checkpoint. The worker // renews the lease around each unit and never queues the entire file at once. type ImportFunc func(context.Context, *Upload, string) (offset int64, result types.JSON, done bool, err error) type ContextFunc func(context.Context, *Upload) (context.Context, error) type AuthorizeFunc func(context.Context, string, string) error