2

I'm trying to make a Facebook chat bot that can send cat pictures. I use a RESTful API to get the cat pictures. They are returned as raw png. The next and final step is to convert that image into a Readable Stream so the Facebook Chat API can send it as an attachment.

I use request.js to grab the image. Request's documentation only mentions saving images as a file and reading files into stream.Readable. I wonder if there's a way to bypass that temporary file, and pipe the image directly into Facebook Chat API.

Here's my code so far:

var request = require("request");
var stream = require("stream");

module.exports = function getCatPicture(api, threadID, body) {
    var options = {
        url: 'http://thecatapi.com/api/images/get?type=png',
        encoding: 'base64'
    }
    var picStream = new stream.Readable;
    request.get(options, function (error, response, body) {
        picStream.push(body, 'base64');
        var catPic = {
            attachment: picStream
        };
        api.sendMessage(catPic, threadID);
        return;
    });
}

I'm getting an error:

Error in uploadAttachment Error: form-data: not implemented
Error in uploadAttachment     at Readable._read (_stream_readable.js:457:22)
Error in uploadAttachment     at Readable.read (_stream_readable.js:336:10)
Error in uploadAttachment     at flow (_stream_readable.js:751:26)
Error in uploadAttachment     at resume_ (_stream_readable.js:731:3)
Error in uploadAttachment     at nextTickCallbackWith2Args (node.js:442:9)
Error in uploadAttachment     at process._tickCallback (node.js:356:17)
Error in uploadAttachment  { [Error: form-data: not implemented]
Error in uploadAttachment   cause: [Error: form-data: not implemented],
Error in uploadAttachment   isOperational: true }
renxinhe
  • 41
  • 1
  • 4
  • see https://github.com/maxogden/mississippi#from and https://github.com/yoshuawuyts/from2-string –  Aug 02 '16 at 22:39
  • You are pushing to the readable stream only after the request return all the pody because you are working with callback, you need to pipe... like `request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))` – yeya Aug 02 '16 at 22:58

1 Answers1

1

There are a few issues here:

  1. This is the main problem which is that you need to implement ._read() on your new Readable stream instance. An upcoming version of node will have a better error message. So for now, you can probably just add picStream._read = function(n){}; after you create picStream.
  2. The image is being unnecessarily converted to base64 and back again. You can just set encoding: null in your options object and body will be a Buffer instance inside your callback. Then you can just do picStream.push(body);.
  3. The stream is not being ended. Add picStream.push(null); after you do picStream.push(body);

Lastly, this is a bit offtopic, but it's kind of silly that the module forces streams to be used when the underlying form-data module that request uses supports many different types of values (including a raw Buffer instance to use as the contents of a file).

mscdex
  • 104,356
  • 15
  • 192
  • 153
  • Thanks for clarifies things up! I've implemented all three of those suggestions. I don't get that form-data error anymore, but a new one showed up: `TypeError: Cannot convert undefined or null to object`. It's at [line 205 of sendMessage.js](https://github.com/Schmavery/facebook-chat-api/blob/master/src/sendMessage.js#L205). I think `file` is being null or something. For reference, I printed out the request `body`, and `request` is indeed reading a buffer correctly, so there shouldn't be an issue there. – renxinhe Aug 02 '16 at 23:55
  • Update 8/2 5:30pm: I just logged `file` on line 205 of `sendMessage.js`. It shows that `file` is `undefined`. I also encountered `Error in uploadAttachment Error: read ECONNRESET` once. I retried the script and the old `TypeError` came back. – renxinhe Aug 03 '16 at 00:32