how to Upload a file from ue4 to Js server, using multer - next.js

I'm currently making a project that requires me to send a png image from unreal engine to a next JS server which uses multer to pass the file on to another server.
When sending my file as a binary the JS server (intermediate server) is not receiving a file from unreal.
I've tried the two following methods
TArray<uint8> rawFileData;
FFileHelper::LoadFileToArray(rawFileData, *media);
Request->SetURL(API_HP_URL + "nude_upload");
Request->SetHeader(TEXT("Content-Type"), TEXT("multipart/form-data; boundary=----WebKitFormBoundarywpp9S2IUDici8hpI"));
Request->SetHeader(TEXT("Connection"), TEXT("keep-alive"));
Request->SetHeader(TEXT("accept"), TEXT("application/json, text/plain, */*"));
Request->SetContent(rawFileData);
Request->SetVerb("POST");
Request->OnProcessRequestComplete().BindUObject(this, &AHttpCommunicator::OnPostNudeSSResponse);
Request->ProcessRequest();
and
FString JsonString;
TArray<uint8> rawFileData;
TSharedRef<TJsonWriter<TCHAR>> JsonWriter = JsonWriterFactory<TCHAR>::Create(&JsonString);
JsonWriter->WriteObjectStart();
JsonWriter->WriteValue("fileName", pPathToFile);
JsonWriter->WriteValue("file", FBase64::Encode(rawFileData));
JsonWriter->WriteObjectEnd();
JsonWriter->Close();
Request->SetURL(API_HP_URL + "nude_upload");
Request->SetHeader(TEXT("Content-Type"), TEXT("multipart/form-data; boundary=----WebKitFormBoundarywpp9S2IUDici8hpI"));
Request->SetHeader(TEXT("Connection"), TEXT("keep-alive"));
Request->SetHeader(TEXT("accept"), TEXT("application/json, text/plain, */*"));
Request->SetContentAsString(JsonString);
Request->SetVerb("POST");
Request->OnProcessRequestComplete().BindUObject(this, &AHttpCommunicator::OnPostNudeSSResponse);
Request->ProcessRequest();
both of these methods have the server return an undefined file obj
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import path from 'path';
import MulterGoogleCloudStorage from "multer-google-storage";
import nextConnect from 'next-connect';
const Multer = require('multer');
const { Storage } = require('#google-cloud/storage');
const CLOUD_BUCKET = 'nude_locks';
const PROJECT_ID = 'hp-production-338902';
const KEY_FILE = path.resolve('./hp-production-key.json')
const storage = new Storage({
projectId: PROJECT_ID,
keyFilename: KEY_FILE
});
const bucket = storage.bucket(CLOUD_BUCKET);
const upload = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024,
}
}).single('file');
const apiRoute = nextConnect({
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
apiRoute.use(upload);
apiRoute.post((req, res) => {
console.log(req.file);
if (!req.file) {
res.status(400).send("No file uploaded.");
return;
}
const blob = bucket.file(req.file.originalname);
// Make sure to set the contentType metadata for the browser to be able
// to render the image instead of downloading the file (default behavior)
const blobStream = blob.createWriteStream({
metadata: {
contentType: req.file.mimetype
}
});
blobStream.on("error", err => {
next(err);
return;
});
blobStream.on("finish", () => {
console.log('finish');
console.log(blob);
// The public URL can be used to directly access the file via HTTP.
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
// Make the image public to the web (since we'll be displaying it in browser)
blob.makePublic().then(() => {
res.status(200).send(`Success!\n Image uploaded to ${publicUrl}`);
});
});
blobStream.end(req.file.buffer);
});
export default apiRoute;
export const config = {
api: {
bodyParser: false,
},
}
const fileSelectedHandler = e => {
const file = new File("D:/_Spectre/VHS/P210107_VHS_Configurator/P04_Unreal/Human_Configurator/Saved/Screenshots/Windows/-1-nude-2022-2-13.png");
console.log(file);
const formData = new FormData();
formData.append('file', file);
axios.post('/api/nude_upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
}
})
.then(res => {
console.log(res);
});
}
Is there a way to create a file object from UE4?
alternatively is there a way to retrieve google cloud storage access tokens from UE4

