apnotic 0.7.0 → 0.8.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: 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