KeyholeIO 0.1.1
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.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/keyholeio.gemspec +21 -0
- data/lib/keyholeio/version.rb +3 -0
- data/lib/keyholeio.rb +305 -0
- metadata +71 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/keyholeio.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "keyholeio/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "KeyholeIO"
|
7
|
+
s.version = Keyholeio::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Kishyr Ramdial"]
|
10
|
+
s.email = ["kishyr@immedia.co.za"]
|
11
|
+
s.homepage = "http://keyhole.io/"
|
12
|
+
s.summary = %q{Ruby library for Keyhole.IO's key-value pair database-as-a-service}
|
13
|
+
s.description = %q{Connect and utilise Keyhole.IO's key-value pair database using this simple library.}
|
14
|
+
|
15
|
+
#s.rubyforge_project = "keyholeio"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
data/lib/keyholeio.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
#
|
2
|
+
# Keyhole.IO Ruby API
|
3
|
+
# http://keyhole.io/developer/libraries
|
4
|
+
#
|
5
|
+
# By Kishyr Ramdial <kishyr@immedia.co.za>
|
6
|
+
# Revision date: 28 June 2011
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'cgi'
|
11
|
+
require 'json'
|
12
|
+
require 'net/http'
|
13
|
+
|
14
|
+
# Keyhole.IO API Server
|
15
|
+
$http = Net::HTTP.new("api.keyhole.io")
|
16
|
+
$version = "v1"
|
17
|
+
|
18
|
+
class KeyholeIO
|
19
|
+
attr_accessor :apikey, :token
|
20
|
+
|
21
|
+
def initialize(apikey, entity_options = nil)
|
22
|
+
@@apikey = apikey
|
23
|
+
unless entity_options.nil?
|
24
|
+
self.register_entity(entity_options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Entities
|
29
|
+
#
|
30
|
+
# POST /entity
|
31
|
+
# Creates an entity if it doesn't exist and returns a token. If an already exists, it'll return a new token.
|
32
|
+
def register_entity(options)
|
33
|
+
raw_response = self.class.post_data_with_apikey("/entity", options)
|
34
|
+
if raw_response["meta"]["status"].to_i == 200
|
35
|
+
@@token = raw_response["data"]["token"]
|
36
|
+
end
|
37
|
+
raw_response
|
38
|
+
end
|
39
|
+
|
40
|
+
# GET /entity
|
41
|
+
# Check if an entity exists, and return its description and its channel (if set) if it exists.
|
42
|
+
def check_entity(options)
|
43
|
+
self.class.get_data_with_apikey("/entity", options)
|
44
|
+
end
|
45
|
+
|
46
|
+
# DELETE /entity
|
47
|
+
# Deletes an entity and all its datastores.
|
48
|
+
def delete_entity(id)
|
49
|
+
_hash = { :apikey => @@apikey }
|
50
|
+
_identifier = { :id => id }
|
51
|
+
_hash.merge!(_identifier)
|
52
|
+
self.class.delete_data_with_token("/entity", _hash)
|
53
|
+
end
|
54
|
+
|
55
|
+
# PUT /entity
|
56
|
+
# Nullifies the token given preventing further access to its entity and datastores.
|
57
|
+
def nullify_entity_token
|
58
|
+
self.class.put_data_with_token("/entity")
|
59
|
+
end
|
60
|
+
|
61
|
+
# POST /entity/password
|
62
|
+
def change_password(oldpass, newpass)
|
63
|
+
options = { :old => oldpass, :new => newpass }
|
64
|
+
raw_response = self.class.post_data_with_token("/entity/password", options)
|
65
|
+
if raw_response["meta"]["status"].to_i == 200
|
66
|
+
@@token = raw_response["data"]["token"]
|
67
|
+
end
|
68
|
+
raw_response
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Datastore
|
73
|
+
#
|
74
|
+
# POST /datastore
|
75
|
+
# Create or update a datastore (set a value to a key)
|
76
|
+
# FIXME: doesn't support binary uploads
|
77
|
+
def set_datastore(key, value, meta = nil)
|
78
|
+
val = value
|
79
|
+
met = meta
|
80
|
+
|
81
|
+
if [Hash, Array].include?(value.class)
|
82
|
+
val = value.to_json
|
83
|
+
end
|
84
|
+
|
85
|
+
if meta and [Hash, Array].include?(meta.class)
|
86
|
+
met = meta.to_json
|
87
|
+
end
|
88
|
+
|
89
|
+
options = { :k => key, :v => val }
|
90
|
+
options[:meta] = met unless met.nil?
|
91
|
+
self.class.post_data_with_token("/datastore", options)
|
92
|
+
end
|
93
|
+
|
94
|
+
# GET /datastore
|
95
|
+
# Returns a paginated list of keys and values.
|
96
|
+
def get_all_datastores(options = nil)
|
97
|
+
self.class.get_data_with_token("/datastore", options)
|
98
|
+
end
|
99
|
+
|
100
|
+
# GET /datastore/key[/nestedkey]
|
101
|
+
# Returns the datastore for the given key or nested key.
|
102
|
+
def get_datastore(key)
|
103
|
+
self.class.get_data_with_token("/datastore/#{key}")
|
104
|
+
end
|
105
|
+
|
106
|
+
# DELETE /datastore/key
|
107
|
+
# Deletes a datastore (and all uploaded files) given a key. There is no undo!
|
108
|
+
def delete_datastore(key)
|
109
|
+
self.class.delete_data_with_token("/datastore/#{key}")
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# Groups
|
114
|
+
#
|
115
|
+
# POST /group
|
116
|
+
# Creates a new group using the apikey and an identifier (id)
|
117
|
+
def create_group(group_name)
|
118
|
+
self.class.post_data_with_apikey("/group", { :id => group_name })
|
119
|
+
end
|
120
|
+
|
121
|
+
# GET /group
|
122
|
+
# Lists all entities in a group
|
123
|
+
def get_group(group_name)
|
124
|
+
self.class.get_data_with_apikey("/group", { :id => group_name })
|
125
|
+
end
|
126
|
+
|
127
|
+
# PUT /group
|
128
|
+
# Adds an entity with identifier to the specified group.
|
129
|
+
def add_entity_to_group(group, entity)
|
130
|
+
options = { :id => group, :entity => entity }
|
131
|
+
self.class.put_data_with_apikey("/group", options)
|
132
|
+
end
|
133
|
+
|
134
|
+
# DELETE /group
|
135
|
+
# Remove an entity from a specified group.
|
136
|
+
def delete_entity_from_group(group, entity)
|
137
|
+
options = { :id => group, :entity => entity }
|
138
|
+
self.class.delete_data_with_apikey("/group", options)
|
139
|
+
end
|
140
|
+
|
141
|
+
# DELETE /group/rm
|
142
|
+
# Deletes the specified group completely (but not its entities)
|
143
|
+
def delete_group(group_name)
|
144
|
+
self.class.delete_data_with_apikey("/group/rm", { :id => group_name })
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
# Messaging Clients
|
149
|
+
#
|
150
|
+
# POST /entity/messaging/type
|
151
|
+
# Adds a messaging client to an entity for messaging via Apple Push Notification, email.
|
152
|
+
def add_msg_client(type, client_id)
|
153
|
+
self.class.post_data_with_token("/entity/messaging/#{type}", { :id => client_id })
|
154
|
+
end
|
155
|
+
|
156
|
+
# GET /entity/messaging/type
|
157
|
+
# Checks if a messaging client of type {type} exists for an entity.
|
158
|
+
def check_msg_client(type, client_id)
|
159
|
+
self.class.get_data_with_token("/entity/messaging/#{type}", { :id => client_id })
|
160
|
+
end
|
161
|
+
|
162
|
+
# DELETE /entity/messaging/type
|
163
|
+
# Deletes a messaging client of type {type}.
|
164
|
+
def delete_msg_client(type, client_id)
|
165
|
+
self.class.delete_data_with_token("/entity/messaging/#{type}", { :id => client_id })
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
# Real-Time Streaming Channels
|
170
|
+
#
|
171
|
+
# POST /entity/channel
|
172
|
+
# Creates a channel and returns a channel name.
|
173
|
+
def create_channel
|
174
|
+
self.class.post_data_with_token("/entity/channel")
|
175
|
+
end
|
176
|
+
|
177
|
+
# GET /entity/channel
|
178
|
+
# Return how many clients are connected to the channel.
|
179
|
+
def total_clients_in_channel
|
180
|
+
self.class.get_data_with_token("/entity/channel")
|
181
|
+
end
|
182
|
+
|
183
|
+
# PUT /entity/channel
|
184
|
+
# Generates a new channel name and returns it.
|
185
|
+
def generate_new_channel_name
|
186
|
+
self.class.put_data_with_token("/entity/channel")
|
187
|
+
end
|
188
|
+
|
189
|
+
# DELETE /entity/channel
|
190
|
+
# Deletes the channel and stops sending messages to it.
|
191
|
+
def delete_channel
|
192
|
+
self.class.delete_data_with_token("/entity/channel")
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
# Generic Endpoints
|
197
|
+
# POST
|
198
|
+
def self.post_data_with_apikey(endpoint, options = nil)
|
199
|
+
_hash = { "apikey" => @@apikey }
|
200
|
+
_hash.merge!(options) unless options.nil?
|
201
|
+
self.post_data(endpoint, _hash)
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.post_data_with_token(endpoint, options = nil)
|
205
|
+
_hash = { "token" => @@token }
|
206
|
+
_hash.merge!(options) unless options.nil? unless options.nil?
|
207
|
+
self.post_data(endpoint, _hash)
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.post_data(endpoint, options = nil)
|
211
|
+
req = Net::HTTP::Post.new("/#{$version}#{endpoint}")
|
212
|
+
req.set_form_data(options) unless options.nil?
|
213
|
+
resp = $http.request(req)
|
214
|
+
JSON.parse(resp.body)
|
215
|
+
end
|
216
|
+
|
217
|
+
# GET
|
218
|
+
def self.get_data_with_apikey(endpoint, options = nil)
|
219
|
+
_hash = { "apikey" => @@apikey }
|
220
|
+
_hash.merge!(options)
|
221
|
+
self.get_data(endpoint, _hash)
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.get_data_with_token(endpoint, options = nil)
|
225
|
+
_hash = { "token" => @@token }
|
226
|
+
_hash.merge!(options) unless options.nil?
|
227
|
+
self.get_data(endpoint, _hash)
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.get_data(endpoint, options = nil)
|
231
|
+
req = nil
|
232
|
+
|
233
|
+
unless options.nil?
|
234
|
+
req = Net::HTTP::Get.new("/#{$version}#{endpoint}?".concat(options.to_url_params))
|
235
|
+
else
|
236
|
+
req = Net::HTTP::Get.new("/#{$version}#{endpoint}")
|
237
|
+
end
|
238
|
+
|
239
|
+
resp = $http.request(req)
|
240
|
+
JSON.parse(resp.body)
|
241
|
+
end
|
242
|
+
|
243
|
+
# DELETE
|
244
|
+
def self.delete_data_with_apikey(endpoint, options = nil)
|
245
|
+
_hash = { "apikey" => @@apikey }
|
246
|
+
_hash.merge!(options) unless options.nil?
|
247
|
+
self.delete_data(endpoint, _hash)
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.delete_data_with_token(endpoint, options = nil)
|
251
|
+
_hash = { "token" => @@token }
|
252
|
+
_hash.merge!(options) unless options.nil? unless options.nil?
|
253
|
+
self.delete_data(endpoint, _hash)
|
254
|
+
end
|
255
|
+
|
256
|
+
def self.delete_data(endpoint, options = nil)
|
257
|
+
req = nil
|
258
|
+
|
259
|
+
unless options.nil?
|
260
|
+
req = Net::HTTP::Delete.new("/#{$version}#{endpoint}?".concat(options.to_url_params))
|
261
|
+
else
|
262
|
+
req = Net::HTTP::Delete.new("/#{$version}#{endpoint}")
|
263
|
+
end
|
264
|
+
|
265
|
+
resp = $http.request(req)
|
266
|
+
JSON.parse(resp.body)
|
267
|
+
end
|
268
|
+
|
269
|
+
# PUT
|
270
|
+
def self.put_data_with_apikey(endpoint, options = nil)
|
271
|
+
_hash = { "apikey" => @@apikey }
|
272
|
+
_hash.merge!(options) unless options.nil?
|
273
|
+
self.put_data(endpoint, _hash)
|
274
|
+
end
|
275
|
+
|
276
|
+
def self.put_data_with_token(endpoint, options = nil)
|
277
|
+
_hash = { "token" => @@token }
|
278
|
+
_hash.merge!(options) unless options.nil?
|
279
|
+
self.put_data(endpoint, _hash)
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.put_data(endpoint, options = nil)
|
283
|
+
req = nil
|
284
|
+
|
285
|
+
unless options.nil?
|
286
|
+
req = Net::HTTP::Put.new("/#{$version}#{endpoint}?".concat(options.to_url_params))
|
287
|
+
else
|
288
|
+
req = Net::HTTP::Put.new("/#{$version}#{endpoint}")
|
289
|
+
end
|
290
|
+
req.set_form_data({})
|
291
|
+
resp = $http.request(req)
|
292
|
+
JSON.parse(resp.body)
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
class Hash
|
298
|
+
def to_url_params
|
299
|
+
elements = []
|
300
|
+
keys.size.times do |i|
|
301
|
+
elements << "#{CGI::escape(keys[i].to_s)}=#{CGI::escape(values[i].to_s)}"
|
302
|
+
end
|
303
|
+
elements.join("&")
|
304
|
+
end
|
305
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: KeyholeIO
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kishyr Ramdial
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-06-29 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Connect and utilise Keyhole.IO's key-value pair database using this simple library.
|
22
|
+
email:
|
23
|
+
- kishyr@immedia.co.za
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile
|
33
|
+
- Rakefile
|
34
|
+
- keyholeio.gemspec
|
35
|
+
- lib/keyholeio.rb
|
36
|
+
- lib/keyholeio/version.rb
|
37
|
+
homepage: http://keyhole.io/
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
hash: 3
|
51
|
+
segments:
|
52
|
+
- 0
|
53
|
+
version: "0"
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.8.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Ruby library for Keyhole.IO's key-value pair database-as-a-service
|
70
|
+
test_files: []
|
71
|
+
|