Transcript
Page 1: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Real-Time Ruby for the Real-Time Webaka IM for web-applications

Ilya GrigorikCTO / PostRank

Page 2: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

www.postrank.com www.igvita.com@igrigorik

Background: - PHP, Perl - Ruby + Rails from ‘06

Page 3: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

The slides… Questions & Comments My blog

• Real-Time: the hype & the technology• Real-Time: the benefits

• XMPP• AMQP• PSHB• WebHooks

• Ruby examples• Real-life applications

Fully buzzword compliant!

Page 4: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

The Hype! Make it stop!

Page 5: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Real-Time has many definitionsIt all depends on your context

(micro/nano) seconds“Solution Exhibits Under 700 Nanoseconds of Latency for Inter-Process Communication Messaging”

milliseconds

seconds

minutes / hours

500ms is real-time enough to feel real-time for IM.

Real-time web is IM for web-services

Page 6: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

+ New Applications

+ Better Architecture

Page 7: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Polling: painful, wasteful

Data? No Data? No Data? Yes

Many wasteful checks

Page 8: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Page 9: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Extensible Messaging and Presence Protocol

Page 10: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Extensible Messaging and Presence Protocol (XMPP)

From: A, To: BHello!

From: A, To: BHello!

Page 11: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP Features

Persistent connections

Event-stream protocol

Identity and authentication

Presence

Page 12: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

JID: Federation, Identity & Authentication

User

Jabber Software Foundation

[email protected]/office

Domain Resource

Page 13: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Example: Message Routing with XMPP

<message from="[email protected]/office" type="chat" to="[email protected]" id="aae1a"> <body>hello</body> <active xmlns="http://jabber.org/protocol/chatstates"/></message>

Verbose protocol (XML)

Page 14: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP in the wild: Google Talk

Page 15: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP in the wild: Google Talk + Video

Page 16: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Psi: cross-platform Jabber/XMPP client

Page 17: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP4R (Ruby) Demo

require "rubygems"require "xmpp4r"

jid = Jabber::JID::new("[email protected]")client = Jabber::Client.new(jid)client.connect("talk.google.com")client.auth("password")

to = "[email protected]"subject = "Jabber client"message = "Hello XMPP World!"

piclient.send Jabber::Message::new(to, message).set_subject(subject)

# <message to='[email protected]'># <body>Hello XMPP World!</body># <subject>Jabber client</subject># </message>

Page 18: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP4R (Ruby) Demo

require "rubygems"require "xmpp4r"

jid = Jabber::JID::new("[email protected]")client = Jabber::Client.new(jid)client.connect("talk.google.com")client.auth("password")

to = "[email protected]"subject = "Jabber client"message = "Hello XMPP World!"

piclient.send Jabber::Message::new(to, message).set_subject(subject)

# <message to='[email protected]'># <body>Hello XMPP World!</body># <subject>Jabber client</subject># </message>

Page 19: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP4R (Ruby) Demo

client.send(Jabber::Presence.new.set_type(:away))

# <presence from='[email protected]/iMac8D2CB97D' to='[email protected]/0EDD826C' xmlns='jabber:client'># <show>away</show># <priority>0</priority># <x xmlns='http://www.apple.com/xmpp/idle'># <idle-since>2009-04-01T21:48:15Z</idle-since># </x># </presence>

client.add_message_callback do |m| puts "#{m.from} -- #{m.body}"end

# > [email protected] -- Hey!

Client Idle…

Page 20: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP4R (Ruby) Demo

client.send(Jabber::Presence.new.set_type(:available))

# <presence from='[email protected]/iMac8D2CB97D' to='[email protected]/0EDD826C' xmlns='jabber:client'># <show>away</show># <priority>0</priority># <x xmlns='http://www.apple.com/xmpp/idle'># <idle-since>2009-04-01T21:48:15Z</idle-since># </x># </presence>

client.add_message_callback do |m| puts "#{m.from} -- #{m.body}"end

# > [email protected] -- Hey!

Client Idle…

Page 21: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

One-to-many distribution + C2S

Page 22: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XEP-0060: Publish-Subscribe (Pubsub)

Page 23: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Publish-Subscribe

Subscribe New message!

Persistent connection

Page 24: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

<iq type='set‘ from='[email protected]/blogbot' to='pubsub.shakespeare.lit' id='pub1'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <publish node='princely_musings'>

