S3 client and Signature V4 implementation for MoonBit
async test "客户端构造得出来,UTC 两串由时钟换算而不靠系统区域" {
let credentials = @sigv4.Credentials::new("ak", "sk")
let config = @sdk.Config::new(
"https://s3.example.invalid",
"us-east-1",
credentials,
addressing_style=@sdk.AddressingStyle::Path,
)
let _client = @sdk.Client::new(config, @transport.AsyncHttpTransport::new())
let (date, stamp) = @sdk.utc_stamps(1760000000000L)
assert_eq(date.length(), 8)
assert_eq(stamp.length(), 16)
let code = @sdk.xml_error_code(
"<Error><Code>NoSuchBucket</Code><Message>gone</Message></Error>",
)
assert_eq(code, "NoSuchBucket")
}test "MinIO 这一档:path 风格够用,桶名留在路径里" {
let credentials = @sigv4.Credentials::new("ak", "sk")
let config = @sdk.Config::new(
"http://127.0.0.1:9000",
"us-east-1",
credentials,
addressing_style=@sdk.AddressingStyle::Path,
)
let client = @sdk.Client::new(config, @transport.AsyncHttpTransport::new())
let url = client.presigned_get_url("moonfs-demo", "docs/中文 名.txt", 900)
assert_true(url.has_prefix("http://127.0.0.1:9000/moonfs-demo/docs/"))
assert_true(url.find("X-Amz-Signature=") is Some(_))
}test "OSS 这一档:桶名进 authority,预签名 URL 里看不到路径里的桶名" {
let credentials = @sigv4.Credentials::new("ak", "sk")
let config = @sdk.Config::new(
"https://oss-cn-zhangjiakou.aliyuncs.com",
"cn-zhangjiakou",
credentials,
addressing_style=@sdk.AddressingStyle::VirtualHosted,
)
let client = @sdk.Client::new(config, @transport.AsyncHttpTransport::new())
let url = client.presigned_get_url("examplebucket", "docs/a.txt", 900)
assert_true(url.has_prefix("https://examplebucket.oss-cn-zhangjiakou.aliyuncs.com/docs/a.txt"))
assert_true(!url.has_prefix("https://oss-cn-zhangjiakou.aliyuncs.com/examplebucket"))
}test "COS 这一档:桶名带 APPID,虚主机与真实区域一起给" {
let credentials = @sigv4.Credentials::new("ak", "sk")
let config = @sdk.Config::new(
"https://cos.ap-guangzhou.myqcloud.com",
"ap-guangzhou",
credentials,
addressing_style=@sdk.AddressingStyle::VirtualHosted,
)
let client = @sdk.Client::new(config, @transport.AsyncHttpTransport::new())
let url = client.presigned_get_url("examplebucket-1250000000", "docs/a.txt", 900)
assert_true(
url.has_prefix(
"https://examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/docs/a.txt",
),
)
}test "Kodo 这一档:S3 形端点、虚主机,区域由端点而不是签名域决定" {
let credentials = @sigv4.Credentials::new("ak", "sk")
let config = @sdk.Config::new(
"https://s3.cn-south-1.qiniucs.com",
"cn-south-1",
credentials,
addressing_style=@sdk.AddressingStyle::VirtualHosted,
)
let client = @sdk.Client::new(config, @transport.AsyncHttpTransport::new())
let url = client.presigned_get_url("examplebucket", "docs/a.txt", 900)
assert_true(url.has_prefix("https://examplebucket.s3.cn-south-1.qiniucs.com/docs/a.txt"))
assert_true(url.find("X-Amz-Signature=") is Some(_))
}test "OBS 这一档:端点是 obs.<region>,而且只认虚主机" {
let credentials = @sigv4.Credentials::new("ak", "sk")
let config = @sdk.Config::new(
"https://obs.cn-south-1.myhuaweicloud.com",
"cn-south-1",
credentials,
addressing_style=@sdk.AddressingStyle::VirtualHosted,
)
let client = @sdk.Client::new(config, @transport.AsyncHttpTransport::new())
let url = client.presigned_get_url("examplebucket", "docs/a.txt", 900)
assert_true(url.has_prefix("https://examplebucket.obs.cn-south-1.myhuaweicloud.com/docs/a.txt"))
assert_true(url.find("X-Amz-Signature=") is Some(_))
}| 存储侧要的那一格 | 本 SDK 的件 | 状态 |
|---|---|---|
| 上传 / 下载 / 删除 / 存在 | put_object get_object delete_object stat_object | 已实现 |
| 手动分片五步 | 五个件,见下注 | 已实现 |
| 预签名 GET 与 PUT | presigned_url presigned_get_url | 已实现 |
| 同平台复制 / 移动 | copy_object(移动=复制+delete_object) | 已实现 |
| 单层列举 | list_objects(含前缀与分隔符) | 已实现 |
| 对象 ACL 读写 | put_object_acl get_object_acl | 已实现 |
| 用户元数据 | response_user_metadata + 写入侧的 x-amz-meta-* | 已实现 |
| 桶族四法(端口不要,SDK 自用) | create_bucket bucket_exists list_buckets delete_bucket | 已实现 |
| 大文件"一条式"上传(自动切分片) | 无对应件,分片由调用侧按五步走 | 待开发 |
| 上传进度回调 | 无对应件 | 待开发 |
| 版本化对象(?versionId) | 无对应件 | 待开发 |
| 服务端加密头(x-amz-server-side-encryption) | 无对应件 | 待开发 |
moon add mldong/moon-s3Install
Download zipS3 client and Signature V4 implementation for MoonBit