async upload multiple files to google cloud storage bucket - node.js

I'm trying to upload multiple files to a Google Cloud Storage bucket using NodeJS. I want all files to be uploaded before continuing. I tried several approaches but I can't seem to get it right.
const jpegImages = await fs.readdir(jpegFolder);
console.log('start uploading');
await jpegImages.forEach(async fileName => {
await bucket.upload(
path.join(jpegFolder, fileName),
{destination: fileName}
).then( () => {
console.log(fileName + ' uploaded');
})
})
console.log('finished uploading');
This gives me the following output, which is not what I expect. Why is the 'finished uploading' log not executed after uploading the files?
start uploading
finished uploading
image1.jpeg uploaded
image2.jpeg uploaded
image3.jpeg uploaded

async/await doesn't work with forEach and other array methods.
If you don't need sequential uploading (files can be uploaded in parallel) you could create an array of Promises and use Promise.all() to execute them all at once.
const jpegImages = await fs.readdir(jpegFolder);
console.log('start uploading');
await Promise
.all(jpegImages.map(fileName => {
return bucket.upload(path.join(jpegFolder, fileName), {destination: fileName})
}))
.then(() => {
console.log('All images uploaded')
})
.catch(error => {
console.error(`Error occured during images uploading: ${error}`);
});
console.log('finished uploading');

Related

when file is 100% uploaded to GCS then run

Script seems to be running before file is fully uploaded to GCS.
I have a blobStream.on function that is meant to only run when the data has finished uploading to GCS. The issue is it works sometimes and other time it is running too soon and forgets that another file is also uploading (normally it's the audio file that is still uploading).
I am wondering how can I improve the below script.
index is the number of files uploading 0,1,2 it counts up.
fileLength is the number of the file it is uploading 0,1,2 etc.
What seems to happy is that this part is triggering too soon, as the index and fileLength equal the same amount. It's not taking into account the data that could be because according to me doing a console.log(data) nothing returns it's undefined.
Seems a few errors here.
I am wondering is there anyway to watch the data in this function and when that finished to run the correct script. Also clearly way too many delays - this is because I am trying to slow down the script so it runs at the correct time.
What I can say is that the delay just after the blobStream.on('finish') does seem to help it a little.
blobStream.on("finish", async (data) => {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
await delay(10000);
const publicUrl = format(
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
);
try {
await bucket.file(newfileName).makePublic();
} catch {
message.push({
message:
`Uploaded the file successfully: ${newfileName}, but public access is denied!`,
url: publicUrl,
});
}
console.log(index);
if(index == fileLength){
await delay(10000);
message.push({
originalname: file.originalname,
mimeType: file.mimetype,
message: "Uploaded the file successfully: " + newfileName,
url: publicUrl,
});
console.log(JSON.stringify(message))
await delay(10000)
console.log(JSON.stringify(message))
await delay(10000)
submitToDB(req, res, message);
//res.status(200).send(message);
}
else{
console.log("this is the first index."+ index +"file name "+ file.originalname);
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
message.push({
originalname: file.originalname,
mimeType: file.mimetype,
message: "Uploaded the file successfully: " + newfileName,
url: publicUrl,
})
await delay(1000)
console.log(JSON.stringify(message));
}
});

File Upload to s3 bucket via NodeJS Console app via aws-sdk doesnt get completed

I do have a one time running JS file, which is running as a command line tool. But not as a REST server.
The issue I have is that I do have the following function which accepts the arguments and uploads a file to a specified S3 bucket.
const uploadToAWSS3Bucket = (stream, fileName, bucketName) =>{
const params = {
Bucket: bucketName || '',
Key: fileName,
Body: stream
};
console.log(`Using Bucket ${bucketName} for uploading the file ${fileName}`);
return s3.upload(params, (err, data) => {
if (err) {
console.log(err);
}
console.log(data.stringify);
console.log(`File uploaded successfully. ${data.Location}`);
console.log(`Finished uploading the file ${fileName} to Bucket ${bucketName}.`);
}).promise();
// await sleep(80000);
};
This is called/implemented by the following method.
(async()=>{
const result = await uploadToAWSS3Bucket(stream, 'filename.json', 'mybucketname');
console.log(result);
});
However, the node index.js command exits with giving out a commandline output and it appears that the file upload never gets completed because of that.
Anything that I am missing or any trick that would work on this case?
The command exits without doing anything because your IIFE is missing a () at the end.
(async () => {
console.log('do something');
})();

my videos on google bucket can not fast forward or rewind

So i built an e-learning platform with node.js and vue.js, and i am using GCP buckets to store my videos privately, everything works perfectly asides the fact that my videos can not fast forward or rewind, if you try moving the video to a specific position (maybe towards the end of the video) it returns to the same spot where you were initially, at first i taught it was a vue problem, but i tried playing this videos from my GCP bucket dashboard directly but it does the same thing. it only works fine when i use the firefox browser.
i am using the Uniform: No object-level ACLs enabled access control and the Not public permission settings. I am new the GCP, i have no idea what could be the problem
here is the node.js function i am using
const upload = async (req, res) => {
try {
if (!req.file) {
res.status(400).send('No file uploaded.');
return;
}
const gcsFileName = `${Date.now()}-${req.file.originalname}`;
var reader = fs.createReadStream('uploads/'+req.file.originalname);
reader.pipe(
bucket.file(gcsFileName).createWriteStream({ resumable: false, gzip: true })
.on('finish', () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = format(
`https://storage.googleapis.com/bucketname/` + gcsFileName
);
// console.log('https://storage.googleapis.com/faslearn_files/' + gcsFileName)
fs.unlink('uploads/' + req.file.originalname, (err) => {
if (err) {
console.log("failed to delete local image:" + err);
} else {
console.log('successfully deleted local image');
}
});
res.status(200).send(publicUrl);
})
.on('error', err => {
console.log(err);
return
})
//.end(req.file.buffer)
)
// Read and display the file data on console
reader.on('data', function (chunk) {
console.log('seen chunk');
});
} catch (err) {
console.log(" some where");
res.status(500).send({
message: `Could not upload the file: ${req.file.originalname}. ${err}`,
});
}
};
the issue was comming from the way i encoded the video, i was supposed to use the blob but i used the pipe

