feat: integrate multi-cloud storage (S3, OSS, COS, Local)

Add built-in storage support from v-hono-storage module:
- StorageProvider interface with 4 backends
- FileService with HTTP handlers
- Multipart upload support
- 86 property-based tests
- Retry mechanism with exponential backoff

Breaking: None (backward compatible)
This commit is contained in:
qinqx
2026-01-25 14:07:34 +08:00
parent fa26a136e6
commit e7760ea80d
33 changed files with 17951 additions and 159 deletions
+164
View File
@@ -0,0 +1,164 @@
module hono
import io
// 存储操作结果
pub struct StorageResult {
pub:
success bool
object_key string
etag string
size i64
error_msg string
}
// 文件对象信息
pub struct ObjectInfo {
pub:
key string
size i64
etag string
content_type string
last_modified i64
metadata map[string]string
}
// 列表选项
pub struct ListOptions {
pub:
prefix string
delimiter string
max_keys int = 1000
start_after string
}
// 列表结果
pub struct ListResult {
pub:
objects []ObjectInfo
common_prefixes []string
is_truncated bool
next_marker string
}
// 预签名URL选项
pub struct PresignOptions {
pub:
expires_in int = 3600 // 秒
method string = 'GET'
content_type string
}
// 分片信息
pub struct PartInfo {
pub:
part_number int
etag string
size i64
}
// 统一存储接口
pub interface StorageProvider {
mut:
// 基本操作
upload(bucket string, key string, data []u8, content_type string) !StorageResult
upload_stream(bucket string, key string, mut reader io.Reader, size i64, content_type string) !StorageResult
download(bucket string, key string) ![]u8
download_stream(bucket string, key string, mut writer io.Writer) !i64
delete(bucket string, key string) !
exists(bucket string, key string) !bool
// 元数据操作
head(bucket string, key string) !ObjectInfo
copy(src_bucket string, src_key string, dst_bucket string, dst_key string) !StorageResult
// 列表操作
list(bucket string, options ListOptions) !ListResult
// 预签名URL
presign_url(bucket string, key string, options PresignOptions) !string
// 分片上传
init_multipart(bucket string, key string, content_type string) !string // 返回 upload_id
upload_part(bucket string, key string, upload_id string, part_number int, data []u8) !string // 返回 etag
complete_multipart(bucket string, key string, upload_id string, parts []PartInfo) !StorageResult
abort_multipart(bucket string, key string, upload_id string) !
// Bucket 操作
create_bucket(bucket string) !
delete_bucket(bucket string) !
bucket_exists(bucket string) !bool
// 获取提供者名称
provider_name() string
}
// 创建成功的存储结果
pub fn new_storage_result(object_key string, etag string, size i64) StorageResult {
return StorageResult{
success: true
object_key: object_key
etag: etag
size: size
error_msg: ''
}
}
// 创建失败的存储结果
pub fn new_storage_error_result(error_msg string) StorageResult {
return StorageResult{
success: false
object_key: ''
etag: ''
size: 0
error_msg: error_msg
}
}
// 创建对象信息
pub fn new_object_info(key string, size i64, etag string, content_type string, last_modified i64) ObjectInfo {
return ObjectInfo{
key: key
size: size
etag: etag
content_type: content_type
last_modified: last_modified
metadata: map[string]string{}
}
}
// 创建带元数据的对象信息
pub fn new_object_info_with_metadata(key string, size i64, etag string, content_type string, last_modified i64, metadata map[string]string) ObjectInfo {
return ObjectInfo{
key: key
size: size
etag: etag
content_type: content_type
last_modified: last_modified
metadata: metadata
}
}
// 创建空的列表结果
pub fn new_empty_list_result() ListResult {
return ListResult{
objects: []ObjectInfo{}
common_prefixes: []string{}
is_truncated: false
next_marker: ''
}
}
// 创建列表结果
pub fn new_list_result(objects []ObjectInfo, common_prefixes []string, is_truncated bool, next_marker string) ListResult {
return ListResult{
objects: objects
common_prefixes: common_prefixes
is_truncated: is_truncated
next_marker: next_marker
}
}
// 创建分片信息
pub fn new_part_info(part_number int, etag string, size i64) PartInfo {
return PartInfo{
part_number: part_number
etag: etag
size: size
}
}