Related

What's the proper way for returning a response using Formidable on Nextjs Api?

I'm sending an uploaded file to a Next.js API route using FormData. The file is then processed on the API route using formidable and passed to sanity client in order to upload the asset, but I can't return the data to the client... I get this message in console:
API resolved without sending a response for /api/posts/uploadImage, this may result in stalled requests.
When console logging the document inside the API everything is in there, I just can't send back that response to client side. Here's my client upload function:
const addPostImage = (e) => {
const selectedFile = e.target.files[0];
if (
selectedFile.type === "image/jpeg" ||
selectedFile.type === "image/png" ||
selectedFile.type === "image/svg" ||
selectedFile.type === "image/gif" ||
selectedFile.type === "image/tiff"
) {
const form = new FormData();
form.append("uploadedFile", selectedFile);
axios
.post("/api/posts/uploadImage", form, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((image) => {
setPostImage(image);
toast.success("Image uploaded!");
})
.catch((error) => {
toast.error(`Error uploading image ${error.message}`);
});
} else {
setWrongImageType(true);
}
};
This is my API:
import { client } from "../../../client/client";
import formidable from "formidable";
import { createReadStream } from "fs";
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
const form = new formidable.IncomingForm();
form.keepExtensions = true;
form.parse(req, async (err, fields, files) => {
const file = files.uploadedFile;
const document = await client.assets.upload(
"image",
createReadStream(file.filepath),
{
contentType: file.mimetype,
filename: file.originalFilename,
}
);
console.log(document);
res.status(200).json(document);
});
};
Solution:
As stated in the comments by #juliomalves, I had to promisify the form parsing function and await its results like so:
import { client } from "../../../client/client";
import formidable from "formidable";
import { createReadStream } from "fs";
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
const form = new formidable.IncomingForm();
form.keepExtensions = true;
const formPromise = await new Promise((resolve, reject) => {
form.parse(req, async (err, fields, files) => {
if (err) reject(err);
const file = files.uploadedFile;
const document = await client.assets.upload(
"image",
createReadStream(file.filepath),
{
contentType: file.mimetype,
filename: file.originalFilename,
}
);
resolve(document);
});
});
res.json(formPromise);
};
Then I checked for the response's status on the client-side.
Your code is not working because by default formidable saves files to disk, which is not available on vercel. This works.
const chunks = []
let buffer;
const form = formidable({
fileWriteStreamHandler: (/* file */) => {
const writable = new Writable();
// eslint-disable-next-line no-underscore-dangle
writable._write = (chunk, enc, next) => {
chunks.push(chunk);
next();
};
return writable;
},
})
form.parse(req, (err, fields) => {
if (err) {
res.end(String(err));
return;
}
buffer = Buffer.concat(chunks);
res.end();
});

FormData using BusBoy for firebase works in serve but not in deploy

