datasift 1.5.0 → 2.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 (47) hide show
  1. data/.gitignore +1 -0
  2. data/LICENSE +1 -1
  3. data/README.md +6 -4
  4. data/VERSION +1 -1
  5. data/config.yml +2 -2
  6. data/datasift.gemspec +11 -11
  7. data/examples/historics.sh +2 -0
  8. data/examples/historics/create-from-csdl.rb +71 -0
  9. data/examples/historics/create-from-hash.rb +65 -0
  10. data/examples/historics/delete.rb +30 -0
  11. data/examples/historics/env.rb +37 -0
  12. data/examples/historics/list.rb +30 -0
  13. data/examples/historics/start.rb +30 -0
  14. data/examples/historics/stop.rb +30 -0
  15. data/examples/historics/view.rb +28 -0
  16. data/examples/push.sh +2 -0
  17. data/examples/push/delete.rb +33 -0
  18. data/examples/push/env.rb +53 -0
  19. data/examples/push/list.rb +30 -0
  20. data/examples/push/pause.rb +33 -0
  21. data/examples/push/push-from-hash.rb +72 -0
  22. data/examples/push/push-historic-from-csdl.rb +98 -0
  23. data/examples/push/push-stream-from-csdl.rb +70 -0
  24. data/examples/push/resume.rb +33 -0
  25. data/examples/push/stop.rb +33 -0
  26. data/examples/push/view-log.rb +45 -0
  27. data/examples/push/view.rb +31 -0
  28. data/lib/DataSift/apiclient.rb +20 -25
  29. data/lib/DataSift/definition.rb +97 -57
  30. data/lib/DataSift/exceptions.rb +25 -8
  31. data/lib/DataSift/historic.rb +321 -0
  32. data/lib/DataSift/mockapiclient.rb +23 -34
  33. data/lib/DataSift/push_definition.rb +115 -0
  34. data/lib/DataSift/push_subscription.rb +330 -0
  35. data/lib/DataSift/stream_consumer.rb +53 -70
  36. data/lib/DataSift/stream_consumer_http.rb +11 -15
  37. data/lib/DataSift/user.rb +189 -61
  38. data/lib/datasift.rb +5 -10
  39. data/test/helper.rb +80 -6
  40. data/test/test_definition.rb +0 -9
  41. data/test/test_historics.rb +233 -0
  42. data/test/test_pushdefinition.rb +92 -0
  43. data/test/test_pushsubscription.rb +17 -0
  44. data/test/test_user.rb +0 -6
  45. data/test/testdata.yml +26 -0
  46. metadata +38 -23
  47. data/test/test_live_api.rb +0 -100
@@ -1,27 +1,12 @@
1
- #
2
- # mockapiclient.rb - This file contains the MockApiClient class.
3
- #
4
- # Copyright (C) 2011 MediaSift Ltd
5
- #
6
- # == Overview
7
- #
8
- # The MockApiClient class implements a fake DataSift API interface.
9
-
10
1
  module DataSift
11
- # MockApiCLient class.
12
- #
13
- # == Introduction
14
- #
15
- # The ApiClient class implements a fake DataSift API interface.
16
- #
2
+ #The MockApiClient class implements a fake DataSift API interface.
17
3
  class MockApiClient
18
- # Set the response to be returned by the call method
19
- # === Parameters
20
- #
21
- # * +code+ - The HTTP response code
22
- # * +data+ - The dictionary that would have come from the response body
23
- # * +rate_limit+ - The new rate_limit value
24
- # * +rate_limit_remaining+ - The new rate_limit_remaining value
4
+ #Set the response to be returned by the call method
5
+ #=== Parameters
6
+ #* +code+ - The HTTP response code
7
+ #* +data+ - The dictionary that would have come from the response body
8
+ #* +rate_limit+ - The new rate_limit value
9
+ #* +rate_limit_remaining+ - The new rate_limit_remaining value
25
10
  def setResponse(code, data, rate_limit, rate_limit_remaining)
26
11
  @response = {
27
12
  'response_code' => code,
@@ -31,25 +16,29 @@ module DataSift
31
16
  }
32
17
  end
33
18
 
