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
data/README.md
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
EventMachine library for U.C.Engine
|
2
|
-
===================================
|
1
|
+
# EventMachine library for U.C.Engine
|
3
2
|
|
4
3
|
em-ucengine is a Ruby library for [U.C.Engine](http://ucengine.org/) powered
|
5
4
|
by [EventMachine](https://github.com/eventmachine/eventmachine). It can
|
6
5
|
connect, subscribe and publish events to U.C.Engine.
|
7
6
|
|
8
|
-
|
9
|
-
How to use it
|
10
|
-
-------------
|
7
|
+
## Install
|
11
8
|
|
12
9
|
Install with Rubygems:
|
13
10
|
|
@@ -15,43 +12,94 @@ Install with Rubygems:
|
|
15
12
|
|
16
13
|
If you use bundler, add it to your `Gemfile`:
|
17
14
|
|
18
|
-
gem "em-ucengine", "~>0.
|
15
|
+
gem "em-ucengine", "~> 0.3"
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
### Client
|
19
20
|
|
20
|
-
|
21
|
+
#### EventMachine
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
23
|
+
We have a classic block style API:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require "em-ucengine"
|
27
|
+
EventMachine::UCEngine::Client.run do |uce|
|
28
|
+
uce.connect("participant", "pwd") do |err, session|
|
29
|
+
EM.add_periodic_timer(1) { session.publish("em-ucengine.example.ping", "demo") }
|
30
|
+
session.subscribe("demo") do |err, event|
|
31
|
+
puts "Hey, we received an event: #{event.inspect}"
|
30
32
|
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
31
36
|
|
32
|
-
|
37
|
+
Each method call return a deferable.
|
33
38
|
|
39
|
+
```ruby
|
40
|
+
require "em-ucengine"
|
41
|
+
EventMachine::UCEngine::Client.run do |uce|
|
42
|
+
req = uce.connect("participant", "pwd")
|
43
|
+
req.callback do |session|
|
44
|
+
session.publish("em-ucengine.example.ping", "demo")
|
45
|
+
end
|
46
|
+
req.errback do |error|
|
47
|
+
puts "error"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
34
51
|
|
35
|
-
|
36
|
-
----
|
52
|
+
#### Net/HTTP
|
37
53
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
54
|
+
```ruby
|
55
|
+
require "em-ucengine"
|
56
|
+
|
57
|
+
uce = UCEngine::Client.new
|
58
|
+
session = uce.connect("participant", "pwd")
|
59
|
+
session.publish("em-ucengine.example.ping", "demo")
|
60
|
+
```
|
61
|
+
|
62
|
+
### Brick
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
require "em-ucengine"
|
66
|
+
require "em-ucengine/brick"
|
67
|
+
|
68
|
+
class MyBrick
|
69
|
+
include EM::UCEngine::Brick
|
44
70
|
|
71
|
+
on "ping" do |event|
|
72
|
+
puts event
|
73
|
+
end
|
74
|
+
end
|
45
75
|
|
46
|
-
|
47
|
-
|
76
|
+
brick = MyBrick.run
|
77
|
+
```
|
78
|
+
|
79
|
+
Don't hesitate to look at the specs for more examples ;-)
|
80
|
+
|
81
|
+
## TODO
|
82
|
+
|
83
|
+
* Release the gem with another name
|
84
|
+
* Complete the specs
|
85
|
+
* Implements the download and upload methods for the Net::HTTP backend
|
86
|
+
|
87
|
+
## Issues or Suggestions
|
48
88
|
|
49
89
|
Found an issue or have a suggestion? Please report it on
|
50
90
|
[Github's issue tracker](http://github.com/af83/ucengine.em/issues).
|
51
91
|
|
92
|
+
First you must have an ucengine instance goto the source directory and start:
|
93
|
+
|
94
|
+
make run
|
95
|
+
|
96
|
+
Once the console started successfully, in an other shell
|
97
|
+
|
98
|
+
./rel/ucengine/bin/demo.sh localhost
|
99
|
+
|
52
100
|
If you wants to make a pull request, please check the specs before:
|
53
101
|
|
54
|
-
|
102
|
+
rake test
|
55
103
|
|
56
104
|
|
57
105
|
Copyright (c) 2011 af83, released under the LGPL license
|
data/lib/em-ucengine.rb
CHANGED
@@ -1,188 +1,3 @@
|
|
1
|
-
require "
|
2
|
-
require "em-
|
3
|
-
require "
|
4
|
-
|
5
|
-
|
6
|
-
module EventMachine
|
7
|
-
class UCEngine
|
8
|
-
|
9
|
-
def self.run(*args)
|
10
|
-
EM.run { yield self.new(*args) }
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(host="localhost", port=5280, api_root="/api", api_version="0.4")
|
14
|
-
@host = host
|
15
|
-
@port = port
|
16
|
-
@root = api_root
|
17
|
-
@version = api_version
|
18
|
-
end
|
19
|
-
|
20
|
-
def time
|
21
|
-
Session.new(self, nil, nil).time { |time| yield time }
|
22
|
-
end
|
23
|
-
|
24
|
-
def connect(user, password, metadata=nil)
|
25
|
-
body = { "name" => user, "credential" => password }
|
26
|
-
body["metadata"] = metadata if metadata
|
27
|
-
http = EM::HttpRequest.new(url "presence").post :body => body
|
28
|
-
http.errback { yield nil }
|
29
|
-
http.callback do
|
30
|
-
data = Yajl::Parser.parse(http.response)
|
31
|
-
data = data["result"] if data
|
32
|
-
yield Session.new(self, data["uid"], data["sid"])
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def url(path)
|
37
|
-
"http://#{@host}:#{@port}#{@root}/#{@version}/#{path}"
|
38
|
-
end
|
39
|
-
|
40
|
-
class Session < Struct.new(:uce, :uid, :sid)
|
41
|
-
|
42
|
-
### Time - http://docs.ucengine.org/api.html#time ###
|
43
|
-
|
44
|
-
def time
|
45
|
-
get("/time") { |result| yield result if block_given? }
|
46
|
-
end
|
47
|
-
|
48
|
-
### Presence - http://docs.ucengine.org/api.html#authentication ###
|
49
|
-
|
50
|
-
def presence(sid)
|
51
|
-
get("/presence/#{sid}") { |result| yield result if block_given? }
|
52
|
-
end
|
53
|
-
|
54
|
-
def disconnect
|
55
|
-
delete("/presence/#{sid}") { |result| yield result if block_given? }
|
56
|
-
end
|
57
|
-
|
58
|
-
### Users - http://docs.ucengine.org/api.html#user ###
|
59
|
-
|
60
|
-
def users
|
61
|
-
get("/user") { |result| yield result if block_given? }
|
62
|
-
end
|
63
|
-
|
64
|
-
def user(uid)
|
65
|
-
get("/user/#{uid}") { |result| yield result if block_given? }
|
66
|
-
end
|
67
|
-
|
68
|
-
def create_user(data)
|
69
|
-
post("/user", data) { |result| yield result && result.to_i if block_given? }
|
70
|
-
end
|
71
|
-
|
72
|
-
def update_user(uid, data)
|
73
|
-
put("/user/#{uid}", data) { |result| yield result if block_given? }
|
74
|
-
end
|
75
|
-
|
76
|
-
def delete_user(uid)
|
77
|
-
delete("/user/#{uid}") { |result| yield result if block_given? }
|
78
|
-
end
|
79
|
-
|
80
|
-
### General infos - http://docs.ucengine.org/api.html#infos ###
|
81
|
-
|
82
|
-
def infos
|
83
|
-
get("/infos") { |result| yield result if block_given? }
|
84
|
-
end
|
85
|
-
|
86
|
-
def update_infos(metadata)
|
87
|
-
put("/infos", :metadata => metadata) { |result| yield result if block_given? }
|
88
|
-
end
|
89
|
-
|
90
|
-
### Meetings - http://docs.ucengine.org/api.html#meeting ###
|
91
|
-
|
92
|
-
def meetings(status=nil)
|
93
|
-
get("/meeting/#{status}") { |result| yield result if block_given? }
|
94
|
-
end
|
95
|
-
|
96
|
-
def meeting(meeting)
|
97
|
-
get("/meeting/all/#{meeting}") { |result| yield result if block_given? }
|
98
|
-
end
|
99
|
-
|
100
|
-
def create_meeting(meeting, body={})
|
101
|
-
body.merge!(:meeting => meeting)
|
102
|
-
post("/meeting/all", body) { |result| yield result if block_given? }
|
103
|
-
end
|
104
|
-
|
105
|
-
def update_meeting(meeting, body={})
|
106
|
-
put("/meeting/all/#{meeting}", body) { |result| yield result if block_given? }
|
107
|
-
end
|
108
|
-
|
109
|
-
def delete_meeting(meeting)
|
110
|
-
delete("/meeting/all/#{meeting}") { |result| yield result if block_given? }
|
111
|
-
end
|
112
|
-
|
113
|
-
### Rosters - http://docs.ucengine.org/api.html#join-a-meeting ###
|
114
|
-
|
115
|
-
def roster(meeting)
|
116
|
-
get("/meeting/all/#{meeting}/roster") { |result| yield result if block_given? }
|
117
|
-
end
|
118
|
-
|
119
|
-
def join_roster(meeting)
|
120
|
-
post("/meeting/all/#{meeting}/roster") { |result| yield result if block_given? }
|
121
|
-
end
|
122
|
-
|
123
|
-
def quit_roster(meeting, uid=nil)
|
124
|
-
delete("/meeting/all/#{meeting}/roster/#{uid || @uid}") { |result| yield result if block_given? }
|
125
|
-
end
|
126
|
-
|
127
|
-
### Events - http://docs.ucengine.org/api.html#events ###
|
128
|
-
|
129
|
-
def events(meeting, params={})
|
130
|
-
params[:_async] = "no"
|
131
|
-
get("/event/#{meeting}", params) { |result| yield result if block_given? }
|
132
|
-
end
|
133
|
-
|
134
|
-
def subscribe(meeting, params={}, &blk)
|
135
|
-
params[:_async] = "lp"
|
136
|
-
recurse = Proc.new do |result|
|
137
|
-
next unless result
|
138
|
-
blk.call(result)
|
139
|
-
params[:start] = result.last["datetime"].to_i + 1
|
140
|
-
get("/event/#{meeting}", params, &recurse) if EM.reactor_running?
|
141
|
-
end
|
142
|
-
time do |time|
|
143
|
-
params[:start] = time
|
144
|
-
get("/event/#{meeting}", params, &recurse)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def publish(type, meeting=nil, metadata=nil)
|
149
|
-
body = { :type => type }
|
150
|
-
body[:metadata] = metadata if metadata
|
151
|
-
post("/event/#{meeting}", body) { |result| yield result if block_given? }
|
152
|
-
end
|
153
|
-
|
154
|
-
def search(params)
|
155
|
-
get("/search/event/", params) { |result| yield result if block_given? }
|
156
|
-
end
|
157
|
-
|
158
|
-
protected
|
159
|
-
|
160
|
-
def get(path, params={})
|
161
|
-
http_request(:get, path, :query => params) { |result| yield result }
|
162
|
-
end
|
163
|
-
|
164
|
-
def post(path, body=nil)
|
165
|
-
http_request(:post, path, :body => body) { |result| yield result }
|
166
|
-
end
|
167
|
-
|
168
|
-
def put(path, body=nil)
|
169
|
-
http_request(:put, path, :body => body) { |result| yield result }
|
170
|
-
end
|
171
|
-
|
172
|
-
def delete(path)
|
173
|
-
http_request(:delete, path) { |result| yield result }
|
174
|
-
end
|
175
|
-
|
176
|
-
def http_request(method, path, opts={})
|
177
|
-
opts[:query] ||= {}
|
178
|
-
opts[:query].merge!(:uid => uid, :sid => sid)
|
179
|
-
http = EM::HttpRequest.new(uce.url path).send(method, opts)
|
180
|
-
http.errback { yield nil }
|
181
|
-
http.callback do
|
182
|
-
data = Yajl::Parser.parse(http.response)
|
183
|
-
yield data && data.has_key?("result") && data["result"]
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
1
|
+
require "em-ucengine/client"
|
2
|
+
require "em-ucengine/client_nethttp"
|
3
|
+
require "em-ucengine/client_em"
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'em-ucengine/utils'
|
2
|
+
|
3
|
+
module EventMachine
|
4
|
+
module UCEngine
|
5
|
+
# This module allows to create a new brick for UCE. A brick may be either
|
6
|
+
# an independent entity or a composition of several bricks, resulting in a
|
7
|
+
# "meta-brick". On this case, only the meta-brick should be runned and only
|
8
|
+
# one connection to UCE will be used.
|
9
|
+
#
|
10
|
+
# When creating a brick, one would provide a bootstrap block and declare at
|
11
|
+
# least one event handler for the brick to manage. Handlers will be executed
|
12
|
+
# in the context of the Brick instance, so one may also write arbitrary code
|
13
|
+
# to be used in handlers blocks.
|
14
|
+
#
|
15
|
+
# See examples/bricks.rb and specs for more details.
|
16
|
+
module Brick
|
17
|
+
def self.included(klass)
|
18
|
+
klass.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Methods defined here will be made available as class methods on the
|
22
|
+
# class including Brick. Some class variables are pushed as well:
|
23
|
+
# +@@routes+, +@@bricks+, +@@bootstrap+.
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
def self.extended(klass)
|
27
|
+
klass.class_eval {
|
28
|
+
class_variable_set("@@routes", {})
|
29
|
+
class_variable_set("@@bricks", [])
|
30
|
+
class_variable_set("@@bootstrap", Proc.new {})
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Define a bootstrap block, which will be called before subscribing
|
35
|
+
# to events.
|
36
|
+
def bootstrap(&block)
|
37
|
+
class_variable_set("@@bootstrap", block)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Define an event handler.
|
41
|
+
#
|
42
|
+
# @param [String] route
|
43
|
+
# @yield [Event] a callback to be executed when a matching event is received
|
44
|
+
# @example
|
45
|
+
# on "my.event" do |event|
|
46
|
+
# # do something
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
def on(route, &callback)
|
50
|
+
routes = class_variable_get("@@routes")
|
51
|
+
routes[route] ||= []
|
52
|
+
routes[route] << callback
|
53
|
+
end
|
54
|
+
|
55
|
+
# Add a sub-brick to the current brick.
|
56
|
+
#
|
57
|
+
# @param [Constant] Brick's class/module name
|
58
|
+
# @example
|
59
|
+
# use MySpecializedBrick
|
60
|
+
def use(name)
|
61
|
+
class_variable_get("@@bricks") << name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :uce
|
66
|
+
|
67
|
+
# Create a new brick.
|
68
|
+
#
|
69
|
+
# @param [Hash] config
|
70
|
+
def initialize(config={})
|
71
|
+
@uce = nil
|
72
|
+
@config = config
|
73
|
+
end
|
74
|
+
|
75
|
+
# Start EventMachine, initialize and start the brick.
|
76
|
+
#
|
77
|
+
# When composing several bricks, only the meta-brick should be
|
78
|
+
# runned.
|
79
|
+
#
|
80
|
+
# @param [Hash] config
|
81
|
+
def self.run(config={})
|
82
|
+
brick = self.new config
|
83
|
+
EM::run do
|
84
|
+
brick.start
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Start the brick.
|
89
|
+
#
|
90
|
+
# @param [EM::UCEngine::Client] uce (nil) shared instance of the client,
|
91
|
+
# used by sub-bricks when composing so that only one UCE connection is
|
92
|
+
# made and used
|
93
|
+
def start(uce=nil)
|
94
|
+
# Not in a sub-brick, connect to UCE.
|
95
|
+
if uce.nil?
|
96
|
+
@uce = EM::UCEngine::Client.new(@config[:host], @config[:port])
|
97
|
+
@uce.connect(@config[:name], @config[:credential]) do |err, uce|
|
98
|
+
@uce = uce
|
99
|
+
ready(bricks.map do |brick|
|
100
|
+
b = brick.new
|
101
|
+
b.start @uce
|
102
|
+
b
|
103
|
+
end)
|
104
|
+
end
|
105
|
+
else # Sub-brick, init with the shared UCE client instance.
|
106
|
+
@uce = uce
|
107
|
+
self.instance_eval &bootstrap
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Accessor for +@@bootstrap+.
|
112
|
+
def bootstrap
|
113
|
+
self.class.class_variable_get("@@bootstrap")
|
114
|
+
end
|
115
|
+
|
116
|
+
# Accessor for +@@routes+.
|
117
|
+
def routes
|
118
|
+
self.class.class_variable_get("@@routes")
|
119
|
+
end
|
120
|
+
|
121
|
+
# Accessor for +@@bricks+.
|
122
|
+
def bricks
|
123
|
+
self.class.class_variable_get("@@bricks")
|
124
|
+
end
|
125
|
+
|
126
|
+
# Wrapper around EventMachine's +Timer+. Pass it a block to be
|
127
|
+
# executed after a time range.
|
128
|
+
#
|
129
|
+
# @param [Integer] n time range in milliseconds
|
130
|
+
# @yield
|
131
|
+
def after(n, &block)
|
132
|
+
EventMachine::Timer.new(n, &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Wrapper around EventMachine's +PeriodicTimer+. Pass it a block
|
136
|
+
# to be executed on a defined time frame.
|
137
|
+
#
|
138
|
+
# @param [Integer] n time range in milliseconds
|
139
|
+
# @yield
|
140
|
+
def every(n, &block)
|
141
|
+
EventMachine::PeriodicTimer.new(n, &block)
|
142
|
+
end
|
143
|
+
|
144
|
+
protected
|
145
|
+
|
146
|
+
# Hook sub-brick's declared event handlers into the event loop, by subscribing to
|
147
|
+
# UCE core.
|
148
|
+
#
|
149
|
+
# @param [Array<Brick>] brick_instances
|
150
|
+
def ready(bricks_instances)
|
151
|
+
r = routes.keys
|
152
|
+
|
153
|
+
# Bootstrap.
|
154
|
+
self.instance_eval &bootstrap
|
155
|
+
|
156
|
+
# Merge routes when composing bricks.
|
157
|
+
bricks_instances.each do |brick|
|
158
|
+
r += brick.routes.keys
|
159
|
+
end
|
160
|
+
|
161
|
+
# Subscribe to UCE for declared event handlers.
|
162
|
+
@uce.subscribe "", :type => r.uniq.join(',') do |err, events|
|
163
|
+
events.each do |event|
|
164
|
+
routes[event["type"]].each do |callback|
|
165
|
+
self.instance_exec(event, &callback)
|
166
|
+
end unless routes[event["type"]].nil?
|
167
|
+
bricks_instances.each do |brick|
|
168
|
+
brick.routes[event["type"]].each do |callback|
|
169
|
+
brick.instance_exec(event, &callback)
|
170
|
+
end unless brick.routes[event["type"]].nil?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|