Firebase Google Cloud Function: createReadStream results in empty file

故事扮演 提交于 2021-02-05 07:17:13

问题


I try to process a Video file (stored in Google Firebase storage) through a Google Cloud Function. I have working code that download the entire video files into the NodeJS Google cloud function: await bucket.file(filePath).download({ destination: tempFile }). But the goal is only to read the framerate, therefore the headers of the videofile would suffice. But createReadStream gives me an empty tempFile. Any advise much appreciated!

exports.checkFramerate = functions.region('europe-west1').storage.object().onFinalize(async (object, context) => {
    const bucket =  admin.storage().bucket(object.bucket); // Bucket class
    const filePath = object.name;   //  videos/xbEXdMNFb1Blbd9r2E8m/comp_test.mp4
    const fileName = filePath.split('/').pop(); // comp_test.mp4
    const bucketDir = path.dirname(filePath); // videos/xbEXdMNFb1Blbd9r2E8m

    const tempFile = path.join(os.tmpdir(), 'temp.mp4')
    fs.closeSync(fs.openSync(tempFile, 'w'))
    console.log("tempFile size1", fs.statSync(tempFile).size)

    // await bucket.file(filePath).download({ destination: tempFile }); // this works: tempFile size2 = 3180152
    await bucket.file(filePath).createReadStream({                      // this does not work: tempFile size2 = 0
        start: 10000,
        end: 20000
      })
      .on('error', function(err) {console.log(err)})
      .pipe(fs.createWriteStream(tempFile));


    console.log("tempFile size2", fs.statSync(tempFile).size)

    mi(tempFile).then(data => {
        console.log("frameRate", data[0].general.frame_rate[0])
        return data[0].general.frame_rate[0];
    }).catch(e => {console.error(e)});
});

I tried implementing even the example of https://googleapis.dev/nodejs/storage/latest/File.html#createReadStream but to no avail. remoteFile.download works beautifully but remoteFile.createReadStream gives me empty files...

const remoteFile = bucket.file(filePath);
const localFilename = tempFile;

remoteFile.createReadStream()
    .on('error', function(err) {})
    .on('response', function(response) {})
    .on('end', function() {})
    .pipe(fs.createWriteStream(localFilename));

fs.stat(localFilename, (err, stats) => {
    if (err) {console.log(err)}
    return console.log("stats async",stats.size)
})

回答1:


Your problem is that the stream API isn't promisifed. So, the await does nothing, and your function continues before the stream is piped, and the file is still zero-length when you stat it the second time.

The download method works just fine because it returns a Promise.

This answer outlines the general approach you need to take. In summary though, you basically want the section of your code that does the piping to read like this:

const stream = bucket.file(filePath).createReadStream({
    start: 10000,
    end: 20000
  })
  .pipe(fs.createWriteStream(tempFile));

await new Promise((resolve, reject) => {
    stream.on('finish', resolve);
    stream.on('error', reject);
  });

console.log("tempFile size2", fs.statSync(tempFile).size)

Your function will then wait until the finish event occurs when the piping is complete and the stream is closed. Obviously you probably want to do something more clever with the error handler too, but this is the general form of what you need.




回答2:


as mentioned, promise should be used

reading json file example

 let  buf = '';

 const loadData = async () => {
  return await new Promise((resolve, reject) => {
    storage.bucket('bucket-name').file('test-config.json')
      .createReadStream()
      .on('error', reject)
      .on('data', function(d) {
        buf += d;
      }).on('end', function() {
        resolve(buf)
      });
  })
}

const data = await loadData()


来源:https://stackoverflow.com/questions/59143523/firebase-google-cloud-function-createreadstream-results-in-empty-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!