pixeltrix-prowler 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,20 @@
1
+ *1.1.0 (July 10th, 2009)
2
+
3
+ * Add support for Delayed::Job background processing
4
+
5
+ * Update documentation for instance level configuration
6
+
7
+ * Add support for instance level configuration
8
+
9
+ * Add support for provider key
10
+
11
+ * Clean up implementation
12
+
13
+ * Remove unnecessary configuration
14
+
15
+ * Remove deprecated API
16
+
17
+
1
18
  *1.0.3 (July 9th, 2009)
2
19
 
3
20
  * Add verify method for configured API key
data/INSTALL CHANGED
@@ -32,6 +32,23 @@ To use Prowler within your application just call the notify method, e.g.
32
32
 
33
33
  Prowler.notify "Event", "Description", Prowler::Priority::NORMAL
34
34
 
35
+ If you need to send to multiple accounts from within a single application you
36
+ can create an instance of the Prowler class to override the global settings, e.g.
37
+
38
+ prowler = Prowler.new('apikey', 'application')
39
+ prowler.notify "Event", "Description", Prowler::Priority::NORMAL
40
+
41
+ If performance is a concern then there is built in support for Delayed::Job.
42
+ This can done either on a global basis, e.g.
43
+
44
+ Prowler.configure do |config|
45
+ config.delayed = true
46
+ end
47
+
48
+ or on a individual message basis, e.g.
49
+
50
+ Prowler.notify "Event", "Description", Prowler::Priority::NORMAL, true
51
+
35
52
  ABOUT
36
53
 
37
54
  Prowler relies upon the Prowl iPhone application which is advertised as
data/README CHANGED
@@ -32,6 +32,23 @@ To use Prowler within your application just call the notify method, e.g.
32
32
 
33
33
  Prowler.notify "Event", "Description", Prowler::Priority::NORMAL
34
34
 
35
+ If you need to send to multiple accounts from within a single application you
36
+ can create an instance of the Prowler class to override the global settings, e.g.
37
+
38
+ prowler = Prowler.new('apikey', 'application')
39
+ prowler.notify "Event", "Description", Prowler::Priority::NORMAL
40
+
41
+ If performance is a concern then there is built in support for Delayed::Job.
42
+ This can done either on a global basis, e.g.
43
+
44
+ Prowler.configure do |config|
45
+ config.delayed = true
46
+ end
47
+
48
+ or on a individual message basis, e.g.
49
+
50
+ Prowler.notify "Event", "Description", Prowler::Priority::NORMAL, true
51
+
35
52
  ABOUT
36
53
 
37
54
  Prowler relies upon the Prowl iPhone application which is advertised as
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.3
1
+ 1.1.0
data/lib/prowler.rb CHANGED
@@ -29,6 +29,23 @@
29
29
  #
30
30
  # Prowler.notify "Event", "Description", Prowler::Priority::NORMAL
31
31
  #
32
+ # If you need to send to multiple accounts from within a single application you
33
+ # can create an instance of the Prowler class to override the global settings, e.g.
34
+ #
35
+ # prowler = Prowler.new('apikey', 'application')
36
+ # prowler.notify "Event", "Description", Prowler::Priority::NORMAL
37
+ #
38
+ # If performance is a concern then there is built in support for Delayed::Job.
39
+ # This can done either on a global basis, e.g.
40
+ #
41
+ # Prowler.configure do |config|
42
+ # config.delayed = true
43
+ # end
44
+ #
45
+ # or on a individual message basis, e.g.
46
+ #
47
+ # Prowler.notify "Event", "Description", Prowler::Priority::NORMAL, true
48
+ #
32
49
  # === About
33
50
  #
34
51
  # Prowler relies upon the Prowl iPhone application which is advertised as
@@ -39,15 +56,13 @@
39
56
  # For more about the Prowl application see: http://prowl.weks.net/
40
57
 
41
58
  require 'logger'
42
- require 'net/http'
43
59
  require 'net/https'
60
+ require 'uri'
44
61
 
45
- module Prowler
62
+ class Prowler
46
63
 
47
- API_PATH = "/publicapi/add"
48
- DEPRECATED_API_PATH = "/api/add_notification.php?application=%s&event=%s&description=%s"
49
- VERIFY_PATH = "/publicapi/verify?apikey=%s"
50
- USER_AGENT = "Prowler/1.0.3"
64
+ SERVICE_URL = "https://prowl.weks.net/publicapi"
65
+ USER_AGENT = "Prowler/1.1.0"
51
66
 
