rapns 3.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +31 -0
- data/LICENSE +7 -0
- data/README.md +138 -0
- data/bin/rapns +41 -0
- data/config/database.yml +39 -0
- data/lib/generators/rapns_generator.rb +34 -0
- data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
- data/lib/generators/templates/add_app_to_rapns.rb +11 -0
- data/lib/generators/templates/add_gcm.rb +94 -0
- data/lib/generators/templates/create_rapns_apps.rb +16 -0
- data/lib/generators/templates/create_rapns_feedback.rb +15 -0
- data/lib/generators/templates/create_rapns_notifications.rb +26 -0
- data/lib/generators/templates/rapns.rb +39 -0
- data/lib/rapns/apns/app.rb +8 -0
- data/lib/rapns/apns/binary_notification_validator.rb +12 -0
- data/lib/rapns/apns/device_token_format_validator.rb +12 -0
- data/lib/rapns/apns/feedback.rb +14 -0
- data/lib/rapns/apns/notification.rb +86 -0
- data/lib/rapns/apns/required_fields_validator.rb +14 -0
- data/lib/rapns/app.rb +29 -0
- data/lib/rapns/configuration.rb +46 -0
- data/lib/rapns/daemon/apns/app_runner.rb +36 -0
- data/lib/rapns/daemon/apns/connection.rb +113 -0
- data/lib/rapns/daemon/apns/delivery.rb +63 -0
- data/lib/rapns/daemon/apns/delivery_handler.rb +21 -0
- data/lib/rapns/daemon/apns/disconnection_error.rb +20 -0
- data/lib/rapns/daemon/apns/feedback_receiver.rb +74 -0
- data/lib/rapns/daemon/app_runner.rb +135 -0
- data/lib/rapns/daemon/database_reconnectable.rb +57 -0
- data/lib/rapns/daemon/delivery.rb +43 -0
- data/lib/rapns/daemon/delivery_error.rb +19 -0
- data/lib/rapns/daemon/delivery_handler.rb +46 -0
- data/lib/rapns/daemon/delivery_queue.rb +42 -0
- data/lib/rapns/daemon/delivery_queue_18.rb +44 -0
- data/lib/rapns/daemon/delivery_queue_19.rb +42 -0
- data/lib/rapns/daemon/feeder.rb +37 -0
- data/lib/rapns/daemon/gcm/app_runner.rb +13 -0
- data/lib/rapns/daemon/gcm/delivery.rb +206 -0
- data/lib/rapns/daemon/gcm/delivery_handler.rb +20 -0
- data/lib/rapns/daemon/interruptible_sleep.rb +18 -0
- data/lib/rapns/daemon/logger.rb +68 -0
- data/lib/rapns/daemon.rb +136 -0
- data/lib/rapns/gcm/app.rb +7 -0
- data/lib/rapns/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +11 -0
- data/lib/rapns/gcm/notification.rb +31 -0
- data/lib/rapns/gcm/payload_size_validator.rb +13 -0
- data/lib/rapns/multi_json_helper.rb +16 -0
- data/lib/rapns/notification.rb +54 -0
- data/lib/rapns/patches/rails/3.1.0/postgresql_adapter.rb +12 -0
- data/lib/rapns/patches/rails/3.1.1/postgresql_adapter.rb +17 -0
- data/lib/rapns/patches.rb +6 -0
- data/lib/rapns/version.rb +3 -0
- data/lib/rapns.rb +21 -0
- data/lib/tasks/cane.rake +18 -0
- data/lib/tasks/test.rake +33 -0
- data/spec/acceptance/gcm_upgrade_spec.rb +34 -0
- data/spec/acceptance_spec_helper.rb +85 -0
- data/spec/support/simplecov_helper.rb +13 -0
- data/spec/support/simplecov_quality_formatter.rb +8 -0
- data/spec/unit/apns/app_spec.rb +15 -0
- data/spec/unit/apns/feedback_spec.rb +12 -0
- data/spec/unit/apns/notification_spec.rb +198 -0
- data/spec/unit/app_spec.rb +18 -0
- data/spec/unit/configuration_spec.rb +38 -0
- data/spec/unit/daemon/apns/app_runner_spec.rb +39 -0
- data/spec/unit/daemon/apns/connection_spec.rb +234 -0
- data/spec/unit/daemon/apns/delivery_handler_spec.rb +48 -0
- data/spec/unit/daemon/apns/delivery_spec.rb +160 -0
- data/spec/unit/daemon/apns/disconnection_error_spec.rb +18 -0
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +118 -0
- data/spec/unit/daemon/app_runner_shared.rb +66 -0
- data/spec/unit/daemon/app_runner_spec.rb +129 -0
- data/spec/unit/daemon/database_reconnectable_spec.rb +109 -0
- data/spec/unit/daemon/delivery_error_spec.rb +13 -0
- data/spec/unit/daemon/delivery_handler_shared.rb +28 -0
- data/spec/unit/daemon/delivery_queue_spec.rb +29 -0
- data/spec/unit/daemon/feeder_spec.rb +95 -0
- data/spec/unit/daemon/gcm/app_runner_spec.rb +17 -0
- data/spec/unit/daemon/gcm/delivery_handler_spec.rb +36 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +236 -0
- data/spec/unit/daemon/interruptible_sleep_spec.rb +40 -0
- data/spec/unit/daemon/logger_spec.rb +156 -0
- data/spec/unit/daemon_spec.rb +139 -0
- data/spec/unit/gcm/app_spec.rb +5 -0
- data/spec/unit/gcm/notification_spec.rb +55 -0
- data/spec/unit/notification_shared.rb +38 -0
- data/spec/unit/notification_spec.rb +6 -0
- data/spec/unit_spec_helper.rb +145 -0
- metadata +240 -0
data/CHANGELOG.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
## 2.0.5 (Nov 4, 2012) ##
|
2
|
+
* Support content-available (#68).
|
3
|
+
* Append to log files.
|
4
|
+
* Fire a callback when Feedback is received.
|
5
|
+
|
6
|
+
## 2.0.5.rc1 (Oct 5, 2012) ##
|
7
|
+
* Release db connections back into the pool after use (#72).
|
8
|
+
* Continue to start daemon if a connection cannot be made during startup (#62) (@mattconnolly).
|
9
|
+
|
10
|
+
## 2.0.4 (Aug 6, 2012) ##
|
11
|
+
* Don't exit when there aren't any Rapns::App instances, just warn (#55).
|
12
|
+
|
13
|
+
## 2.0.3 (July 26, 2012) ##
|
14
|
+
* JRuby support.
|
15
|
+
* Explicitly list all attributes instead of calling column_names (#53).
|
16
|
+
|
17
|
+
## 2.0.2 (July 25, 2012) ##
|
18
|
+
* Support MultiJson < 1.3.0.
|
19
|
+
* Make all model attributes accessible.
|
20
|
+
|
21
|
+
## 2.0.1 (July 7, 2012) ##
|
22
|
+
* Fix delivery when using Ruby 1.8.
|
23
|
+
* MultiJson support.
|
24
|
+
|
25
|
+
## 2.0.0 (June 19, 2012) ##
|
26
|
+
|
27
|
+
* Support for multiple apps.
|
28
|
+
* Hot Updates - add/remove apps without restart.
|
29
|
+
* MDM support.
|
30
|
+
* Removed rapns.yml in favour of command line options.
|
31
|
+
* Started the changelog!
|
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2012 Ian Leitch
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/ileitch/rapns.png?branch=master)](http://travis-ci.org/ileitch/rapns)
|
2
|
+
|
3
|
+
### Rapns - Professional grade APNs and GCM daemon
|
4
|
+
|
5
|
+
* Supports both APNs (iOS) and GCM (Google Cloud Messaging, Android).
|
6
|
+
* Seamless Rails integration.
|
7
|
+
* Scalable - choose the number of threads each app spawns.
|
8
|
+
* Designed for uptime - signal -HUP to add, update apps.
|
9
|
+
* Stable - reconnects database and network connections when lost.
|
10
|
+
* Works with MRI, JRuby, Rubinius 1.8 and 1.9.
|
11
|
+
* [Airbrake](http://airbrakeapp.com/) integration.
|
12
|
+
|
13
|
+
### Who uses Rapns?
|
14
|
+
|
15
|
+
[GateGuru](http://gateguruapp.com) and [Desk.com](http://desk.com), among others!
|
16
|
+
|
17
|
+
*I'd love to hear if you use Rapns - @ileitch on twitter.*
|
18
|
+
|
19
|
+
## Getting Started
|
20
|
+
|
21
|
+
Add Rapns to your Gemfile:
|
22
|
+
|
23
|
+
gem 'rapns'
|
24
|
+
|
25
|
+
Generate the migration, rapns.yml and migrate:
|
26
|
+
|
27
|
+
rails g rapns
|
28
|
+
rake db:migrate
|
29
|
+
|
30
|
+
## Generating Certificates
|
31
|
+
|
32
|
+
1. Open up Keychain Access and select the `Certificates` category in the sidebar.
|
33
|
+
2. Expand the disclosure arrow next to the iOS Push Services certificate you want to export.
|
34
|
+
3. Select both the certificate and private key.
|
35
|
+
4. Right click and select `Export 2 items...`.
|
36
|
+
5. Save the file as `cert.p12`, make sure the File Format is `Personal Information Exchange (p12)`.
|
37
|
+
6. If you decide to set a password for your exported certificate, please read the 'Adding Apps' section below.
|
38
|
+
7. Convert the certificate to a .pem, where `<environment>` should be `development` or `production`, depending on the certificate you exported.
|
39
|
+
|
40
|
+
`openssl pkcs12 -nodes -clcerts -in cert.p12 -out <environment>.pem`
|
41
|
+
|
42
|
+
## Create an App
|
43
|
+
|
44
|
+
#### APNs
|
45
|
+
```ruby
|
46
|
+
app = Rapns::Apns::App.new
|
47
|
+
app.name = "ios_app"
|
48
|
+
app.certificate = File.read("/path/to/development.pem")
|
49
|
+
app.environment = "development"
|
50
|
+
app.password = "certificate password"
|
51
|
+
app.connections = 1
|
52
|
+
app.save!
|
53
|
+
```
|
54
|
+
|
55
|
+
#### GCM
|
56
|
+
```ruby
|
57
|
+
app = Rapns::Gcm::App.new
|
58
|
+
app.name = "android_app"
|
59
|
+
app.auth_key = "..."
|
60
|
+
app.connections = 1
|
61
|
+
app.save!
|
62
|
+
```
|
63
|
+
|
64
|
+
## Create a Notification
|
65
|
+
|
66
|
+
#### APNs
|
67
|
+
```ruby
|
68
|
+
n = Rapns::Apns::Notification.new
|
69
|
+
n.app = Rapns::Apns::App.find_by_name("ios_app")
|
70
|
+
n.device_token = "..."
|
71
|
+
n.alert = "hi mom!"
|
72
|
+
n.attributes_for_device = {:foo => :bar}
|
73
|
+
n.save!
|
74
|
+
```
|
75
|
+
|
76
|
+
#### GCM
|
77
|
+
```ruby
|
78
|
+
n = Rapns::Gcm::Notification.new
|
79
|
+
n.app = Rapns::Gcm::App.find_by_name("android_app")
|
80
|
+
n.registration_ids = ["..."]
|
81
|
+
n.data = {:message => "hi mom!"}
|
82
|
+
n.save!
|
83
|
+
```
|
84
|
+
|
85
|
+
## Starting Rapns
|
86
|
+
|
87
|
+
cd /path/to/rails/app
|
88
|
+
rapns <Rails environment> [options]
|
89
|
+
|
90
|
+
See [Configuration](wiki/Configuration) for a list of options, or run `rapns --help`.
|
91
|
+
|
92
|
+
## Updating Rapns
|
93
|
+
|
94
|
+
After updating you should run `rails g rapns` to check for any new migrations.
|
95
|
+
|
96
|
+
## Wiki
|
97
|
+
|
98
|
+
### General
|
99
|
+
* [Configuration](wiki/Configuration)
|
100
|
+
* [Upgrading from 2.x to 3.0](wiki/Upgrading-from-version-2.x-to-3.0)
|
101
|
+
* [Deploying to Heroku](wiki/Heroku)
|
102
|
+
* [Hot App Updates](wiki/Hot-App-Updates)
|
103
|
+
|
104
|
+
### APNs
|
105
|
+
* [Advanced APNs Features](wiki/Advanced-APNs-Features)
|
106
|
+
* [APNs Delivery Failure Handling](wiki/APNs-Delivery-Failure-Handling)
|
107
|
+
* [Why open multiple connections to the APNs?](wiki/Why-open-multiple-connections-to-the-APNs%3F)
|
108
|
+
* [Silent failures might be dropped connections](wiki/Dropped-connections)
|
109
|
+
|
110
|
+
### GCM
|
111
|
+
|
112
|
+
## Contributing
|
113
|
+
|
114
|
+
Fork as usual and go crazy!
|
115
|
+
|
116
|
+
When running specs, please note that the ActiveRecord adapter can be changed by setting the `ADAPTER` environment variable. For example: `ADAPTER=postgresql rake`.
|
117
|
+
|
118
|
+
Available adapters for testing are `mysql`, `mysql2` and `postgresql`.
|
119
|
+
|
120
|
+
Note that the database username is changed at runtime to be the currently logged in user's name. So if you're testing
|
121
|
+
with mysql and you're using a user named 'bob', you will need to grant a mysql user 'bob' access to the 'rapns_test'
|
122
|
+
mysql database.
|
123
|
+
|
124
|
+
### Contributors
|
125
|
+
|
126
|
+
Thank you to the following wonderful people for contributing:
|
127
|
+
|
128
|
+
* [@blakewatters](https://github.com/blakewatters)
|
129
|
+
* [@forresty](https://github.com/forresty)
|
130
|
+
* [@sjmadsen](https://github.com/sjmadsen)
|
131
|
+
* [@ivanyv](https://github.com/ivanyv)
|
132
|
+
* [@taybenlor](https://github.com/taybenlor)
|
133
|
+
* [@tompesman](https://github.com/tompesman)
|
134
|
+
* [@EpicDraws](https://github.com/EpicDraws)
|
135
|
+
* [@dei79](https://github.com/dei79)
|
136
|
+
* [@adorr](https://github.com/adorr)
|
137
|
+
* [@mattconnolly](https://github.com/mattconnolly)
|
138
|
+
* [@emeitch](https://github.com/emeitch)
|
data/bin/rapns
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'rapns'
|
5
|
+
|
6
|
+
environment = ARGV[0]
|
7
|
+
|
8
|
+
banner = 'Usage: rapns <Rails environment> [options]'
|
9
|
+
if environment.nil? || environment =~ /^-/
|
10
|
+
puts banner
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
# A mock configuration to be used before the Rails environment is loaded.
|
15
|
+
class CommandlineConfig < Struct.new(*Rapns::CONFIG_ATTRS); end
|
16
|
+
config = CommandlineConfig.new
|
17
|
+
|
18
|
+
ARGV.options do |opts|
|
19
|
+
opts.banner = banner
|
20
|
+
opts.on('-f', '--foreground', 'Run in the foreground.') { config.foreground = true }
|
21
|
+
opts.on('-P N', '--db-poll N', Integer, "Frequency in seconds to check for new notifications. Default: #{config.push_poll}.") { |n| config.push_poll = n }
|
22
|
+
opts.on('-F N', '--feedback-poll N', Integer, "Frequency in seconds to check for feedback. Default: #{config.feedback_poll}.") { |n| config.feedback_poll = n }
|
23
|
+
opts.on('-e', '--no-error-checks', 'Disable APNs error checking after notification delivery.') { config.check_for_errors = false }
|
24
|
+
opts.on('-n', '--no-airbrake-notify', 'Disables error notifications via Airbrake.') { config.airbrake_notify = false }
|
25
|
+
opts.on('-p PATH', '--pid-file PATH', String, 'Path to write PID file. Relative to Rails root unless absolute.') { |path| config.pid_file = path }
|
26
|
+
opts.on('-b N', '--batch-size N', Integer, 'ActiveRecord notifications batch size.') { |n| config.batch_size = n }
|
27
|
+
opts.on('-v', '--version', 'Print this version of rapns.') { puts "rapns #{Rapns::VERSION}"; exit }
|
28
|
+
opts.on('-h', '--help', 'You\'re looking at it.') { puts opts; exit }
|
29
|
+
opts.parse!
|
30
|
+
end
|
31
|
+
|
32
|
+
ENV['RAILS_ENV'] = environment
|
33
|
+
load 'config/environment.rb'
|
34
|
+
load 'config/initializers/rapns.rb' if File.exist?('config/initializers/rapns.rb')
|
35
|
+
|
36
|
+
Rapns.config.update(config)
|
37
|
+
|
38
|
+
require 'rapns/daemon'
|
39
|
+
require 'rapns/patches'
|
40
|
+
|
41
|
+
Rapns::Daemon.start
|
data/config/database.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# postgresql is the default if no ADAPTER environment variable is set when running specs.
|
2
|
+
|
3
|
+
postgresql:
|
4
|
+
adapter: postgresql
|
5
|
+
database: rapns_test
|
6
|
+
host: localhost
|
7
|
+
username: postgres
|
8
|
+
password: ""
|
9
|
+
|
10
|
+
jdbcpostgresql:
|
11
|
+
adapter: jdbcpostgresql
|
12
|
+
database: rapns_test
|
13
|
+
host: localhost
|
14
|
+
username: postgres
|
15
|
+
password: ""
|
16
|
+
|
17
|
+
mysql:
|
18
|
+
adapter: mysql
|
19
|
+
database: rapns_test
|
20
|
+
host: localhost
|
21
|
+
username: rapns_test
|
22
|
+
password: ""
|
23
|
+
encoding: utf8
|
24
|
+
|
25
|
+
mysql2:
|
26
|
+
adapter: mysql
|
27
|
+
database: rapns_test
|
28
|
+
host: localhost
|
29
|
+
username: rapns_test
|
30
|
+
password: ""
|
31
|
+
encoding: utf8
|
32
|
+
|
33
|
+
jdbcmysql:
|
34
|
+
adapter: jdbcmysql
|
35
|
+
database: rapns_test
|
36
|
+
host: localhost
|
37
|
+
username: rapns_test
|
38
|
+
password: ""
|
39
|
+
encoding: utf8
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class RapnsGenerator < Rails::Generators::Base
|
2
|
+
include Rails::Generators::Migration
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
def self.next_migration_number(path)
|
6
|
+
@time ||= Time.now.utc
|
7
|
+
@calls ||= -1
|
8
|
+
@calls += 1
|
9
|
+
(@time + @calls.seconds).strftime("%Y%m%d%H%M%S")
|
10
|
+
end
|
11
|
+
|
12
|
+
def copy_migration
|
13
|
+
add_rapns_migration('create_rapns_notifications')
|
14
|
+
add_rapns_migration('create_rapns_feedback')
|
15
|
+
add_rapns_migration('add_alert_is_json_to_rapns_notifications')
|
16
|
+
add_rapns_migration('add_app_to_rapns')
|
17
|
+
add_rapns_migration('create_rapns_apps')
|
18
|
+
add_rapns_migration('add_gcm')
|
19
|
+
end
|
20
|
+
|
21
|
+
def copy_config
|
22
|
+
copy_file 'rapns.rb', 'config/initializers/rapns.rb'
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def add_rapns_migration(template)
|
28
|
+
migration_dir = File.expand_path('db/migrate')
|
29
|
+
|
30
|
+
if !self.class.migration_exists?(migration_dir, template)
|
31
|
+
migration_template "#{template}.rb", "db/migrate/#{template}.rb"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddAppToRapns < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :rapns_notifications, :app, :string, :null => true
|
4
|
+
add_column :rapns_feedback, :app, :string, :null => true
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.down
|
8
|
+
remove_column :rapns_notifications, :app
|
9
|
+
remove_column :rapns_feedback, :app
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class AddGcm < ActiveRecord::Migration
|
2
|
+
module Rapns
|
3
|
+
class App < ActiveRecord::Base
|
4
|
+
self.table_name = 'rapns_apps'
|
5
|
+
end
|
6
|
+
|
7
|
+
class Notification < ActiveRecord::Base
|
8
|
+
belongs_to :app
|
9
|
+
self.table_name = 'rapns_notifications'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.up
|
14
|
+
add_column :rapns_notifications, :type, :string, :null => true
|
15
|
+
add_column :rapns_apps, :type, :string, :null => true
|
16
|
+
|
17
|
+
AddGcm::Rapns::Notification.update_all :type => 'Rapns::Apns::Notification'
|
18
|
+
AddGcm::Rapns::App.update_all :type => 'Rapns::Apns::App'
|
19
|
+
|
20
|
+
change_column_null :rapns_notifications, :type, false
|
21
|
+
change_column_null :rapns_apps, :type, false
|
22
|
+
change_column_null :rapns_notifications, :device_token, true
|
23
|
+
change_column_null :rapns_notifications, :expiry, true
|
24
|
+
change_column_null :rapns_apps, :environment, true
|
25
|
+
change_column_null :rapns_apps, :certificate, true
|
26
|
+
|
27
|
+
change_column :rapns_notifications, :error_description, :text
|
28
|
+
change_column :rapns_notifications, :sound, :string, :default => 'default'
|
29
|
+
|
30
|
+
rename_column :rapns_notifications, :attributes_for_device, :data
|
31
|
+
rename_column :rapns_apps, :key, :name
|
32
|
+
|
33
|
+
add_column :rapns_apps, :auth_key, :string, :null => true
|
34
|
+
|
35
|
+
add_column :rapns_notifications, :collapse_key, :string, :null => true
|
36
|
+
add_column :rapns_notifications, :delay_while_idle, :boolean, :null => false, :default => false
|
37
|
+
add_column :rapns_notifications, :registration_ids, :text, :null => true
|
38
|
+
add_column :rapns_notifications, :app_id, :integer, :null => true
|
39
|
+
add_column :rapns_notifications, :retries, :integer, :null => true, :default => 0
|
40
|
+
|
41
|
+
Rapns::Notification.reset_column_information
|
42
|
+
Rapns::App.reset_column_information
|
43
|
+
|
44
|
+
Rapns::App.all.each do |app|
|
45
|
+
Rapns::Notification.update_all(['app_id = ?', app.id], ['app = ?', app.name])
|
46
|
+
end
|
47
|
+
|
48
|
+
change_column_null :rapns_notifications, :app_id, false
|
49
|
+
remove_column :rapns_notifications, :app
|
50
|
+
|
51
|
+
remove_index :rapns_notifications, :name => "index_rapns_notifications_multi"
|
52
|
+
add_index :rapns_notifications, [:app_id, :delivered, :failed, :deliver_after], :name => "index_rapns_notifications_multi"
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.down
|
56
|
+
AddGcm::Rapns::Notification.where(:type => 'Rapns::Gcm::Notification').delete_all
|
57
|
+
|
58
|
+
remove_column :rapns_notifications, :type
|
59
|
+
remove_column :rapns_apps, :type
|
60
|
+
|
61
|
+
change_column_null :rapns_notifications, :device_token, false
|
62
|
+
change_column_null :rapns_notifications, :expiry, false
|
63
|
+
change_column_null :rapns_apps, :environment, false
|
64
|
+
change_column_null :rapns_apps, :certificate, false
|
65
|
+
|
66
|
+
change_column :rapns_notifications, :error_description, :string
|
67
|
+
change_column :rapns_notifications, :sound, :string, :default => '1.aiff'
|
68
|
+
|
69
|
+
rename_column :rapns_notifications, :data, :attributes_for_device
|
70
|
+
rename_column :rapns_apps, :name, :key
|
71
|
+
|
72
|
+
remove_column :rapns_apps, :auth_key
|
73
|
+
|
74
|
+
remove_column :rapns_notifications, :collapse_key
|
75
|
+
remove_column :rapns_notifications, :delay_while_idle
|
76
|
+
remove_column :rapns_notifications, :registration_ids
|
77
|
+
remove_column :rapns_notifications, :retries
|
78
|
+
|
79
|
+
add_column :rapns_notifications, :app, :string, :null => true
|
80
|
+
|
81
|
+
Rapns::Notification.reset_column_information
|
82
|
+
Rapns::App.reset_column_information
|
83
|
+
|
84
|
+
Rapns::App.all.each do |app|
|
85
|
+
Rapns::Notification.update_all(['app = ?', app.key], ['app_id = ?', app.id])
|
86
|
+
end
|
87
|
+
|
88
|
+
change_column_null :rapns_notifications, :key, false
|
89
|
+
remove_column :rapns_notifications, :app_id
|
90
|
+
|
91
|
+
remove_index :rapns_notifications, :name => "index_rapns_notifications_multi"
|
92
|
+
add_index :rapns_notifications, [:delivered, :failed, :deliver_after], :name => "index_rapns_notifications_multi"
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateRapnsApps < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :rapns_apps do |t|
|
4
|
+
t.string :key, :null => false
|
5
|
+
t.string :environment, :null => false
|
6
|
+
t.text :certificate, :null => false
|
7
|
+
t.string :password, :null => true
|
8
|
+
t.integer :connections, :null => false, :default => 1
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :rapns_apps
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateRapnsFeedback < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :rapns_feedback do |t|
|
4
|
+
t.string :device_token, :null => false, :limit => 64
|
5
|
+
t.timestamp :failed_at, :null => false
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :rapns_feedback, :device_token
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table :rapns_feedback
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreateRapnsNotifications < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :rapns_notifications do |t|
|
4
|
+
t.integer :badge, :null => true
|
5
|
+
t.string :device_token, :null => false, :limit => 64
|
6
|
+
t.string :sound, :null => true, :default => "1.aiff"
|
7
|
+
t.string :alert, :null => true
|
8
|
+
t.text :attributes_for_device, :null => true
|
9
|
+
t.integer :expiry, :null => false, :default => 1.day.to_i
|
10
|
+
t.boolean :delivered, :null => false, :default => false
|
11
|
+
t.timestamp :delivered_at, :null => true
|
12
|
+
t.boolean :failed, :null => false, :default => false
|
13
|
+
t.timestamp :failed_at, :null => true
|
14
|
+
t.integer :error_code, :null => true
|
15
|
+
t.string :error_description, :null => true
|
16
|
+
t.timestamp :deliver_after, :null => true
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :rapns_notifications, [:delivered, :failed, :deliver_after], :name => "index_rapns_notifications_multi"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.down
|
24
|
+
drop_table :rapns_notifications
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Rapns configuration. Options set here are overridden by command-line options.
|
2
|
+
|
3
|
+
Rapns.configure do |config|
|
4
|
+
|
5
|
+
# Run in the foreground?
|
6
|
+
# config.foreground = false
|
7
|
+
|
8
|
+
# Frequency in seconds to check for new notifications.
|
9
|
+
# config.push_poll = 2
|
10
|
+
|
11
|
+
# Frequency in seconds to check for feedback
|
12
|
+
# config.feedback_poll = 60
|
13
|
+
|
14
|
+
# Enable/Disable error notifications via Airbrake.
|
15
|
+
# config.airbrake_notify = true
|
16
|
+
|
17
|
+
# Disable APNs error checking after notification delivery.
|
18
|
+
# config.check_for_errors = true
|
19
|
+
|
20
|
+
# ActiveRecord notifications batch size.
|
21
|
+
# config.batch_size = 5000
|
22
|
+
|
23
|
+
# Path to write PID file. Relative to Rails root unless absolute.
|
24
|
+
# config.pid_file = '/path/to/rapns.pid'
|
25
|
+
|
26
|
+
# Define a block that will be called with a Rapns::Apns::Feedback instance
|
27
|
+
# when feedback is received from the APNs that a notification has
|
28
|
+
# failed to be delivered. Further notifications should not be sent to the device.
|
29
|
+
#
|
30
|
+
# Example:
|
31
|
+
# config.on_apns_feedback do |feedback|
|
32
|
+
# device = Device.find_by_device_token(feedback.device_token)
|
33
|
+
# if device
|
34
|
+
# device.active = false
|
35
|
+
# device.save!
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Rapns
|
2
|
+
module Apns
|
3
|
+
class BinaryNotificationValidator < ActiveModel::Validator
|
4
|
+
|
5
|
+
def validate(record)
|
6
|
+
if record.payload_size > 256
|
7
|
+
record.errors[:base] << "APN notification cannot be larger than 256 bytes. Try condensing your alert and device attributes."
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Rapns
|
2
|
+
module Apns
|
3
|
+
class Feedback < ActiveRecord::Base
|
4
|
+
self.table_name = 'rapns_feedback'
|
5
|
+
|
6
|
+
attr_accessible :device_token, :failed_at, :app
|
7
|
+
|
8
|
+
validates :device_token, :presence => true
|
9
|
+
validates :failed_at, :presence => true
|
10
|
+
|
11
|
+
validates_with Rapns::Apns::DeviceTokenFormatValidator
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Rapns
|
2
|
+
module Apns
|
3
|
+
class Notification < Rapns::Notification
|
4
|
+
class MultipleAppAssignmentError < StandardError; end
|
5
|
+
|
6
|
+
validates :device_token, :presence => true
|
7
|
+
validates :badge, :numericality => true, :allow_nil => true
|
8
|
+
|
9
|
+
validates_with Rapns::Apns::DeviceTokenFormatValidator
|
10
|
+
validates_with Rapns::Apns::BinaryNotificationValidator
|
11
|
+
validates_with Rapns::Apns::RequiredFieldsValidator
|
12
|
+
|
13
|
+
alias_method :attributes_for_device=, :data=
|
14
|
+
alias_method :attributes_for_device, :data
|
15
|
+
|
16
|
+
def device_token=(token)
|
17
|
+
write_attribute(:device_token, token.delete(" <>")) if !token.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
def alert=(alert)
|
21
|
+
if alert.is_a?(Hash)
|
22
|
+
write_attribute(:alert, multi_json_dump(alert))
|
23
|
+
self.alert_is_json = true if has_attribute?(:alert_is_json)
|
24
|
+
else
|
25
|
+
write_attribute(:alert, alert)
|
26
|
+
self.alert_is_json = false if has_attribute?(:alert_is_json)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def alert
|
31
|
+
string_or_json = read_attribute(:alert)
|
32
|
+
|
33
|
+
if has_attribute?(:alert_is_json)
|
34
|
+
if alert_is_json?
|
35
|
+
multi_json_load(string_or_json)
|
36
|
+
else
|
37
|
+
string_or_json
|
38
|
+
end
|
39
|
+
else
|
40
|
+
multi_json_load(string_or_json) rescue string_or_json
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
MDM_KEY = '__rapns_mdm__'
|
45
|
+
def mdm=(magic)
|
46
|
+
self.attributes_for_device = { MDM_KEY => magic }
|
47
|
+
end
|
48
|
+
|
49
|
+
CONTENT_AVAILABLE_KEY = '__rapns_content_available__'
|
50
|
+
def content_available=(bool)
|
51
|
+
return unless bool
|
52
|
+
self.attributes_for_device = { CONTENT_AVAILABLE_KEY => true }
|
53
|
+
end
|
54
|
+
|
55
|
+
def as_json
|
56
|
+
json = ActiveSupport::OrderedHash.new
|
57
|
+
|
58
|
+
if attributes_for_device && attributes_for_device.key?(MDM_KEY)
|
59
|
+
json['mdm'] = attributes_for_device[MDM_KEY]
|
60
|
+
else
|
61
|
+
json['aps'] = ActiveSupport::OrderedHash.new
|
62
|
+
json['aps']['alert'] = alert if alert
|
63
|
+
json['aps']['badge'] = badge if badge
|
64
|
+
json['aps']['sound'] = sound if sound
|
65
|
+
|
66
|
+
if attributes_for_device && attributes_for_device[CONTENT_AVAILABLE_KEY]
|
67
|
+
json['aps']['content-available'] = 1
|
68
|
+
end
|
69
|
+
|
70
|
+
if attributes_for_device
|
71
|
+
non_aps_attributes = attributes_for_device.reject { |k, v| k == CONTENT_AVAILABLE_KEY }
|
72
|
+
non_aps_attributes.each { |k, v| json[k.to_s] = v.to_s }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
json
|
77
|
+
end
|
78
|
+
|
79
|
+
def to_binary(options = {})
|
80
|
+
id_for_pack = options[:for_validation] ? 0 : id
|
81
|
+
[1, id_for_pack, expiry, 0, 32, device_token, payload_size, payload].pack("cNNccH*na*")
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Rapns
|
2
|
+
module Apns
|
3
|
+
class RequiredFieldsValidator < ActiveModel::Validator
|
4
|
+
|
5
|
+
# Notifications must contain one of alert, badge or sound as per:
|
6
|
+
# https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html
|
7
|
+
def validate(record)
|
8
|
+
if record.alert.nil? && record.badge.nil? && record.sound.nil?
|
9
|
+
record.errors[:base] << "APN Notification must contain one of alert, badge, or sound"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|