em-ucengine 0.1.1 → 0.3.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.
- data/README.md +75 -27
- data/lib/em-ucengine.rb +3 -188
- data/lib/em-ucengine/brick.rb +177 -0
- data/lib/em-ucengine/brick_test.rb +27 -0
- data/lib/em-ucengine/client.rb +268 -0
- data/lib/em-ucengine/client_em.rb +239 -0
- data/lib/em-ucengine/client_nethttp.rb +97 -0
- data/lib/em-ucengine/errors.rb +21 -0
- data/lib/em-ucengine/utils.rb +46 -0
- metadata +132 -90
@@ -0,0 +1,27 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module UCEngine
|
3
|
+
module Brick
|
4
|
+
# A simple class to allowing you to test your bricks
|
5
|
+
module Test
|
6
|
+
# Return the instance of the brick
|
7
|
+
def brick
|
8
|
+
return @b unless @b.nil?
|
9
|
+
@b = app.new
|
10
|
+
@b.start MiniTest::Mock.new
|
11
|
+
@b
|
12
|
+
end
|
13
|
+
|
14
|
+
# Trigger a U.C.Engine event into the brick
|
15
|
+
#
|
16
|
+
# @param [String] name
|
17
|
+
# @param [Hash] data
|
18
|
+
def trigger(name, data={})
|
19
|
+
event = data.merge "type" => name
|
20
|
+
brick.routes[name].each do |proc|
|
21
|
+
brick.instance_exec(event, &proc)
|
22
|
+
end unless brick.routes[name].nil?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "uri"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
|
6
|
+
module UCEngine
|
7
|
+
class Client
|
8
|
+
|
9
|
+
# Create a new U.C.Engine client
|
10
|
+
#
|
11
|
+
# @param [String] Host of the U.C.Engine instance
|
12
|
+
# @param [Number] Port of the U.C.Engine instance
|
13
|
+
# @param [String] Entry point of the API
|
14
|
+
# @param [String] Version of U.C.Engine API
|
15
|
+
def initialize(host="localhost", port=5280, api_root="/api", api_version="0.6")
|
16
|
+
@host = host
|
17
|
+
@port = port
|
18
|
+
@root = api_root
|
19
|
+
@version = api_version
|
20
|
+
end
|
21
|
+
|
22
|
+
# Format url to api
|
23
|
+
#
|
24
|
+
# @param [String] Path of the method
|
25
|
+
def url(path)
|
26
|
+
URI.escape("http://#{@host}:#{@port}#{@root}/#{@version}#{path}")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get server time
|
30
|
+
def time(&block)
|
31
|
+
Session.new(self, nil, nil).time &block
|
32
|
+
end
|
33
|
+
|
34
|
+
# Connect to U.C.Engine
|
35
|
+
#
|
36
|
+
# @param [String] User name
|
37
|
+
# @param [String] Password
|
38
|
+
# @param [Hash] Metadata of the user
|
39
|
+
def connect(user, password, metadata=nil, &block)
|
40
|
+
body = { "name" => user, "credential" => password }
|
41
|
+
body["metadata"] = metadata if metadata
|
42
|
+
req = post(url("/presence"), {}, body)
|
43
|
+
answer_connect(req, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create a user
|
47
|
+
#
|
48
|
+
# @param [Hash] data
|
49
|
+
def create_user(data)
|
50
|
+
# FIXME: for now users can't be created with metadata.
|
51
|
+
answer post("/user", data), &block
|
52
|
+
end
|
53
|
+
|
54
|
+
# Session represent the U.C.Engine client with and sid and uid
|
55
|
+
# See #connect
|
56
|
+
class Session < Struct.new(:uce, :uid, :sid)
|
57
|
+
def url(*args)
|
58
|
+
uce.url(*args)
|
59
|
+
end
|
60
|
+
|
61
|
+
### Time - http://docs.ucengine.org/api.html#time ###
|
62
|
+
|
63
|
+
# Get server time
|
64
|
+
def time(&block)
|
65
|
+
answer get(url("/time")), &block
|
66
|
+
end
|
67
|
+
|
68
|
+
### Presence - http://docs.ucengine.org/api.html#authentication ###
|
69
|
+
|
70
|
+
# Get infos on the presence
|
71
|
+
#
|
72
|
+
# @param [String] Sid
|
73
|
+
def presence(sid, &block)
|
74
|
+
answer get(url("/presence/#{sid}")), &block
|
75
|
+
end
|
76
|
+
|
77
|
+
# Disconnect a user
|
78
|
+
#
|
79
|
+
# @param [String] Sid
|
80
|
+
def disconnect(sid, &block)
|
81
|
+
answer delete(url "/presence/#{sid}"), &block
|
82
|
+
end
|
83
|
+
|
84
|
+
### Users - http://docs.ucengine.org/api.html#user ###
|
85
|
+
|
86
|
+
# List users
|
87
|
+
def users(&block)
|
88
|
+
answer get(url "/user"), &block
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get user info
|
92
|
+
#
|
93
|
+
# @param [String] uid
|
94
|
+
def user(uid, &block)
|
95
|
+
answer get(url("/user/#{uid}")), &block
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create user
|
99
|
+
#
|
100
|
+
# @param [Hash] data
|
101
|
+
def create_user(data, &block)
|
102
|
+
answer post(url("/user"), data), &block
|
103
|
+
end
|
104
|
+
|
105
|
+
# Update user
|
106
|
+
#
|
107
|
+
# @param [String] uid
|
108
|
+
# @param [Hash] data
|
109
|
+
def update_user(uid, data, &block)
|
110
|
+
answer put(url("/user/#{uid}"), data), &block
|
111
|
+
end
|
112
|
+
|
113
|
+
# Delete a user
|
114
|
+
#
|
115
|
+
# @param [String] uid
|
116
|
+
def delete_user(uid, &block)
|
117
|
+
answer delete(url("/user/#{uid}")), &block
|
118
|
+
end
|
119
|
+
|
120
|
+
# Check user ACL
|
121
|
+
#
|
122
|
+
# @param [String] uid
|
123
|
+
# @param [String] action
|
124
|
+
# @param [String] object
|
125
|
+
# @param [Hash] conditions
|
126
|
+
# @param [String] meeting name
|
127
|
+
def user_can(uid, action, object, conditions={}, location="", &block)
|
128
|
+
answer_bool get(url("/user/#{uid}/can/#{action}/#{object}/#{location}"), :conditions => conditions), &block
|
129
|
+
end
|
130
|
+
|
131
|
+
### Meetings - http://docs.ucengine.org/api.html#meeting ###
|
132
|
+
|
133
|
+
# List meetings
|
134
|
+
#
|
135
|
+
def meetings(&block)
|
136
|
+
answer get(url "/meeting/"), &block
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get meeting
|
140
|
+
#
|
141
|
+
# @param [String] meeting
|
142
|
+
def meeting(meeting, &block)
|
143
|
+
answer get(url "/meeting/#{meeting}"), &block
|
144
|
+
end
|
145
|
+
|
146
|
+
# Create a meeting
|
147
|
+
#
|
148
|
+
# @param [String] meeting name
|
149
|
+
# @param [Hash] metadata
|
150
|
+
def create_meeting(meeting, body={}, &block)
|
151
|
+
body.merge!(:name => meeting)
|
152
|
+
answer post(url("/meeting/"), body), &block
|
153
|
+
end
|
154
|
+
|
155
|
+
# Update a meeting
|
156
|
+
#
|
157
|
+
# @param [String] meeting name
|
158
|
+
# @param [Hash] metadata
|
159
|
+
def update_meeting(meeting, body={}, &block)
|
160
|
+
answer put(url "/meeting//#{meeting}", body), &block
|
161
|
+
end
|
162
|
+
|
163
|
+
### Rosters - http://docs.ucengine.org/api.html#join-a-meeting ###
|
164
|
+
|
165
|
+
# List users on the meeting
|
166
|
+
#
|
167
|
+
# @param [String] meeting
|
168
|
+
def roster(meeting, &block)
|
169
|
+
answer get(url "/meeting/#{meeting}/roster"), &block
|
170
|
+
end
|
171
|
+
|
172
|
+
# Join the meeting
|
173
|
+
#
|
174
|
+
# @param [String] meeting
|
175
|
+
def join_roster(meeting, body={}, &block)
|
176
|
+
answer post(url "/meeting/#{meeting}/roster", body), &block
|
177
|
+
end
|
178
|
+
|
179
|
+
# Quit the meeting
|
180
|
+
#
|
181
|
+
# @param [String] meeting
|
182
|
+
# @param [String] uid
|
183
|
+
def quit_roster(meeting, uid=nil, &block)
|
184
|
+
answer delete(url "/meeting/#{meeting}/roster/#{uid || @uid}"), &block
|
185
|
+
end
|
186
|
+
|
187
|
+
### Events - http://docs.ucengine.org/api.html#events ###
|
188
|
+
|
189
|
+
# Get events
|
190
|
+
#
|
191
|
+
# @param [String] meeting
|
192
|
+
# @param [Hash] params
|
193
|
+
def events(meeting=nil, params={}, &block)
|
194
|
+
answer get(url("/event/#{meeting}"), params), &block
|
195
|
+
end
|
196
|
+
|
197
|
+
# Publish event
|
198
|
+
#
|
199
|
+
# @param [String] type
|
200
|
+
# @param [String] meeting
|
201
|
+
# @param [Hash] metadata
|
202
|
+
def publish(type, meeting=nil, metadata=nil, parent=nil, &block)
|
203
|
+
args = { :type => type, :uid => uid, :sid => sid }
|
204
|
+
args[:parent] = parent if parent
|
205
|
+
args[:metadata] = metadata if metadata
|
206
|
+
answer json_post(url("/event/#{meeting}"), args), &block
|
207
|
+
end
|
208
|
+
|
209
|
+
# Get event
|
210
|
+
#
|
211
|
+
# @param [String] id
|
212
|
+
def event(id, &block)
|
213
|
+
# Fixme: remove meeting fake param on the 0.7 release
|
214
|
+
answer get(url("/event/meeting/#{id}"), {}), &block
|
215
|
+
end
|
216
|
+
|
217
|
+
# Search
|
218
|
+
#
|
219
|
+
# @param [Hash] params
|
220
|
+
def search(params, &block)
|
221
|
+
answer get(url "/search/event/", params, &block)
|
222
|
+
end
|
223
|
+
|
224
|
+
### Files - http://docs.ucengine.org/api.html#upload-a-file ###
|
225
|
+
|
226
|
+
# Delete a file
|
227
|
+
#
|
228
|
+
# @param [String] meeting
|
229
|
+
# @param [String] filename
|
230
|
+
def delete_file(meeting, filename, &block)
|
231
|
+
answer delete(url("/file/#{meeting}/#{filename}")), &block
|
232
|
+
end
|
233
|
+
|
234
|
+
# List files on a meeting room
|
235
|
+
#
|
236
|
+
# @param [String] meeting
|
237
|
+
# @param [Hash] params
|
238
|
+
def files(meeting, params={}, &block)
|
239
|
+
answer get(url("/file/#{meeting}"), params), &block
|
240
|
+
end
|
241
|
+
|
242
|
+
### Roles - http://docs.ucengine.org/api.html#roles ###
|
243
|
+
|
244
|
+
# Create a role
|
245
|
+
#
|
246
|
+
# @param [Hash] data
|
247
|
+
def create_role(data, &block)
|
248
|
+
answer post(url("/role/"), data), &block
|
249
|
+
end
|
250
|
+
|
251
|
+
# Delete a role
|
252
|
+
#
|
253
|
+
# @param [String] name
|
254
|
+
def delete_role(name, &block)
|
255
|
+
answer delete(url "/role/#{name}"), &block
|
256
|
+
end
|
257
|
+
|
258
|
+
# Set a role to a user
|
259
|
+
#
|
260
|
+
# @param [String] uid
|
261
|
+
# @param [Hash] params
|
262
|
+
def user_role(uid, params={}, &block)
|
263
|
+
answer post(url("/user/#{uid}/roles"), params), &block
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require "eventmachine"
|
2
|
+
require "em-http-request"
|
3
|
+
require "em-http/middleware/json_response"
|
4
|
+
require "multipart_body"
|
5
|
+
require "em-eventsource"
|
6
|
+
|
7
|
+
require_relative "errors"
|
8
|
+
|
9
|
+
module EventMachine
|
10
|
+
module UCEngine
|
11
|
+
# Use response as block
|
12
|
+
module EventMachineResponse
|
13
|
+
def answer(req, &block)
|
14
|
+
response = EM::DefaultDeferrable.new
|
15
|
+
req.errback do
|
16
|
+
error = UCEngine::Client::HttpError.new(0, "connect error", req.last_effective_url)
|
17
|
+
response.fail error
|
18
|
+
yield error, nil if block_given?
|
19
|
+
end
|
20
|
+
req.callback do
|
21
|
+
data = req.response
|
22
|
+
if data["error"]
|
23
|
+
error = UCEngine::Client::UCError.new(req.response_header.status, data["error"], req.last_effective_url)
|
24
|
+
response.fail error
|
25
|
+
yield error, nil if block_given?
|
26
|
+
else
|
27
|
+
response.succeed data["result"]
|
28
|
+
yield nil, data["result"] if block_given?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
response
|
32
|
+
end
|
33
|
+
|
34
|
+
def answer_bool(req, &block)
|
35
|
+
answer(req) do |err, result|
|
36
|
+
result = (result == "true")
|
37
|
+
yield nil, result if block_given?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def answer_download(req)
|
42
|
+
response = EM::DefaultDeferrable.new
|
43
|
+
req.errback do
|
44
|
+
error = UCEngine::Client::HttpError.new(0, "connect error", req.last_effective_url)
|
45
|
+
response.fail error
|
46
|
+
yield error, nil if block_given?
|
47
|
+
end
|
48
|
+
req.callback do
|
49
|
+
if req.response_header.status == 200
|
50
|
+
data = req.response
|
51
|
+
filename = req.response_header['CONTENT_DISPOSITION']
|
52
|
+
file = Tempfile.new(filename)
|
53
|
+
file.write(data)
|
54
|
+
response.succeed file
|
55
|
+
yield nil, file if block_given?
|
56
|
+
else
|
57
|
+
error = UCEngine::Client::HttpError.new(0, "download error")
|
58
|
+
response.fail error
|
59
|
+
yield error, nil if block_given?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
response
|
63
|
+
end
|
64
|
+
|
65
|
+
def answer_connect(http)
|
66
|
+
response = EM::DefaultDeferrable.new
|
67
|
+
http.errback do
|
68
|
+
error = UCEngine::Client::HttpError.new(0, "connect error", http.uri)
|
69
|
+
response.fail error
|
70
|
+
yield error, nil if block_given?
|
71
|
+
end
|
72
|
+
http.callback do
|
73
|
+
if http.response_header.status >= 500
|
74
|
+
error = UCEngine::Client::HttpError.new(http.response_header.status, http.response, http.uri)
|
75
|
+
response.fail error
|
76
|
+
yield error, nil if block_given?
|
77
|
+
else
|
78
|
+
data = http.response
|
79
|
+
if data['error']
|
80
|
+
error = UCEngine::Client::UCError.new(http.response_header.status, data['error'], http.req.uri.to_s)
|
81
|
+
response.fail error
|
82
|
+
yield error, nil if block_given?
|
83
|
+
else
|
84
|
+
result = data["result"]
|
85
|
+
session = UCEngine::Client::Session.new(self, result["uid"], result["sid"])
|
86
|
+
response.succeed session
|
87
|
+
yield nil, session if block_given?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
response
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
module EventMachineRequest
|
96
|
+
def http_request(method, path, params={}, body={}, session=nil, headers=nil, &block)
|
97
|
+
opts ||= {:query => params, :body => body, :head => headers}
|
98
|
+
|
99
|
+
key = (method == :get || method == :delete) ? :query : :body
|
100
|
+
opts[key].merge!(:uid => self.uid, :sid => self.sid) if self.class == UCEngine::Client::Session
|
101
|
+
|
102
|
+
# TODO: make a em-http-request middleware
|
103
|
+
if headers && headers['Content-Type'] == 'application/json'
|
104
|
+
opts[key] = opts[key].to_json
|
105
|
+
end
|
106
|
+
|
107
|
+
conn = EM::HttpRequest.new(path)
|
108
|
+
req = conn.send(method, opts)
|
109
|
+
req
|
110
|
+
end
|
111
|
+
|
112
|
+
def get(path, params={}, body={}, session=nil, headers=nil)
|
113
|
+
http_request(:get, path, params, body, session, headers)
|
114
|
+
end
|
115
|
+
|
116
|
+
def post(path, params={}, body={}, session=nil, headers={})
|
117
|
+
http_request(:post, path, params, body, session, headers)
|
118
|
+
end
|
119
|
+
|
120
|
+
def put(path, params={}, body={}, session=nil, headers={})
|
121
|
+
http_request(:put, path, params, body, session, headers)
|
122
|
+
end
|
123
|
+
|
124
|
+
def delete(path, params={}, body={}, session=nil, headers={})
|
125
|
+
http_request(:delete, path, params, body, session, headers)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Perform a post request on the API with a content type application/json
|
129
|
+
#
|
130
|
+
# @param [String] path
|
131
|
+
# @param [Hash] body
|
132
|
+
def json_post(path, body)
|
133
|
+
http_request(:post, path, {}, body, nil, {'Content-Type' => 'application/json'})
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Client < ::UCEngine::Client
|
138
|
+
include UCEngine::EventMachineResponse
|
139
|
+
include UCEngine::EventMachineRequest
|
140
|
+
|
141
|
+
EM::HttpRequest.use EM::Middleware::JSONResponse
|
142
|
+
|
143
|
+
def time(&block)
|
144
|
+
Session.new(self, nil, nil).time &block
|
145
|
+
end
|
146
|
+
|
147
|
+
# Init EventMachine and init a new instance of U.C.Engine client
|
148
|
+
# See #initialize for arguments
|
149
|
+
def self.run(*args)
|
150
|
+
EM.run { yield self.new(*args) }
|
151
|
+
end
|
152
|
+
|
153
|
+
# Represent a subscription to the U.C.Engine API
|
154
|
+
# Use #subscribe to create a new one
|
155
|
+
class Subscription < EM::EventSource
|
156
|
+
# Start subscription
|
157
|
+
def start(start)
|
158
|
+
@query[:start] = start
|
159
|
+
super()
|
160
|
+
end
|
161
|
+
|
162
|
+
# Cancel subscription
|
163
|
+
def cancel
|
164
|
+
close
|
165
|
+
yield if block_given?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Session < ::UCEngine::Client::Session
|
170
|
+
include UCEngine::EventMachineResponse
|
171
|
+
include UCEngine::EventMachineRequest
|
172
|
+
|
173
|
+
# Subscribe to events
|
174
|
+
#
|
175
|
+
# @param [String] meeting
|
176
|
+
# @param [Hash] params
|
177
|
+
# @return Subscription
|
178
|
+
def subscribe(meeting, params={}, &block)
|
179
|
+
params[:mode] = "eventsource"
|
180
|
+
params.merge!(:uid => uid, :sid => sid)
|
181
|
+
s = Subscription.new(url("/live/#{meeting}"), params)
|
182
|
+
time do |err, now|
|
183
|
+
s.message do |message|
|
184
|
+
block.call(nil, [JSON.parse(message)])
|
185
|
+
end
|
186
|
+
s.error do |error|
|
187
|
+
if s.ready_state != EM::EventSource::CONNECTING
|
188
|
+
puts error
|
189
|
+
block.call error, nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
s.start(now)
|
193
|
+
end
|
194
|
+
s
|
195
|
+
end
|
196
|
+
|
197
|
+
# Upload a file in a meeting room
|
198
|
+
#
|
199
|
+
# @param [String] meeting name
|
200
|
+
# @param [File] file
|
201
|
+
# @param [Hash] metadata
|
202
|
+
def upload(meeting, file, metadata={}, &block)
|
203
|
+
partfile = Part.new( :name => 'content',
|
204
|
+
:filename => File.basename(file.path),
|
205
|
+
:body => file.read)
|
206
|
+
partuid = Part.new( :name => 'uid',
|
207
|
+
:body => uid)
|
208
|
+
partsid = Part.new( :name => 'sid',
|
209
|
+
:body => sid)
|
210
|
+
parts = [partfile, partsid, partuid]
|
211
|
+
parts << metadata.inject([]) { |array, (key, value)|
|
212
|
+
array << Part.new( :name => "metadata[#{key}]",
|
213
|
+
:body => value )
|
214
|
+
}
|
215
|
+
|
216
|
+
body = MultipartBody.new(parts)
|
217
|
+
|
218
|
+
conn = EM::HttpRequest.new(uce.url "/file/#{meeting}")
|
219
|
+
req = conn.post( :head => {'content-type' => "multipart/form-data; boundary=#{body.boundary}"},
|
220
|
+
:body => "#{body.to_s}\r\n")
|
221
|
+
answer(req, &block)
|
222
|
+
end
|
223
|
+
|
224
|
+
# Download a file
|
225
|
+
# The result will a File object
|
226
|
+
# uce.download("demo", "myfile") do |err, file|
|
227
|
+
# puts file.open.read
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# @param [String] meeting
|
231
|
+
# @param [String] filename
|
232
|
+
def download(meeting, filename, &block)
|
233
|
+
answer_download get(url("/file/#{meeting}/#{filename}")), &block
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|