52
67
  module Priority
53
68
  VERY_LOW = -2
@@ -57,50 +72,50 @@ module Prowler
57
72
  EMERGENCY = 2
58
73
  end
59
74
 
60
- class << self
61
- attr_accessor :host, :port, :secure
62
- attr_accessor :api_key, :username, :password
63
- attr_accessor :application, :send_notifications
75
+ class ConfigurationError < StandardError; end
64
76
 
65
- # The host to connect to.
66
- def host
67
- @host ||= 'prowl.weks.net'
68
- end
77
+ class DelayedJob
78
+ attr_accessor :api_key, :provider_key, :application
79
+ attr_accessor :event, :message, :priority
69
80
 
70
- # The port on which the service runs.
71
- def port
72
- @port || (secure ? 443 : 80)
81
+ def initialize #:nodoc:
82
+ yield self if block_given?
73
83
  end
74
84
 
75
- # Whether the service is running over SSL.
76
- def secure
77
- @secure.nil? ? true : !!@secure
85
+ # Send notification
86
+ def perform
87
+ prowler = Prowler.new(api_key, application, provider_key)
88
+ prowler.notify(event, message, priority, false)
78
89
  end
90
+ end
91
+
92
+ class << self
93
+ attr_accessor :api_key, :provider_key
94
+ attr_accessor :application, :send_notifications
95
+ attr_accessor :read_timeout, :open_timeout #:nodoc:
96
+ attr_accessor :delayed
79
97
 
80
98
  # Call this method to configure your account details in an initializer.
81
99
  def configure
82
100
  yield self
83
101
  end
84
102
 
85
- def username=(value) #:nodoc:
86
- logger.warn "The username/password API has been deprecated please switch to using an API key."
87
- @username = value
103
+ def send_notifications #:nodoc:
104
+ @send_notifications.nil? ? true : !!@send_notifications
88
105
  end
89
106
 
90
- # Whether to send notifications
91
- def send_notifications
92
- @send_notifications.nil? ? true : !!@send_notifications
107
+ def delayed #:nodoc:
108
+ @delayed.nil? ? false : !!@delayed
93
109
  end
94
- alias :send_notifications? :send_notifications
95
110
 
96
111
  # Reset configuration
97
112
  def reset_configuration
98
- @host = @port = @secure = @application = @username = @password = @api_key = nil
113
+ @application = @api_key = @provider_key = nil
99
114
  end
100
115
 
101
116
  # Whether the library has been configured
102
117
  def configured?
103
- !@application.nil? && (!@api_key.nil? || !(@username.nil? || @password.nil?))
118
+ !@application.nil? && !@api_key.nil?
104
119
  end
105
120
 
106
121
  # Returns the default logger or a logger that prints to STDOUT.
@@ -110,75 +125,146 @@ module Prowler
110
125
  @logger ||= Logger.new(STDERR)
111
126
  end
112
127
 
128
+ def read_timeout #:nodoc:
129
+ @read_timeout ||= 5
130
+ end
131
+
132
+ def open_timeout #:nodoc:
133
+ @open_timeout ||= 2
134
+ end
135
+
113
136
  # Send a notification to your iPhone:
114
137
  # * event: The title of notification you want to send.
115
138
  # * message: The text of the notification message you want to send.
116
139
  # * priority: The priority of the notification - see Prowler::Priority. (Optional)
