slate/common/file-utilities.js

212 lines
6.2 KiB
JavaScript
Raw Normal View History

import * as Actions from "~/common/actions";
2020-10-02 07:24:10 +03:00
import * as Store from "~/common/store";
2020-10-05 00:30:28 +03:00
import * as Constants from "~/common/constants";
import * as Credentials from "~/common/credentials";
2020-10-31 02:12:20 +03:00
import * as Strings from "~/common/strings";
import * as Validations from "~/common/validations";
import * as Events from "~/common/custom-events";
2020-10-02 07:24:10 +03:00
2020-10-05 00:30:28 +03:00
import { encode } from "blurhash";
2020-09-12 01:25:33 +03:00
const STAGING_DEAL_BUCKET = "stage-deal";
2020-10-05 00:30:28 +03:00
const loadImage = async (src) =>
new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "Anonymous";
img.onload = () => resolve(img);
img.onerror = (...args) => reject(args);
img.src = src;
});
const getImageData = (image) => {
2020-12-12 06:57:54 +03:00
let ratio = Math.min(100 / image.height, 100 / image.width);
image.height = image.height * ratio;
image.width = image.width * ratio;
2020-10-05 00:30:28 +03:00
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
const context = canvas.getContext("2d");
2020-12-12 06:57:54 +03:00
context.scale(ratio, ratio);
2020-10-05 00:30:28 +03:00
context.drawImage(image, 0, 0);
return context.getImageData(0, 0, image.width, image.height);
};
const encodeImageToBlurhash = async (imageUrl) => {
const image = await loadImage(imageUrl);
const imageData = getImageData(image);
return encode(imageData.data, imageData.width, imageData.height, 4, 4);
};
// NOTE(jim): We're speaking to a different server now.
const getCookie = (name) => {
var match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]+)"));
if (match) return match[2];
};
2020-11-30 02:47:08 +03:00
export const upload = async ({ file, context, bucketName, routes, excludeFromLibrary }) => {
let formData = new FormData();
const HEIC2ANY = require("heic2any");
2020-08-20 08:29:33 +03:00
// NOTE(jim): You must provide a file from an type="file" input field.
if (!file) {
return null;
}
const isZipFile =
2020-11-14 16:27:45 +03:00
file.type.startsWith("application/zip") || file.type.startsWith("application/x-zip-compressed");
const isUnityFile = await Validations.isUnityFile(file);
2020-11-14 16:27:45 +03:00
// TODO(jim): Put this somewhere else to handle conversion cases.
if (file.type.startsWith("image/heic")) {
const converted = await HEIC2ANY({
blob: file,
toType: "image/png",
quality: 1,
2020-10-02 07:24:10 +03:00
}); //TODO(martina): figure out how to cancel an await if upload has been cancelled
formData.append("data", converted);
} else {
formData.append("data", file);
}
2020-10-02 07:24:10 +03:00
if (Store.checkCancelled(`${file.lastModified}-${file.name}`)) {
return;
}
const _privateUploadMethod = (path, file) =>
new Promise((resolve, reject) => {
const XHR = new XMLHttpRequest();
window.addEventListener(`cancel-${file.lastModified}-${file.name}`, () => {
XHR.abort();
});
XHR.open("post", path, true);
XHR.setRequestHeader("authorization", getCookie(Credentials.session.key));
XHR.onerror = (event) => {
console.log(event);
2020-10-09 05:32:30 +03:00
XHR.abort();
};
// NOTE(jim): UPLOADS ONLY.
XHR.upload.addEventListener(
"progress",
(event) => {
if (!context) {
2020-08-20 08:29:33 +03:00
return;
}
if (event.lengthComputable) {
console.log("FILE UPLOAD PROGRESS", event);
context.setState({
fileLoading: {
...context.state.fileLoading,
[`${file.lastModified}-${file.name}`]: {
name: file.name,
loaded: event.loaded,
total: event.total,
},
},
});
}
},
false
);
window.removeEventListener(`cancel-${file.lastModified}-${file.name}`, () => XHR.abort());
2020-10-02 07:24:10 +03:00
XHR.onloadend = (event) => {
console.log("FILE UPLOAD END", event);
try {
return resolve(JSON.parse(event.target.response));
} catch (e) {
return resolve({
error: "SERVER_UPLOAD_ERROR",
});
}
};
XHR.send(formData);
});
const storageDealRoute =
routes && routes.storageDealUpload ? `${routes.storageDealUpload}/api/deal/` : null;
const generalRoute = routes && routes.upload ? `${routes.upload}/api/data/` : null;
2020-11-14 16:27:45 +03:00
const zipUploadRoute = routes && routes.uploadZip ? `${routes.uploadZip}/api/data/zip/` : null;
2020-11-14 16:27:45 +03:00
if (!storageDealRoute || !generalRoute || !zipUploadRoute) {
Events.dispatchMessage({ message: "We could not find our upload server." });
return {
decorator: "NO_UPLOAD_RESOURCE_URI_ATTACHED",
error: true,
};
}
let res;
if (isZipFile && isUnityFile) {
2020-11-14 16:27:45 +03:00
res = await _privateUploadMethod(`${zipUploadRoute}${file.name}`, file);
} else if (bucketName && bucketName === STAGING_DEAL_BUCKET) {
res = await _privateUploadMethod(`${storageDealRoute}${file.name}`, file);
2020-09-23 14:17:56 +03:00
} else {
res = await _privateUploadMethod(`${generalRoute}${file.name}`, file);
2020-09-23 14:17:56 +03:00
}
2020-10-05 00:30:28 +03:00
if (!res || res.error || !res.data) {
if (context) {
2020-12-12 06:57:54 +03:00
await context.setState({
2020-08-20 08:29:33 +03:00
fileLoading: {
...context.state.fileLoading,
2020-08-20 08:29:33 +03:00
[`${file.lastModified}-${file.name}`]: {
name: file.name,
failed: true,
},
},
2020-08-20 08:29:33 +03:00
});
}
Events.dispatchMessage({ message: "Some of your files could not be uploaded" });
2020-08-20 08:29:33 +03:00
return !res ? { decorator: "NO_RESPONSE_FROM_SERVER", error: true } : res;
}
2020-10-05 00:30:28 +03:00
if (res.data.data.type.startsWith("image/")) {
let url = `${Constants.gateways.ipfs}/${res.data.data.cid}`;
2020-11-02 23:27:11 +03:00
try {
let blurhash = await encodeImageToBlurhash(url);
res.data.data.blurhash = blurhash;
} catch (e) {
console.log(e);
}
2020-10-05 00:30:28 +03:00
}
2020-11-30 02:47:08 +03:00
if (!excludeFromLibrary) {
await Actions.createPendingFiles({ data: res.data });
}
2020-10-05 00:30:28 +03:00
res.data = res.data.data;
return { file, json: res };
};
export const uploadToSlate = async ({ responses, slate }) => {
let added;
let skipped;
if (responses && responses.length) {
const addResponse = await Actions.addFileToSlate({
slate,
data: responses.map((res) => {
return { title: res.file.name, ...res.json.data };
}),
});
if (Events.hasError(addResponse)) {
return;
}
added = addResponse.added;
skipped = addResponse.skipped;
}
2020-10-31 02:12:20 +03:00
let message = Strings.formatAsUploadMessage(added, skipped, true);
Events.dispatchMessage({ message, status: !added ? null : "INFO" });
};