Situation
I have a firebase function that updates the user image.
Problem
When I run locally my function using firebase serve, I successfully upload the image to firestore using Postman. However, when I run firebase deploy and I try to upload the image using Postman, I get a 500 Internal Server Error. The other functions (not dealing with FormData, just json) work perfectly when I deploy them.
I don't understand why it works locally, but not on deploy when I am doing the exact same thing. Not sure if this is something in the config I am missing, or if I am doing something wrong. Any help would be appreciated!
Code
users.js
const { admin, db, firebase } = require('../util/admin');
const config = require('../util/config');
exports.postUserImage = (req, res) => {
const BusBoy = require('busboy');
const path = require('path');
const os = require('os');
const fs = require('fs');
let imgFileName;
let imgToBeUploaded = {};
const busboy = new BusBoy({ headers: req.headers });
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
// Invalid file type
if (mimetype !== 'image/jpeg' && mimetype !== 'image/png') {
return res.status(400).json({ error: 'Invalid file type' });
}
// Extract img extension
const imgDotLength = filename.split('.').length;
const imgExtension = filename.split('.')[imgDotLength - 1];
// Create img file name
imgFileName = `${Math.round(Math.random() * 1000000)}.${imgExtension}`;
// Create img path
const filepath = path.join(os.tmpdir(), imgFileName);
// Create img object to be uploaded
imgToBeUploaded = { filepath, mimetype };
// Use file system to create the file
file.pipe(fs.createWriteStream(filepath));
});
busboy.on('finish', () => {
admin
.storage()
.bucket()
.upload(imgToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: imgToBeUploaded.mimetype
}
}
})
.then(() => {
// Create img url to add to our user
const imgUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imgFileName}?alt=media`;
// Add img url to user document
return db.doc(`/users/${req.user.handle}`).update({ imgUrl });
})
.then(() => {
return res.json({ message: 'Image uploaded succesfully' });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error });
});
});
busboy.end(req.rawBody);
};
index.js
const { app, functions } = require('./util/admin');
const FirebaseAuth = require('./util/firebaseAuth');
const {
postUserImage,
} = require('./handlers/users');
app.post('/user/image', FirebaseAuth, postUserImage);

Why is my image not loading in the Storage dashboard after uploading from Firebase Functions?

I am using the following firebase functions code.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const firestore = admin.firestore();
firestore.settings({timestampsInSnapshots: true});
const cors = require("cors")({ origin: true });
const path = require('path');
const os = require('os');
const fs = require('fs');
// Node.js doesn't have a built-in multipart/form-data parsing library.
// Instead, we can use the 'busboy' library from NPM to parse these requests.
const Busboy = require('busboy');
exports.uploadFile = functions.https.onRequest((req, res) => {
cors(req, res, () => {
console.log('Request headers: ' + JSON.stringify(req.headers));
console.log('Request body: ' + JSON.stringify(req.body));
if (req.method !== "POST") {
return res.status(500).json({
message: "Not allowed"
});
}
const busboy = new Busboy({ headers: req.headers });
let uploadData = null;
busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
console.log('fieldname ' + fieldname + 'file ' + file + ' encoding ' + encoding + ' mimetype ' + mimetype);
const filepath = path.join(os.tmpdir(), filename);
uploadData = { file: filepath, type: mimetype };
file.pipe(fs.createWriteStream(filepath));
});
busboy.on("finish", () => {
console.log('Finished');
const destBucket = admin.storage().bucket("wairz-d5aee.appspot.com");
destBucket.upload(uploadData.file, {
uploadType: "media",
metadata: {
metadata: {
contentType: uploadData.type
}
},
destination: '/Images/myImage.jpg'
})
.then(() => {
console.log('200!');
res.status(200).json({
message: "It worked!"
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
});
busboy.end(req.rawBody);
});
});
Here is my request.
Here are the logs from the function.
Request headers: {"host":"us-central1-wairz-d5aee.cloudfunctions.net","user-agent":"PostmanRuntime/7.20.1","transfer-encoding":"chunked","accept":"*/*","accept-encoding":"gzip, deflate","cache-control":"no-cache","content-type":"multipart/form-data; boundary=--------------------------830355209915480769258810","forwarded":"for=\"67.149.5.133\";proto=https","function-execution-id":"pzmqiu8jmisw","postman-token":"6421769e-df95-494c-a88e-c4cb92885fe1","x-appengine-city":"royal oak","x-appengine-citylatlong":"42.489480,-83.144649","x-appengine-country":"US","x-appengine-default-version-hostname":"ncac955097ca6038f-tp.appspot.com","x-appengine-https":"on","x-appengine-region":"mi","x-appengine-request-log-id":"5dec9cdb00ff072e2cbbdcacd70001737e6e636163393535303937636136303338662d7470000164306565646538376331393663343865373435386434653763616334326336393a3338000100","x-appengine-user-ip":"67.149.5.133","x-cloud-trace-context":"f59ac36f71c2827523171e4a58e540e7/11977574301495828521;o=1","x-forwarded-for":"67.149.5.133","x-forwarded-proto":"https","connection":"close"}
Request body: {"type":"Buffer","data":[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,56,51,48,51,53,53,50,48,57,57,49,53,52,56,48,55,54,57,50,53,56,56,49,48,13,10,67,111,110,116,101,110,116,45,68,105,115,112,111,115,105,116,105,111,110,58,32,102,111,114,109,45,100,97,116,97,59,32,110,97,109,101,61,34,105,109,97,103,101,34,59,32,102,105,108,101,110,97,109,101,61,34,116,101,115,116,73,109,97,103,101,46,106,112,101,103,34,13,10,67,111,110,116,101,110,116,45,84,121,112,101,58,32,105,109,97,103,101,47,106,112,101,103,13,10,13,10,255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255,219,0,132,0,9,6,7,16,15,16,16,16,15,15,15,15,16,15,15,15,14,16,16,13,15,15,15,16,15,15,21,17,22,22,21,17,21,21,24,29,40,32,24,26,37,29,21,21,33,49,33,37,41,43,46,46,46,23,31,51,56,51,45,55,52,45,46,43,1,10,10,10,14,13,14,26,16,16,26,43,31,29,29,43,45,45,45,45,45,43,45,43,43,45,43,43,45,43,45,45,45,45,43,45,45,45,45,45,47,43,45,43,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,255,192,0,17,8,0,184,1,18,3,1,34,0,2,17,1,3,17,1,255,196,0,28,0,0,2,3,1,1,1,1,0,0,0,0,0,0,0,0,0,2,3,0,4,5,1,7,6,8,255,196,0,68,16,0,2,1,2,4,2,6,7,5,4,7,9,0,0,0,0,1,2,0,3,17,4,5,18,33,49,65,19,34,81,97,113,129,6,23,50,83,145,147,210,7,35,66,161,177,51,82,209,225,20,98,115,146,193,194,240,21,22,36,68,114,130,178,226,241,255,196,0,25,1,0,3,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,2,3,1,4,5,255,196,0,45,17,0,3,0,1,3,3,3,2,4,7,0,0,0,0,0,0,0,1,2,17,3,18,33,4,49,65,19,20,97,34,81,50,113,161,177,5,36,129,145,193,225,241,255,218,0,12,3,1,0,2,17,3,17,0,63,0,242,129,12,8,34,24,157,216,56,89,209,12,65,16,196,194,108,32,33,1,4,67,2,2,54,16,16,192,156,81,8,64,70,194,88,96,65,81,24,4,204,18,108,37,17,138,32,168,140,81,52,133,48,212,70,168,128,162,57,4,8,85,12,65,30,130,45,68,114,8,196,42,134,164,122,8,180,18,197,37,154,66,171,35,17,99,149,103,17,99,149,96,38,72,22,16,88,106,176,194,195,38,11,211,57,162,63,76,154,96,5,98,144,10,203,69,98,217,96,97,89,150,44,172,178,194,45,150,105,68,196,17,22,194,60,136,182,19,10,38,33,132,83,8,246,17,76,38,162,169,137,104,182,141,113,20,209,138,32,36,146,72,195,159,20,33,8,34,26,200,158,227,8,67,2,8,134,32,73,132,4,53,16,64,134,4,194,109,132,33,172,16,35,20,67,4,155,58,162,49,68,226,136,192,33,130,52,206,129,24,130,10,136,197,19,9,54,49,68,125,49,20,130,61,4,212,115,219,24,162,61,4,90,136,228,17,142,106,99,169,172,179,76,68,83,89,106,152,152,217,49,200,177,202,32,32,142,81,23,32,194,81,12,9,16,70,233,141,147,0,211,37,161,218,66,32,96,176,151,139,168,150,50,197,46,48,113,3,127,33,51,60,143,183,233,201,81,150,41,132,123,69,176,140,42,43,176,128,194,57,132,91,9,165,81,93,196,75,9,97,196,75,205,69,83,43,188,75,71,188,67,198,43,32,78,206,73,52,115,226,132,53,16,68,53,146,61,198,26,136,106,32,136,106,32,73,134,33,8,34,24,129,38,18,198,44,5,141,88,18,160,150,48,8,43,24,176,33,76,37,17,138,32,136,197,19,25,22,198,32,143,88,164,17,200,38,16,161,169,28,162,41,99,82,49,207,69,220,56,23,151,13,43,111,51,169,153,171,130,112,221,86,236,147,174,6,211,197,112,10,199,44,23,167,164,219,151,40,75,12,139,83,135,134,57,12,178,22,226,85,6,95,193,166,165,240,152,222,16,250,83,185,224,171,56,99,113,9,165,136,137,38,50,100,170,118,182,130,165,199,202,46,191,19,29,135,27,159,9,93,205,201,130,238,59,226,16,166,138,104,211,11,15,68,189,251,163,231,2,68,186,120,69,83,2,170,218,106,182,4,20,70,22,7,172,78,253,135,159,100,202,168,110,111,50,105,51,170,244,107,77,45,222,68,48,149,222,88,121,93,229,80,178,33,226,30,61,226,30,49,105,23,36,25,32,83,7,199,8,193,22,35,22,72,246,152,193,12,64,16,196,9,176,196,37,128,176,196,210,52,49,99,22,44,70,44,48,70,134,172,98,197,172,106,197,100,40,53,17,171,32,160,214,190,147,105,208,38,18,180,208,197,18,222,19,14,106,27,2,1,149,4,117,54,230,54,35,152,129,31,60,150,106,208,106,102,204,45,216,121,31,3,58,178,230,19,30,173,100,174,53,47,239,115,29,241,249,150,82,105,14,146,147,116,180,77,136,117,223,79,141,191,88,187,177,195,11,209,220,183,71,43,245,5,48,71,77,198,252,227,104,83,147,45,199,218,200,254,70,104,58,14,35,129,136,219,79,12,105,210,138,89,144,41,117,133,143,17,254,175,58,148,140,48,188,199,17,45,132,4,2,60,12,92,141,232,238,40,145,105,127,42,171,102,177,224,68,167,138,91,24,120,13,220,70,124,162,90,73,198,178,95,37,204,210,215,7,227,42,81,91,153,119,54,220,2,7,124,167,129,226,102,75,250,74,117,17,252,198,62,229,160,182,70,239,19,41,140,214,198,54,154,126,59,76,154,98,236,38,195,242,47,85,31,84,194,33,225,55,50,252,32,74,96,182,218,184,147,192,95,132,167,130,195,116,149,149,109,178,245,155,248,77,252,99,45,180,105,37,109,118,3,128,183,1,230,98,106,95,132,122,31,195,250,85,151,169,93,151,7,207,230,231,171,117,216,18,7,126,158,95,25,139,85,44,55,154,213,171,235,212,199,128,61,95,229,50,208,26,174,163,123,92,2,64,38,192,158,59,74,233,240,136,245,41,106,86,87,158,197,54,49,14,101,188,106,5,176,28,64,26,172,117,13,124,192,54,23,28,37,23,51,162,121,71,43,135,47,2,220,196,60,99,152,138,134,57,73,64,94,72,50,64,182,15,145,88,197,138,88,197,146,61,138,67,1,134,34,196,49,2,109,6,35,22,40,67,89,164, etc.
fieldname imagefile [object Object] encoding 7bit mimetype image/jpeg
Finished
200!
The image seems to successfully get uploaded to Firebase Storage and it looks like it is the right size. However, when I try to view it in the Storage dashboard, it never loads. Why is this happening?
The issue is that firebase thinks that you have not signed the upload file.
You should sign you upload and generate download token in a unique way.
You send downloadToken as a property in metadata called firebaseStorageDownloadTokens.
import { v4 as uuidv4 } from 'uuid'
const uuid = uuidv4()
const blobStream = fileUpload.createWriteStream({
metadata: {
contentType: file.mimetype,
metadata: { firebaseStorageDownloadTokens: uuid }
}
})
// then you link will be
const url = format(
`https://firebasestorage.googleapis.com/v0/b/${bucket.name}/o/${fileUpload.name}?token=${uuid}&alt=media`
)

