opentok 0.0.92 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +3 -0
- data/README.md +17 -10
- data/lib/open_tok/archive.rb +11 -11
- data/lib/open_tok/archive_timeline_event.rb +3 -3
- data/lib/open_tok/archive_video_resource.rb +2 -2
- data/lib/open_tok/exception.rb +38 -0
- data/lib/open_tok/open_tok_sdk.rb +104 -82
- data/lib/open_tok/request.rb +21 -15
- data/lib/open_tok/role_constants.rb +18 -0
- data/lib/open_tok/session.rb +7 -4
- data/lib/open_tok/session_property_constants.rb +30 -0
- data/lib/open_tok/utils.rb +3 -12
- data/lib/open_tok/version.rb +4 -2
- data/lib/opentok.rb +5 -11
- data/opentok.gemspec +2 -1
- data/spec/opentok_exception_spec.rb +38 -0
- data/spec/opentok_spec.rb +26 -32
- data/spec/spec_helper.rb +1 -1
- metadata +24 -3
data/.rspec
ADDED
data/README.md
CHANGED
@@ -14,12 +14,12 @@ To install as a regular gem just type `gem install opentok`
|
|
14
14
|
|
15
15
|
## Requirements
|
16
16
|
|
17
|
-
You need an api-key and secret.
|
17
|
+
You need an api-key and secret. Sign up at <http://www.tokbox.com/opentok/tools/js/apikey>.
|
18
18
|
|
19
19
|
# OpenTokSDK
|
20
20
|
|
21
21
|
In order to use any of the server side functions, you must first create an `OpenTokSDK` object with your developer credentials.
|
22
|
-
`OpenTokSDK` takes 2
|
22
|
+
`OpenTokSDK` takes 2 parameters:
|
23
23
|
> key (string) - Given to you when you register
|
24
24
|
> secret (string) - Given to you when you register
|
25
25
|
|
@@ -31,22 +31,25 @@ OTSDK = OpenTok::OpenTokSDK.new API_KEY, API_SECRET
|
|
31
31
|
</pre>
|
32
32
|
|
33
33
|
|
34
|
-
|
34
|
+
## Creating Sessions
|
35
35
|
Use your `OpenTokSDK` object to create `session_id`
|
36
36
|
`createSession` takes 1-2 parameters:
|
37
|
-
> location (string) -
|
38
|
-
> properties (object) - OPTIONAL. Set peer to peer as `enabled` or `disabled`. Disabled by default
|
37
|
+
> location (string) - OPTIONAL. a location so OpenTok can stream through the closest server
|
38
|
+
> properties (object) - OPTIONAL. Set peer to peer as `enabled` or `disabled`. Disabled by default
|
39
39
|
|
40
40
|
<pre>
|
41
|
+
# creating a simple session: closest streaming server will be automatically determined when user connects to session
|
42
|
+
sessionId = OTSDK.createSession().to_s
|
43
|
+
|
41
44
|
# Creating Session object, passing request IP address to determine closest production server
|
42
|
-
|
45
|
+
sessionId = OTSDK.createSession( request.remote_ip ).to_s
|
43
46
|
|
44
47
|
# Creating Session object with p2p enabled
|
45
48
|
sessionProperties = {OpenTok::SessionPropertyConstants::P2P_PREFERENCE => "enabled"} # or disabled
|
46
|
-
sessionId = OTSDK.createSession( @location, sessionProperties )
|
49
|
+
sessionId = OTSDK.createSession( @location, sessionProperties ).to_s
|
47
50
|
</pre>
|
48
51
|
|
49
|
-
|
52
|
+
## Generating Tokens
|
50
53
|
With the generated sessionId, you can start generating tokens for each user.
|
51
54
|
`generate_token` takes in hash with 1-4 properties:
|
52
55
|
> session_id (string) - REQUIRED
|
@@ -59,10 +62,14 @@ With the generated sessionId, you can start generating tokens for each user.
|
|
59
62
|
token = OTSDK.generateToken :session_id => session, :role => OpenTok::RoleConstants::PUBLISHER, :connection_data => "username=Bob,level=4"
|
60
63
|
</pre>
|
61
64
|
|
62
|
-
|
65
|
+
Possible Errors:
|
66
|
+
> "Null or empty session ID are not valid"
|
67
|
+
> "An invalid session ID was passed"
|
68
|
+
|
69
|
+
## Manipulating Archive Videos
|
63
70
|
To Download or delete archived video, you must have an Archive ID which you get from the javascript library. If you are unfamiliar with archiving concepts, please visit our [archiving tutorial](http://www.tokbox.com/opentok/api/documentation/gettingstartedarchiving)
|
64
71
|
|
65
|
-
|
72
|
+
## Delete Archives
|
66
73
|
OpenTok SDK has a function `deleteArchive` that lets you delete videos in a recorded archive.
|
67
74
|
Use your `OpenTokSDK` object to call `deleteArchive`
|
68
75
|
`deleteArchive` takes in 2 parameters and returns a true or false boolean representing the success of the delete request
|
data/lib/open_tok/archive.rb
CHANGED
@@ -19,35 +19,35 @@ module OpenTok
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def do_request(path, token)
|
22
|
-
|
22
|
+
Request.new(@api_url, token).fetch(path)
|
23
23
|
end
|
24
24
|
|
25
25
|
def download_archive_url(video_id, token="")
|
26
|
-
if token
|
26
|
+
if token.empty?
|
27
27
|
# this token check supports previous implementation of download_archive_url
|
28
|
-
|
28
|
+
"#{@api_url}/archive/url/#{@archive_id}/#{video_id}"
|
29
29
|
else
|
30
|
-
|
31
|
-
return doc
|
30
|
+
do_request "/archive/url/#{@archive_id}/#{video_id}", token
|
32
31
|
end
|
33
32
|
end
|
33
|
+
|
34
34
|
alias_method :downloadArchiveURL, :download_archive_url
|
35
35
|
|
36
|
-
def self.parse_manifest(manifest,
|
36
|
+
def self.parse_manifest(manifest, api_url, token)
|
37
37
|
archive_id = manifest.attributes['archiveid']
|
38
38
|
archive_title = manifest.attributes['title']
|
39
39
|
|
40
40
|
resources = []
|
41
|
-
manifest.get_elements(
|
42
|
-
resources <<
|
41
|
+
manifest.get_elements('resources')[0].get_elements('video').each do |video|
|
42
|
+
resources << ArchiveVideoResource.parseXML(video)
|
43
43
|
end
|
44
44
|
|
45
45
|
timeline = []
|
46
|
-
manifest.get_elements(
|
47
|
-
timeline <<
|
46
|
+
manifest.get_elements('timeline')[0].get_elements('event').each do |event|
|
47
|
+
timeline << ArchiveTimelineEvent.parseXML(event)
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
Archive.new archive_id, archive_title, resources, timeline, api_url, token
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -8,7 +8,7 @@
|
|
8
8
|
module OpenTok
|
9
9
|
class ArchiveTimelineEvent
|
10
10
|
attr_accessor :event_type, :resource_id, :offset
|
11
|
-
|
11
|
+
|
12
12
|
def initialize(event_type, resource_id, offset)
|
13
13
|
@event_type = event_type
|
14
14
|
@resource_id = resource_id
|
@@ -16,7 +16,7 @@ module OpenTok
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.parseXML(timeline_item)
|
19
|
-
OpenTok::ArchiveTimelineEvent.new
|
19
|
+
OpenTok::ArchiveTimelineEvent.new timeline_item.attributes['type'], timeline_item.attributes['id'], timeline_item.attributes['offset']
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
22
22
|
end
|
@@ -21,8 +21,8 @@ module OpenTok
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.parseXML(video_resource_item)
|
24
|
-
|
24
|
+
ArchiveVideoResource.new video_resource_item.attributes['id'], video_resource_item.attributes['length']
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
end
|
data/lib/open_tok/exception.rb
CHANGED
@@ -10,6 +10,44 @@ module OpenTok
|
|
10
10
|
|
11
11
|
# The exception that gets thrown when an invalid api-key and/or secret is given.
|
12
12
|
class OpenTokException < RuntimeError
|
13
|
+
|
14
|
+
def initialize(code, message)
|
15
|
+
@code = code
|
16
|
+
@mesasge = message
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def inherited(subclass)
|
21
|
+
exceptions << subclass
|
22
|
+
end
|
23
|
+
|
24
|
+
def exceptions
|
25
|
+
@exceptions ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Generates the relevant exception instance based on the XML error data received
|
30
|
+
def from_error(error)
|
31
|
+
child = error.get_elements('Errors')[0].get_elements('error')[0]
|
32
|
+
code = child.attributes['code']
|
33
|
+
exception = exceptions.find{|exc| exc.http_code == code }
|
34
|
+
exception ||= self
|
35
|
+
message = child.children.empty? ? '' : child.children[0].attributes['message']
|
36
|
+
exception.new code, message
|
37
|
+
end
|
38
|
+
|
39
|
+
# To be overriden by subclasses
|
40
|
+
def http_code
|
41
|
+
'000'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class OpenTokNotFound < OpenTokException
|
48
|
+
def self.http_code
|
49
|
+
'404'
|
50
|
+
end
|
13
51
|
end
|
14
52
|
|
15
53
|
end
|
@@ -10,142 +10,163 @@ require 'openssl'
|
|
10
10
|
require 'base64'
|
11
11
|
require 'rexml/document'
|
12
12
|
|
13
|
-
DIGEST = OpenSSL::Digest::Digest.new
|
13
|
+
DIGEST = OpenSSL::Digest::Digest.new 'sha1'
|
14
14
|
|
15
15
|
module OpenTok
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
MULTIPLEXER_NUMOUTPUTSTREAMS = "multiplexer.numOutputStreams" #Integer
|
27
|
-
MULTIPLEXER_SWITCHTYPE = "multiplexer.switchType" #Integer
|
28
|
-
MULTIPLEXER_SWITCHTIMEOUT = "multiplexer.switchTimeout" #Integer
|
29
|
-
P2P_PREFERENCE = "p2p.preference" #String
|
30
|
-
end
|
31
|
-
|
32
|
-
# RoleConstants
|
33
|
-
#
|
34
|
-
# * +SUBSCRIBER+ Can only subscribe
|
35
|
-
# * +PUBLISHER+ Can publish, subscribe, and signal
|
36
|
-
# * +MODERATOR+ Can do the above along with forceDisconnect and forceUnpublish
|
37
|
-
module RoleConstants
|
38
|
-
SUBSCRIBER = "subscriber" #Can only subscribe
|
39
|
-
PUBLISHER = "publisher" #Can publish, subscribe, and signal
|
40
|
-
MODERATOR = "moderator" #Can do the above along with forceDisconnect and forceUnpublish
|
41
|
-
end
|
17
|
+
autoload :Archive , 'open_tok/archive'
|
18
|
+
autoload :ArchiveVideoResource , 'open_tok/archive_video_resource'
|
19
|
+
autoload :ArchiveTimelineEvent , 'open_tok/archive_timeline_event'
|
20
|
+
autoload :OpenTokException , 'open_tok/exception'
|
21
|
+
autoload :Request , 'open_tok/request'
|
22
|
+
autoload :RoleConstants , 'open_tok/role_constants'
|
23
|
+
autoload :Session , 'open_tok/session'
|
24
|
+
autoload :SessionPropertyConstants, 'open_tok/session_property_constants'
|
25
|
+
autoload :Utils , 'open_tok/utils'
|
42
26
|
|
43
27
|
class OpenTokSDK
|
44
|
-
|
28
|
+
attr_reader :api_url
|
45
29
|
|
46
|
-
|
30
|
+
TOKEN_SENTINEL = "T1=="
|
47
31
|
|
48
|
-
|
32
|
+
##
|
33
|
+
# Create a new OpenTok REST API client
|
49
34
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
|
35
|
+
# @param [String] API Key, developer identifier
|
36
|
+
# @param [String] API Secret, developer identifier
|
37
|
+
# @param [String] back_support @deprecated
|
38
|
+
# @param [String] OpenTok endpoint, production by default
|
39
|
+
def initialize(partner_id, partner_secret, back_support = '', api_url = OpenTok::API_URL)
|
53
40
|
@partner_id = partner_id
|
54
41
|
@partner_secret = partner_secret
|
55
|
-
@api_url =
|
42
|
+
@api_url = api_url
|
56
43
|
end
|
57
44
|
|
58
|
-
|
59
|
-
#
|
60
|
-
# * +:create_time+
|
61
|
-
# * +:expire_time+ (optional) The time when the token will expire, defined as an integer value for a Unix timestamp (in seconds). If you do not specify this value, tokens expire in 24 hours after being created.
|
62
|
-
# * +:role+ (optional) Added in OpenTok v0.91.5. This defines the role the user will have. There are three roles: subscriber, publisher, and moderator.
|
63
|
-
# * +:connection_data+ (optional) Added in OpenTok v0.91.20. A string containing metadata describing the connection.
|
45
|
+
##
|
46
|
+
# Generate token for the given session_id
|
64
47
|
#
|
48
|
+
# @param [Hash] opts the options to create a token with.
|
49
|
+
# @option opts [String] :session_id (mandatory) generate a token for the provided session
|
50
|
+
# @option opts [String] :create_time (optional)
|
51
|
+
# @option opts [String] :expire_time (optional) The time when the token will expire, defined as an integer value for a Unix timestamp (in seconds). If you do not specify this value, tokens expire in 24 hours after being created.
|
52
|
+
# @option opts [String] :role (optional) Added in OpenTok v0.91.5. This defines the role the user will have. There are three roles: subscriber, publisher, and moderator.
|
53
|
+
# @option opts [String] :connection_data (optional) Added in OpenTok v0.91.20. A string containing metadata describing the connection.
|
65
54
|
# See http://www.tokbox.com/opentok/tools/documentation/overview/token_creation.html for more information on all options.
|
66
55
|
def generate_token(opts = {})
|
67
|
-
|
56
|
+
create_time = opts.fetch(:create_time, Time.now)
|
57
|
+
session_id = opts.fetch(:session_id, '').to_s
|
68
58
|
|
69
|
-
|
70
|
-
session_id
|
71
|
-
|
59
|
+
# check validity of session_id
|
60
|
+
if !session_id || session_id.to_s.length == ""
|
61
|
+
raise "Null or empty session ID are not valid"
|
62
|
+
end
|
72
63
|
|
73
|
-
|
74
|
-
|
64
|
+
begin
|
65
|
+
subSessionId = session_id[2..session_id.length]
|
66
|
+
subSessionId.sub!("-","+").sub!("_","/")
|
67
|
+
decodedSessionId = Base64.decode64(subSessionId).split("~")
|
68
|
+
(0..4).each do |n|
|
69
|
+
if decodedSessionId and decodedSessionId.length > 1
|
70
|
+
break
|
71
|
+
end
|
72
|
+
subSessionId = subSessionId+"="
|
73
|
+
end
|
74
|
+
unless decodedSessionId[1] == @partner_id
|
75
|
+
raise "An invalid session ID was passed"
|
76
|
+
end
|
77
|
+
rescue Exception => e
|
78
|
+
raise "An invalid session ID was passed"
|
75
79
|
end
|
76
80
|
|
81
|
+
|
82
|
+
role = opts.fetch(:role, RoleConstants::PUBLISHER)
|
83
|
+
|
84
|
+
RoleConstants.is_valid?(role) or raise OpenTokException.new "'#{role}' is not a recognized role"
|
85
|
+
|
77
86
|
data_params = {
|
78
87
|
:role => role,
|
79
|
-
:session_id => session_id,
|
88
|
+
:session_id => session_id.is_a?(Session) ? session_id.session_id : session_id,
|
80
89
|
:create_time => create_time.to_i,
|
81
90
|
:nonce => rand
|
82
91
|
}
|
83
92
|
|
84
|
-
|
85
|
-
raise OpenTokException.new 'Expire time must be a number'
|
86
|
-
raise OpenTokException.new 'Expire time must be in the future'
|
87
|
-
raise OpenTokException.new 'Expire time must be in the next 30 days'
|
93
|
+
unless opts[:expire_time].nil?
|
94
|
+
opts[:expire_time].is_a?(Numeric) or raise OpenTokException.new 'Expire time must be a number'
|
95
|
+
opts[:expire_time] < Time.now.to_i and raise OpenTokException.new 'Expire time must be in the future'
|
96
|
+
opts[:expire_time] > (Time.now.to_i + 2592000) and raise OpenTokException.new 'Expire time must be in the next 30 days'
|
88
97
|
data_params[:expire_time] = opts[:expire_time].to_i
|
89
98
|
end
|
90
99
|
|
91
|
-
|
92
|
-
raise OpenTokException.new 'Connection data must be less than 1000 characters'
|
100
|
+
unless opts[:connection_data].nil?
|
101
|
+
opts[:connection_data].length > 1000 and raise OpenTokException.new 'Connection data must be less than 1000 characters'
|
93
102
|
data_params[:connection_data] = opts[:connection_data]
|
94
103
|
end
|
95
104
|
|
96
|
-
data_string =
|
105
|
+
data_string = Utils.urlencode_hash(data_params)
|
97
106
|
|
98
|
-
sig = sign_string
|
99
|
-
meta_string =
|
107
|
+
sig = sign_string data_string, @partner_secret
|
108
|
+
meta_string = Utils.urlencode_hash(:partner_id => @partner_id, :sig => sig)
|
100
109
|
|
101
|
-
|
110
|
+
TOKEN_SENTINEL + Base64.encode64(meta_string + ":" + data_string).gsub("\n", '')
|
102
111
|
end
|
112
|
+
|
103
113
|
alias_method :generateToken, :generate_token
|
104
114
|
|
105
|
-
|
115
|
+
##
|
116
|
+
# Generates a new OpenTok::Session and set it's session_id,
|
117
|
+
# situating it in TokBox's global network near the IP of the specified @location@.
|
118
|
+
#
|
119
|
+
# param: location
|
120
|
+
# param: opts: valid
|
106
121
|
#
|
107
122
|
# See http://www.tokbox.com/opentok/tools/documentation/overview/session_creation.html for more information
|
108
123
|
def create_session(location='', opts={})
|
109
|
-
opts.merge!({:
|
110
|
-
doc = do_request
|
111
|
-
|
124
|
+
opts.merge!({:location => location})
|
125
|
+
doc = do_request '/session/create', opts
|
126
|
+
|
127
|
+
unless doc.get_elements('Errors').empty?
|
112
128
|
raise OpenTokException.new doc.get_elements('Errors')[0].get_elements('error')[0].children.to_s
|
113
129
|
end
|
114
|
-
|
130
|
+
Session.new doc.root.get_elements('Session')[0].get_elements('session_id')[0].children[0].to_s
|
115
131
|
end
|
132
|
+
|
116
133
|
alias_method :createSession, :create_session
|
117
134
|
|
118
|
-
|
119
|
-
#
|
135
|
+
##
|
136
|
+
# Download an OpenTok archive manifest.
|
137
|
+
# The archive manifest contains video IDs for each recorded stream in the archive.
|
138
|
+
#
|
139
|
+
# @param [String] archive identifier
|
140
|
+
# @param [String] token
|
141
|
+
#
|
142
|
+
# @return [OpenTok::Archive]
|
120
143
|
def get_archive_manifest(archive_id, token)
|
121
144
|
# TODO: verify that token is MODERATOR token
|
122
|
-
|
123
|
-
doc
|
124
|
-
|
145
|
+
doc = do_request "/archive/getmanifest/#{archive_id}", {}, token
|
146
|
+
if doc.get_elements('Errors').empty?
|
147
|
+
Archive.parse_manifest doc.get_elements('manifest')[0], @api_url, token
|
148
|
+
else
|
125
149
|
raise OpenTokException.new doc.get_elements('Errors')[0].get_elements('error')[0].children.to_s
|
126
150
|
end
|
127
|
-
OpenTok::Archive.parse_manifest(doc.get_elements('manifest')[0], @api_url, token)
|
128
151
|
end
|
152
|
+
|
129
153
|
alias_method :getArchiveManifest, :get_archive_manifest
|
130
154
|
|
131
|
-
def delete_archive(
|
132
|
-
|
133
|
-
doc = do_request( deleteURL, {test => 'none'}, token )
|
155
|
+
def delete_archive(archive_id, token)
|
156
|
+
doc = do_request "/archive/delete/#{archive_id}", {:test => 'none'}, token
|
134
157
|
errors = doc.get_elements('Errors')
|
135
158
|
if doc.get_elements('Errors').empty?
|
136
|
-
|
137
|
-
#errorCode = attributes['code']
|
138
|
-
return true
|
159
|
+
true
|
139
160
|
else
|
140
|
-
|
161
|
+
raise OpenTokException.from_error doc
|
141
162
|
end
|
142
163
|
end
|
164
|
+
|
143
165
|
alias_method :deleteArchive, :delete_archive
|
144
166
|
|
145
|
-
def stitchArchive(
|
146
|
-
|
147
|
-
|
148
|
-
response = request.sendRequest(stitchURL, {test => 'none'})
|
167
|
+
def stitchArchive(archive_id)
|
168
|
+
request = Request.new(@api_url, nil, @partner_id, @partner_secret)
|
169
|
+
response = request.sendRequest("/archive/#{archive_id}/stitch", {:test => 'none'})
|
149
170
|
case response.code
|
150
171
|
when '201'
|
151
172
|
return {:code=>201, :message=>"Successfully Created", :location=>response["location"]}
|
@@ -158,19 +179,20 @@ module OpenTok
|
|
158
179
|
else
|
159
180
|
return {:code=>500, :message=>"Server Error"}
|
160
181
|
end
|
161
|
-
return {}
|
162
182
|
end
|
183
|
+
|
163
184
|
alias_method :stitch, :stitchArchive
|
164
185
|
|
165
186
|
protected
|
187
|
+
|
166
188
|
def sign_string(data, secret)
|
167
189
|
OpenSSL::HMAC.hexdigest(DIGEST, secret, data)
|
168
190
|
end
|
169
191
|
|
170
192
|
def do_request(path, params, token=nil)
|
171
|
-
request =
|
172
|
-
body = request.fetch
|
173
|
-
REXML::Document.new
|
193
|
+
request = Request.new @api_url, token, @partner_id, @partner_secret
|
194
|
+
body = request.fetch path, params
|
195
|
+
REXML::Document.new body
|
174
196
|
end
|
175
197
|
end
|
176
198
|
end
|
data/lib/open_tok/request.rb
CHANGED
@@ -7,7 +7,7 @@ Net::HTTP.version_1_2 # to make sure version 1.2 is used
|
|
7
7
|
module OpenTok
|
8
8
|
class Request
|
9
9
|
|
10
|
-
def initialize(api_host, token, partner_id=nil, partner_secret=nil)
|
10
|
+
def initialize(api_host, token, partner_id = nil, partner_secret = nil)
|
11
11
|
@api_host = api_host
|
12
12
|
@token = token
|
13
13
|
@partner_id = partner_id
|
@@ -17,29 +17,24 @@ module OpenTok
|
|
17
17
|
def sendRequest(path, params)
|
18
18
|
url = URI.parse(@api_host + path)
|
19
19
|
|
20
|
-
if params.empty?
|
21
|
-
req = Net::HTTP::Get.new
|
20
|
+
if params.nil? || params.empty?
|
21
|
+
req = Net::HTTP::Get.new url.path
|
22
22
|
else
|
23
|
-
req = Net::HTTP::Post.new
|
23
|
+
req = Net::HTTP::Post.new url.path
|
24
24
|
req.set_form_data(params)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
req.add_field 'X-TB-TOKEN-AUTH', @token
|
29
|
-
elsif @partner_id && @partner_secret
|
30
|
-
req.add_field 'X-TB-PARTNER-AUTH', "#{@partner_id}:#{@partner_secret}"
|
31
|
-
end
|
27
|
+
req = set_headers(req)
|
32
28
|
|
33
29
|
http = Net::HTTP.new(url.host, url.port)
|
34
30
|
http.use_ssl = @api_host.start_with?("https")
|
35
|
-
http.verify_mode = OpenSSL::SSL::
|
31
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
36
32
|
|
37
|
-
|
38
|
-
return res
|
33
|
+
http.start {|h| h.request(req) }
|
39
34
|
end
|
40
35
|
|
41
36
|
def fetch(path, params={})
|
42
|
-
res = sendRequest
|
37
|
+
res = sendRequest path, params
|
43
38
|
|
44
39
|
case res
|
45
40
|
when Net::HTTPSuccess, Net::HTTPRedirection
|
@@ -49,9 +44,20 @@ module OpenTok
|
|
49
44
|
end
|
50
45
|
|
51
46
|
rescue Net::HTTPExceptions => e
|
52
|
-
raise OpenTokException.new "Unable to create fufill request: #{e}"
|
47
|
+
raise OpenTokException.new e.response.code, "Unable to create fufill request: #{e}"
|
53
48
|
rescue NoMethodError => e
|
54
|
-
raise OpenTokException.new "Unable to create a fufill request at this time: #{e}"
|
49
|
+
raise OpenTokException.new e.response.code, "Unable to create a fufill request at this time: #{e}"
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def set_headers(req)
|
55
|
+
if @token
|
56
|
+
req.add_field 'X-TB-TOKEN-AUTH', @token
|
57
|
+
elsif @partner_id && @partner_secret
|
58
|
+
req.add_field 'X-TB-PARTNER-AUTH', "#{@partner_id}:#{@partner_secret}"
|
59
|
+
end
|
60
|
+
req
|
55
61
|
end
|
56
62
|
end
|
57
63
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module OpenTok
|
2
|
+
|
3
|
+
# * +SUBSCRIBER+ Can only subscribe
|
4
|
+
# * +PUBLISHER+ Can publish, subscribe, and signal
|
5
|
+
# * +MODERATOR+ Can do the above along with forceDisconnect and forceUnpublish
|
6
|
+
module RoleConstants
|
7
|
+
SUBSCRIBER = "subscriber" # Can only subscribe
|
8
|
+
PUBLISHER = "publisher" # Can publish, subscribe, and signal
|
9
|
+
MODERATOR = "moderator" # Can do the above along with forceDisconnect and forceUnpublish
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def is_valid?(role)
|
13
|
+
role == SUBSCRIBER || role == PUBLISHER || role == MODERATOR
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/open_tok/session.rb
CHANGED
@@ -6,17 +6,20 @@
|
|
6
6
|
=end
|
7
7
|
|
8
8
|
module OpenTok
|
9
|
-
|
9
|
+
|
10
|
+
##
|
10
11
|
# The session object that contains the session_id
|
11
12
|
class Session
|
12
13
|
attr_reader :session_id
|
14
|
+
attr_reader :created_at
|
13
15
|
|
14
|
-
def initialize(session_id)
|
15
|
-
@session_id
|
16
|
+
def initialize(session_id, create_dt=nil)
|
17
|
+
@session_id = session_id
|
18
|
+
@created_at = create_dt
|
16
19
|
end
|
17
20
|
|
18
21
|
def to_s
|
19
|
-
session_id
|
22
|
+
@session_id
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
module OpenTok
|
3
|
+
|
4
|
+
##
|
5
|
+
# Preferences that could be defined while creating a session
|
6
|
+
module SessionPropertyConstants
|
7
|
+
|
8
|
+
# @deprecated (feature deleted in OpenTok v0.91.48)
|
9
|
+
# @param [Boolean]
|
10
|
+
ECHOSUPPRESSION_ENABLED = 'echoSuppression.enabled'
|
11
|
+
|
12
|
+
# @deprecated (feature deleted in OpenTok v0.91.48)
|
13
|
+
# @param [Integer]
|
14
|
+
MULTIPLEXER_NUMOUTPUTSTREAMS = 'multiplexer.numOutputStreams'
|
15
|
+
|
16
|
+
# @deprecated (feature deleted in OpenTok v0.91.48)
|
17
|
+
# @param [Integer]
|
18
|
+
MULTIPLEXER_SWITCHTYPE = 'multiplexer.switchType'
|
19
|
+
|
20
|
+
# @deprecated (feature deleted in OpenTok v0.91.48)
|
21
|
+
# @param [Integer]
|
22
|
+
MULTIPLEXER_SWITCHTIMEOUT = 'multiplexer.switchTimeout'
|
23
|
+
|
24
|
+
# Whether the session's streams will be transmitted directly between peers
|
25
|
+
# @param [disabled, enabled]
|
26
|
+
P2P_PREFERENCE = 'p2p.preference'
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/open_tok/utils.rb
CHANGED
@@ -1,19 +1,10 @@
|
|
1
|
-
require '
|
1
|
+
require 'addressable/uri'
|
2
2
|
|
3
3
|
module OpenTok
|
4
4
|
module Utils
|
5
|
-
# would recommend using `addressable` gem instead
|
6
5
|
def self.urlencode_hash(hash)
|
7
|
-
|
8
|
-
|
9
|
-
name_value[0] = CGI.escape name_value[0].to_s
|
10
|
-
name_value[1].map { |e| CGI.escape e.to_s }
|
11
|
-
name_value[1] = name_value[1].join "&" + name_value[0] + "="
|
12
|
-
name_value.join '='
|
13
|
-
else
|
14
|
-
name_value.map { |e| CGI.escape e.to_s }.join '='
|
15
|
-
end
|
16
|
-
end.join '&'
|
6
|
+
uri = Addressable::URI.new :query_values => hash
|
7
|
+
uri.query
|
17
8
|
end
|
18
9
|
end
|
19
10
|
end
|
data/lib/open_tok/version.rb
CHANGED
data/lib/opentok.rb
CHANGED
@@ -7,18 +7,12 @@
|
|
7
7
|
Last modified: 2012-08-28
|
8
8
|
=end
|
9
9
|
|
10
|
+
require 'rubygems'
|
11
|
+
|
10
12
|
module OpenTok
|
11
|
-
require 'rubygems'
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
API_URL = 'http://api.opentok.com/hl'
|
15
|
+
|
16
|
+
autoload :OpenTokSDK, 'open_tok/open_tok_sdk'
|
15
17
|
|
16
|
-
require 'open_tok/exception'
|
17
|
-
require 'open_tok/utils'
|
18
|
-
require 'open_tok/request'
|
19
|
-
require 'open_tok/open_tok_sdk'
|
20
|
-
require 'open_tok/session'
|
21
|
-
require 'open_tok/archive'
|
22
|
-
require 'open_tok/archive_video_resource'
|
23
|
-
require 'open_tok/archive_timeline_event'
|
24
18
|
end
|
data/opentok.gemspec
CHANGED
@@ -4,7 +4,7 @@ require "open_tok/version"
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "opentok"
|
7
|
-
s.version =
|
7
|
+
s.version = OpenTok::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Stijn Mathysen", "Karmen Blake", "Song Zheng"]
|
10
10
|
s.email = ["stijn@skylight.be", "karmenblake@gmail.com", "song@tokbox.com"]
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
+
s.add_dependency "addressable"
|
22
23
|
s.add_development_dependency "rake"
|
23
24
|
s.add_development_dependency "rspec"
|
24
25
|
s.add_development_dependency "webmock"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rexml/document'
|
3
|
+
require 'open_tok/exception'
|
4
|
+
|
5
|
+
describe OpenTok::OpenTokException do
|
6
|
+
|
7
|
+
subject { OpenTok::OpenTokException }
|
8
|
+
|
9
|
+
describe "when inhereted" do
|
10
|
+
it "should include the subclass in the internal structure" do
|
11
|
+
length = OpenTok::OpenTokException.exceptions.length
|
12
|
+
Foo = Class.new OpenTok::OpenTokException do
|
13
|
+
def self.http_code
|
14
|
+
1000
|
15
|
+
end
|
16
|
+
end
|
17
|
+
OpenTok::OpenTokException.exceptions.length.should eq length+1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "when creating an exception" do
|
22
|
+
|
23
|
+
let(:body_error) { "<Errors><error code='404'><itemNotFound message='Archive foo not found'/></error></Errors>"}
|
24
|
+
|
25
|
+
let(:body_unknown_error) { "<Errors><error code='100'></error></Errors>"}
|
26
|
+
|
27
|
+
it "should find the relevant child using the HTTP error code" do
|
28
|
+
response = REXML::Document.new body_error
|
29
|
+
OpenTok::OpenTokException.from_error(response).should be_instance_of OpenTok::OpenTokNotFound
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return the general exception if unknown HTTP error code" do
|
33
|
+
response = REXML::Document.new body_unknown_error
|
34
|
+
OpenTok::OpenTokException.from_error(response).should be_instance_of OpenTok::OpenTokException
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/spec/opentok_spec.rb
CHANGED
@@ -4,26 +4,22 @@ describe OpenTok do
|
|
4
4
|
|
5
5
|
let(:api_key) { '459782' }
|
6
6
|
let(:api_secret) { 'b44c3baa32b6476d9d88e8194d0eb1c6b777f76b' }
|
7
|
-
let(:api_url) { '
|
7
|
+
let(:api_url) { 'http://api.opentok.com/hl' }
|
8
8
|
let(:host) { 'localhost' }
|
9
9
|
|
10
|
-
|
10
|
+
subject { OpenTok::OpenTokSDK.new api_key, api_secret }
|
11
11
|
|
12
12
|
describe "test Initializers" do
|
13
13
|
it "should be backwards compatible if user set api URL with no effect" do
|
14
|
-
opentok = OpenTok::OpenTokSDK.new api_key, api_secret, {:api_url=>"bla bla"}
|
15
|
-
opentok.api_url.should eq api_url
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should set api URL with no options" do
|
19
|
-
opentok = OpenTok::OpenTokSDK.new api_key, api_secret
|
14
|
+
opentok = OpenTok::OpenTokSDK.new api_key, api_secret, {:api_url => "bla bla"}
|
20
15
|
opentok.api_url.should eq api_url
|
21
16
|
end
|
22
17
|
|
23
18
|
it "should be OpenTok SDK Object" do
|
24
|
-
|
25
|
-
opentok.should be_instance_of OpenTok::OpenTokSDK
|
19
|
+
subject.should be_instance_of OpenTok::OpenTokSDK
|
26
20
|
end
|
21
|
+
|
22
|
+
its(:api_url) { should == api_url }
|
27
23
|
end
|
28
24
|
|
29
25
|
describe "Generate Sessions" do
|
@@ -36,11 +32,6 @@ describe OpenTok do
|
|
36
32
|
session.to_s.should match(/\A[0-9A-z_-]{40,}\Z/)
|
37
33
|
end
|
38
34
|
|
39
|
-
it "should generate valid session camelCase" do
|
40
|
-
session = opentok.createSession host
|
41
|
-
session.to_s.should match(/\A[0-9A-z_-]{40,}\Z/)
|
42
|
-
end
|
43
|
-
|
44
35
|
it "should generate valid p2p session" do
|
45
36
|
# Creating Session object with p2p enabled
|
46
37
|
sessionProperties = {OpenTok::SessionPropertyConstants::P2P_PREFERENCE => "enabled"} # or disabled
|
@@ -61,21 +52,25 @@ describe OpenTok do
|
|
61
52
|
end
|
62
53
|
|
63
54
|
describe "Generate Tokens" do
|
64
|
-
let(:
|
65
|
-
|
55
|
+
let(:session) { subject.createSession host }
|
56
|
+
|
57
|
+
it "should raise error" do
|
58
|
+
expect { subject.generateToken({:role=>OpenTok::RoleConstants::MODERATOR}) }.to raise_error
|
59
|
+
end
|
66
60
|
it "should generate valid token" do
|
67
|
-
token =
|
61
|
+
token = subject.generate_token({:session_id => session, :role=>OpenTok::RoleConstants::MODERATOR})
|
68
62
|
token.should match(/(T1==)+[0-9A-z_]+/)
|
69
63
|
end
|
70
64
|
it "should generate valid token camelCase" do
|
71
|
-
token =
|
65
|
+
token = subject.generateToken({:session_id => session, :role=>OpenTok::RoleConstants::MODERATOR})
|
72
66
|
token.should match(/(T1==)+[0-9A-z_]+/)
|
73
67
|
end
|
74
68
|
it "should be able to set parameters in token" do
|
75
|
-
token =
|
69
|
+
token = subject.generate_token :session_id => session, :role=> OpenTok::RoleConstants::PUBLISHER, :connection_data => "username=Bob,level=4"
|
76
70
|
str = token[4..token.length]
|
77
71
|
decoded = Base64.decode64(str)
|
78
|
-
decoded.should match(
|
72
|
+
decoded.should match(/.*username%3DBob.*/)
|
73
|
+
decoded.should match(/.*level%3D4.*/)
|
79
74
|
end
|
80
75
|
end
|
81
76
|
|
@@ -111,14 +106,15 @@ describe OpenTok do
|
|
111
106
|
use_vcr_cassette "deleteArchive"
|
112
107
|
let(:api_key) { '459782' }
|
113
108
|
let(:api_secret) { 'b44c3baa32b6476d9d88e8194d0eb1c6b777f76b' }
|
114
|
-
let(:opentok) { OpenTok::OpenTokSDK.new api_key, api_secret, {:api_url=>""} }
|
109
|
+
let(:opentok) { OpenTok::OpenTokSDK.new api_key, api_secret, {:api_url => ""} }
|
115
110
|
let(:session) { '1_MX40NTk3ODJ-MTI3LjAuMC4xflR1ZSBTZXAgMDQgMTQ6NTM6MDIgUERUIDIwMTJ-MC41MjExODEzfg' }
|
116
111
|
let(:token) { opentok.generateToken({:session_id => session, :role=>OpenTok::RoleConstants::PUBLISHER}) }
|
117
112
|
let(:archiveId) { "200567af-0726-4e93-883b-fe0426d6310a" }
|
118
113
|
|
119
|
-
it "should
|
120
|
-
|
121
|
-
|
114
|
+
it "should raise an Exception on item not found" do
|
115
|
+
expect{
|
116
|
+
opentok.deleteArchive archiveId, token
|
117
|
+
}.to raise_error OpenTok::OpenTokException
|
122
118
|
end
|
123
119
|
end
|
124
120
|
|
@@ -126,15 +122,13 @@ describe OpenTok do
|
|
126
122
|
use_vcr_cassette "stitchArchive"
|
127
123
|
let(:api_key) { '459782' }
|
128
124
|
let(:api_secret) { 'b44c3baa32b6476d9d88e8194d0eb1c6b777f76b' }
|
129
|
-
let(:opentok) { OpenTok::OpenTokSDK.new api_key, api_secret
|
130
|
-
let(:session) { '1_MX40NTk3ODJ-MTI3LjAuMC4xflR1ZSBTZXAgMDQgMTQ6NTM6MDIgUERUIDIwMTJ-MC41MjExODEzfg' }
|
131
|
-
let(:token) { opentok.generateToken({:session_id => session, :role=>OpenTok::RoleConstants::MODERATOR}) }
|
125
|
+
let(:opentok) { OpenTok::OpenTokSDK.new api_key, api_secret }
|
132
126
|
let(:archiveId) { "200567af-0726-4e93-883b-fe0426d6310a" }
|
133
127
|
|
134
|
-
it "should return
|
135
|
-
a = opentok.stitchArchive
|
136
|
-
a[:code].should
|
137
|
-
a[:location].start_with?('http').should
|
128
|
+
it "should return stitch url" do
|
129
|
+
a = opentok.stitchArchive archiveId
|
130
|
+
a[:code].should eq 201
|
131
|
+
a[:location].start_with?('http').should be_true
|
138
132
|
end
|
139
133
|
end
|
140
134
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opentok
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,8 +11,24 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2013-07-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: addressable
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
16
32
|
- !ruby/object:Gem::Dependency
|
17
33
|
name: rake
|
18
34
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,6 +107,7 @@ extensions: []
|
|
91
107
|
extra_rdoc_files: []
|
92
108
|
files:
|
93
109
|
- .gitignore
|
110
|
+
- .rspec
|
94
111
|
- CHANGES
|
95
112
|
- Gemfile
|
96
113
|
- LICENSE
|
@@ -150,7 +167,9 @@ files:
|
|
150
167
|
- lib/open_tok/exception.rb
|
151
168
|
- lib/open_tok/open_tok_sdk.rb
|
152
169
|
- lib/open_tok/request.rb
|
170
|
+
- lib/open_tok/role_constants.rb
|
153
171
|
- lib/open_tok/session.rb
|
172
|
+
- lib/open_tok/session_property_constants.rb
|
154
173
|
- lib/open_tok/utils.rb
|
155
174
|
- lib/open_tok/version.rb
|
156
175
|
- lib/opentok.rb
|
@@ -160,6 +179,7 @@ files:
|
|
160
179
|
- spec/cassettes/invalidSession.yml
|
161
180
|
- spec/cassettes/session.yml
|
162
181
|
- spec/cassettes/stitchArchive.yml
|
182
|
+
- spec/opentok_exception_spec.rb
|
163
183
|
- spec/opentok_spec.rb
|
164
184
|
- spec/spec_helper.rb
|
165
185
|
homepage: https://github.com/opentok/Opentok-Ruby-SDK
|
@@ -182,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
202
|
version: '0'
|
183
203
|
requirements: []
|
184
204
|
rubyforge_project: opentok
|
185
|
-
rubygems_version: 1.8.
|
205
|
+
rubygems_version: 1.8.25
|
186
206
|
signing_key:
|
187
207
|
specification_version: 3
|
188
208
|
summary: OpenTok gem
|
@@ -192,5 +212,6 @@ test_files:
|
|
192
212
|
- spec/cassettes/invalidSession.yml
|
193
213
|
- spec/cassettes/session.yml
|
194
214
|
- spec/cassettes/stitchArchive.yml
|
215
|
+
- spec/opentok_exception_spec.rb
|
195
216
|
- spec/opentok_spec.rb
|
196
217
|
- spec/spec_helper.rb
|