<item> <entry xmlns='http://www.w3.org/2005/Atom'> <title>Soliloquy<title> <summary> To be, or not to be: that is the question! <summary> <link rel='alternate' type='text/html' href='http://denmark.lit/2003/12/13/atom03'/> <id>tag:denmark.lit,2003:entry-32397</id> <published>2003-12-13T18:30:02Z</published> <updated>2003-12-13T18:30:02Z</updated> </entry> </item>

</publish> </pubsub></iq>

IQ Stanza

PubSub Protocol: Client XML

Page 25: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

<iq type='set‘ from='[email protected]/blogbot' to='pubsub.shakespeare.lit' id='pub1'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <publish node='princely_musings'>

<item> <entry xmlns='http://www.w3.org/2005/Atom'> <title>Soliloquy<title> <summary> To be, or not to be: that is the question! <summary> <link rel='alternate' type='text/html' href='http://denmark.lit/2003/12/13/atom03'/> <id>tag:denmark.lit,2003:entry-32397</id> <published>2003-12-13T18:30:02Z</published> <updated>2003-12-13T18:30:02Z</updated> </entry> </item>

</publish> </pubsub></iq>

AtomPub

PubSub Protocol: Client XML

Page 26: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XEP-0060: Publish-Subscribe (Pubsub)Publish

Distribute

Page 27: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

<message from='pubsub.shakespeare.lit' to='[email protected]' id='foo'> <event xmlns='http://jabber.org/protocol/pubsub#event'> <items node='princely_musings'> <item id='ae890ac52d0df67ed7cfdf51b644e901'> [ ... ENTRY ... ] </item> </items> </event></message>

<message from='pubsub.shakespeare.lit' to='[email protected]' id='bar'> <event xmlns='http://jabber.org/protocol/pubsub#event'> <items node='princely_musings'> <item id='ae890ac52d0df67ed7cfdf51b644e901'> [ ... ENTRY ... ] </item> </items> </event></message>

Subscriber A

XEP-0060: Publish-Subscribe (Pubsub)

Subscriber B

Page 28: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Real-time communication

XMPP XMPPXMPP

Page 29: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Page 30: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Ruby + FireEagle via XMPP

require 'fire_hydrant'require 'yaml'

hydrant = FireHydrant.new(YAML.load(File.read("config.yml")))

hydrant.on_location_update do |user| puts "#{user.token} has moved to #{user.locations.first}."end

hydrant.run!

Push notifications

Page 31: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

XMPP / Jabber Servers

Ejabberd ErlangDjabberd PerlOpenFire JavaTigase Java RPM, GUI, shiny

Defacto XMPP server

Page 32: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Advanced Message Queuing Protocol (AMQP)

Page 33: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Working Group (16 companies)

“AMQP is an open Internet Protocol for Business Messaging”

Page 34: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP ArchitecturePublisher

AMQP Broker Consumer

Page 35: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Clustering

Broker Clustering

Page 36: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Broker Internals

Direct Exchange

Topic Exchange

Fanout Exchange

Routing key: usd.stock.amzMessage: I like AMZ!

Page 37: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Direct Exchange

Direct Exchange

Topic Exchange

Fanout Exchange

Routing key: usd.stock.amzMessage: I like AMZ!

Queue Name: amazonBind: usd.stock.amz

Page 38: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Topic Exchange

Direct Exchange

Topic Exchange

Fanout Exchange

Queue Name: stocksBind: usd.stock.*

Routing key: usd.stock.amzMessage: I like AMZ!

Page 39: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Topic Exchange

Direct Exchange

Topic Exchange

Fanout Exchange

Routing key: usd.stock.msftMessage: I like Microsoft!

Message: I like Microsoft! Queue

Page 40: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Fanout Exchange

Direct Exchange

Topic Exchange

Fanout Exchange

Routing key: usd.stock.msftMessage: I like Microsoft!

Queue 2

Name: stocksBind: “”

Queue 1

Page 41: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Fanout Exchange

Direct Exchange

Topic Exchange

Fanout Exchange

Routing key: usd.stock.msftMessage: I like Microsoft!

Queue 2 Message: I like MicrosoftQueue

1

Page 42: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Kung-fu: Load-balancing

Page 43: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

AMQP Load Balancing

Direct Exchange

Topic Exchange

Fanout Exchange

Routing key: usd.stock.amzMessage: I like AMZ!

Only one client gets the message!Queue

Page 44: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Elastic AMQP Load-balancing

GET /purchase

OK

Bind: purchase.pdf

HAProxy

App server BApp server A

Page 45: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

More AMQP Kung-fu: - Pubsub - Key routing - Failover - Instant feedback - At least once, exactly-once - …

