⌘K
↑↓ Navigate ↵ Open Esc Close
Tier 2File09 / 29

File Upload: a two-step handshake, then a raw upload

Persistent State: files are effectively a fifth tier: durable like leaderboards/profile, but for binary data instead of JSON.

Uploading a file to a player's brainCloud account is a two-step handshake, not one call. prepareUserUpload tells brainCloud what's coming (path, name, size, sharing/overwrite flags) and returns an uploadId. uploadFile then performs the actual transfer against that id. The FileUploader JS example (repositories/js-examples/FileUploader) exercises this end to end, including the memory-only variant for uploading generated content, like a screenshot, without ever touching the local filesystem.

How it works

  1. Prepare first, upload second. prepareUserUpload(cloudPath, cloudFileName, isShareable, replaceIfExists, fileSize, callback) returns data.fileDetails.uploadId. Nothing is transferred yet; brainCloud just reserves the slot.
  2. The actual transfer is a separate call using that id. uploadFile(xhr, file, uploadId) takes a raw XMLHttpRequest already wired with progress/complete/error/abort listeners, plus the browser File object and the uploadId from step 1.
  3. Generated content skips the file picker entirely. uploadFileFromMemory(cloudPath, cloudFileName, isShareable, replaceIfExists, blob, callback) uploads a Blob directly. There's no prepareUserUpload handshake for this path, and no local file ever exists.
  4. Progress is tracked through the supplied XMLHttpRequest, not a brainCloud callback. xhr.upload.addEventListener("progress", ...) is standard browser API, wired before the upload call.

Code

Grab the file, guard the unselected case, then wire the XHRbraincloud-fileuploadtest.html:361-375
function uploadFile() {
  var xhr = new XMLHttpRequest();
  var file = document.getElementById('fileToUpload').files[0];

  if(file === undefined) {
    console.log("Please select a file in Step 2. to upload.");
    document.getElementById("incomingResponse").innerHTML = "Error uploading file. Please select a file in Step 2. to upload. ";
  }

  var fileSize = file.size;

  xhr.upload.addEventListener("progress", uploadProgress, false);
  xhr.addEventListener("load", uploadComplete, false);
  xhr.addEventListener("error", uploadFailed, false);
  xhr.addEventListener("abort", uploadCanceled, false);
Step 1: reserve the upload, get an idbraincloud-fileuploadtest.html:378-391
brainCloud.file.prepareUserUpload(
  document.getElementById("cloudPath").value,
  document.getElementById("cloudFileName").value,
  document.getElementById("isShareable").checked,
  document.getElementById("replaceIfExists").checked,
  fileSize,
  function(result) {
    if (result.status == 200) {
      var uploadId = result.data.fileDetails.uploadId;
      brainCloud.file.uploadFile(xhr, file, uploadId);   // step 2, actual transfer
    }
  }
);
Memory-only upload: no file picker, no prepare stepbraincloud-fileuploadtest.html:394-406
brainCloud.file.uploadFileFromMemory(
  document.getElementById("cloudPath").value,
  document.getElementById("cloudFileName").value,
  document.getElementById("isShareable").checked,
  document.getElementById("replaceIfExists").checked,
  new Blob([document.getElementById("fileInMemoryContent").value], {type: 'text/plain'}),
  function(result) { /* ... */ }
);

Gotchas worth knowing up front

  • prepareUserUpload and uploadFile are two different calls with two different jobs. The first reserves the slot and returns an id. The second does the byte transfer. Calling uploadFile without a fresh uploadId from prepareUserUpload leaves nothing to upload against.
  • This method name was a real, live bug in the reference app until it was fixed. The example was calling prepareFileUpload, a method that doesn't exist on the File service, instead of prepareUserUpload. It's fixed now (js-examples@a0f3e56), which is also what makes this article's citations trustworthy: the code shown above is the corrected, confirmed-working version, not the version that was silently broken.
  • Progress tracking is the XMLHttpRequest's job, not the SDK's. brainCloud hands back the transport primitive. Wiring progress/load/error/abort listeners is standard browser code, not a brainCloud callback pattern.
  • uploadFileFromMemory is the right tool for generated content (screenshots, exported save data). It skips the two-step handshake entirely and uploads a Blob directly. No local file required.