├── .gitignore ├── README.md ├── example ├── index.html └── server.js ├── index.js ├── libs └── sse.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server-Sent-Events-Nodejs 2 | Make Server Sent Events (Node-js) 3 | 4 | >Easy to make a server sent events(SSE) with nodejs 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install sse-nodejs 10 | ``` 11 | 12 | ## How to use 13 | 14 | Use with express: 15 | 16 | ```javascript 17 | var SSE = require('sse-nodejs'); 18 | 19 | var express = require('express'); 20 | 21 | var app = express(); 22 | 23 | app.get('/', function (req,res) { 24 | res.sendFile(__dirname+ '/index.html'); 25 | }); 26 | 27 | app.get('/time', function (req,res) { 28 | var app = SSE(res); 29 | 30 | app.sendEvent('time', function () { 31 | return new Date 32 | },1000); 33 | 34 | app.disconnect(function () { 35 | console.log("disconnected"); 36 | }); 37 | 38 | app.removeEvent('time',3100); 39 | 40 | }); 41 | 42 | app.listen(3000, function () { 43 | console.log('Simple SSE server start at port: 3000') 44 | }); 45 | 46 | ``` 47 | 48 | Use in frontend 49 | 50 | 51 | ```html 52 | 53 | 54 |
55 | 56 | HELLO WORLD 57 | 58 | 59 | 65 | 66 | ``` 67 | 68 | ## Option 69 | 70 | ```javascript 71 | var app = sse(res, options); 72 | ``` 73 | 74 | | Option | Desciption | 75 | | ------------- | ------------- | 76 | | padding | add padding 2Kb, default true | 77 | | heartbeat | send a "heartbeat" every 10 seconds. https://bugzilla.mozilla.org/show_bug.cgi?id=444328 | 78 | | retry | time to retry, default time 3000 | 79 | | headers | add extra header, default header {"Content-Type": "text/event-stream","Cache-Control": "no-cache", "Connection": "keep-alive"} | 80 | 81 | 82 | ## Function 83 | 84 | | Function | Desciption | 85 | | ------------- | ------------- | 86 | | send(data) | send data only (message on server sent events) | 87 | | sendEvent(name,data,timeInterval) | send data after timeInterval if no timeInterval send once (data can be a function)| 88 | | removeEvent(nameEvent, timeout) | remove an event after timeout, if no timeout it will remove immediately | 89 | | disconnect(function) | listen event 'close' | 90 | 91 | 92 | ## How to use 93 | 94 | You can use this module with HTTP response object 95 | 96 | 97 | ### The MIT License (MIT) 98 | 99 | Copyright (c) <2015> Tran Quoc Cuong 100 | 101 | Permission is hereby granted, free of charge, to any person obtaining a copy 102 | of this software and associated documentation files (the "Software"), to deal 103 | in the Software without restriction, including without limitation the rights 104 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105 | copies of the Software, and to permit persons to whom the Software is 106 | furnished to do so, subject to the following conditions: 107 | 108 | The above copyright notice and this permission notice shall be included in 109 | all copies or substantial portions of the Software. 110 | 111 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 112 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 113 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 114 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 115 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 116 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 117 | THE SOFTWARE. 118 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HELLO WORLD 6 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | var sse = require('../'); 2 | 3 | var express = require('express'); 4 | 5 | var app = express(); 6 | 7 | app.get('/', function (req,res) { 8 | res.sendFile(__dirname+ '/index.html'); 9 | }); 10 | 11 | app.get('/time', function (req,res) { 12 | var app = sse(res); 13 | 14 | app.sendEvent('time', function () { 15 | return new Date 16 | },1000); 17 | 18 | app.disconnect(function () { 19 | console.log("disconnected"); 20 | }); 21 | 22 | app.removeEvent('time',3100); 23 | 24 | }); 25 | 26 | app.listen(3000, function () { 27 | console.log('Simple SSE server start at port: 3000') 28 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var SSE = require('./libs/sse'); 2 | 3 | 4 | module.exports = function (res, options) { 5 | var newServerSent = new SSE(res, options); 6 | return newServerSent; 7 | }; 8 | 9 | module.exports.SSEServer = SSE; 10 | -------------------------------------------------------------------------------- /libs/sse.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var http = require('http'); 3 | 4 | class ServerSendEvent { 5 | constructor(response, options) { 6 | if (response instanceof http.OutgoingMessage) { 7 | this.res = response; 8 | var options = options || {}; 9 | var defaultHeaders = { 10 | "Content-Type": "text/event-stream", 11 | "Cache-Control": "no-cache", 12 | "Connection": "keep-alive" 13 | }; 14 | var padding = options.padding || true; 15 | var heartbeat = options.heartbeat || false; 16 | var retry = options.retry || 3000; 17 | var header = Object.assign({}, defaultHeaders, options.headers); 18 | this.events = {}; 19 | this.id = 0; 20 | this.res.writeHead(200, header); 21 | 22 | if (padding) { 23 | this.res.write(":" + Array(2049).join(" ") + "\n"); // 2kB 24 | } 25 | this.res.write("retry: " + retry + '\n'); 26 | 27 | if (heartbeat) { 28 | setInterval(function () { 29 | this.res.write("data: \n\n"); 30 | }.bind(this), 10000) 31 | } 32 | 33 | } else { 34 | throw Error("Not a http response object") 35 | } 36 | } 37 | 38 | send(data) { 39 | if (typeof data === 'string' || typeof data === 'number') { 40 | this.res.write('data: ' + data + '\n\n'); 41 | } else if (typeof data === 'object') { 42 | this.res.write('data: ' + JSON.stringify(data) + '\n\n'); 43 | } else { 44 | throw Error('Invalid data'); 45 | } 46 | this.res.flushHeaders(); 47 | } 48 | 49 | sendInterval(name, fn, time) { 50 | if (typeof fn === 'function') { 51 | if (this.events[name]) { 52 | throw Error('Event already existed'); 53 | } else { 54 | this.events[name] = []; 55 | } 56 | this.events[name] = setInterval(fn, time || 1000); 57 | } 58 | } 59 | 60 | removeEvent(name, time) { 61 | var self = this; 62 | if (time) { 63 | setTimeout(function () { 64 | self.removeEvent(name); 65 | }, time) 66 | } else { 67 | if (this.events[name]) { 68 | clearInterval(this.events[name]); 69 | } else { 70 | for (var key in this.event) { 71 | if (this.event.hasOwnProperty(key) && !this.events[name].length) { 72 | clearInterval(this.events[key]) 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | sendEvent(name, data, time) { 80 | var self = this; 81 | if (typeof name === 'string') { 82 | if (time) { 83 | this.events[name] = setInterval(function () { 84 | self.sendEvent(name, data) 85 | }, time); 86 | } else { 87 | this.res.write('id: ' + ++this.id + '\n'); 88 | this.res.write('event: ' + name + '\n'); 89 | if (typeof data === 'string' || typeof data === 'number') { 90 | this.res.write('data: ' + data + '\n\n'); 91 | } else if (typeof data === 'object') { 92 | this.res.write('data: ' + JSON.stringify(data) + '\n\n'); 93 | } else if (typeof data === 'function') { 94 | this.res.write('data: ' + JSON.stringify(data()) + '\n\n'); 95 | } else { 96 | throw Error('Invalid data'); 97 | } 98 | this.res.flushHeaders(); 99 | } 100 | } else { 101 | throw Error('Invalid parameter: name'); 102 | } 103 | } 104 | 105 | disconnect(fn) { 106 | if (typeof fn === 'function') { 107 | this.res.on('close', fn); 108 | } else { 109 | throw Error('Parameter must be a function'); 110 | } 111 | 112 | } 113 | } 114 | 115 | module.exports = ServerSendEvent; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sse-nodejs", 3 | "version": "0.1.0", 4 | "description": "Make a server sent events", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "server", 11 | "sent", 12 | "event", 13 | "server sent", 14 | "sse" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/trquoccuong/Server-Sent-Events-Nodejs.git" 19 | }, 20 | "author": "Tran Quoc Cuong