bigbluebutton-api-ruby 0.0.11 → 0.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -2
- data/.rvmrc +1 -1
- data/.travis.yml +6 -0
- data/CHANGELOG.rdoc +19 -8
- data/Gemfile +9 -1
- data/Gemfile.lock +62 -9
- data/LICENSE +5 -7
- data/LICENSE_003 +20 -0
- data/README.rdoc +42 -19
- data/Rakefile +31 -19
- data/bigbluebutton-api-ruby.gemspec +5 -5
- data/examples/get_version_example.rb +18 -0
- data/examples/join_example.rb +59 -0
- data/examples/overall_0.7_example.rb +92 -0
- data/examples/prepare.rb +38 -0
- data/extras/bigbluebutton_bot.rb +64 -0
- data/extras/download_bot_from.txt +1 -0
- data/extras/test-presentation.pdf +0 -0
- data/features/check_status.feature +45 -0
- data/features/config.yml.example +21 -0
- data/features/create_meetings.feature +29 -0
- data/features/end_meetings.feature +27 -0
- data/features/join_meetings.feature +29 -0
- data/features/pre_upload_slides.feature +14 -0
- data/features/recordings.feature +34 -0
- data/features/step_definitions/check_status_steps.rb +119 -0
- data/features/step_definitions/common_steps.rb +122 -0
- data/features/step_definitions/create_meetings_steps.rb +54 -0
- data/features/step_definitions/end_meetings_steps.rb +49 -0
- data/features/step_definitions/join_meetings_steps.rb +39 -0
- data/features/step_definitions/pre_upload_slides_steps.rb +13 -0
- data/features/step_definitions/recordings_steps.rb +38 -0
- data/features/support/api_tests/configs.rb +51 -0
- data/features/support/env.rb +7 -0
- data/features/support/hooks.rb +11 -0
- data/lib/bigbluebutton_api.rb +301 -97
- data/lib/bigbluebutton_formatter.rb +105 -19
- data/lib/bigbluebutton_modules.rb +92 -0
- data/lib/hash_to_xml.rb +22 -51
- data/spec/bigbluebutton_api_0.8_spec.rb +273 -0
- data/spec/bigbluebutton_api_spec.rb +211 -117
- data/spec/bigbluebutton_formatter_spec.rb +178 -29
- data/spec/bigbluebutton_modules_spec.rb +95 -0
- data/spec/data/hash_to_xml_complex.xml +45 -0
- data/spec/hash_to_xml_spec.rb +143 -0
- data/spec/spec_helper.rb +4 -2
- data/spec/support/forgery/forgeries/random_name.rb +7 -0
- data/spec/support/forgery/forgeries/url.rb +5 -0
- metadata +47 -12
- data/test/config.yml.example +0 -9
- data/test/test.rb +0 -154
@@ -0,0 +1,122 @@
|
|
1
|
+
# Common steps, used in several features
|
2
|
+
|
3
|
+
When /^the default BigBlueButton server$/ do
|
4
|
+
@api = BigBlueButton::BigBlueButtonApi.new(@config_server['url'],
|
5
|
+
@config_server['salt'],
|
6
|
+
@config_server['version'].to_s,
|
7
|
+
@config['debug'])
|
8
|
+
@api.timeout = @config['timeout_req']
|
9
|
+
end
|
10
|
+
|
11
|
+
# default create call, with no optional parameters (only the mod pass)
|
12
|
+
When /^that a meeting was created$/ do
|
13
|
+
steps %Q{ When the default BigBlueButton server }
|
14
|
+
|
15
|
+
@req.id = Forgery(:basic).random_name("test")
|
16
|
+
@req.name = @req.id
|
17
|
+
@req.mod_pass = Forgery(:basic).password
|
18
|
+
@req.opts = { :moderatorPW => @req.mod_pass }
|
19
|
+
@req.method = :create
|
20
|
+
@req.response = @api.create_meeting(@req.id, @req.name, @req.opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
When /^that a meeting was created with all the optional arguments$/i do
|
24
|
+
steps %Q{ When the default BigBlueButton server }
|
25
|
+
|
26
|
+
@req.id = Forgery(:basic).random_name("test-create")
|
27
|
+
@req.name = @req.id
|
28
|
+
@req.mod_pass = Forgery(:basic).password
|
29
|
+
@req.opts = { :moderatorPW => @req.mod_pass,
|
30
|
+
:attendeePW => Forgery(:basic).password,
|
31
|
+
:welcome => Forgery(:lorem_ipsum).words(10),
|
32
|
+
:dialNumber => Forgery(:basic).number(:at_most => 999999999).to_s,
|
33
|
+
:logoutURL => Forgery(:internet).url,
|
34
|
+
:voiceBridge => Forgery(:basic).number(:at_least => 70000, :at_most => 79999),
|
35
|
+
:webVoice => Forgery(:basic).text,
|
36
|
+
:maxParticipants => Forgery(:basic).number }
|
37
|
+
if @api.version >= "0.8"
|
38
|
+
@req.opts.merge!( { :record => false,
|
39
|
+
:duration => Forgery(:basic).number(:at_least => 10, :at_most => 60),
|
40
|
+
:meta_one => "one", :meta_TWO => "TWO" } )
|
41
|
+
end
|
42
|
+
@req.method = :create
|
43
|
+
@req.response = @api.create_meeting(@req.id, @req.name, @req.opts)
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^the meeting is running$/ do
|
47
|
+
steps %Q{ When the meeting is running with 1 attendees }
|
48
|
+
end
|
49
|
+
|
50
|
+
When /^the meeting is running with (\d+) attendees$/ do |count|
|
51
|
+
mobile_salt = @config_server.has_key?('mobile_salt') ? @config_server['mobile_salt'] : ""
|
52
|
+
BigBlueButtonBot.new(@api, @req.id, mobile_salt, count.to_i, @config['timeout_bot_start'])
|
53
|
+
end
|
54
|
+
|
55
|
+
When /^the response is an error with the key "(.*)"$/ do |key|
|
56
|
+
@req.exception.should_not be_nil
|
57
|
+
@req.exception.key.should == key
|
58
|
+
end
|
59
|
+
|
60
|
+
When /^the response is successful$/ do
|
61
|
+
@req.response[:returncode].should be_true
|
62
|
+
end
|
63
|
+
|
64
|
+
When /^the response is successful with no messages$/ do
|
65
|
+
@req.response[:returncode].should be_true
|
66
|
+
@req.response[:messageKey].should == ""
|
67
|
+
@req.response[:message].should == ""
|
68
|
+
end
|
69
|
+
|
70
|
+
When /^the response has the messageKey "(.*)"$/ do |key|
|
71
|
+
@req.response[:messageKey].should == key
|
72
|
+
@req.response[:message].should_not be_empty
|
73
|
+
end
|
74
|
+
|
75
|
+
When /^the response is successful and well formatted$/ do
|
76
|
+
case @req.method
|
77
|
+
when :create
|
78
|
+
steps %Q{ When the response to the create method is successful and well formatted }
|
79
|
+
when :end
|
80
|
+
steps %Q{ When the response to the end method is successful and well formatted }
|
81
|
+
when :get_recordings
|
82
|
+
steps %Q{ When the response to the get_recordings method is successful and well formatted }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
When /^the response to the create method is successful and well formatted$/ do
|
87
|
+
@req.response[:returncode].should be_true
|
88
|
+
@req.response[:meetingID].should == @req.id
|
89
|
+
@req.response[:hasBeenForciblyEnded].should be_false
|
90
|
+
@req.response[:messageKey].should == ""
|
91
|
+
@req.response[:message].should == ""
|
92
|
+
|
93
|
+
if @req.opts.has_key?(:attendeePW)
|
94
|
+
@req.response[:attendeePW].should == @req.opts[:attendeePW]
|
95
|
+
else # auto generated password
|
96
|
+
@req.response[:attendeePW].should be_a(String)
|
97
|
+
@req.response[:attendeePW].should_not be_empty
|
98
|
+
@req.opts[:attendeePW] = @req.response[:attendeePW]
|
99
|
+
end
|
100
|
+
if @req.opts.has_key?(:moderatorPW)
|
101
|
+
@req.response[:moderatorPW].should == @req.opts[:moderatorPW]
|
102
|
+
else # auto generated password
|
103
|
+
@req.response[:moderatorPW].should be_a(String)
|
104
|
+
@req.response[:moderatorPW].should_not be_empty
|
105
|
+
@req.opts[:moderatorPW] = @req.response[:moderatorPW]
|
106
|
+
end
|
107
|
+
|
108
|
+
if @api.version >= "0.8"
|
109
|
+
@req.response[:createTime].should be_a(Numeric)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
When /^the response to the end method is successful and well formatted$/ do
|
114
|
+
@req.response[:returncode].should be_true
|
115
|
+
@req.response[:messageKey].should == "sentEndMeetingRequest"
|
116
|
+
@req.response[:message].should_not be_empty
|
117
|
+
end
|
118
|
+
|
119
|
+
When /^the response to the get_recordings method is successful and well formatted$/ do
|
120
|
+
@req.response[:returncode].should be_true
|
121
|
+
@req.response[:recordings].should == []
|
122
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
When /^the create method is called with all the optional arguments$/i do
|
2
|
+
steps %Q{ When that a meeting was created with all the optional arguments }
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^the create method is called with no optional arguments$/i do
|
6
|
+
steps %Q{ When the default BigBlueButton server }
|
7
|
+
steps %Q{ When that a meeting was created }
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^the create method is called with a duplicated meeting id$/ do
|
11
|
+
steps %Q{ When the default BigBlueButton server }
|
12
|
+
|
13
|
+
@req.id = Forgery(:basic).random_name("test-create")
|
14
|
+
@req.name = @req.id
|
15
|
+
|
16
|
+
# first meeting
|
17
|
+
@req.method = :create
|
18
|
+
@api.create_meeting(@req.id, @req.name)
|
19
|
+
|
20
|
+
begin
|
21
|
+
# duplicated meeting to be tested
|
22
|
+
@req.method = :create
|
23
|
+
@req.response = @api.create_meeting(@req.id, @req.name)
|
24
|
+
rescue Exception => @req.exception
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
When /^the create method is called$/ do
|
29
|
+
steps %Q{ When the default BigBlueButton server }
|
30
|
+
|
31
|
+
@req.id = Forgery(:basic).random_name("test-create")
|
32
|
+
@req.name = @req.id
|
33
|
+
@req.method = :create
|
34
|
+
@req.response = @api.create_meeting(@req.id, @req.name)
|
35
|
+
@req.mod_pass = @req.response[:moderatorPW]
|
36
|
+
end
|
37
|
+
|
38
|
+
When /^the meeting is forcibly ended$/ do
|
39
|
+
@req.response = @api.end_meeting(@req.id, @req.mod_pass)
|
40
|
+
end
|
41
|
+
|
42
|
+
When /^the create method is called again with the same meeting id$/ do
|
43
|
+
begin
|
44
|
+
@req.method = :create
|
45
|
+
@req.response = @api.create_meeting(@req.id, @req.name)
|
46
|
+
rescue Exception => @req.exception
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
When /^the meeting exists in the server$/ do
|
51
|
+
@req.response = @api.get_meetings
|
52
|
+
@req.response[:meetings].reject!{ |m| m[:meetingID] != @req.id }
|
53
|
+
@req.response[:meetings].count.should == 1
|
54
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
When /^the method to end the meeting is called$/ do
|
2
|
+
begin
|
3
|
+
@req.method = :end
|
4
|
+
@req.response = @api.end_meeting(@req.id, @req.mod_pass)
|
5
|
+
rescue Exception => @req.exception
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^the meeting should be ended$/ do
|
10
|
+
# the meeting only ends when everybody closes the session
|
11
|
+
BigBlueButtonBot.finalize
|
12
|
+
|
13
|
+
# wait for the meeting to end
|
14
|
+
Timeout::timeout(@config['timeout_ending']) do
|
15
|
+
running = true
|
16
|
+
while running
|
17
|
+
sleep 1
|
18
|
+
response = @api.get_meetings
|
19
|
+
selected = response[:meetings].reject!{ |m| m[:meetingID] != @req.id }
|
20
|
+
running = selected[0][:running] unless selected.nil?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^the flag hasBeenForciblyEnded should be set$/ do
|
27
|
+
@req.response[:hasBeenForciblyEnded].should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
When /^the information returned by get_meeting_info is correct$/ do
|
31
|
+
# check only what is different in a meeting that WAS ENDED
|
32
|
+
# the rest is checked in other scenarios
|
33
|
+
|
34
|
+
@req.response = @api.get_meeting_info(@req.id, @req.mod_pass)
|
35
|
+
@req.response[:running].should be_false
|
36
|
+
@req.response[:hasBeenForciblyEnded].should be_true
|
37
|
+
@req.response[:participantCount].should == 0
|
38
|
+
@req.response[:moderatorCount].should == 0
|
39
|
+
@req.response[:attendees].should == []
|
40
|
+
|
41
|
+
# start and end times that should be within 2 hours from now
|
42
|
+
@req.response[:startTime].should be_a(DateTime)
|
43
|
+
@req.response[:startTime].should < DateTime.now
|
44
|
+
@req.response[:startTime].should >= DateTime.now - (2/24.0)
|
45
|
+
@req.response[:endTime].should be_a(DateTime)
|
46
|
+
@req.response[:endTime].should < DateTime.now
|
47
|
+
@req.response[:endTime].should >= DateTime.now - (2/24.0)
|
48
|
+
@req.response[:endTime].should > @req.response[:startTime]
|
49
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
When /^the user tries to access the link to join the meeting as (.*)$/ do |role|
|
2
|
+
case role.downcase.to_sym
|
3
|
+
when :moderator
|
4
|
+
@req.response = @api.join_meeting_url(@req.id, "any-mod", @req.mod_pass)
|
5
|
+
when :attendee
|
6
|
+
@req.response = @api.join_meeting_url(@req.id, "any-attendee", @req.response[:attendeePW])
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^he is redirected to the BigBlueButton client$/ do
|
11
|
+
# requests the join url and expects a redirect
|
12
|
+
uri = URI(@req.response)
|
13
|
+
response = Net::HTTP.get_response(uri)
|
14
|
+
response.should be_a(Net::HTTPFound)
|
15
|
+
response.code.should == "302"
|
16
|
+
|
17
|
+
# check redirect to the correct bbb client page
|
18
|
+
bbb_client_url = @api.url.gsub(URI(@api.url).path, "") + "/client/BigBlueButton.html"
|
19
|
+
response["location"].should match(/#{bbb_client_url}/)
|
20
|
+
end
|
21
|
+
|
22
|
+
When /^the user tries to access the link to join a meeting that was not created$/ do
|
23
|
+
@req.response = @api.join_meeting_url("should-not-exist-in-server", "any", "any")
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^the response is an xml with the error "(.*)"$/ do |error|
|
27
|
+
# requests the join url and expects an ok with an xml in the response body
|
28
|
+
uri = URI(@req.response)
|
29
|
+
response = Net::HTTP.get_response(uri)
|
30
|
+
response.should be_a(Net::HTTPOK)
|
31
|
+
response.code.should == "200"
|
32
|
+
response["content-type"].should match(/text\/xml/)
|
33
|
+
response.body.should match(/#{error}/)
|
34
|
+
end
|
35
|
+
|
36
|
+
When /^the user tries to access the link to join the meeting using a wrong password$/ do
|
37
|
+
@req.response = @api.join_meeting_url(@req.id, "any-attendee", @req.mod_pass + "is wrong")
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
When /^the user creates a meeting pre\-uploading the following presentations:$/ do |table|
|
2
|
+
modules = BigBlueButton::BigBlueButtonModules.new
|
3
|
+
table.hashes.each do |pres|
|
4
|
+
modules.add_presentation(pres["type"].to_sym, pres["presentation"])
|
5
|
+
end
|
6
|
+
|
7
|
+
@req.id = Forgery(:basic).random_name("test-pre-upload")
|
8
|
+
@req.name = @req.id
|
9
|
+
@req.method = :create
|
10
|
+
@req.opts = {}
|
11
|
+
@req.response = @api.create_meeting(@req.id, @req.name, @req.opts, modules)
|
12
|
+
@req.mod_pass = @req.response[:moderatorPW]
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
When /^the user creates a meeting with the record flag$/ do
|
2
|
+
steps %Q{ When the default BigBlueButton server }
|
3
|
+
|
4
|
+
@req.id = Forgery(:basic).random_name("test-recordings")
|
5
|
+
@req.name = @req.id
|
6
|
+
@req.method = :create
|
7
|
+
@req.opts = { :record => true }
|
8
|
+
@req.response = @api.create_meeting(@req.id, @req.name, @req.opts)
|
9
|
+
@req.mod_pass = @req.response[:moderatorPW]
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^the meeting is set to be recorded$/ do
|
13
|
+
@req.response = @api.get_meeting_info(@req.id, @req.mod_pass)
|
14
|
+
@req.response[:returncode].should be_true
|
15
|
+
@req.response[:recording].should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
When /^the user creates a meeting without the record flag$/ do
|
19
|
+
steps %Q{ When the default BigBlueButton server }
|
20
|
+
|
21
|
+
@req.id = Forgery(:basic).random_name("test-recordings")
|
22
|
+
@req.name = @req.id
|
23
|
+
@req.method = :create
|
24
|
+
@req.opts = {}
|
25
|
+
@req.response = @api.create_meeting(@req.id, @req.name)
|
26
|
+
@req.mod_pass = @req.response[:moderatorPW]
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^the meeting is not set to be recorded$/i do
|
30
|
+
@req.response = @api.get_meeting_info(@req.id, @req.mod_pass)
|
31
|
+
@req.response[:returncode].should be_true
|
32
|
+
@req.response[:recording].should be_false
|
33
|
+
end
|
34
|
+
|
35
|
+
When /^the user calls the get_recordings method$/ do
|
36
|
+
@req.method = :get_recordings
|
37
|
+
@req.response = @api.get_recordings
|
38
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module BigBlueButtonAPITests
|
2
|
+
|
3
|
+
# Test object that stores information about an API request
|
4
|
+
class APIRequest
|
5
|
+
attr_accessor :opts # options hash
|
6
|
+
attr_accessor :id # meetind id
|
7
|
+
attr_accessor :mod_pass # moderator password
|
8
|
+
attr_accessor :name # meeting name
|
9
|
+
attr_accessor :method # last api method called
|
10
|
+
attr_accessor :response # last api response
|
11
|
+
attr_accessor :exception # last exception
|
12
|
+
end
|
13
|
+
|
14
|
+
# Global configurations
|
15
|
+
module Configs
|
16
|
+
class << self
|
17
|
+
attr_accessor :cfg # configuration file
|
18
|
+
attr_accessor :cfg_server # shortcut to the choosen server configs
|
19
|
+
attr_accessor :req # api request
|
20
|
+
|
21
|
+
def initialize_cfg
|
22
|
+
config_file = File.join(File.dirname(__FILE__), '..', '..', 'config.yml')
|
23
|
+
unless File.exist? config_file
|
24
|
+
throw Exception.new(config_file + " does not exists. Copy the example and configure your server.")
|
25
|
+
end
|
26
|
+
config = YAML.load_file(config_file)
|
27
|
+
config
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize_cfg_server
|
31
|
+
if ENV['SERVER']
|
32
|
+
unless self.cfg['servers'].has_key?(ENV['SERVER'])
|
33
|
+
throw Exception.new("Server #{ENV['SERVER']} does not exists in your configuration file.")
|
34
|
+
end
|
35
|
+
srv = self.cfg['servers'][ENV['SERVER']]
|
36
|
+
else
|
37
|
+
srv = self.cfg['servers'][self.cfg['servers'].keys.first]
|
38
|
+
end
|
39
|
+
srv['bbb_version'] = '0.7' unless srv.has_key?('bbb_version')
|
40
|
+
srv
|
41
|
+
end
|
42
|
+
|
43
|
+
def load
|
44
|
+
self.cfg = initialize_cfg
|
45
|
+
self.cfg_server = initialize_cfg_server
|
46
|
+
self.req = BigBlueButtonAPITests::APIRequest.new
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
$:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'bigbluebutton_api'
|
4
|
+
require 'forgery'
|
5
|
+
Dir["#{File.dirname(__FILE__)}/../../spec/support/forgery/**/*.rb"].each { |f| require f }
|
6
|
+
|
7
|
+
Dir["#{File.dirname(__FILE__)}/../../extras/**/*.rb"].each { |f| require f }
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Before do
|
2
|
+
# stores the global configurations in variables that are easier to access
|
3
|
+
BigBlueButtonAPITests::Configs.load
|
4
|
+
@config = BigBlueButtonAPITests::Configs.cfg
|
5
|
+
@config_server = BigBlueButtonAPITests::Configs.cfg_server
|
6
|
+
@req = BigBlueButtonAPITests::Configs.req
|
7
|
+
end
|
8
|
+
|
9
|
+
After do |scenario|
|
10
|
+
BigBlueButtonBot.finalize
|
11
|
+
end
|
data/lib/bigbluebutton_api.rb
CHANGED
@@ -3,37 +3,27 @@ require 'cgi'
|
|
3
3
|
require 'rexml/document'
|
4
4
|
require 'digest/sha1'
|
5
5
|
require 'rubygems'
|
6
|
-
require 'nokogiri'
|
7
6
|
require 'hash_to_xml'
|
8
7
|
require 'bigbluebutton_exception'
|
9
8
|
require 'bigbluebutton_formatter'
|
9
|
+
require 'bigbluebutton_modules'
|
10
10
|
|
11
11
|
module BigBlueButton
|
12
12
|
|
13
|
-
# This class provides access to the BigBlueButton API.
|
14
|
-
# is an open source project that provides web conferencing for distance
|
15
|
-
# education (http://code.google.com/p/bigbluebutton/wiki/API). This API
|
16
|
-
# was developed to support the following version of BBB: 0.7, 0.8 (soon)
|
13
|
+
# This class provides access to the BigBlueButton API. For more details see README.rdoc.
|
17
14
|
#
|
18
15
|
# Sample usage of the API is as follows:
|
19
|
-
# 1
|
20
|
-
# 2
|
21
|
-
# 3
|
16
|
+
# 1. Create a meeting with create_meeting;
|
17
|
+
# 2. Redirect a user to the URL returned by join_meeting_url;
|
18
|
+
# 3. Get information about the meetings with get_meetings and get_meeting_info;
|
19
|
+
# 4. To force meeting to end, call end_meeting .
|
22
20
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# 0.0.3 and below:
|
30
|
-
# Author:: Joe Kinsella (mailto:joe.kinsella@gmail.com)
|
31
|
-
# Copyright:: Copyright (c) 2010 Joe Kinsella
|
32
|
-
# License:: Distributes under same terms as Ruby
|
33
|
-
#
|
34
|
-
# Considerations about the returning hash:
|
35
|
-
# * The XML returned by BBB is converted to a Hash. See the desired method's documentation for examples.
|
36
|
-
# * Three values will *always* exist in the hash: :returncode (boolean), :messageKey (string) and :message (string)
|
21
|
+
# Important info about the data returned by the methods:
|
22
|
+
# * The XML returned by BBB is converted to a Hash. See individual method's documentation for examples.
|
23
|
+
# * Three values will *always* exist in the hash:
|
24
|
+
# * :returncode (boolean)
|
25
|
+
# * :messageKey (string)
|
26
|
+
# * :message (string)
|
37
27
|
# * Some of the values returned by BBB are converted to better represent the data. Some of these are listed
|
38
28
|
# bellow. They will *always* have the type informed:
|
39
29
|
# * :meetingID (string)
|
@@ -52,11 +42,11 @@ module BigBlueButton
|
|
52
42
|
# salt:: Secret salt for this server
|
53
43
|
# version:: API version: 0.7 (valid for 0.7, 0.71 and 0.71a)
|
54
44
|
def initialize(url, salt, version='0.7', debug=false)
|
55
|
-
@supported_versions = ['0.7']
|
45
|
+
@supported_versions = ['0.7', '0.8']
|
56
46
|
@url = url
|
57
47
|
@salt = salt
|
58
48
|
@debug = debug
|
59
|
-
@timeout =
|
49
|
+
@timeout = 10 # default timeout for api requests
|
60
50
|
|
61
51
|
@version = version || get_api_version
|
62
52
|
unless @supported_versions.include?(@version)
|
@@ -66,74 +56,107 @@ module BigBlueButton
|
|
66
56
|
puts "BigBlueButtonAPI: Using version #{@version}" if @debug
|
67
57
|
end
|
68
58
|
|
69
|
-
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
|
74
|
-
# web_voice_conf:: Custom voice-extension for users using VoIP
|
75
|
-
def join_meeting_url(meeting_id, user_name, password,
|
76
|
-
user_id = nil, web_voice_conf = nil)
|
77
|
-
|
78
|
-
params = { :meetingID => meeting_id, :password => password, :fullName => user_name,
|
79
|
-
:userID => user_id, :webVoiceConf => web_voice_conf }
|
80
|
-
get_url(:join, params)
|
81
|
-
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# API calls since 0.7
|
62
|
+
#
|
63
|
+
|
82
64
|
|
83
65
|
# Creates a new meeting. Returns the hash with the response or
|
84
66
|
# throws BigBlueButtonException on failure.
|
85
|
-
# meeting_name::
|
86
|
-
# meeting_id::
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
67
|
+
# meeting_name (string):: Name for the meeting
|
68
|
+
# meeting_id (string, integer):: Unique identifier for the meeting
|
69
|
+
# options (Hash):: Hash with optional parameters. The accepted parameters are:
|
70
|
+
# moderatorPW (string, int), attendeePW (string, int), welcome (string),
|
71
|
+
# dialNumber (int), logoutURL (string), maxParticipants (int),
|
72
|
+
# voiceBridge (int), record (boolean), duration (int) and "meta" parameters
|
73
|
+
# (usually strings). If a parameter passed in the hash is not supported it will
|
74
|
+
# simply be discarded. For details about each see BBB API docs.
|
75
|
+
# modules (BigBlueButtonModules):: Configuration for the modules. The modules are sent as an xml and the
|
76
|
+
# request will use an HTTP POST instead of GET. Currently only the
|
77
|
+
# "presentation" module is available. Only used for version > 0.8.
|
78
|
+
# See usage examples below.
|
93
79
|
#
|
94
|
-
# ===
|
80
|
+
# === Example
|
81
|
+
#
|
82
|
+
# options = { :moderatorPW => "123", :attendeePW => "321", :welcome => "Welcome here!",
|
83
|
+
# :dialNumber => 5190909090, :logoutURL => "http://mconf.org", :maxParticipants => 25,
|
84
|
+
# :voiceBridge => 76543, :record => "true", :duration => 0, :meta_category => "Remote Class" }
|
85
|
+
# create_meeting("My Meeting", "my-meeting", options)
|
86
|
+
#
|
87
|
+
# === Example with modules (see BigBlueButtonModules docs for more)
|
88
|
+
#
|
89
|
+
# modules = BigBlueButton::BigBlueButtonModules.new
|
90
|
+
# modules.add_presentation(:url, "http://www.samplepdf.com/sample.pdf")
|
91
|
+
# modules.add_presentation(:url, "http://www.samplepdf.com/sample2.pdf")
|
92
|
+
# modules.add_presentation(:file, "presentations/class01.ppt")
|
93
|
+
# modules.add_presentation(:base64, "JVBERi0xLjQKJ....[clipped here]....0CiUlRU9GCg==", "first-class.pdf")
|
94
|
+
# create_meeting("My Meeting", "my-meeting", nil, modules)
|
95
|
+
#
|
96
|
+
# === Example response for 0.7
|
95
97
|
#
|
96
98
|
# On successful creation:
|
97
99
|
#
|
98
100
|
# {
|
99
|
-
# :returncode=>true, :meetingID=>"
|
100
|
-
# :attendeePW=>"1234", :moderatorPW=>"4321", :hasBeenForciblyEnded=>false,
|
101
|
-
# :messageKey=>"", :message=>""
|
101
|
+
# :returncode => true, :meetingID => "test",
|
102
|
+
# :attendeePW => "1234", :moderatorPW => "4321", :hasBeenForciblyEnded => false,
|
103
|
+
# :messageKey => "", :message => ""
|
102
104
|
# }
|
103
105
|
#
|
104
106
|
# Meeting that was forcibly ended:
|
105
107
|
#
|
106
108
|
# {
|
107
|
-
# :returncode=>true, :meetingID=>"
|
108
|
-
# :attendeePW=>"1234", :moderatorPW=>"4321", :hasBeenForciblyEnded=>true,
|
109
|
-
# :messageKey=>"duplicateWarning",
|
110
|
-
# :message=>"This conference was already in existence and may currently be in progress."
|
109
|
+
# :returncode => true, :meetingID => "test",
|
110
|
+
# :attendeePW => "1234", :moderatorPW => "4321", :hasBeenForciblyEnded => true,
|
111
|
+
# :messageKey => "duplicateWarning",
|
112
|
+
# :message => "This conference was already in existence and may currently be in progress."
|
111
113
|
# }
|
112
114
|
#
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
115
|
+
# === Example response for 0.8
|
116
|
+
#
|
117
|
+
# {
|
118
|
+
# :returncode => true, :meetingID => "Test", :createTime => 1308591802,
|
119
|
+
# :attendeePW => "1234", :moderatorPW => "4321", :hasBeenForciblyEnded => false,
|
120
|
+
# :messageKey => "", :message => ""
|
121
|
+
# }
|
122
|
+
#
|
123
|
+
def create_meeting(meeting_name, meeting_id, options={}, modules=nil)
|
124
|
+
valid_options = [:moderatorPW, :attendeePW, :welcome, :maxParticipants,
|
125
|
+
:dialNumber, :voiceBridge, :webVoice, :logoutURL]
|
126
|
+
|
127
|
+
selected_opt = options.clone
|
128
|
+
if @version >= "0.8"
|
129
|
+
# v0.8 added "record", "duration" and "meta_" parameters
|
130
|
+
valid_options += [:record, :duration]
|
131
|
+
selected_opt.reject!{ |k,v| !valid_options.include?(k) and !(k.to_s =~ /^meta_.*$/) }
|
132
|
+
selected_opt[:record] = selected_opt[:record].to_s if selected_opt.has_key?(:record)
|
133
|
+
else
|
134
|
+
selected_opt.reject!{ |k,v| !valid_options.include?(k) }
|
135
|
+
end
|
136
|
+
params = { :name => meeting_name, :meetingID => meeting_id }.merge(selected_opt)
|
122
137
|
|
123
|
-
|
138
|
+
# with modules we send a post request (only for >= 0.8)
|
139
|
+
if modules and @version >= "0.8"
|
140
|
+
response = send_api_request(:create, params, modules.to_xml)
|
141
|
+
else
|
142
|
+
response = send_api_request(:create, params)
|
143
|
+
end
|
124
144
|
|
125
145
|
formatter = BigBlueButtonFormatter.new(response)
|
126
146
|
formatter.to_string(:meetingID)
|
127
147
|
formatter.to_string(:moderatorPW)
|
128
148
|
formatter.to_string(:attendeePW)
|
129
149
|
formatter.to_boolean(:hasBeenForciblyEnded)
|
150
|
+
if @version >= "0.8"
|
151
|
+
formatter.to_int(:createTime)
|
152
|
+
end
|
130
153
|
|
131
154
|
response
|
132
155
|
end
|
133
156
|
|
134
157
|
# Ends an existing meeting. Throws BigBlueButtonException on failure.
|
135
|
-
# meeting_id:: Unique identifier for the meeting
|
136
|
-
# moderator_password:: Moderator password
|
158
|
+
# meeting_id (string, int):: Unique identifier for the meeting
|
159
|
+
# moderator_password (string, int):: Moderator password
|
137
160
|
#
|
138
161
|
# === Return examples (for 0.7)
|
139
162
|
#
|
@@ -151,12 +174,29 @@ module BigBlueButton
|
|
151
174
|
|
152
175
|
# Returns true or false as to whether meeting is open. A meeting is
|
153
176
|
# only open after at least one participant has joined.
|
154
|
-
# meeting_id:: Unique identifier for the meeting
|
177
|
+
# meeting_id (string, int):: Unique identifier for the meeting
|
155
178
|
def is_meeting_running?(meeting_id)
|
156
179
|
hash = send_api_request(:isMeetingRunning, { :meetingID => meeting_id } )
|
157
180
|
BigBlueButtonFormatter.new(hash).to_boolean(:running)
|
158
181
|
end
|
159
182
|
|
183
|
+
# Returns the url used to join the meeting
|
184
|
+
# meeting_id (string, int):: Unique identifier for the meeting
|
185
|
+
# user_name (string):: Name of the user
|
186
|
+
# password (string):: Password for this meeting - used to set the user as moderator or attendee
|
187
|
+
# options (Hash):: Hash with optional parameters. The accepted parameters are:
|
188
|
+
# userID (string, int), webVoiceConf (string, int) and createTime (int).
|
189
|
+
# For details about each see BBB API docs.
|
190
|
+
def join_meeting_url(meeting_id, user_name, password, options={})
|
191
|
+
valid_options = [:userID, :webVoiceConf]
|
192
|
+
valid_options += [:createTime] if @version >= "0.8"
|
193
|
+
options.reject!{ |k,v| !valid_options.include?(k) }
|
194
|
+
|
195
|
+
params = { :meetingID => meeting_id, :password => password, :fullName => user_name }.merge(options)
|
196
|
+
|
197
|
+
get_url(:join, params)
|
198
|
+
end
|
199
|
+
|
160
200
|
# Warning: As of this version of the gem, this call does not work
|
161
201
|
# (instead of returning XML response, it should join the meeting).
|
162
202
|
#
|
@@ -164,14 +204,19 @@ module BigBlueButton
|
|
164
204
|
# directing the user's browser to moderator_url or attendee_url
|
165
205
|
# (note: this will still be required however to actually use bbb).
|
166
206
|
# Returns the URL a user can use to enter this meeting.
|
167
|
-
# meeting_id::
|
168
|
-
# user_name::
|
169
|
-
# password::
|
170
|
-
#
|
171
|
-
#
|
172
|
-
|
173
|
-
|
174
|
-
|
207
|
+
# meeting_id (string, int):: Unique identifier for the meeting
|
208
|
+
# user_name (string):: Name of the user
|
209
|
+
# password (string, int):: Moderator or attendee password for this meeting
|
210
|
+
# options (Hash):: Hash with optional parameters. The accepted parameters are:
|
211
|
+
# userID (string, int), webVoiceConf (string, int) and createTime (int).
|
212
|
+
# For details about each see BBB API docs.
|
213
|
+
def join_meeting(meeting_id, user_name, password, options={})
|
214
|
+
valid_options = [:userID, :webVoiceConf]
|
215
|
+
valid_options += [:createTime] if @version >= "0.8"
|
216
|
+
options.reject!{ |k,v| !valid_options.include?(k) }
|
217
|
+
|
218
|
+
params = { :meetingID => meeting_id, :password => password, :fullName => user_name }.merge(options)
|
219
|
+
|
175
220
|
send_api_request(:join, params)
|
176
221
|
end
|
177
222
|
|
@@ -179,10 +224,10 @@ module BigBlueButton
|
|
179
224
|
# See the API documentation for details on the return XML
|
180
225
|
# (http://code.google.com/p/bigbluebutton/wiki/API).
|
181
226
|
#
|
182
|
-
# meeting_id:: Unique identifier for the meeting
|
183
|
-
# password:: Moderator password for this meeting
|
227
|
+
# meeting_id (string, int):: Unique identifier for the meeting
|
228
|
+
# password (string, int):: Moderator password for this meeting
|
184
229
|
#
|
185
|
-
# ===
|
230
|
+
# === Example responses for 0.7
|
186
231
|
#
|
187
232
|
# With attendees:
|
188
233
|
#
|
@@ -205,12 +250,23 @@ module BigBlueButton
|
|
205
250
|
# :attendees=>[], :messageKey=>"", :message=>""
|
206
251
|
# }
|
207
252
|
#
|
253
|
+
# === Example responses for 0.8
|
254
|
+
#
|
255
|
+
# {
|
256
|
+
# :returncode => true, :meetingName => "test", :meetingID => "test", :createTime => 1321906390524,
|
257
|
+
# :voiceBridge => 72194, :attendeePW => "1234", :moderatorPW => "4321", :running => false, :recording => false,
|
258
|
+
# :hasBeenForciblyEnded => false, :startTime => nil, :endTime => nil, :participantCount => 0, :maxUsers => 9,
|
259
|
+
# :moderatorCount => 0, :attendees => [],
|
260
|
+
# :metadata => { :two => "TWO", :one => "one" },
|
261
|
+
# :messageKey => "", :message => ""
|
262
|
+
# }
|
263
|
+
#
|
208
264
|
def get_meeting_info(meeting_id, password)
|
209
265
|
response = send_api_request(:getMeetingInfo, { :meetingID => meeting_id, :password => password } )
|
210
266
|
|
211
267
|
formatter = BigBlueButtonFormatter.new(response)
|
212
268
|
formatter.flatten_objects(:attendees, :attendee)
|
213
|
-
response[:attendees].each { |a|
|
269
|
+
response[:attendees].each { |a| BigBlueButtonFormatter.format_attendee(a) }
|
214
270
|
|
215
271
|
formatter.to_string(:meetingID)
|
216
272
|
formatter.to_string(:moderatorPW)
|
@@ -219,6 +275,15 @@ module BigBlueButton
|
|
219
275
|
formatter.to_boolean(:running)
|
220
276
|
formatter.to_datetime(:startTime)
|
221
277
|
formatter.to_datetime(:endTime)
|
278
|
+
formatter.to_int(:participantCount)
|
279
|
+
formatter.to_int(:moderatorCount)
|
280
|
+
if @version >= "0.8"
|
281
|
+
formatter.to_string(:meetingName)
|
282
|
+
formatter.to_int(:maxUsers)
|
283
|
+
formatter.to_int(:voiceBridge)
|
284
|
+
formatter.to_int(:createTime)
|
285
|
+
formatter.to_boolean(:recording)
|
286
|
+
end
|
222
287
|
|
223
288
|
response
|
224
289
|
end
|
@@ -226,7 +291,7 @@ module BigBlueButton
|
|
226
291
|
# Returns a hash object containing information about the meetings currently existent in the BBB
|
227
292
|
# server, either they are running or not.
|
228
293
|
#
|
229
|
-
# ===
|
294
|
+
# === Example responses for 0.7
|
230
295
|
#
|
231
296
|
# Server with one or more meetings:
|
232
297
|
#
|
@@ -247,7 +312,7 @@ module BigBlueButton
|
|
247
312
|
|
248
313
|
formatter = BigBlueButtonFormatter.new(response)
|
249
314
|
formatter.flatten_objects(:meetings, :meeting)
|
250
|
-
response[:meetings].each { |m|
|
315
|
+
response[:meetings].each { |m| BigBlueButtonFormatter.format_meeting(m) }
|
251
316
|
response
|
252
317
|
end
|
253
318
|
|
@@ -259,13 +324,119 @@ module BigBlueButton
|
|
259
324
|
response[:returncode] ? response[:version].to_s : ""
|
260
325
|
end
|
261
326
|
|
262
|
-
|
327
|
+
|
328
|
+
|
329
|
+
#
|
330
|
+
# API calls since 0.8
|
331
|
+
#
|
332
|
+
|
333
|
+
# Retrieves the recordings that are available for playback for a given meetingID (or set of meeting IDs).
|
334
|
+
# options (Hash):: Hash with optional parameters. The accepted parameters are:
|
335
|
+
# :meetingID (string, Array). For details about each see BBB API docs.
|
336
|
+
# Any of the following values are accepted for :meetingID :
|
337
|
+
# :meetingID => "id1"
|
338
|
+
# :meetingID => "id1,id2,id3"
|
339
|
+
# :meetingID => ["id1"]
|
340
|
+
# :meetingID => ["id1", "id2", "id3"]
|
341
|
+
#
|
342
|
+
# === Example responses
|
343
|
+
# TODO: this example is not accurate yet
|
344
|
+
#
|
345
|
+
# { :returncode => true,
|
346
|
+
# :recordings => [
|
347
|
+
# {
|
348
|
+
# :recordID => "7f5745a08b24fa27551e7a065849dda3ce65dd32-1321618219268", :meetingID=>"bd1811beecd20f24314819a52ec202bf446ab94b",
|
349
|
+
# :name => "Evening Class1", :published => true,
|
350
|
+
# :startTime => #<DateTime: 2011-11-18T12:10:23+00:00 (212188378223/86400,0/1,2299161)>,
|
351
|
+
# :endTime => #<DateTime: 2011-11-18T12:12:25+00:00 (42437675669/17280,0/1,2299161)>,
|
352
|
+
# :metadata => { :course => "Fundamentals Of JAVA",
|
353
|
+
# :description => "List of recordings",
|
354
|
+
# :activity => "Evening Class1" },
|
355
|
+
# :playback => {
|
356
|
+
# :format => {
|
357
|
+
# :type => "slides",
|
358
|
+
# :url => "http://test-install.blindsidenetworks.com/playback/slides/playback.html?meetingId=7f5745a08b24fa27551e7a065849dda3ce65dd32-1321618219268",
|
359
|
+
# :length=>3
|
360
|
+
# }
|
361
|
+
# }
|
362
|
+
# },
|
363
|
+
# { :recordID => "183f0bf3a0982a127bdb8161-13085974450", :meetingID => "CS102",
|
364
|
+
# ...
|
365
|
+
# ...
|
366
|
+
# }
|
367
|
+
# ]
|
368
|
+
# }
|
369
|
+
#
|
370
|
+
def get_recordings(options={})
|
371
|
+
raise BigBlueButtonException.new("Method only supported for versions >= 0.8") if @version < "0.8"
|
372
|
+
|
373
|
+
valid_options = [:meetingID]
|
374
|
+
options.reject!{ |k,v| !valid_options.include?(k) }
|
375
|
+
|
376
|
+
# ["id1", "id2", "id3"] becomes "id1,id2,id3"
|
377
|
+
if options.has_key?(:meetingID)
|
378
|
+
options[:meetingID] = options[:meetingID].join(",") if options[:meetingID].instance_of?(Array)
|
379
|
+
end
|
380
|
+
|
381
|
+
response = send_api_request(:getRecordings, options)
|
382
|
+
|
383
|
+
formatter = BigBlueButtonFormatter.new(response)
|
384
|
+
formatter.flatten_objects(:recordings, :recording)
|
385
|
+
response[:recordings].each { |r| BigBlueButtonFormatter.format_recording(r) }
|
386
|
+
response
|
387
|
+
end
|
388
|
+
|
389
|
+
# Publish and unpublish recordings for a given recordID (or set of record IDs).
|
390
|
+
# recordIDs (string, Array):: ID or IDs of the target recordings.
|
391
|
+
# Any of the following values are accepted:
|
392
|
+
# "id1"
|
393
|
+
# "id1,id2,id3"
|
394
|
+
# ["id1"]
|
395
|
+
# ["id1", "id2", "id3"]
|
396
|
+
# publish (boolean):: Publish or unpublish the recordings?
|
397
|
+
#
|
398
|
+
# === Example responses
|
399
|
+
#
|
400
|
+
# { :returncode => true, :published => true }
|
401
|
+
#
|
402
|
+
def publish_recordings(recordIDs, publish)
|
403
|
+
raise BigBlueButtonException.new("Method only supported for versions >= 0.8") if @version < "0.8"
|
404
|
+
|
405
|
+
recordIDs = recordIDs.join(",") if recordIDs.instance_of?(Array) # ["id1", "id2"] becomes "id1,id2"
|
406
|
+
response = send_api_request(:publishRecordings, { :recordID => recordIDs, :publish => publish.to_s })
|
407
|
+
end
|
408
|
+
|
409
|
+
# Delete one or more recordings for a given recordID (or set of record IDs).
|
410
|
+
# recordIDs (string, Array):: ID or IDs of the target recordings.
|
411
|
+
# Any of the following values are accepted:
|
412
|
+
# "id1"
|
413
|
+
# "id1,id2,id3"
|
414
|
+
# ["id1"]
|
415
|
+
# ["id1", "id2", "id3"]
|
416
|
+
#
|
417
|
+
# === Example responses
|
418
|
+
#
|
419
|
+
# { :returncode => true, :deleted => true }
|
420
|
+
#
|
421
|
+
def delete_recordings(recordIDs)
|
422
|
+
raise BigBlueButtonException.new("Method only supported for versions >= 0.8") if @version < "0.8"
|
423
|
+
|
424
|
+
recordIDs = recordIDs.join(",") if recordIDs.instance_of?(Array) # ["id1", "id2"] becomes "id1,id2"
|
425
|
+
response = send_api_request(:deleteRecordings, { :recordID => recordIDs })
|
426
|
+
end
|
427
|
+
|
428
|
+
|
429
|
+
#
|
430
|
+
# Helper functions
|
431
|
+
#
|
432
|
+
|
433
|
+
# Make a simple request to the server to test the connection.
|
263
434
|
def test_connection
|
264
435
|
response = send_api_request(:index)
|
265
436
|
response[:returncode]
|
266
437
|
end
|
267
438
|
|
268
|
-
# API's are equal if all the following attributes are equal
|
439
|
+
# API's are equal if all the following attributes are equal.
|
269
440
|
def ==(other)
|
270
441
|
r = true
|
271
442
|
[:url, :supported_versions, :salt, :version, :debug].each do |param|
|
@@ -274,11 +445,20 @@ module BigBlueButton
|
|
274
445
|
r
|
275
446
|
end
|
276
447
|
|
448
|
+
# Returns the HTTP response object returned in the last API call.
|
277
449
|
def last_http_response
|
278
450
|
@http_response
|
279
451
|
end
|
280
452
|
|
281
|
-
|
453
|
+
# Returns the XML returned in the last API call.
|
454
|
+
def last_xml_response
|
455
|
+
@xml_response
|
456
|
+
end
|
457
|
+
|
458
|
+
# Formats an API call URL for the method 'method' using the parameters in 'params'.
|
459
|
+
# method (symbol):: The API method to be called (:create, :index, :join, and others)
|
460
|
+
# params (Hash):: The parameters to be passed in the URL
|
461
|
+
def get_url(method, params={})
|
282
462
|
if method == :index
|
283
463
|
return @url
|
284
464
|
end
|
@@ -286,38 +466,50 @@ module BigBlueButton
|
|
286
466
|
url = "#{@url}/#{method}?"
|
287
467
|
|
288
468
|
# stringify and escape all params
|
289
|
-
|
290
|
-
|
291
|
-
|
469
|
+
params.delete_if { |k, v| v.nil? } unless params.nil?
|
470
|
+
params_string = ""
|
471
|
+
params_string = params.map{ |k,v| "#{k}=" + CGI::escape(v.to_s) unless k.nil? || v.nil? }.join("&")
|
292
472
|
|
293
473
|
# checksum calc
|
294
|
-
checksum_param =
|
474
|
+
checksum_param = params_string + @salt
|
295
475
|
checksum_param = method.to_s + checksum_param
|
296
476
|
checksum = Digest::SHA1.hexdigest(checksum_param)
|
297
477
|
|
298
478
|
# final url
|
299
|
-
url += "#{
|
479
|
+
url += "#{params_string}&" unless params_string.empty?
|
300
480
|
url += "checksum=#{checksum}"
|
301
481
|
end
|
302
482
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
483
|
+
# Performs an API call.
|
484
|
+
#
|
485
|
+
# Throws a BigBlueButtonException if something goes wrong (e.g. server offline).
|
486
|
+
# Also throws an exception of the request was not successful (i.e. returncode == FAILED).
|
487
|
+
#
|
488
|
+
# Only formats the standard values in the response (the ones that exist in all responses).
|
489
|
+
#
|
490
|
+
# method (symbol):: The API method to be called (:create, :index, :join, and others)
|
491
|
+
# params (Hash):: The parameters to be passed in the URL
|
492
|
+
# data (string):: Data to be sent with the request. If set, the request will use an HTTP
|
493
|
+
# POST instead of a GET and the data will be sent in the request body.
|
494
|
+
def send_api_request(method, params={}, data=nil)
|
495
|
+
url = get_url(method, params)
|
496
|
+
|
497
|
+
@http_response = send_request(url, data)
|
307
498
|
return { } if @http_response.body.empty?
|
308
499
|
|
309
500
|
# 'Hashify' the XML
|
310
|
-
|
501
|
+
@xml_response = @http_response.body
|
502
|
+
hash = Hash.from_xml(@xml_response)
|
311
503
|
|
312
504
|
# simple validation of the xml body
|
313
|
-
unless hash.has_key?(:
|
505
|
+
unless hash.has_key?(:returncode)
|
314
506
|
raise BigBlueButtonException.new("Invalid response body. Is the API URL correct? \"#{@url}\", version #{@version}")
|
315
507
|
end
|
316
508
|
|
317
509
|
# default cleanup in the response
|
318
510
|
hash = BigBlueButtonFormatter.new(hash).default_formatting
|
319
511
|
|
320
|
-
#
|
512
|
+
# if the return code is an error generates an exception
|
321
513
|
unless hash[:returncode]
|
322
514
|
exception = BigBlueButtonException.new(hash[:message])
|
323
515
|
exception.key = hash.has_key?(:messageKey) ? hash[:messageKey] : ""
|
@@ -329,20 +521,32 @@ module BigBlueButton
|
|
329
521
|
|
330
522
|
protected
|
331
523
|
|
332
|
-
|
524
|
+
# :nodoc:
|
525
|
+
# If data is set, uses a POST with data in the request body
|
526
|
+
# Otherwise uses GET
|
527
|
+
def send_request(url, data=nil)
|
333
528
|
begin
|
334
529
|
puts "BigBlueButtonAPI: URL request = #{url}" if @debug
|
335
530
|
url_parsed = URI.parse(url)
|
336
531
|
http = Net::HTTP.new(url_parsed.host, url_parsed.port)
|
337
532
|
http.open_timeout = @timeout
|
338
533
|
http.read_timeout = @timeout
|
339
|
-
|
534
|
+
if data.nil?
|
535
|
+
response = http.get(url_parsed.request_uri)
|
536
|
+
else
|
537
|
+
puts "BigBlueButtonAPI: Sending as a POST request with data.size = #{data.size}" if @debug
|
538
|
+
opts = { 'Content-Type' => 'text/xml' }
|
539
|
+
response = http.post(url_parsed.request_uri, data, opts)
|
540
|
+
end
|
340
541
|
puts "BigBlueButtonAPI: URL response = #{response.body}" if @debug
|
542
|
+
|
341
543
|
rescue TimeoutError => error
|
342
544
|
raise BigBlueButtonException.new("Timeout error. Your server is probably down: \"#{@url}\"")
|
545
|
+
|
343
546
|
rescue Exception => error
|
344
547
|
raise BigBlueButtonException.new("Connection error. Your URL is probably incorrect: \"#{@url}\"")
|
345
548
|
end
|
549
|
+
|
346
550
|
response
|
347
551
|
end
|
348
552
|
|