fix garageS3

This commit is contained in:
2026-08-27 20:46:23 +07:00
parent 64575d81b5
commit d032cec0b2
3 changed files with 279 additions and 86 deletions
+124 -7
View File
@@ -1,4 +1,4 @@
module GarageS3
module garageS3
export
GarageStorage,
@@ -7,8 +7,7 @@ export
list_files,
delete_file
using AWS
using AWSS3
using AWS, AWSS3
# ---------------------------------------------- 100 --------------------------------------------- #
# Garage uses Path-Style routing (https://s3-api.my-domain.com/bucket/key).
@@ -64,10 +63,36 @@ AWS.check_credentials(c::SimpleCredentials) = c
AWS.region(aws::GarageConfig) = aws.region
AWS.credentials(aws::GarageConfig) = aws.credentials
""" Generate the base URL for a Garage S3 service request.
# Arguments
- `aws::GarageConfig`
The Garage configuration containing the endpoint.
- `service::String`
The AWS service name (e.g., `"s3"`).
- `region::String`
The AWS region string.
# Return
- `String`: The stripped endpoint URL (trailing slashes removed).
"""
function AWS.generate_service_url(aws::GarageConfig, service::String, region::String)
return strip(aws.endpoint, '/')
end
""" Generate the full service URL including the resource path for a Garage S3 request.
# Arguments
- `aws::GarageConfig`
The Garage configuration containing the endpoint.
- `service::String`
The AWS service name (e.g., `"s3"`).
- `resource::String`
The S3 resource path (e.g., `"/bucket/key"`).
# Return
- `String`: The full URL combining the endpoint and resource path.
"""
function AWS.generate_service_url(aws::GarageConfig, service::String, resource::String)
endpoint = strip(aws.endpoint, '/')
resource_path = startswith(resource, '/') ? resource : "/" * resource
@@ -82,14 +107,61 @@ struct GarageStorage
config::GarageConfig
bucket::String
end
""" Create a thread-safe Garage S3 storage client.
# Arguments
- `endpoint::String`
The Garage S3 API endpoint URL (e.g., `"https://s3-api.yiem.cc"`).
- `key::String`
The Garage access key ID (created via garage-ui).
- `secret::String`
The secret key corresponding to the access key.
- `bucket::String`
The name of the S3 bucket to use.
# Keyword Arguments
- `region::String = "garage"`
The region identifier for the Garage instance.
# Return
- `GarageStorage`: A thread-safe storage client instance.
# Examples
```jldoctest
julia> storage = GarageStorage("https://s3-api.yiem.cc", "GKb080154a2e5b19100b1b2c6e", "a2c6b1379c2f731d3e6e5a408dd4d6cffca7511717675f55114ff94828febca1", "sommpanion-s3")
GarageStorage(GarageConfig(...), "sommpanion-s3")
```
"""
function GarageStorage(endpoint::String, key::String, secret::String, bucket::String; region::String="garage")
creds = SimpleCredentials(key, secret, "")
config = GarageConfig(endpoint, region, creds)
return GarageStorage(config, bucket)
end
# Write object to Garage
""" Upload an object to the Garage S3 bucket.
# Arguments
- `storage::GarageStorage`
The storage client instance.
- `key::String`
The object key (name) in the bucket. Must not contain slashes (`/`).
- `data::Union{String, Vector{UInt8}}`
The data to upload.
# Return
- `Nothing` if the key contains slashes (upload aborted with warning).
- Prints a success message if the upload completes.
# Notes
- Slashes in keys are prohibited to prevent S3 listing issues. Use a flat naming
convention (e.g., `"users-1002.json"` instead of `"users/1002.json"`).
# Examples
```julia
julia> put_file(storage, "test.json", "{\"status\": \"active\"}")
Successfully uploaded: test.json
```
"""
function put_file(storage::GarageStorage, key::String, data::Union{String, Vector{UInt8}})
# Check if the key contains a slash (virtual folder character)
if occursin('/', key)
@@ -102,19 +174,64 @@ function put_file(storage::GarageStorage, key::String, data::Union{String, Vecto
println("Successfully uploaded: ", key)
end
# Read object from Garage
""" Download an object from the Garage S3 bucket.
# Arguments
- `storage::GarageStorage`
The storage client instance.
- `key::String`
The object key (name) in the bucket.
# Return
- `Vector{UInt8}`: The raw bytes of the downloaded object.
# Examples
```julia
julia> data = String(get_file(storage, "test.json"))
"\"{\\\"status\\\": \\\"active\\\"}\""
```
"""
function get_file(storage::GarageStorage, key::String)::Vector{UInt8}
return s3_get(storage.config, storage.bucket, key)
end
# List keys in bucket (Thread-safe & explicit credentials)
""" List all object keys in the Garage S3 bucket.
# Arguments
- `storage::GarageStorage`
The storage client instance.
# Return
- `Vector{String}`: A list of object keys (file names) in the bucket.
# Examples
```julia
julia> keys = list_files(storage)
3-element Vector{String}:
"test1.json"
"test2.json"
"users-1002.json"
```
"""
function list_files(storage::GarageStorage)
# Approach 2: s3_list_objects returns a Vector of Dicts with object details
objects = s3_list_objects(storage.config, storage.bucket)
return [obj["Key"] for obj in objects]
end
# Delete object from Garage
""" Delete an object from the Garage S3 bucket.
# Arguments
- `storage::GarageStorage`
The storage client instance.
- `key::String`
The object key (name) to delete.
# Examples
```julia
julia> delete_file(storage, "test.json")
```
"""
function delete_file(storage::GarageStorage, key::String)
s3_delete(storage.config, storage.bucket, key)
end