Chloe and the RTW
      Trotter Cashion
    Strange Loop 2011
For those
looking only
  at slides!
Co-Founder
@cashion
github.com/
   trotter
Go Get It!
http://github.com/mashion/chloe
Why?
Knockout!
simulchart.com
Knockout!
 Made me cry :-(
We can Haz?
 http://utterinsanity.files.wordpress.com/2008/09/funny-pictures-cat-drives-an-invisible-racecar.jpg%3Fw%3D497%26h%3D318
We can Haz?
 http://utterinsanity.files.wordpress.com/2008/09/funny-pictures-cat-drives-an-invisible-racecar.jpg%3Fw%3D497%26h%3D318
We can Haz?
 http://utterinsanity.files.wordpress.com/2008/09/funny-pictures-cat-drives-an-invisible-racecar.jpg%3Fw%3D497%26h%3D318
Got me thinking...
Chloe
A realtime web-server... that doesn’t suck.
Cool History, Right?
  http://github.com/mashion/chloe
Usage...
A Simple Chat Service
<html>
  <head>
    <script type="text/javascript" src="/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="http://localhost:8901/chloe.js">

       </script>
    <script type="text/javascript" src="/chat.js"></script>
    <title>Ajax Chat</title>
  </head>
  <body>
    <form>
      <input name="message" id="message" type="text"/>
      <input name="submit" type="submit" value="Send"/>
    </form>
    <ul id="messages"></ul>
  </body>
</html>
<html>
  <head>
    <script type="text/javascript" src="/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="http://localhost:8901/chloe.js">

       </script>
    <script type="text/javascript" src="/chat.js"></script>
    <title>Ajax Chat</title>
  </head>                     Include Chloe JS
  <body>
    <form>
      <input name="message" id="message" type="text"/>
      <input name="submit" type="submit" value="Send"/>
    </form>
    <ul id="messages"></ul>
  </body>
</html>
<html>
  <head>
    <script type="text/javascript" src="/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="http://localhost:8901/chloe.js">

       </script>
    <script type="text/javascript" src="/chat.js"></script>
    <title>Ajax Chat</title>
  </head>
  <body>
    <form>         Include Your JS
      <input name="message" id="message" type="text"/>
      <input name="submit" type="submit" value="Send"/>
    </form>
    <ul id="messages"></ul>
  </body>
</html>
$(function () {
  var form = $('form'),
      container = $('#messages');
      chloe = new Chloe({host: 'localhost', port: 8901});

  chloe.connect(function () {
    form.submit(function () {
      chloe.send(form.serialize());
      $('#message').val('');
      return false;
    });

    chloe.onmessage(function (message) {
      container.prepend("<li>" + message + "</li>");
    });
  });

});
$(function () {
  var form = $('form'),
      container = $('#messages');
      chloe = new Chloe({host: 'localhost', port: 8901});

  chloe.connect(function () {
    form.submit(function Instantiate
                          () {         Chloe
      chloe.send(form.serialize());
      $('#message').val('');
      return false;
    });

    chloe.onmessage(function (message) {
      container.prepend("<li>" + message + "</li>");
    });
  });

});
$(function () {
  var form = $('form'),
      container = $('#messages');
      chloe = new Chloe({host: 'localhost', port: 8901});

  chloe.connect(function () {
    form.submit(function () {
      chloe.send(form.serialize());
      $('#message').val(''); Server
               Connect to the
      return false;
    });

    chloe.onmessage(function (message) {
      container.prepend("<li>" + message + "</li>");
    });
  });

});
$(function () {
  var form = $('form'),
      container = $('#messages');
      chloe = new Chloe({host: 'localhost', port: 8901});

  chloe.connect(function () {
    form.submit(function () {
      chloe.send(form.serialize());
      $('#message').val('');
      return false;
    });            Send data to the   server
    chloe.onmessage(function (message) {
      container.prepend("<li>" + message + "</li>");
    });
  });

});
$(function () {
  var form = $('form'),
      container = $('#messages');
      chloe = new Chloe({host: 'localhost', port: 8901});

  chloe.connect(function () {
    form.submit(function () {
      chloe.send(form.serialize());
      $('#message').val('');
      return false; this function when
               Run                       a message arrives
    });

    chloe.onmessage(function (message) {
      container.prepend("<li>" + message + "</li>");
    });
  });

});
get '/' do
  erubis :index
end

post '/updates' do
  data = URI.decode_www_form(request.body.read)
  params = Hash[data]
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
                {"data" => params["message"]})
  'ok'
end
get '/' do
  erubis :index
end

post '/updates' html from earlier
         Get the do
  data = URI.decode_www_form(request.body.read)
  params = Hash[data]
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
                {"data" => params["message"]})
  'ok'
end
get '/' do
  erubis :index
end
                     chloe.send(form.serialize());
post '/updates' do
  data = URI.decode_www_form(request.body.read)
  params = Hash[data]
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
                {"data" => params["message"]})
  'ok'
end
get '/' do
  erubis :index
end

post '/updates' do Ruby trick!
  data = URI.decode_www_form(request.body.read)
  params = Hash[data]
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
                {"data" => params["message"]})
  'ok'
end
get '/' do
  erubis :index
end

