View
3.329
Download
4
Category
Preview:
DESCRIPTION
An introduction to WebSockets and why Primus might be a better fit for your project. This presentation was given at WebRebels
Citation preview
TransformingTransformingTransforming
WebSocketsWebSocketsWebSockets
!
3rdEden
"
3rd-Eden
fb
arnout.kazemier
the good partsthe good partsWebSocketsWebSockets
the good partsWebSockets
Chrome 20
Firefox 12
Opera 12.1
Safari 6
Internet Explorer 10
Chrome 4
Firefox 4
Opera 11
Safari 4.2
Internet Explorer 10
oh, it’s bi-directional &
supports binary
oh, it’s bi-directional &
supports binary
oh, it’s bi-directional &
supports binary
The EndThe EndThe End
that nobody told youthat nobody told youthat nobody told youThe partsThe partsThe parts
HTTP proxy settings in your network settings can cause a full browser crash.
user agent sniff
if (! // Target safari browsers! $.browser.safari!! // Not chrome! && !$.browser.chrome!! // And correct WebKit version! && parseFloat($.browser.version, 0) < 534.54!) {! // Don’t use WebSockets!return;!
}
Writing to a closed WebSocket can cause a full browser crash
write crash
var ws = new WebSocket("wss://localhost:8080/");!!ws.onmessage = function message(event) {! // Wrap sends in a setTimeout out to allow the! // readyState to be correctly set to closed. But! // Only have this delay on mobile devices! if (mobile) return setTimeout(function () {! ws.send("Sup Oslo");! }, 0);!! ws.send("Sup Oslo");!};
Pressing ESC in Firefox closes the WebSocket connection
connection end
$('body').keydown(function (e) {! // make sure that you capture the `esc` key and! // prevent it's default action from happening! if (e.which === 27) e.preventDefault();!});
Firefox can create ghost connections when you connect during ws.onclose.
Don’t use self signed SSL certificates, not for development and not in production
4G, 3G, LTE, mobile providers WTF ARE YOU DOING?? — Reverse proxy
Virus scanners such as AVG block WebSockets.
User, network and server firewalls block WebSockets.
Load balancers don't understand and block WebSockets.
So yeah.. Real-Time is HARD
What if…What if…What if…we could change thiswe could change thiswe could change this
Frameworks!Frameworks!Frameworks!
frameworkws
https://github.com/einaros/ws/
super damned fast
supports binary
cross domain
all the cool kids are doing it
i’m the only somewhat maintainer
no fallbacks or downgrading
broken by firewalls/virus scanners
only server, no client
module*
frameworksocket.io
http://github.com/learnboost/socket.io
multiple transports
cross domain
invested with bugs
poorly / not maintained / left for dead
no message order guarantee
dies behind firewall/virusscanners
frameworkengine.io
http://github.com/learnboost/engine.io
supports multiple transports
cross domain
upgrade instead of downgrade
works behind firewalls & virusscanners
not well battle tested yet
no message order guarantee
frameworkbrowserchannelhttps://github.com/josephg/node-browserchannel
multiple transports
client maintained by google
message order guaranteed
works behind firewalls & virusscanners
not cross domain
no websocket support
coffeescript on the server ._.
frameworksockjs
https://github.com/sockjs/sockjs-node/
multiple transports (tons of them)
cross domain
poor error handling
no query string allowed for connect
argh, more coffeescript
connection delay with firewalls
poorly maintained
in the way of developers
They all have different use cases and API's. !
Changing product specs == rewrite
we could change this toowe could change this toowe could change this tooWhat if…What if…What if…
npm install primus
Primus wraps and improves popular real-time frameworks. So you can focus on building apps.
CommunityCommunityCommunity
community
community
1014
15
stars, but growing steadystar it on http://github.com/primus/primus1014
1 line of code to switch betweenexcluding adding a framework to your package.json
different frameworks build-insocket.io, engine.io, sockjs, websockets, browserchannel, but allows addition third party5
1014
15
community
community
5031
5031
50 different pluginssubstream, emit, primus-emitter, primus-cluster, primus-rooms, primus-multiplex, primus-redis
different authorsdamonoehlman, mmalecki, jcrugzz, daffl, balupton, cayasso & many more31
community#primus on irc.freenode.net
questions are bugs, ask them in our github issue tracker
why was primus inventedwhy was primus inventedwhy was primus inventedHistoryHistoryHistory
historyreal-time layer for the bigpipe app framework
historywhich had an engine.io wrapper
historyno single point of failure
historyextracted and released as !
primus
Use casesUse casesUse cases
use cases
module & framework authors
use cases
startups & web developers
Learning PrimusLearning Primus
Learning Primus
learning primus
cd your-awesome-project!!$ npm install --save primus ws!!echo "??" !echo “profit!”!!vim index.js
learning primus
'use strict';!!var Primus = require("primus")! , server = require("http").createServer(fn)! , primus = new Primus(server, { transformer:"ws" });!!primus.on("connection", function connection(spark) {! console.log("connection received", spark.id);! spark.write("ohai");!! spark.on("data", function data(msg) {! console.log("received", msg);! });!});!!server.listen(8080);
learning primus
<script src="http://localhost:8080/primus/primus.js"></script>!<script>!'use strict';!!var primus = new Primus("http://localhost:8080");!!primus.on("open", function connected() {! console.log("connection opened");! primus.write("ohai");!});!!primus.on("data", function data(msg) {! console.log(“received", msg);!});!</script>
SwitchingSwitchingSwitching
1 line of code
var primus = new Primus(server, { ! transformer: “sockjs" // engine.io, socket.io etc!});
1 line of code
1 line of code
module.exports = require(“primus/transformer").extend({! server: function () {! // This is only exposed and ran on the server.! },!! client: function () {! // This is stringified end send/stored in the client.! // Can be ran on the server, if used through Node.js! },!! // Optional library for the front-end, assumes globals! library: fs.readFileSync(__dirname +"./yourclientlib.js")!});
StabilityStabilityStability
manual patching
manual patching
Stream CompatibleStream CompatibleStream Compatible
stream compatible
primus.on("end", function disconnected() {! console.log("connection ended");!});!!primus.end();!primus.write();!!fs.createReadStream(__dirname + '/index.html').pipe(spark, {! end: false!});
EncodingEncodingEncoding
message encoding
var primus = new Primus(server, { ! parser: "JSON" // JSON by default!});
message encoding
var primus = new Primus(server, { ! parser: "EJSON" // or binary-pack or a third party module!});
message encoding
module.exports = {! encoder: function (data, fn) {! // encode data to a string.! },!! decoder: function (data, fn) {! // decode data to an object! },!! // Optional library for the front-end, assumes globals! library: fs.readFileSync(__dirname +"./yourclientlib.js")!};
message encoding
primus.transform('incoming', function (packet) {! // This would transform all incoming messages to foo;! packet.data = 'foo';!});!!primus.transform('outgoing', function (packet) {! // This would transform all outgoing messages to foo;! packet.data = 'foo';!});
transforming
ReconnectReconnectReconnect
reconnect
var primus = new Primus("http://localhost:8080", {! strategy: "disconnect, online"!});
BroadcastBroadcastBroadcast
broadcast
primus.write("message"); // send message to all users!!primus.forEach(function (spark) {! // Or iterate over all connections, select the once you! // want and only write to those!! spark.write("message");!});
Node clientNode clientNode client
node.js
var primus = new Primus(server)! , Socket = primus.Socket;!!var client = new Socket(“http://localhost:8080”);!!// or if you want to connect to a remote server:!var primus = require(“primus”).createSocket({/* options */});
PluginsPluginsPlugins
plugins
// The long awaited Socket.IO 1.0 release with Primus:!!var server = require("http").createServer(fn)! , primus = new Primus(server, { transformer:"engine.io" });!!primus.use(“emitter","primus-emitter")! .use(“multiplex”, require(“primus-multiplex”))! .use(“primus-emitter”, "primus-rooms");
plugins
module.exports = {! server: function () {! // This is only exposed and ran on the server.! },!! client: function () {! // This is stringified end send/stored in the client.! // Can be ran on the server, if used through Node.js! },!! // Optional library for the front-end, assumes globals! library: fs.readFileSync(__dirname +"./yourclientlib.js")!};
and middlewareand middlewareand middlewarePluginsPluginsPlugins
middleware
var server = require("http").createServer(fn)! , primus = new Primus(server, { transformer:"sockjs" });!!primus.before(“session”, require(“session-parse-module”))! .before(“middleware-name”, "middleware-module-name");
!
3rdEden
"
3rd-Eden
fb
arnout.kazemier
That's it! Thanks & check it out on http://primus.io
http://primus.io
Recommended