pling 0.2.0 → 0.3.0
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/lib/pling/gcm/gateway.rb +87 -0
- data/lib/pling/gcm.rb +21 -0
- data/lib/pling/version.rb +1 -1
- data/lib/pling.rb +1 -0
- data/pling.gemspec +1 -0
- data/spec/pling/gcm/gateway_spec.rb +186 -0
- metadata +58 -13
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Pling
|
6
|
+
module GCM
|
7
|
+
##
|
8
|
+
# Pling gateway to communicate with Google's Android GCM service.
|
9
|
+
#
|
10
|
+
# The gateway is implemented using Faraday. It defaults to Faraday's :net_http adapter.
|
11
|
+
# You can customize the adapter by passing the :adapter configuration.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# Pling::GCM::Gateway.new({
|
16
|
+
# :key => 'your-api-key', # Your google account's api key (Required)
|
17
|
+
# :push_url => 'http://...', # The push url to use (Optional, Default: GCM default authentication url)
|
18
|
+
# :adapter => :net_http, # The Faraday adapter you want to use (Optional, Default: :net_http)
|
19
|
+
# :connection => {} # Options you want to pass to Faraday (Optional, Default: {})
|
20
|
+
# })
|
21
|
+
class Gateway < Pling::Gateway
|
22
|
+
|
23
|
+
handles :android, :gcm
|
24
|
+
|
25
|
+
##
|
26
|
+
# Initializes a new gateway to Apple's Push Notification service
|
27
|
+
#
|
28
|
+
# @param [Hash] configuration
|
29
|
+
# @option configuration [String] :key Your google account's api key (Required)
|
30
|
+
# @option configuration [String] :push_url The URL to push to (Optional)
|
31
|
+
# @option configuration [Symbol] :adapter The Faraday adapter to use (Optional)
|
32
|
+
# @option configuration [String] :connection Any options for Faraday (Optional)
|
33
|
+
# @raise Pling::AuthenticationFailed
|
34
|
+
def initialize(configuration)
|
35
|
+
super
|
36
|
+
require_configuration([:key])
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Sends the given message to the given device.
|
41
|
+
#
|
42
|
+
# @param [#to_pling_message] message
|
43
|
+
# @param [#to_pling_device] device
|
44
|
+
# @raise Pling::DeliveryFailed
|
45
|
+
def deliver!(message, device)
|
46
|
+
data = {
|
47
|
+
:registration_ids => [device.identifier],
|
48
|
+
:data => {
|
49
|
+
:body => message.body,
|
50
|
+
:badge => message.badge,
|
51
|
+
:sound => message.sound,
|
52
|
+
:subject => message.subject
|
53
|
+
}.delete_if { |_, value| value.nil? },
|
54
|
+
:collapse_key => "collapse-#{message.body.hash}"
|
55
|
+
}
|
56
|
+
|
57
|
+
data[:data].merge!(message.payload) if configuration[:payload] && message.payload
|
58
|
+
|
59
|
+
response = connection.post(configuration[:push_url], data, { :Authorization => "key=#{configuration[:key]}"})
|
60
|
+
|
61
|
+
if !response.success? || response.body['failure'].to_i > 0
|
62
|
+
error_class = Pling::GCM.const_get(response.body['results'][0]['error']) rescue Pling::DeliveryFailed
|
63
|
+
raise error_class.new("GCM Delivery failed: [#{response.status}] #{response.body}", message, device)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def default_configuration
|
70
|
+
super.merge({
|
71
|
+
:push_url => 'https://android.googleapis.com/gcm/send',
|
72
|
+
:adapter => :net_http,
|
73
|
+
:connection => {}
|
74
|
+
})
|
75
|
+
end
|
76
|
+
|
77
|
+
def connection
|
78
|
+
@connection ||= Faraday.new(configuration[:connection]) do |builder|
|
79
|
+
builder.use FaradayMiddleware::EncodeJson
|
80
|
+
builder.use FaradayMiddleware::ParseJson, :content_type => /\bjson$/
|
81
|
+
builder.use Faraday::Response::Logger if configuration[:debug]
|
82
|
+
builder.adapter(configuration[:adapter])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/pling/gcm.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pling
|
2
|
+
##
|
3
|
+
# This module adds support for Google Cloud Messaging for Android (GCM) to pling.
|
4
|
+
# Please refer to {Pling::GCM::Gateway} for documentation.
|
5
|
+
#
|
6
|
+
# @see Pling::GCM::Gateway
|
7
|
+
module GCM
|
8
|
+
autoload :Gateway, 'pling/gcm/gateway'
|
9
|
+
|
10
|
+
class MissingRegistration < Pling::DeliveryFailed; end
|
11
|
+
class InvalidRegistration < Pling::DeliveryFailed; end
|
12
|
+
class MismatchSenderId < Pling::DeliveryFailed; end
|
13
|
+
class NotRegistered < Pling::DeliveryFailed; end
|
14
|
+
class MessageTooBig < Pling::DeliveryFailed; end
|
15
|
+
class InvalidTtl < Pling::DeliveryFailed; end
|
16
|
+
class Unavailable < Pling::DeliveryFailed; end
|
17
|
+
class InternalServerError < Pling::DeliveryFailed; end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
data/lib/pling/version.rb
CHANGED
data/lib/pling.rb
CHANGED
@@ -8,6 +8,7 @@ module Pling
|
|
8
8
|
autoload :Gateway, 'pling/gateway'
|
9
9
|
autoload :APN, 'pling/apn'
|
10
10
|
autoload :C2DM, 'pling/c2dm'
|
11
|
+
autoload :GCM, 'pling/gcm'
|
11
12
|
autoload :Middleware, 'pling/middleware'
|
12
13
|
autoload :Adapter, 'pling/adapter'
|
13
14
|
autoload :Configurable, 'pling/configurable'
|
data/pling.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
19
|
s.add_runtime_dependency "faraday", "~> 0.7"
|
20
|
+
s.add_runtime_dependency "faraday_middleware", "~> 0.8"
|
20
21
|
s.add_runtime_dependency "json", "~> 1.4"
|
21
22
|
s.add_runtime_dependency("jruby-openssl") if RUBY_PLATFORM == 'java'
|
22
23
|
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Pling::GCM::Gateway do
|
4
|
+
|
5
|
+
let(:valid_configuration) do
|
6
|
+
{ :key => 'some-key' }
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:push_response_mock) do
|
10
|
+
mock('Faraday send response', :success? => true, :status => 200, :body => "")
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:connection_mock) do
|
14
|
+
mock('Faraday connection').tap do |mock|
|
15
|
+
mock.stub(:post).
|
16
|
+
with('https://android.googleapis.com/gcm/send', anything, anything).
|
17
|
+
and_return(push_response_mock)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:message) { Pling::Message.new('Hello from Pling') }
|
22
|
+
let(:device) { Pling::Device.new(:identifier => 'DEVICEIDENTIFIER', :type => :android) }
|
23
|
+
|
24
|
+
|
25
|
+
before { Faraday.stub(:new).and_return(connection_mock) }
|
26
|
+
|
27
|
+
it 'should handle various apn related device types' do
|
28
|
+
Pling::GCM::Gateway.handled_types.should =~ [:android, :gcm]
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when created with an invalid configuration' do
|
32
|
+
[:key].each do |attribute|
|
33
|
+
it "should raise an error when :#{attribute} is missing" do
|
34
|
+
configuration = valid_configuration
|
35
|
+
configuration.delete(attribute)
|
36
|
+
expect { Pling::GCM::Gateway.new(configuration) }.to raise_error(ArgumentError, /:#{attribute} is missing/)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when created with valid configuration' do
|
42
|
+
|
43
|
+
context 'configuration' do
|
44
|
+
it 'should allow configuring Faraday\'s :connection settings' do
|
45
|
+
Faraday.should_receive(:new).with(:ssl => { :verify => false })
|
46
|
+
Pling::GCM::Gateway.new(valid_configuration.merge(:connection => { :ssl => { :verify => false }})).deliver(message, device)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should use Faraday::Response::Logger when :debug is set to true' do
|
50
|
+
builder = mock(:use => true, :adapter => true)
|
51
|
+
builder.should_receive(:use).with(Faraday::Response::Logger)
|
52
|
+
Faraday.stub(:new).and_yield(builder).and_return(connection_mock)
|
53
|
+
|
54
|
+
Pling::GCM::Gateway.new(valid_configuration.merge(:debug => true)).deliver(message, device)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should use the adapter set with :adapter' do
|
58
|
+
builder = mock(:use => true, :adapter => true)
|
59
|
+
builder.should_receive(:adapter).with(:typheus)
|
60
|
+
Faraday.stub(:new).and_yield(builder).and_return(connection_mock)
|
61
|
+
|
62
|
+
Pling::GCM::Gateway.new(valid_configuration.merge(:adapter => :typheus)).deliver(message, device)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#deliver' do
|
69
|
+
subject { Pling::GCM::Gateway.new(valid_configuration) }
|
70
|
+
|
71
|
+
let(:valid_push_params) do
|
72
|
+
{
|
73
|
+
:registration_ids => [device.identifier],
|
74
|
+
:data => { :body => message.body },
|
75
|
+
:collapse_key => "collapse-#{message.body.hash}"
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
let(:valid_push_headers) do
|
80
|
+
{
|
81
|
+
:Authorization => 'key=some-key'
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should raise an error if no message is given' do
|
86
|
+
expect { subject.deliver(nil, device) }.to raise_error
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should raise an error the device is given' do
|
90
|
+
expect { subject.deliver(message, nil) }.to raise_error
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should call #to_pling_message on the given message' do
|
94
|
+
message.should_receive(:to_pling_message).and_return(message)
|
95
|
+
subject.deliver(message, device)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should call #to_pling_device on the given device' do
|
99
|
+
device.should_receive(:to_pling_device).and_return(device)
|
100
|
+
subject.deliver(message, device)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should try to deliver the given message' do
|
104
|
+
connection_mock.should_receive(:post).
|
105
|
+
with('https://android.googleapis.com/gcm/send', valid_push_params, valid_push_headers).
|
106
|
+
and_return(push_response_mock)
|
107
|
+
|
108
|
+
subject.deliver(message, device)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should raise a Pling::DeliveryFailed exception if the delivery was not successful' do
|
112
|
+
connection_mock.should_receive(:post).and_return(push_response_mock)
|
113
|
+
push_response_mock.stub(:status => 401, :success? => false, :body => "Something went wrong")
|
114
|
+
|
115
|
+
expect { subject.deliver(message, device) }.to raise_error Pling::DeliveryFailed, /Something went wrong/
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should raise a Pling::DeliveryFailed exception if the response body contained an error' do
|
119
|
+
connection_mock.should_receive(:post).and_return(push_response_mock)
|
120
|
+
push_response_mock.stub(:status => 200, :success? => true, :body => { 'failure' => 1, 'results' => ['error' => 'SomeError'] })
|
121
|
+
|
122
|
+
expect { subject.deliver(message, device) }.to raise_error Pling::DeliveryFailed, /SomeError/
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should send data.badge if the given message has a badge' do
|
126
|
+
connection_mock.should_receive(:post).
|
127
|
+
with(anything, hash_including(:data => hash_including({ :badge => '10' })), anything).
|
128
|
+
and_return(push_response_mock)
|
129
|
+
message.badge = 10
|
130
|
+
subject.deliver(message, device)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should send data.sound if the given message has a sound' do
|
134
|
+
connection_mock.should_receive(:post).
|
135
|
+
with(anything, hash_including(:data => hash_including({ :sound => 'pling' })), anything).
|
136
|
+
and_return(push_response_mock)
|
137
|
+
message.sound = :pling
|
138
|
+
subject.deliver(message, device)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should send data.subject if the given message has a subject' do
|
142
|
+
connection_mock.should_receive(:post).
|
143
|
+
with(anything, hash_including(:data => hash_including({ :subject => 'Important!' })), anything).
|
144
|
+
and_return(push_response_mock)
|
145
|
+
message.subject = 'Important!'
|
146
|
+
subject.deliver(message, device)
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when configured to include payload' do
|
150
|
+
before do
|
151
|
+
valid_configuration.merge!(:payload => true)
|
152
|
+
message.payload = { :data => 'available' }
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should include the given payload' do
|
156
|
+
connection_mock.should_receive(:post).
|
157
|
+
with(anything, hash_including(:data => hash_including({ :data => 'available' })), anything).
|
158
|
+
and_return(push_response_mock)
|
159
|
+
subject.deliver(message, device)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when configured to not include payload' do
|
164
|
+
before do
|
165
|
+
valid_configuration.merge!(:payload => false)
|
166
|
+
message.payload = { :data => 'available' }
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should include the given payload' do
|
170
|
+
connection_mock.should_receive(:post).
|
171
|
+
with(anything, hash_not_including(:'data.data' => 'available'), anything).
|
172
|
+
and_return(push_response_mock)
|
173
|
+
subject.deliver(message, device)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
[:MissingRegistration, :InvalidRegistration, :MismatchSenderId,
|
178
|
+
:NotRegistered, :MessageTooBig, :InvalidTtl, :Unavailable,
|
179
|
+
:InternalServerError].each do |exception|
|
180
|
+
it "should raise a Pling::GCM::#{exception} when the response body is ''" do
|
181
|
+
push_response_mock.stub(:body => { 'failure' => 1, 'results' => [{ 'error' => exception }]})
|
182
|
+
expect { subject.deliver(message, device) }.to raise_error Pling::GCM.const_get(exception)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2012-09-10 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: faraday
|
18
|
-
requirement:
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
@@ -23,10 +23,31 @@ dependencies:
|
|
23
23
|
version: '0.7'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements:
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ~>
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0.7'
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: faraday_middleware
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.8'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
27
48
|
- !ruby/object:Gem::Dependency
|
28
49
|
name: json
|
29
|
-
requirement:
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
30
51
|
none: false
|
31
52
|
requirements:
|
32
53
|
- - ~>
|
@@ -34,10 +55,15 @@ dependencies:
|
|
34
55
|
version: '1.4'
|
35
56
|
type: :runtime
|
36
57
|
prerelease: false
|
37
|
-
version_requirements:
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '1.4'
|
38
64
|
- !ruby/object:Gem::Dependency
|
39
65
|
name: rspec
|
40
|
-
requirement:
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
41
67
|
none: false
|
42
68
|
requirements:
|
43
69
|
- - ~>
|
@@ -45,10 +71,15 @@ dependencies:
|
|
45
71
|
version: '2.7'
|
46
72
|
type: :development
|
47
73
|
prerelease: false
|
48
|
-
version_requirements:
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '2.7'
|
49
80
|
- !ruby/object:Gem::Dependency
|
50
81
|
name: yard
|
51
|
-
requirement:
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
52
83
|
none: false
|
53
84
|
requirements:
|
54
85
|
- - ! '>='
|
@@ -56,10 +87,15 @@ dependencies:
|
|
56
87
|
version: '0.7'
|
57
88
|
type: :development
|
58
89
|
prerelease: false
|
59
|
-
version_requirements:
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0.7'
|
60
96
|
- !ruby/object:Gem::Dependency
|
61
97
|
name: rake
|
62
|
-
requirement:
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
63
99
|
none: false
|
64
100
|
requirements:
|
65
101
|
- - ! '>='
|
@@ -67,7 +103,12 @@ dependencies:
|
|
67
103
|
version: '0.9'
|
68
104
|
type: :development
|
69
105
|
prerelease: false
|
70
|
-
version_requirements:
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0.9'
|
71
112
|
description: Pling is a notification framework that supports multiple gateways. Currently
|
72
113
|
supported are Android Push and SMS.
|
73
114
|
email:
|
@@ -98,6 +139,8 @@ files:
|
|
98
139
|
- lib/pling/delayed_initializer.rb
|
99
140
|
- lib/pling/device.rb
|
100
141
|
- lib/pling/gateway.rb
|
142
|
+
- lib/pling/gcm.rb
|
143
|
+
- lib/pling/gcm/gateway.rb
|
101
144
|
- lib/pling/message.rb
|
102
145
|
- lib/pling/middleware.rb
|
103
146
|
- lib/pling/middleware/base.rb
|
@@ -113,6 +156,7 @@ files:
|
|
113
156
|
- spec/pling/delayed_initializer_spec.rb
|
114
157
|
- spec/pling/device_spec.rb
|
115
158
|
- spec/pling/gateway_spec.rb
|
159
|
+
- spec/pling/gcm/gateway_spec.rb
|
116
160
|
- spec/pling/message_spec.rb
|
117
161
|
- spec/pling_spec.rb
|
118
162
|
- spec/spec_helper.rb
|
@@ -136,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
180
|
version: '0'
|
137
181
|
requirements: []
|
138
182
|
rubyforge_project:
|
139
|
-
rubygems_version: 1.8.
|
183
|
+
rubygems_version: 1.8.24
|
140
184
|
signing_key:
|
141
185
|
specification_version: 3
|
142
186
|
summary: Pling is a notification framework that supports multiple gateways
|
@@ -151,6 +195,7 @@ test_files:
|
|
151
195
|
- spec/pling/delayed_initializer_spec.rb
|
152
196
|
- spec/pling/device_spec.rb
|
153
197
|
- spec/pling/gateway_spec.rb
|
198
|
+
- spec/pling/gcm/gateway_spec.rb
|
154
199
|
- spec/pling/message_spec.rb
|
155
200
|
- spec/pling_spec.rb
|
156
201
|
- spec/spec_helper.rb
|