pyapns2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/pyapns2/version.rb +3 -0
  2. data/lib/pyapns2.rb +134 -0
  3. metadata +147 -0
@@ -0,0 +1,3 @@
1
+ class Pyapns2
2
+ VERSION = "1.0.0"
3
+ end
data/lib/pyapns2.rb ADDED
@@ -0,0 +1,134 @@
1
+ require 'net/http'
2
+ require 'xml/libxml/xmlrpc'
3
+
4
+ class Pyapns2
5
+
6
+ require 'pyapns2/version'
7
+
8
+ class Error < StandardError; end
9
+
10
+ attr_reader :host, :port
11
+
12
+ class ProvisionedClient
13
+
14
+ attr_reader :client, :app_id
15
+
16
+ def initialize(client, app_id)
17
+ @client = client
18
+ @app_id = app_id
19
+ end
20
+
21
+ # See Pyapns2::Client#notify, with the exception this version prefills in the app_id.
22
+ def notify(token, notification = nil)
23
+ client.notify app_id, token, notification
24
+ end
25
+
26
+ # See Pyapns2::Client#feedback, with the exception this version prefills in the app_id.
27
+ def feedback
28
+ client.feedback app_id
29
+ end
30
+
31
+ def inspect
32
+ "#<#{self.class.name} server=#{host}:#{port}, app_id=#{app_id}>"
33
+ end
34
+
35
+ end
36
+
37
+ # Returns a pre-provisioned client that also automatically prepends
38
+ # the app_id automatically to all api calls, making giving a simpler interface.
39
+ def self.provision(options = {})
40
+ host, port = options.delete(:host), options.delete(:port)
41
+ host ||= "localhost"
42
+ port ||= 7077
43
+ client = new(host, port)
44
+ client.provision(options)
45
+ ProvisionedClient.new client, options[:app_id]
46
+ end
47
+
48
+ def initialize(host = 'localhost', port = 7077)
49
+ raise ArgumentError, "host must be a string" unless host.is_a?(String)
50
+ raise ArgumentError, "port must be a number" unless port.is_a?(Numeric)
51
+ @host = host
52
+ @port = port
53
+ @http = Net::HTTP.new host, port
54
+ @xmlrpc = XML::XMLRPC::Client.new @http, "/"
55
+ end
56
+
57
+ def inspect
58
+ "#<#{self.class.name} server=#{host}:#{port}>"
59
+ end
60
+
61
+ # Given a hash of options, calls provision on the pyapns server. This
62
+ # expects the following options and will raise an ArgumentError if they're
63
+ # not given:
64
+ #
65
+ # :app_id - A String name for your application
66
+ # :timeout - A number (e.g. 15) for how long to time out after when connecting to the apn server
67
+ # :env / :environment - One of production or sandbox. The type of server to connect to.
68
+ # :cert - Either a path to the certificate file or the certificate contents as a string.
69
+ def provision(options)
70
+ options[:environment] = options.delete(:env) if options.has_key?(:env)
71
+ app_id = options[:app_id]
72
+ timeout = options[:timeout]
73
+ cert = options[:cert]
74
+ env = options[:environment]
75
+ raise ArgumentError, ":app_id must be a string" unless app_id.is_a?(String) && !app_id.strip.empty?
76
+ raise ArgumentError, ":cert must be a string" unless cert.is_a?(String) && !cert.strip.empty?
77
+ raise ArgumentError, ":environment (or :env) must be one of sandbox or production" unless %w(production sandbox).include?(env)
78
+ raise ArgumentError, ":timeout must be a valid integer" unless timeout.is_a?(Numeric) && timeout >= 0
79
+ @xmlrpc.call 'provision', app_id, cert, env, timeout
80
+ true
81
+ rescue LibXML::XML::XMLRPC::RemoteCallError => e
82
+ raise Error.new e.message
83
+ end
84
+
85
+ # The main notification endpoint. Takes the app_id as the first argument, and then one
86
+ # of three sets of notification data:
87
+ #
88
+ # 1. A single token (as a string) and notification (as a dictionary)
89
+ # 2. A hash of token to notifications.
90
+ # 3. An array of tokens mapping to an array of notifications.
91
+ #
92
+ # Under the hook, it will automatically convert it to the most appropriate form before continuing.
93
+ # Will raise ArgumentError if you attempt to pass in bad information.
94
+ def notify(app_id, token, notification = nil)
95
+ if token.is_a?(Hash)
96
+ token, notification = extra_notification_info_from_hash token
97
+ end
98
+ raise ArgumentError, "Please ensure you provide an app_id" unless app_id
99
+ raise ArgumentError, "Please ensure you provide a single notification or an array of notifications" unless typed_item_of(notification, Hash)
100
+ raise ArgumentError, "Please ensure you provide device tokens or a string of tokens" unless typed_item_of(token, String)
101
+ types = [notification.is_a?(Array), token.is_a?(Array)]
102
+ if types.any? && !types.all?
103
+ raise ArgumentError, "The notifications and the strings must both be arrays if one is."
104
+ end
105
+ @xmlrpc.call 'notify', app_id, token, notification
106
+ true
107
+ rescue LibXML::XML::XMLRPC::RemoteCallError => e
108
+ raise Error.new e.message
109
+ end
110
+
111
+ # Takes an app id and returns the list of feedback from pyapns.
112
+ def feedback(app_id)
113
+ raise ArgumentError, "app_id must be provided" unless app_id
114
+ @xmlrpc.call('feedback', app_id).params
115
+ rescue LibXML::XML::XMLRPC::RemoteCallError => e
116
+ raise Error.new e.message
117
+ end
118
+
119
+ private
120
+
121
+ def extra_notification_info_from_hash(hash)
122
+ tokens, notifications = [], []
123
+ hash.each_pair do |k,v|
124
+ tokens << k
125
+ notifications << v
126
+ end
127
+ return tokens, notifications
128
+ end
129
+
130
+ def typed_item_of(value, klass)
131
+ value.is_a?(klass) || (value.is_a?(Array) && value.all? { |v| v.is_a?(klass) })
132
+ end
133
+
134
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pyapns2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Darcy Laycock
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: libxml-xmlrpc
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.4'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rr
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: webmock
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: vcr
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: ! 'Pyapns2 provides an alterantive, simpler client for the pyapns push
111
+ notification server, using libxml-xmlrpc to handle all of the xmlrpc.
112
+
113
+ It also is tested against Ruby 1.9'
114
+ email:
115
+ - darcy@filtersquad.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - lib/pyapns2/version.rb
121
+ - lib/pyapns2.rb
122
+ homepage: http://github.com/filtersquad
123
+ licenses: []
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: 1.3.6
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 1.8.24
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: An alternative ruby client for the pyapns push notification server with an
146
+ emphasis on Ruby 1.9 support.
147
+ test_files: []