Help us shape the future of Go! Take the 2026 Go Developer Survey

presign

package
v0.14.4 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package presign 实现预签名上传 service。

流程:

  1. 客户端调 Init 申请预签名 URL + token
  2. 客户端 PUT 直传文件到 URL
  3. 客户端调 Complete 通知服务写 share 表
  4. 服务返回 share_code

当前实现:fallback 走"自家直传 URL + token"模式(不依赖真实 S3/OSS 预签名)。 当 OpenDAL binding 接入后,可直接生成真实预签名 URL。

Index

Constants

View Source
const (
	// SchemeSelf 自家中转:客户端 PUT /api/v1/presign/upload-direct/:uploadID
	SchemeSelf = "self"
	// SchemeS3 真·预签名直传:客户端 PUT 对象存储,服务器只签名不过流量
	SchemeS3 = "s3"
)

直传模式标记(meta.Scheme / InitResult.Scheme,服务端判定为准)

Variables

View Source
var (
	ErrUploadNotFound  = errors.New("upload not found")
	ErrTokenInvalid    = errors.New("upload token invalid")
	ErrUploadExpired   = errors.New("upload expired")
	ErrAlreadyComplete = errors.New("upload already completed")
)

错误定义

Functions

This section is empty.

Types

type CompleteResult

type CompleteResult struct {
	*InitMeta
	ShareCode    string
	ShareURL     string
	FullShareURL string
	OwnerIP      string
}

CompleteResult Complete 返回结果(包含 share_code)

type InitMeta

type InitMeta struct {
	UploadID    string    `json:"upload_id"`
	ObjectKey   string    `json:"object_key"`
	FileName    string    `json:"file_name"`
	FileSize    int64     `json:"file_size"`
	ContentType string    `json:"content_type"`
	Scheme      string    `json:"scheme"`
	ExpireAt    time.Time `json:"expire_at"`
	Complete    bool      `json:"complete"`
	UserID      uint      `json:"user_id"`
	ExpireValue int32     `json:"expire_value"`
	ExpireStyle string    `json:"expire_style"`
	RequireAuth bool      `json:"require_auth"`
	// PasswordHash 为 require_auth=true 时分享密码的 bcrypt 哈希(明文不落存储)
	PasswordHash string `json:"password_hash,omitempty"`
	// FileHash 直传完成后服务端计算的 SHA-256(写入 file_codes.file_hash,秒传依据)
	// SessionTTL 直传会话/签名时效(handler 按管理配置下发;0=服务端默认 1h)
	SessionTTL time.Duration `json:"-"`
	FileHash   string        `json:"file_hash,omitempty"`
}

InitMeta init 元信息

type InitResult

type InitResult struct {
	UploadID      string            `json:"upload_id"`
	UploadURL     string            `json:"upload_url"`
	Method        string            `json:"method"`
	Headers       map[string]string `json:"headers"`
	ExpireSeconds int32             `json:"expire_seconds"`
	ObjectKey     string            `json:"object_key"`
	Scheme        string            `json:"scheme"`
	Token         string            `json:"token"`
}

InitResult init 返回

type ObjectStore

type ObjectStore interface {
	PresignPutURL(ctx context.Context, objectKey string, expire time.Duration) (string, error)
	// HeadObject 直传完成核实用:对象必须真实存在并取实际大小(S3 为事实源)
	HeadObject(ctx context.Context, objectKey string) (size int64, etag string, err error)
}

ObjectStore 真预签名直传能力(由 *storage.StorageService 实现)。 PresignPutURL 对 local/webdav 返回 storage.ErrPresignUnsupported,调用方回退自家中转。

type QuickUploadResult

type QuickUploadResult struct {
	ShareCode    string
	FullShareURL string
}

QuickUploadResult 秒传命中结果

type Service

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

Service 预签名上传 service

func NewService

func NewService(rdb *redis.Client, baseURL string, signingKey string) *Service

NewService 创建 service。rdb nil 归一化:typed-nil 接口会骗过 "Redis 可用"守卫(!= nil 判真)。 rdb 为 nil(redis.host 未配置)时进入单机内存模式:直传会话存进程内 TTL KV,预签名直传全功能可用(单进程语义等价;重启未完成会话作废)。

func (*Service) Abort

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

Abort 取消

func (*Service) CheckQuickUpload

func (s *Service) CheckQuickUpload(ctx context.Context, fileHash string, fileSize int64) (*QuickUploadResult, error)

CheckQuickUpload 秒传检查:按客户端提供的 SHA-256 + 文件大小查找未过期的既有分享。 命中即无需直传,直接出码(对标上游 init 返回 existed 语义)。

func (*Service) Complete

func (s *Service) Complete(ctx context.Context, uploadID, token, ownerIP string) (*CompleteResult, error)

Complete 完成通知(调 share service 写分享表)

func (*Service) GetMeta

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

GetMeta 查询(管理后台用)

func (*Service) Init

func (s *Service) Init(ctx context.Context, meta InitMeta) (*InitResult, error)

Init 申请预签名

func (*Service) SetObjectStore

func (s *Service) SetObjectStore(o ObjectStore)

SetObjectStore 注入真预签名直传能力(s3 后端;不支持时 Init 自动回退自家中转)

func (*Service) SetShareService

func (s *Service) SetShareService(svc ShareServiceInterface)

SetShareService 注入 share service(用于 Complete 时写分享表)

func (*Service) SetStorage

func (s *Service) SetStorage(st StorageWriter)

SetStorage 注入存储服务(直传按当前激活后端落盘,含路径防御)

func (*Service) UploadDirect

func (s *Service) UploadDirect(ctx context.Context, uploadID, token string, body io.Reader, declaredSize int64) error

UploadDirect 处理预签名直传:校验 token → 流式写文件(meta.ObjectKey 路径)。 由 bootstrap 注册的 PUT /api/v1/presign/upload-direct/:uploadID 端点调用。 body 流式消费(配合 hertz StreamRequestBody),大文件不再整体进内存; 写入字节数必须与 init 申报的 meta.FileSize 完全一致,超出即拒并清理。

type ShareServiceInterface

type ShareServiceInterface interface {
	ShareFile(ctx context.Context, req *share.ShareFileReq) (*share.ShareResp, error)
	CreateShare(ctx context.Context, req *share.ShareFileReq) (*share.ShareResp, error)
}

ShareServiceInterface share service 接口(避免循环依赖) 与 share.Service.ShareFile / CreateShare 签名保持一致

type StorageWriter

type StorageWriter interface {
	SaveBytes(ctx context.Context, savePath string, data []byte) error
	DeleteFile(ctx context.Context, filePath string) error
}

StorageWriter 存储写入抽象(由 *storage.StorageService 实现)。 单方法接口避免反向依赖存储包,也保持既有 StorageInterface/mock 不动。

Jump to

Keyboard shortcuts

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