Add support for S3-backed image storage
This commit is contained in:
1 parent
7fcb2eb747
commit
8763a8e74a
55 files changed
+2611
-111
No files matched your search
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
endpoint=http://rustfs:9000
|
||||
|
||||
if ! aws --endpoint-url "$endpoint" s3api head-bucket --bucket "$S3_BUCKET" >/dev/null 2>&1; then
|
||||
if [ "$AWS_DEFAULT_REGION" = us-east-1 ]; then
|
||||
aws --endpoint-url "$endpoint" s3api create-bucket --bucket "$S3_BUCKET"
|
||||
else
|
||||
aws --endpoint-url "$endpoint" s3api create-bucket --bucket "$S3_BUCKET" \
|
||||
--create-bucket-configuration "LocationConstraint=$AWS_DEFAULT_REGION"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Dashboard images need public object reads. Listing and writes remain authenticated.
|
||||
cat > /tmp/public-images-policy.json <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Principal": "*",
|
||||
"Action": "s3:GetObject",
|
||||
"Resource": "arn:aws:s3:::$S3_BUCKET/uploads/*"
|
||||
}]
|
||||
}
|
||||
EOF
|
||||
aws --endpoint-url "$endpoint" s3api put-bucket-policy --bucket "$S3_BUCKET" \
|
||||
--policy file:///tmp/public-images-policy.json
|
||||
echo "RustFS development bucket ready: $S3_BUCKET"
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Split an image into two lossless, random-looking PNG fixture shares."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
import secrets
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def split_image(input_path: Path, output_dir: Path, index: int | None = None) -> tuple[Path, Path]:
|
||||
if index is None:
|
||||
index = 1
|
||||
while any((output_dir / f"image_{index}{part}.png").exists() for part in ("a", "b")):
|
||||
index += 1
|
||||
if index < 1:
|
||||
raise ValueError("Image index must be a positive integer")
|
||||
|
||||
paths = (
|
||||
output_dir / f"image_{index}a.png",
|
||||
output_dir / f"image_{index}b.png",
|
||||
)
|
||||
for path in paths:
|
||||
if path.exists():
|
||||
raise FileExistsError(f"Refusing to overwrite {path}; choose another --index")
|
||||
|
||||
# RGBA shares preserve every decoded pixel, including transparency. For animated
|
||||
# inputs, use the first frame, matching the dashboard's static image upload behavior.
|
||||
with Image.open(input_path) as source:
|
||||
image = source.convert("RGBA")
|
||||
pixels = image.tobytes()
|
||||
first = secrets.token_bytes(len(pixels))
|
||||
second = bytes(pixel ^ mask for pixel, mask in zip(pixels, first))
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
for path, share in zip(paths, (first, second)):
|
||||
# Exclusive creation also prevents overwriting a file created during splitting.
|
||||
encoded = BytesIO()
|
||||
Image.frombytes("RGBA", image.size, share).save(encoded, format="PNG")
|
||||
with path.open("xb") as output:
|
||||
output.write(encoded.getvalue())
|
||||
return paths
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("input_image", type=Path)
|
||||
parser.add_argument("--output-dir", type=Path, default=Path("."))
|
||||
parser.add_argument("--index", type=int, help="Fixture number (default: first unused positive index)")
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
paths = split_image(args.input_image, args.output_dir, args.index)
|
||||
except (OSError, ValueError) as error:
|
||||
parser.exit(1, f"Could not split image: {error}\n")
|
||||
for path in paths:
|
||||
print(path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user