post '/updates' do
  data = URI.decode_www_form(request.body.read)
  params = Hash[data]
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
                {"data" => params["message"]})
        Chloe broadcast/multicast url
  'ok'
end
get '/' do
  erubis :index
end

post '/updates' do
  data = URI.decode_www_form(request.body.read)
  params = Hash[data] data to Chloe
              Send the
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
                {"data" => params["message"]})
  'ok'
end
How It Works
Chloe and the Realtime Web
Chrome
Chrome   Server
Chrome          Server *




         *could be Java, Ruby, Scala, Clojure, Node...
Chrome          Server *                 Chloe




         *could be Java, Ruby, Scala, Clojure, Node...
Chrome            Server *                 Chloe
         GET /




           *could be Java, Ruby, Scala, Clojure, Node...
Chrome                Server *               Chloe
           GET /
         index.html




             *could be Java, Ruby, Scala, Clojure, Node...
Chrome                Server *                Chloe
           GET /
         index.html
          /chloe.js




              *could be Java, Ruby, Scala, Clojure, Node...
Chrome                Server *                Chloe
           GET /
         index.html
          /chloe.js
     “Hey Everyone”




              *could be Java, Ruby, Scala, Clojure, Node...
Chrome                Server *                Chloe
           GET /
         index.html
          /chloe.js
     “Hey Everyone”
                      POST /updates “Hey Everyone”




              *could be Java, Ruby, Scala, Clojure, Node...
Chrome                Server *                Chloe
           GET /
         index.html
          /chloe.js
     “Hey Everyone”
                      POST /updates “Hey Everyone”
                       POST /send “Hey Everyone”




              *could be Java, Ruby, Scala, Clojure, Node...
Chrome                Server *                Chloe
           GET /
         index.html
          /chloe.js
     “Hey Everyone”
                      POST /updates “Hey Everyone”
                       POST /send “Hey Everyone”
     “Hey Everyone”


              *could be Java, Ruby, Scala, Clojure, Node...
Fallbacks

Websockets
Long polling (jsonp)
Cross domain xhr - SOON!
This seems to be enough for now...
Channels
chloe.connect(function () {
  chloe.subscribe('chat-room-5', function (message) {
    $("#messages").prepend("<li>" + message + "</li>")
  });
});




post '/updates' do
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
       { "data" => "Hello room!",
         "channel" => "chat-room-5"})
  "ok"
end
Channel Name
chloe.connect(function () {
  chloe.subscribe('chat-room-5', function (message) {
    $("#messages").prepend("<li>" + message + "</li>")
  });
});




post '/updates' do
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
       { "data" => "Hello room!",
         "channel" => "chat-room-5"})
  "ok"
end
chloe.connect(function () {
  chloe.subscribe('chat-room-5', function (message) {
    $("#messages").prepend("<li>" + message + "</li>")
  });
});
                   Called when message arrives


post '/updates' do
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
       { "data" => "Hello room!",
         "channel" => "chat-room-5"})
  "ok"
end
chloe.connect(function () {
  chloe.subscribe('chat-room-5', function (message) {
    $("#messages").prepend("<li>" + message + "</li>")
  });
});




post '/updates' do
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
       { "data" => "Hello room!",
         "channel" => "chat-room-5"})
  "ok"
end
chloe.connect(function () {
  chloe.subscribe('chat-room-5', function (message) {
    $("#messages").prepend("<li>" + message + "</li>")
  });
});




post '/updates' do
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
       { "data" => "Hello room!",
         "channel" => "chat-room-5"})
  "ok"
end
                  Channel for broadcast
What’s left for Channels


 Bi-directionality
 Per Channel callbacks
Performance
 Difficult to determine...
50
                                          50



              40


                                 33.5
Memory (MB)




              30


              20
                       17

              10


              0
                   0         500        1000
                            Sessions
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1




               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#            Increase number of file descriptors
    /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1




               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#              Increase transaction queue length
    /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1




               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#                Increase size of listen queue
    /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1




               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#              Increase incoming packet queue
    /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1




               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl Increase maximum receive window
                  -w net.ipv4.tcp_syncookies=1




               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1
                  Increase send window



               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1

               How many SYN requests to keep in memory


               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
Tune Your TCP Stack
#   ulimit -n 65536
#   ifconfig eth0 txqueuelen 8192
#   /sbin/sysctl -w net.core.somaxconn=4096
#   /sbin/sysctl -w net.core.netdev_max_backlog=16384
#   /sbin/sysctl -w net.core.rmem_max=16777216
#   /sbin/sysctl -w net.core.wmem_max=16777216
#   /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192
#   /sbin/sysctl -w net.ipv4.tcp_syncookies=1


             Makes tcp_max_syn_backlog work


               From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
How much Overhead?
How much Overhead?


       ?
Up and Running
Binaries Available