117
- def notify(event, message, priority = Priority::NORMAL)
118
- raise RuntimeError, "Prowler needs to be configured first before using it" unless configured?
119
-
120
- http = Net::HTTP.new(host, port)
121
- http.use_ssl = secure
122
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
123
- http.start do
124
- headers = {
125
- 'User-Agent' => USER_AGENT
126
- }
127
- http.read_timeout = 5 # seconds
128
- http.open_timeout = 2 # seconds
129
- if api_key
130
- request = Net::HTTP::Post.new(API_PATH, headers)
131
- request.set_form_data({ 'apikey' => api_key, 'priority' => priority, 'application' => application, 'event' => event, 'description' => message })
132
- else
133
- request = Net::HTTP::Get.new(sprintf(DEPRECATED_API_PATH, URI.escape(application), URI.escape(event), URI.escape(message)), headers)
134
- request.basic_auth(username, password)
135
- end
136
- response = begin
137
- http.request(request) if send_notifications?
138
- rescue TimeoutError => e
139
- logger.error "Timeout while contacting the Prowl server."
140
- nil
141
- end
142
- case response
143
- when Net::HTTPSuccess then
144
- logger.info "Prowl Success: #{response.class}"
145
- when NilClass then
146
- # Do nothing
147
- else
148
- logger.error "Prowl Failure: #{response.class}\n#{response.body if response.respond_to? :body}"
149
- end
140
+ # * delayed: Whether to use Delayed::Job to send notifications. (Optional)
141
+ def notify(event, message, priority = Priority::NORMAL, delayed = self.delayed)
142
+ raise ConfigurationError, "You must provide an API key to send notifications" if api_key.nil?
143
+ raise ConfigurationError, "You must provide an application name to send notifications" if application.nil?
144
+ if delayed
145
+ enqueue_delayed_job(self, event, message, priority)
146
+ else
147
+ perform(
148
+ :add, api_key, provider_key,
149
+ {
150
+ :application => application,
151
+ :event => event,
152
+ :description => message,
153
+ :priority => priority
154
+ }
155
+ )
150
156
  end
151
157
  end
152
158
 
153
159
  # Verify the configured API key is valid
154
160
  def verify
155
- raise RuntimeError, "Prowler needs to be configured first before using it" unless api_key
156
-
157
- http = Net::HTTP.new(host, port)
158
- http.use_ssl = secure
159
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
160
- http.start do
161
- headers = {
162
- 'User-Agent' => USER_AGENT
163
- }
164
- http.read_timeout = 5 # seconds
165
- http.open_timeout = 2 # seconds
166
- request = Net::HTTP::Get.new(sprintf(VERIFY_PATH, api_key), headers)
167
- response = begin
168
- http.request(request) if send_notifications?
169
- rescue TimeoutError => e
170
- logger.error "Timeout while contacting the Prowl server."
171
- nil
172
- end
173
- case response
174
- when Net::HTTPSuccess then
175
- logger.info "Prowl Success: #{response.class}"
176
- true
177
- else
178
- logger.error "Prowl Failure: #{response.class}\n#{response.body if response.respond_to? :body}"
179
- false
161
+ raise ConfigurationError, "You must provide an API key to verify" if api_key.nil?
162
+ perform(:verify, api_key, provider_key, {}, :get)
163
+ end
164
+
165
+ def perform(command, api_key, provider_key, data = {}, method = :post) #:nodoc:
166
+ params = { :apikey => api_key, :provider_key => provider_key }.merge(data).delete_if { |k,v| v.nil? }
167
+ case method
168
+ when :post
169
+ perform_post(command, params)
170
+ else
171
+ perform_get(command, params)
172
+ end
173
+ end
174
+
175
+ def enqueue_delayed_job(config, event, message, priority) #:nodoc:
176
+ record = Delayed::Job.enqueue(DelayedJob.new do |job|
177
+ job.api_key = config.api_key
178
+ job.provider_key = config.provider_key
179
+ job.application = config.application
180
+ job.event = event
181
+ job.message = message
182
+ job.priority = priority
183
+ end)
184
+ !record.new_record?
185
+ end
186
+
187
+ private
188
+ def headers(extra_headers = {}) #:nodoc:
189
+ { 'User-Agent' => USER_AGENT }.merge(extra_headers)
190
+ end
191
+
192
+ def perform_get(command, params) #:nodoc:
193
+ url = URI.parse("#{SERVICE_URL}/#{command}?#{params.map{ |k,v| %(#{URI.encode(k.to_s)}=#{URI.encode(v.to_s)}) }.join('&')}")
194
+ request = Net::HTTP::Get.new("#{url.path}?#{url.query}", headers)
195
+ perform_request(url, request)
196
+ end
197
+
198
+ def perform_post(command, params) #:nodoc:
199
+ url = URI.parse("#{SERVICE_URL}/#{command}")
200
+ request = Net::HTTP::Post.new(url.path, headers)
201
+ request.form_data = params
202
+ perform_request(url, request)
203
+ end
204
+
205
+ def perform_request(url, request) #:nodoc:
206
+ http = Net::HTTP.new(url.host, url.port)
207
+ http.use_ssl = true
208
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
209
+ http.read_timeout = read_timeout
210
+ http.open_timeout = open_timeout
211
+ http.start do
212
+ begin
213
+ return true unless send_notifications
214
+ response = http.request(request)
215
+ case response
216
+ when Net::HTTPSuccess then
217
+ logger.info "Prowl Success: #{response.class}"
218
+ true
219
+ else
220
+ logger.error "Prowl Failure: #{response.class}\n#{response.body if response.respond_to? :body}"
221
+ false
222
+ end
223
+ rescue TimeoutError => e
224
+ logger.error "Timeout while contacting the Prowl server."
225
+ false
226
+ end
180
227
  end