34
- # Clear the response so we throw an exception if we get called again
35
- # without a new response being set.
36
- #
19
+ #Clear the response so we throw an exception if we get called again
20
+ #without a new response being set.
37
21
  def clearResponse()
38
22
  @response = false
39
23
  end
40
24
 
41
- # Fake a call to a DataSift API endpoint.
42
- # === Parameters
43
- #
44
- # * +endpoint+ - The endpoint of the API call.
45
- # * +params+ - The parameters to be passed along with the request.
46
- # * +username+ - The username for the Auth header
47
- # * +api_key+ - The API key for the Auth header
48
- def call(username, api_key, endpoint, params = {}, user_agent = 'DataSiftPHP/0.0')
25
+ #Fake a call to a DataSift API endpoint.
26
+ #=== Parameters
27
+ #* +endpoint+ - The endpoint of the API call.
28
+ #* +params+ - The parameters to be passed along with the request.
29
+ #* +username+ - The username for the Auth header
30
+ #* +api_key+ - The API key for the Auth header
31
+ #=== Returns
32
+ #A Hash containing the following as set with the setResponse method...
33
+ #* +response_code+ - The HTTP response code.
34
+ #* +data+ - A Hash containing the response data.
35
+ #* +rate_limit+ - The total API credits you get per hour.
36
+ #* +rate_limit_remaining+ - The number of API credits you have remaining for this hour.
37
+ def call(username, api_key, endpoint, params = {}, user_agent = 'DataSiftRuby/0.0')
49
38
  if !@response
50
39
  raise StandardError, 'Expected response not set in mock object'
51
40
  end
52
- @response
41
+ return @response
53
42
  end
54
43
  end
55
44
  end
