em-ucengine 0.1.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|