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 ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --colour
3
+ --tty
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. Request them at <http://www.tokbox.com/opentok/tools/js/apikey>.
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-3 parameters:
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
- # Creating Sessions
34
+ ## Creating Sessions
35
35
  Use your `OpenTokSDK` object to create `session_id`
36
36
  `createSession` takes 1-2 parameters:
37
- > location (string) - give Opentok a hint on where you are running your application
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
- session_id = OTSDK.createSession( request.ip )
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
- # Generating Token
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
- # Manipulating Archive Videos
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
- # Delete Archives
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
@@ -19,35 +19,35 @@ module OpenTok
19
19
  end
20
20
 
21
21
  def do_request(path, token)
22
- OpenTok::Request.new(@api_url, token).fetch(path)
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
- return "#{@api_url}/archive/url/#{@archive_id}/#{video_id}"
28
+ "#{@api_url}/archive/url/#{@archive_id}/#{video_id}"
29
29
  else
30
- doc = do_request "/archive/url/#{@archive_id}/#{video_id}", token
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, apiUrl, token)
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("resources")[0].get_elements("video").each do |video|
42
- resources << OpenTok::ArchiveVideoResource.parseXML(video)
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("timeline")[0].get_elements("event").each do |event|
47
- timeline << OpenTok::ArchiveTimelineEvent.parseXML(event)
46
+ manifest.get_elements('timeline')[0].get_elements('event').each do |event|
47
+ timeline << ArchiveTimelineEvent.parseXML(event)
48
48
  end
49
49
 
50
- OpenTok::Archive.new(archive_id, archive_title, resources, timeline, apiUrl, token)
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(timeline_item.attributes['type'], timeline_item.attributes['id'], timeline_item.attributes['offset'])
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
- OpenTok::ArchiveVideoResource.new(video_resource_item.attributes['id'], video_resource_item.attributes['length'])
24
+ ArchiveVideoResource.new video_resource_item.attributes['id'], video_resource_item.attributes['length']
25
25
  end
26
26
  end
27
-
27
+
28
28
  end
@@ -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('sha1')
13
+ DIGEST = OpenSSL::Digest::Digest.new 'sha1'
14
14
 
15
15
  module OpenTok
16
16
 
17
- # SessionPropertyConstants
18
- #
19
- # * +ECHOSUPPRESSION_ENABLED+ boolean
20
- # * +MULTIPLEXER_NUMOUTPUTSTREAMS+ integer
21
- # * +MULTIPLEXER_SWITCHTYPE+ integer
22
- # * +MULTIPLEXER_SWITCHTIMEOUT+ integer
23
- # * +P2P_PREFERENCE+ string
24
- module SessionPropertyConstants
25
- ECHOSUPPRESSION_ENABLED = "echoSuppression.enabled" #Boolean
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
- attr_accessor :api_url
28
+ attr_reader :api_url
45
29
 
46
- @@TOKEN_SENTINEL = "T1=="
30
+ TOKEN_SENTINEL = "T1=="
47
31
 
48
- # Create a new OpenTokSDK object.
32
+ ##
33
+ # Create a new OpenTok REST API client
49
34
  #
50
- # The first two attributes are required; +parnter_id+ and +partner_secret+ are the api-key and secret
51
- # that are provided to you.
52
- def initialize(partner_id, partner_secret, backSupport="")
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 = API_URL
42
+ @api_url = api_url
56
43
  end
57
44
 
58
- # Generate token for the given session_id. The options you can provide are;
59
- # * +:session_id+ (required) generate a token for the provided session
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
- { :session_id => nil, :create_time => nil, :expire_time => nil, :role => nil, :connection_data => nil }.merge!(opts)
56
+ create_time = opts.fetch(:create_time, Time.now)
57
+ session_id = opts.fetch(:session_id, '').to_s
68
58
 
69
- create_time = opts[:create_time].nil? ? Time.now : opts[:create_time]
70
- session_id = opts[:session_id].nil? ? '' : opts[:session_id]
71
- role = opts[:role].nil? ? RoleConstants::PUBLISHER : opts[:role]
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
- if role != RoleConstants::SUBSCRIBER && role != RoleConstants::PUBLISHER && role != RoleConstants::MODERATOR
74
- raise OpenTokException.new "'#{role}' is not a recognized role"
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
- if not opts[:expire_time].nil?
85
- raise OpenTokException.new 'Expire time must be a number' if not opts[:expire_time].is_a?(Numeric)
86
- raise OpenTokException.new 'Expire time must be in the future' if opts[:expire_time] < Time.now.to_i
87
- raise OpenTokException.new 'Expire time must be in the next 30 days' if opts[:expire_time] > (Time.now.to_i + 2592000)
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
- if not opts[:connection_data].nil?
92
- raise OpenTokException.new 'Connection data must be less than 1000 characters' if opts[:connection_data].length > 1000
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 = OpenTok::Utils.urlencode_hash(data_params)
105
+ data_string = Utils.urlencode_hash(data_params)
97
106
 
