Skip to content
Browse files

Broke out connections into a new module that opens and closes connect…

…ions easily.
  • Loading branch information...
1 parent 1a9e4a3 commit e6b7afeeb09cb716f0845145107003aa3a6cc387 @markbates markbates committed
View
2 Rakefile
@@ -4,7 +4,7 @@ require 'gemstub'
Gemstub.test_framework = :rspec
Gemstub.gem_spec do |s|
- s.version = "0.2.1"
+ s.version = "0.2.2"
s.rubyforge_project = "magrathea"
s.add_dependency('configatron')
s.email = 'mark@markbates.com'
View
4 apn_on_rails.gemspec
@@ -2,7 +2,7 @@
Gem::Specification.new do |s|
s.name = %q{apn_on_rails}
- s.version = "0.2.1.20090730113724"
+ s.version = "0.2.2.20090730143010"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["markbates"]
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
s.description = %q{apn_on_rails was developed by: markbates}
s.email = %q{mark@markbates.com}
s.extra_rdoc_files = ["README", "LICENSE"]
- s.files = ["lib/apn_on_rails/apn_on_rails.rb", "lib/apn_on_rails/app/models/apn/device.rb", "lib/apn_on_rails/app/models/apn/notification.rb", "lib/apn_on_rails/tasks/apn.rake", "lib/apn_on_rails/tasks/db.rake", "lib/apn_on_rails.rb", "lib/apn_on_rails_tasks.rb", "README", "LICENSE", "generators/apn_migrations_generator.rb", "generators/templates/apn_migrations/001_create_apn_devices.rb", "generators/templates/apn_migrations/002_create_apn_notifications.rb"]
+ s.files = ["lib/apn_on_rails/apn_on_rails.rb", "lib/apn_on_rails/app/models/apn/connection.rb", "lib/apn_on_rails/app/models/apn/device.rb", "lib/apn_on_rails/app/models/apn/notification.rb", "lib/apn_on_rails/tasks/apn.rake", "lib/apn_on_rails/tasks/db.rake", "lib/apn_on_rails.rb", "lib/apn_on_rails_tasks.rb", "README", "LICENSE", "generators/apn_migrations_generator.rb", "generators/templates/apn_migrations/001_create_apn_devices.rb", "generators/templates/apn_migrations/002_create_apn_notifications.rb"]
s.homepage = %q{http://www.metabates.com}
s.require_paths = ["lib"]
s.rubyforge_project = %q{magrathea}
View
14 lib/apn_on_rails/apn_on_rails.rb
@@ -14,12 +14,22 @@
configatron.apn.set_default(:passphrase, '')
configatron.apn.set_default(:port, 2195)
-configatron.apn.set_default(:host, 'gateway.sandbox.push.apple.com')
-configatron.apn.set_default(:cert, File.join(rails_root, 'config', 'apple_push_notification_development.pem'))
+
+configatron.apn.feedback.set_default(:passphrase, configatron.apn.passphrase)
+configatron.apn.feedback.set_default(:port, 2196)
if rails_env == 'production'
configatron.apn.set_default(:host, 'gateway.push.apple.com')
configatron.apn.set_default(:cert, File.join(rails_root, 'config', 'apple_push_notification_production.pem'))
+
+ configatron.apn.feedback.set_default(:host, 'feedback.push.apple.com')
+ configatron.apn.feedback.set_default(:cert, configatron.apn.cert)
+else
+ configatron.apn.set_default(:host, 'gateway.sandbox.push.apple.com')
+ configatron.apn.set_default(:cert, File.join(rails_root, 'config', 'apple_push_notification_development.pem'))
+
+ configatron.apn.feedback.set_default(:host, 'feedback.sandbox.push.apple.com')
+ configatron.apn.feedback.set_default(:cert, configatron.apn.cert)
end
module APN # :nodoc:
View
65 lib/apn_on_rails/app/models/apn/connection.rb
@@ -0,0 +1,65 @@
+module APN
+ module Connection
+
+ class << self
+
+ # Yields up an SSL socket to write notifications to.
+ # The connections are close automatically.
+ #
+ # Example:
+ # APN::Configuration.open_for_delivery do |conn|
+ # conn.write('my cool notification')
+ # end
+ #
+ # Configuration parameters are:
+ #
+ # configatron.apn.passphrase = ''
+ # configatron.apn.port = 2195
+ # configatron.apn.host = 'gateway.sandbox.push.apple.com' # Development
+ # configatron.apn.host = 'gateway.push.apple.com' # Production
+ # configatron.apn.cert = File.join(rails_root, 'config', 'apple_push_notification_development.pem')) # Development
+ # configatron.apn.cert = File.join(rails_root, 'config', 'apple_push_notification_production.pem')) # Production
+ def open_for_delivery(options = {}, &block)
+ open(options, &block)
+ end
+
+ # Yields up an SSL socket to receive feedback from.
+ # The connections are close automatically.
+ # Configuration parameters are:
+ #
+ # configatron.apn.feedback.passphrase = ''
+ # configatron.apn.feedback.port = 2196
+ # configatron.apn.feedback.host = 'feedback.sandbox.push.apple.com' # Development
+ # configatron.apn.feedback.host = 'feedback.push.apple.com' # Production
+ # configatron.apn.feedback.cert = File.join(rails_root, 'config', 'apple_push_notification_development.pem')) # Development
+ # configatron.apn.feedback.cert = File.join(rails_root, 'config', 'apple_push_notification_production.pem')) # Production
+ def open_for_feedback(options = {}, &block) # :nodoc:
+
+ end
+
+ private
+ def open(options = {}, &block) # :nodoc:
+ options = {:cert => configatron.apn.cert,
+ :passphrase => configatron.apn.passphrase,
+ :host => configatron.apn.host,
+ :port => configatron.apn.port}.merge(options)
+ cert = File.read(options[:cert])
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.key = OpenSSL::PKey::RSA.new(cert, options[:passphrase])
+ ctx.cert = OpenSSL::X509::Certificate.new(cert)
+
+ s = TCPSocket.new(options[:host], options[:port])
+ ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
+ ssl.sync = true
+ ssl.connect
+
+ yield ssl if block_given?
+
+ ssl.close
+ s.close
+ end
+
+ end
+
+ end # Connection
+end # APN
View
26 lib/apn_on_rails/app/models/apn/notification.rb
@@ -86,25 +86,15 @@ class << self
# so as to not be sent again.
def send_notifications(notifications = APN::Notification.all(:conditions => {:sent_at => nil}))
unless notifications.nil? || notifications.empty?
- logger.info "APN: Attempting to deliver #{pluralize(notifications.size, 'notification')}."
- cert = File.read(configatron.apn.cert)
- ctx = OpenSSL::SSL::SSLContext.new
- ctx.key = OpenSSL::PKey::RSA.new(cert, configatron.apn.passphrase)
- ctx.cert = OpenSSL::X509::Certificate.new(cert)
-
- s = TCPSocket.new(configatron.apn.host, configatron.apn.port)
- ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
- ssl.sync = true
- ssl.connect
-
- notifications.each do |noty|
- ssl.write(noty.message_for_sending)
- noty.sent_at = Time.now
- noty.save
+
+ APN::Connection.open_for_delivery do |conn|
+ notifications.each do |noty|
+ conn.write(noty.message_for_sending)
+ noty.sent_at = Time.now
+ noty.save
+ end
end
-
- ssl.close
- s.close
+
end
end
View
40 spec/apn_on_rails/app/models/apn/connection_spec.rb
@@ -0,0 +1,40 @@
+require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
+
+describe APN::Connection do
+
+ describe 'open_for_delivery' do
+
+ it 'should create a connection to Apple, yield it, and then close' do
+ rsa_mock = mock('rsa_mock')
+ OpenSSL::PKey::RSA.should_receive(:new).with(apn_cert, '').and_return(rsa_mock)
+
+ cert_mock = mock('cert_mock')
+ OpenSSL::X509::Certificate.should_receive(:new).and_return(cert_mock)
+
+ ctx_mock = mock('ctx_mock')
+ ctx_mock.should_receive(:key=).with(rsa_mock)
+ ctx_mock.should_receive(:cert=).with(cert_mock)
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ctx_mock)
+
+ tcp_mock = mock('tcp_mock')
+ tcp_mock.should_receive(:close)
+ TCPSocket.should_receive(:new).with('gateway.sandbox.push.apple.com', 2195).and_return(tcp_mock)
+
+ ssl_mock = mock('ssl_mock')
+ ssl_mock.should_receive(:sync=).with(true)
+ ssl_mock.should_receive(:connect)
+ ssl_mock.should_receive(:write).with('message-0')
+ ssl_mock.should_receive(:write).with('message-1')
+ ssl_mock.should_receive(:close)
+ OpenSSL::SSL::SSLSocket.should_receive(:new).with(tcp_mock, ctx_mock).and_return(ssl_mock)
+
+ APN::Connection.open_for_delivery do |conn|
+ conn.write('message-0')
+ conn.write('message-1')
+ end
+
+ end
+
+ end
+
+end
View
21 spec/apn_on_rails/app/models/apn/notification_spec.rb
@@ -67,29 +67,10 @@
notify.should_receive(:save)
end
- rsa_mock = mock('rsa_mock')
- OpenSSL::PKey::RSA.should_receive(:new).with(apn_cert, '').and_return(rsa_mock)
-
- cert_mock = mock('cert_mock')
- OpenSSL::X509::Certificate.should_receive(:new).and_return(cert_mock)
-
- ctx_mock = mock('ctx_mock')
- ctx_mock.should_receive(:key=).with(rsa_mock)
- ctx_mock.should_receive(:cert=).with(cert_mock)
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ctx_mock)
-
- # TCPSocket.new(configatron.apn.host, configatron.apn.port)
- tcp_mock = mock('tcp_mock')
- tcp_mock.should_receive(:close)
- TCPSocket.should_receive(:new).with('gateway.sandbox.push.apple.com', 2195).and_return(tcp_mock)
-
ssl_mock = mock('ssl_mock')
- ssl_mock.should_receive(:sync=).with(true)
- ssl_mock.should_receive(:connect)
ssl_mock.should_receive(:write).with('message-0')
ssl_mock.should_receive(:write).with('message-1')
- ssl_mock.should_receive(:close)
- OpenSSL::SSL::SSLSocket.should_receive(:new).with(tcp_mock, ctx_mock).and_return(ssl_mock)
+ APN::Connection.should_receive(:open_for_delivery).and_yield(ssl_mock)
APN::Notification.send_notifications(notifications)

0 comments on commit e6b7afe

Please sign in to comment.
Something went wrong with that request. Please try again.