Skip to content

Latest commit

 

History

History
313 lines (250 loc) · 11.1 KB

README.zh-CN.md

File metadata and controls

313 lines (250 loc) · 11.1 KB

go-storage

Build Status Go dev License go storage dev

一个厂商中立的存储库。

愿景

只需一次编写,即可在任意存储服务中运行。

目标

  • 厂商中立
  • 生产就绪
  • 极致性能

示例

package main

import (
    "log"

    "github.com/beyondstorage/go-storage/v5/services"
    "github.com/beyondstorage/go-storage/v5/types"

    // 添加 fs 支持
    _ "github.com/beyondstorage/go-storage/services/fs/v4"
    // 添加 s3 支持
    _ "github.com/beyondstorage/go-storage/services/s3/v3"
    // 添加 gcs 支持
    _ "github.com/beyondstorage/go-storage/services/gcs/v3"
    // 添加 azblob 支持
    _ "github.com/beyondstorage/go-storage/services/azblob/v3"
    // 更多支持,可在 BeyondStorage 下获取
    _ "github.com/beyondstorage/go-storage/services/xxx" 
)

func main() {
    // 使用连接字符串初始化 storager
    store, err := services.NewStoragerFromString("s3://bucket_name/path/to/workdir")
    if err != nil {
        log.Fatalf("service init failed: %v", err)
    }

    // 将 io.Reader 中的数据写入 hello.txt
    n, err := store.Write("hello.txt", r, length)

    // 从 hello.txt 中读取数据到 io.Writer
    n, err := store.Read("hello.txt", w)

    // 检查 hello.txt 是否存在并获取其元数据
    o, err := store.Stat("hello.txt")

    // 使用对象的函数获取元数据
    length, ok := o.GetContentLength()
    
    // List 将创建路径下对象的迭代器
    it, err := store.List("path")
    
    for {
    	// 使用迭代器检索下一个对象,直到迭代完成
    	o, err := it.Next()
    	if errors.Is(err, types.IterateDone) {
    		break
        }
    }

    // 删除 hello.txt
    err = store.Delete("hello.txt")
}

更多示例可以在 go-storage-example 找到。

特点

支持多种本地服务

目前已经有 16 个稳定的服务通过了所有的 集成测试

另有 3 个公测版本的服务已实现了所需功能,但还没有通过 集成测试

最后还有 4 个处于内测阶段的服务仍在开发中。

更多关于服务的想法可以在 Service Integration Tracking 找到。

完整且易扩展的接口

基本操作

  • 元数据: 获取 storager 元数据
meta := store.Metadata()
_ := meta.GetWorkDir() // 获取对象的工作目录
_, ok := meta.GetWriteSizeMaximum() // 获取写操作的最大尺寸
  • 读取: 读取 对象 的内容
// 在偏移量 1024 处读取 2048 字节到 io.Writer
n, err := store.Read("path", w, pairs.WithOffset(1024), pairs.WithSize(2048))
  • 写入: 将内容写入 对象
// 从 io.Reader 写入 2048 字节
n, err := store.Write("path", r, 2048)
  • 统计: 获取 对象 元数据并检查是否存在
o, err := store.Stat("path")
if errors.Is(err, services.ErrObjectNotExist) {
	// 对象不存在
}
length, ok := o.GetContentLength() // 获取对象的内容长度
  • 删除: 删除一个 对象
err := store.Delete("path") // 删除对象 "路径"
  • 列表: 列出给定前缀或目录中的 对象
it, err := store.List("path")
for {
	o, err := it.Next()
	if err != nil && errors.Is(err, types.IterateDone) {
        // 列表结束
    }
    length, ok := o.GetContentLength() // 获取对象的内容长度
}

扩展操作

  • 拷贝: 复制一个 对象 到 storager
err := store.(Copier).Copy(src, dst) // 从 src 复制一个对象到 dst
  • 移动: 移动一个 对象 到 storager
err := store.(Mover).Move(src, dst) // 从 src 移动一个对象到 dst
  • 链接: 为 对象 生成一个可访问的公共 url