http://bit.ly/igvita-amqp

Page 46: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

require 'mq' AMQP.start(:host => 'amqp-server.com') do

mq = MQ.new mq.topic('stocks').publish("5.95", :key => "usd.amz") end

AMQP.start(:host => 'amqp-server.com') do mq = MQ.new mq.queue(’stocks').bind(mq.topic('stocks'), :key => 'usd.*').subscribe{ |price| print ’stock quote: ', price } end

Publisher

AMQP + Ruby Example

Page 47: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

require 'mq' AMQP.start(:host => 'amqp-server.com') do

mq = MQ.new mq.topic('stocks').publish("5.95", :key => "usd.amz") end

AMQP.start(:host => 'amqp-server.com') do mq = MQ.new mq.queue(‘stocks').bind(mq.topic('stocks'), :key => 'usd.*').subscribe{ |price| print ‘stock quote: ', price } end

Consumer

AMQP + Ruby Example

Page 48: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Page 49: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

http://blog.webhooks.org/2009/04/23/slides-from-pivotal-labs-talk/

WebHooks:Pattern for enabling user-defined callbacks in web-applications

Page 50: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

http://blog.webhooks.org/2009/04/23/slides-from-pivotal-labs-talk/

WebHooks @ PayPal

Page 51: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

http://blog.webhooks.org/2009/04/23/slides-from-pivotal-labs-talk/

WebHooks Workflow

HAProxy

App server BApp server A

1

/register http://callback-1.com/register http://callback-2.com

ok

http://blog.webhooks.org/2009/04/23/slides-from-pivotal-labs-talk/

HAProxy

App server BApp server A

2

/post Hello World!

ok

3/post Hello World!

/post Hello World!

http://callback-1.com

http://callback-2.com

Page 52: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

WebHooks WorkflowWebHooks @ GitHub

Page 53: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Rails ActiveRecord + WebHooks

Page 54: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Watercoolr: Ruby WebHooks Servervia a simple Sinatra app

http://github.com/jcapote/watercoolr

→ POST /channels← { 'id':'2d0128d' }1

2 → POST /subscribers data={ 'channel':'2d0128d', 'url':'http://api.calback.com/handler' }← { 'status': 'OK' }

you → POST /messages data={ 'channel':'2d0128d', 'message':'hey guys!' } watercoolr → POST http://api.callback.com/handler data='hey guys!' ...for every subscriber...← { 'status': 'OK' }

3

Page 55: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Watercoolr on Google App EngineDataMapper + Sinatra + Jruby

require 'rubygems'require 'rest_client'require 'json'

# ruby postbin.rb http://www.postbin.org/1j11vyp

puts "creating channel..."resp = RestClient.post 'http://watercoolr.appspot.com/channels', :data => ''id = JSON.parse(resp)["id"]

puts "adding subscriber to channel #{id}"resp = RestClient.post 'http://watercoolr.appspot.com/subscribers', :data => { :channel => id, :url => ARGV[0] }.to_json

puts resp # {"status":"OK"}

puts "posting message to #{id}"resp = RestClient.post 'http://watercoolr.appspot.com/messages', :data => { :channel => id, :message => 'Hello World' }.to_json

puts resp # {"status":"OK"}

Page 56: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Watercoolr on Google App EngineDataMapper + Sinatra + Jruby

require 'rubygems'require 'rest_client'require 'json'

# ruby postbin.rb http://www.postbin.org/1j11vyp

puts "creating channel..."resp = RestClient.post 'http://watercoolr.appspot.com/channels', :data => ''id = JSON.parse(resp)["id"]

puts "adding subscriber to channel #{id}"resp = RestClient.post 'http://watercoolr.appspot.com/subscribers', :data => { :channel => id, :url => ARGV[0] }.to_json

puts resp # {"status":"OK"}

puts "posting message to #{id}"resp = RestClient.post 'http://watercoolr.appspot.com/messages', :data => { :channel => id, :message => 'Hello World' }.to_json

puts resp # {"status":"OK"}

Page 57: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Watercoolr on Google App EngineDataMapper + Sinatra + Jruby

require 'rubygems'require 'rest_client'require 'json'

# ruby postbin.rb http://www.postbin.org/1j11vyp

puts "creating channel..."resp = RestClient.post 'http://watercoolr.appspot.com/channels', :data => ''id = JSON.parse(resp)["id"]

puts "adding subscriber to channel #{id}"resp = RestClient.post 'http://watercoolr.appspot.com/subscribers', :data => { :channel => id, :url => ARGV[0] }.to_json

