#!/usr/bin/env bash # PUT one local file to the presigned URL that creative_upload_from_url (begin) # handed back. The bytes go straight from this machine to object storage — # never through the model, never through the gateway. # # upload_local_asset.sh # # is the tool result saved to a file. It carries # `upload_url`, `method` and `headers` (a JSON object); `reused: true` means # the library already holds these bytes and there is nothing to send. set -euo pipefail file="${1:?file path}" ticket="${2:?path to the saved begin result JSON}" reused=$(python3 -c 'import json,sys; print(str(json.load(open(sys.argv[1])).get("reused", False)).lower())' "$ticket") if [ "$reused" = "true" ]; then echo "reused: library already holds these bytes as an asset, nothing to upload" exit 0 fi url=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("upload_url") or "")' "$ticket") # An empty upload_url with reused=false means the object already sits in # storage under its content hash (a previous upload that never finished, or one # filed under another account). There is nothing to PUT; go straight to finish. # If finish then answers 409 "not in storage", the stored object is unusable: # begin again without content_sha256 to get a fresh ticket, and PUT that. if [ -z "$url" ]; then echo "in-storage: object already present, skip PUT and call finish" exit 0 fi method=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("method") or "PUT")' "$ticket") mapfile -t header_args < <(python3 - "$ticket" <<'PY' import json, sys for key, value in (json.load(open(sys.argv[1])).get("headers") or {}).items(): print("-H") print(f"{key}: {value}") PY ) status=$(curl -sS -o /dev/null -w '%{http_code}' -X "$method" "${header_args[@]}" --data-binary "@$file" "$url") if [ "$status" -ge 300 ]; then echo "upload failed: HTTP $status" >&2 exit 1 fi echo "uploaded: HTTP $status"