본문으로 건너뛰기

원시 파일 ​

리포지토리의 파일 경로는 웹 서버의 파일처럼 동작합니다. PUT은 본문을 경로의 다음 버전으로 저장합니다. GET은 현재 버전을 반환합니다. curl이나 PowerShell만 있고 다른 도구가 없는 빌드 스크립트와 CI 작업에서 사용하세요.

주소는 세 가지 메서드 모두 같습니다:

text
https://<host>/api/v1/repositories/<repository>/raw/<path>

예: https://arkvory.example/api/v1/repositories/releases/raw/builds/game/1.4/GameSetup.exe.

파일 저장 ​

리포지토리와 쓰기 액세스가 있는 키가 필요합니다. 계정 및 키를 참조하세요. 키를 Authorization: Bearer <key>로 보내세요. 원시 파일은 다른 종류의 인증을 받지 않습니다.

bash
export ARKVORY_KEY="$(cat ~/.arkvory/key)"
URL="https://arkvory.example/api/v1/repositories/releases/raw/builds/game/1.4/GameSetup.exe"

curl --fail-with-body -sS -T ./GameSetup.exe \
  -H "Authorization: Bearer $ARKVORY_KEY" \
  "$URL"
powershell
$headers = @{ Authorization = "Bearer $env:ARKVORY_KEY" }
$url = 'https://arkvory.example/api/v1/repositories/releases/raw/builds/game/1.4/GameSetup.exe'
Invoke-RestMethod -Method Put -InFile .\GameSetup.exe -Headers $headers -Uri $url
bash
wget -qO- --method=PUT --body-file=GameSetup.exe \
  --header="Authorization: Bearer $ARKVORY_KEY" "$URL"

curl -T에는 폴더가 아니라 파일의 전체 주소를 주세요. URL이 허용하지 않는 문자는 경로에서 인코딩하세요. 공백은 %20, #은 %23, ?는 %3F로 씁니다.

응답은 JSON입니다. 새 파일이나 새 바이트는 201을 반환합니다:

json
{
  "path": "builds/game/1.4/GameSetup.exe",
  "revision": 1,
  "created": true,
  "artifact": { "id": "00000000-0000-4000-8000-000000000001", "size": "1048576", "sha256": "…" }
}

경로에 이미 정확히 이 바이트가 있으면 "created": false와 같은 리비전으로 200을 반환합니다. 아무것도 저장되지 않습니다. CI 작업의 한 단계는 새 버전을 만들지 않고 다시 실행할 수 있습니다. size는 십진수 문자열입니다.

체크섬 보내기 ​

X-Checksum-Sha256으로 파일의 SHA-256을, Content-Length로 길이를 보내세요. curl -T와 PowerShell은 파일의 길이를 보냅니다. 그러면 서버는 바이트를 한 번에 스토리지에 직접 쓰고 그곳에서 검사합니다. 잘못된 체크섬은 integrity_mismatch 코드와 함께 422를 반환하고, 아무것도 저장하지 않으며, 경로를 그대로 유지합니다.

bash
curl --fail-with-body -sS -T ./GameSetup.exe \
  -H "Authorization: Bearer $ARKVORY_KEY" \
  -H "X-Checksum-Sha256: $(sha256sum GameSetup.exe | cut -d' ' -f1)" \
  "$URL"
powershell
$headers['X-Checksum-Sha256'] = (Get-FileHash .\GameSetup.exe -Algorithm SHA256).Hash.ToLower()
Invoke-RestMethod -Method Put -InFile .\GameSetup.exe -Headers $headers -Uri $url

체크섬 없이, 또는 Content-Length가 없는 청크 본문으로 보내면 서버는 먼저 본문을 임시 파일에 쓰고 해시합니다. 그런 다음 저장합니다. 이 경우 잠시 동안 서버 디스크에 파일 크기의 최대 두 배가 필요하고, 바이트를 두 번 처리합니다. 실패로 남은 임시 파일은 서버가 하루 뒤에 제거합니다.

