apns-ruby 0.0.2 → 1.0.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -13
  3. data/lib/apns/connection.rb +31 -13
  4. metadata +2 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a82816830da1287822fead19cd690a9e6f9a8042
4
- data.tar.gz: cf75ab95b88a81f4b3415182744c3ddf5888e760
3
+ metadata.gz: fb5a30cf2461e888a174d71c290a566c23bd41d7
4
+ data.tar.gz: 0bd5422d9e7656b5937489728528fcc66f11b745
5
5
  SHA512:
6
- metadata.gz: 8426a8e9f97f4ee0ba56d8b619d3c6588ab7e801db21aacad8e4f1a5ba13a2c8fb208a67061189c2a2214d3f24e46641e3c7c19d8727eac80f8af7991878620b
7
- data.tar.gz: 2e4ef8e08692bf8228aa6a280c9f72d28efbda116d84b6e44be8e80db2c1d2bc5d7394afdd638b137aac6867bd57ee80ffacc8452c62c9a79cefba3fae34236b
6
+ metadata.gz: 9e5b3605fdfc3bbd279b93f4ec8348e171a0c5b8be8c371b07a104993d199fbaf8a0580e93e797bbe702dc5b2b4585ac761235aa1fa577ee14e3465d48fa3993
7
+ data.tar.gz: 7285ff7bf0688969409368e5434bc7246e6bd2e9768f8a15d1422ef27b6c4b6d09414a444d7e9c1ac23a5e2c2e7a1cd621b9491e782daea653145cdd5ec02ccf
data/README.md CHANGED
@@ -4,6 +4,8 @@ This gem sends APNS notifications with proper error handling. Most importantly,
4
4
  * Storing notifications in a database, and have a separate process consume them. Worse, only a single consumer is ever allowed.
5
5
  * Opening a new SSL connection for every notification, which typically takes several hundred milliseconds. Imagine how long it would take to send a million notifications.
6
6
 
7
+ As of 2015-03-04, this gem has been powering [PicCollage](http://pic-collage.com/) for more than a year, sending more than 500 notifications per second at peak time, only to be limited by the devices database's throughput.
8
+
7
9
  Example usage:
8
10
  ```
9
11
  pem = path_to_your_pem_file
@@ -27,19 +29,8 @@ n1 = APNS::Notification.new(token, alert: 'hello')
27
29
  ne = APNS::Notification.new('bogustoken', alert: 'error')
28
30
  n2 = APNS::Notification.new(token, alert: 'world')
29
31
  conn.push([n1, ne, n2])
30
- # Should receive only a 'hello' notification on your device
31
-
32
- # Wait for Apple to report an error and close the connection on their side, due to
33
- # the bogus token in the second notification.
34
- # We'll detect this and automatically retry and invoke your error handler.
35
- sleep(7)
36
- conn.push([APNS::Notification.new(token, alert: 'hello world 0')])
37
- sleep(7)
38
- conn.push([APNS::Notification.new(token, alert: 'hello world 1')])
39
-
40
- # 'Invalid token: bogustoken' is printed out
41
- # We should be receiving each and every successful notification with texts:
42
- # 'world', 'hello world 0', and 'hello world 1'.
32
+ # 'Invalid token: bogustoken' is printed out.
33
+ # Moreover, we should be receiving each and every successful notification with texts 'hello' and 'world'.
43
34
  ```
44
35
 
45
36
  A great amount of code in this gem is copied from https://github.com/jpoz/APNS , many thanks to his pioneering work. This work itself is licensed under the MIT license.
@@ -20,6 +20,14 @@ class Connection
20
20
  @host = host
21
21
  @port = port
22
22
 
23
+ # Our current strategy is to read errors emitted by the APNS in a separate
24
+ # thread spawned when we open a new connection (read_errors method).
25
+ # If this thread receives an error information from the @ssl, it turns on
26
+ # the @lock, so that no direct write operation can be performed on the same
27
+ # Connection instance.
28
+ #
29
+ @lock = Mutex.new
30
+
23
31
  @sock, @ssl = open_connection
24
32
  ObjectSpace.define_finalizer(self, self.class.finalize(@sock, @ssl))
25
33
  end
@@ -31,8 +39,8 @@ class Connection
31
39
  end
32
40
 
33
41
  def push ns
34
- # The notification identifier is set to 4 bytes in the APNS protocol. Thus,
35
- # upon hitting this limit, read for failures and restart the counting again.
42
+ # The notification identifier is set to 4 bytes in the APNS protocol.
43
+ # Thus, upon hitting this limit, read for failures and restart the counting again.
36
44
  if @notifications.size + ns.size > MAX_32_BIT - 10
37
45
  code, failed_id = read_failure_info(timeout: 3)
38
46
  if failed_id
@@ -48,7 +56,7 @@ class Connection
48
56
  n.message_identifier = [@notifications.size].pack('N')
49
57
  @notifications.push(n)
50
58
  }
51
- write ns
59
+ @lock.synchronize{ write ns }
52
60
  end
53
61
 
54
62
 
@@ -57,16 +65,6 @@ class Connection
57
65
  def write ns
58
66
  packed = pack_notifications(ns)
59
67
  @ssl.write(packed)
60
- rescue Errno::EPIPE, Errno::ECONNRESET, OpenSSL::SSL::SSLError
61
- code, failed_id = read_failure_info(timeout: 30)
62
- reopen_connection
63
- return unless failed_id # there's nothing we can do
64
-
65
- @error_handler.call(code, @notifications.item_at(failed_id))
66
-
67
- @notifications.delete_where_index_less_than(failed_id+1)
68
- ns = @notifications.items_from(failed_id+1)
69
- retry
70
68
  end
71
69
 
72
70
  def pack_notifications notifications
@@ -105,9 +103,29 @@ class Connection
105
103
  ssl = OpenSSL::SSL::SSLSocket.new(sock,context)
106
104
  ssl.connect
107
105
 
106
+ Thread.new {
107
+ read_errors ssl
108
+ }
109
+
108
110
  return sock, ssl
109
111
  end
110
112
 
113
+ def read_errors ssl
114
+ tuple = ssl.read(6)
115
+
116
+ @lock.synchronize {
117
+ _, code, failed_id = tuple.unpack("ccN")
118
+ reopen_connection
119
+ return unless failed_id # there's nothing we can do
120
+
121
+ @error_handler.call(code, @notifications.item_at(failed_id))
122
+
123
+ @notifications.delete_where_index_less_than(failed_id+1)
124
+ ns = @notifications.items_from(failed_id+1)
125
+ write ns
126
+ }
127
+ end
128
+
111
129
  # Override inspect since we do not want to print out the entire @notifications,
112
130
  # whose size might be over tens of thousands
113
131
  def inspect
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apns-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - awaw
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-05 00:00:00.000000000 Z
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: APNS notifications sent properly with correct connection management and
14
14
  error handling
@@ -47,4 +47,3 @@ signing_key:
47
47
  specification_version: 4
48
48
  summary: APNS notifications sent properly
49
49
  test_files: []
50
- has_rdoc: