Mine sisu juurde
Sursa Developers

Suurte failide üleslaadimine

Faili saab saata ühe päringuga POST /v1/cards kuni paigalduse üleslaadimislimiidini (vaikimisi 200 MB). Suurema faili või sellise võrgu korral, kus pikk päring tõenäoliselt katkeb, laadige fail üles osadena:

  1. Looge üleslaadimine: teatage Sursale faili nimi, tüüp ja suurus.
  2. Saatke osad mis tahes järjekorras ja soovi korral paralleelselt. Ebaõnnestunud osa saadetakse eraldi uuesti.
  3. Lõpetage üleslaadimine kogu faili SHA-256 räsiga. Sursa paneb faili kokku ja kontrollib seda.
  4. Kasutage faili asemel üleslaadimise ID-d: kaardi, arhiivi või kohandatud allika dokumendi jaoks.
PiirangVäärtus
Faili suurusKuni 5 GB
Osa suurusSursa valib selle väljal part_size, 5–100 MiB; viimane osa võib olla väiksem
Osade arvKuni 1000
Aeg lõpetamiseks24 tundi pärast üleslaadimise loomist
Aeg lõpetatud üleslaadimise kasutamiseks24 tundi

1. Looge üleslaadimine

POST /v1/uploads võtab vastu faili nime, tüübi ja suuruse ning selle, milleks kavatsete faili kasutada:

FILE=training-video-transcripts.zip
SIZE=$(wc -c < "$FILE" | tr -d ' ')

curl -X POST https://api.sursa.com/v1/uploads \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d "{\"filename\": \"$FILE\", \"content_type\": \"application/zip\", \"size\": $SIZE, \"purpose\": \"archive\"}"
{
  "id": "upl_5d3c2b1a0f9e8d7c6b5a493827161504",
  "status": "pending",
  "part_size": 8388608,
  "part_count": 23,
  "expires_at": "2026-10-25T10:00:00Z"
}
purposeÜleslaadimist kasutatakse
card_fileKaardi jaoks: POST /v1/cards.
archiveDokumendiarhiivi jaoks: POST /v1/cards/archive.
import_attachmentKohandatud allika dokumendi failina väljal upload_id või attachments.

Võtmel peab olema selle koha ulatus, kuhu üleslaadimine läheb: card_file ja archive jaoks cards:write, import_attachment jaoks import:write.

Sursa valib väärtuse part_size ja ütleb, mitu osa saata. Kui teate faili SHA-256 räsi ette, võite selle siin edastada ka väljal sha256.

2. Saatke osad

Lõigake fail part_count tükiks, igaüks part_size baiti (viimane on ülejääk), ja saatke iga tükk päringuga PUT /v1/uploads/{upload_id}/parts/{n}. Osad nummerdatakse alates 1-st. Keha on osa toored baidid.

UPLOAD=upl_5d3c2b1a0f9e8d7c6b5a493827161504
split -b 8388608 -a 4 "$FILE" part-

n=1
for part in part-*; do
  curl -X PUT "https://api.sursa.com/v1/uploads/$UPLOAD/parts/$n" \
    -H "Authorization: Bearer $SURSA_API_KEY" \
    -H "Content-Type: application/octet-stream" \
    --data-binary "@$part" --retry 5 --fail
  n=$((n + 1))
done

Osa uuesti saatmine asendab selle, seega saadetakse ebaõnnestunud või ajalõpuga osa lihtsalt uuesti. Kuni 4 paralleelset osa kasutavad kiire ühenduse tavaliselt täielikult ära.

Osade kontrollimine

Iga osa läheb läbi API: otselinke salvestusruumi ei ole. Osa vastusel on päis ETag, osa SHA-256 räsi jutumärkides, ja sama väärtus JSON-keha väljal etag. GET /v1/uploads/{upload_id} loetleb väljal parts seni saabunud osad, nii et pärast katkestust saadate ainult puuduvad osad.

3. Lõpetage üleslaadimine

POST /v1/uploads/{upload_id}/complete võtab vastu kogu faili SHA-256 räsi 64 kuueteistkümnendsüsteemi märgina ja soovi korral väljal parts iga osa väärtuse etag, et kontrollida ka osi:

SHA=$(shasum -a 256 "$FILE" | cut -d' ' -f1)
curl -X POST "https://api.sursa.com/v1/uploads/$UPLOAD/complete" \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -H "Idempotency-Key: complete-$UPLOAD" \
  -H "Content-Type: application/json" \
  -d "{\"sha256\": \"$SHA\"}"

Sursa paneb osad kokku, võrdleb räsi ja kontrollib faili samamoodi nagu iga üleslaadimist: selle vormingut ja, kui see on lubatud, viirusskannimisega. Vastus on 200, kui kontroll on tehtud, ja 202, kui see veel käib. Üleslaadimise olek muutub väärtuselt processing väärtusele ready või väärtusele rejected, mille põhjus on väljal reject_reason. Lugege olekut päringuga GET /v1/uploads/{upload_id}.