Mac, Ubuntu 32bit, Ubuntu 64bit
Fully self-contained (Erlang included)
.deb and .rpm will be coming soon...
It’s Easy!
#   wget http://bit.ly/oqyQfL
#   tar xzvf chloe-0.0.3-osx.tgz
#   cd chloe-0.0.3
#   ./bin/chloe start
#   ./bin/chloe stop
It’s Easy!
#   wget http://bit.ly/oqyQfL
#   tar xzvf chloe-0.0.3-osx.tgz
#   cd chloe-0.0.3
#   ./bin/chloe start
#   ./bin/chloe stop
It’s Easy!
#   wget http://bit.ly/oqyQfL
#   tar xzvf chloe-0.0.3-osx.tgz
#   cd chloe-0.0.3
#   ./bin/chloe start
#   ./bin/chloe stop
It’s Easy!
#   wget http://bit.ly/oqyQfL
#   tar xzvf chloe-0.0.3-osx.tgz
#   cd chloe-0.0.3
#   ./bin/chloe start
#   ./bin/chloe stop
It’s Easy!
#   wget http://bit.ly/oqyQfL
#   tar xzvf chloe-0.0.3-osx.tgz
#   cd chloe-0.0.3
#   ./bin/chloe start
#   ./bin/chloe stop
./etc/app.config