181
228
  end
229
+ end
230
+
231
+ attr_accessor :api_key, :provider_key #:nodoc:
232
+ attr_accessor :application, :send_notifications #:nodoc:
233
+
234
+ # Create an instance for sending to different accounts within a single Rails application
235
+ # * api_key: Your API key.
236
+ # * application: The name of your application.
237
+ # * provider_key: Key to override the rate limit of 1000 requests per hour. (Optional)
238
+ def initialize(api_key, application, provider_key = nil)
239
+ @api_key, @application, @provider_key = api_key, application, provider_key
240
+ end
241
+
242
+ # Send a notification to your iPhone:
243
+ # * event: The title of notification you want to send.
244
+ # * message: The text of the notification message you want to send.
245
+ # * priority: The priority of the notification - see Prowler::Priority. (Optional)
246
+ # * delayed: Whether to use Delayed::Job to send notifications. (Optional)
247
+ def notify(event, message, priority = Priority::NORMAL, delayed = self.class.delayed)
248
+ raise ConfigurationError, "You must provide an API key to send notifications" if api_key.nil?
249
+ raise ConfigurationError, "You must provide an application name to send notifications" if application.nil?
250
+ if delayed
251
+ self.class.enqueue_delayed_job(self, event, message, priority)
252
+ else
253
+ self.class.perform(
254
+ :add, api_key, provider_key,
255
+ {
256
+ :application => application,
257
+ :event => event,
258
+ :description => message,
259
+ :priority => priority
260
+ }
261
+ )
182
262
  end
183
263
  end
264
+
265
+ # Verify the configured API key is valid
266
+ def verify
267
+ raise ConfigurationError, "You must provide an API key to verify" if api_key.nil?
268
+ self.class.perform(:verify, api_key, provider_key, {}, :get)
269
+ end
184
270
  end
data/prowler.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{prowler}
5
- s.version = "1.0.3"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Andrew White"]
9
- s.date = %q{2009-07-09}
9
+ s.date = %q{2009-07-10}
10
10
  s.description = %q{A simple wrapper class that provides basic access to the Prowl API.}
11
11
  s.email = %q{andyw@pixeltrix.co.uk}