체크섬과 길이를 보냈는데 경로에 이미 이 바이트가 있으면, 서버는 본문을 읽지 않고 200으로 응답하고 연결을 닫습니다.

생성만 ​

PUT은 조건을 하나만 읽습니다: If-None-Match: *. 이를 사용하면 서버는 경로가 없을 때만 파일을 저장합니다. 그렇지 않으면 바이트가 같아도 사유 already_exists와 함께 409로 응답합니다. PUT의 If-None-Match에 다른 값을 쓰면 400을 반환합니다.

bash
curl --fail-with-body -sS -T ./notes.txt \
  -H "Authorization: Bearer $ARKVORY_KEY" -H "If-None-Match: *" \
  "https://arkvory.example/api/v1/repositories/releases/raw/docs/notes.txt"

두 작성자 ​

두 요청이 동시에 같은 경로를 변경하면 먼저 온 쪽이 이깁니다. 나중 요청은 사유 revision_mismatch와 함께 409를 받고, 경로는 이긴 쪽의 내용을 유지합니다. 새 리비전을 만들려면 요청을 다시 실행하세요. 진 쪽이 업로드한 바이트는 보존이 제거할 때까지 경로 없는 아티팩트로 남습니다.

파일 읽기 ​

GET은 경로의 현재 버전을 반환합니다. HEAD는 헤더만 반환합니다.

bash
curl --fail-with-body -sS -H "Authorization: Bearer $ARKVORY_KEY" -o GameSetup.exe "$URL"
powershell
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Headers $headers -Uri $url -OutFile .\GameSetup.exe
bash
wget --header="Authorization: Bearer $ARKVORY_KEY" -O GameSetup.exe "$URL"

응답 헤더:

헤더값
ETag"sha256:<digest>": 콘텐츠의 SHA-256(따옴표 포함)
Content-Length파일 크기
Accept-Rangesbytes
Content-Type항상 application/octet-stream
Content-Disposition경로의 마지막 세그먼트를 파일 이름으로 한 attachment
X-Arkvory-Artifact-Id이 버전을 담고 있는 아티팩트의 ID

알 수 없는 경로는 404를 반환합니다.

범위와 조건부 요청 ​

요청 헤더효과
Range: bytes=0-1023요청한 부분과 Content-Range가 있는 206. 파일 끝을 넘는 시작은 Content-Range: bytes */<size>와 함께 416을 반환합니다.
Range: bytes=-1024마지막 1024바이트
Range: bytes=1048576-오프셋부터 끝까지
If-Range: "sha256:…"ETag가 정확히 이것일 때만 Range를 적용합니다. 경로가 새 버전이면 새 파일 전체를 받습니다.
If-None-Match: "sha256:…"ETag가 같으면 본문 없이 304. HEAD에서도 동작합니다.

한 요청에 범위 하나만 지원합니다. 여러 범위를 가진 요청은 파일 전체를 반환합니다.

경로는 언제든 새 버전이 될 수 있고, GET은 경로를 다시 확인합니다. 다운로드를 안전하게 이어서 하려면 첫 응답의 ETag를 기억해 If-Range로 보내세요:

bash
etag=$(curl -sSI -H "Authorization: Bearer $ARKVORY_KEY" "$URL" | awk 'tolower($1)=="etag:" {print $2}' | tr -d '\r')
curl -sS -H "Authorization: Bearer $ARKVORY_KEY" -H "If-Range: $etag" \
  -H "Range: bytes=1048576-" "$URL" >> GameSetup.part

파일이 변경되지 않았을 때 다운로드를 건너뛰려면, 지난번에 저장한 ETag를 보내세요:

bash
curl -sS -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $ARKVORY_KEY" \
  -H 'If-None-Match: "sha256:<digest>"' "$URL"

대용량 파일에는 arkvoryctl get이 재개와 SHA-256 검증을 대신 처리합니다.

경로와 버전 ​

