Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Keeping Your Clients ‘NSync - Node.js and Derby...

Keeping Your Clients ‘NSync - Node.js and Derby: The New Kids on the Block

My presentation for Pivotal Labs NY 4/3/2012 on Derby, the new multi-client synchronization framework made by Nate Smith and Brian Noguchi.
Code from demo at: http://github.com/ledwards/skyhopper

Lee Edwards

April 03, 2012
Tweet

More Decks by Lee Edwards

Other Decks in Programming

Transcript

  1. Keeping Your Clients ‘NSync Node.js and Derby: The New Kids

    on the Block Lee Edwards April 3, 2012 Tuesday, April 3, 12
  2. Sockets in Python import socket s = socket.socket() s.connect((address, port))

    s.send("Request Data") print s.recv(4096) s.close() Tuesday, April 3, 12
  3. Polling on Rails <div id="inbox_status">Unknown</div> <%= periodically_call_remote :url => {

    :action => 'get_inbox_status', :user_id => @user.id}, :update => 'inbox_status', :frequency => 60, :condition => "$('inbox_status').innerHTML == 'Unknown'", :before => "Element.show('progress_indicator')", :complete => "Element.hide('progress_indicator')" }%> Tuesday, April 3, 12
  4. Comet Subvert HTTP 1.1 using: • Forever iframe • XHR/multipart

    • XHR Long Polling Tuesday, April 3, 12
  5. One Good Answer • Leave the HTTP 1.1 standard alone

    • Leave the browser idiosyncrasies alone • Build high-level abstraction on top of them • Client API (Javascript) • Server API (Ruby, or something less cool) Tuesday, April 3, 12
  6. • Server-side Javascript • Built on V8 Engine • Event-driven

    • Non-blocking I/O Tuesday, April 3, 12
  7. • Node-based MVC framework • Heavily Rails inspired • Includes

    a router! • Supports sessions! • Has a few templating engine choices! Tuesday, April 3, 12
  8. • Compatible with every browser (IE > 5.5) • ...Including

    mobile browsers! • Cross-domain connections • Heartbeats, timeouts, disconnect events Tuesday, April 3, 12
  9. Derby • HTML templating with view bindings • Model syncing

    • Conflict resolution • Persistence • Performance oriented • Built on Racer - no glue code Tuesday, April 3, 12
  10. Creating Players get('/play/:gameId?', function(page, model, params) { var gameId =

    params.gameId; model.subscribe({ _game: 'game.' + params.gameId }, function() { var nextPlayerCount = (model.get('_game.players.length') || 0) + 1; model.push('_game.players', { name: "Player " + nextPlayerCount }); model.set('_game.playerCount', nextPlayerCount); model.ref('_player', '_game.players.' + (nextPlayerCount - 1)); page.render({ gameId: gameId, }); }); }); Tuesday, April 3, 12
  11. Creating Cards model.push('_player.cards', { "thumbnail-url": "http://.." + randomInt + ".gif",

    domId: model.get('_player.name') + model.get('_player.nextCardIndex'), ownerIndex: model.get('_game.players').indexOf(model.get('_player')), cardIndex: model.get('_player.nextCardIndex'), position: { top: "0px", left: "0px" } }); Tuesday, April 3, 12
  12. <Body:> <h1>Welcome ((_player.name))</h1> <p><label>Your name: <input value="((_player.name))"></label> <p>There are ((_game.playerCount))

    players in the game:</p> <div id="players"> <ul> ((#_game.players)) <li>((.name))</li> ((/)) </ul> </div> <div id="table"> ((#_game.players)) ((.cards > card)) ((/)) </div> <card:> ... Tuesday, April 3, 12
  13. Events exports.dragEnd = function(e) { var element = $(e.target); var

    top = element.position().top + "px"; var left = element.position().left + "px"; var card = model.at(element); for (playerIndex in model.get('_game.players')) { card.set('position', { top: top, left: left }); }; } Tuesday, April 3, 12
  14. Callbacks model.on('set', '_game.players.*.cards.*.position', function(playerIndex, cardIndex, position) { var domId =

    model.get('_game.players.' + playerIndex + '.cards.' + cardIndex + '.domId'); var element = jQuery("#" + domId); element.css('left', position.left); element.css('top', position.top); } ); Tuesday, April 3, 12