apnotic 0.7.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4ce6144cfd4d92ded62f555d22b37758855eb2cc
4
- data.tar.gz: c239e3fad3adb4a77629d638358eee7f91552c42
3
+ metadata.gz: 8304b356ec75720e4a6b0a1b969f42a6478fb989
4
+ data.tar.gz: 5ee9a617bc2abb21e3aa98ffd119c4ada2b978be
5
5
  SHA512:
6
- metadata.gz: 3fd69fe8c84117767cf19b448a3758bc309ca4d6c208e445aba50a71b3b1fb9f793e4b2bde12d2719a5c476eee2a5c5d1fe50424a2630f759c65e7eb69d63427
7
- data.tar.gz: db924a220d2c2084703ca2b10c0759b6b74a8d9f38833c5247781b69ad6d631290dbfd181119e677a0403229ec2e7e9cc749498f4486df18f89d79a0713f5b8e
6
+ metadata.gz: cfc56210bd04357a57c7187a513610e8a3de664cf3f9a41bbc0e27320ac0e89f7121ea8e32db0a980edb9dd8099c5fd830d6ebd968a615205c343c7819d32b7a
7
+ data.tar.gz: b59e06b515806102cab4add4675d180f967038790d0fb7ddfc6c92b04884d3c0eca2a826e5252d14221e35858293383cd879c2c1bda88f72aa783454fa2f9b2f
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency "http-2", "~> 0.8.1"
20
+ spec.add_dependency "net-http2", "~> 0.7.2"
21
21
  spec.add_dependency "connection_pool", "~> 2.0"
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.3"
@@ -1,8 +1,8 @@
1
1
  require 'apnotic/connection'
2
2
  require 'apnotic/connection_pool'
3
3
  require 'apnotic/notification'
4
+ require 'apnotic/request'
4
5
  require 'apnotic/response'
5
- require 'apnotic/stream'
6
6
  require 'apnotic/version'
7
7
 
8
8
  module Apnotic
@@ -1,7 +1,5 @@
1
- require 'socket'
1
+ require 'net-http2'
2
2
  require 'openssl'
3
- require 'uri'
4
- require 'http/2'
5
3
 
6
4
  module Apnotic
7
5
 
@@ -9,128 +7,45 @@ module Apnotic
9
7
  APPLE_PRODUCTION_SERVER_URI = "https://api.push.apple.com:443"
10
8
 
11
9
  class Connection
12
- attr_reader :uri, :cert_path
10
+ attr_reader :url, :cert_path
13
11
 
14
12
  class << self
15
13
  def development(options={})
16
- options.merge!(uri: APPLE_DEVELOPMENT_SERVER_URI)
14
+ options.merge!(url: APPLE_DEVELOPMENT_SERVER_URI)
17
15
  new(options)
18
16
  end
19
17
  end
20
18
 
21
19
  def initialize(options={})
22
- @uri = URI.parse(options[:uri] || APPLE_PRODUCTION_SERVER_URI)
20
+ @url = options[:url] || APPLE_PRODUCTION_SERVER_URI
23
21
  @cert_path = options[:cert_path]
24
22
  @cert_pass = options[:cert_pass]
25
23
 
26
- @pipe_r, @pipe_w = Socket.pair(:UNIX, :STREAM, 0)
27
- @socket_thread = nil
28
- @mutex = Mutex.new
29
-
30
- raise "URI needs to be a HTTPS address" if uri.scheme != 'https'
31
24
  raise "Cert file not found: #{@cert_path}" unless @cert_path && File.exist?(@cert_path)
25
+
26
+ @client = NetHttp2::Client.new(@url, ssl_context: ssl_context)
32
27
  end
33
28
 
34
29
  def push(notification, options={})
35
- open
36
-
37
- new_stream.push(notification, options)
30
+ request = Apnotic::Request.new(notification)
31
+ response = @client.post(request.path, request.body, request.headers, timeout: options[:timeout])
32
+ Apnotic::Response.new(headers: response.headers, body: response.body) if response
38
33
  end
39
34
 
40
35
  def close
41
- exit_thread(@socket_thread)
42
-
43
- @ssl_context = nil
44
- @h2 = nil
45
- @pipe_r = nil
46
- @pipe_w = nil
47
- @socket_thread = nil
36
+ @client.close
48
37
  end
49
38
 
50
39
  private
51
40
 
52
- def new_stream
53
- Apnotic::Stream.new(uri: @uri, h2_stream: h2.new_stream)
54
- end
55
-
56
- def open
57
- return if @socket_thread
58
-
59
- @socket_thread = Thread.new do
60
-
61
- socket = new_socket
62
-
63
- begin
64
- thread_loop(socket)
65
- ensure
66
- socket.close unless socket.closed?
67
- @socket_thread = nil
68
- end
69
- end.tap { |t| t.abort_on_exception = true }
70
- end
71
-
72
- def thread_loop(socket)
73
- loop do
74
-
75
- available = socket.pending
76
- if available > 0
77
- data_received = socket.sysread(available)
78
- h2 << data_received
79
- break if socket.nil? || socket.closed?
80
- end
81
-
82
- ready = IO.select([socket, @pipe_r])
83
-
84
- if ready[0].include?(@pipe_r)
85
- data_to_send = @pipe_r.read_nonblock(1024)
86
- socket.write(data_to_send)
87
- end
88
-
89
- if ready[0].include?(socket)
90
- data_received = socket.read_nonblock(1024)
91
- h2 << data_received
92
- break if socket.nil? || socket.closed?
93
- end
94
- end
95
- end
96
-
97
- def new_socket
98
- tcp = TCPSocket.new(@uri.host, @uri.port)
99
- socket = OpenSSL::SSL::SSLSocket.new(tcp, ssl_context)
100
- socket.sync_close = true
101
- socket.hostname = @uri.hostname
102
-
103
- socket.connect
104
-
105
- socket
106
- end
107
-
108
41
  def ssl_context
109
42
  @ssl_context ||= begin
110
43
  ctx = OpenSSL::SSL::SSLContext.new
111
44
  certificate = File.read(@cert_path)
112
- passphrase = @cert_pass
113
- ctx.key = OpenSSL::PKey::RSA.new(certificate, passphrase)
45
+ ctx.key = OpenSSL::PKey::RSA.new(certificate, @cert_pass)
114
46
  ctx.cert = OpenSSL::X509::Certificate.new(certificate)
115
47
  ctx
116
48
  end
117
49
  end
118
-
119
- def h2
120
- @h2 ||= HTTP2::Client.new.tap do |h2|
121
- h2.on(:frame) do |bytes|
122
- @mutex.synchronize do
123
- @pipe_w.write(bytes)
124
- @pipe_w.flush
125
- end
126
- end
127
- end
128
- end
129
-
130
- def exit_thread(thread)
131
- return unless thread && thread.alive?
132
- thread.exit
133
- thread.join
134
- end
135
50
  end
136
51
  end
@@ -0,0 +1,23 @@
1
+ module Apnotic
2
+
3
+ class Request
4
+ attr_reader :path, :headers, :body
5
+
6
+ def initialize(notification)
7
+ @path = "/3/device/#{notification.token}"
8
+ @headers = build_headers_for notification
9
+ @body = notification.body
10
+ end
11
+
12
+ private
13
+
14
+ def build_headers_for(notification)
15
+ h = {}
16
+ h.merge!('apns-id' => notification.apns_id) if notification.apns_id
17
+ h.merge!('apns-expiration' => notification.expiration) if notification.expiration
18
+ h.merge!('apns-priority' => notification.priority) if notification.priority
19
+ h.merge!('apns-topic' => notification.topic) if notification.topic
20
+ h
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Apnotic
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apnotic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roberto Ostinelli
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-27 00:00:00.000000000 Z
11
+ date: 2016-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: http-2
14
+ name: net-http2
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.8.1
19
+ version: 0.7.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.8.1
26
+ version: 0.7.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: connection_pool
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -103,8 +103,8 @@ files:
103
103
  - lib/apnotic/connection.rb
104
104
  - lib/apnotic/connection_pool.rb
105
105
  - lib/apnotic/notification.rb
106
+ - lib/apnotic/request.rb
106
107
  - lib/apnotic/response.rb
107
- - lib/apnotic/stream.rb
108
108
  - lib/apnotic/version.rb
109
109
  homepage: http://github.com/ostinelli/apnotic
110
110
  licenses:
@@ -1,71 +0,0 @@
1
- module Apnotic
2
-
3
- class Stream
4
-
5
- DEFAULT_TIMEOUT = 30
6
-
7
- def initialize(options={})
8
- @h2_stream = options[:h2_stream]
9
- @uri = options[:uri]
10
- @headers = {}
11
- @data = ''
12
- @completed = false
13
- @mutex = Mutex.new
14
- @cv = ConditionVariable.new
15
-
16
- @h2_stream.on(:headers) do |hs|
17
- hs.each { |k, v| @headers[k] = v }
18
- end
19
-
20
- @h2_stream.on(:data) { |d| @data << d }
21
- @h2_stream.on(:close) do
22
- @mutex.synchronize do
23
- @completed = true
24
- @cv.signal
25
- end
26
- end
27
- end
28
-
29
- def push(notification, options={})
30
- headers = build_headers_for notification
31
- body = notification.body
32
-
33
- @h2_stream.headers(headers, end_stream: false)
34
- @h2_stream.data(body, end_stream: true)
35
-
36
- respond(options)
37
- end
38
-
39
- private
40
-
41
- def build_headers_for(notification)
42
- headers = {
43
- ':scheme' => @uri.scheme,
44
- ':method' => 'POST',
45
- ':path' => "/3/device/#{notification.token}",
46
- 'host' => @uri.host,
47
- 'content-length' => notification.body.bytesize.to_s
48
- }
49
- headers.merge!('apns-id' => notification.apns_id) if notification.apns_id
50
- headers.merge!('apns-expiration' => notification.expiration) if notification.expiration
51
- headers.merge!('apns-priority' => notification.priority) if notification.priority
52
- headers.merge!('apns-topic' => notification.topic) if notification.topic
53
- headers
54
- end
55
-
56
- def respond(options={})
57
- options[:timeout] ||= DEFAULT_TIMEOUT
58
-
59
- @mutex.synchronize { @cv.wait(@mutex, options[:timeout]) }
60
-
61
- if @completed
62
- Apnotic::Response.new(
63
- headers: @headers,
64
- body: @data
65
- )
66
- else
67
- nil
68
- end
69
- end
70
- end
71
- end