원시 파일은 경로 기반 파일입니다. 새 바이트로 하는 모든 PUT은 경로에 리비전을 추가합니다: 리비전 1, 2, 3 등입니다. 이전 리비전은 남습니다. 각 리비전이 경로의 마지막 세그먼트 이름을 딴 자체 불변 아티팩트를 가리키므로 바이트는 절대 대체되지 않습니다.

  • 원시 주소의 GET은 항상 현재 리비전을 제공합니다.
  • 경로의 모든 리비전을 보려면 기록을 읽으세요: getAssetHistory 또는 콘솔의 파일 기록.
  • 이전 리비전을 읽으려면 getAssetRevision이 해당 아티팩트를 반환합니다. 아티팩트의 콘텐츠 주소로 내려받으세요.
  • 이전 리비전으로 되돌리려면 restoreAsset을 사용하세요. 이전 바이트를 가리키는 새 리비전을 추가합니다.
  • 리포지토리의 경로를 접두사로 나열하려면 listAssetPage를 사용하세요.
  • 경로는 삭제할 수 없습니다. 기록은 남습니다. 보존은 경로 리비전이 사용하는 아티팩트를 제거하지 않습니다.

같은 작업이 SDK(client.raw.putRawFile, downloadRawFile)와 arkvoryctl(put, get)에 있습니다.

경로 규칙 ​