Read .mp4 file from firebase storage using fs to send that video to tenserflow model

my graduation project is to convert video into text.
I'm trying to read video uploaded in Firebase storage & sent from android app, to send it to TenserFlow model.
but I can't read the video.
here is my function:
exports.readVideo = functions.storage
.object()
.onFinalize(async (object) => {
const bucket = admin.storage().bucket(object.bucket);
const tempFilePath = path.join(os.tmpdir(), object.name);
console.log(tempFilePath);
console.log('download');
// note download
await bucket
.file(object.name!)
.download({
destination: tempFilePath,
})
.then()
.catch((err) => {
console.log({
type: 'download',
err: err,
});
});
console.log('read');
// note read
let stream = await bucket
.file(object.name!)
.createReadStream({
start: 10000,
end: 20000,
})
.on('error', function (err) {
console.log('error 1');
console.log({ error: err });
})
await new Promise((resolve, reject) => {
console.log('error 2');
stream.on('finish', resolve);
console.log('error 3');
stream.on('error', reject);
console.log("end!")
stream.on('end', resolve);
}).catch((error) => {
// successMessage is whatever we passed in the resolve(...) function above.
// It doesn't have to be a string, but if it is only a succeed message, it probably will be.
console.log("oups! " + error)
});
console.log('tempFile size2', fs.statSync(tempFilePath).size);­­­
return fs.unlinkSync(tempFilePath);
});
and I got that error:
Function execution took 60008 ms, finished with status: 'timeout'
As the error message shows, the regular file system on Cloud Functions is read only. The only place you can write to is /tmp, as also shown in the documentation on file system access in Cloud Functions. I'm not sure why os.tmpdir() doesn't give you a location at that path, but you might want to hard-code the directory.
One thing to keep in mind: /tmp is a RAM disk and not a physical disk, so your allocated memory will need to have enough space for the files you write to it.

Download file from google cloud storage directly to client in nodejs

I want to be able to send the file downloaded from google cloud directly to the client and not have to first save on my server then create a download to client from the saved version on my server, cause this make the process slow, as the file is downloaded two times, first from google cloud to my own server then from my own server to client.
router.get("/:filename", async(req, res) => {
try {
// Grab filename from request parameter
const fetchURL =req.params.filename;
const file = await File.findOne({fetchURL});
const srcFileName = file.originalname;
// Call GCS with bucketName and check the file method with srcFileName and check again with download method which takes download path as argument
storage
.bucket(bucketName)
.file(srcFileName)
.download({
destination: path.join(process.cwd(), "downloads", srcFileName)
})
.then(() =>
res.download(path.join(process.cwd(), "downloads", srcFileName), err =>
err ? console.log(err) : null
)
)
.catch(err =>res.status(400).json({
message: err.message
}));
} catch (err) {
res.status(res.statusCode).json({
message: `There was an error downloading your file. ${err.message}`
});
}
});
This works for me in NodeJS+Express server:
const {Storage} = require('#google-cloud/storage');
const storage = new Storage({projectId, keyFilename});
router.get('/:id', async function (req, res) {
let fileName = 'test.jpg'; //For example
let contetType = 'image/jpg;' //For example
res.writeHead(200, {
'Content-Disposition': `attachment;filename=${filename}`,
'Content-Type': `${contetType}`
});
await storage
.bucket('my-bucket')
.file(`Images/${req.params.id}/${filename}`)
.createReadStream() //stream is created
.pipe(res);
});}

Resources