opentok 0.0.92 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.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
|