houston 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc1f9887759e151475336ef952b607870f3b29b3
4
- data.tar.gz: 1e09658a9c4177061c0e5137385779dcbee858e1
3
+ metadata.gz: 19ea781099fb74df316010704e9335580db3418c
4
+ data.tar.gz: bb5452a82ab13181e6fee98915a37799ae1dbe0d
5
5
  SHA512:
6
- metadata.gz: 537b0cd3c221e84bc6b156e33eebb07d65edf5c5eb79430b4755f48ad8a7d2fd6532570619d07d12fd17d0d8861b2b64b300b297f498469cacc9cf18e42e75bd
7
- data.tar.gz: 35b91cd235c889a02b2e18828f99c8ea5bcd0a3a67c85f30f69fb467466a97334676bf8365bd15df6fa518303251cc802491cc080359d4f63df91648e25bee02
6
+ metadata.gz: 24c557aa4a8ac29e937cc0f8c4ecccb2bd1218c3f204e3cf273d7c942646e0aa7cd7c01ddc5228ba8d6693ee46a0c65d1a732f2a8c50364ac7d452b8ca274390
7
+ data.tar.gz: 552d74c3ff780d5168fe3a3fda11b31e3da9292c3a13607cc8741fa088e76b4d1c52677bbbe7e40ebcd6c029ce1b7d0a2eed7341fb1525c089303fe95d467717
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- houston (1.0.0)
4
+ houston (2.0.0)
5
5
  commander (~> 4.1)
6
6
  json
7
7
 
@@ -12,13 +12,19 @@ GEM
12
12
  highline (~> 1.6.11)
13
13
  highline (1.6.19)
14
14
  json (1.8.1)
15
+ multi_json (1.8.0)
15
16
  rake (0.9.6)
16
17
  rspec (0.9.4)
18
+ simplecov (0.7.1)
19
+ multi_json (~> 1.0)
20
+ simplecov-html (~> 0.7.1)
21
+ simplecov-html (0.7.1)
17
22
 
18
23
  PLATFORMS
19
24
  ruby
20
25
 
21
26
  DEPENDENCIES
22
27
  houston!
23
- rake (~> 0.9)
24
- rspec (~> 0.6)
28
+ rake
29
+ rspec
30
+ simplecov
data/README.md CHANGED
@@ -60,6 +60,10 @@ connection.write(notification.message)
60
60
  connection.close
