@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in
113 lines • 4.21 kB
JavaScript
// workaround for this is not a function when deployed
// see https://github.com/pvorb/node-md5/issues/52
import md5 from "md5";
export class Upload_Result {
success;
filename;
hash;
size;
url;
constructor(success, filename, hash, size) {
this.success = success;
this.filename = filename;
this.hash = hash;
this.size = size;
}
}
export async function upload_file(file, url) {
const buffer = await file.arrayBuffer();
const hashString = hash(buffer);
const ext = file.name.split('.').pop();
const filename = hashString + "." + ext;
const alias = file.name.split('.').shift();
console.assert(alias !== undefined);
const body = { alias: alias, filename: filename };
const exists = await fetch(url + '/exists', { method: "POST", body: JSON.stringify(body) });
const answer = await exists.json();
if (!answer.success) {
console.warn("exists check did fail");
}
if (answer.exists) {
console.log("file already exists", hashString);
return new Upload_Result(true, filename, hashString, file.size);
}
console.log("begin uploading file", alias, file.size);
const formData = new FormData();
formData.append("file", file);
const headers = {};
headers["filesize"] = file.size;
if (alias)
headers["alias"] = alias;
const upload_res_raw = await fetch(url + '/upload/file', { method: "POST", body: formData, headers: headers });
const upload_res = await upload_res_raw.json();
if (upload_res?.success === false) {
if (upload_res.message !== undefined) {
console.error("Upload failed:", upload_res.message);
}
else {
console.error("Upload failed");
}
return null;
}
console.assert(upload_res.hash_sum === hashString, "hash sum did not match", "received:", upload_res.hash_sum, "expected:", hashString);
if (upload_res.success)
console.log("successfully uploaded", hashString, upload_res.id);
const res = new Upload_Result(upload_res.success, filename, hashString, file.size);
res.url = url;
return res;
}
export function hash(buffer) {
return md5(new Uint8Array(buffer));
}
;
export async function download_file(filename, expectedHash, expectedSize, serverUrl, skipChecks = false) {
try {
const download_res = await fetch(serverUrl + '/download/file', { method: "POST", body: filename });
if (download_res.status !== 200) {
// const res = await download_res.json();
console.error("download failed", download_res);
return null;
}
const bin = await download_res.blob();
const buffer = await bin.arrayBuffer();
if (!skipChecks)
console.assert(bin.size === expectedSize, "size mismatch", "expected:", expectedSize, "got:", bin.size);
const result_hash = hash(buffer);
if (!skipChecks)
console.assert(result_hash === expectedHash, "hash mismatch, downloaded file is invalid");
return bin.arrayBuffer();
}
catch (err) {
console.error(err);
}
return null;
}
export async function download(url, progressCallback) {
const response = await fetch(url);
const reader = response.body?.getReader();
const contentLength = response.headers.get('Content-Length');
const total = contentLength ? parseInt(contentLength) : 0;
if (!reader)
return null;
let received = 0;
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (value) {
chunks.push(value);
received += value.length;
progressCallback.call(null, new ProgressEvent('progress', { loaded: received, total: total }));
}
if (done) {
break;
}
}
const final = new Uint8Array(received);
let position = 0;
for (const chunk of chunks) {
final.set(chunk, position);
position += chunk.length;
}
return final;
}
//# sourceMappingURL=engine_web_api.js.map