ucengine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ucengine.rb ADDED
@@ -0,0 +1,192 @@
1
+ require 'json'
2
+
3
+ require 'net/http'
4
+ require 'cgi'
5
+
6
+ # ucengine.rb implements the UCEngine API, it can currently handle
7
+ # publish/subscribe to any event stream.
8
+ #
9
+ # Author:: Victor Goya (victor.goya@af83.com)
10
+ # Copyright:: Copyright (c) 2010 AF83
11
+ # License:: LGPL
12
+ # Website:: http://ucengine.org/
13
+
14
+ # This class is the main and only class in ucengine.rb, it handles
15
+ # connections and request to the UCEngine server.
16
+ #
17
+ # uce = UCEngine.new("localhost", 4567)
18
+ # uce.connect("bibi", :password => 'abcd') do |uce|
19
+ # uce.subscribe(["af83"], :type => 'chat.message.new', :search => 'HTML5') do |event|
20
+ # uce.push(:location => [event['org'], event['meeting']]
21
+ # :from => 'bot',
22
+ # :type => 'chat.message.new',
23
+ # :metadata => {"text" => "Hey, you were talking about HTML5"})
24
+ # end
25
+ # end
26
+ class UCEngine
27
+
28
+ # Print every request and everything above.
29
+ DEBUG = 0
30
+ # Print everything that seems fishy.
31
+ WARNING = 1
32
+ # Print regular errors, usually HTTP errors.
33
+ ERROR = 2
34
+ # Only print critical errors (bad hostname or port, etc).
35
+ CRITICAL = 3
36
+ # Don't print anything (default).
37
+ QUIET = 4
38
+
39
+ # Create a new UCEngine object. 'host' is the hostname of the UCEngine server
40
+ # and 'port' is to TCP port to connect to. Note that this method doesn't create
41
+ # a new connection, see the #connect method.
42
+ # An additional 'debug' parameter set the debug level of the library, all the
43
+ # debug information are written in the error output.
44
+ def initialize(host, port, debug = UCEngine::QUIET)
45
+ @host = host
46
+ @port = port
47
+ @http = Net::HTTP.new(host, port)
48
+ @threads = []
49
+ @debug = debug
50
+ debug(UCEngine::DEBUG, "Initialisation complete for #{host}:#{port}.")
51
+ end
52
+
53
+ # Connect to the UCEngine server with the User ID 'uid' and the its credential.
54
+ #
55
+ #
56
+ # uce = UCEngine.new("localhost", 4567)
57
+ # uce.connect("bibi", :password => 'abcd') do |uce|
58
+ # ... your code goes here
59
+ # end
60
+ #
61
+ # It is currently possible to use :token or :password as authentification method.
62
+ def connect(uid, credential)
63
+ @uid = uid
64
+ response = put("/presence/#{@uid}", {:auth => 'token', :credential => credential[:token]})
65
+ @sid = response['result']
66
+ debug(UCEngine::DEBUG, "Authentification complete for #{@uid}/#{@sid}.")
67
+ yield self
68
+ @threads.each do |thread|
69
+ thread.join
70
+ end
71
+ end
72
+
73
+ # Subscribe to an event stream. The 'location' parameter is where you're expecting
74
+ # the events to come:
75
+ # * ["organisation", "meeting"]: events from a specific meeting.
76
+ # * ["organisation"]: events from all meetings of the organisation and for the organisation itself.
77
+ # * []: all events.
78
+ #
79
+ # The function takes extra parameters:
80
+ # :type => the type of event (ex. 'chat.message.new', 'internal.user.add', etc).
81
+ # :from => the origin of the message, the value is an uid.
82
+ # :parent => the id of the the parent event.
83
+ # :search => list of keywords that match the metadata of the returned events
84
+ #
85
+ #
86
+ # uce.subscribe(["af83"], :type => 'internal.meeting.add', :search => 'HTML5') do |event|
87
+ # puts "A new meeting about HTML5 was created"
88
+ # end
89
+ def subscribe(location, params = {})
90
+ debug(UCEngine::DEBUG, "Subscribe to #{location} with #{params}.")
91
+ @threads << Thread.new do
92
+ Net::HTTP.start(@host, @port) do |http|
93
+ params[:_async] = "lp"
94
+ params[:start] = 0 if !params[:start]
95
+ while true
96
+ begin
97
+ events = get("/event/#{location.join("/")}", params, http)['result']
98
+ rescue Timeout::Error
99
+ debug(UCEngine::WARNING, "Subscribe timeout ... retry")
100
+ retry
101
+ rescue EOFError
102
+ debug(UCEngine::WARNING, "Subscribe closed ... retry")
103
+ sleep 10
104
+ retry
105
+ end
106
+ events.each do |event|
107
+ yield event
108
+ end
109
+ params[:start] = events[-1]['datetime'] + 1
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ # Publish an event. Publishing an event require a few mandatories parameters:
116
+ # [:location] As described in the subscribe method: ["organisation", "meeting"] publish the event in a specific meeting, ["organisation"] publish the event in the organisation and []: publish the event in the server root.
117
+ # [:type] The type of event to send, the format of this type is usually 'namespace.object.action', for example: 'chat.message.new', 'twitter.tweet.new', 'internal.user.update'
118
+ # [:parent] The id of the parent, this parameter is useful to build event hierarchy.
119
+ # [:metadata] A hash of freely defined values to append to the event.
120
+ #
121
+ # uce.publish(:location => ["af83", "WebWorkersCamp"],
122
+ # :type => 'presentation.slide.add'
123
+ # :metadata => {:url => 'http://myserver/slides/03.png',
124
+ # :index => 3})
125
+ def publish(event)
126
+ debug(UCEngine::DEBUG, "Publish to #{event[:location]}, type: #{event[:type]}, parent: #{event[:parent]}, metadata: #{event[:metadata]}")
127
+ params = Hash.new
128
+ params[:type] = event[:type]
129
+ params[:parent] = event[:parent] if event[:parent]
130
+ if event[:metadata]
131
+ event[:metadata].each_key do |key|
132
+ params["metadata[#{key}]"] = event[:metadata][key]
133
+ end
134
+ end
135
+ put("/event/#{event[:location].join("/")}", params)
136
+ end
137
+
138
+ # Return the current timestamp from the server. The timestamp is expressed in milliseconds
139
+ # from Epoch (january 1st 1970).
140
+ # This function can be useful if you need to search for events from _now_.
141
+ #
142
+ # uce.time -> 1240394032
143
+ #
144
+ def time
145
+ time = get("/time", Hash.new)['result'].to_i
146
+ debug(UCEngine::DEBUG, "Fecth timestamp from UCEngine: #{time}")
147
+ return time
148
+ end
149
+
150
+ protected
151
+
152
+ # Encode parameters
153
+ def UCEngine.encode(params)
154
+ params.collect { |k,v| "#{k}=#{CGI::escape(v.to_s)}" }.join('&')
155
+ end
156
+
157
+ # Print debug messages
158
+ def debug(level, message)
159
+ $stderr.write("#{message}\n\n") if level >= @debug
160
+ end
161
+
162
+ # Handle GET requests
163
+ def get(path, params, http = @http)
164
+ params[:uid] = @uid if @uid
165
+ params[:sid] = @sid if @sid
166
+ result = JSON.parse(http.get("/api/0.1/#{path}?#{UCEngine.encode(params)}").body)
167
+ debug(UCEngine::DEBUG, "Request: GET /api/0.1/#{path}?#{UCEngine.encode(params)}\nResult: #{result}")
168
+ return result
169
+ end
170
+
171
+ # Handle POST requests
172
+ def post(path, params, http = @http)
173
+ params[:uid] = @uid if @uid
174
+ params[:sid] = @sid if @sid
175
+ result = JSON.parse(http.post("/api/0.1/#{path}", UCEngine.encode(params)).body)
176
+ debug(UCEngine::DEBUG, "Request: POST /api/0.1/#{path}?#{UCEngine.encode(params)}\nResult: #{result}")
177
+ return result
178
+ end
179
+
180
+ # Handle PUT requests
181
+ def put(path, params)
182
+ params['_method'] = "PUT"
183
+ post(path, params)
184
+ end
185
+
186
+ # Handle DELETE requests
187
+ def delete(path, params)
188
+ params['_method'] = "DELETE"
189
+ post(path, params)
190
+ end
191
+
192
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'ucengine.rb'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestUcengine < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ucengine.rb}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["AF83"]
12
+ s.date = %q{2010-11-23}
13
+ s.description = %q{ucengine.rb is a Ruby library to consume the UCEngine API}
14
+ s.email = %q{victor.goya@af83.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/ucengine.rb",
27
+ "test/helper.rb",
28
+ "test/test_ucengine.rb.rb",
29
+ "ucengine.rb.gemspec"
30
+ ]
31
+ s.homepage = %q{http://github.com/AF83/ucengine.rb}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.7}
35
+ s.summary = %q{Ruby library for UCEngine}
36
+ s.test_files = [
37
+ "test/helper.rb",
38
+ "test/test_ucengine.rb.rb"
39
+ ]
40
+
41
+ if s.respond_to? :specification_version then
42
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
47
+ s.add_runtime_dependency(%q<json>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
50
+ s.add_dependency(%q<json>, [">= 0"])
51
+ end
52
+ else
53
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
54
+ s.add_dependency(%q<json>, [">= 0"])
55
+ end
56
+ end
57
+
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ucengine
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - AF83
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-01 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thoughtbot-shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: json
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ description: ucengine.rb is a Ruby library to consume the UCEngine API
47
+ email: victor.goya@af83.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - LICENSE
54
+ - README.rdoc
55
+ files:
56
+ - .document
57
+ - .gitignore
58
+ - LICENSE
59
+ - README.rdoc
60
+ - Rakefile
61
+ - VERSION
62
+ - doc/UCEngine.html
63
+ - doc/UCEngine/Debug.html
64
+ - doc/created.rid
65
+ - doc/images/brick.png
66
+ - doc/images/brick_link.png
67
+ - doc/images/bug.png
68
+ - doc/images/bullet_black.png
69
+ - doc/images/bullet_toggle_minus.png
70
+ - doc/images/bullet_toggle_plus.png
71
+ - doc/images/date.png
72
+ - doc/images/find.png
73
+ - doc/images/loadingAnimation.gif
74
+ - doc/images/macFFBgHack.png
75
+ - doc/images/package.png
76
+ - doc/images/page_green.png
77
+ - doc/images/page_white_text.png
78
+ - doc/images/page_white_width.png
79
+ - doc/images/plugin.png
80
+ - doc/images/ruby.png
81
+ - doc/images/tag_green.png
82
+ - doc/images/wrench.png
83
+ - doc/images/wrench_orange.png
84
+ - doc/images/zoom.png
85
+ - doc/index.html
86
+ - doc/js/darkfish.js
87
+ - doc/js/jquery.js
88
+ - doc/js/quicksearch.js
89
+ - doc/js/thickbox-compressed.js
90
+ - doc/lib/ucengine_rb.html
91
+ - doc/rdoc.css
92
+ - lib/ucengine.rb
93
+ - test/helper.rb
94
+ - test/test_ucengine.rb
95
+ - ucengine.rb.gemspec
96
+ has_rdoc: true
97
+ homepage: http://github.com/AF83/ucengine.rb
98
+ licenses: []
99
+
100
+ post_install_message:
101
+ rdoc_options:
102
+ - --charset=UTF-8
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements: []
122
+
123
+ rubyforge_project:
124
+ rubygems_version: 1.3.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Ruby library for UCEngine
128
+ test_files:
129
+ - test/helper.rb
130
+ - test/test_ucengine.rb