node-formidable/formidable

arguments about fileWriteStreamHandler

Xiaoooyooo opened this issue · 8 comments

I'm trying to do something before the file has been write to the directory. So I found that fileWriteStreamHandler may be helpful. And it did help me a lot.
And I found that there is a problem with the type definition file. Here is the type:

/**
         * which by default writes to host machine file system every file parsed; The function should
         * return an instance of a Writable stream that will receive the uploaded file data. With this
         * option, you can have any custom behavior regarding where the uploaded file data will be
         * streamed for. If you are looking to write the file uploaded in other types of cloud storages
         * (AWS S3, Azure blob storage, Google cloud storage) or private file storage, this is the option
         * you're looking for. When this option is defined the default behavior of writing the file in the
         * host machine file system is lost.
         *
         * @default null
         */
        fileWriteStreamHandler?: (() => Writable) | undefined;

Note that the arguments of the fileWriteStreamHandler, there is nothing here, but there is something actually:

VolatileFile {
    _events: [Object: null prototype] { error: [Function (anonymous)] },
    _eventsCount: 1,
    _maxListeners: undefined,
    lastModifiedDate: null,
    filepath: 'D:\\My Code Library\\daily\\build\\data\\blogs\\Cookie.md',
    newFilename: 'Cookie.md',
    originalFilename: 'Cookie.md',
    mimetype: 'application/octet-stream',
    hashAlgorithm: false,
    createFileWriteStream: [Function: fileWriteStreamHandler],
    size: 0,
    _writeStream: null,
    hash: null,
    [Symbol(kCapture)]: false
  }

So I think this should be a bug about the definition file.

@Xiaoooyooo oh thanks! Sure, I think it should be (file: VolatileFile | PersistentFile), PR is welcome

Is it possible to pass in more params?

I upload my file and I want it to be streamed to another server via sftp. The final filename is determined by some other form fields that posted along with the uploaded file. I cannot create the writable with only the file itself.

@KennanChan

Use a variable that is closed over

let finalFilename;

 const form = formidable({
      fileWriteStreamHandler: (/* file */) => {
        // use variable finalFilename here
        return writable;
      },
    });

form.on('field', (name, value) => {
    if (name===`finalFilename`) {
        finalFilename = value
    }
});

Note this only works if finalFilename is sent before the file (inside the formdata)

Would you guys be kind a fix my code here so i can be able to upload my audio files to Firebase Storage.

const form = new formidable.IncomingForm();

      form.parse(req, async function (err, fields, files) {
        console.log("FILEEEE", files.mediaFile);
        const storageRef = ref(storage, "mediaa");
        await uploadBytes(storageRef, files.mediaFile).then((snapshot) => {
          console.log("Uploaded a blob or file!", snapshot);
        });
        res.send({ fields, files });
      });

Never used Formidable before so i don't really understand this.
I was reading the docs that i should pass fileWriteStreamHandler to the options but i don't know how to write the handler function for this.
Thanks!

@IlirBajrami Hi, I'm not that familiar with Firebase Storage, I read the doc for while, and here is my finally demo, maybe you can try this:

const http = require("http");
const fs = require("fs");
const formidable = require("formidable");
const stream = require("stream");

// there are some other type stream in nodejs, here I use Writable
class MyWritable extends stream.Writable {
  _write(chunk, encoding, callback) {
    console.log(encoding, chunk);
    // upload the buffer here
    setTimeout(() => {
      // remember to call `callback` when finished upload one chunk
      callback();
    }, 1000);
  }
  _final(callback) {
    console.log("_final");
    callback();
  }
}

const server = http.createServer((req, res) => {
  const { method, url } = req;
  console.log(method, url);
  if (url === "/") {
    res.writeHead(200, {
      "content-type": "text/html",
    });
    return fs.createReadStream("index.html").pipe(res);
  }
  if (method === "POST" && url === "/upload") {
    return formidable({
      fileWriteStreamHandler: () => {
        return new MyWritable();
      },
    }).parse(req, (err, fields, files) => {
      if (err) {
        res.statusCode = 500;
        return res.end(500);
      }
      res.writeHead(200, {
        "content-type": "application/json",
      });
      res.end(JSON.stringify({ files, fields }));
    });
  }

  res.statusCode = 404;
  res.end("404");
});

server.listen(8888, () => {
  console.log("http://127.0.0.1:8888\n");
});

@Xiaoooyooo might be right.

@IlirBajrami, I'm not familiar much with Firebase Storage either, but you can check out our example for S3 upload, it's should be something similar - https://github.com/node-formidable/formidable/blob/master/examples/store-files-on-s3.js

@Xiaoooyooo @tunnckoCore thank you for your answers. They both helped me fix my file uploading. I was using Nextjs so it was a bit different but i managed to make it work. :)

gboer commented

this is fixed in version 2.0.6 of @types/formidable, so this issue can be closed :)