98
- sig = sign_string(data_string, @partner_secret)
99
- meta_string = OpenTok::Utils.urlencode_hash(:partner_id => @partner_id, :sig => sig)
107
+ sig = sign_string data_string, @partner_secret
108
+ meta_string = Utils.urlencode_hash(:partner_id => @partner_id, :sig => sig)
100
109
 
101
- @@TOKEN_SENTINEL + Base64.encode64(meta_string + ":" + data_string).gsub("\n", '')
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
- # Generates a new OpenTok::Session and set it's session_id, situating it in TokBox's global network near the IP of the specified @location@.
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!({:partner_id => @partner_id, :location=>location})
110
- doc = do_request("/session/create", opts)
111
- if not doc.get_elements('Errors').empty?
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
- OpenTok::Session.new(doc.root.get_elements('Session')[0].get_elements('session_id')[0].children[0].to_s)
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
- # This method takes two parameters. The first parameter is the +archive_id+ of the archive that contains the video (a String). The second parameter is the +token+ (a String)
119
- # The method returns an +OpenTok::Archive+ object. The resources property of this object is an array of OpenTok::ArchiveVideoResource objects. Each OpenTok::ArchiveVideoResource object represents a video in the archive.
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 = do_request("/archive/getmanifest/#{archive_id}", {}, token)
124
- if not doc.get_elements('Errors').empty?
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( aid, token )
132
- deleteURL = "/hl/archive/delete/#{aid}"
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
- #error = errors[0].get_elements('error')[0]
137
- #errorCode = attributes['code']
138
- return true
159
+ true
139
160
  else
140
- return false
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(aid)
146
- stitchURL = "/hl/archive/#{aid}/stitch"
147
- request = OpenTok::Request.new(@api_url, nil, @partner_id, @partner_secret)
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 = OpenTok::Request.new(@api_url, token, @partner_id, @partner_secret)
172
- body = request.fetch(path, params)
173
- REXML::Document.new(body)
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
@@ -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(url.path)
20
+ if params.nil? || params.empty?
21
+ req = Net::HTTP::Get.new url.path
22
22
  else
23
- req = Net::HTTP::Post.new(url.path)
23
+ req = Net::HTTP::Post.new url.path
24
24
  req.set_form_data(params)
25
25
  end
26
26
 
27
- if @token
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::VERIFY_NONE
31
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
36
32
 
37
- res = http.start {|h| h.request(req) }
38
- return res
33
+ http.start {|h| h.request(req) }
39
34
  end
40
35
 
41
36
  def fetch(path, params={})
42
- res = sendRequest(path, params)
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
@@ -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 = 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
@@ -1,19 +1,10 @@
1
- require 'cgi'
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
- hash.to_a.map do |name_value|
8
- if name_value[1].is_a? Array
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
@@ -1,3 +1,5 @@
1
- module Opentok
2
- VERSION = "0.0.92"
1
+ module OpenTok
2
+
3
+ VERSION = '0.1.0'
4
+
3
5
  end
@@ -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
- VERSION = "tbrb-v0.91.2012-08-28"
14
- API_URL = "https://api.opentok.com"
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
@@ -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 = Opentok::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
@@ -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) { 'https://api.opentok.com' }
7
+ let(:api_url) { 'http://api.opentok.com/hl' }
8
8
  let(:host) { 'localhost' }
9
9
 
10
- let(:opentok) { OpenTok::OpenTokSDK.new api_key, api_secret }
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
- opentok = OpenTok::OpenTokSDK.new api_key, api_secret
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(:opentok) { OpenTok::OpenTokSDK.new api_key, api_secret }
65
- let(:session) { opentok.createSession host }
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 = opentok.generate_token({:session_id => session, :role=>OpenTok::RoleConstants::MODERATOR})
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 = opentok.generateToken({:session_id => session, :role=>OpenTok::RoleConstants::MODERATOR})
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 = opentok.generate_token :session_id => session, :role=> OpenTok::RoleConstants::PUBLISHER, :connection_data => "username=Bob,level=4"
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(/publisher.*username.*Bob.*level.*4/)
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 return false on wrong moderator" do
120
- a = opentok.deleteArchive( archiveId, token )
121
- a.should eq false
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, {:api_url=>""} }
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 stich url" do
135
- a = opentok.stitchArchive( archiveId )
136
- a[:code].should == 201
137
- a[:location].start_with?('http').should eq true
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
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../lib/opentok.rb'
1
+ require 'opentok'
2
2
 
3
3
  require 'vcr'
4
4
  require 'webmock'
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.92
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: 2012-10-29 00:00:00.000000000 Z
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.24
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