61
61
  ```
62
62
 
63
+ ## Versioning
64
+
65
+ Houston 2.0 supports the new [enhanced notification format](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW4). Support for the legacy notification format is available in 1.x releases.
66
+
63
67
  ## Command Line Tool
64
68
 
65
69
  Houston also comes with the `apn` binary, which provides a convenient way to test notifications from the command line.
data/houston.gemspec CHANGED
@@ -16,8 +16,9 @@ Gem::Specification.new do |s|
16
16
  s.add_dependency "commander", "~> 4.1"
17
17
  s.add_dependency "json"
18
18
 
19
- s.add_development_dependency "rspec", "~> 0.6"
20
- s.add_development_dependency "rake", "~> 0.9"
19
+ s.add_development_dependency "rspec"
20
+ s.add_development_dependency "rake"
21
+ s.add_development_dependency "simplecov"
21
22
 
22
23
  s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
23
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -71,7 +71,9 @@ module Houston
71
71
  end
72
72
 
73
73
  if error
74
- command, status, index = error.unpack("cci")
74
+ command, status, index = error.unpack("ccN")
75
+ # status == 10 means shutdown, and the given id is the last one successfully sent
76
+ index += 1 if status == 10
75
77
  notifications.slice!(0..index)
76
78
  notifications.each(&:mark_as_unsent!)
77
79
  push(*notifications)
@@ -4,7 +4,7 @@ module Houston
4
4
  class Notification
5
5
  MAXIMUM_PAYLOAD_SIZE = 256
6
6
 
7
- attr_accessor :token, :alert, :badge, :sound, :content_available, :custom_data, :id, :expiry
7
+ attr_accessor :token, :alert, :badge, :sound, :content_available, :custom_data, :id, :expiry, :priority
8
8
  attr_reader :sent_at
9
9
 
10
10
  alias :device :token
@@ -17,6 +17,7 @@ module Houston
17
17
  @sound = options.delete(:sound)
18
18
  @expiry = options.delete(:expiry)
19
19
  @id = options.delete(:id)
20
+ @priority = options.delete(:priority)
20
21
  @content_available = options.delete(:content_available)
21
22
 
22
23
  @custom_data = options
@@ -34,12 +35,12 @@ module Houston
34
35
  end
35
36
 
36
37
  def message
37
- json = payload.to_json
38
- device_token = [@token.gsub(/[<\s>]/, '')].pack('H*')
39
- @expiry ||= Time.now + 86400
40
- @id ||= 0
41
-
42
- [1, @id, @expiry.to_i, 0, 32, device_token, 0, json.bytes.count, json].pack('ciicca*cca*')
38
+ data = [device_token_item,
39
+ payload_item,
40
+ identifier_item,
41
+ expiration_item,
42
+ priority_item].compact.join
43
+ [2, data.bytes.count, data].pack('cNa*')
43
44
  end
44
45
 
45
46
  def mark_as_sent!
@@ -57,5 +58,28 @@ module Houston
57
58
  def valid?
58
59
  payload.to_json.bytesize <= MAXIMUM_PAYLOAD_SIZE
59
60
  end
61
+
62
+ private
63
+
64
+ def device_token_item
65
+ [1, 32, @token.gsub(/[<\s>]/, '')].pack('cnH*')
66
+ end
67
+
68
+ def payload_item
69
+ json = payload.to_json
70
+ [2, json.bytes.count, json].pack('cna*')
71
+ end
72
+
73
+ def identifier_item
74
+ [3, 4, @id].pack('cnN') unless @id.nil?
75
+ end
76
+
77
+ def expiration_item
78
+ [4, 4, @expiry].pack('cnN') unless @expiry.nil?
79
+ end
80
+
81
+ def priority_item
82
+ [5, 1, @priority].pack('cnc') unless @priority.nil?
83
+ end
60
84
  end
61
85
  end
@@ -1,3 +1,3 @@
1
1
  module Houston
2
- VERSION = "1.0.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -0,0 +1,199 @@
1
+ require 'spec_helper'
2
+
3
+ describe Houston::Notification do
4
+ let(:notification_options) {
5
+ {
6
+ token: '<ce8be627 2e43e855 16033e24 b4c28922 0eeda487 9c477160 b2545e95 b68b5969>',
7
+ alert: 'Houston, we have a problem.',
8
+ badge: 2701,
9
+ sound: 'sosumi.aiff',
10
+ expiry: 1234567890,
11
+ id: 42,
12
+ priority: 10,
13
+ content_available: true,
14
+ # custom data
15
+ key1: 1,
16
+ key2: 'abc'
17
+ }
18
+ }
19
+
20
+ subject { Houston::Notification.new(notification_options) }
21
+
22
+ its(:token) { should == '<ce8be627 2e43e855 16033e24 b4c28922 0eeda487 9c477160 b2545e95 b68b5969>' }
23
+ its(:alert) { should == 'Houston, we have a problem.' }
24
+ its(:badge) { should == 2701 }
25
+ its(:sound) { should == 'sosumi.aiff' }
26
+ its(:expiry) { should == 1234567890 }
27
+ its(:id) { should == 42 }
28
+ its(:priority) { should == 10 }
29
+ its(:content_available) { should be_true }
30
+ its(:custom_data) { should == { key1: 1, key2: 'abc' } }
31
+
32
+ context 'using :device instead of :token' do
33
+ subject do
34
+ notification_options[:device] = notification_options[:token]
35
+ notification_options.delete(:token)
36
+ Houston::Notification.new(notification_options)
37
+ end
38
+
39
+ its(:device) { '<ce8be627 2e43e855 16033e24 b4c28922 0eeda487 9c477160 b2545e95 b68b5969>' }
40
+ end
41
+
42
+ describe '#payload' do
43
+ it 'should create a compliant dictionary' do
44
+ subject.payload.should == {
45
+ 'aps' => {
46
+ 'alert' => 'Houston, we have a problem.',
47
+ 'badge' => 2701,
48
+ 'sound' => 'sosumi.aiff',
49
+ 'content-available' => 1
50
+ },
51
+ :key1 => 1,
52
+ :key2 => 'abc'
53
+ }
54
+ end
55
+
56
+ it 'should create a dictionary of only custom data and empty aps' do
57
+ Houston::Notification.new(key1: 123, key2: 'xyz').payload.should == {
58
+ 'aps' => {},
59
+ :key1 => 123,
60
+ :key2 => 'xyz'
61
+ }
62
+ end
63
+
64
+ it 'should create a dictionary only with alerts' do
65
+ Houston::Notification.new(alert: 'Hello, World!').payload.should == {
66
+ 'aps' => { 'alert' => 'Hello, World!' }
67
+ }
68
+ end
69
+
70
+ it 'should create a dictionary only with badges' do
71
+ Houston::Notification.new(badge: '123').payload.should == {
72
+ 'aps' => { 'badge' => 123 }
73
+ }
74
+ end
75
+
76
+ it 'should create a dictionary only with sound' do
77
+ Houston::Notification.new(sound: 'ring.aiff').payload.should == {
78
+ 'aps' => { 'sound' => 'ring.aiff' }
79
+ }
80
+ end
81
+
82
+ it 'should create a dictionary only with content-available' do
83
+ Houston::Notification.new(content_available: true).payload.should == {
84
+ 'aps' => { 'content-available' => 1 }
85
+ }
86
+ end
87
+
88
+ it 'should allow custom data inside aps key' do
89
+ notification_options = { :badge => 567, 'aps' => { 'loc-key' => 'my-key' } }
90
+ Houston::Notification.new(notification_options).payload.should == {
91
+ 'aps' => { 'loc-key' => 'my-key', 'badge' => 567 }
92
+ }
93
+ end
94
+ end
95
+
96
+ describe '#sent?' do
97
+ it 'should be false initially' do
98
+ subject.sent?.should be_false
99
+ end
100
+
101
+ it 'should be true after marking as sent' do
102
+ subject.mark_as_sent!
103
+ subject.sent?.should be_true
104
+ end
105
+
106
+ it 'should be false after marking as unsent' do
107
+ subject.mark_as_sent!
108
+ subject.mark_as_unsent!
109
+ subject.sent?.should be_false
110
+ end
111
+ end
112
+
113
+ describe '#message' do
114
+ it 'should create a message with command 2' do
115
+ command, _1, _2 = subject.message.unpack('cNa*')
116
+ command.should == 2
117
+ end
118
+
119
+ it 'should create a message with correct frame length' do
120
+ _1, length, _2 = subject.message.unpack('cNa*')
121
+ length.should == 182
122
+ end
123
+
124
+ def parse_items(items_stream)
125
+ items = []
126
+ until items_stream.empty?
127
+ item_id, item_length, items_stream = items_stream.unpack('cna*')
128
+ item_data, items_stream = items_stream.unpack("a#{item_length}a*")
129
+ items << [item_id, item_length, item_data]
130
+ end
131
+ items
132
+ end
133
+
134
+ it 'should include five items' do
135
+ _1, _2, items_stream = subject.message.unpack('cNa*')
136
+ parse_items(items_stream).should have(5).items
137
+ end
138
+
139
+ it 'should include an item #1 with the token as hexadecimal' do
140
+ _1, _2, items_stream = subject.message.unpack('cNa*')
141
+ items = parse_items(items_stream)
142
+ items.should include([1, 32, ['ce8be6272e43e85516033e24b4c289220eeda4879c477160b2545e95b68b5969'].pack('H*')])
143
+ end
144
+
145
+ it 'should include an item #2 with the payload as JSON' do
146
+ _1, _2, items_stream = subject.message.unpack('cNa*')
147
+ items = parse_items(items_stream)
148
+ items.should include([2, 126, '{"key1":1,"key2":"abc","aps":{"alert":"Houston, we have a problem.","badge":2701,"sound":"sosumi.aiff","content-available":1}}'])
149
+ end
150
+
151
+ it 'should include an item #3 with the identifier' do
152
+ _1, _2, items_stream = subject.message.unpack('cNa*')
153
+ items = parse_items(items_stream)
154
+ items.should include([3, 4, [42].pack('N')])
155
+ end
156
+
157
+ it 'should include an item #4 with the expiry' do
158
+ _1, _2, items_stream = subject.message.unpack('cNa*')
159
+ items = parse_items(items_stream)
160
+ items.should include([4, 4, [1234567890].pack('N')])
161
+ end
162
+
163
+ it 'should include an item #4 with the priority' do
164
+ _1, _2, items_stream = subject.message.unpack('cNa*')
165
+ items = parse_items(items_stream)
166
+ items.should include([5, 1, [10].pack('c')])
167
+ end
168
+
169
+ it 'might be missing the identifier item' do
170
+ notification_options.delete(:id)
171
+ notification = Houston::Notification.new(notification_options)
172
+ msg = notification.message
173
+ _1, _2, items_stream = notification.message.unpack('cNa*')
174
+ items = parse_items(items_stream)
175
+ items.should have(4).items
176
+ items.find { |item| item[0] == 3 }.should be_nil
177
+ end
178
+
179
+ it 'might be missing the expiry item' do
180
+ notification_options.delete(:expiry)
181
+ notification = Houston::Notification.new(notification_options)
182
+ msg = notification.message
183
+ _1, _2, items_stream = notification.message.unpack('cNa*')
184
+ items = parse_items(items_stream)
185
+ items.should have(4).items
186
+ items.find { |item| item[0] == 4 }.should be_nil
187
+ end
188
+
189
+ it 'might be missing the priority item' do
190
+ notification_options.delete(:priority)
191
+ notification = Houston::Notification.new(notification_options)
192
+ msg = notification.message
193
+ _1, _2, items_stream = notification.message.unpack('cNa*')
194
+ items = parse_items(items_stream)
195
+ items.should have(4).items
196
+ items.find { |item| item[0] == 5 }.should be_nil
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,10 @@
1
+ unless ENV['CI']
2
+ require 'simplecov'
3
+
4
+ SimpleCov.start do
5
+ add_filter '/spec/'
6
+ end
7
+ end
8
+
9
+ require 'houston'
10
+ require 'rspec'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: houston
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattt Thompson
@@ -42,30 +42,44 @@ dependencies:
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
- version: '0.6'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - '>='
53
53
  - !ruby/object:Gem::Version
54
- version: '0.6'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
- version: '0.9'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
- version: '0.9'
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Houston is a simple gem for sending Apple Push Notifications. Pass your
70
84
  credentials, construct your message, and send it.
71
85
  email: m@mattt.me
@@ -86,6 +100,8 @@ files:
86
100
  - ./LICENSE
87
101
  - ./Rakefile
88
102
  - ./README.md
103
+ - spec/notification_spec.rb
104
+ - spec/spec_helper.rb
89
105
  - bin/apn
90
106
  homepage: http://github.com/mattt/houston
91
107
  licenses:
@@ -111,4 +127,6 @@ rubygems_version: 2.0.3
111
127
  signing_key:
112
128
  specification_version: 4
113
129
  summary: Send Apple Push Notifications
114
- test_files: []
130
+ test_files:
131
+ - spec/notification_spec.rb
132
+ - spec/spec_helper.rb