logo
Public
0
0
WeChat Login

s3vfs

Go Reference

s3vfs (cnb.cool/svn/s3vfs) 是一个独立的 Go 模块,将分层文件树映射为兼容 Amazon S3 协议的 HTTP 服务。它从 OpenList 的 server/s3 思路中提炼而来,通过稳定的 Tree 接口将底层存储抽象与 S3 协议层解耦,并提供可直接复用的 localfs 本地文件系统适配器。

目录

功能特性

  • 完整的 S3 协议实现 — 支持 ListBucketHeadObjectGetObjectPutObjectDeleteObjectDeleteMultiCopyObject 等核心操作
  • Bucket 管理 — 支持 CreateBucketDeleteBucket,以及 bucket 存在性快速判断
  • 版本控制 — 完整的 S3 版本控制语义,包括 GetBucketVersioningPutBucketVersioningListObjectVersions、delete marker 及版本回溯能力
  • Multipart Upload — 原生 multipart 上传支持,具备持久化与跨重启恢复能力
  • 范围读取 — 支持高效的 HTTP Range 请求与按偏移量读取
  • 用户态虚拟文件读取 — 子包 rangefs 可把支持 HTTP Range 的远端对象映射成进程内可 Read / Seek / Close 的文件句柄,适合无法使用 FUSE 的容器场景
  • 列表分页 — 完整支持 prefixdelimitermarkermax-keys 列表参数
  • 轻量级 list 索引localfs 可按 prefix 命中已排序索引,并对进程内写入即时更新、对外部文件变化定期自动追平
  • AWS Signature V4 认证 — 自研 V4 签名验证中间件,支持 Header 签名与 Query String 签名两种模式,兼容 AWS SDK
  • 动态凭证管理 — 运行时可热更新 AK/SK,无需重启服务
  • 条件写入 — 支持 If-MatchIf-None-Match 等 Put Conditions
  • 元数据持久化 — ETag 与用户 metadata 本地持久化,服务重启后可完整恢复
  • 空目录占位 — 自动生成 ThisIsAnEmptyFolderInTheS3Bucket 占位对象以保持空目录在 S3 视角下的可见性
  • 双模式存储映射
    • 静态映射: 将预定义的本地目录固定映射为指定名称的 bucket
    • 动态 namespace: 以根目录下的子目录自动对应 bucket,支持运行时创建和删除
  • 低内存占用 — 大对象操作内存分配显著低于同类方案
  • 零外部 auth 依赖 — 认证模块完全自研,不依赖第三方库

架构概览

设计原则

  1. 最小接口边界Tree 仅定义支撑 S3 协议映射所需的最小方法集合(BucketsStatListOpenPutDeleteMkdirAll),避免适配器实现负担过重
  2. 渐进式能力扩展 — 高阶能力通过可选接口(RangeTreeBucketManagerBucketVersioner 等)按需追加,不污染主接口
  3. 按需暴露优化接口localfs 通过可选的 PrefixLister 直接按 prefix 命中对象索引,避免 ListBucket 退化为全桶递归扫描
  4. 协议层隔离 — 通过 protocolBackend 适配器将无 context.Contextgofakes3.Backend 接口桥接至带上下文的 Tree 接口,使上层逻辑可正常使用 context 进行超时和取消控制
  5. 认证外置 — 由于 johannesboyne/gofakes3 移除了内置 auth,本模块在 Server 外层自研 V4 签名中间件,维持动态 AK/SK 能力的同时保持对协议层的最小侵入

安装

go get cnb.cool/svn/s3vfs@latest

要求: Go 1.24 或更高版本。

快速开始

以下示例展示如何将本地目录暴露为 S3 兼容的 HTTP 服务:

