apn_sender 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +2 -1
- data/VERSION +1 -1
- data/apn_sender.gemspec +4 -3
- data/contrib/apn_sender.monitrc +7 -7
- data/generators/templates/script +0 -1
- data/lib/apn.rb +1 -11
- data/lib/apn/connection/base.rb +12 -6
- data/lib/apn/queue_manager.rb +5 -0
- data/lib/apn/queue_name.rb +4 -0
- data/lib/apn/sender.rb +3 -2
- data/lib/apn/sender_daemon.rb +15 -16
- metadata +25 -13
data/README.rdoc
CHANGED
@@ -30,7 +30,8 @@ where +token+ is the unique identifier of the iPhone to receive the notification
|
|
30
30
|
# :alert #=> The alert to send
|
31
31
|
# :badge #=> The badge number to send
|
32
32
|
# :sound #=> The sound file to play on receipt, or true to play the default sound installed with your app
|
33
|
-
|
33
|
+
|
34
|
+
If any other keys are present they'll be be passed along as custom data to your application.
|
34
35
|
|
35
36
|
=== 2. Sending Queued Messages
|
36
37
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.1
|
data/apn_sender.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{apn_sender}
|
8
|
-
s.version = "1.0.
|
8
|
+
s.version = "1.0.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kali Donovan"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-16}
|
13
13
|
s.description = %q{Resque-based background worker to send Apple Push Notifications over a persistent TCP socket. Includes Resque tweaks to allow persistent sockets between jobs, helper methods for enqueueing APN notifications, and a background daemon to send them.}
|
14
14
|
s.email = %q{kali.donovan@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/apn/notification.rb",
|
35
35
|
"lib/apn/notification_job.rb",
|
36
36
|
"lib/apn/queue_manager.rb",
|
37
|
+
"lib/apn/queue_name.rb",
|
37
38
|
"lib/apn/sender.rb",
|
38
39
|
"lib/apn/sender_daemon.rb",
|
39
40
|
"lib/apn/tasks.rb",
|
@@ -45,7 +46,7 @@ Gem::Specification.new do |s|
|
|
45
46
|
s.homepage = %q{http://github.com/kdonovan/apple_push_notification}
|
46
47
|
s.rdoc_options = ["--charset=UTF-8"]
|
47
48
|
s.require_paths = ["lib"]
|
48
|
-
s.rubygems_version = %q{1.3.
|
49
|
+
s.rubygems_version = %q{1.3.6}
|
49
50
|
s.summary = %q{Resque-based background worker to send Apple Push Notifications over a persistent TCP socket.}
|
50
51
|
s.test_files = [
|
51
52
|
"test/helper.rb",
|
data/contrib/apn_sender.monitrc
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# An example Monit configuration file for running the apn_sender background daemon
|
2
2
|
#
|
3
|
-
# 1. Replace #{app_name} with
|
3
|
+
# 1. Replace #{app_name} with your application name
|
4
4
|
# 2. Add any arguments between apn_sender the and start/stop command
|
5
|
-
# 3. Install as a monitrc file
|
5
|
+
# 3. Install as a monitrc file (paste to bottom of /etc/monit/monitrc, or save as a .monitrc file and include in the main config)
|
6
6
|
|
7
7
|
check process redis
|
8
|
-
with pidfile /
|
8
|
+
with pidfile /var/run/redis.pid
|
9
9
|
group apn_sender
|
10
|
-
start program = "/usr/bin/redis-server /etc/redis.conf"
|
10
|
+
start program = "/usr/bin/redis-server /etc/redis/redis.conf"
|
11
11
|
stop program = "/bin/echo SHUTDOWN | nc localhost 6379"
|
12
12
|
if failed host 127.0.0.1 port 6379 then restart
|
13
13
|
if 5 restarts within 5 cycles then timeout
|
14
14
|
|
15
15
|
|
16
16
|
check process apn_sender
|
17
|
-
with pidfile /var/www
|
17
|
+
with pidfile /var/www/#{app_name}/shared/pids/apn_sender.pid
|
18
18
|
group apn_sender
|
19
|
-
start program = "/
|
20
|
-
stop program = "/
|
19
|
+
start program = "/var/www/#{app_name}/current/script/apn_sender --environment=production --verbose start"
|
20
|
+
stop program = "/var/www/{#app_name}/current/script/apn_sender --environment=production --verbose stop"
|
21
21
|
depends_on redis
|
data/generators/templates/script
CHANGED
data/lib/apn.rb
CHANGED
@@ -3,18 +3,8 @@ require 'resque/plugins/access_worker_from_job'
|
|
3
3
|
require 'resque/hooks/before_unregister_worker'
|
4
4
|
require 'json'
|
5
5
|
|
6
|
+
require 'apn/queue_name'
|
6
7
|
require 'apn/queue_manager'
|
7
|
-
|
8
|
-
module APN
|
9
|
-
# Change this to modify the queue notification jobs are pushed to and pulled from
|
10
|
-
QUEUE_NAME = :apple_push_notifications
|
11
|
-
|
12
|
-
# Enqueues a notification to be sent in the background via the persistent TCP socket, assuming apn_sender is running (or will be soon)
|
13
|
-
def self.notify(token, opts = {})
|
14
|
-
APN::QueueManager.enqueue(APN::NotificationJob, token, opts)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
8
|
require 'apn/notification'
|
19
9
|
require 'apn/notification_job'
|
20
10
|
require 'apn/connection/base'
|
data/lib/apn/connection/base.rb
CHANGED
@@ -52,6 +52,12 @@ module APN
|
|
52
52
|
self.logger.send(level, "#{Time.now}: #{message}")
|
53
53
|
end
|
54
54
|
|
55
|
+
# Log the message first, to ensure it reports what went wrong if in daemon mode. Then die, because something went horribly wrong.
|
56
|
+
def log_and_die(msg)
|
57
|
+
log(:fatal, msg)
|
58
|
+
raise msg
|
59
|
+
end
|
60
|
+
|
55
61
|
def apn_production?
|
56
62
|
@opts[:environment] && @opts[:environment] != '' && :production == @opts[:environment].to_sym
|
57
63
|
end
|
@@ -62,19 +68,20 @@ module APN
|
|
62
68
|
@opts[:cert_path] ||= File.join(File.expand_path(RAILS_ROOT), "config", "certs") if defined?(RAILS_ROOT)
|
63
69
|
@opts[:environment] ||= RAILS_ENV if defined?(RAILS_ENV)
|
64
70
|
|
65
|
-
|
71
|
+
log_and_die("Missing certificate path. Please specify :cert_path when initializing class.") unless @opts[:cert_path]
|
72
|
+
|
66
73
|
cert_name = apn_production? ? "apn_production.pem" : "apn_development.pem"
|
67
74
|
cert_path = File.join(@opts[:cert_path], cert_name)
|
68
75
|
|
69
76
|
@apn_cert = File.exists?(cert_path) ? File.read(cert_path) : nil
|
70
|
-
|
77
|
+
log_and_die("Missing apple push notification certificate in #{cert_path}") unless @apn_cert
|
71
78
|
end
|
72
79
|
|
73
80
|
# Open socket to Apple's servers
|
74
81
|
def setup_connection
|
75
|
-
|
82
|
+
log_and_die("Missing apple push notification certificate") unless @apn_cert
|
76
83
|
return true if @socket && @socket_tcp
|
77
|
-
|
84
|
+
log_and_die("Trying to open half-open connection") if @socket || @socket_tcp
|
78
85
|
|
79
86
|
ctx = OpenSSL::SSL::SSLContext.new
|
80
87
|
ctx.cert = OpenSSL::X509::Certificate.new(@apn_cert)
|
@@ -85,8 +92,7 @@ module APN
|
|
85
92
|
@socket.sync = true
|
86
93
|
@socket.connect
|
87
94
|
rescue SocketError => error
|
88
|
-
|
89
|
-
raise "Error with connection to #{apn_host}: #{error}"
|
95
|
+
log_and_die("Error with connection to #{apn_host}: #{error}")
|
90
96
|
end
|
91
97
|
|
92
98
|
# Close open sockets
|
data/lib/apn/queue_manager.rb
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
# example implementation
|
4
4
|
|
5
5
|
module APN
|
6
|
+
# Enqueues a notification to be sent in the background via the persistent TCP socket, assuming apn_sender is running (or will be soon)
|
7
|
+
def self.notify(token, opts = {})
|
8
|
+
APN::QueueManager.enqueue(APN::NotificationJob, token, opts)
|
9
|
+
end
|
10
|
+
|
6
11
|
# Extends Resque, allowing us to add all the callbacks to Resque we desire without affecting the expected
|
7
12
|
# functionality in the parent app, if we're included in e.g. a Rails application.
|
8
13
|
class QueueManager
|
data/lib/apn/sender.rb
CHANGED
@@ -19,7 +19,7 @@ module APN
|
|
19
19
|
# Send a raw string over the socket to Apple's servers (presumably already formatted by APN::Notification)
|
20
20
|
def send_to_apple( notification, attempt = 0 )
|
21
21
|
if attempt > TIMES_TO_RETRY_SOCKET_ERROR
|
22
|
-
|
22
|
+
log_and_die("Error with connection to #{apn_host} (retried #{TIMES_TO_RETRY_SOCKET_ERROR} times): #{error}")
|
23
23
|
end
|
24
24
|
|
25
25
|
self.socket.write( notification.to_s )
|
@@ -73,4 +73,5 @@ worker.work(5)
|
|
73
73
|
args = ['--environment=production', '--cert-path=/Users/kali/Code/insurrection/certs/']
|
74
74
|
APN::SenderDaemon.new(args).daemonize
|
75
75
|
|
76
|
-
|
76
|
+
# To run daemonized version in Rails app
|
77
|
+
./script/apn_sender --environment=production start
|
data/lib/apn/sender_daemon.rb
CHANGED
@@ -1,18 +1,24 @@
|
|
1
|
-
#
|
1
|
+
# Based roughly on delayed_job's delayed/command.rb
|
2
2
|
require 'rubygems'
|
3
3
|
require 'daemons'
|
4
4
|
require 'optparse'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
require 'apn/queue_name'
|
8
|
+
require 'apn/connection/base'
|
9
|
+
require 'apn/sender'
|
5
10
|
|
6
11
|
module APN
|
7
12
|
# A wrapper designed to daemonize an APN::Sender instance to keep in running in the background.
|
8
|
-
# Connects worker's output to
|
13
|
+
# Connects worker's output to a custom logger, if available. Creates a pid file suitable for
|
9
14
|
# monitoring with {monit}[http://mmonit.com/monit/].
|
10
15
|
#
|
11
|
-
# Based off delayed_job's great example
|
16
|
+
# Based off delayed_job's great example, except we can be much lighter by not loading the entire
|
17
|
+
# Rails environment. To use in a Rails app, <code>script/generate apn_sender</code>.
|
12
18
|
class SenderDaemon
|
13
19
|
|
14
20
|
def initialize(args)
|
15
|
-
@options = {:
|
21
|
+
@options = {:worker_count => 1, :environment => :development, :delay => 5}
|
16
22
|
|
17
23
|
optparse = OptionParser.new do |opts|
|
18
24
|
opts.banner = "Usage: #{File.basename($0)} [options] start|stop|restart|run"
|
@@ -24,16 +30,16 @@ module APN
|
|
24
30
|
opts.on('-e', '--environment=NAME', 'Specifies the environment to run this apn_sender under ([development]/production).') do |e|
|
25
31
|
@options[:environment] = e
|
26
32
|
end
|
27
|
-
opts.on('--cert-path=NAME', '
|
33
|
+
opts.on('--cert-path=NAME', 'Path to directory containing apn .pem certificates.') do |path|
|
28
34
|
@options[:cert_path] = path
|
29
35
|
end
|
30
|
-
opts.on('-n', '--
|
36
|
+
opts.on('-n', '--number-of-workers=WORKERS', "Number of unique workers to spawn") do |worker_count|
|
31
37
|
@options[:worker_count] = worker_count.to_i rescue 1
|
32
38
|
end
|
33
39
|
opts.on('-v', '--verbose', "Turn on verbose mode") do
|
34
40
|
@options[:verbose] = true
|
35
41
|
end
|
36
|
-
opts.on('-V', '--
|
42
|
+
opts.on('-V', '--very-verbose', "Turn on very verbose mode") do
|
37
43
|
@options[:very_verbose] = true
|
38
44
|
end
|
39
45
|
opts.on('-d', '--delay=D', "Delay between rounds of work (seconds)") do |d|
|
@@ -56,14 +62,7 @@ module APN
|
|
56
62
|
end
|
57
63
|
|
58
64
|
def run(worker_name = nil)
|
59
|
-
Dir.chdir(::RAILS_ROOT)
|
60
|
-
require File.join(::RAILS_ROOT, 'config', 'environment')
|
61
|
-
|
62
|
-
# Replace the default logger
|
63
65
|
logger = Logger.new(File.join(::RAILS_ROOT, 'log', 'apn_sender.log'))
|
64
|
-
logger.level = ActiveRecord::Base.logger.level
|
65
|
-
ActiveRecord::Base.logger = logger
|
66
|
-
ActiveRecord::Base.clear_active_connections!
|
67
66
|
|
68
67
|
worker = APN::Sender.new(@options)
|
69
68
|
worker.logger = logger
|
@@ -71,10 +70,10 @@ module APN
|
|
71
70
|
worker.very_verbose = @options[:very_verbose]
|
72
71
|
worker.work(@options[:delay])
|
73
72
|
rescue => e
|
74
|
-
logger.fatal(e) if logger.respond_to?(:fatal)
|
75
73
|
STDERR.puts e.message
|
74
|
+
logger.fatal(e) if logger && logger.respond_to?(:fatal)
|
76
75
|
exit 1
|
77
76
|
end
|
78
77
|
|
79
78
|
end
|
80
|
-
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apn_sender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 1.0.1
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Kali Donovan
|
@@ -9,29 +14,33 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-16 00:00:00 -07:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: resque
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
23
29
|
version: "0"
|
24
|
-
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
25
32
|
- !ruby/object:Gem::Dependency
|
26
33
|
name: resque-access_worker_from_job
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - ">="
|
32
38
|
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
33
41
|
version: "0"
|
34
|
-
|
42
|
+
type: :runtime
|
43
|
+
version_requirements: *id002
|
35
44
|
description: Resque-based background worker to send Apple Push Notifications over a persistent TCP socket. Includes Resque tweaks to allow persistent sockets between jobs, helper methods for enqueueing APN notifications, and a background daemon to send them.
|
36
45
|
email: kali.donovan@gmail.com
|
37
46
|
executables: []
|
@@ -59,6 +68,7 @@ files:
|
|
59
68
|
- lib/apn/notification.rb
|
60
69
|
- lib/apn/notification_job.rb
|
61
70
|
- lib/apn/queue_manager.rb
|
71
|
+
- lib/apn/queue_name.rb
|
62
72
|
- lib/apn/sender.rb
|
63
73
|
- lib/apn/sender_daemon.rb
|
64
74
|
- lib/apn/tasks.rb
|
@@ -79,18 +89,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
89
|
requirements:
|
80
90
|
- - ">="
|
81
91
|
- !ruby/object:Gem::Version
|
92
|
+
segments:
|
93
|
+
- 0
|
82
94
|
version: "0"
|
83
|
-
version:
|
84
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
96
|
requirements:
|
86
97
|
- - ">="
|
87
98
|
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
88
101
|
version: "0"
|
89
|
-
version:
|
90
102
|
requirements: []
|
91
103
|
|
92
104
|
rubyforge_project:
|
93
|
-
rubygems_version: 1.3.
|
105
|
+
rubygems_version: 1.3.6
|
94
106
|
signing_key:
|
95
107
|
specification_version: 3
|
96
108
|
summary: Resque-based background worker to send Apple Push Notifications over a persistent TCP socket.
|