url, err := store.(Reacher).Reach("path") // 生成一个对象的 url
  • 目录: 对象 目录
o, err := store.(Direr).CreateDir("path") // 创建一个对象目录

大文件操作

  • 分段: 允许进行分段上传
ms := store.(Multiparter)

// 创建一个分段对象
o, err := ms.CreateMultipart("path")
// 将 io.reader 中的 1024 字节分段写入索引 1
n, part, err := ms.WriteMultipart(o, r, 1024, 1)
// 完成分段对象创建
err := ms.CompleteMultipart(o, []*Part{part})
  • 追加: 允许追加到一个对象上
as := store.(Appender)

// 创建一个可追加的对象
o, err := as.CreateAppend("path")
// 从 io.Reader 写入 1024 字节
n, err := as.WriteAppend(o, r, 1024)
// 提交一个待追加的对象
err = as.CommitAppend(o)
  • 块: 允许将一个对象与块 id 进行组合
bs := store.(Blocker)

// 创建一个块对象
o, err := bs.CreateBlock("path")
// 将 io.reader 中的 1024 字节写入 id 为 ”id-abc“ 的块
n, err := bs.WriteBlock(o, r, 1024, "id-abc")
// 通过块 id 组合区块
err := bs.CombineBlock(o, []string{"id-abc"})
  • 页:允许进行随机写入
ps := store.(Pager)

// 创建一个页面对象
o, err := ps.CreatePage("path")
// Write 1024 bytes from io.Reader at offset 2048
n, err := ps.WritePage(o, r, 1024, 2048)

综合元数据

全局对象元数据

  • id: 服务中的唯一键
  • name: 服务工作目录的相对路径
  • mode: 对象的模式可以由以下几种进行组合:read, dir, part 以及 更多
  • etag: 实体标签,定义于 rfc2616
  • content-length: 对象的内容大小
  • content-md5: rfc2616 中定义的 Md5 简介
  • content-type: rfc2616 中定义的媒体类型
  • last-modified: 对象的最后更新时间

系统对象元数据

服务系统对象元数据,如 storage-class 等。

o, err := store.Stat("path")

// 通过 go-service-s3 提供的 API 获取服务系统元数据
om := s3.GetObjectSystemMetadata(o)
_ = om.StorageClass // 此对象的存储类型
_ = om.ServerSideEncryptionCustomerAlgorithm // 此对象的 sse 算法

强类型的接口

自我维护的代码生成器 定义 有助于生成我们所有的 API、pairs 和元数据。

生成的 pairs 可用作 API 的可选参数。

func WithContentMd5(v string) Pair {
    return Pair{
        Key:   "content_md5",
        Value: v,
    }
}

生成的对象元数据可用于从对象中获取内容 md5。

func (o *Object) GetContentMd5() (string, bool) {
    o.stat()
    
    if o.bit&objectIndexContentMd5 != 0 {
        return o.contentMd5, true
    }
    
    return "", false
}

服务器端加密

支持通过 system pair 和 system metadata 指定在服务端对数据进行加密编码, 并且我们可以通过 Default Pairs 来简化工作。

func NewS3SseC(key []byte) (types.Storager, error) {
    defaultPairs := s3.DefaultStoragePairs{
        Write: []types.Pair{
            // 要求密钥的加密算法必须为 AES256
            s3.WithServerSideEncryptionCustomerAlgorithm(s3.ServerSideEncryptionAes256),
            // 你的 AES-256 密钥, 必须具有 32 个字节长度
            s3.WithServerSideEncryptionCustomerKey(key),
        },
        // 现在你必须提供客户密钥才能读取加密数据
        Read: []types.Pair{
            // 要求密钥的加密算法必须为 AES256
            s3.WithServerSideEncryptionCustomerAlgorithm(s3.ServerSideEncryptionAes256),
            // 你的 AES-256 密钥, 必须具有 32 个字节长度
            s3.WithServerSideEncryptionCustomerKey(key),
        }}
    
    return s3.NewStorager(..., s3.WithDefaultStoragePairs(defaultPairs))
}

赞助商