package main import ( "log" "net/http" "cnb.cool/svn/s3vfs" "cnb.cool/svn/s3vfs/localfs" ) func main() { // 创建静态 bucket 映射 store, err := localfs.Static( localfs.Dir("public", "./data/public"), localfs.Dir("backup", "./data/backup"), ) if err != nil { log.Fatal(err) } // 创建 S3 服务器并启用认证 server, err := s3vfs.New( store, s3vfs.WithCredentials("your-access-key", "your-secret-key"), ) if err != nil { log.Fatal(err) } // 启动 HTTP 服务(默认监听端口 9000) log.Fatal(http.ListenAndServe(":9000", server.Handler())) }

启动后即可使用 AWS SDK 或任何 S3 兼容客户端访问:

Endpoint: http://localhost:9000 AccessKey: your-access-key SecretKey: your-secret-key Region: us-east-1

说明: localfs.Static(...) 只注册静态 bucket 到本地目录的映射,不会自动创建 ./data/public./data/backup。这与 S3 中“声明 bucket”不等于“执行 CreateBucket” 的语义一致。若需要在启动时确保目录已落盘,请预先创建目录,或显式调用 store.CreateBucket(...)

若开启了 WithCredentials(...)WithCredentialMap(...),所有请求都必须使用 AWS Signature V4 做签名;直接用浏览器或未签名的curl去访问时,会被认证中间件拒绝。

Nginx 透明代理配置

若需要通过 Nginx 暴露 s3vfs,推荐给 S3 API 分配独立域名并代理到根路径。以下为最小可用配置:

server { listen 443 ssl http2; server_name s3.example.com; ssl_certificate /etc/nginx/certs/s3.example.com.crt; ssl_certificate_key /etc/nginx/certs/s3.example.com.key; client_max_body_size 0; merge_slashes off; location / { proxy_http_version 1.1; proxy_pass http://127.0.0.1:9000; # 透传签名相关头(SigV4 签名依赖这些字段,任何改动都会导致 403) proxy_pass_request_headers on; proxy_set_header Host $http_host; proxy_set_header Authorization $http_authorization; proxy_set_header X-Amz-Date $http_x_amz_date; proxy_set_header X-Amz-Content-Sha256 $http_x_amz_content_sha256; proxy_set_header X-Amz-Security-Token $http_x_amz_security_token; proxy_set_header Amz-Sdk-Invocation-Id $http_amz_sdk_invocation_id; proxy_set_header Amz-Sdk-Request $http_amz_sdk_request; proxy_set_header Accept-Encoding $http_accept_encoding; proxy_set_header Range $http_range; proxy_set_header Connection ""; proxy_request_buffering off; proxy_buffering off; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } }

关键要求:

  • 独立域名 + 根路径——例如 https://s3.example.com/,不要挂在 /s3/ 等子路径下。
  • 禁止改写 URI——不要使用 rewritetry_files、301/302 跳转或路径标准化,否则 SigV4 签名立即失效。
  • 保留原始 Host——proxy_set_header Host $http_host 不可省略,否则签名与后端收到的 Host 不一致。
  • 上游链路同样不可改写已签名头——若前面还有 CDN、WAF、Ingress 或平台网关,须保证 AuthorizationX-Amz-DateX-Amz-Content-Sha256Amz-Sdk-*Accept-Encoding 等头不被删除、压缩或改写。

使用示例

静态 Bucket 映射

使用 localfs.Static 将预定义的本地目录映射为固定名称的 bucket:

store, err := localfs.Static( localfs.Dir("assets", "/srv/assets"), // bucket "assets" -> /srv/assets localfs.Dir("archive", "/srv/archive"), // bucket "archive" -> /srv/archive localfs.Dir("docs", "/opt/documents"), // bucket "docs" -> /opt/documents )

注意:

  1. 静态模式下仅能创建预定义列表中的 bucket,不支持运行时动态添加新 bucket。
  2. localfs.Static(...) 不会自动执行 mkdir -p;若映射目录尚不存在,请预先创建,或在启动时对预定义 bucket 显式调用 store.CreateBucket(...)

动态 Namespace Bucket

使用 localfs.Namespace 将一个根目录作为动态 bucket 命名空间,根目录下的每个子目录自动成为一个 bucket:

store, err := localfs.Namespace("./data") // ./data/photos -> bucket "photos" // ./data/videos -> bucket "videos" // 运行时可通过 S3 API 动态创建新 bucket(即新建子目录)

自定义认证配置

提供三种方式配置 AWS Signature V4 认证:

// 方式一:单组静态 AK/SK s3vfs.WithCredentials("access-key-1", "secret-key-1") // 方式二:多组静态 AK/SK s3vfs.WithCredentialMap(map[string]string{ "access-key-1": "secret-key-1", "access-key-2": "secret-key-2", }) // 方式三:注入可运行时修改的 CredentialStore store := s3vfs.NewCredentialStore(map[string]string{ "access-key": "secret-key", }) s3vfs.WithCredentialStore(store)

若不设置任何认证选项,服务将以匿名模式运行,所有请求无需签名即可访问。

运行时动态管理凭证

Server 提供完整的运行时凭证管理 API,可在不重启服务的情况下增删改 AK/SK:

server, _ := s3vfs.New(store, s3vfs.WithCredentials("initial-ak", "initial-sk")) // 新增或覆盖一组凭证 _ = server.SetCredential("new-ak", "new-sk") // 移除指定凭证 server.DeleteCredential("old-ak") // 整体替换所有凭证 _ = server.ReplaceCredentials(map[string]string{ "ak-1": "sk-1", "ak-2": "sk-2", }) // 查询当前生效的凭证 sk, ok := server.Credential("ak-1") // 查询单组 all := server.Credentials() // 查询全部快照 store := server.CredentialStore() // 获取底层 CredentialStore

结构化日志

使用 log/slog 标准库进行结构化日志输出:

logger := slog.Default() // 或自定义 logger: // logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) server, err := s3vfs.New( store, s3vfs.WithCredentials("ak", "sk"), s3vfs.WithLogger(logger), )

嵌入现有 HTTP 服务

s3vfs.Server 实现了 http.Handler 接口,可灵活集成到现有的 HTTP 路由体系中:

mux := http.NewServeMux() // 方式一:挂载到特定路径前缀 mux.Handle("/s3/", http.StripPrefix("/s3/", server.Handler())) // 方式二:直接作为 Handler 使用(Server 自身也实现了 ServeHTTP) mux.Handle("/s3/", server) // 方式三:独立端口 go func() { log.Fatal(server.ListenAndServe(":9000")) }() // 其他路由继续使用主 mux mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello from main app")) }) log.Fatal(http.ListenAndServe(":8080", mux))

API 参考

完整的 API 文档请参阅 pkg.go.dev/cnb.cool/svn/s3vfs

若需要在应用内部把远端对象当作“近似本地文件”读取,而不是对外提供 S3 服务,可直接使用同仓子包 rangefs。该子包提供基于 HTTP Range 的虚拟文件句柄、共享块缓存、小范围 Seek 连接复用与指数退避能力,详细设计见 rangefs/README.md

核心类型

类型定义位置说明
Serverserver.goS3 HTTP 服务实例,封装协议引擎与认证中间件
Treetypes.go核心存储抽象接口,定义文件树到 S3 映射的最小方法集
Buckettypes.go描述一个 S3 bucket 的元数据
Entrytypes.go描述 bucket 内的对象或目录条目
ObjectReadertypes.go对象读取结果,包含元信息与读取流
PutObjectInputtypes.go对象写入请求的输入描述
ObjectMetadatatypes.go持久化的 S3 对象元数据
CredentialStorecredentials.go线程安全的动态 AK/SK 存储

Tree 接口体系

Tree 是 s3vfs 的核心抽象,定义了将任意后端存储暴露为 S3 服务必须实现的最低方法集:

type Tree interface { Buckets(ctx context.Context) ([]Bucket, error) Stat(ctx context.Context, bucket, key string) (Entry, error) List(ctx context.Context, bucket, dir string) ([]Entry, error) Open(ctx context.Context, bucket, key string) (*ObjectReader, error) Put(ctx context.Context, bucket, key string, input PutObjectInput) error Delete(ctx context.Context, bucket, key string) error MkdirAll(ctx context.Context, bucket, dir string) error }

可选扩展接口

以下接口均为可选实现,s3vfs 会通过类型断言检测并使用相应能力:

接口定义位置方法说明
RangeTreetypes.goOpenRange高效范围读取,避免全量加载
BucketCheckertypes.goBucketExists快速判断 bucket 是否存在
BucketManagertypes.goCreateBucket, DeleteBucketBucket 生命周期管理
ObjectCopiertypes.goCopy底层原生复制,避免 read-write 回环
MetadataLoadertypes.goLoadObjectMetadata加载持久化的对象元数据
PrefixListertypes.goListPrefix按 prefix 高效列对象,避免全桶递归扫描
BucketVersionerversioning.goVersioning, SetVersioningBucket 版本控制配置管理
VersionedObjectWriterversioning.goPutVersioned带版本语义的对象写入
VersionedObjectRemoverversioning.goDeleteVersioned带版本语义的对象删除(创建 delete marker)
VersionedObjectReaderversioning.goStatVersion, OpenVersion按版本 ID 读取对象
VersionedRangeReaderversioning.goOpenVersionRange按版本高效范围读取
VersionedObjectDeleterversioning.goDeleteVersion删除指定版本
VersionListerversioning.goListVersions列出对象的所有版本历史
MultipartObjectStoremultipart.goBeginMultipartUpload, PutMultipartPart, CompleteMultipartUpload, AbortMultipartUpload, ListMultipartUploads, ListMultipartParts完整的 multipart upload 能力

Server 方法

构造函数

方法签名说明
Newfunc New(tree Tree, opts ...Option) (*Server, error)基于 Tree 和选项创建 S3 Server
MustNewfunc MustNew(tree Tree, opts ...Option) *Server创建失败时 panic,适合已固化配置的启动路径
NewHandlerfunc NewHandler(tree Tree, opts ...Option) (http.Handler, error)New(...).Handler() 的便捷封装

服务运行

方法签名说明
Handlerfunc (s *Server) Handler() http.Handler返回可挂载的 http.Handler
ServeHTTPfunc (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)实现 http.Handler 接口
ListenAndServefunc (s *Server) ListenAndServe(addr string) error直接启动 HTTP 服务

Bucket 查询

方法签名说明
Bucketsfunc (s *Server) Buckets(ctx context.Context) ([]Bucket, error)列出当前可见的 bucket

凭证管理(运行时)

方法签名说明
SetCredentialfunc (s *Server) SetCredential(accessKey, secretKey string) error新增或覆盖一组 AK/SK
DeleteCredentialfunc (s *Server) DeleteCredential(accessKey string)移除指定 AK/SK
ReplaceCredentialsfunc (s *Server) ReplaceCredentials(all map[string]string) error整体替换全部 AK/SK
Credentialfunc (s *Server) Credential(accessKey string) (string, bool)查询单组 AK/SK
Credentialsfunc (s *Server) Credentials() map[string]string查询全部 AK/SK 快照
CredentialStorefunc (s *Server) CredentialStore() *CredentialStore获取底层凭证仓库引用

Option 选项函数

通过函数式选项模式配置 Server 行为:

函数类型默认值说明
WithCredentialsOption无(匿名模式)设置单组静态 AK/SK
WithCredentialMapOption设置多组静态 AK/SK
WithCredentialStoreOption空 store注入外部 CredentialStore 实例
WithLoggerOptionnil(静默)设置结构化日志输出器(*slog.Logger
WithIntegrityCheckOptiontrue是否校验上传请求中的 Content-MD5
WithRequestIDGeneratorOption随机生成自定义 gofakes3 请求 ID 生成器

凭证管理

CredentialStore 提供线程安全的动态 AK/SK 存储:

// 构造 store, err := s3vfs.NewCredentialStore(map[string]string{ "ak-1": "sk-1", }) // 操作 store.Set("ak-2", "sk-2") // 写入或覆盖 store.Delete("ak-1") // 删除 all := store.List() // 快照 count := store.Len() // 数量 sk, ok := store.Get("ak-2") // 查询 store.Replace(newMap) // 整体替换

错误处理

s3vfs 使用哨兵错误值(sentinel errors)进行精确错误分类:

错误变量说明判断辅助函数
ErrNotFound对象或目录不存在IsNotFound(err)
ErrVersionNotFound对象版本不存在IsVersionNotFound(err)
ErrMultipartUploadNotFoundMultipart upload 不存在IsMultipartUploadNotFound(err)
ErrBucketNotFoundBucket 不存在IsBucketNotFound(err)
ErrBucketAlreadyExistsBucket 已存在
ErrBucketNotEmptyBucket 非空不可删除
ErrNotSupported底层适配器未实现该操作
ErrInvalidBucketBucket 名称非法
ErrInvalidKey对象 key 非法
ErrInvalidPartMultipart part 非法或与服务端不一致
ErrInvalidPartOrderComplete multipart 时 part 顺序非法

所有错误均支持 errors.Is() 进行精确匹配。

localfs 适配器

localfs 是 s3vfs 内置的本地文件系统适配器,完整实现了 Tree 接口及所有可选扩展接口。

构造函数

函数签名说明
Dirfunc Dir(name, root string) Bucket创建一条 bucket 到本地目录的映射定义
Staticfunc Static(buckets ...Bucket) (*Store, error)基于固定目录映射创建 Store
MustStaticfunc MustStatic(buckets ...Bucket) *Store失败时 panic 的 Static 变体
Namespacefunc Namespace(root string) (*Store, error)基于根目录创建动态 namespace Store
MustNamespacefunc MustNamespace(root string) *Store失败时 panic 的 Namespace 变体

配置 list 索引

localfs 默认启用轻量级 list 索引,首次 LIST 时惰性建索引,随后:

  • 进程内通过 S3 协议产生的 Put / Delete / MkdirAll 会即时增量更新索引
  • 底层目录被外部进程直接改写时,会在下一次 LIST 且超过刷新周期后自动重扫追平
  • 默认刷新周期为 2s,也可按业务密度调整
store, _ := localfs.Static(localfs.Dir("archive", "/srv/archive")) store.ConfigureListIndex(localfs.ListIndexConfig{ RefreshInterval: 2 * time.Second, })

localfs 特性清单

  • 完整实现 TreeRangeTreeBucketCheckerBucketManagerObjectCopierMetadataLoader
  • 完整实现 BucketVersionerVersionedObjectWriterVersionedObjectRemoverVersionedObjectReaderVersionedRangeReaderVersionedObjectDeleterVersionLister
  • 完整实现 MultipartObjectStore
  • 元数据持久化于 .s3vfs 隐藏目录内
  • Multipart part 数据持久化为文件,ETag 编入文件名以优化查询
  • 轻量级 list 索引按 key 排序保存在内存中,支持 prefix 二分命中与自动刷新
  • 自动拒绝 .. 路径逃逸攻击
  • 自动推断 Content-Type(基于文件扩展名)

S3 API 兼容性

已支持的 S3 操作

类别操作说明
BucketGET / (ListBuckets)列出所有 bucket
PUT /{bucket} (CreateBucket)创建 bucket
DELETE /{bucket} (DeleteBucket)删除空 bucket
HEAD /{bucket} (BucketExists)判断 bucket 是否存在
对象HEAD /{bucket}/{key} (HeadObject)获取对象元信息
GET /{bucket}/{key} (GetObject)下载对象(支持 Range)
PUT /{bucket}/{key} (PutObject)上传对象(支持 Conditions)
DELETE /{bucket}/{key} (DeleteObject)删除对象
POST /?delete (DeleteMulti)批量删除对象
PUT /{bucket}/{key} (CopyObject)复制对象(通过 x-amz-copy-source)
列表GET /{bucket}?list-type=2 (ListBucketV2)列出对象(支持 prefix/delimiter/max-keys/marker 分页)
版本控制GET /{bucket}?versioning获取版本控制配置
PUT /{bucket}?versioning设置版本控制配置
GET /{bucket}?versions列出对象所有版本
GET /{bucket}/{key}?versionId=按 versionId 获取/头信息/删除
MultipartPOST /{bucket}/{key}?uploads发起 multipart upload
PUT /...?partNumber=&uploadId=上传 part
POST /...?uploadId= (Complete)完成 multipart upload
DELETE /...?uploadId= (Abort)中止 multipart upload
GET /{bucket}?uploads列出进行中的 multipart uploads
GET /{bucket}/{key}?uploadId=列出指定 upload 的 parts

暂未支持

  • Object Lock / Lifecycle Configuration / Replication 等 S3 高阶语义
  • Tagging 相关 API
  • ACL / Policy 权限模型(当前仅通过 AK/SK 区分认证与否)
  • 原生 OpenList 适配器(规划中)

版本控制

s3vfs 完整实现 S3 版本控制语义:

  • 三种状态: Enabled(启用)、Suspended(暂停)、None(从未启用)
  • 启用版本控制的 bucket 下,每次 PutObject 生成新的 VersionID
  • DeleteObject 在启用状态下创建 delete marker 而非真正删除数据
  • 可通过指定 versionId 获取历史版本的元信息与内容
  • 可通过 DeleteObject?versionId= 删除指定版本(含 delete marker)
  • ListObjectVersions 返回完整的版本历史,包含 delete marker
  • 版本配置与版本历史均持久化至本地磁盘,跨重启不丢失

Multipart Upload

基于 johannesboyne/gofakes3 的原生 MultipartBackend 扩展点实现:

  • 单个 upload 最大支持 10000 个 part(由 MaxMultipartPartNumber 定义)
  • Part 数据持久化为本地文件,ETag 编入文件名以加速 complete 阶段匹配
  • Upload 状态持久化至 .s3vfs 目录,支持服务重启后恢复未完成的 upload
  • Complete 时按 CompletedPart.PartNumber 顺序组装,避免二次全量拷贝
  • Abort 彻底清理所有已上传的 part 文件及状态记录

性能基准

截至 2026-04-05 的实测数据(对比 rclone/gofakes3 主线方案):

基准测试vs rclone内存分配 (B/op) 变化
SignedHeadExistingObject基本持平
MultipartTwoPartUpload慢 57.15%下降 93.08%
MultipartConcurrentUploads-4慢 71.66%下降 73.84%
MultipartLargeObjectUpload-4快 ~18.50% (p=0.114, 不宣称统计显著)下降 98.31%

结论: 本方案在所有 multipart 场景下内存占用显著更低,大对象吞吐具有优势;小对象并发场景吞吐弱于 rclone 但换来更低的资源消耗与 restart-safe 语义保证。

同日新增 localfs 轻量级 list 索引后,NVR 风格目录树(archive/YYYY/MM/DD/cam-XX/HH/clip.ts)的 LIST 延时变化如下:

场景旧实现新实现改善
10k month_browse96.15ms10.85ms-88.72%
10k day_browse93.89ms0.54ms-99.42%
10k camera_day_list93.57ms0.28ms-99.70%
20k month_browse168.23ms21.50ms-87.22%
20k day_browse166.81ms0.87ms-99.48%
20k camera_day_list164.79ms0.36ms-99.78%
20k day_browse x8 平均368.02ms1.74ms-99.53%
20k day_browse x8 p95405.85ms2.55ms-99.37%

结论: 旧实现的 LIST 成本主要由“全桶递归扫描”决定;引入 PrefixLister + localfs 轻量级索引后,NVR 归档这类深目录树已基本回到“与命中 prefix 成比例”的延时区间,更适合 1-2 万 文件量级的浏览型场景。

开发

环境要求

  • Go 1.24+
  • Linux / macOS / Windows

构建与测试

# 运行全部测试 go test ./... # 运行指定包的测试 go test ./localfs/... go test -v -run TestServer ./... # 性能基准测试 go test -run '^$' -bench 'BenchmarkMultipart(TwoPartUpload|LargeObjectUpload|ConcurrentUploads)$' -benchmem ./...

项目结构

s3vfs/ ├── server.go # Server 核心结构与构造逻辑 ├── server_auth.go # AWS SigV4 认证中间件 ├── server_compat.go # 目录兼容中间件 ├── backend.go # 核心 Backend 实现(Tree → gofakes3 桥接) ├── backend_protocol.go # Protocol adapter(context 注入与 multipart 路由) ├── backend_versioning.go # 版本控制相关 Backend 方法 ├── types.go # Tree 接口定义与核心数据类型 ├── options.go # Option 函数式选项与默认配置 ├── credentials.go # 动态凭证存储 ├── auth_v4.go # AWS Signature V4 签名验证算法 ├── errors.go # 哨兵错误值与判断辅助函数 ├── list.go # 对象遍历与分页逻辑 ├── multipart.go # Multipart 接口定义与类型 ├── versioning.go # 版本控制接口定义与类型 ├── logger.go # 结构化日志适配 ├── localfs/ # 本地文件系统适配器 │ ├── store.go # Store 实现(Tree 全接口) │ ├── objects.go # 对象读写操作 │ ├── list_index.go # 轻量级 list 索引与自动刷新 │ ├── metadata.go # 元数据持久化 │ ├── versioning.go # 版本控制状态管理 │ ├── versioning_state.go # 版本状态持久化 │ ├── versioning_files.go # 版本文件 I/O │ ├── versioning_commit.go # 版本提交逻辑 │ ├── multipart.go # multipart 主逻辑 │ ├── multipart_state.go # multipart 状态持久化 │ ├── multipart_files.go # multipart 文件 I/O │ └── multipart_runtime.go # multipart 运行时缓存 ├── examples/ │ └── basic/main.go # 最简使用示例 ├── server_test.go # Server 集成测试 ├── server_list_index_test.go # list 索引回归测试 ├── server_benchmark_test.go # 性能基准测试 ├── auth_test.go # 签名验证单元测试 └── localfs/localfs_test.go # localfs 适配器测试

贡献指南

欢迎提交 Issue 和 Pull Request!

开发流程

  1. Fork 本仓库
  2. 创建特性分支: git checkout -b feature/my-feature
  3. 编写代码与测试
  4. 确保全部测试通过: go test ./...
  5. 如涉及性能变更,补充或更新基准测试数据
  6. 提交 Pull Request

代码规范

  • 遵循 Effective GoGo Code Review Comments
  • 公开 API 必须附带 Godoc 注释
  • 保持接口最小化原则:新增能力优先考虑可选扩展接口
  • 错误处理使用 errors.Is() 进行哨兵错误匹配
  • 保持向后兼容性,不轻易破坏已有 API

License

本项目基于 MIT 许可证开源。详见 LICENSE 文件。

About

一个将分层文件树映射为可直接对外暴露的 S3 协议服务Go模块扩展包

Language
Go100%