GithubHelp home page GithubHelp logo

susie's Introduction

SuSiE - Server-Sent Events with hapi

Build Status

Above example under /examples. Start with npm start

This is a plugin that adds simple Server-Sent Events (aka EventSource) capabilities to hapi. It decorates the toolkit with a new method h.event(). You can send individual events as objects, or you can simply pass a stream and some options and SuSiE will make things work as you expect.

You probably already know this but install it with: npm install --save susie

Usage

First load and register the plugin:

await server.register(require('susie'));

With event objects

In a route handler you can now call h.event() to start an SSE response:

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, h) {

        return h.event({ data: 'my data' });
    }
});

The first time you call h.event(), appropriate HTTP response headers will be sent, along with your first event. Subsequent calls to h.event() will send more events.

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, h) {

        const response = h.event({ id: 1, data: 'my data' });

        setTimeout(function () {

            h.event({ id: 2, data: { a: 1 } }); // object datum
        }, 500);

        return response;
    }
});

If any of your datum are objects, they will be stringified for you. Make sure to parse them again in the client, if you're expecting JSON.

With a readable stream

A really nice way to provide an EventSource is using a ReadableStream. This is really simple with SuSiE. Just call h.event(stream):

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, h) {

        var Readable = require('stream').Readable;
        var rs = Readable();

        var c = 97;
        rs._read = function () {
            rs.push(String.fromCharCode(c++));
            if (c > 'z'.charCodeAt(0)) rs.push(null);
        };

        return h.event(rs);
    }
});

http://cl.ly/d5XT/Screen%20Shot%202015-09-13%20at%2015.50.25.png

Each chunk coming off the stream will be sent as an event. The content of the chunk will be the data parameter. You can provide an optional event option and id generator. By default the id will be the number of chunks received:

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, h) {

        var i = 0;
        var generateId = function (chunk) { return i += 10; }
        return h.event(stream, null, { event: 'update', generateId });
    }
});

Object mode streams

If the stream is in objectMode, each object that comes off the stream will be stringified and the resulting string will be used as the data parameter. See example under examples for example.

Considerations

How do I finish a SSE stream for good?

In the SSE spec, it says that when the HTTP response ends, the browser will try to reconnect, sending another request to the endpoint. You may want this. Or you may really want to stop to the events being streamed altogether.

When you call h.event(null) or your stream emits its end event, the HTTP response will conclude. However, SuSiE will send one last event to the browser before it closes. You should listen for this end event in your client code and close the EventSource, before the browser attempts to reconnect:

<script>
    var source = new EventSource('/events');
    ...
    source.addEventListener('end', function (event) {

        this.close();
    });
</script>

susie's People

Contributors

g-div avatar greenkeeperio-bot avatar mtharrison avatar vdeturckheim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

susie's Issues

Error registering the plugin from a manifest.json though rejoice

Using rejoice an error occurs while registering susie as plugin.

Having a manifest.json like this:

{
    "connections": [{
        "port": 8080
    }],
    "plugins": {
        "susie": {}
    }
}

and running the command:

rejoice -c manifest.json

the following error occurs:

/tmp/susie/node_modules/hapi/node_modules/hoek/lib/index.js:730
    throw new Error(msgs.join(' ') || 'Unknown error');
    ^

Error: Invalid plugin options {
  "options": {}
}

[1] "0" must be a string
    at Object.exports.contain.exports.reachTemplate.exports.assert (/tmp/susie/node_modules/hapi/node_modules/hoek/lib/index.js:730:11)
    at Object.exports.apply (/tmp/susie/node_modules/hapi/lib/schema.js:17:10)
    at module.exports.internals.Plugin.internals.Plugin.register.each [as register] (/tmp/susie/node_modules/hapi/lib/plugin.js:221:25)
    at /tmp/susie/node_modules/glue/lib/index.js:109:20
    at iterate (/tmp/susie/node_modules/items/lib/index.js:35:13)
    at Object.exports.serial (/tmp/susie/node_modules/items/lib/index.js:38:9)
    at /tmp/susie/node_modules/glue/lib/index.js:107:15
    at /tmp/susie/node_modules/glue/lib/index.js:115:9
    at iterate (/tmp/susie/node_modules/items/lib/index.js:35:13)
    at done (/tmp/susie/node_modules/items/lib/index.js:27:25)

