2020-08-16 12:23:02 +03:00
|
|
|
import * as LibraryManager from "~/node_common/managers/library";
|
|
|
|
import * as Utilities from "~/node_common/utilities";
|
|
|
|
import * as Constants from "~/node_common/constants";
|
|
|
|
|
|
|
|
import B from "busboy";
|
|
|
|
import FS from "fs";
|
|
|
|
import path from "path";
|
|
|
|
|
|
|
|
import { v4 as uuid } from "uuid";
|
|
|
|
|
|
|
|
const HIGH_WATER_MARK = 1024 * 1024 * 3;
|
|
|
|
|
|
|
|
export const formMultipart = (req, res, { user }) =>
|
|
|
|
new Promise(async (resolve, reject) => {
|
|
|
|
let form = new B({
|
|
|
|
headers: req.headers,
|
|
|
|
highWaterMark: HIGH_WATER_MARK,
|
|
|
|
});
|
|
|
|
|
|
|
|
let target = null;
|
|
|
|
let tempPath = null;
|
|
|
|
|
2020-09-22 03:36:45 +03:00
|
|
|
form.on("file", function(fieldname, file, filename, encoding, mime) {
|
2020-08-16 12:23:02 +03:00
|
|
|
target = {
|
|
|
|
type: mime,
|
|
|
|
name: filename,
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO(jim):
|
|
|
|
// Construct a stream instead.
|
2020-09-22 03:36:45 +03:00
|
|
|
tempPath = path.join(
|
|
|
|
Constants.FILE_STORAGE_URL,
|
|
|
|
path.basename(`temp-${uuid()}`)
|
|
|
|
);
|
2020-08-16 12:23:02 +03:00
|
|
|
let outStream = FS.createWriteStream(tempPath);
|
|
|
|
return file.pipe(outStream);
|
|
|
|
});
|
|
|
|
|
|
|
|
form.on("error", async (e) => {
|
|
|
|
await FS.unlinkSync(tempPath);
|
|
|
|
return reject({
|
|
|
|
decorator: "SERVER_UPLOAD_PARSE_FAILURE",
|
|
|
|
error: true,
|
|
|
|
message: e,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
form.on("finish", async () => {
|
|
|
|
// NOTE(jim):
|
|
|
|
// FS.createReadStream works the most consistently.
|
2020-09-22 03:36:45 +03:00
|
|
|
const readStream = FS.createReadStream(tempPath, {
|
|
|
|
highWaterMark: HIGH_WATER_MARK,
|
|
|
|
});
|
2020-08-16 12:23:02 +03:00
|
|
|
const data = LibraryManager.createLocalDataIncomplete(target);
|
|
|
|
|
2020-09-22 03:36:45 +03:00
|
|
|
// TODO(jim): Put this call into a file for all Textile related calls.
|
2020-08-16 12:23:02 +03:00
|
|
|
let push;
|
|
|
|
try {
|
2020-09-22 03:36:45 +03:00
|
|
|
const {
|
|
|
|
buckets,
|
|
|
|
bucketKey,
|
|
|
|
} = await Utilities.getBucketAPIFromUserToken(
|
|
|
|
user.data.tokens.api,
|
|
|
|
user
|
|
|
|
);
|
2020-08-16 12:23:02 +03:00
|
|
|
push = await buckets.pushPath(bucketKey, data.name, readStream);
|
|
|
|
} catch (e) {
|
|
|
|
await FS.unlinkSync(tempPath);
|
|
|
|
return reject({
|
|
|
|
decorator: "SERVER_BUCKETS_PUSH_ISSUE",
|
|
|
|
error: true,
|
|
|
|
message: e,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE(jim)
|
|
|
|
// Delete temporary local file,
|
|
|
|
await FS.unlinkSync(tempPath);
|
|
|
|
|
|
|
|
// NOTE(jim)
|
|
|
|
// Get remote file size from bucket.
|
2020-09-22 03:36:45 +03:00
|
|
|
// TODO(jim): Put this call into a file for all Textile related calls.
|
2020-08-16 12:23:02 +03:00
|
|
|
let ipfs = push.path.path;
|
|
|
|
try {
|
2020-09-22 03:36:45 +03:00
|
|
|
const {
|
|
|
|
buckets,
|
|
|
|
bucketKey,
|
|
|
|
} = await Utilities.getBucketAPIFromUserToken(
|
|
|
|
user.data.tokens.api,
|
|
|
|
user
|
|
|
|
);
|
2020-08-16 12:23:02 +03:00
|
|
|
const newUpload = await buckets.listIpfsPath(ipfs);
|
|
|
|
data.size = newUpload.size;
|
|
|
|
} catch (e) {
|
|
|
|
return reject({
|
|
|
|
decorator: "SERVER_BUCKETS_VERIFY_ISSUE",
|
|
|
|
error: true,
|
|
|
|
message: e,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolve({ decorator: "SERVER_UPLOAD_SUCCESS", data, ipfs });
|
|
|
|
});
|
|
|
|
|
|
|
|
return req.pipe(form);
|
|
|
|
});
|