{chloe,
  [
     {application_server, "http://localhost:4567"},
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}
./etc/app.config

{chloe,                For XHR
  [
     {application_server, "http://localhost:4567"},
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}
./etc/app.config

{chloe,
  [
        Callback url on your application
     {application_server, "http://localhost:4567"},
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}
./etc/app.config

{chloe,
  [
                  Chloe port
     {application_server, "http://localhost:4567"},
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}
./etc/app.config

{chloe,
  [
                          Where Chloe’s JavaScript Lives
     {application_server, "http://localhost:4567"},
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}
./etc/app.config

{chloe,
  [
     {application_server, "http://localhost:4567"},
                            Directory for Logs
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}
./etc/app.config

{chloe,
  [
     {application_server, "http://localhost:4567"},
     {application_server_url, "http://localhost:4567/updates"},
     {port, 8901},
     {doc_root, "./public"},
     {log_dir, "/var/log/chloe"},
     {secret, “SEKRET PASSFRASE”}
  ]}

                           For security (not required)...
Signing Requests
SECRET = "SEKRET PASSFRASE”

post '/updates' do
  data = URI.decode_www_form(request.body.read)
  message = Hash[data]["message"]
  sig = Digest::MD5.hexdigest(message + SECRET)
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
             {"data" => message, "sig" => sig})
  'ok'
end
Signing Requests
SECRET = "SEKRET PASSFRASE”

post '/updates' do
  data = URI.decode_www_form(request.body.read)
  message = Hash[data]["message"]
  sig = Digest::MD5.hexdigest(message + SECRET)
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
             {"data" => message, "sig" => sig})
  'ok'
end
Signing Requests
SECRET = "SEKRET PASSFRASE”

post '/updates' do
             From ./etc/app.config
  data = URI.decode_www_form(request.body.read)
  message = Hash[data]["message"]
  sig = Digest::MD5.hexdigest(message + SECRET)
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
             {"data" => message, "sig" => sig})
  'ok'
end
Signing Requests
SECRET = "SEKRET PASSFRASE”

post '/updates' do
                   Concat t wo strings
  data = URI.decode_www_form(request.body.read)
  message = Hash[data]["message"]
  sig = Digest::MD5.hexdigest(message + SECRET)
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
             {"data" => message, "sig" => sig})
  'ok'
end
Signing Requests
SECRET = "SEKRET PASSFRASE”

post '/updates' do
                      Hash them
  data = URI.decode_www_form(request.body.read)
  message = Hash[data]["message"]
  sig = Digest::MD5.hexdigest(message + SECRET)
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
             {"data" => message, "sig" => sig})
  'ok'
end
Signing Requests
SECRET = "SEKRET PASSFRASE”

post '/updates' do
  data = URI.decode_www_form(request.body.read)
  message = Hash[data]["message"]
  sig = Digest::MD5.hexdigest(message + SECRET)
  uri = URI.parse("http://localhost:8901/send")
  Net::HTTP.post_form(uri,
             {"data" => message, "sig" => sig})
  'ok'
end
                   Add signature to request
If `secret` is in your
config, all requests to
`/send` must be signed
Coming Soon
Improved Performance
Bi-directional channels
Per-channel callback urls
Runtime configuration
SSL Support
Coming Later

Improved monitoring
Explore switch to mochiweb internally
Client side authentication
Internals
Erlang Nerdery Time!
Session Manager
       Transports
Yaws
        Callback
                    Sessions




                    Channel Store
Session Manager
       Transports
Yaws
        Callback
                    Sessions




                    Channel Store
Session Manager
       Transports
Yaws
        Callback
                    Sessions




                    Channel Store
Session Manager
       Transports
Yaws
        Callback
                    Sessions




                    Channel Store
Session Manager
       Transports
Yaws
        Callback
                    Sessions




                    Channel Store
Session
Yaws   Websocket
                   Manager   Session
Session
     Yaws   Websocket
                        Manager   Session
Browser
Session
     Yaws      Websocket
                           Manager   Session
Browser
          New Conn
Session
     Yaws      Websocket
                            Manager   Session
Browser
          New Conn
                      Session?
Session
     Yaws      Websocket
                             Manager   Session
Browser
          New Conn
                      Session?
                     Session Pid
Session
     Yaws      Websocket
                             Manager   Session
Browser
          New Conn
                      Session?
                     Session Pid

                            Message!
Session
     Yaws      Websocket
                             Manager   Session
Browser
          New Conn
                      Session?
                     Session Pid

                            Message!
                                            Server
Channel
Yaws    Store    Session   Websocket
Channel
     Yaws    Store    Session   Websocket

Server
Channel
     Yaws        Store    Session   Websocket

Server
         Sessions?
Channel
     Yaws         Store    Session   Websocket

Server
         Sessions?
         Session Pid
Channel
     Yaws         Store    Session   Websocket

Server
         Sessions?
         Session Pid
                Message!
Channel
     Yaws         Store    Session    Websocket

Server
         Sessions?
         Session Pid
                Message!
                                Message!
Channel
     Yaws         Store    Session    Websocket

Server
         Sessions?
         Session Pid
                Message!
                                Message!
                                           Browser
Message Structure
{ data,
  version,
  type,
  channel,
  id,
  sessionId
}
Message Structure
{ data,
  version,
  type,The message itself
  channel,
  id,
  sessionId
}
Message Structure
{ data,
  version,
  type,
        Version of the message protocol
  channel,
  id,
  sessionId
}
Message Structure
{ data,
  version,
  type,
  channel,
        Four types: connect, message,
  id,               channel-subscribe, poll
  sessionId
}
Message Structure
{ data,
  version,
  type,
  channel,
  id,
  sessionId the message is going
        Where
}
Message Structure
{ data,
  version,
  type,
  channel,
  id,
  sessionId
}       No Idea...
Message Structure
{ data,
  version,
  type,
  channel,
  id,
  sessionId
}
       Session id for connection
Please Go Play With It

 http://github.com/mashion/chloe
 http://mashion.net
 http://trottercashion.com
 @cashion
Moved to Mountain View
        Be my friend?
Thank You!
 Good luck w/ Chloe

More Related Content

PDF
Fake My Party
PDF
Boom! Promises/A+ Was Born
PPTX
Async Frontiers
PPTX
The Promised Land (in Angular)
PDF
Web Crawling with NodeJS
ODP
The promise of asynchronous php
PPTX
ES6 is Nigh
ODP
The promise of asynchronous PHP
Fake My Party
Boom! Promises/A+ Was Born
Async Frontiers
The Promised Land (in Angular)
Web Crawling with NodeJS
The promise of asynchronous php
ES6 is Nigh
The promise of asynchronous PHP

What's hot (20)

PDF
Server Side Swift: Vapor
PDF
Consul ou comment bien tirer sur l’élastique
KEY
Async. and Realtime Geo Applications with Node.js
PDF
Introducing ruby on rails
PDF
A Gentle Introduction to Event Loops
PDF
JavaScript Promise
ODP
The promise of asynchronous php
PDF
Introduction to ECMAScript 2015
PDF
Asynchronous PHP and Real-time Messaging
PDF
Apache CouchDB talk at Ontario GNU Linux Fest
PDF
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
ODP
My app is secure... I think
PDF
React PHP: the NodeJS challenger
PDF
Play á la Rails
PDF
An opinionated intro to Node.js - devrupt hospitality hackathon
PDF
Symfony: Your Next Microframework (SymfonyCon 2015)
PDF
ZeroMQ: Messaging Made Simple
PDF
Interceptors: Into the Core of Pedestal
PDF
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
PDF
Solr @ Etsy - Apache Lucene Eurocon
Server Side Swift: Vapor
Consul ou comment bien tirer sur l’élastique
Async. and Realtime Geo Applications with Node.js
Introducing ruby on rails
A Gentle Introduction to Event Loops
JavaScript Promise
The promise of asynchronous php
Introduction to ECMAScript 2015
Asynchronous PHP and Real-time Messaging
Apache CouchDB talk at Ontario GNU Linux Fest
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
My app is secure... I think
React PHP: the NodeJS challenger
Play á la Rails
An opinionated intro to Node.js - devrupt hospitality hackathon
Symfony: Your Next Microframework (SymfonyCon 2015)
ZeroMQ: Messaging Made Simple
Interceptors: Into the Core of Pedestal
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
Solr @ Etsy - Apache Lucene Eurocon
Ad

Viewers also liked (20)

PDF
LXC, Docker, and the future of software delivery | LinuxCon 2013
KEY
Brunch With Coffee
PDF
Blazes: coordination analysis for distributed programs
PDF
Hyperdex - A closer look
PDF
Riak Search - Erlang Factory London 2010
PDF
ElasticSearch - index server used as a document database
PDF
(Functional) reactive programming (@pavlobaron)
PDF
Complex Legacy System Archiving/Data Retention with MongoDB and Xquery
PDF
Spring Cleaning for Your Smartphone
PDF
NkSIP: The Erlang SIP application server
PDF
Web-Oriented Architecture (WOA)
PDF
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
PDF
Scalable XQuery Processing with Zorba on top of MongoDB
PDF
Interoperability With RabbitMq
PPS
Erlang plus BDB: Disrupting the Conventional Web Wisdom
PDF
Shrinking the Haystack" using Solr and OpenNLP
PDF
Scaling Gilt: from Monolithic Ruby Application to Distributed Scala Micro-Ser...
PPTX
AST - the only true tool for building JavaScript
PDF
Erlang as a cloud citizen, a fractal approach to throughput
PDF
Pregel: A System for Large-Scale Graph Processing
LXC, Docker, and the future of software delivery | LinuxCon 2013
Brunch With Coffee
Blazes: coordination analysis for distributed programs
Hyperdex - A closer look
Riak Search - Erlang Factory London 2010
ElasticSearch - index server used as a document database
(Functional) reactive programming (@pavlobaron)
Complex Legacy System Archiving/Data Retention with MongoDB and Xquery
Spring Cleaning for Your Smartphone
NkSIP: The Erlang SIP application server
Web-Oriented Architecture (WOA)
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
Scalable XQuery Processing with Zorba on top of MongoDB
Interoperability With RabbitMq
Erlang plus BDB: Disrupting the Conventional Web Wisdom
Shrinking the Haystack" using Solr and OpenNLP
Scaling Gilt: from Monolithic Ruby Application to Distributed Scala Micro-Ser...
AST - the only true tool for building JavaScript
Erlang as a cloud citizen, a fractal approach to throughput
Pregel: A System for Large-Scale Graph Processing
Ad

Similar to Chloe and the Realtime Web (20)

PDF
WebSocket
DOC
T2
KEY
Pushing the web — WebSockets
PDF
Comet with node.js and V8
PPT
Http VS. Https
PDF
Consuming RESTful services in PHP
PDF
Consuming RESTful Web services in PHP
KEY
Socket.io
PDF
Server-Sent Events (real-time HTTP push for HTML5 browsers)
PPTX
Real time websites and mobile apps with SignalR
PPTX
Html5 communication
KEY
Push the web with HTML5
PDF
2015-10-07 PPDC HTTP Adapters
PDF
Real-Time with Flowdock
PPT
thisisahypertextbastamaonanasiyaprom.ppt
PPT
Get Real: Adventures in realtime web apps
PDF
Scalatra 2.2
PPT
Camelone-2012 HTML5 WebSocket ActiveMQ/Camel
PPTX
computer network introduction. psc notes . Assisant professor in cse.
ZIP
Fast & Scalable Front/Back-ends using Ruby, Rails & XMPP
WebSocket
T2
Pushing the web — WebSockets
Comet with node.js and V8
Http VS. Https
Consuming RESTful services in PHP
Consuming RESTful Web services in PHP
Socket.io
Server-Sent Events (real-time HTTP push for HTML5 browsers)
Real time websites and mobile apps with SignalR
Html5 communication
Push the web with HTML5
2015-10-07 PPDC HTTP Adapters
Real-Time with Flowdock
thisisahypertextbastamaonanasiyaprom.ppt
Get Real: Adventures in realtime web apps
Scalatra 2.2
Camelone-2012 HTML5 WebSocket ActiveMQ/Camel
computer network introduction. psc notes . Assisant professor in cse.
Fast & Scalable Front/Back-ends using Ruby, Rails & XMPP

Recently uploaded (20)

PDF
A novel scalable deep ensemble learning framework for big data classification...
PDF
DP Operators-handbook-extract for the Mautical Institute
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
PPTX
Tartificialntelligence_presentation.pptx
PDF
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
PPT
Module 1.ppt Iot fundamentals and Architecture
PDF
A comparative study of natural language inference in Swahili using monolingua...
PPTX
Web Crawler for Trend Tracking Gen Z Insights.pptx
PDF
A contest of sentiment analysis: k-nearest neighbor versus neural network
PDF
August Patch Tuesday
PDF
Hybrid model detection and classification of lung cancer
PDF
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
PPTX
O2C Customer Invoices to Receipt V15A.pptx
PDF
Unlock new opportunities with location data.pdf
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
WOOl fibre morphology and structure.pdf for textiles
PDF
A Late Bloomer's Guide to GenAI: Ethics, Bias, and Effective Prompting - Boha...
PPTX
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
DOCX
search engine optimization ppt fir known well about this
A novel scalable deep ensemble learning framework for big data classification...
DP Operators-handbook-extract for the Mautical Institute
1 - Historical Antecedents, Social Consideration.pdf
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
Tartificialntelligence_presentation.pptx
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
Module 1.ppt Iot fundamentals and Architecture
A comparative study of natural language inference in Swahili using monolingua...
Web Crawler for Trend Tracking Gen Z Insights.pptx
A contest of sentiment analysis: k-nearest neighbor versus neural network
August Patch Tuesday
Hybrid model detection and classification of lung cancer
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
O2C Customer Invoices to Receipt V15A.pptx
Unlock new opportunities with location data.pdf
Univ-Connecticut-ChatGPT-Presentaion.pdf
WOOl fibre morphology and structure.pdf for textiles
A Late Bloomer's Guide to GenAI: Ethics, Bias, and Effective Prompting - Boha...
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
search engine optimization ppt fir known well about this

Chloe and the Realtime Web

  • 1. Chloe and the RTW Trotter Cashion Strange Loop 2011
  • 5. github.com/ trotter
  • 10. Knockout! Made me cry :-(
  • 11. We can Haz? http://utterinsanity.files.wordpress.com/2008/09/funny-pictures-cat-drives-an-invisible-racecar.jpg%3Fw%3D497%26h%3D318
  • 12. We can Haz? http://utterinsanity.files.wordpress.com/2008/09/funny-pictures-cat-drives-an-invisible-racecar.jpg%3Fw%3D497%26h%3D318
  • 13. We can Haz? http://utterinsanity.files.wordpress.com/2008/09/funny-pictures-cat-drives-an-invisible-racecar.jpg%3Fw%3D497%26h%3D318
  • 15. Chloe A realtime web-server... that doesn’t suck.
  • 16. Cool History, Right? http://github.com/mashion/chloe
  • 18. <html>   <head>     <script type="text/javascript" src="/jquery-1.6.4.min.js"></script>  <script type="text/javascript" src="http://localhost:8901/chloe.js"> </script>     <script type="text/javascript" src="/chat.js"></script>     <title>Ajax Chat</title>   </head>   <body>     <form>       <input name="message" id="message" type="text"/>       <input name="submit" type="submit" value="Send"/>     </form>     <ul id="messages"></ul>   </body> </html>
  • 19. <html>   <head>     <script type="text/javascript" src="/jquery-1.6.4.min.js"></script>  <script type="text/javascript" src="http://localhost:8901/chloe.js"> </script>     <script type="text/javascript" src="/chat.js"></script>     <title>Ajax Chat</title>   </head> Include Chloe JS   <body>     <form>       <input name="message" id="message" type="text"/>       <input name="submit" type="submit" value="Send"/>     </form>     <ul id="messages"></ul>   </body> </html>
  • 20. <html>   <head>     <script type="text/javascript" src="/jquery-1.6.4.min.js"></script>  <script type="text/javascript" src="http://localhost:8901/chloe.js"> </script>     <script type="text/javascript" src="/chat.js"></script>     <title>Ajax Chat</title>   </head>   <body>     <form> Include Your JS       <input name="message" id="message" type="text"/>       <input name="submit" type="submit" value="Send"/>     </form>     <ul id="messages"></ul>   </body> </html>
  • 21. $(function () {   var form = $('form'),       container = $('#messages');       chloe = new Chloe({host: 'localhost', port: 8901});   chloe.connect(function () {    form.submit(function () {       chloe.send(form.serialize());       $('#message').val('');       return false;     });     chloe.onmessage(function (message) {       container.prepend("<li>" + message + "</li>");     });   }); });
  • 22. $(function () {   var form = $('form'),       container = $('#messages');       chloe = new Chloe({host: 'localhost', port: 8901});   chloe.connect(function () {    form.submit(function Instantiate () { Chloe       chloe.send(form.serialize());       $('#message').val('');       return false;     });     chloe.onmessage(function (message) {       container.prepend("<li>" + message + "</li>");     });   }); });
  • 23. $(function () {   var form = $('form'),       container = $('#messages');       chloe = new Chloe({host: 'localhost', port: 8901});   chloe.connect(function () {    form.submit(function () {       chloe.send(form.serialize());       $('#message').val(''); Server Connect to the       return false;     });     chloe.onmessage(function (message) {       container.prepend("<li>" + message + "</li>");     });   }); });
  • 24. $(function () {   var form = $('form'),       container = $('#messages');       chloe = new Chloe({host: 'localhost', port: 8901});   chloe.connect(function () {    form.submit(function () {       chloe.send(form.serialize());       $('#message').val('');       return false;     }); Send data to the server     chloe.onmessage(function (message) {       container.prepend("<li>" + message + "</li>");     });   }); });
  • 25. $(function () {   var form = $('form'),       container = $('#messages');       chloe = new Chloe({host: 'localhost', port: 8901});   chloe.connect(function () {    form.submit(function () {       chloe.send(form.serialize());       $('#message').val('');       return false; this function when Run a message arrives     });     chloe.onmessage(function (message) {       container.prepend("<li>" + message + "</li>");     });   }); });
  • 26. get '/' do   erubis :index end post '/updates' do   data = URI.decode_www_form(request.body.read) params = Hash[data] uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,                 {"data" => params["message"]})   'ok' end
  • 27. get '/' do   erubis :index end post '/updates' html from earlier Get the do   data = URI.decode_www_form(request.body.read) params = Hash[data] uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,                 {"data" => params["message"]})   'ok' end
  • 28. get '/' do   erubis :index end chloe.send(form.serialize()); post '/updates' do   data = URI.decode_www_form(request.body.read) params = Hash[data] uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,                 {"data" => params["message"]})   'ok' end
  • 29. get '/' do   erubis :index end post '/updates' do Ruby trick!   data = URI.decode_www_form(request.body.read) params = Hash[data] uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,                 {"data" => params["message"]})   'ok' end
  • 30. get '/' do   erubis :index end post '/updates' do   data = URI.decode_www_form(request.body.read) params = Hash[data] uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,                 {"data" => params["message"]}) Chloe broadcast/multicast url   'ok' end
  • 31. get '/' do   erubis :index end post '/updates' do   data = URI.decode_www_form(request.body.read) params = Hash[data] data to Chloe Send the uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,                 {"data" => params["message"]})   'ok' end
  • 35. Chrome Server
  • 36. Chrome Server * *could be Java, Ruby, Scala, Clojure, Node...
  • 37. Chrome Server * Chloe *could be Java, Ruby, Scala, Clojure, Node...
  • 38. Chrome Server * Chloe GET / *could be Java, Ruby, Scala, Clojure, Node...
  • 39. Chrome Server * Chloe GET / index.html *could be Java, Ruby, Scala, Clojure, Node...
  • 40. Chrome Server * Chloe GET / index.html /chloe.js *could be Java, Ruby, Scala, Clojure, Node...
  • 41. Chrome Server * Chloe GET / index.html /chloe.js “Hey Everyone” *could be Java, Ruby, Scala, Clojure, Node...
  • 42. Chrome Server * Chloe GET / index.html /chloe.js “Hey Everyone” POST /updates “Hey Everyone” *could be Java, Ruby, Scala, Clojure, Node...
  • 43. Chrome Server * Chloe GET / index.html /chloe.js “Hey Everyone” POST /updates “Hey Everyone” POST /send “Hey Everyone” *could be Java, Ruby, Scala, Clojure, Node...
  • 44. Chrome Server * Chloe GET / index.html /chloe.js “Hey Everyone” POST /updates “Hey Everyone” POST /send “Hey Everyone” “Hey Everyone” *could be Java, Ruby, Scala, Clojure, Node...
  • 45. Fallbacks Websockets Long polling (jsonp) Cross domain xhr - SOON! This seems to be enough for now...
  • 47. chloe.connect(function () {   chloe.subscribe('chat-room-5', function (message) {     $("#messages").prepend("<li>" + message + "</li>")   }); }); post '/updates' do   uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,        { "data" => "Hello room!", "channel" => "chat-room-5"})   "ok" end
  • 48. Channel Name chloe.connect(function () {   chloe.subscribe('chat-room-5', function (message) {     $("#messages").prepend("<li>" + message + "</li>")   }); }); post '/updates' do   uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,        { "data" => "Hello room!", "channel" => "chat-room-5"})   "ok" end
  • 49. chloe.connect(function () {   chloe.subscribe('chat-room-5', function (message) {     $("#messages").prepend("<li>" + message + "</li>")   }); }); Called when message arrives post '/updates' do   uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,        { "data" => "Hello room!", "channel" => "chat-room-5"})   "ok" end
  • 50. chloe.connect(function () {   chloe.subscribe('chat-room-5', function (message) {     $("#messages").prepend("<li>" + message + "</li>")   }); }); post '/updates' do   uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,        { "data" => "Hello room!", "channel" => "chat-room-5"})   "ok" end
  • 51. chloe.connect(function () {   chloe.subscribe('chat-room-5', function (message) {     $("#messages").prepend("<li>" + message + "</li>")   }); }); post '/updates' do   uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,        { "data" => "Hello room!", "channel" => "chat-room-5"})   "ok" end Channel for broadcast
  • 52. What’s left for Channels Bi-directionality Per Channel callbacks
  • 53. Performance Difficult to determine...
  • 54. 50 50 40 33.5 Memory (MB) 30 20 17 10 0 0 500 1000 Sessions
  • 55. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 56. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # Increase number of file descriptors /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 57. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # Increase transaction queue length /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 58. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # Increase size of listen queue /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 59. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # Increase incoming packet queue /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 60. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl Increase maximum receive window -w net.ipv4.tcp_syncookies=1 From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 61. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 Increase send window From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 62. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 How many SYN requests to keep in memory From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 63. Tune Your TCP Stack # ulimit -n 65536 # ifconfig eth0 txqueuelen 8192 # /sbin/sysctl -w net.core.somaxconn=4096 # /sbin/sysctl -w net.core.netdev_max_backlog=16384 # /sbin/sysctl -w net.core.rmem_max=16777216 # /sbin/sysctl -w net.core.wmem_max=16777216 # /sbin/sysctl -w net.ipv4.tcp_max_syn_backlog=8192 # /sbin/sysctl -w net.ipv4.tcp_syncookies=1 Makes tcp_max_syn_backlog work From cometd: http://cometd.org/documentation/2.x/howtos/loadtesting
  • 67. Binaries Available Mac, Ubuntu 32bit, Ubuntu 64bit Fully self-contained (Erlang included) .deb and .rpm will be coming soon...
  • 68. It’s Easy! # wget http://bit.ly/oqyQfL # tar xzvf chloe-0.0.3-osx.tgz # cd chloe-0.0.3 # ./bin/chloe start # ./bin/chloe stop
  • 69. It’s Easy! # wget http://bit.ly/oqyQfL # tar xzvf chloe-0.0.3-osx.tgz # cd chloe-0.0.3 # ./bin/chloe start # ./bin/chloe stop
  • 70. It’s Easy! # wget http://bit.ly/oqyQfL # tar xzvf chloe-0.0.3-osx.tgz # cd chloe-0.0.3 # ./bin/chloe start # ./bin/chloe stop
  • 71. It’s Easy! # wget http://bit.ly/oqyQfL # tar xzvf chloe-0.0.3-osx.tgz # cd chloe-0.0.3 # ./bin/chloe start # ./bin/chloe stop
  • 72. It’s Easy! # wget http://bit.ly/oqyQfL # tar xzvf chloe-0.0.3-osx.tgz # cd chloe-0.0.3 # ./bin/chloe start # ./bin/chloe stop
  • 73. ./etc/app.config {chloe, [ {application_server, "http://localhost:4567"}, {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]}
  • 74. ./etc/app.config {chloe, For XHR [ {application_server, "http://localhost:4567"}, {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]}
  • 75. ./etc/app.config {chloe, [ Callback url on your application {application_server, "http://localhost:4567"}, {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]}
  • 76. ./etc/app.config {chloe, [ Chloe port {application_server, "http://localhost:4567"}, {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]}
  • 77. ./etc/app.config {chloe, [ Where Chloe’s JavaScript Lives {application_server, "http://localhost:4567"}, {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]}
  • 78. ./etc/app.config {chloe, [ {application_server, "http://localhost:4567"}, Directory for Logs {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]}
  • 79. ./etc/app.config {chloe, [ {application_server, "http://localhost:4567"}, {application_server_url, "http://localhost:4567/updates"}, {port, 8901}, {doc_root, "./public"}, {log_dir, "/var/log/chloe"}, {secret, “SEKRET PASSFRASE”} ]} For security (not required)...
  • 80. Signing Requests SECRET = "SEKRET PASSFRASE” post '/updates' do   data = URI.decode_www_form(request.body.read) message = Hash[data]["message"] sig = Digest::MD5.hexdigest(message + SECRET) uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,              {"data" => message, "sig" => sig})   'ok' end
  • 81. Signing Requests SECRET = "SEKRET PASSFRASE” post '/updates' do   data = URI.decode_www_form(request.body.read) message = Hash[data]["message"] sig = Digest::MD5.hexdigest(message + SECRET) uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,              {"data" => message, "sig" => sig})   'ok' end
  • 82. Signing Requests SECRET = "SEKRET PASSFRASE” post '/updates' do From ./etc/app.config   data = URI.decode_www_form(request.body.read) message = Hash[data]["message"] sig = Digest::MD5.hexdigest(message + SECRET) uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,              {"data" => message, "sig" => sig})   'ok' end
  • 83. Signing Requests SECRET = "SEKRET PASSFRASE” post '/updates' do Concat t wo strings   data = URI.decode_www_form(request.body.read) message = Hash[data]["message"] sig = Digest::MD5.hexdigest(message + SECRET) uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,              {"data" => message, "sig" => sig})   'ok' end
  • 84. Signing Requests SECRET = "SEKRET PASSFRASE” post '/updates' do Hash them   data = URI.decode_www_form(request.body.read) message = Hash[data]["message"] sig = Digest::MD5.hexdigest(message + SECRET) uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,              {"data" => message, "sig" => sig})   'ok' end
  • 85. Signing Requests SECRET = "SEKRET PASSFRASE” post '/updates' do   data = URI.decode_www_form(request.body.read) message = Hash[data]["message"] sig = Digest::MD5.hexdigest(message + SECRET) uri = URI.parse("http://localhost:8901/send")   Net::HTTP.post_form(uri,              {"data" => message, "sig" => sig})   'ok' end Add signature to request
  • 86. If `secret` is in your config, all requests to `/send` must be signed
  • 87. Coming Soon Improved Performance Bi-directional channels Per-channel callback urls Runtime configuration SSL Support
  • 88. Coming Later Improved monitoring Explore switch to mochiweb internally Client side authentication
  • 90. Session Manager Transports Yaws Callback Sessions Channel Store
  • 91. Session Manager Transports Yaws Callback Sessions Channel Store
  • 92. Session Manager Transports Yaws Callback Sessions Channel Store
  • 93. Session Manager Transports Yaws Callback Sessions Channel Store
  • 94. Session Manager Transports Yaws Callback Sessions Channel Store
  • 95. Session Yaws Websocket Manager Session
  • 96. Session Yaws Websocket Manager Session Browser
  • 97. Session Yaws Websocket Manager Session Browser New Conn
  • 98. Session Yaws Websocket Manager Session Browser New Conn Session?
  • 99. Session Yaws Websocket Manager Session Browser New Conn Session? Session Pid
  • 100. Session Yaws Websocket Manager Session Browser New Conn Session? Session Pid Message!
  • 101. Session Yaws Websocket Manager Session Browser New Conn Session? Session Pid Message! Server
  • 102. Channel Yaws Store Session Websocket
  • 103. Channel Yaws Store Session Websocket Server
  • 104. Channel Yaws Store Session Websocket Server Sessions?
  • 105. Channel Yaws Store Session Websocket Server Sessions? Session Pid
  • 106. Channel Yaws Store Session Websocket Server Sessions? Session Pid Message!
  • 107. Channel Yaws Store Session Websocket Server Sessions? Session Pid Message! Message!
  • 108. Channel Yaws Store Session Websocket Server Sessions? Session Pid Message! Message! Browser
  • 109. Message Structure { data, version, type, channel, id, sessionId }
  • 110. Message Structure { data, version, type,The message itself channel, id, sessionId }
  • 111. Message Structure { data, version, type, Version of the message protocol channel, id, sessionId }
  • 112. Message Structure { data, version, type, channel, Four types: connect, message, id, channel-subscribe, poll sessionId }
  • 113. Message Structure { data, version, type, channel, id, sessionId the message is going Where }
  • 114. Message Structure { data, version, type, channel, id, sessionId } No Idea...
  • 115. Message Structure { data, version, type, channel, id, sessionId } Session id for connection
  • 116. Please Go Play With It http://github.com/mashion/chloe http://mashion.net http://trottercashion.com @cashion
  • 117. Moved to Mountain View Be my friend?
  • 118. Thank You! Good luck w/ Chloe