규칙값
길이1~1024자
폴더/로 구분된 세그먼트
허용 안 함빈 세그먼트(a//b), . 또는 .., 백슬래시, 콜론, 제어 문자

curl과 브라우저는 보내기 전에 URL에서 .과 ..을 제거하므로 그런 경로는 도달하지 않습니다. 규칙을 어긴 경로는 400을 반환합니다.

권한 ​

개인용 토큰과 파일 키는 리포지토리에 대한 읽기 또는 쓰기 액세스를 가집니다. 서비스 키는 정확한 작업을 가집니다.

작업서비스 키 작업개인용 토큰 또는 파일 키
GET, HEADcontent.read읽기 액세스
PUTupload.create, upload.write, upload.complete, asset.read, asset.write, artifact.read쓰기 액세스, 토큰 범위 read-write

다운로드만 하는 배포 에이전트에는 content.read 작업이 필요합니다.

읽기 게이트웨이는 GET과 HEAD만 받습니다. 미러는 읽기를 제공하고 409와 사유 mirror_read_only로 PUT을 거부합니다.

제한 ​

제한값
파일 크기설치의 최대 객체 크기, ARKVORY_MAX_OBJECT_BYTES(기본 약 10 TiB)
하나의 PUT 요청30분 안에 끝나야 하고 30초 넘게 멈추면 안 됩니다(ARKVORY_UPLOAD_DEADLINE_MS, ARKVORY_UPLOAD_IDLE_TIMEOUT_MS). 이것이 허용되는 최댓값이기도 합니다.
동시 업로드기본적으로 서버당 2개, 키당 1개(ARKVORY_MAX_UPLOADS, ARKVORY_MAX_UPLOADS_PER_PRINCIPAL). 대기 중인 요청은 20초 후 503과 함께 포기합니다.
동시 다운로드기본적으로 서버당 16개, 키당 4개
할당량파일이 리포지토리 할당량과 설치 용량에 포함됨

하나의 PUT에는 재개가 없습니다. 실패하면 처음 바이트부터 다시 시작합니다. 원시 파일은 작은 파일과 중간 크기 파일, 그리고 스크립트에 사용하세요. 대용량 파일이나 느린 네트워크에는 arkvoryctl put 또는 SDK를 사용하세요. 파트로 나누어 업로드하고, 실패 후 이어서 진행하며, SHA-256을 검사합니다. 또한 파일을 경로의 리비전으로 저장합니다. 변수에 대한 설명은 환경 변수에 있습니다.

Unity Addressables ​

Addressables는 일반 GET 요청으로 카탈로그와 번들을 불러오므로 빌드 폴더를 raw 경로 아래에 둘 수 있습니다. 내부 빌드, QA, 도구에 적합합니다. 공개 인터넷의 플레이어에게는 적합하지 않습니다. raw 읽기에는 항상 키가 필요하고, 다운로드 링크는 24시간 안에 만료되며, 배포된 클라이언트 안의 키는 비밀이 아니기 때문입니다.

arkvoryctl put으로 폴더를 업로드하세요. 바이트가 바뀌지 않은 파일은 다시 보내지 않습니다. 경로는 항상 최신 리비전을 반환하고 오래된 카탈로그가 새 번들과 만나면 안 되므로, 빌드마다 폴더 하나를 사용하세요.

bash
cd ServerData/StandaloneWindows64
find . -type f | while read -r file; do
  arkvoryctl put "$file" "addressables/game/$BUILD/StandaloneWindows64/${file#./}" || exit 1
done
powershell
$root = (Resolve-Path .\ServerData\StandaloneWindows64).Path
Get-ChildItem $root -Recurse -File | ForEach-Object {
  $relative = $_.FullName.Substring($root.Length + 1) -replace '\\', '/'
  arkvoryctl put $_.FullName "addressables/game/$env:BUILD/StandaloneWindows64/$relative"
  if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}

Addressables 프로필의 원격 로드 경로를 그 폴더의 raw 주소로 설정하세요. 예: https://arkvory.example/api/v1/repositories/releases/raw/addressables/game/<build>/[BuildTarget]. 클라이언트에는 읽기만 가능한 키를 주세요. 읽기 권한이 있는 개인용 액세스 토큰이나 content.read 동작이 있는 서비스 키입니다. raw는 Authorization 헤더의 키만 받으므로 모든 요청에 설정하세요.

csharp
Addressables.WebRequestOverride = request =>
{
    if (request.url.StartsWith("https://arkvory.example/"))
        request.SetRequestHeader("Authorization", "Bearer " + readKey);
};

Addressables 1.x에서 이 속성은 Addressables.WebRequestOverride입니다. 사용 중인 버전에서 이름을 확인하세요. 이것은 검증된 통합이 아니라 하나의 패턴입니다.

문제 해결 ​

오류는 code, reason, message, requestId가 있는 JSON 문서입니다. 오류를 참조하세요. 서버 로그에서 요청을 찾을 수 있도록 관리자에게 requestId를 알려 주세요.

상태사유원인해결 방법
400validation경로, Content-Length, X-Checksum-Sha256 또는 If-None-Match가 유효하지 않음경로 규칙을 확인하고 URL을 인코딩하세요
401credential_missing, credential_invalid, token_expired키가 없거나, 잘못된 키이거나, 만료된 토큰Authorization: Bearer <key>를 보내세요. 원시 파일에는 Basic 인증이 동작하지 않습니다.
403permission_missing, read_only_token키가 쓸 수 없거나 읽기 전용 토큰권한의 작업을 가진 키를 사용하세요
404경로가 없거나 키가 리포지토리를 볼 수 없음리포지토리 이름과 경로를 확인하세요
409already_existsIf-None-Match: *인데 경로가 존재헤더를 제거하고 리비전을 추가하세요
409revision_mismatch다른 요청이 먼저 경로를 변경함요청을 다시 실행하세요
409mirror_read_only리포지토리가 미러임주 서버에 쓰세요
416range_not_satisfiable범위가 파일 끝 뒤에서 시작HEAD로 크기를 확인하세요
422integrity_mismatch본문이 X-Checksum-Sha256 또는 Content-Length와 일치하지 않음체크섬을 다시 계산하고 프록시를 확인하세요
503busy동시 전송이 너무 많음Retry-After의 시간을 기다린 뒤 다시 시도하세요
507storage_quota리포지토리 할당량 또는 설치 용량에 도달함공간을 확보하거나 더 큰 할당량을 요청하세요
상태 아님전송 중 curl: (55) 또는 (56)서버가 연결을 닫음. 경로에 이미 바이트가 있으면 200으로 응답하고 닫습니다.curl -i를 실행하고 응답을 읽으세요
상태 아님30분 후 연결이 닫힘업로드 기한arkvoryctl put을 사용하세요

Arkvory · ProAnimaStudio