Headers required by SSE?

Why do you include just one header (ie: content-type) but not also the other remaining headers ( cache-control and connection I mean) usually found in other SSE library?

Do something useful with objectMode streams

There's 2 possible approaches I can think of:

  • Pass objects from stream straight onto stringify implementation. I.E trust the provider knows what they're doing
  • Stringify object streams to JSON and wrap in usual way

I think no 2 makes the most sense. There's no reason stream provider should know about SSE format/fields.

How to create a chatroom ?

Hi,

I like this plugin a lot, however I wanted to ask for advice regarding the creation of a multi-rooms chat with SUSIE.

I assume I would need the following setup:

  • GET /room/{roomId} to subscribe to the room.
  • POST /room/{roomId} to write into the room

How do I make the actions executed in the POST handler get sent to the GET one ? And also, is there a solution to do this even if I have multiple instance of server that would get access to a redis or mongo base?

thanks a lot!

Get Error Messages when using Susie reply event

Version: 2
Hi,
I am using version 2 and we get this error in server, although the mssage is delivered.

Debug: internal, implementation, error 
    Error: write after end
    at writeAfterEnd (_stream_writable.js:236:12)
    at PassThrough.Writable.write (_stream_writable.js:287:5)
    at Object.internals.writeEvent (/home/ubuntu/bot-farm/node_modules/susie/lib/index.js:14:16)
    at Function.internals.handleEvent (/home/ubuntu/bot-farm/node_modules/susie/lib/index.js:69:15)
    at bound (domain.js:301:14)
    at Function.runBound [as event] (domain.js:314:12)
    at Redis.Subscriber.on (/home/ubuntu/bot-farm/routes/proxy/chatSSE.js:24:15)
    at emitTwo (events.js:130:20)
    at Redis.emit (events.js:213:7)
    at Redis.exports.returnReply (/home/ubuntu/bot-farm/node_modules/ioredis/lib/redis/parser.js:107:14)
    at JavascriptRedisParser.returnReply (/home/ubuntu/bot-farm/node_modules/ioredis/lib/redis/parser.js:27:13)
    at JavascriptRedisParser.execute (/home/ubuntu/bot-farm/node_modules/redis-parser/lib/parser.js:574:12)
    at Socket.<anonymous> (/home/ubuntu/bot-farm/node_modules/ioredis/lib/redis/event_handler.js:107:22)
    at emitOne (events.js:115:13)
    at Socket.emit (events.js:210:7)
    at addChunk (_stream_readable.js:266:12)

This is the route code

  handler: (req, reply) => {
    const { query: { user: channel } } = req
    console.log('Received Ping', channel)
    let payload = req.payload
    // const stream = new PassThrough({ objectMode: true })
    if (R.not(R.isNil(Subscriber))) {
      Subscriber.on('message', (channel, message) => {
        const messageParsed = JSON.parse(message)
        reply.event({ event: channel, data: messageParsed })
        // stream.write({ data: messageParsed })
      })
      Subscriber.subscribe(channel)
    }
    reply.event({ event: channel, data: null })
    // reply.event(stream, null, { event: channel })
  },

When I use stream it does not come, although stream mixes up multiple clients connecting to the server.

Question about using multiple stream for multiple clients

Hi,
I am trying to build an app where each user can listen to their own stream based on their id. I am trying to build up the stream list dynamically. Is there a limit to number of streams allowed per server?

I get this warning in my project:
(node) warning: possible EventEmitter memory leak detected. 11 data listeners added. Use emitter.setMaxListeners() to increase limit. Trace at PassThrough.addListener (events.js:239:17) at PassThrough.Readable.on (_stream_readable.js:665:33) at PassThrough.Readable.pipe (_stream_readable.js:525:7) at Function.internals.handleEvent [as event] (/../node_modules/susie/lib/index.js:40:19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.