@@ -0,0 +1,115 @@
1
+ module DataSift
2
+ #The PushDefinition class represents a stream definition.
3
+ class PushDefinition
4
+ #Output parameter names are prefixed with this string before being sent to
5
+ #the API.
6
+ OUTPUT_PARAMS_PREFIX = 'output_params.'
7
+
8
+ #The initial status for subscriptions to this endpoint.
9
+ attr_accessor :initial_status
10
+ #The output type for this Push definition.
11
+ attr_accessor :output_type
12
+ #The output parameters for this Push definition.
13
+ attr_accessor :output_params
14
+
15
+ #Constructor. A User object is required.
16
+ #=== Parameters
17
+ #* +user+ - The DataSift::User object.
18
+ def initialize(user)
19
+ raise InvalidDataError, 'Please supply a valid User object when creating a Definition object.' unless user.is_a? DataSift::User
20
+ @user = user
21
+ @initial_status = ''
22
+ @output_type = ''
23
+ @output_params = {}
24
+ end
25
+
26
+ #Validate the output type and parameters with the DataSift API.
27
+ def validate()
28
+ begin
29
+ params = { 'output_type' => @output_type }
30
+ @output_params.each { |k,v| params[OUTPUT_PARAMS_PREFIX + k] = v }
31
+ @user.callAPI('push/validate', params)
32
+ rescue APIError => err
33
+ case err.http_code
34
+ when 400
35
+ raise InvalidDataError, err
36
+ else
37
+ raise APIError.new(err.http_code), 'Unexpected APIError code: ' + err.http_code.to_s + ' [' + err.message + ']'
38
+ end
39
+ end
40
+ end
41
+
42
+ #Subscribe this endpoint to a Definition.
43
+ #=== Parameters
44
+ #* +definition+ - The Definition object.
45
+ #* +name+ - A name for this subscription.
46
+ #=== Returns
47
+ #A PushSubscription object.
48
+ def subscribeDefinition(definition, name)
49
+ return subscribeStreamHash(definition.hash, name)
50
+ end
51
+
52
+ #Subscribe this endpoint to a stream hash.
53
+ #=== Parameters
54
+ #* +hash+ - The stream hash.
55
+ #* +name+ - A name for this subscription.
56
+ #=== Returns
57
+ #A PushSubscription object.
58
+ def subscribeStreamHash(hash, name)
59
+ return subscribe('hash', hash, name)
60
+ end
61
+
62
+ #Subscribe this endpoint to a Historics query.
63
+ #=== Parameters
64
+ #* +historic+ - The Historic object.
65
+ #* +name+ - A name for this subscription.
66
+ #=== Returns
67
+ #A PushSubscription object.
68
+ def subscribeHistoric(historic, name)
69
+ return subscribeHistoricPlaybackId(historic.hash, name)
70
+ end
71
+
72
+ #Subscribe this endpoint to a Historics playback ID.
73
+ #=== Parameters
74
+ #* +playback_id+ - The playback ID.
75
+ #* +name+ - A name for this subscription.
76
+ #=== Returns
77
+ #A PushSubscription object.
78
+ def subscribeHistoricPlaybackId(playback_id, name)
79
+ return subscribe('playback_id', playback_id, name)
80
+ end
81
+
82
+ #Subscribe this endpoint to a hash.
83
+ #=== Parameters
84
+ #* +hash_type+ - The hash type.
85
+ #* +hash+ - The hash.
86
+ #* +name+ - A name for this subscription.
87
+ #=== Returns
88
+ #A PushSubscription object.
89
+ def subscribe(hash_type, hash, name)
90
+ begin
91
+ # API call parameters
92
+ params = {
93
+ 'name' => name,
94
+ hash_type => hash,
95
+ 'output_type' => @output_type
96
+ }
97
+ # Output parameters with prefix
98
+ @output_params.each { |k,v| params[OUTPUT_PARAMS_PREFIX + k] = v }
99
+ # Add the initial status if it's not empty
100
+ params['initial_status'] = @initial_status unless @initial_status == ''
101
+
102
+ # Call the API and create a new PushSubscription from the returned
103
+ # object
104
+ return PushSubscription.new(@user, @user.callAPI('push/create', params))
105
+ rescue APIError => err
106
+ case err.http_code
107
+ when 400
108
+ raise InvalidDataError, err
109
+ else
110
+ raise APIError.new(err.http_code), 'Unexpected APIError code: ' + err.http_code.to_s + ' [' + err.message + ']'
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,330 @@
1
+ module DataSift
2
+ #The PushSubscription class represents a stream definition.
3
+ class PushSubscription < PushDefinition
4
+ #Constant for the stream hash type.
5
+ HASH_TYPE_STREAM = 'stream'
6
+ #Constant for the historic hash type.
7
+ HASH_TYPE_HISTORIC = 'historic'
8
+
9
+ #Constant for the "active" status.
10
+ STATUS_ACTIVE = 'active'
11
+ #Constant for the "paused" status.
12
+ STATUS_PAUSED = 'paused'
13
+ #Constant for the "stopped" status.
14
+ STATUS_STOPPED = 'stopped'
15
+ #Constant for the "finishing" status.
16
+ STATUS_FINISHING = 'finishing'
17
+ #Constant for the "finished" status.
18
+ STATUS_FINISHED = 'finished'
19
+ #Constant for the "failed" status.
20
+ STATUS_FAILED = 'failed'
21
+ #Constant for the "deleted" status.
22
+ STATUS_DELETED = 'deleted'
23
+
24
+ #Constant for the order by ID option.
25
+ ORDERBY_ID = 'id'
26
+ #Constant for the order by created_at option.
27
+ ORDERBY_CREATED_AT = 'created_at'
28
+ #Constant for the order by request_time option.
29
+ ORDERBY_REQUEST_TIME = 'request_time'
30
+
31
+ #Constant for ascending order option.
32
+ ORDERDIR_ASC = 'asc'
33
+ #Constnat for the descending order option.
34
+ ORDERDIR_DESC = 'desc'
35
+
36
+ #Get a single Push subscription by ID.
37
+ #=== Parameters
38
+ #* +id+ - The subscription ID.
39
+ #=== Returns
40
+ #A PushSubscription object.
41
+ def self.get(user, id)
42
+ return new(user, user.callAPI('push/get', { 'id' => id }))
43
+ end
44
+
45
+ #Get a page of Push subscriptions in the given user's account, where each
46
+ #page contains up to per_page items. Results will be ordered according to
47
+ #the supplied ordering parameters.
48
+ #=== Parameters
49
+ #* +user+ - The user object making the request.
50
+ #* +page+ - The page number to get.
51
+ #* +per_page+ - The number of items per page.
52
+ #* +order_by+ - The field by which to order the results.
53
+ #* +order_dir+ - Ascending or descending.
54
+ #* +include_finished+ - True to include subscriptions against finished Historics queries.
55
+ #* +hash_type+ - Optional hash type to look for (hash is also required)
56
+ #* +hash* - Optional hash to look for (hash_type is also required)
57
+ #=== Returns
58
+ #A Hash containing...
59
+ #* +count+ - The total number of matching Push subscriptions in your account.
60
+ #* +subscriptions+ - An array of Hashes where each Hash is a Push subscription.
61
+ def self.list(user, page = 1, per_page = 20, order_by = ORDERBY_CREATED_AT, order_dir = ORDERDIR_ASC, include_finished = false, hash_type = false, hash = false)
62
+ begin
63
+ raise InvalidDataError, 'The specified page number is invalid' unless page >= 1
64
+ raise InvalidDataError, 'The specified per_page value is invalid' unless per_page >= 1
65
+
66
+ params = {
67
+ 'page' => page,
68
+ 'per_page' => per_page,
69
+ 'order_by' => order_by,
70
+ 'order_dir' => order_dir
71
+ }
72
+
73
+ if hash_type and hash
74
+ params[hash_type] = hash
75
+ end
76
+
77
+ if include_finished
78
+ params['include_finished'] = 1
79
+ end
80
+
81
+ res = user.callAPI('push/get', params)
82
+
83
+ retval = { 'count' => res['count'], 'subscriptions' => [] }
84
+ for subscription in res['subscriptions']
85
+ retval['subscriptions'].push(new(user, subscription))
86
+ end
87
+ return retval
88
+ rescue APIError => err
89
+ case err.http_code
90
+ when 400
91
+ # Missing or invalid parameters
92
+ raise InvalidDataError, err
93
+ else
94
+ raise APIError.new(err.http_code), 'Unexpected APIError code: ' + err.http_code.to_s + ' [' + err.message + ']'
95
+ end
96
+ end
97
+ end
98
+
99
+ #Get a page of Push subscriptions for the given stream hash, where each
100
+ #page contains up to per_page items. Results will be ordered according to
101
+ #the supplied ordering parameters.
102
+ #=== Parameters
103
+ #* +user+ - The user object making the request.
104
+ #* +hash+ - The stream hash.
105
+ #* +page+ - The page number to get.
106
+ #* +per_page+ - The number of items per page.
107
+ #* +order_by+ - The field by which to order the results.
108
+ #* +order_dir+ - Ascending or descending.
109
+ #* +include_finished+ - True to include subscriptions against finished Historics queries.
110
+ #=== Returns
111
+ #A Hash containing...
112
+ #* +count+ - The total number of matching Push subscriptions in your account.
113
+ #* +subscriptions+ - An array of Hashes where each Hash is a Push subscription.
114
+ def self.listByStreamHash(user, hash, page = 1, per_page = 20, order_by = ORDERBY_CREATED_AT, order_dir = ORDERDIR_ASC)
115
+ return self.list(user, page, per_page, order_by, order_dir, false, 'hash', hash)
116
+ end
117
+
118
+ #Get a page of Push subscriptions for the given stream hash, where each
119
+ #page contains up to per_page items. Results will be ordered according to
120
+ #the supplied ordering parameters.
121
+ #=== Parameters
122
+ #* +user+ - The user object making the request.
123
+ #* +playback_id+ - The playback ID.
124
+ #* +page+ - The page number to get.
125
+ #* +per_page+ - The number of items per page.
126
+ #* +order_by+ - The field by which to order the results.
127
+ #* +order_dir+ - Ascending or descending.
128
+ #* +include_finished+ - True to include subscriptions against finished Historics queries.
129
+ #=== Returns
130
+ #A Hash containing...
131
+ #* +count+ - The total number of matching Push subscriptions in your account.
132
+ #* +subscriptions+ - An array of Hashes where each Hash is a Push subscription.
133
+ def self.listByPlaybackId(user, playback_id, page = 1, per_page = 20, order_by = ORDERBY_CREATED_AT, order_dir = ORDERDIR_ASC, include_finished = false)
134
+ return self.list(user, page, per_page, order_by, order_dir, include_finished, 'playback_id', playback_id)
135
+ end
136
+
137
+ #Page through recent Push subscription log entries, specifying the sort
138
+ #order.
139
+ #=== Parameters
140
+ #* +user+ - The user object making the request.
141
+ #* +page+ - The page number to get.
142
+ #* +per_page+ - The number of items per page.
143
+ #* +order_by+ - The field by which to order the results.
144
+ #* +order_dir+ - Ascending or descending.
145
+ #* +id+ - Optional subscription ID.
146
+ #=== Returns
147
+ #A Hash containing...
148
+ #* +count+ - The total number of matching log entries.
149
+ #* +log_entries+ - An array of Hashes where each Hash is a log entry.
150
+ def self.getLogs(user, page = 1, per_page = 20, order_by = ORDERBY_REQUEST_TIME, order_dir = ORDERDIR_DESC, id = false)
151
+ begin
152
+ raise InvalidDataError, 'The specified page number is invalid' unless page >= 1
153
+ raise InvalidDataError, 'The specified per_page value is invalid' unless per_page >= 1
154
+
155
+ params = {
156
+ 'page' => page,
157
+ 'per_page' => per_page,
158
+ 'order_by' => order_by,
159
+ 'order_dir' => order_dir
160
+ }
161
+
162
+ if id != false
163
+ params['id'] = id
164
+ end
165
+
166
+ return user.callAPI('push/log', params)
167
+ rescue APIError => err
168
+ case err.http_code
169
+ when 400
170
+ # Missing or invalid parameters
171
+ raise InvalidDataError, err
172
+ else
173
+ raise APIError.new(err.http_code), 'Unexpected APIError code: ' + err.http_code.to_s + ' [' + err.message + ']'
174
+ end
175
+ end
176
+ end
177
+
178
+ #The ID of this subscription.
179
+ attr_reader :id
180
+ #The date/time when this subscription was created.
181
+ attr_reader :created_at
182
+ #The friendly name of this subscription.
183
+ attr_reader :name
184
+ #The current status of this subscription.
185
+ attr_reader :status
186
+ #The stream hash or Historics query playback_id to which this subscription is subscribed.
187
+ attr_reader :hash
188
+ #The type of hash that hash is, 'stream' or 'historic'.
189
+ attr_reader :hash_type
190
+ #The date/time of the last time the subscription tried to push data to the endpoint, or null if it never has.
191
+ attr_reader :last_request
192
+ #The date/time of the last time the endpoint successfully accepted data from the subscription, or null if it never has.
193
+ attr_reader :last_success
194
+ #Whether this Push subscription has been deleted.
195
+ attr_reader :is_deleted
196
+
197
+ #Constructor. A User object is required, along with a Hash containing the
198
+ #subscription data.
199
+ #=== Parameters
200
+ #* +user+ - The DataSift::User object.
201
+ #* +data+ - The Hash containing the subscription data.
202
+ def initialize(user, data)
203
+ super(user)
204
+ init(data)
205
+ end
206
+
207
+ #Extract the subscription data from a Hash.
208
+ #=== Parameters
209
+ #* +data+ - The Hash containing the subscription data.
210
+ def init(data)
211
+ raise InvalidDataError, 'No id found' unless data.has_key?('id')
212
+ @id = data['id']
213
+
214
+ raise InvalidDataError, 'No name found' unless data.has_key?('name')
215
+ @name = data['name']
216
+
217
+ raise InvalidDataError, 'No created_at found' unless data.has_key?('created_at')
218
+ @created_at = DateTime.strptime(String(data['created_at']), '%s') unless data['created_at'].nil?
219
+
220
+ raise InvalidDataError, 'No status found' unless data.has_key?('status')
221
+ @status = data['status']
222
+
223
+ raise InvalidDataError, 'No hash_type found' unless data.has_key?('hash_type')
224
+ @hash_type = data['hash_type']
225
+
226
+ raise InvalidDataError, 'No hash found' unless data.has_key?('hash')
227
+ @hash = data['hash']
228
+
229
+ raise InvalidDataError, 'No last_request found' unless data.has_key?('last_request')
230
+ @last_request = DateTime.strptime(String(data['last_request']), '%s') unless data['last_request'].nil?
231
+
232
+ raise InvalidDataError, 'No last_success found' unless data.has_key?('last_success')
233
+ @last_success = DateTime.strptime(String(data['last_success']), '%s') unless data['last_success'].nil?
234
+
235
+ raise InvalidDataError, 'No output_type found' unless data.has_key?('output_type')
236
+ @output_type = data['output_type']
237
+
238
+ raise InvalidDataError, 'No output_params found' unless data.has_key?('output_params')
239
+ @output_params = parseOutputParams(data['output_params'])
240
+
241
+ @is_deleted = true if @status == STATUS_DELETED
242
+ end
243
+
244
+ #Reload the data for this subscription from the API.
245
+ def reload()
246
+ init(@user.callAPI('push/get', { 'id' => @id }))
247
+ end
248
+
249
+ #Name setter. Raises an InvalidDataError if this subscription has been
250
+ #deleted.
251
+ def name=(new_name)
252
+ raise InvalidDataError, 'Cannot set the name of a deleted Push subscription' unless not @is_deleted
253
+ @name = new_name
254
+ end
255
+
256
+ #Save changes to the name and output_params to the API.
257
+ def save()
258
+ raise InvalidDataError, 'Cannot save changes to a deleted Push subscription' unless not @is_deleted
259
+ params = {
260
+ 'id' => @id,
261
+ 'name' => @name
262
+ }
263
+ @output_params.each { |k,v| params[OUTPUT_PARAMS_PREFIX + k] = v }
264
+ init(@user.callAPI('push/update', params))
265
+ end
266
+
267
+ #Pause this subscription.
268
+ def pause()
269
+ raise InvalidDataError, 'Cannot pause a deleted Push subscription' unless not @is_deleted
270
+ init(@user.callAPI('push/pause', { 'id' => @id }))
271
+ end
272
+
273
+ #Resume this subscription.
274
+ def resume()
275
+ raise InvalidDataError, 'Cannot resume a deleted Push subscription' unless not @is_deleted
276
+ init(@user.callAPI('push/resume', { 'id' => @id }))
277
+ end
278
+
279
+ #Stop this subscription.
280
+ def stop()
281
+ raise InvalidDataError, 'Cannot stop a deleted Push subscription' unless not @is_deleted
282
+ init(@user.callAPI('push/stop', { 'id' => @id }))
283
+ end
284
+
285
+ #Delete this subscription.
286
+ def delete()
287
+ raise InvalidDataError, 'Cannot delete a deleted Push subscription' unless not @is_deleted
288
+ @user.callAPI('push/delete', { 'id' => @id })
289
+ # The delete API call does not return the object, so set the status
290
+ # manually.
291
+ @status = STATUS_DELETED
292
+ end
293
+
294
+ #Get a page of the log for this subscription, ordered as specified.
295
+ #=== Parameters
296
+ #* +page+ - The page number to get.
297
+ #* +per_page+ - The number of items per page.
298
+ #* +order_by+ - The field by which to order the results.
299
+ #* +order_dir+ - Ascending or descending.
300
+ #=== Returns
301
+ #A Hash containing...
302
+ #* +count+ - The total number of matching log entries.
303
+ #* +log_entries+ - An array of Hashes where each Hash is a log entry.
304
+ def getLog(page = 1, per_page = 20, order_by = ORDERBY_REQUEST_TIME, order_dir = ORDERDIR_DESC)
305
+ return PushSubscription.getLogs(@user, page, per_page, order_by, order_dir, @id)
306
+ end
307
+
308
+ private
309
+
310
+ #Recursive method to parse the output_params as received from the API into
311
+ #the flattened dot-notation used by the client libraries.
312
+ #=== Parameters
313
+ #* +params+ - A hash of parameters.
314
+ #* +prefix+ - The current key prefix.
315
+ #=== Returns
316
+ #A Hash containing the flattened data.
317
+ def parseOutputParams(params, prefix = '')
318
+ retval = {}
319
+ params.each do |k,v|
320
+ if v.kind_of?(Hash)
321
+ retval = retval.merge(parseOutputParams(v, prefix + k + '.'))
322
+ else
323
+ retval[prefix + k] = v
324
+ end
325
+ end
326
+ return retval
327
+ end
328
+
329
+ end
330
+ end