How to create a folder in Firebase Storage using Admin API

Aim: to upload a file into a folder within Firebase Storage
E.g.
default_bucket/folder1/file1
default_bucket/folder1/file2
default_bucket/folder2/file3
Using Firebase client-side I am able to upload a file to a folder within Firebase Storage like this:
const storageRef = firebase.storage().ref();
const fileRef = storageRef.child(`${folder}/${filename}`);
const metadata = {
contentType: file.type,
customMetadata: { }
};
return fileRef.put(file, metadata);
If the folder does not exist, it get's created.
However I have not managed to do the same server-side using the Admin SDK.
The code below, uploads the file into the default bucket.
But, I want to upload the file into a named folder within the default bucket.
The client side makes a POST request to the GCF, sending the file and a folder name.
Busboy is used to extra the folder name and file and pass them to the upload function; which uploads the file, then returns a donwnload link for it.
index.js
const task = require('./tasks/upload-file-to-storage');
app.post('/upload', (req, res, next) => {
try {
let uploadedFilename;
let folder;
if (req.method === 'OPTIONS') {
optionsHelper.doOptions(res);
} else if (req.method === 'POST') {
res.set('Access-Control-Allow-Origin', '*');
const busboy = new Busboy({ headers: req.headers });
const uploads = [];
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
uploadedFilename = `${folder}^${filename}`;
const filepath = path.join(os.tmpdir(), uploadedFilename);
uploads.push({ file: filepath, filename: filename, folder: folder });
file.pipe(fs.createWriteStream(filepath));
});
busboy.on('field', (fieldname, val) => {
if (fieldname === 'folder') {
folder = val;
}
});
busboy.on('finish', () => {
if (uploads.length === 0) {
res.end('no files found');
}
for (let i = 0; i < uploads.length; i++) {
const upload = uploads[i];
const file = upload.file;
task.uploadFile(helpers.fbAdmin, upload.folder, upload.file, uploadedFilename).then(downloadLink => {
res.write(`${downloadLink}\n`);
fs.unlinkSync(file);
res.end();
});
}
});
busboy.end(req.rawBody);
} else {
// Client error - only support POST
res.status(405).end();
}
} catch (e) {
console.error(e);
res.sendStatus(500);
}
});
const api = functions.https.onRequest(app);
module.exports = {
api
;
upload-file-to-storage.js
exports.uploadFile = (fbAdmin, folder, filepath, filename) => {
// get the bucket to upload to
const bucket = fbAdmin.storage().bucket(); //`venture-spec-sheet.appspot.com/${folder}`
const uuid = uuid();
// Uploads a local file to the bucket
return bucket
.upload(filepath, {
gzip: true,
metadata: {
//destination: `/${folder}/${filename}`,
cacheControl: 'public, max-age=31536000',
firebaseStorageDownloadTokens: uuid
}
})
.then(() => {
const d = new Date();
const expires = d.setFullYear(d.getFullYear() + 50);
// get file from the bucket
const myFile = fbAdmin
.storage()
.bucket()
.file(filename);
// generate a download link and return it
return myFile.getSignedUrl({ action: 'read', expires: expires }).then(urls => {
const signedUrl = urls[0];
return signedUrl;
});
});
};
I've tried a few things
Setting the bucket name to default and a folder. This resulted in a server error.
const bucket = fbAdmin.storage().bucket(`${defaultName}/${folder}`);
Setting the bucket name to the folder. This resulted in a server error.
const bucket = fbAdmin.storage().bucket(folder);
And, I've also tried using the destination property of uploadOptions.
But this still puts the file in the default bucket.
.upload(filepath, {
gzip: true,
metadata: {
destination: `${folder}/${filename}`, // and /${folder}/${filename}
}
})
Is it possible to upload to a folder using the Admin SDK?
E.g. I want to upload a file so that is is placed in a named "folder".
I.e. so I can reference the file at the path: bucket/folder/file.jpg
In the example below, each "folder" is named with a firebase key.
Found the problem.
I stupidly declared the destination option in the wrong place.
Instead of in the metadata object:
return bucket
.upload(filepath, {
gzip: true,
metadata: {
destination: `${folder}/${filename}`,
cacheControl: 'public, max-age=31536000',
firebaseStorageDownloadTokens: uuid
}
})
It should have been on the options object:
return bucket
.upload(filepath, {
gzip: true,
destination: `${folder}/${filename}`,
metadata: {
cacheControl: 'public, max-age=31536000',
firebaseStorageDownloadTokens: uuid
}
})
With this change made the file now gets uploaded into a named "folder".
There is a create folder option besides Upload File button for a bucket in Storage console.One can create folders in bucket and upload files to it on console. To create such folders in bucket using admin APIs, add folders before file reference. e.g.
const blob = bucket.file('folder1/folder2/' + req.file.originalname);

Firebase Functions get files from storage

I have to send a file to an API, therefor I have to use fs.readFileSync(). After uploading the picture to the storage, I am calling my function to execute the API call. But I cannot get the file from the storage. This is a section of the code, which always gets null in the result. I tried also to .getFiles() without a parameter and then I got all files but I dont want to filter them by iteration.
exports.stripe_uploadIDs = functions.https //.region("europe-west1")
.onCall((data, context) => {
const authID = context.auth.uid;
console.log("request is authentificated? :" + authID);
if (!authID) {
throw new functions.https.HttpsError("not authorized", "not authorized");
}
let accountID;
let result_fileUpload;
let tempFile = path.join(os.tmpdir(), "id_front.jpg");
const options_id_front_jpeg = {
prefix: "/user/" + authID + "/id_front.jpg"
};
const storageRef = admin
.storage()
.bucket()
.getFiles(options_id_front)
.then(results => {
console.log("JPG" + JSON.stringify(results));
// need to write this file to tempFile
return results;
});
const paymentRef = storageRef.then(() => {
return admin
.database()
.ref("Payment/" + authID)
.child("accountID")
.once("value");
});
const setAccountID = paymentRef.then(snap => {
accountID = snap.val();
return accountID;
});
const fileUpload = setAccountID.then(() => {
return Stripe.fileUploads.create(
{
purpose: "identity_document",
file: {
data: tempFile, // Documentation says I should use fs.readFileSync("filepath")
name: "id_front.jpg",
type: "application/octet-stream"
}
},
{ stripe_account: accountID }
);
});
const fileResult = fileUpload.then(result => {
result_fileUpload = result;
console.log(JSON.stringify(result_fileUpload));
return result_fileUpload;
});
return fileResult;
});
Result is:
JPG[[]]
You need to download your file from a bucket to your local function context env.
After your Firebase function start executing you can call the below:
More or less the below should work, just tweak to your needs. Call this within you .onCall context, you get the idea
import admin from 'firebase-admin';
import * as path from 'path';
import * as os from 'os';
import * as fs from 'fs';
admin.initializeApp();
const { log } = console;
async function tempFile(fileBucket: string, filePath: string) {
const bucket = admin.storage().bucket(fileBucket);
const fileName = 'MyFile.ext';
const tempFilePath = path.join(os.tmpdir(), fileName);
const metadata = {
contentType: 'DONT_FORGET_CONTEN_TYPE'
};
// Donwload the file to a local temp file
// Do whatever you need with it
await bucket.file(filePath).download({ destination: tempFilePath });
log('File downloaded to', tempFilePath);
// After you done and if you need to upload the modified file back to your
// bucket then uploaded
// This is optional
await bucket.upload(tempFilePath, {
destination: filePath,
metadata: metadata
});
//free up disk space by realseasing the file.
// Otherwise you might be charged extra for keeping memory space
return fs.unlinkSync(tempFilePath);
}

Resources