puts resp # {"status":"OK"}

puts "posting message to #{id}"resp = RestClient.post 'http://watercoolr.appspot.com/messages', :data => { :channel => id, :message => 'Hello World' }.to_json

puts resp # {"status":"OK"}

Page 58: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

http://bit.ly/igvita-watercoolrhttp://www.github.com/igrigorik/watercoolrhttp://www.postbin.org

POST’ing to PostBingreat debugging tool

Page 59: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

PubSub over HTTPbasically, WebHooks…

Page 60: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

“A simple, open, server-to-server web-hook-based pubsub (publish/subscribe) protocol as an extension to Atom and RSS.”

“Parties (servers) speaking the PubSubHubbub protocol can get near-instant notifications (via webhook callbacks) when a topic (feed URL) they're interested in is updated.”

http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.2.html

+ Spec’ed PubSub Protocol

+ Deployed & Available

+ XML Transport

- XML Transport

- Not as general purpose

- No firehose

http://docs.google.com/present/view?id=ajd8t6gk4mh2_34dvbpchfs

Page 61: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

1

2

Page 62: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

3

4

Page 63: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

PSHB in the WildGoogle, Typepad, Wordpress…

Page 64: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Consuming PSHB in Rubygem install pubsubhubbub

require 'pubsubhubbub'

EventMachine.run { hub = EventMachine::PubSubHubbub.new('http://pubsubhubbub.appspot.com/') # subscribe to real-time notifications hub.subscribe "http://blog.yoursite.com/atom.xml", "http://yourhub.com/hubbub” # unsubscribe hub.unsubscribe "http://blog.yoursite.com/atom.xml", "http://yourhub.com/hubbub” hub.callback { puts "Processed" } hub.errback { puts "Error! " + hub.response_header.status.to_s }}

Page 65: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Consuming PSHB in Rubygem install pubsubhubbub

require 'pubsubhubbub'

EventMachine.run { hub = EventMachine::PubSubHubbub.new('http://pubsubhubbub.appspot.com/') # subscribe to real-time notifications hub.subscribe "http://blog.yoursite.com/atom.xml", "http://yourhub.com/hubbub” # unsubscribe hub.unsubscribe "http://blog.yoursite.com/atom.xml", "http://yourhub.com/hubbub” hub.callback { puts "Processed" } hub.errback { puts "Error! " + hub.response_header.status.to_s }}

Page 66: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Consuming PSHB in Rubygem install pubsubhubbub

require 'pubsubhubbub'

EventMachine.run { hub = EventMachine::PubSubHubbub.new('http://pubsubhubbub.appspot.com/') # subscribe to real-time notifications hub.subscribe "http://blog.yoursite.com/atom.xml", "http://yourhub.com/hubbub” # unsubscribe hub.unsubscribe "http://blog.yoursite.com/atom.xml", "http://yourhub.com/hubbub” hub.callback { puts "Processed" } hub.errback { puts "Error! " + hub.response_header.status.to_s }}

Page 67: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Publishing PSHB in Rubygem install pubsubhubbub

require 'pubsubhubbub'

EventMachine.run { hub = EventMachine::PubSubHubbub.new('http://pubsubhubbub.appspot.com/publish') # publish notification to all subscribers hub.publish ['http://www.test.com', 'http://www.test.com/2'] hub.callback { puts "Notified PSHB Hub" } hub.errback { puts "Notification failed" + hub.response_header.status.to_s } }

Page 68: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Publishing PSHB in Rubygem install pubsubhubbub

require 'pubsubhubbub'

EventMachine.run { hub = EventMachine::PubSubHubbub.new('http://pubsubhubbub.appspot.com/publish') # publish notification to all subscribers hub.publish ['http://www.test.com', 'http://www.test.com/2'] hub.callback { puts "Notified PSHB Hub" } hub.errback { puts "Notification failed" + hub.response_header.status.to_s } }

Page 69: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

http://github.com/igrigorik/pubsubhubbub

Page 70: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Real-Time Web = “IM for web applications”

• XMPP : Presence• AMQP : Routing

• WebHooks : Extensibility• PubsubHubbub : PubSub over HTTP

Page 71: Real-time Ruby for the Real-time Web

Real-Time Ruby & Real-Time Web @igrigorik #railssummit #realtimehttp://bit.ly/eda

Questions?

The slides… Questions & Comments My blog

http://bit.ly/igvita-amqphttp://bit.ly/igvita-webhookshttp://bit.ly/igvita-pshb

Related Blog Posts:


Top Related