# WebEvents | |||||
This library provides an easy way to send events to a web browser (or any other | |||||
client) over HTTP. | |||||
## Usage | |||||
See the `test.js` file for an example application. | |||||
### Server | |||||
``` | |||||
var http = require("http"); | |||||
var WebEvents = require("webevnts"); | |||||
var events = WebEvents(); | |||||
http.createServer(function(req, res) { | |||||
/* | |||||
* Whatever else your app does on each request | |||||
*/ | |||||
events.handle(req, res); | |||||
}); | |||||
// Emit whatever events you need | |||||
events.emit("someevent", { some: "parameters" }); | |||||
``` | |||||
### Client | |||||
``` | |||||
var events = WebEvents(); | |||||
// Listen to events | |||||
events.on("someevent", function(evt) { | |||||
// evt -> { some: "parameters" } | |||||
}); | |||||
``` |
(function() { | |||||
function post(url, cb) { | |||||
var xhr = new XMLHttpRequest(); | |||||
xhr.addEventListener("load", function() { | |||||
var obj = JSON.parse(xhr.responseText); | |||||
if (obj.error) { | |||||
cb(obj.error); | |||||
} else { | |||||
cb(null, obj); | |||||
} | |||||
}); | |||||
xhr.addEventListener("error", function(err) { | |||||
cb(err); | |||||
}); | |||||
xhr.open("POST", url); | |||||
xhr.send(); | |||||
} | |||||
window.WebEvents = function() { | |||||
var self = {}; | |||||
var cbs = {}; | |||||
var key = null; | |||||
function emit(name, args) { | |||||
if (!cbs[name]) | |||||
return; | |||||
cbs[name].forEach(function(cb) { | |||||
cb(args); | |||||
}); | |||||
} | |||||
function init(time) { | |||||
post("/webevents/register", function(err, res) { | |||||
// Retry on error | |||||
if (err) { | |||||
console.error(err); | |||||
time = time || 1000; | |||||
setTimeout(function() { init(time * 2) }, time); | |||||
return; | |||||
} | |||||
key = res.key; | |||||
await(); | |||||
}); | |||||
} | |||||
function await(time) { | |||||
post("/webevents/await/"+key, function(err, res) { | |||||
// Retry registering on error | |||||
if (err) { | |||||
console.error(err); | |||||
time = time || 1000; | |||||
setTimeout(function() { init(time * 2) }, time); | |||||
return; | |||||
} | |||||
res.forEach(function(evt) { | |||||
emit(evt.name, evt.args); | |||||
}); | |||||
await(); | |||||
}); | |||||
} | |||||
self.on = function(name, cb) { | |||||
if (!cbs[name]) | |||||
cbs[name] = []; | |||||
cbs[name].push(cb); | |||||
}; | |||||
init(); | |||||
return self; | |||||
} | |||||
})(); |
var crypto = require("crypto"); | |||||
function Listener() { | |||||
var self = {} | |||||
var key = crypto.randomBytes(16).toString("hex"); | |||||
self.key = key; | |||||
var events = []; | |||||
var waiter = null; | |||||
function respond() { | |||||
waiter.end(JSON.stringify(events)); | |||||
waiter = null; | |||||
events = []; | |||||
} | |||||
self.emit = function(name, args) { | |||||
events.push({ name: name, args: args }); | |||||
if (waiter != null) { | |||||
respond(); | |||||
} | |||||
} | |||||
self.handle = function(res) { | |||||
waiter = res; | |||||
if (events.length > 0) { | |||||
respond(); | |||||
} | |||||
} | |||||
return self; | |||||
} | |||||
function WebEvents() { | |||||
var self = {} | |||||
var listeners = {}; | |||||
self.emit = function(name, args) { | |||||
for (var i in listeners) { | |||||
listeners[i].emit(name, args); | |||||
} | |||||
} | |||||
self.handle = function(req, res) { | |||||
var parts = req.url.substring(1).split("/"); | |||||
if (parts[0] !== "webevents") | |||||
return; | |||||
res.writeHead(200, { "content-type": "application/json" }); | |||||
if (parts[1] === "register") { | |||||
var listener = Listener(); | |||||
listeners[listener.key] = listener; | |||||
res.end(JSON.stringify({ key: listener.key })); | |||||
} else if (parts[1] === "await") { | |||||
var listener = listeners[parts[2]]; | |||||
if (!listener) { | |||||
res.end(JSON.stringify({ | |||||
error: "Listener "+parts[2]+" not registered" | |||||
})); | |||||
return; | |||||
} | |||||
listener.handle(res); | |||||
} | |||||
} | |||||
return self | |||||
} | |||||
module.exports = WebEvents; |
{ | |||||
"name": "webevents", | |||||
"version": "1.0.0", | |||||
"description": "A simple library for sending events from the server to the client.", | |||||
"main": "index.js", | |||||
"scripts": { | |||||
"test": "echo \"Error: no test specified\" && exit 1" | |||||
}, | |||||
"author": "Martin Dørum Nygaard <martid0311@gmail.com> (https://www.mort.coffee)", | |||||
"license": "ISC" | |||||
} |
var http = require("http"); | |||||
var Eventer = require("."); | |||||
var fs = require("fs"); | |||||
var html = | |||||
"<!DOCTYPE html>"+ | |||||
"<html>"+ | |||||
"<head>"+ | |||||
"<title>WebEvents</title>"+ | |||||
"</head>"+ | |||||
"<body>"+ | |||||
"<div "+ | |||||
"id='thing' "+ | |||||
"style='position: absolute; width: 30px; height: 30px; background: blue;'></div>"+ | |||||
"<script src='/client.js'></script>"+ | |||||
"<script>"+ | |||||
"var events = WebEvents();"+ | |||||
"events.on('move', function(evt) {"+ | |||||
"var elem = document.getElementById('thing');"+ | |||||
"elem.style.top = evt.y+'px';"+ | |||||
"elem.style.left = evt.x+'px';"+ | |||||
"});"+ | |||||
"</script>"+ | |||||
"</body>"+ | |||||
"</html>"; | |||||
var eventer = Eventer(); | |||||
http.createServer(function(req, res) { | |||||
if (req.url == "/") { | |||||
res.end(html); | |||||
} else if (req.url == "/client.js") { | |||||
fs.createReadStream("client.js") | |||||
.pipe(res) | |||||
.on("error", err => res.end(err.toString())); | |||||
} else if (req.url.indexOf("/webevents") === 0) { | |||||
eventer.handle(req, res); | |||||
} | |||||
}).listen(8080); | |||||
// Just keep track of some coordinates to send to the client as events | |||||
var x = 0; | |||||
var y = 0; | |||||
var vx = 30; | |||||
var vy = 30; | |||||
setInterval(() => { | |||||
if (x < 0) | |||||
vx = Math.abs(vx); | |||||
else if (x > 1000) | |||||
vx = -Math.abs(vx); | |||||
if (y < 0) | |||||
vy = Math.abs(vy); | |||||
else if (y > 600) | |||||
vy = -Math.abs(vy); | |||||
x += vx; | |||||
y += vy; | |||||
eventer.emit("move", { x: x, y: y }); | |||||
}, 100); |