Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unified Processing for YAML/Redis; -c option points to YAML file; read certificates from files #2

Merged
merged 2 commits into from
Jun 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ And run `bundle install` to install the gems.

## Configuration

### Via Redis or YAML File

The configuration of Pushr can either be stored in Redis or in a YAML file. **The default is Redis.**

If you want to use a YAML file, you need to specify it via the `-c` option of the `pushr` daemon.
Note that this will also override any existing Redis configuration.
APNS certificates can be loaded from file. If a relative file name is given, it's assumed to be relative to the same path as the YAML config file.

### Redis

By default the gem tries to connect to a Redis instance at localhost. If you define the `PUSHR_URL` environment variable
it will use that. The configuration is stored in Redis and you add the configuration per push provider with the console
(`bundle console`):
Expand Down Expand Up @@ -68,6 +78,82 @@ You can have each provider per app_name and you can have more than one app_name.
the certificate for the APNS provider. If you only want to prepare the database with the configurations, you can set the
`enabled` switch to `false`. Only enabled configurations will be used by the daemon.

### YAML File

If a YAML file is used for configuration, it needs to follow the structure of the example below, and may contain only the desired sections.

The certificates will be read from files. For security reasons, you might not want to check-in the certificate files into your source code repository.

If no absolute path is given of the PEM files, the location is assumed to be relative to the location of the YAML file.

The following example of a YAML configuration file can be found under `./lib/generators/templates/pushr.yml`.


```
# Configurations for all Pushr Gems
---

# Android Messaging:

- type: Pushr::ConfigurationGcm
app: gcm-development
enabled: true
connections: 1
api: your-api-key-here


# Feedback Service for all APNS Connections:

- type: Pushr::ConfigurationApnsFeedback
app: apns-feedback
enabled: true
connections: 1
feedback_poll: 300 # seconds

# Apple Messaging:

- type: Pushr::ConfigurationApns
app: ios-development
enabled: true
connections: 1
skip_check_for_error: false
sandbox: true
certificate: filename.pem

- type: Pushr::ConfigurationApns
app: ios-development
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: true
certificate: pushr/ios-development.pem

- type: Pushr::ConfigurationApns
app: ios-production
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: false
certificate: pushr/ios-production.pem

- type: Pushr::ConfigurationApns
app: ios-beta
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: true
certificate: pushr/ios-beta.pem

- type: Pushr::ConfigurationApns
app: ios-enterprise
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: false
certificate: pushr/ios-enterprise.pem

```

### Generating Certificates for APNS

1. Open up Keychain Access and select the `Certificates` category in the sidebar.
Expand All @@ -94,6 +180,7 @@ Where `<options>` can be:
-f, --foreground Run in the foreground. Log is not written.
-p, --pid-file PATH Path to write PID file. Relative to Rails root unless absolute.
-b, --feedback-processor PATH Path to the feedback processor. Default: lib/push/feedback_processor.
-c, --configuration FILE Read the configuration from this YAML file (optional)
-v, --version Print this version of push.
-h, --help You're looking at it.

