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 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.1"
15
+ gem "em-ucengine", "~> 0.3"
16
+
17
+ ## Usage
18
+
19
+ ### Client
19
20
 
20
- Then, you can use it in your code:
21
+ #### EventMachine
21
22
 
22
- require "em-ucengine"
23
- EventMachine::UCEngine.run do |uce|
24
- uce.connect("participant", "pwd") do |session|
25
- EM.add_periodic_timer(1) { session.publish("em-ucengine.example.ping", "demo") }
26
- session.subscribe("demo") do |event|
27
- puts "Hey, we received an event: #{event.inspect}"
28
- end
29
- end
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
- Don't hesitate to look at the specs for more examples ;-)
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
- TODO
36
- ----
52
+ #### Net/HTTP
37
53
 
38
- * Files API
39
- * ACL or Roles API
40
- * Better error handling
41
- * Complete the specs
42
- * Compatibility with em-synchrony
43
- * Yard documentation
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
- Issues or Suggestions
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
- ./spec/em-ucengine_spec.rb
102
+ rake test
55
103
 
56
104
 
57
105
  Copyright (c) 2011 af83, released under the LGPL license
@@ -1,188 +1,3 @@
1
- require "eventmachine"
2
- require "em-http-request"
3
- require "yajl"
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