diff --git a/Gemfile b/Gemfile
index 4f2c736a1..e65b8d357 100644
--- a/Gemfile
+++ b/Gemfile
@@ -13,7 +13,7 @@ gem "haml"
gem 'roxml', :git => "git://github.com/Empact/roxml.git"
gem 'gpgme'
-
+gem 'pubsubhubbub'
#mai crazy async stuff
#gem 'em-synchrony', :git => 'git://github.com/igrigorik/em-synchrony.git', :require => 'em-synchrony/em-http'
gem 'em-http-request',:git => 'git://github.com/igrigorik/em-http-request.git', :require => 'em-http'
diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb
index 11dbd939a..654f9af6f 100644
--- a/app/controllers/dashboards_controller.rb
+++ b/app/controllers/dashboards_controller.rb
@@ -1,7 +1,8 @@
class DashboardsController < ApplicationController
- before_filter :authenticate_user!, :except => :receive
+ before_filter :authenticate_user!, :except => [:receive, :hub]
include ApplicationHelper
+ include DashboardsHelper
def index
@posts = Post.paginate :page => params[:page], :order => 'created_at DESC'
@@ -15,6 +16,17 @@ class DashboardsController < ApplicationController
render :nothing => true
end
+ def hub
+ if params[:mode] == "subscribe"
+ response.status = subscribe(params)
+ end
+
+ render :nothing => true
+ end
+
+
+
+
def warzombie
render :nothing => true
if User.owner.email == "tom@joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil
diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb
index d4061d124..1e68a74da 100644
--- a/app/controllers/status_messages_controller.rb
+++ b/app/controllers/status_messages_controller.rb
@@ -1,5 +1,5 @@
class StatusMessagesController < ApplicationController
- before_filter :authenticate_user!
+ #before_filter :authenticate_user!
def index
@status_messages = StatusMessage.paginate :page => params[:page], :order => 'created_at DESC'
@@ -7,8 +7,7 @@ class StatusMessagesController < ApplicationController
respond_to do |format|
format.html
- format.xml {render :xml => Post.build_xml_for(@status_messages)}
- format.json { render :json => @status_messages }
+ format.atom {render :xml => Diaspora::XML::generate(:current_url => request.url, :objects => @status_messages)}
end
end
diff --git a/app/helpers/dashboards_helper.rb b/app/helpers/dashboards_helper.rb
index 8673a62e8..dc181652a 100644
--- a/app/helpers/dashboards_helper.rb
+++ b/app/helpers/dashboards_helper.rb
@@ -1,5 +1,19 @@
module DashboardsHelper
+ def subscribe(opts = {})
+ subscriber = Subscriber.first(:url => opts[:callback], :topic => opts[:topic])
+ subscriber ||= Subscriber.new(:url => opts[:callback], :topic => opts[:topic])
+ if subscriber.save
+
+ if opts[:verify] == 'sync'
+ 204
+ elsif opts[:verify] == 'async'
+ 202
+ end
+ else
+ 400
+ end
+ end
end
diff --git a/app/models/status_message.rb b/app/models/status_message.rb
index 96c9c689e..65e578dd6 100644
--- a/app/models/status_message.rb
+++ b/app/models/status_message.rb
@@ -9,8 +9,7 @@ class StatusMessage < Post
validates_presence_of :message
-
- def ==(other)
+ def ==(other)
(self.message == other.message) && (self.person.email == other.person.email)
end
diff --git a/app/models/subscriber.rb b/app/models/subscriber.rb
new file mode 100644
index 000000000..19d234d24
--- /dev/null
+++ b/app/models/subscriber.rb
@@ -0,0 +1,9 @@
+class Subscriber
+ include MongoMapper::Document
+
+ key :url
+ key :topic
+
+ validates_presence_of :url, :topic
+
+end
diff --git a/config/routes.rb b/config/routes.rb
index 08b1f6f55..64cea07b0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -18,7 +18,7 @@ Diaspora::Application.routes.draw do |map|
resources :users
match 'receive', :to => 'dashboards#receive'
-
+ match 'hub', :to => 'dashboards#hub'
root :to => 'dashboards#index'
end
diff --git a/lib/common.rb b/lib/common.rb
index fcd9cd82b..05acb4fbe 100644
--- a/lib/common.rb
+++ b/lib/common.rb
@@ -61,6 +61,9 @@ module Diaspora
recipients.map!{|x| x = x.url + "receive/"}
xml = self.class.build_xml_for([self])
@@queue.add_post_request( recipients, xml )
+
+ @@queue.add_hub_notification('http://pubsubhubbub.appspot.com/publish/', User.owner.url + self.class.to_s.pluralize.underscore )
+
@@queue.process
end
end
@@ -91,4 +94,90 @@ module Diaspora
end
end
end
+
+ module XML
+
+ OWNER = User.owner
+
+ def self.generate(opts= {})
+ xml = Generate::headers(opts[:current_url])
+ xml << Generate::author
+ xml << Generate::endpoints
+ xml << Generate::subject
+ xml << Generate::entries(opts[:objects])
+ xml << Generate::footer
+ end
+
+ module Generate
+ def self.headers(current_url)
+ <<-XML
+
+
+Diaspora
+#{current_url}
+Stream
+its a stream
+#{Time.now.xmlschema}
+ XML
+ end
+
+ def self.author
+ <<-XML
+
+#{OWNER.real_name}
+#{OWNER.url}
+
+ XML
+ end
+
+ def self.endpoints
+ <<-XML
+
+ XML
+ end
+
+ def self.subject
+ <<-XML
+
+http://activitystrea.ms/schema/1.0/person
+#{OWNER.url}
+#{OWNER.real_name}
+
+
+ XML
+ end
+
+ def self.entries(objects)
+ xml = ""
+ if objects.respond_to? :each
+ objects.each {|x| xml << self.entry(x)}
+ else
+ xml << self.entry(objects)
+ end
+ xml
+ end
+
+ def self.entry(object)
+ eval "#{object.class}_build_entry(object)"
+ end
+
+ def self.StatusMessage_build_entry(status_message)
+ <<-XML
+
+#{status_message.message}
+
+#{OWNER.url}status_messages/#{status_message.id}
+#{status_message.created_at.xmlschema}
+#{status_message.updated_at.xmlschema}
+
+ XML
+ end
+
+ def self.footer
+ <<-XML.strip
+
+ XML
+ end
+ end
+ end
end
diff --git a/lib/message_handler.rb b/lib/message_handler.rb
index 66bc0688a..95c6eb650 100644
--- a/lib/message_handler.rb
+++ b/lib/message_handler.rb
@@ -17,20 +17,28 @@ class MessageHandler
destinations.each{|dest| @queue.push(Message.new(:post, dest, b))}
end
+ def add_hub_notification(destination, feed_location)
+ @queue.push(Message.new(:pubhub, destination, feed_location))
+ end
+
def process
@queue.pop{ |query|
case query.type
when :post
- http = EventMachine::HttpRequest.new(query.destination).post :timeout => TIMEOUT, :body =>{:xml => query.body}
- http.callback {process}
+ http = EventMachine::HttpRequest.new(query.destination).post :timeout => TIMEOUT, :body =>{:xml => query.body}
+ http.callback { puts query.destination; process; process}
when :get
http = EventMachine::HttpRequest.new(query.destination).get :timeout => TIMEOUT
http.callback {send_to_seed(query, http.response); process}
+ when :pubhub
+ http = EventMachine::PubSubHubbub.new(query.destination).publish query.body, :timeout => TIMEOUT
+ http.callback { puts "boner city" + http.response ; process}
else
raise "message is not a type I know!"
end
http.errback {
+ puts http.response
puts "failure from #{query.destination}, retrying"
query.try_count +=1
@queue.push query unless query.try_count >= NUM_TRIES
diff --git a/spec/controllers/dashboards_controller_spec.rb b/spec/controllers/dashboards_controller_spec.rb
index 6b48d9a63..053dbdda0 100644
--- a/spec/controllers/dashboards_controller_spec.rb
+++ b/spec/controllers/dashboards_controller_spec.rb
@@ -4,8 +4,8 @@ describe DashboardsController do
render_views
before do
- request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user)
@user = Factory.create(:user, :profile => Profile.create( :first_name => "bob", :last_name => "smith"))
+ request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user)
end
it "on index sets a variable containing all a user's friends when a user is signed in" do
@@ -15,4 +15,45 @@ describe DashboardsController do
assigns[:friends].should == Person.friends.all
end
+ describe 'PubSubHubBuB intergration' do
+
+ describe 'incoming subscriptions' do
+ it 'should register a friend' do
+ Subscriber.all.count.should == 0
+
+ post :hub, {:callback => "http://example.com/",
+ :mode => 'subscribe',
+ :topic => '/status_messages',
+ :verify => 'async'}
+ response.status.should == 202
+
+ Subscriber.all.count.should == 1
+ end
+
+ it 'should keep track of what topic a subscriber wants' do
+ post :hub, {:callback => "http://example.com/",
+ :mode => 'subscribe',
+ :topic => '/status_messages',
+ :verify => 'async'}
+ Subscriber.first.topic.should == '/status_messages'
+ end
+ end
+
+ it 'should return a 204 for a sync request' do
+ post :hub, {:callback => "http://example.com/",
+ :mode => 'subscribe',
+ :topic => '/status_messages',
+ :verify => 'sync'}
+ response.status.should == 204
+ end
+
+ it 'should confirm subscription of a sync request' do
+ post :hub, {:callback => "http://example.com/",
+ :mode => 'subscribe',
+ :topic => '/status_messages',
+ :verify => 'sync'}
+
+ end
+
+ end
end
diff --git a/spec/lib/common_spec.rb b/spec/lib/common_spec.rb
index 7e2073d4d..debd5031f 100644
--- a/spec/lib/common_spec.rb
+++ b/spec/lib/common_spec.rb
@@ -1,6 +1,5 @@
require File.dirname(__FILE__) + '/../spec_helper'
-
include Diaspora
describe Diaspora do
@@ -63,7 +62,6 @@ describe Diaspora do
xml.should include ""
end
end
-
end
end
diff --git a/spec/lib/xml_spec.rb b/spec/lib/xml_spec.rb
new file mode 100644
index 000000000..5c1714d73
--- /dev/null
+++ b/spec/lib/xml_spec.rb
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Diaspora::XML do
+ before do
+ @user = Factory.create(:user, :profile => { :first_name => "robert", :last_name => "grimm" } )
+ Diaspora::XML::OWNER = @user
+ end
+
+ describe Diaspora::XML::Generate do
+
+ describe "header" do
+ it 'should generate an OStatus compliant header' do
+ Diaspora::XML::Generate::headers(:current_url => @user.url).should include @user.url
+ end
+ end
+
+ describe "status message entry" do
+ before do
+ @status_message = Factory.create(:status_message, :message => "feed me")
+ end
+
+ it "should encode to activity stream xml" do
+ sm_entry = Diaspora::XML::generate(:objects => @status_message, :current_url => "http://diaspora.com/")
+ sm_entry.should include(@status_message.message)
+ sm_entry.should include('title')
+ end
+
+ end
+ end
+
+end
diff --git a/spec/models/subscriber_spec.rb b/spec/models/subscriber_spec.rb
new file mode 100644
index 000000000..4cfad9bbe
--- /dev/null
+++ b/spec/models/subscriber_spec.rb
@@ -0,0 +1,15 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Subscriber do
+ it 'should require a url' do
+ n = Subscriber.new
+ n.valid?.should be false
+
+ n.topic = '/status_messages'
+ n.valid?.should be false
+
+ n.url = "http://clown.com/"
+
+ n.valid?.should be true
+ end
+end