bigbluebutton-api-ruby 0.0.11 → 0.1.0.rc1
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/.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
|
|