12
12
  s.extra_rdoc_files = [
data/test/prowler_test.rb CHANGED
@@ -13,32 +13,14 @@ class ProwlerTest < Test::Unit::TestCase
13
13
 
14
14
  should "be done with a block" do
15
15
  Prowler.configure do |config|
16
- config.host = "prowler"
17
- config.port = 666
18
- config.secure = false
19
16
  config.api_key = "apikey"
20
17
  config.application = "application"
21
18
  end
22
19
 
23
- assert_equal "prowler", Prowler.host
24
- assert_equal 666, Prowler.port
25
- assert_equal false, Prowler.secure
26
20
  assert_equal "apikey", Prowler.api_key
27
21
  assert_equal "application", Prowler.application
28
22
  end
29
23
 
30
- should "set a default host" do
31
- assert_equal "prowl.weks.net", Prowler.host
32
- end
33
-
34
- should "set a default port" do
35
- assert_equal 443, Prowler.port
36
- end
37
-
38
- should "default to secure" do
39
- assert_equal true, Prowler.secure
40
- end
41
-
42
24
  should "not set a default application" do
43
25
  assert_equal nil, Prowler.application
44
26
  end
@@ -47,55 +29,63 @@ class ProwlerTest < Test::Unit::TestCase
47
29
  assert_equal nil, Prowler.api_key
48
30
  end
49
31
 
50
- should "raise an exception if not configured" do
51
- assert_raises RuntimeError do
52
- Prowler.notify("Event", "Description", Prowler::Priority::NORMAL)
53
- end
32
+ should "override class configuration when using an instance" do
33
+ prowler = Prowler.new("apikey2", "application2")
34
+ assert_equal "apikey2", prowler.api_key
35
+ assert_equal "application2", prowler.application
54
36
  end
55
37
  end
56
38
 
57
- context "Prowler deprecated configuration" do
39
+ context "Sending a notification" do
58
40
  setup do
59
- Logger.any_instance.stubs(:warn)
60
41
  Prowler.reset_configuration
42
+ Prowler.configure do |config|
43
+ config.api_key = "apikey"
44
+ config.application = "Application Name"
45
+ end
61
46
  Prowler.send_notifications = false
62
47
  end
63
48
 
64
- should "be done with a block" do
65
- Prowler.configure do |config|
66
- config.host = "prowler"
67
- config.port = 666
68
- config.secure = false
69
- config.application = "application"
70
- config.username = "username"
71
- config.password = "password"
49
+ should "raise an exception if API key not configured" do
50
+ Prowler.reset_configuration
51
+ assert_raises Prowler::ConfigurationError do
52
+ Prowler.notify("Event", "Description", Prowler::Priority::NORMAL)
72
53
  end
73
54
 
74
- assert_equal "username", Prowler.username
75
- assert_equal "password", Prowler.password
55
+ prowler = Prowler.new(nil, nil)
56
+ assert_raises Prowler::ConfigurationError do
57
+ prowler.notify("Event", "Description", Prowler::Priority::NORMAL)
58
+ end
76
59
  end
77
60
 
78
- should "log a warning when using the deprecated API" do
79
- Logger.any_instance.expects(:warn).with("The username/password API has been deprecated please switch to using an API key.")
80
- Prowler.configure { |config| config.username = "username" }
81
- end
61
+ should "raise an exception if application not configured" do
62
+ Prowler.reset_configuration
63
+ Prowler.configure do |config|
64
+ config.api_key = "apikey"
65
+ end
66
+ assert_raises Prowler::ConfigurationError do
67
+ Prowler.notify("Event", "Description", Prowler::Priority::NORMAL)
68
+ end
82
69
 
83
- should "not set a default username" do
84
- assert_equal nil, Prowler.username
70
+ prowler = Prowler.new("apikey", nil)
71
+ assert_raises Prowler::ConfigurationError do
72
+ prowler.notify("Event", "Description", Prowler::Priority::NORMAL)
73
+ end
85
74
  end
86
75
 
87
- should "not set a default password" do
88
- assert_equal nil, Prowler.password
76
+ should "not verify SSL certificates" do
77
+ Net::HTTP.any_instance.expects(:use_ssl=).with(true)
78
+ Net::HTTP.any_instance.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
79
+ Prowler.notify("Event Name", "Message Text", Prowler::Priority::NORMAL)
89
80
  end
90
81
 
91
- should "raise an exception if not configured" do
92
- assert_raises RuntimeError do
93
- Prowler.notify("Event", "Description", Prowler::Priority::NORMAL)
94
- end
82
+ should "not send notifications if send_notifications is false" do
83
+ Net::HTTP.any_instance.expects(:request).never
84
+ Prowler.notify("Event Name", "Message Text", Prowler::Priority::NORMAL)
95
85
  end
96
86
  end
97
87
 
98
- context "Sending a notification" do
88
+ context "Verifying an API key" do
99
89
  setup do
100
90
  Prowler.reset_configuration
101
91
  Prowler.configure do |config|
@@ -105,15 +95,27 @@ class ProwlerTest < Test::Unit::TestCase
105
95
  Prowler.send_notifications = false
106
96
  end
107
97
 
98
+ should "raise an exception if API key not configured" do
99
+ Prowler.reset_configuration
100
+ assert_raises Prowler::ConfigurationError do
101
+ Prowler.verify
102
+ end
103
+
104
+ prowler = Prowler.new(nil, nil)
105
+ assert_raises Prowler::ConfigurationError do
106
+ prowler.verify
107
+ end
108
+ end
109
+
108
110
  should "not verify SSL certificates" do
109
111
  Net::HTTP.any_instance.expects(:use_ssl=).with(true)
110
112
  Net::HTTP.any_instance.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
111
- Prowler.notify("Event Name", "Message Text", Prowler::Priority::NORMAL)
113
+ Prowler.verify
112
114
  end
113
115
 
114
116
  should "not send notifications if send_notifications is false" do
115
117
  Net::HTTP.any_instance.expects(:request).never
116
- Prowler.notify("Event Name", "Message Text", Prowler::Priority::NORMAL)
118
+ Prowler.verify
117
119
  end
118
120
  end
119
121
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixeltrix-prowler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew White
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-09 00:00:00 -07:00
12
+ date: 2009-07-10 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15