add garageS3 feature

This commit is contained in:
2026-08-27 19:40:21 +07:00
parent fb54fddf10
commit 64575d81b5
3 changed files with 140 additions and 1 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
name = "GeneralUtils"
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
version = "0.5.11"
version = "0.6.0"
authors = ["tonaerospace <tonaerospace.etc@gmail.com>"]
[deps]
+2
View File
@@ -21,6 +21,8 @@ using .llmUtil
include("interface.jl")
using .interface
include("garageS3.jl")
using .garageS3
#------------------------------------------------------------------------------------------------100
+137
View File
@@ -0,0 +1,137 @@
module GarageS3
export
GarageStorage,
put_file,
get_file,
list_files,
delete_file
using AWS
using AWSS3
# ---------------------------------------------- 100 --------------------------------------------- #
# Garage uses Path-Style routing (https://s3-api.my-domain.com/bucket/key).
# this file use local AWS config
""" Example
const storage = GarageStorage(
"https://s3-api.yiem.cc",
"GKb080154a2e5b19100b1b2c6e", # key ID (create at garage-ui.yiem.cc)
"a2c6b1379c2f731d3e6e5a408dd4d6cffca7511717675f55114ff94828febca1", # key ID's secret key
"sommpanion-s3"
)
# Safe to run inside concurrent HTTP handlers (e.g., Oxygen.jl, HTTP.jl)
put_file(storage, "users-1005.json", "{\"status\": \"active\"}")
keys = list_files(storage)
data = String(get_file(storage, "users-1004.json"))
println("Read back: ", data)
println("Bucket keys: ", keys)
# test with curl
curl -v \
-H 'Host: sommpanion-s3.s3-web.yiem.cc' \
http://192.168.88.106:3902/users-1002.json
# test with a browser
https://s3-web.mydomain.com/my_bucket_name/users-1002.json
"""
# ===================================================================
# 1. Custom GarageConfig Definition (Thread-Safe, No Global State)
# ===================================================================
struct SimpleCredentials
access_key_id::String
secret_key::String
token::String
end
struct GarageConfig <: AWS.AbstractAWSConfig
endpoint::String
region::String
credentials::SimpleCredentials
end
# Required extensions for AWS.jl pipeline
AWS.refresh!(c::SimpleCredentials; force::Bool=false) = c
AWS.credentials(c::SimpleCredentials) = c
AWS.check_credentials(c::SimpleCredentials) = c
AWS.region(aws::GarageConfig) = aws.region
AWS.credentials(aws::GarageConfig) = aws.credentials
function AWS.generate_service_url(aws::GarageConfig, service::String, region::String)
return strip(aws.endpoint, '/')
end
function AWS.generate_service_url(aws::GarageConfig, service::String, resource::String)
endpoint = strip(aws.endpoint, '/')
resource_path = startswith(resource, '/') ? resource : "/" * resource
return string(endpoint, resource_path)
end
# ===================================================================
# 2. Thread-Safe Storage Client Wrapper
# ===================================================================
struct GarageStorage
config::GarageConfig
bucket::String
end
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
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)
@warn "Upload aborted! Slashes ('/') are not allowed in keys ('$key') to prevent S3 listing issues. Use a flat naming convention instead (e.g., 'users-1002.json')."
return nothing
end
# Proceed if the key is flat
s3_put(storage.config, storage.bucket, key, data)
println("Successfully uploaded: ", key)
end
# Read object from Garage
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)
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
function delete_file(storage::GarageStorage, key::String)
s3_delete(storage.config, storage.bucket, key)
end
end # module GarageS3