Expand All @@ -113,6 +200,24 @@ Pushr::MessageApns.new(
content_available: 1).save
```


Silent Push Notification via APNS:

```ruby
Push::MessageApns.create(
app: 'app_name',
device: '<APNS device_token here>',
alert: nil,
sound: nil,
badge: 1,
content_available: 1, # see footnote
expiry: 1.day.to_i,
attributes_for_device: nil)
```

Use `content_available: 1` if the iOS device should start your app upon receiving the silent push notification.


GCM:
```ruby
Pushr::MessageGcm.new(
Expand Down
4 changes: 4 additions & 0 deletions bin/pushr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ ARGV.options do |opts|
settings.foreground = true
end

opts.on('-c FILE', '--configuration FILE', 'Read the configuration from this YAML file') do |file|
settings.configuration_file = file
end

opts.on('-p PATH', '--pid-file PATH', String,
'Path to write PID file. Relative to current directory unless absolute.') do |path|
settings.pid_file = path
Expand Down
61 changes: 61 additions & 0 deletions lib/generators/templates/pushr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Configurations for all Pushr Gems
---

# Android Messaging:

- type: Pushr::ConfigurationGcm
app: gcm-development
enabled: true
connections: 1
api: your-api-key-here


# Feedback Service for all APNS Connections:

- type: Pushr::ConfigurationApnsFeedback
app: apns-feedback
enabled: true
connections: 1
feedback_poll: 300 # seconds

# Apple Messaging:

- type: Pushr::ConfigurationApns
app: ios-development
enabled: true
connections: 1
skip_check_for_error: false
sandbox: true
certificate: filename.pem

- type: Pushr::ConfigurationApns
app: ios-development
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: true
certificate: pushr/ios-development.pem

- type: Pushr::ConfigurationApns
app: ios-production
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: false
certificate: pushr/ios-production.pem

- type: Pushr::ConfigurationApns
app: ios-beta
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: true
certificate: pushr/ios-beta.pem

- type: Pushr::ConfigurationApns
app: ios-enterprise
enabled: true
connections: 1
# skip_check_for_error: true
sandbox: false
certificate: pushr/ios-enterprise.pem
40 changes: 32 additions & 8 deletions lib/pushr/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module Pushr
class Configuration
include ActiveModel::Validations

validates :app, presence: true
validates :connections, presence: true
validates :connections, numericality: { greater_than: 0, only_integer: true }
Expand Down Expand Up @@ -31,20 +30,45 @@ def delete
end

def self.all
configurations = Pushr::Core.redis { |conn| conn.hgetall('pushr:configurations') }
configurations.each { |key, config| configurations[key] = instantiate(config, key) }
configurations.values
if Pushr::Daemon.config.configuration_file # only set if file exists
read_from_yaml_file
else
read_from_redis
end
end

def self.find(key)
config = Pushr::Core.redis { |conn| conn.hget('pushr:configurations', key) }
instantiate(config, key)
end

def self.instantiate(config, id)
hsh = ::MultiJson.load(config).merge!(id: id)
klass = hsh['type'].split('::').reduce(Object) { |a, e| a.const_get e }
klass.new(hsh)
def to_json
MultiJson.dump(to_hash)
end

private

def read_from_yaml_file
filename = Pushr::Daemon.config.configuration_file
configs = File.open( filename ) { |fd| YAML.load(fd) }
configs.map do |hsh|
klass = hsh['type'].split('::').reduce(Object) { |a, e| a.const_get e }
klass.new(hsh)
end
end
end

def read_from_redis
configurations = Pushr::Core.redis { |conn| conn.hgetall('pushr:configurations') }
configurations.each { |key, config| configurations[key] = instantiate(config, key) }
configurations.values
end

def self.instantiate(config, id)
hsh = ::MultiJson.load(config).merge!(id: id)
klass = hsh['type'].split('::').reduce(Object) { |a, e| a.const_get e }
klass.new(hsh)
end

end
end
1 change: 1 addition & 0 deletions lib/pushr/core.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'yaml'
require 'active_model'
require 'multi_json'
require 'pushr/version'
Expand Down
2 changes: 1 addition & 1 deletion lib/pushr/daemon/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class << self
attr_reader :apps

def load
@apps = Configuration.all.keep_if { |c| c.enabled == true }.map { |c| App.new(c) }
@apps = Pushr::Configuration.all.keep_if { |c| c.enabled == true }.map { |c| App.new(c) }
end

def total_connections
Expand Down
15 changes: 14 additions & 1 deletion lib/pushr/daemon/settings.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Pushr
module Daemon
class Settings
attr_reader :pid_file
attr_reader :pid_file, :configuration_file
attr_accessor :foreground, :error_notification, :feedback_processor, :stats_processor

def initialize
Expand All @@ -10,11 +10,24 @@ def initialize
@feedback_processor = nil
@stats_processor = nil
@pid_file = nil
@configuration_file = nil
end

def pid_file=(arg)
@pid_file = File.join(Dir.pwd, arg) if arg && !Pathname.new(arg).absolute?
end

def configuration_file=(filename)
if filename
filename = File.join(Dir.pwd,filename) if ! Pathname.new(filename).absolute?
if File.file?(filename)
@configuration_file = filename
else
Pushr::Daemon.logger.error("can not find config file: #{filename}")
end
end
end

end
end
end
2 changes: 2 additions & 0 deletions spec/lib/pushr/daemon/app_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
allow(logger).to receive(:error)
allow(logger).to receive(:warn)
Pushr::Daemon.logger = logger
Pushr::Daemon.config = settings
end

let(:settings) { Pushr::Daemon::Settings.new }
let(:config) { Pushr::ConfigurationDummy.new(app: 'app_name', connections: 1, enabled: true) }
describe 'self' do
before(:each) do
Expand Down
4 changes: 4 additions & 0 deletions spec/support/pushr_invalid_configuration_dummy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ class InvalidConfigurationDummy < Pushr::Configuration
def name
:invalid_dummy
end

def to_hash
{ type: self.class.to_s, app: app, enabled: enabled, connections: connections, test_attr: test_attr }
end
end
end