4. Kasutage üleslaadimist

Edastage upload_id seal, kus saadaksite faili. Iga üleslaadimist kasutatakse üks kord: pärast seda on selle olek consumed.

Kaardi ja arhiivi puhul saatke upload_id vormi multipart/form-data asemel JSON-kehas. See keha võtab kogu vastu selle nime järgi väljal collection.

# A card from the uploaded file
curl -X POST https://api.sursa.com/v1/cards \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -H "Idempotency-Key: card-from-$UPLOAD" \
  -H "Content-Type: application/json" \
  -d "{\"upload_id\": \"$UPLOAD\", \"collection\": \"support\", \"async\": true}"

# An archive of documents from the uploaded ZIP
curl -X POST https://api.sursa.com/v1/cards/archive \
  -H "Authorization: Bearer $SURSA_API_KEY" \
  -H "Idempotency-Key: archive-from-$UPLOAD" \
  -H "Content-Type: application/json" \
  -d "{\"upload_id\": \"$UPLOAD\", \"collection\": \"support\"}"

Täielik üleslaadija

import { createHash } from "node:crypto";
import { createReadStream } from "node:fs";
import { open, stat } from "node:fs/promises";
import { basename } from "node:path";

const BASE = "https://api.sursa.com";
const auth = { Authorization: `Bearer ${process.env.SURSA_API_KEY}` };

async function call(method, path, body, headers = {}) {
  const isJson = body !== undefined && !(body instanceof Uint8Array);
  const response = await fetch(BASE + path, {
    method,
    headers: { ...auth, ...(isJson ? { "Content-Type": "application/json" } : {}), ...headers },
    body: isJson ? JSON.stringify(body) : body,
  });
  if (!response.ok) throw new Error(`${method} ${path}: HTTP ${response.status} ${await response.text()}`);
  return response.json();
}

export async function uploadLargeFile(file, contentType, purpose, parallel = 4) {
  const { size } = await stat(file);
  const upload = await call("POST", "/v1/uploads",
    { filename: basename(file), content_type: contentType, size, purpose },
    { "Idempotency-Key": crypto.randomUUID() });

  const hash = createHash("sha256");
  for await (const block of createReadStream(file)) hash.update(block);

  const handle = await open(file);

  let next = 1;
  async function worker() {
    for (let n = next++; n <= upload.part_count; n = next++) {
      const buffer = new Uint8Array(Math.min(upload.part_size, size - (n - 1) * upload.part_size));
      await handle.read(buffer, 0, buffer.length, (n - 1) * upload.part_size);
      for (let attempt = 1; ; attempt++) {
        try {
          await call("PUT", `/v1/uploads/${upload.id}/parts/${n}`, buffer, { "Content-Type": "application/octet-stream" });
          break;
        } catch (error) {
          if (attempt === 5) throw error;
          await new Promise((resolve) => setTimeout(resolve, 1000 * 2 ** attempt));
        }
      }
    }
  }
  await Promise.all(Array.from({ length: parallel }, worker));
  await handle.close();

  await call("POST", `/v1/uploads/${upload.id}/complete`, { sha256: hash.digest("hex") },
    { "Idempotency-Key": `complete-${upload.id}` });
  for (;;) {
    const state = await call("GET", `/v1/uploads/${upload.id}`);
    if (state.status === "ready") return upload.id;
    if (state.status === "rejected") throw new Error(`upload rejected: ${state.reject_reason}`);
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
}

Vead

KoodOlekPõhjus
uploads.too_large413Fail on suurem kui 5 GB või suurem kui organisatsiooni paketi kogu salvestusruum.
limits.storage402Organisatsioonil ei ole faili jaoks piisavalt vaba salvestusruumi.
uploads.part_invalid400Osa number on vahemikust väljas või osa suurus ei ole lubatud piirides.
uploads.checksum_mismatch422Kokkupandud faili SHA-256 ei ole see, mille saatsite. Mõni osa on rikutud või puudub: saatke osad uuesti ja lõpetage üleslaadimine uuesti.
uploads.not_ready409Üleslaadimine ei ole veel lõpetatud ega kontrollitud. Oodake olekut ready.
uploads.already_used409Üleslaadimist on juba kasutatud. Iga üleslaadimist kasutatakse üks kord.
uploads.expired410Möödunud on üle 24 tunni. Looge uus üleslaadimine.
uploads.rejected422Fail ei läbinud kontrolle, näiteks selle vorming ei vasta selle nimele. Teade ütleb, miks.
uploads.not_found404Organisatsioonis sellist üleslaadimist ei ole.