bmo 0.8.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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +4 -0
- data/Gemfile +32 -0
- data/Gemfile.lock +237 -0
- data/Guardfile +27 -0
- data/LICENSE +21 -0
- data/README.md +88 -0
- data/bmo.gemspec +20 -0
- data/bmo.png +0 -0
- data/lib/bmo/apns/client.rb +84 -0
- data/lib/bmo/apns/connection.rb +55 -0
- data/lib/bmo/apns/notification.rb +92 -0
- data/lib/bmo/configuration.rb +67 -0
- data/lib/bmo/gcm/client.rb +23 -0
- data/lib/bmo/gcm/connection.rb +25 -0
- data/lib/bmo/gcm/notification.rb +61 -0
- data/lib/bmo/utils.rb +17 -0
- data/lib/bmo/version.rb +5 -0
- data/lib/bmo.rb +81 -0
- data/spec/bmo/apns/notification_spec.rb +81 -0
- data/spec/spec_helper.rb +2 -0
- metadata +96 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 39304f792a910d0a9f4e7e1e50067919aa28ec67
|
|
4
|
+
data.tar.gz: 2a478f2e6fc7e7b0e80fc87a492bf63a024e7338
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2979469971ebf385203814428d3d7fe6e18a3bdae760f6994fef7c43eacb964bb160b00f41b179f4346540988fe036678a8e00b186f4847cbf98c99492048ee6
|
|
7
|
+
data.tar.gz: a41eedfd88a9f130fe2408ddc2c6894843792019badc9ed10df6fbd239b6860822cce989e97c1d6bd8975d2794be747f1e188f92d2133049143298104b5f2111
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
source 'https://rubygems.org'
|
|
3
|
+
|
|
4
|
+
# Specify your gem's dependencies in poleica.gemspec
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
group :test do
|
|
8
|
+
gem 'rspec'
|
|
9
|
+
gem 'coveralls'
|
|
10
|
+
gem 'flay'
|
|
11
|
+
gem 'flog'
|
|
12
|
+
gem 'reek'
|
|
13
|
+
gem 'rubocop'
|
|
14
|
+
gem 'simplecov'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
group :development do
|
|
18
|
+
gem 'jazz_hands'
|
|
19
|
+
|
|
20
|
+
# Guards
|
|
21
|
+
gem 'guard'
|
|
22
|
+
gem 'guard-bundler'
|
|
23
|
+
gem 'guard-rspec'
|
|
24
|
+
gem 'guard-rubocop'
|
|
25
|
+
gem 'guard-flay', github: 'pericles/guard-flay'
|
|
26
|
+
gem 'guard-reek', github: 'pericles/guard-reek'
|
|
27
|
+
gem 'guard-flog', github: 'antoinelyset/guard-flog'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
group :darwin do
|
|
31
|
+
gem 'terminal-notifier-guard'
|
|
32
|
+
end
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
GIT
|
|
2
|
+
remote: git://github.com/antoinelyset/guard-flog.git
|
|
3
|
+
revision: 40ea28590ae29349860901d3c9b8253b24c31588
|
|
4
|
+
specs:
|
|
5
|
+
guard-flog (0.0.1)
|
|
6
|
+
flog (~> 4.2.0)
|
|
7
|
+
guard (>= 1.8)
|
|
8
|
+
|
|
9
|
+
GIT
|
|
10
|
+
remote: git://github.com/pericles/guard-flay.git
|
|
11
|
+
revision: 75b9be79c12394626af0064bcec1075959c3cbdd
|
|
12
|
+
specs:
|
|
13
|
+
guard-flay (0.0.1)
|
|
14
|
+
flay (~> 2.4.0)
|
|
15
|
+
flay-haml (~> 0.0.3)
|
|
16
|
+
guard (>= 1.8)
|
|
17
|
+
|
|
18
|
+
GIT
|
|
19
|
+
remote: git://github.com/pericles/guard-reek.git
|
|
20
|
+
revision: febe7ac4f4c6f029a30a9213e92bc1ba44b4e2d4
|
|
21
|
+
specs:
|
|
22
|
+
guard-reek (0.0.1)
|
|
23
|
+
guard (>= 1.8)
|
|
24
|
+
reek (~> 1.3.2)
|
|
25
|
+
|
|
26
|
+
PATH
|
|
27
|
+
remote: .
|
|
28
|
+
specs:
|
|
29
|
+
bmo (0.8.0)
|
|
30
|
+
equalizer (~> 0.0.0)
|
|
31
|
+
faraday (~> 0.8.0)
|
|
32
|
+
|
|
33
|
+
GEM
|
|
34
|
+
remote: https://rubygems.org/
|
|
35
|
+
specs:
|
|
36
|
+
actionpack (4.0.2)
|
|
37
|
+
activesupport (= 4.0.2)
|
|
38
|
+
builder (~> 3.1.0)
|
|
39
|
+
erubis (~> 2.7.0)
|
|
40
|
+
rack (~> 1.5.2)
|
|
41
|
+
rack-test (~> 0.6.2)
|
|
42
|
+
activesupport (4.0.2)
|
|
43
|
+
i18n (~> 0.6, >= 0.6.4)
|
|
44
|
+
minitest (~> 4.2)
|
|
45
|
+
multi_json (~> 1.3)
|
|
46
|
+
thread_safe (~> 0.1)
|
|
47
|
+
tzinfo (~> 0.3.37)
|
|
48
|
+
ast (1.1.0)
|
|
49
|
+
atomic (1.1.14)
|
|
50
|
+
awesome_print (1.2.0)
|
|
51
|
+
binding_of_caller (0.7.2)
|
|
52
|
+
debug_inspector (>= 0.0.1)
|
|
53
|
+
builder (3.1.4)
|
|
54
|
+
celluloid (0.15.2)
|
|
55
|
+
timers (~> 1.1.0)
|
|
56
|
+
coderay (1.1.0)
|
|
57
|
+
columnize (0.3.6)
|
|
58
|
+
coolline (0.4.2)
|
|
59
|
+
coveralls (0.7.0)
|
|
60
|
+
multi_json (~> 1.3)
|
|
61
|
+
rest-client
|
|
62
|
+
simplecov (>= 0.7)
|
|
63
|
+
term-ansicolor
|
|
64
|
+
thor
|
|
65
|
+
debug_inspector (0.0.2)
|
|
66
|
+
debugger (1.6.3)
|
|
67
|
+
columnize (>= 0.3.1)
|
|
68
|
+
debugger-linecache (~> 1.2.0)
|
|
69
|
+
debugger-ruby_core_source (~> 1.2.4)
|
|
70
|
+
debugger-linecache (1.2.0)
|
|
71
|
+
debugger-ruby_core_source (1.2.4)
|
|
72
|
+
diff-lcs (1.2.5)
|
|
73
|
+
diffy (3.0.1)
|
|
74
|
+
docile (1.1.1)
|
|
75
|
+
equalizer (0.0.8)
|
|
76
|
+
erubis (2.7.0)
|
|
77
|
+
faraday (0.8.8)
|
|
78
|
+
multipart-post (~> 1.2.0)
|
|
79
|
+
ffi (1.9.3)
|
|
80
|
+
flay (2.4.0)
|
|
81
|
+
ruby_parser (~> 3.0)
|
|
82
|
+
sexp_processor (~> 4.0)
|
|
83
|
+
flay-haml (0.0.3)
|
|
84
|
+
flay (>= 1.2, < 3)
|
|
85
|
+
haml (>= 3, < 5)
|
|
86
|
+
flog (4.2.0)
|
|
87
|
+
ruby_parser (~> 3.1, > 3.1.0)
|
|
88
|
+
sexp_processor (~> 4.4)
|
|
89
|
+
formatador (0.2.4)
|
|
90
|
+
grit (2.5.0)
|
|
91
|
+
diff-lcs (~> 1.1)
|
|
92
|
+
mime-types (~> 1.15)
|
|
93
|
+
posix-spawn (~> 0.3.6)
|
|
94
|
+
guard (2.2.4)
|
|
95
|
+
formatador (>= 0.2.4)
|
|
96
|
+
listen (~> 2.1)
|
|
97
|
+
lumberjack (~> 1.0)
|
|
98
|
+
pry (>= 0.9.12)
|
|
99
|
+
thor (>= 0.18.1)
|
|
100
|
+
guard-bundler (2.0.0)
|
|
101
|
+
bundler (~> 1.0)
|
|
102
|
+
guard (~> 2.2)
|
|
103
|
+
guard-rspec (4.2.0)
|
|
104
|
+
guard (>= 2.1.1)
|
|
105
|
+
rspec (>= 2.14, < 4.0)
|
|
106
|
+
guard-rubocop (1.0.1)
|
|
107
|
+
guard (~> 2.0)
|
|
108
|
+
rubocop (~> 0.10)
|
|
109
|
+
haml (4.0.4)
|
|
110
|
+
tilt
|
|
111
|
+
hirb (0.7.1)
|
|
112
|
+
i18n (0.6.9)
|
|
113
|
+
jazz_hands (0.5.2)
|
|
114
|
+
awesome_print (~> 1.2)
|
|
115
|
+
coolline (>= 0.4.2)
|
|
116
|
+
hirb (~> 0.7.1)
|
|
117
|
+
pry (~> 0.9.12)
|
|
118
|
+
pry-debugger (~> 0.2.2)
|
|
119
|
+
pry-doc (~> 0.4.6)
|
|
120
|
+
pry-git (~> 0.2.3)
|
|
121
|
+
pry-rails (~> 0.3.2)
|
|
122
|
+
pry-remote (>= 0.1.7)
|
|
123
|
+
pry-stack_explorer (~> 0.4.9)
|
|
124
|
+
railties (>= 3.0, < 5.0)
|
|
125
|
+
listen (2.4.0)
|
|
126
|
+
celluloid (>= 0.15.2)
|
|
127
|
+
rb-fsevent (>= 0.9.3)
|
|
128
|
+
rb-inotify (>= 0.9)
|
|
129
|
+
lumberjack (1.0.4)
|
|
130
|
+
method_source (0.8.2)
|
|
131
|
+
mime-types (1.25.1)
|
|
132
|
+
minitest (4.7.5)
|
|
133
|
+
multi_json (1.8.2)
|
|
134
|
+
multipart-post (1.2.0)
|
|
135
|
+
parser (2.0.0)
|
|
136
|
+
ast (~> 1.1)
|
|
137
|
+
slop (~> 3.4, >= 3.4.5)
|
|
138
|
+
posix-spawn (0.3.8)
|
|
139
|
+
powerpack (0.0.9)
|
|
140
|
+
pry (0.9.12.4)
|
|
141
|
+
coderay (~> 1.0)
|
|
142
|
+
method_source (~> 0.8)
|
|
143
|
+
slop (~> 3.4)
|
|
144
|
+
pry-debugger (0.2.2)
|
|
145
|
+
debugger (~> 1.3)
|
|
146
|
+
pry (~> 0.9.10)
|
|
147
|
+
pry-doc (0.4.6)
|
|
148
|
+
pry (>= 0.9)
|
|
149
|
+
yard (>= 0.8)
|
|
150
|
+
pry-git (0.2.3)
|
|
151
|
+
diffy
|
|
152
|
+
grit
|
|
153
|
+
pry (>= 0.9.8)
|
|
154
|
+
pry-rails (0.3.2)
|
|
155
|
+
pry (>= 0.9.10)
|
|
156
|
+
pry-remote (0.1.7)
|
|
157
|
+
pry (~> 0.9)
|
|
158
|
+
slop (~> 3.0)
|
|
159
|
+
pry-stack_explorer (0.4.9.1)
|
|
160
|
+
binding_of_caller (>= 0.7)
|
|
161
|
+
pry (>= 0.9.11)
|
|
162
|
+
rack (1.5.2)
|
|
163
|
+
rack-test (0.6.2)
|
|
164
|
+
rack (>= 1.0)
|
|
165
|
+
railties (4.0.2)
|
|
166
|
+
actionpack (= 4.0.2)
|
|
167
|
+
activesupport (= 4.0.2)
|
|
168
|
+
rake (>= 0.8.7)
|
|
169
|
+
thor (>= 0.18.1, < 2.0)
|
|
170
|
+
rainbow (1.1.4)
|
|
171
|
+
rake (10.1.0)
|
|
172
|
+
rb-fsevent (0.9.3)
|
|
173
|
+
rb-inotify (0.9.2)
|
|
174
|
+
ffi (>= 0.5.0)
|
|
175
|
+
reek (1.3.4)
|
|
176
|
+
ruby2ruby (~> 2.0.2)
|
|
177
|
+
ruby_parser (~> 3.2)
|
|
178
|
+
sexp_processor
|
|
179
|
+
rest-client (1.6.7)
|
|
180
|
+
mime-types (>= 1.16)
|
|
181
|
+
rspec (2.14.1)
|
|
182
|
+
rspec-core (~> 2.14.0)
|
|
183
|
+
rspec-expectations (~> 2.14.0)
|
|
184
|
+
rspec-mocks (~> 2.14.0)
|
|
185
|
+
rspec-core (2.14.7)
|
|
186
|
+
rspec-expectations (2.14.4)
|
|
187
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
|
188
|
+
rspec-mocks (2.14.4)
|
|
189
|
+
rubocop (0.15.0)
|
|
190
|
+
parser (~> 2.0)
|
|
191
|
+
powerpack (~> 0.0.6)
|
|
192
|
+
rainbow (>= 1.1.4)
|
|
193
|
+
ruby2ruby (2.0.6)
|
|
194
|
+
ruby_parser (~> 3.1)
|
|
195
|
+
sexp_processor (~> 4.0)
|
|
196
|
+
ruby_parser (3.2.2)
|
|
197
|
+
sexp_processor (~> 4.1)
|
|
198
|
+
sexp_processor (4.4.0)
|
|
199
|
+
simplecov (0.8.2)
|
|
200
|
+
docile (~> 1.1.0)
|
|
201
|
+
multi_json
|
|
202
|
+
simplecov-html (~> 0.8.0)
|
|
203
|
+
simplecov-html (0.8.0)
|
|
204
|
+
slop (3.4.7)
|
|
205
|
+
term-ansicolor (1.2.2)
|
|
206
|
+
tins (~> 0.8)
|
|
207
|
+
terminal-notifier-guard (1.5.3)
|
|
208
|
+
thor (0.18.1)
|
|
209
|
+
thread_safe (0.1.3)
|
|
210
|
+
atomic
|
|
211
|
+
tilt (2.0.0)
|
|
212
|
+
timers (1.1.0)
|
|
213
|
+
tins (0.13.1)
|
|
214
|
+
tzinfo (0.3.38)
|
|
215
|
+
yard (0.8.7.3)
|
|
216
|
+
|
|
217
|
+
PLATFORMS
|
|
218
|
+
ruby
|
|
219
|
+
|
|
220
|
+
DEPENDENCIES
|
|
221
|
+
bmo!
|
|
222
|
+
coveralls
|
|
223
|
+
flay
|
|
224
|
+
flog
|
|
225
|
+
guard
|
|
226
|
+
guard-bundler
|
|
227
|
+
guard-flay!
|
|
228
|
+
guard-flog!
|
|
229
|
+
guard-reek!
|
|
230
|
+
guard-rspec
|
|
231
|
+
guard-rubocop
|
|
232
|
+
jazz_hands
|
|
233
|
+
reek
|
|
234
|
+
rspec
|
|
235
|
+
rubocop
|
|
236
|
+
simplecov
|
|
237
|
+
terminal-notifier-guard
|
data/Guardfile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
guard 'bundler' do
|
|
2
|
+
watch('Gemfile')
|
|
3
|
+
watch(/^.+\.gemspec/)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
guard :rspec do
|
|
7
|
+
watch(%r{^spec/.+_spec\.rb$})
|
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
|
9
|
+
watch('spec/spec_helper.rb') { "spec" }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
guard :rubocop do
|
|
13
|
+
watch(%r{.+\.rb$})
|
|
14
|
+
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
guard :flog do
|
|
18
|
+
watch(%r{^lib/(.+)\.rb$})
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
guard :reek do
|
|
22
|
+
watch(%r{^lib/(.+)\.rb$})
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
guard :flay do
|
|
26
|
+
watch(%r{^lib/(.+)\.rb$})
|
|
27
|
+
end
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2013 Antoine Lyset
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<img src="https://raw.github.com/antoinelyset/bmo/master/bmo.png"
|
|
2
|
+
alt="BMO"
|
|
3
|
+
align="right"
|
|
4
|
+
width="150px"/>
|
|
5
|
+
|
|
6
|
+
<br>
|
|
7
|
+
<br>
|
|
8
|
+
<br>
|
|
9
|
+
|
|
10
|
+
# BMO (Beemo)
|
|
11
|
+
|
|
12
|
+
BMO is a gem to Push Notifications to iOS (via APNS) and Android (via GCM)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
gem install bmo
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
In Gemfile :
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
gem 'bmo'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## APNS
|
|
27
|
+
|
|
28
|
+
### Usage
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
token = "123456789" # The device token given to you by Apple
|
|
32
|
+
data = {aps: {alert: "Hello from BMO!"}}
|
|
33
|
+
BMO.send_ios_notification(token, data)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The aps Hash content's is described here :
|
|
37
|
+
|
|
38
|
+
[https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html)
|
|
39
|
+
|
|
40
|
+
### Configuration
|
|
41
|
+
|
|
42
|
+
Default Params :
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
BMO.configuration do |config|
|
|
46
|
+
config.apns.gateway_host = 'gateway.push.apple.com'
|
|
47
|
+
config.apns.gateway_port = 2195
|
|
48
|
+
config.apns.feedback_host = 'feedback.push.apple.com'
|
|
49
|
+
config.apns.feedback_port = 2196
|
|
50
|
+
config.apns.cert_path = nil
|
|
51
|
+
config.apns.cert_pass = nil
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If you set a cert_path option it will use a SSL encapsulation otherwise it will use Pure TCP.
|
|
56
|
+
This option is particularly useful if you use a stunnel.
|
|
57
|
+
|
|
58
|
+
## GCM
|
|
59
|
+
|
|
60
|
+
### Usage
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
token = "123456789" # The device token given to you by Apple
|
|
64
|
+
data = {message: "Hello from BMO!"}
|
|
65
|
+
BMO.send_android_notification(token, data)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The data contennt is described here :
|
|
69
|
+
|
|
70
|
+
[http://developer.android.com/google/gcm/server.html](http://developer.android.com/google/gcm/server.html)
|
|
71
|
+
|
|
72
|
+
### Configuration
|
|
73
|
+
|
|
74
|
+
Default Params :
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
BMO.configuration do |config|
|
|
78
|
+
config.gcm.gateway_url = 'https://android.googleapis.com/gcm/send'
|
|
79
|
+
config.gcm.api_key = nil
|
|
80
|
+
end
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
You should set the api_key.
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
BMO is released under the [MIT
|
|
88
|
+
License](http://www.opensource.org/licenses/MIT)
|
data/bmo.gemspec
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../lib/bmo/version', __FILE__)
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |gem|
|
|
6
|
+
gem.name = 'bmo'
|
|
7
|
+
gem.summary = 'Push notifications to iOS and Android devices'
|
|
8
|
+
gem.description = gem.summary
|
|
9
|
+
gem.authors = ['Antoine Lyset']
|
|
10
|
+
gem.email = ['antoinelyset@gmail.com']
|
|
11
|
+
gem.homepage = 'https://github.com/antoinelyset/bmo'
|
|
12
|
+
gem.require_paths = ['lib']
|
|
13
|
+
gem.version = BMO::VERSION.dup
|
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
|
15
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
16
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
17
|
+
gem.add_runtime_dependency('equalizer', '~> 0.0.0')
|
|
18
|
+
gem.add_runtime_dependency('faraday', '~> 0.8.0')
|
|
19
|
+
gem.license = 'MIT'
|
|
20
|
+
end
|
data/bmo.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
module APNS
|
|
4
|
+
# APNS Client Class
|
|
5
|
+
#
|
|
6
|
+
# @!attribute gateway_host
|
|
7
|
+
# @!attribute gateway_port
|
|
8
|
+
# @!attribute feedback_host
|
|
9
|
+
# @!attribute feedback_port
|
|
10
|
+
# @!attribute cert_path
|
|
11
|
+
# @!attribute cert_pass
|
|
12
|
+
class Client
|
|
13
|
+
attr_reader :cert_path, :cert_pass,
|
|
14
|
+
:gateway_host, :gateway_port,
|
|
15
|
+
:feedback_host, :feedback_port
|
|
16
|
+
|
|
17
|
+
# The constructor of the Client object
|
|
18
|
+
# it will only use a ssl connection if you pass a cert_path option
|
|
19
|
+
#
|
|
20
|
+
# @param gateway_host [String]
|
|
21
|
+
# @param gateway_port [Integer]
|
|
22
|
+
# @param feedback_host [String]
|
|
23
|
+
# @param feedback_port [Integer]
|
|
24
|
+
#
|
|
25
|
+
# @options options [String] :cert_pass
|
|
26
|
+
# @options options [String] :cert_path path to certificate file
|
|
27
|
+
#
|
|
28
|
+
def initialize(gateway_host, gateway_port,
|
|
29
|
+
feedback_host, feedback_port,
|
|
30
|
+
options = {})
|
|
31
|
+
@gateway_host = gateway_host
|
|
32
|
+
@gateway_port = gateway_port
|
|
33
|
+
@feedback_host = feedback_host
|
|
34
|
+
@feedback_port = feedback_port
|
|
35
|
+
@cert_path = options[:cert_path]
|
|
36
|
+
@cert_pass = options[:cert_pass]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param notification [Notification] the notification to send to Apple
|
|
40
|
+
#
|
|
41
|
+
def send_notification(notification)
|
|
42
|
+
connection = APNS::Connection.new(@gateway_host, @gateway_port,
|
|
43
|
+
@cert_path, @cert_pass)
|
|
44
|
+
connection.connect do |socket|
|
|
45
|
+
socket.write(notification.to_package)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Get the Feedback from Apple
|
|
50
|
+
#
|
|
51
|
+
# @return <Array[FeedbackTuple]> A feedback tuple contains the time
|
|
52
|
+
# when Apple determined that the app no longer exists on the device,
|
|
53
|
+
# and a the token of device token
|
|
54
|
+
def get_feedback
|
|
55
|
+
connection = APNS::Connection.new(@feedback_host, @feedback_port,
|
|
56
|
+
@cert_path, @cert_pass)
|
|
57
|
+
connection.connect do |socket|
|
|
58
|
+
feedback_tuples = []
|
|
59
|
+
while (data = socket.read(38))
|
|
60
|
+
tuple = data.unpack('N1n1H*')
|
|
61
|
+
feedback_tuples << FeedbackTuple.new(tuple[0], tuple[2])
|
|
62
|
+
end
|
|
63
|
+
feedback_tuples
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
# Handle the Feedback Object
|
|
70
|
+
#
|
|
71
|
+
# @!attribute time [Time] Time when the device was notified
|
|
72
|
+
# but didn't have the app installed
|
|
73
|
+
# @!attribute token [String] The Token of the device notified wrongly
|
|
74
|
+
class FeedbackTuple
|
|
75
|
+
attr_reader :time, :token
|
|
76
|
+
|
|
77
|
+
def initialize(timestamp, token)
|
|
78
|
+
@time = Time.at(timestamp)
|
|
79
|
+
@token = token
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end # class Client
|
|
83
|
+
end # module APNS
|
|
84
|
+
end # module BMO
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
module APNS
|
|
4
|
+
# Handle the connection state SSL or Pure TCP
|
|
5
|
+
class Connection
|
|
6
|
+
attr_reader :host, :port, :cert_path, :cert_pass
|
|
7
|
+
|
|
8
|
+
def initialize(host, port, cert_path = nil, cert_pass = nil)
|
|
9
|
+
@host = host
|
|
10
|
+
@port = port
|
|
11
|
+
@cert_path = cert_path
|
|
12
|
+
@cert_pass = cert_pass
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Create a connection to Apple. If a cert_path exists it uses SSL else
|
|
16
|
+
# a pure TCPSocket. It then yields the socket and handles the closing
|
|
17
|
+
#
|
|
18
|
+
# @return The yielded return
|
|
19
|
+
def connect(&block)
|
|
20
|
+
socket = cert_path ? ssl_socket : tcp_socket
|
|
21
|
+
|
|
22
|
+
yielded = yield socket
|
|
23
|
+
|
|
24
|
+
socket.close
|
|
25
|
+
yielded
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# @return [TCPSocket]
|
|
31
|
+
def tcp_socket
|
|
32
|
+
TCPSocket.new(host, port)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [SSLSocket] the SSLSocket connected and setted to sync_close
|
|
36
|
+
# to sync tcp_socket and ssl_socket closing.
|
|
37
|
+
def ssl_socket
|
|
38
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
|
|
39
|
+
ssl_socket.sync_close = true
|
|
40
|
+
ssl_socket.connect
|
|
41
|
+
ssl_socket
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @return [SSLContext] SSLContext setted with the certificate
|
|
45
|
+
#
|
|
46
|
+
def ssl_context
|
|
47
|
+
cert = File.read(cert_path)
|
|
48
|
+
context = OpenSSL::SSL::SSLContext.new
|
|
49
|
+
context.cert = OpenSSL::X509::Certificate.new(cert)
|
|
50
|
+
context.key = OpenSSL::PKey::RSA.new(cert, cert_pass)
|
|
51
|
+
context
|
|
52
|
+
end
|
|
53
|
+
end # class Connection
|
|
54
|
+
end # module APNS
|
|
55
|
+
end # module BMO
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
module APNS
|
|
4
|
+
# The Notification Class handles all the packaging logic
|
|
5
|
+
class Notification
|
|
6
|
+
# Define ==
|
|
7
|
+
include Equalizer.new(:device_token, :payload)
|
|
8
|
+
|
|
9
|
+
attr_reader :device_token, :payload
|
|
10
|
+
|
|
11
|
+
def initialize(device_token, payload)
|
|
12
|
+
@device_token = DeviceToken.new(device_token)
|
|
13
|
+
@payload = Payload.new(payload)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_package
|
|
17
|
+
payload_packaged = payload.to_package
|
|
18
|
+
device_token_packaged = device_token.to_package
|
|
19
|
+
[
|
|
20
|
+
0, 0,
|
|
21
|
+
device_token_packaged.size,
|
|
22
|
+
device_token_packaged,
|
|
23
|
+
0,
|
|
24
|
+
payload_packaged.size,
|
|
25
|
+
payload_packaged
|
|
26
|
+
].pack('ccca*cca*')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def validate!
|
|
30
|
+
device_token.validate!
|
|
31
|
+
payload.validate!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# The Payload contains the data sent to Apple
|
|
37
|
+
class Payload
|
|
38
|
+
class PayloadTooLarge < Exception; end
|
|
39
|
+
|
|
40
|
+
MAX_BYTE_SIZE = 256
|
|
41
|
+
|
|
42
|
+
# Define ==
|
|
43
|
+
include Equalizer.new(:data)
|
|
44
|
+
|
|
45
|
+
attr_reader :data
|
|
46
|
+
|
|
47
|
+
def initialize(data)
|
|
48
|
+
@data = Utils.coerce_to_symbols(data)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def to_package
|
|
52
|
+
data.to_json.bytes.to_a.pack('C*')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def validate!
|
|
56
|
+
if to_package.size > MAX_BYTE_SIZE
|
|
57
|
+
str = <<-EOS
|
|
58
|
+
Payload size should be less than #{Payload::MAX_BYTE_SIZE} bytes"
|
|
59
|
+
EOS
|
|
60
|
+
fail PayloadTooLarge, str
|
|
61
|
+
end
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
end # class Payload
|
|
65
|
+
|
|
66
|
+
# The DeviceToken is the id of a Device for an App
|
|
67
|
+
class DeviceToken
|
|
68
|
+
# Define ==
|
|
69
|
+
include Equalizer.new(:token)
|
|
70
|
+
|
|
71
|
+
class MalformedDeviceToken < Exception; end
|
|
72
|
+
|
|
73
|
+
attr_reader :token
|
|
74
|
+
|
|
75
|
+
def initialize(token)
|
|
76
|
+
@token = token
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def to_package
|
|
80
|
+
[token].pack('H*')
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def validate!
|
|
84
|
+
unless token =~ /^[a-z0-9]{64}$/i
|
|
85
|
+
fail(MalformedDeviceToken, 'Malformed Device Token')
|
|
86
|
+
end
|
|
87
|
+
true
|
|
88
|
+
end
|
|
89
|
+
end # class DeviceToken
|
|
90
|
+
end # class Notification
|
|
91
|
+
end # module APNS
|
|
92
|
+
end # module BMO
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# Main BMO module
|
|
3
|
+
module BMO
|
|
4
|
+
# Handles all the configuration per provider
|
|
5
|
+
class Configuration
|
|
6
|
+
attr_reader :apns, :gcm
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@apns = APNS.new
|
|
10
|
+
@gcm = GCM.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# APNS Configuration
|
|
14
|
+
#
|
|
15
|
+
# @!attribute gateway_host
|
|
16
|
+
# @!attribute gateway_port
|
|
17
|
+
# @!attribute feedback_host
|
|
18
|
+
# @!attribute feedback_port
|
|
19
|
+
# @!attribute cert_path
|
|
20
|
+
# @!attribute cert_pass
|
|
21
|
+
class APNS
|
|
22
|
+
attr_accessor :cert_path, :cert_pass,
|
|
23
|
+
:gateway_host, :gateway_port,
|
|
24
|
+
:feedback_host, :feedback_port
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@gateway_host = 'gateway.push.apple.com'
|
|
28
|
+
@gateway_port = 2195
|
|
29
|
+
@feedback_host = 'feedback.push.apple.com'
|
|
30
|
+
@feedback_port = 2196
|
|
31
|
+
@cert_path = nil
|
|
32
|
+
@cert_pass = nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# GCM Configuration
|
|
37
|
+
class GCM
|
|
38
|
+
attr_accessor :gateway_url, :api_key
|
|
39
|
+
def initialize
|
|
40
|
+
@gateway_url = 'https://android.googleapis.com/gcm/send'
|
|
41
|
+
@api_key = nil
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end # class Configuration
|
|
45
|
+
|
|
46
|
+
module_function
|
|
47
|
+
|
|
48
|
+
def configure
|
|
49
|
+
yield(configuration) if block_given?
|
|
50
|
+
configuration
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def configuration
|
|
54
|
+
@configuration ||= Configuration.new
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Needed because we can't use module_function and attr_writer
|
|
58
|
+
# rubocop:disable TrivialAccessors
|
|
59
|
+
def configuration=(configuration)
|
|
60
|
+
@configuration = configuration
|
|
61
|
+
end
|
|
62
|
+
# rubocop:enable
|
|
63
|
+
|
|
64
|
+
def reset_configuration
|
|
65
|
+
@configuration = Configuration.new
|
|
66
|
+
end
|
|
67
|
+
end # BMO
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
module GCM
|
|
4
|
+
# GCM Client Class
|
|
5
|
+
class Client
|
|
6
|
+
attr_reader :gateway_url, :api_key
|
|
7
|
+
|
|
8
|
+
def initialize(gateway_url, api_key)
|
|
9
|
+
@gateway_url = gateway_url
|
|
10
|
+
@api_key = api_key
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @param notification [Notification] the notification to send to Google
|
|
14
|
+
#
|
|
15
|
+
def send_notification(notification)
|
|
16
|
+
connection = GCM::Connection.new(gateway_url, api_key)
|
|
17
|
+
connection.connect do |request|
|
|
18
|
+
request.body = notification.to_package
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end # class Client
|
|
22
|
+
end # module APNS
|
|
23
|
+
end # module BMO
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
module GCM
|
|
4
|
+
# Handle the connection state SSL or Pure TCP
|
|
5
|
+
class Connection
|
|
6
|
+
def initialize(gateway_url, api_key)
|
|
7
|
+
@gateway_url = gateway_url
|
|
8
|
+
@faraday_connection = Faraday::Connection.new(gateway_url)
|
|
9
|
+
@api_key = api_key
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def connect(&block)
|
|
13
|
+
faraday_connection.post(gateway_url) do |request|
|
|
14
|
+
request.headers.merge!(content_type: 'application/json',
|
|
15
|
+
authorization: "key=#{api_key}")
|
|
16
|
+
yield request
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
protected
|
|
21
|
+
|
|
22
|
+
attr_reader :faraday_connection, :gateway_url, :api_key
|
|
23
|
+
end # class Connection
|
|
24
|
+
end # module GCM
|
|
25
|
+
end # module BMO
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
module GCM
|
|
4
|
+
# The Notification Class handles all the packaging logic
|
|
5
|
+
class Notification
|
|
6
|
+
# Define ==
|
|
7
|
+
include Equalizer.new(:device_token, :payload)
|
|
8
|
+
|
|
9
|
+
attr_reader :device_token, :payload
|
|
10
|
+
|
|
11
|
+
def initialize(device_token, payload)
|
|
12
|
+
@device_token = device_token
|
|
13
|
+
@payload = Payload.new(payload)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_package
|
|
17
|
+
{
|
|
18
|
+
registration_ids: [device_token],
|
|
19
|
+
data: payload.to_package
|
|
20
|
+
}.to_json
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate!
|
|
24
|
+
payload.validate!
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
# The Payload contains the data sent to Apple
|
|
30
|
+
class Payload
|
|
31
|
+
# Error Raised when the payload packaged > MAX_BYTE_SIZE
|
|
32
|
+
class PayloadTooLarge < Exception; end
|
|
33
|
+
|
|
34
|
+
MAX_BYTE_SIZE = 4096
|
|
35
|
+
|
|
36
|
+
# Define ==
|
|
37
|
+
include Equalizer.new(:data)
|
|
38
|
+
|
|
39
|
+
attr_reader :data
|
|
40
|
+
|
|
41
|
+
def initialize(data)
|
|
42
|
+
@data = Utils.coerce_to_symbols(data)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_package
|
|
46
|
+
data
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def validate!
|
|
50
|
+
if to_package.size > MAX_BYTE_SIZE
|
|
51
|
+
str = <<-EOS
|
|
52
|
+
Payload size should be less than #{Payload::MAX_BYTE_SIZE} bytes"
|
|
53
|
+
EOS
|
|
54
|
+
fail PayloadTooLarge, str
|
|
55
|
+
end
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
end # class Payload
|
|
59
|
+
end # class Notification
|
|
60
|
+
end # module APNS
|
|
61
|
+
end # module BMO
|
data/lib/bmo/utils.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module BMO
|
|
3
|
+
# Utility module
|
|
4
|
+
module Utils
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
# Coerce string hash keys to symbols
|
|
8
|
+
def coerce_to_symbols(hash)
|
|
9
|
+
hash_symbolized = {}
|
|
10
|
+
hash.each_pair do |key, value|
|
|
11
|
+
key = key.to_sym if key.respond_to?(:to_sym)
|
|
12
|
+
hash_symbolized[key] = value
|
|
13
|
+
end
|
|
14
|
+
hash_symbolized
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/bmo/version.rb
ADDED
data/lib/bmo.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'openssl'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'equalizer'
|
|
7
|
+
require 'faraday'
|
|
8
|
+
|
|
9
|
+
require 'bmo/version'
|
|
10
|
+
require 'bmo/configuration'
|
|
11
|
+
require 'bmo/utils'
|
|
12
|
+
|
|
13
|
+
require 'bmo/apns/notification'
|
|
14
|
+
require 'bmo/apns/connection'
|
|
15
|
+
require 'bmo/apns/client'
|
|
16
|
+
|
|
17
|
+
require 'bmo/gcm/notification'
|
|
18
|
+
require 'bmo/gcm/connection'
|
|
19
|
+
require 'bmo/gcm/client'
|
|
20
|
+
|
|
21
|
+
# Main BMO namespace
|
|
22
|
+
module BMO
|
|
23
|
+
# All the methods will be Class Methods
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# Send ios notification with the configuration of BMO
|
|
27
|
+
# (see #BMO::Configuration)
|
|
28
|
+
#
|
|
29
|
+
# @param device_token [String]
|
|
30
|
+
# @param data [Hash] The data you want to send
|
|
31
|
+
#
|
|
32
|
+
# @return The Socket#write return
|
|
33
|
+
#
|
|
34
|
+
# @see https://developer.apple.com/library/ios/documentation/
|
|
35
|
+
# NetworkingInternet/Conceptual/RemoteNotificationsPG/
|
|
36
|
+
# Chapters/ApplePushService.html
|
|
37
|
+
def send_ios_notification(device_token, data)
|
|
38
|
+
notification = APNS::Notification.new(device_token, data)
|
|
39
|
+
apns_client.send_notification(notification)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Get the iOS Feedback tuples
|
|
43
|
+
#
|
|
44
|
+
# @return [Array<FeedbackTuple>] Feedback Object containing
|
|
45
|
+
# a time and a token
|
|
46
|
+
def get_ios_feedback
|
|
47
|
+
apns_client.get_feedback
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Send android notification with the configuration of BMO
|
|
51
|
+
# (see #BMO::Configuration)
|
|
52
|
+
#
|
|
53
|
+
# @param device_token [String]
|
|
54
|
+
# @param data [Hash] The data you want to send
|
|
55
|
+
#
|
|
56
|
+
# @return [Faraday::Response] The HTTP Response
|
|
57
|
+
#
|
|
58
|
+
# @see http://developer.android.com/google/gcm/server.html]
|
|
59
|
+
def send_android_notification(device_token, data)
|
|
60
|
+
notification = GCM::Notification.new(device_token, data)
|
|
61
|
+
android_client.send_notification(notification)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def apns_client
|
|
67
|
+
conf = BMO.configuration.apns
|
|
68
|
+
APNS::Client.new(conf.gateway_host,
|
|
69
|
+
conf.gateway_port,
|
|
70
|
+
conf.feedback_host,
|
|
71
|
+
conf.feedback_port,
|
|
72
|
+
cert_path: conf.cert_path,
|
|
73
|
+
cert_pass: conf.cert_pass)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def gcm_client
|
|
77
|
+
conf = BMO.configuration.gcm
|
|
78
|
+
GCM::Client.new(conf.gateway_url,
|
|
79
|
+
conf.api_key)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '../../../spec_helper'
|
|
4
|
+
|
|
5
|
+
describe BMO::APNS::Notification::DeviceToken do
|
|
6
|
+
describe '#token' do
|
|
7
|
+
it 'returns the token' do
|
|
8
|
+
device_token = described_class.new('abc')
|
|
9
|
+
expect(device_token.token).to eq('abc')
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#==' do
|
|
14
|
+
it 'returns true for equal device token' do
|
|
15
|
+
device_token = described_class.new('abc')
|
|
16
|
+
device_token_bis = described_class.new('abc')
|
|
17
|
+
expect(device_token == device_token_bis).to be_true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'returns true for equal device token' do
|
|
21
|
+
device_token = described_class.new('abc')
|
|
22
|
+
device_token_bis = described_class.new('abc')
|
|
23
|
+
expect(device_token).to eq(device_token_bis)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'returns false for equal device token' do
|
|
27
|
+
device_token = described_class.new('abc')
|
|
28
|
+
device_token_bis = described_class.new('def')
|
|
29
|
+
expect(device_token).to_not eq(device_token_bis)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'returns true for equal device token' do
|
|
33
|
+
device_token = described_class.new('abc')
|
|
34
|
+
device_token_bis = described_class.new('def')
|
|
35
|
+
expect(device_token == device_token_bis).to be_false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe '#validate!' do
|
|
40
|
+
it 'returns true if the token is 64 chars' do
|
|
41
|
+
device_token = described_class.new('a' * 64)
|
|
42
|
+
expect(device_token.validate!).to be_true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'returns false if the token is not 64 chars' do
|
|
46
|
+
device_token = described_class.new('a' * 63)
|
|
47
|
+
expect { device_token.validate! }.to raise_error
|
|
48
|
+
BMO::APNS::Notification::DeviceToken::MalformedDeviceToken
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'returns false if the token contains a special char' do
|
|
52
|
+
device_token = described_class.new(('a' * 63) + '"')
|
|
53
|
+
expect { device_token.validate! }.to raise_error
|
|
54
|
+
BMO::APNS::Notification::DeviceToken::MalformedDeviceToken
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '#to_package' do
|
|
59
|
+
it 'returns the packaged token' do
|
|
60
|
+
device_token = described_class.new('0' * 64)
|
|
61
|
+
expect(device_token.to_package).to eq("\x00" * 32)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe BMO::APNS::Notification::Payload do
|
|
67
|
+
it 'coerce hash keys to symbols' do
|
|
68
|
+
payload = described_class.new('Finn' => 'The Human')
|
|
69
|
+
expect(payload.data).to eq(Finn: 'The Human')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "doesn't coerce incompatible types" do
|
|
73
|
+
payload = described_class.new(1 => 'For Money')
|
|
74
|
+
expect(payload.data).to eq(1 => 'For Money')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'returns true for equality between coerced hash and symbolized hash ' do
|
|
78
|
+
payload = described_class.new('Jake' => 'The Dog')
|
|
79
|
+
expect(payload).to eq(described_class.new(Jake: 'The Dog'))
|
|
80
|
+
end
|
|
81
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bmo
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.8.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Antoine Lyset
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-01-07 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: equalizer
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.0.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.0.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.8.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.8.0
|
|
41
|
+
description: Push notifications to iOS and Android devices
|
|
42
|
+
email:
|
|
43
|
+
- antoinelyset@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- .gitignore
|
|
49
|
+
- .rspec
|
|
50
|
+
- Gemfile
|
|
51
|
+
- Gemfile.lock
|
|
52
|
+
- Guardfile
|
|
53
|
+
- LICENSE
|
|
54
|
+
- README.md
|
|
55
|
+
- bmo.gemspec
|
|
56
|
+
- bmo.png
|
|
57
|
+
- lib/bmo.rb
|
|
58
|
+
- lib/bmo/apns/client.rb
|
|
59
|
+
- lib/bmo/apns/connection.rb
|
|
60
|
+
- lib/bmo/apns/notification.rb
|
|
61
|
+
- lib/bmo/configuration.rb
|
|
62
|
+
- lib/bmo/gcm/client.rb
|
|
63
|
+
- lib/bmo/gcm/connection.rb
|
|
64
|
+
- lib/bmo/gcm/notification.rb
|
|
65
|
+
- lib/bmo/utils.rb
|
|
66
|
+
- lib/bmo/version.rb
|
|
67
|
+
- spec/bmo/apns/notification_spec.rb
|
|
68
|
+
- spec/spec_helper.rb
|
|
69
|
+
homepage: https://github.com/antoinelyset/bmo
|
|
70
|
+
licenses:
|
|
71
|
+
- MIT
|
|
72
|
+
metadata: {}
|
|
73
|
+
post_install_message:
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - '>='
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - '>='
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '0'
|
|
87
|
+
requirements: []
|
|
88
|
+
rubyforge_project:
|
|
89
|
+
rubygems_version: 2.1.11
|
|
90
|
+
signing_key:
|
|
91
|
+
specification_version: 4
|
|
92
|
+
summary: Push notifications to iOS and Android devices
|
|
93
|
+
test_files:
|
|
94
|
+
- spec/bmo/apns/notification_spec.rb
|
|
95
|
+
- spec/spec_helper.rb
|
|
96
|
+
has_rdoc:
|