mercurius 0.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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +31 -0
- data/Rakefile +13 -0
- data/lib/mercurius/android.rb +2 -0
- data/lib/mercurius/apns/core.rb +128 -0
- data/lib/mercurius/apns/notification.rb +47 -0
- data/lib/mercurius/apple.rb +2 -0
- data/lib/mercurius/gcm/core.rb +113 -0
- data/lib/mercurius/gcm/notification.rb +55 -0
- data/lib/mercurius/version.rb +3 -0
- data/lib/mercurius.rb +3 -0
- data/mercurius.gemspec +30 -0
- data/spec/lib/mercurius_spec.rb +148 -0
- data/spec/spec_helper.rb +1 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 65ff200559fb5130010b47d7d2be2cc1e524b0de
|
4
|
+
data.tar.gz: 8a28049240b58317298775619721978b80cb7ce7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ce55894987fecb4a496c014681d07dbea9375e805e2a1523b2d2495fe09a8bfb9a13254f6a78fd720ab3d994311903c5a0ace2415a2edf8b21b7b81dfaf10bd1
|
7
|
+
data.tar.gz: 334217c4278902311a45fed9ae873b912246354f25972d04dab17356fdca3f68fd0d6d0a214f103d7fd399d617253d99858ddc35a3bc19038d0c7edadbb34173
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mercurius
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.5
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Mercurius
|
2
|
+
|
3
|
+
### Send push messages to Android, iOS devices.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install mercurius
|
8
|
+
|
9
|
+
or add to your ``Gemfile``
|
10
|
+
|
11
|
+
gem 'mercurius'
|
12
|
+
|
13
|
+
and install it with
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
## Contributing
|
18
|
+
|
19
|
+
Please fork, modify, and send a pull request if you want to help improve this gem.
|
20
|
+
|
21
|
+
## Thanks
|
22
|
+
|
23
|
+
This gem is based off of the 'pushmeup' gem by Nicos Karalis
|
24
|
+
|
25
|
+
https://github.com/NicosKaralis/pushmeup
|
26
|
+
|
27
|
+
## License
|
28
|
+
|
29
|
+
Mercurius is released under the MIT license:
|
30
|
+
|
31
|
+
http://www.opensource.org/licenses/MIT
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
task :test => :spec
|
9
|
+
|
10
|
+
desc 'Open an IRB session preloaded with this library'
|
11
|
+
task :console do
|
12
|
+
sh "irb -rubygems -I lib -r mercurius.rb"
|
13
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'openssl'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module APNS
|
6
|
+
class Error < Exception; end
|
7
|
+
class ConfigurationError < Error; end
|
8
|
+
|
9
|
+
@host = 'gateway.sandbox.push.apple.com'
|
10
|
+
@port = 2195
|
11
|
+
@pem_path = nil
|
12
|
+
@pem_password = nil
|
13
|
+
@pem_data = nil
|
14
|
+
|
15
|
+
@persistent = false
|
16
|
+
@mutex = Mutex.new
|
17
|
+
@retries = 3 # TODO: check if we really need this
|
18
|
+
|
19
|
+
@sock = nil
|
20
|
+
@ssl = nil
|
21
|
+
|
22
|
+
class << self
|
23
|
+
attr_accessor :host, :port, :pem_path, :pem_password, :pem_data
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.start_persistence
|
27
|
+
@persistent = true
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.stop_persistence
|
31
|
+
@persistent = false
|
32
|
+
self.close_connection
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.send_notification(device_token, message)
|
36
|
+
notification = APNS::Notification.new(device_token, message)
|
37
|
+
send_notifications([notification])
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.send_notifications(notifications)
|
41
|
+
@mutex.synchronize do
|
42
|
+
with_connection do
|
43
|
+
notifications.each do |n|
|
44
|
+
@ssl.write(n.packaged_notification)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.feedback
|
51
|
+
sock, ssl = feedback_connection
|
52
|
+
apns_feedback = []
|
53
|
+
|
54
|
+
# read lines from the socket
|
55
|
+
while line = ssl.read(38)
|
56
|
+
line.strip!
|
57
|
+
f = line.unpack('N1n1H140')
|
58
|
+
apns_feedback << { timestamp: Time.at(f[0]), token: f[2] }
|
59
|
+
end
|
60
|
+
|
61
|
+
ssl.close
|
62
|
+
sock.close
|
63
|
+
|
64
|
+
apns_feedback
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def self.with_connection
|
70
|
+
attempts = 1
|
71
|
+
|
72
|
+
begin
|
73
|
+
open_connection if connection_closed?
|
74
|
+
yield
|
75
|
+
rescue StandardError, Errno::EPIPE
|
76
|
+
raise Error.new("Failed after #{@retries} attempts.") unless attempts < @retries
|
77
|
+
close_connection
|
78
|
+
attempts += 1
|
79
|
+
retry
|
80
|
+
end
|
81
|
+
|
82
|
+
close_connection unless @persistent
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.open_connection
|
86
|
+
@sock = TCPSocket.new(self.host, self.port)
|
87
|
+
@ssl = OpenSSL::SSL::SSLSocket.new(@sock, context)
|
88
|
+
@ssl.connect
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.close_connection
|
92
|
+
@ssl.close
|
93
|
+
@ssl = nil
|
94
|
+
@sock.close
|
95
|
+
@sock = nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.connection_closed?
|
99
|
+
@ssl.nil? || @sock.nil? || @ssl.closed? || @sock.closed?
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.feedback_connection
|
103
|
+
fhost = self.host.gsub('gateway','feedback')
|
104
|
+
sock = TCPSocket.new(fhost, 2196)
|
105
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, context)
|
106
|
+
ssl.connect
|
107
|
+
return sock, ssl
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.context
|
111
|
+
context = OpenSSL::SSL::SSLContext.new
|
112
|
+
context.cert = OpenSSL::X509::Certificate.new(pem_data)
|
113
|
+
context.key = OpenSSL::PKey::RSA.new(pem_data, pem_password)
|
114
|
+
context
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.pem_data
|
118
|
+
return @pem_data if @pem_data
|
119
|
+
|
120
|
+
if @pem_path
|
121
|
+
raise ConfigurationError.new('The specified PEM file does not exist.') unless File.exist?(@pem_path)
|
122
|
+
@pem_data = File.read(@pem_path)
|
123
|
+
else
|
124
|
+
raise ConfigurationError.new('PEM not configured properly.')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module APNS
|
2
|
+
class Notification
|
3
|
+
attr_accessor :device_token, :alert, :badge, :sound, :other
|
4
|
+
|
5
|
+
def initialize(device_token, message)
|
6
|
+
self.device_token = device_token
|
7
|
+
if message.is_a?(Hash)
|
8
|
+
self.alert = message[:alert]
|
9
|
+
self.badge = message[:badge]
|
10
|
+
self.sound = message[:sound]
|
11
|
+
self.other = message[:other]
|
12
|
+
elsif message.is_a?(String)
|
13
|
+
self.alert = message
|
14
|
+
else
|
15
|
+
raise "Notification needs to have either a Hash or String"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def packaged_notification
|
20
|
+
pt = self.packaged_token
|
21
|
+
pm = self.packaged_message
|
22
|
+
[0, 0, 32, pt, 0, pm.bytesize, pm].pack("ccca*cca*")
|
23
|
+
end
|
24
|
+
|
25
|
+
def packaged_token
|
26
|
+
[device_token.gsub(/[\s|<|>]/,'')].pack('H*')
|
27
|
+
end
|
28
|
+
|
29
|
+
def packaged_message
|
30
|
+
aps = {'aps'=> {} }
|
31
|
+
aps['aps']['alert'] = self.alert if self.alert
|
32
|
+
aps['aps']['badge'] = self.badge if self.badge
|
33
|
+
aps['aps']['sound'] = self.sound if self.sound
|
34
|
+
aps.merge!(self.other) if self.other
|
35
|
+
aps.to_json.gsub(/\\u([\da-fA-F]{4})/) {|m| [$1].pack("H*").unpack("n*").pack("U*")}
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(that)
|
39
|
+
device_token == that.device_token &&
|
40
|
+
alert == that.alert &&
|
41
|
+
badge == that.badge &&
|
42
|
+
sound == that.sound &&
|
43
|
+
other == that.other
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module GCM
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
@host = 'https://android.googleapis.com/gcm/send'
|
8
|
+
@format = :json
|
9
|
+
@key = nil
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :host, :format, :key
|
13
|
+
|
14
|
+
def key(identity = nil)
|
15
|
+
if @key.is_a?(Hash)
|
16
|
+
raise %{If your key is a hash of keys you'll need to pass a identifier to the notification!} if identity.nil?
|
17
|
+
return @key[identity]
|
18
|
+
else
|
19
|
+
return @key
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def key_identities
|
24
|
+
if @key.is_a?(Hash)
|
25
|
+
return @key.keys
|
26
|
+
else
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.send_notification(device_tokens, data = {}, options = {})
|
33
|
+
n = GCM::Notification.new(device_tokens, data, options)
|
34
|
+
self.send_notifications([n])
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.send_notifications(notifications)
|
38
|
+
responses = []
|
39
|
+
notifications.each do |n|
|
40
|
+
responses << self.prepare_and_send(n)
|
41
|
+
end
|
42
|
+
responses
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def self.prepare_and_send(n)
|
48
|
+
if n.device_tokens.count < 1 || n.device_tokens.count > 1000
|
49
|
+
raise "Number of device tokens must be between 1 and 1000"
|
50
|
+
end
|
51
|
+
if !n.collapse_key.nil? && n.time_to_live.nil?
|
52
|
+
raise %q{If you are defining a "collapse key" you need a "time to live"}
|
53
|
+
end
|
54
|
+
if @key.is_a?(Hash) && n.identity.nil?
|
55
|
+
raise %{If your key is a Hash of keys you'll need to pass a identifier to the notification!}
|
56
|
+
end
|
57
|
+
|
58
|
+
if self.format == :json
|
59
|
+
self.send_push_as_json(n)
|
60
|
+
elsif self.format == :text
|
61
|
+
self.send_push_as_plain_text(n)
|
62
|
+
else
|
63
|
+
raise "Invalid format"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.send_push_as_json(n)
|
68
|
+
headers = {
|
69
|
+
'Authorization' => "key=#{ self.key(n.identity) }",
|
70
|
+
'Content-Type' => 'application/json',
|
71
|
+
}
|
72
|
+
body = {
|
73
|
+
registration_ids: n.device_tokens,
|
74
|
+
data: n.data,
|
75
|
+
collapse_key: n.collapse_key,
|
76
|
+
time_to_live: n.time_to_live,
|
77
|
+
delay_while_idle: n.delay_while_idle
|
78
|
+
}
|
79
|
+
return self.send_to_server(headers, body.to_json)
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.send_push_as_plain_text(n)
|
83
|
+
raise "Still has to be done: http://developer.android.com/guide/google/gcm/gcm.html"
|
84
|
+
headers = {
|
85
|
+
# TODO: Aceitar key ser um hash
|
86
|
+
'Authorization' => "key=#{ self.key(n.identity) }",
|
87
|
+
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8',
|
88
|
+
}
|
89
|
+
return self.send_to_server(headers, body)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.send_to_server(headers, body)
|
93
|
+
params = { headers: headers, body: body}
|
94
|
+
response = self.post(self.host, params)
|
95
|
+
build_response(response)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.build_response(response)
|
99
|
+
case response.code
|
100
|
+
when 200
|
101
|
+
{ response: 'success', body: JSON.parse(response.body), headers: response.headers, status_code: response.code }
|
102
|
+
when 400
|
103
|
+
{ response: 'Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.', status_code: response.code }
|
104
|
+
when 401
|
105
|
+
{ response: 'There was an error authenticating the sender account.', status_code: response.code }
|
106
|
+
when 500
|
107
|
+
{ response: 'There was an internal error in the GCM server while trying to process the request.', status_code: response.code }
|
108
|
+
when 503
|
109
|
+
{ response: 'Server is temporarily unavailable.', status_code: response.code }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module GCM
|
2
|
+
class Notification
|
3
|
+
attr_accessor :device_tokens, :data, :collapse_key, :time_to_live, :delay_while_idle, :identity
|
4
|
+
|
5
|
+
def initialize(tokens, data, options = {})
|
6
|
+
self.device_tokens = tokens
|
7
|
+
self.data = data
|
8
|
+
|
9
|
+
@collapse_key = options[:collapse_key]
|
10
|
+
@time_to_live = options[:time_to_live]
|
11
|
+
@delay_while_idle = options[:delay_while_idle]
|
12
|
+
@identity = options[:identity]
|
13
|
+
end
|
14
|
+
|
15
|
+
def device_tokens=(tokens)
|
16
|
+
if tokens.is_a?(Array)
|
17
|
+
@device_tokens = tokens
|
18
|
+
elsif tokens.is_a?(String)
|
19
|
+
@device_tokens = [tokens]
|
20
|
+
else
|
21
|
+
raise "device_tokens needs to be either an Array or a String"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def data=(data)
|
26
|
+
if data.is_a?(Hash)
|
27
|
+
@data = data
|
28
|
+
else
|
29
|
+
raise "data parameter must be the type of Hash"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def delay_while_idle=(delay_while_idle)
|
34
|
+
@delay_while_idle = (delay_while_idle == true || delay_while_idle == :true)
|
35
|
+
end
|
36
|
+
|
37
|
+
def time_to_live=(time_to_live)
|
38
|
+
if time_to_live.is_a?(Integer)
|
39
|
+
@time_to_live = time_to_live
|
40
|
+
else
|
41
|
+
raise %q{"time_to_live" must be seconds as an integer value, like "100"}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def ==(that)
|
46
|
+
device_tokens == that.device_tokens &&
|
47
|
+
data == that.data &&
|
48
|
+
collapse_key == that.collapse_key &&
|
49
|
+
time_to_live == that.time_to_live &&
|
50
|
+
delay_while_idle == that.delay_while_idle &&
|
51
|
+
identity == that.identity
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/mercurius.rb
ADDED
data/mercurius.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mercurius/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'mercurius'
|
7
|
+
s.version = Mercurius::VERSION
|
8
|
+
s.authors = ["John Beck"]
|
9
|
+
s.email = ["jbeck@live.com"]
|
10
|
+
|
11
|
+
s.homepage = "https://github.com/jrbeck/mercurius"
|
12
|
+
s.summary = %q{Send push notifications to mobile devices through native services}
|
13
|
+
s.description = <<-DESC
|
14
|
+
This gem is a wrapper to send push notifications to devices through native push services.
|
15
|
+
DESC
|
16
|
+
|
17
|
+
s.rubyforge_project = "mercurius"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
|
25
|
+
s.add_dependency 'httparty'
|
26
|
+
s.add_dependency 'json'
|
27
|
+
|
28
|
+
s.add_development_dependency 'rake'
|
29
|
+
s.add_development_dependency 'rspec'
|
30
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mercurius do
|
4
|
+
describe "APNS" do
|
5
|
+
it "should have an APNS object" do
|
6
|
+
defined?(APNS).should_not be_false
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should not forget the APNS default parameters" do
|
10
|
+
APNS.host.should == "gateway.sandbox.push.apple.com"
|
11
|
+
APNS.port.should == 2195
|
12
|
+
APNS.pem_path.should be_equal(nil)
|
13
|
+
APNS.pem_password.should be_equal(nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Notifications" do
|
17
|
+
describe "#==" do
|
18
|
+
it "should properly equate objects without caring about object identity" do
|
19
|
+
a = APNS::Notification.new("123", {:alert => "hi"})
|
20
|
+
b = APNS::Notification.new("123", {:alert => "hi"})
|
21
|
+
a.should eq(b)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.send_notification' do
|
27
|
+
let(:token) { 'token' }
|
28
|
+
let(:message) { 'message' }
|
29
|
+
let(:pem_data) { 'pem_data' }
|
30
|
+
let(:cert) { double }
|
31
|
+
let(:key) { double }
|
32
|
+
let(:sock) { double(close: nil) }
|
33
|
+
let(:ssl) { double(connect: nil, write: nil, close: nil) }
|
34
|
+
let(:packaged) { 'packaged' }
|
35
|
+
|
36
|
+
after do
|
37
|
+
APNS.pem_path = nil
|
38
|
+
APNS.pem_data = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
allow(OpenSSL::X509::Certificate).to receive(:new).
|
43
|
+
with(pem_data).and_return(cert)
|
44
|
+
allow(OpenSSL::PKey::RSA).to receive(:new).
|
45
|
+
with(pem_data, anything).and_return(key)
|
46
|
+
allow(TCPSocket).to receive(:new).and_return(sock)
|
47
|
+
allow(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl)
|
48
|
+
end
|
49
|
+
|
50
|
+
shared_examples 'notifications' do
|
51
|
+
it 'notifications are sent' do
|
52
|
+
expect(ssl).to have_received(:write).with(/"#{message}"/)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with pem setting' do
|
57
|
+
context 'with an existing pem file' do
|
58
|
+
let(:path) { '/good/path' }
|
59
|
+
|
60
|
+
before do
|
61
|
+
allow(File).to receive(:exist?).with(path).and_return(true)
|
62
|
+
allow(File).to receive(:read).with(path).and_return(pem_data)
|
63
|
+
end
|
64
|
+
|
65
|
+
before { APNS.pem_path = '/good/path' }
|
66
|
+
before { APNS.send_notification(token, message) }
|
67
|
+
|
68
|
+
include_examples 'notifications'
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the pem does not exist' do
|
72
|
+
before { APNS.pem_path = '/bad/path' }
|
73
|
+
|
74
|
+
it 'fails' do
|
75
|
+
expect do
|
76
|
+
APNS.send_notification(token, message)
|
77
|
+
end.to raise_error(APNS::ConfigurationError, /does not exist/)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with pem_data' do
|
83
|
+
before { APNS.pem_data = pem_data }
|
84
|
+
before { APNS.send_notification(token, message) }
|
85
|
+
|
86
|
+
include_examples 'notifications'
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'without pem or pem_data' do
|
90
|
+
before { APNS.pem_path = nil }
|
91
|
+
|
92
|
+
it 'fails' do
|
93
|
+
expect do
|
94
|
+
APNS.send_notification(token, message)
|
95
|
+
end.to raise_error(APNS::ConfigurationError, /PEM not configured properly/)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "GCM" do
|
103
|
+
it "should have a GCM object" do
|
104
|
+
defined?(GCM).should_not be_false
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "Notifications" do
|
108
|
+
|
109
|
+
before do
|
110
|
+
@options = {:data => "dummy data"}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should allow only notifications with device_tokens as array" do
|
114
|
+
n = GCM::Notification.new("id", @options)
|
115
|
+
n.device_tokens.is_a?(Array).should be_true
|
116
|
+
|
117
|
+
n.device_tokens = ["a" "b", "c"]
|
118
|
+
n.device_tokens.is_a?(Array).should be_true
|
119
|
+
|
120
|
+
n.device_tokens = "a"
|
121
|
+
n.device_tokens.is_a?(Array).should be_true
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should allow only notifications with data as hash with :data root" do
|
125
|
+
n = GCM::Notification.new("id", { :data => "data" })
|
126
|
+
|
127
|
+
n.data.is_a?(Hash).should be_true
|
128
|
+
n.data.should == {:data => "data"}
|
129
|
+
|
130
|
+
n.data = {:a => ["a", "b", "c"]}
|
131
|
+
n.data.is_a?(Hash).should be_true
|
132
|
+
n.data.should == {:a => ["a", "b", "c"]}
|
133
|
+
|
134
|
+
n.data = {:a => "a"}
|
135
|
+
n.data.is_a?(Hash).should be_true
|
136
|
+
n.data.should == {:a => "a"}
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "#==" do
|
140
|
+
it "should properly equate objects without caring about object identity" do
|
141
|
+
a = GCM::Notification.new("id", { :data => "data" })
|
142
|
+
b = GCM::Notification.new("id", { :data => "data" })
|
143
|
+
a.should eq(b)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'mercurius'
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mercurius
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Beck
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: |2
|
70
|
+
This gem is a wrapper to send push notifications to devices through native push services.
|
71
|
+
email:
|
72
|
+
- jbeck@live.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".ruby-gemset"
|
79
|
+
- ".ruby-version"
|
80
|
+
- ".travis.yml"
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- lib/mercurius.rb
|
86
|
+
- lib/mercurius/android.rb
|
87
|
+
- lib/mercurius/apns/core.rb
|
88
|
+
- lib/mercurius/apns/notification.rb
|
89
|
+
- lib/mercurius/apple.rb
|
90
|
+
- lib/mercurius/gcm/core.rb
|
91
|
+
- lib/mercurius/gcm/notification.rb
|
92
|
+
- lib/mercurius/version.rb
|
93
|
+
- mercurius.gemspec
|
94
|
+
- spec/lib/mercurius_spec.rb
|
95
|
+
- spec/spec_helper.rb
|
96
|
+
homepage: https://github.com/jrbeck/mercurius
|
97
|
+
licenses: []
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project: mercurius
|
115
|
+
rubygems_version: 2.2.2
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Send push notifications to mobile devices through native services
|
119
|
+
test_files:
|
120
|
+
- spec/lib/mercurius_spec.rb
|
121
|
+
- spec/spec_helper.rb
|