opentok 0.1.3 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +16 -2
  3. data/.travis.yml +6 -0
  4. data/.yardopts +1 -0
  5. data/CONTRIBUTING.md +47 -0
  6. data/DEVELOPING.md +91 -0
  7. data/LICENSE +19 -5
  8. data/README.md +170 -53
  9. data/Rakefile +10 -5
  10. data/doc/OpenTok.html +411 -0
  11. data/doc/OpenTok/Archive.html +1320 -0
  12. data/doc/OpenTok/ArchiveList.html +216 -0
  13. data/doc/OpenTok/Archives.html +1028 -0
  14. data/doc/OpenTok/Client.html +695 -0
  15. data/doc/OpenTok/OpenTok.html +1046 -0
  16. data/doc/OpenTok/OpenTokArchiveError.html +142 -0
  17. data/doc/OpenTok/OpenTokAuthenticationError.html +143 -0
  18. data/doc/OpenTok/OpenTokError.html +138 -0
  19. data/doc/OpenTok/Session.html +665 -0
  20. data/doc/OpenTok/TokenGenerator.html +204 -0
  21. data/doc/OpenTok/TokenGenerator/ClassMethods.html +187 -0
  22. data/doc/README.md +15 -0
  23. data/doc/_index.html +182 -0
  24. data/doc/class_list.html +54 -0
  25. data/doc/css/common.css +1 -0
  26. data/doc/css/full_list.css +57 -0
  27. data/doc/css/style.css +339 -0
  28. data/doc/file.README.html +87 -0
  29. data/doc/file_list.html +56 -0
  30. data/doc/frames.html +26 -0
  31. data/doc/index.html +87 -0
  32. data/doc/js/app.js +219 -0
  33. data/doc/js/full_list.js +178 -0
  34. data/doc/js/jquery.js +4 -0
  35. data/doc/method_list.html +227 -0
  36. data/doc/top-level-namespace.html +112 -0
  37. data/lib/opentok.rb +3 -14
  38. data/lib/opentok/archive.rb +92 -0
  39. data/lib/opentok/archive_list.rb +17 -0
  40. data/lib/opentok/archives.rb +120 -0
  41. data/lib/opentok/client.rb +125 -0
  42. data/lib/opentok/constants.rb +5 -0
  43. data/lib/opentok/exceptions.rb +10 -0
  44. data/lib/opentok/opentok.rb +174 -0
  45. data/lib/opentok/session.rb +76 -0
  46. data/lib/opentok/token_generator.rb +101 -0
  47. data/lib/opentok/version.rb +4 -0
  48. data/opentok.gemspec +29 -22
  49. data/sample/Archiving/Gemfile +4 -0
  50. data/sample/Archiving/README.md +212 -0
  51. data/sample/Archiving/archiving_sample.rb +80 -0
  52. data/sample/Archiving/public/css/sample.css +22 -0
  53. data/sample/Archiving/public/img/archiving-off.png +0 -0
  54. data/sample/Archiving/public/img/archiving-on-idle.png +0 -0
  55. data/sample/Archiving/public/img/archiving-on-message.png +0 -0
  56. data/sample/Archiving/public/js/host.js +37 -0
  57. data/sample/Archiving/public/js/participant.js +13 -0
  58. data/sample/Archiving/views/history.erb +65 -0
  59. data/sample/Archiving/views/host.erb +69 -0
  60. data/sample/Archiving/views/index.erb +48 -0
  61. data/sample/Archiving/views/layout.erb +29 -0
  62. data/sample/Archiving/views/participant.erb +55 -0
  63. data/sample/HelloWorld/Gemfile +4 -0
  64. data/sample/HelloWorld/README.md +123 -0
  65. data/sample/HelloWorld/hello_world.rb +27 -0
  66. data/sample/HelloWorld/public/js/helloworld.js +32 -0
  67. data/sample/HelloWorld/views/index.erb +21 -0
  68. data/spec/cassettes/OpenTok_Archives/should_create_archives.yml +48 -0
  69. data/spec/cassettes/OpenTok_Archives/should_create_named_archives.yml +49 -0
  70. data/spec/cassettes/OpenTok_Archives/should_delete_an_archive_by_id.yml +32 -0
  71. data/spec/cassettes/OpenTok_Archives/should_find_archives_by_id.yml +46 -0
  72. data/spec/cassettes/OpenTok_Archives/should_stop_archives.yml +48 -0
  73. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_all_archives.yml +104 -0
  74. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_archives_with_an_offset.yml +71 -0
  75. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_count_number_of_archives.yml +60 -0
  76. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_part_of_the_archives_when_using_offset_and_count.yml +82 -0
  77. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_default_sessions.yml +39 -0
  78. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions.yml +39 -0
  79. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions_with_a_location_hint.yml +39 -0
  80. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions.yml +39 -0
  81. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions_for_invalid_media_modes.yml +39 -0
  82. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions_with_a_location_hint.yml +39 -0
  83. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_sessions_with_a_location_hint.yml +39 -0
  84. data/spec/matchers/token.rb +48 -0
  85. data/spec/opentok/archives_spec.rb +91 -0
  86. data/spec/opentok/opentok_spec.rb +144 -0
  87. data/spec/opentok/session_spec.rb +71 -0
  88. data/spec/shared/opentok_generates_tokens.rb +62 -0
  89. data/spec/shared/session_generates_tokens.rb +63 -0
  90. data/spec/spec_helper.rb +6 -7
  91. metadata +197 -59
  92. data/.rspec +0 -3
  93. data/CHANGES +0 -33
  94. data/doc/reference.md +0 -122
  95. data/lib/open_tok/archive.rb +0 -53
  96. data/lib/open_tok/archive_timeline_event.rb +0 -22
  97. data/lib/open_tok/archive_video_resource.rb +0 -28
  98. data/lib/open_tok/exception.rb +0 -50
  99. data/lib/open_tok/open_tok_sdk.rb +0 -198
  100. data/lib/open_tok/request.rb +0 -63
  101. data/lib/open_tok/role_constants.rb +0 -18
  102. data/lib/open_tok/session.rb +0 -25
  103. data/lib/open_tok/session_property_constants.rb +0 -30
  104. data/lib/open_tok/utils.rb +0 -10
  105. data/lib/open_tok/version.rb +0 -5
  106. data/sample/sample.rb +0 -26
  107. data/spec/cassettes/archives.yml +0 -83
  108. data/spec/cassettes/deleteArchive.yml +0 -91
  109. data/spec/cassettes/invalidSession.yml +0 -41
  110. data/spec/cassettes/session.yml +0 -46
  111. data/spec/cassettes/stitchArchive.yml +0 -42
  112. data/spec/opentok_exception_spec.rb +0 -38
  113. data/spec/opentok_spec.rb +0 -135
@@ -1,18 +1,7 @@
1
- =begin
2
- OpenTok Ruby Library
3
- http://www.tokbox.com/
4
-
5
- Copyright 2010 - 2012, TokBox, Inc.
6
-
7
- Last modified: 2012-08-28
8
- =end
9
-
10
- require 'rubygems'
1
+ require "opentok/version"
2
+ require "opentok/opentok"
11
3
 
4
+ # Namespace for classes and modules in the OpenTok 2.2 Ruby SDK.
12
5
  module OpenTok
13
6
 
14
- API_URL = 'http://api.opentok.com/hl'
15
-
16
- autoload :OpenTokSDK, 'open_tok/open_tok_sdk'
17
-
18
7
  end
@@ -0,0 +1,92 @@
1
+ require "active_support/inflector"
2
+
3
+ module OpenTok
4
+ # Represents an archive of an OpenTok session.
5
+ #
6
+ # @attr [int] created_at
7
+ # The time at which the archive was created, in milliseconds since the UNIX epoch.
8
+ #
9
+ # @attr [string] duration
10
+ # The duration of the archive, in milliseconds.
11
+ #
12
+ # @attr [string] id
13
+ # The archive ID.
14
+ #
15
+ # @attr [string] name
16
+ # The name of the archive. If no name was provided when the archive was created, this is set
17
+ # to null.
18
+ #
19
+ # @attr [string] partner_id
20
+ # The API key associated with the archive.
21
+ #
22
+ # @attr [string] reason
23
+ # For archives with the status "stopped", this can be set to "90 mins exceeded", "failure",
24
+ # "session ended", or "user initiated". For archives with the status "failed", this can be set
25
+ # to "system failure".
26
+ #
27
+ # @attr [string] session_id
28
+ # The session ID of the OpenTok session associated with this archive.
29
+ #
30
+ # @attr [float] size
31
+ # The size of the MP4 file. For archives that have not been generated, this value is set to 0.
32
+ #
33
+ # @attr [string] status
34
+ # The status of the archive, which can be one of the following:
35
+ #
36
+ # * "available" -- The archive is available for download from the OpenTok cloud.
37
+ # * "failed" -- The archive recording failed.
38
+ # * "started" -- The archive started and is in the process of being recorded.
39
+ # * "stopped" -- The archive stopped recording.
40
+ # * "uploaded" -- The archive is available for download from the the upload target
41
+ # S3 bucket.
42
+ #
43
+ # @attr [string] url
44
+ # The download URL of the available MP4 file. This is only set for an archive with the status set to
45
+ # "available"; for other archives, (including archives with the status "uploaded") this property is
46
+ # set to null. The download URL is obfuscated, and the file is only available from the URL for
47
+ # 10 minutes. To generate a new URL, call the Archive.listArchives() or OpenTok.getArchive() method.
48
+ class Archive
49
+
50
+ # @private
51
+ def initialize(interface, json)
52
+ @interface = interface
53
+ # TODO: validate json fits schema
54
+ @json = json
55
+ end
56
+
57
+ # A JSON encoded string representation of the archive
58
+ def to_json
59
+ @json.to_json
60
+ end
61
+
62
+ # Stops an OpenTok archive that is being recorded.
63
+ #
64
+ # Archives automatically stop recording after 90 minutes or when all clients have disconnected
65
+ # from the session being archived.
66
+ def stop
67
+ # TODO: validate returned json fits schema
68
+ @json = @interface.stop_by_id @json['id']
69
+ end
70
+
71
+ # Deletes an OpenTok archive.
72
+ #
73
+ # You can only delete an archive which has a status of "available" or "uploaded". Deleting an
74
+ # archive removes its record from the list of archives. For an "available" archive, it also
75
+ # removes the archive file, making it unavailable for download.
76
+ def delete
77
+ # TODO: validate returned json fits schema
78
+ @json = @interface.delete_by_id @json['id']
79
+ end
80
+
81
+ # @private ignore
82
+ def method_missing(method, *args, &block)
83
+ camelized_method = method.to_s.camelize(:lower)
84
+ if @json.has_key? camelized_method and args.empty?
85
+ # TODO: convert create_time method call to a Time object
86
+ @json[camelized_method]
87
+ else
88
+ super method, *args, &block
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,17 @@
1
+ require "opentok/archive"
2
+
3
+ module OpenTok
4
+ # A class for accessing an array of Archive objects.
5
+ class ArchiveList < Array
6
+
7
+ # The total number archives.
8
+ attr_reader :total
9
+
10
+ # @private
11
+ def initialize(interface, json)
12
+ @total = json['count']
13
+ super json['items'].map { |item| Archive.new interface, item }
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,120 @@
1
+ require "opentok/client"
2
+ require "opentok/archive"
3
+ require "opentok/archive_list"
4
+
5
+ module OpenTok
6
+ # A class for working with OpenTok 2.0 archives.
7
+ class Archives
8
+
9
+ # @private
10
+ def initialize(client)
11
+ @client = client
12
+ end
13
+
14
+ # Starts archiving an OpenTok 2.0 session.
15
+ #
16
+ # Clients must be actively connected to the OpenTok session for you to successfully start
17
+ # recording an archive.
18
+ #
19
+ # You can only record one archive at a time for a given session. You can only record archives
20
+ # of OpenTok server-enabled sessions; you cannot archive peer-to-peer sessions.
21
+ #
22
+ # @param [String] session_id The session ID of the OpenTok session to archive.
23
+ # @param [Hash] options A hash with the key 'name' or :name.
24
+ # @option options [String] :name This is the name of the archive. You can use this name
25
+ # to identify the archive. It is a property of the Archive object, and it is a property
26
+ # of archive-related events in the OpenTok.js library.
27
+ #
28
+ # @return [Archive] The Archive object, which includes properties defining the archive,
29
+ # including the archive ID.
30
+ #
31
+ # @raise [OpenTokArchiveError] The archive could not be started. The request was invalid or
32
+ # the session has no connected clients.
33
+ # @raise [OpenTokAuthenticationError] Authentication failed while starting an archive.
34
+ # Invalid API key.
35
+ # @raise [OpenTokArchiveError] The archive could not be started. The session ID does not exist.
36
+ # @raise [OpenTokArchiveError] The archive could not be started. The session could be
37
+ # peer-to-peer or the session is already being recorded.
38
+ # @raise [OpenTokArchiveError] The archive could not be started.
39
+ def create(session_id, options = {})
40
+ raise ArgumentError, "session_id not provided" if session_id.to_s.empty?
41
+ opts = Hash.new
42
+ opts[:name] = options[:name].to_s || options["name"].to_s
43
+ archive_json = @client.start_archive(session_id, opts)
44
+ Archive.new self, archive_json
45
+ end
46
+
47
+ # Gets an Archive object for the given archive ID.
48
+ #
49
+ # @param [String] archive_id The archive ID.
50
+ #
51
+ # @return [Archive] The Archive object.
52
+ # @raise [OpenTokArchiveError] The archive could not be retrieved. The archive ID is invalid.
53
+ # @raise [OpenTokAuthenticationError] Authentication failed while retrieving the archive.
54
+ # Invalid API key.
55
+ # @raise [OpenTokArchiveError] The archive could not be retrieved.
56
+ def find(archive_id)
57
+ raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty?
58
+ archive_json = @client.get_archive(archive_id.to_s)
59
+ Archive.new self, archive_json
60
+ end
61
+
62
+ # Returns an ArchiveList, which is an array of archives that are completed and in-progress,
63
+ # for your API key.
64
+ #
65
+ # @param [Hash] options A hash with keys defining which range of archives to retrieve.
66
+ # @option options [integer] :offset Optional. The index offset of the first archive. 0 is offset
67
+ # of the most recently started archive. 1 is the offset of the archive that started prior to
68
+ # the most recent archive. If you do not specify an offset, 0 is used.
69
+ # @option options [integer] :count Optional. The number of archives to be returned. The maximum
70
+ # number of archives returned is 1000.
71
+ #
72
+ # @return [ArchiveList] An ArchiveList object, which is an array of Archive objects.
73
+ def all(options = {})
74
+ raise ArgumentError, "Limit is invalid" unless options[:count].nil? or (0..100).include? options[:count]
75
+ archive_list_json = @client.list_archives(options[:offset], options[:count])
76
+ ArchiveList.new self, archive_list_json
77
+ end
78
+
79
+ # Stops an OpenTok archive that is being recorded.
80
+ #
81
+ # Archives automatically stop recording after 90 minutes or when all clients have disconnected
82
+ # from the session being archived.
83
+ #
84
+ # @param [String] archive_id The archive ID of the archive you want to stop recording.
85
+ #
86
+ # @return [Archive] The Archive object corresponding to the archive being stopped.
87
+ #
88
+ # @raise [OpenTokArchiveError] The archive could not be stopped. The request was invalid.
89
+ # @raise [OpenTokAuthenticationError] Authentication failed while stopping an archive.
90
+ # @raise [OpenTokArchiveError] The archive could not be stopped. The archive ID does not exist.
91
+ # @raise [OpenTokArchiveError] The archive could not be stopped. The archive is not currently
92
+ # recording.
93
+ # @raise [OpenTokArchiveError] The archive could not be started.
94
+ def stop_by_id(archive_id)
95
+ raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty?
96
+ archive_json = @client.stop_archive(archive_id)
97
+ Archive.new self, archive_json
98
+ end
99
+
100
+ # Deletes an OpenTok archive.
101
+ #
102
+ # You can only delete an archive which has a status of "available", "uploaded", or "deleted".
103
+ # Deleting an archive removes its record from the list of archives. For an "available" archive,
104
+ # it also removes the archive file, making it unavailable for download. For a "deleted"
105
+ # archive, the archive remains deleted.
106
+ #
107
+ # @param [String] archive_id The archive ID of the archive you want to delete.
108
+ #
109
+ # @raise [OpenTokAuthenticationError] Authentication failed or an invalid archive ID was given.
110
+ # @raise [OpenTokArchiveError] The archive could not be deleted. The status must be
111
+ # 'available', 'deleted', or 'uploaded'.
112
+ # @raise [OpenTokArchiveError] The archive could not be deleted.
113
+ def delete_by_id(archive_id)
114
+ raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty?
115
+ response = @client.delete_archive(archive_id)
116
+ (200..300).include? response.code
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,125 @@
1
+ require "opentok/exceptions"
2
+
3
+ require "httparty"
4
+
5
+ module OpenTok
6
+ # @private For internal use by the SDK.
7
+ class Client
8
+ include HTTParty
9
+ # TODO: expose a setting for http debugging for developers
10
+ # debug_output $stdout
11
+
12
+ def initialize(api_key, api_secret, api_url)
13
+ self.class.base_uri api_url
14
+ self.class.headers({
15
+ "X-TB-PARTNER-AUTH" => "#{api_key}:#{api_secret}",
16
+ "User-Agent" => "OpenTok-Ruby-SDK/#{VERSION}"
17
+ })
18
+ @api_key = api_key
19
+ end
20
+
21
+ def create_session(opts)
22
+ response = self.class.post("/session/create", :body => opts)
23
+ case response.code
24
+ when (200..300)
25
+ response
26
+ when 403
27
+ raise OpenTokAuthenticationError, "Authentication failed while creating a session. API Key: #{@api_key}"
28
+ else
29
+ raise OpenTokError, "Failed to create session. Response code: #{response.code}"
30
+ end
31
+ end
32
+
33
+ def start_archive(session_id, opts)
34
+ body = { "sessionId" => session_id, "action" => "start" }
35
+ body["name"] = opts[:name] unless opts[:name].nil?
36
+ response = self.class.post("/v2/partner/#{@api_key}/archive", {
37
+ :body => body.to_json,
38
+ :headers => { "Content-Type" => "application/json" }
39
+ })
40
+ case response.code
41
+ when 200
42
+ response
43
+ when 400
44
+ raise OpenTokArchiveError, "The archive could not be started. The request was invalid or the session has no connected clients."
45
+ when 403
46
+ raise OpenTokAuthenticationError, "Authentication failed while starting an archive. API Key: #{@api_key}"
47
+ when 404
48
+ raise OpenTokArchiveError, "The archive could not be started. The Session ID does not exist: #{session_id}"
49
+ when 409
50
+ raise OpenTokArchiveError, "The archive could not be started. The session could be peer-to-peer or the session is already being recorded."
51
+ else
52
+ raise OpenTokArchiveError, "The archive could not be started"
53
+ end
54
+ end
55
+
56
+ def get_archive(archive_id)
57
+ response = self.class.get("/v2/partner/#{@api_key}/archive/#{archive_id}")
58
+ case response.code
59
+ when 200
60
+ response
61
+ when 400
62
+ raise OpenTokArchiveError, "The archive could not be retrieved. The Archive ID was invalid: #{archive_id}"
63
+ when 403
64
+ raise OpenTokAuthenticationError, "Authentication failed while retrieving an archive. API Key: #{@api_key}"
65
+ else
66
+ raise OpenTokArchiveError, "The archive could not be retrieved."
67
+ end
68
+ end
69
+
70
+ def list_archives(offset, count)
71
+ query = Hash.new
72
+ query[:offset] = offset unless offset.nil?
73
+ query[:count] = count unless count.nil?
74
+ response = self.class.get("/v2/partner/#{@api_key}/archive", {
75
+ :query => query.empty? ? nil : query
76
+ })
77
+ case response.code
78
+ when 200
79
+ response
80
+ when 403
81
+ raise OpenTokAuthenticationError, "Authentication failed while retrieving archives. API Key: #{@api_key}"
82
+ else
83
+ raise OpenTokArchiveError, "The archives could not be retrieved."
84
+ end
85
+ end
86
+
87
+ def stop_archive(archive_id)
88
+ response = self.class.post("/v2/partner/#{@api_key}/archive/#{archive_id}", {
89
+ :body => { "action" => "stop" }.to_json,
90
+ :headers => { "Content-Type" => "application/json" }
91
+ })
92
+ case response.code
93
+ when 200
94
+ response
95
+ when 400
96
+ raise OpenTokArchiveError, "The archive could not be stopped. The request was invalid."
97
+ when 403
98
+ raise OpenTokAuthenticationError, "Authentication failed while stopping an archive. API Key: #{@api_key}"
99
+ when 404
100
+ raise OpenTokArchiveError, "The archive could not be stopped. The Archive ID does not exist: #{archive_id}"
101
+ when 409
102
+ raise OpenTokArchiveError, "The archive could not be stopped. The archive is not currently recording."
103
+ else
104
+ raise OpenTokArchiveError, "The archive could not be started."
105
+ end
106
+ end
107
+
108
+ def delete_archive(archive_id)
109
+ response = self.class.delete("/v2/partner/#{@api_key}/archive/#{archive_id}", {
110
+ :headers => { "Content-Type" => "application/json" }
111
+ })
112
+ case response.code
113
+ when 204
114
+ response
115
+ when 403
116
+ raise OpenTokAuthenticationError, "Authentication failed or an invalid Archive ID was given while deleting an archive. API Key: #{@api_key}, Archive ID: #{archive_id}"
117
+ when 409
118
+ raise OpenTokArchiveError, "The archive could not be deleted. The status must be 'available', 'deleted', or 'uploaded'. Archive ID: #{archive_id}"
119
+ else
120
+ raise OpenTokArchiveError, "The archive could not be deleted."
121
+ end
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,5 @@
1
+ module OpenTok
2
+ API_URL = "https://api.opentok.com"
3
+ TOKEN_SENTINEL = "T1=="
4
+ ROLES = { subscriber: "subscriber", publisher: "publisher", moderator: "moderator" }
5
+ end
@@ -0,0 +1,10 @@
1
+ module OpenTok
2
+
3
+ # Defines errors raised by methods of the OpenTok Ruby SDK.
4
+ class OpenTokError < StandardError; end
5
+ # Defines errors raised by archive-related methods of the OpenTok Ruby SDK.
6
+ class OpenTokArchiveError < OpenTokError; end
7
+ # Defines errors raised when you attempt an operation using an invalid OpenTok API key or secret.
8
+ class OpenTokAuthenticationError < OpenTokError; end
9
+
10
+ end
@@ -0,0 +1,174 @@
1
+ require "opentok/constants"
2
+ require "opentok/session"
3
+ require "opentok/client"
4
+ require "opentok/token_generator"
5
+ require "opentok/archives"
6
+
7
+ require "resolv"
8
+
9
+ module OpenTok
10
+ # Contains methods for creating OpenTok sessions, generating tokens, and working with archives.
11
+ #
12
+ # To create a new OpenTok object, call the OpenTok constructor with your OpenTok API key
13
+ # and the API secret from the OpenTok dashboard (https://dashboard.tokbox.com). Do not
14
+ # publicly share your API secret. You will use it with the OpenTok constructor (only on your web
15
+ # server) to create OpenTok sessions.
16
+ #
17
+ # @attr_reader [String] api_secret @private The OpenTok API secret.
18
+ # @attr_reader [String] api_key @private The OpenTok API key.
19
+ #
20
+ #
21
+ # @!method generate_token(options)
22
+ # Generates a token for a given session.
23
+ #
24
+ # @param [String] sessioin_id The session ID of the session to be accessed by the client using
25
+ # the token.
26
+ #
27
+ # @param [Hash] options A hash defining options for the token.
28
+ # @option options [String] :role The role for the token. Set this to one of the following
29
+ # values:
30
+ # * <code>:subscriber</code> -- A subscriber can only subscribe to streams.
31
+ #
32
+ # * <code>:publisher</code> -- A publisher can publish streams, subscribe to
33
+ # streams, and signal. (This is the default value if you do not specify a role.)
34
+ #
35
+ # * <code>:moderator</code> -- In addition to the privileges granted to a
36
+ # publisher, in clients using the OpenTok.js 2.2 library, a moderator can call the
37
+ # <code>forceUnpublish()</code> and <code>forceDisconnect()</code> method of the
38
+ # Session object.
39
+ # @option options [integer] :expire_time The expiration time, in seconds since the UNIX epoch.
40
+ # Pass in 0 to use the default expiration time of 24 hours after the token creation time.
41
+ # The maximum expiration time is 30 days after the creation time.
42
+ # @option options [String] :data A string containing connection metadata describing the
43
+ # end-user. For example, you can pass the user ID, name, or other data describing the
44
+ # end-user. The length of the string is limited to 1000 characters. This data cannot be
45
+ # updated once it is set.
46
+ # @return [String] The token string.
47
+ class OpenTok
48
+
49
+ include TokenGenerator
50
+ generates_tokens({
51
+ :api_key => ->(instance) { instance.api_key },
52
+ :api_secret => ->(instance) { instance.api_secret }
53
+ })
54
+
55
+ # @private
56
+ # don't want these to be mutable, may cause bugs related to inconsistency since these values are
57
+ # cached in objects that this can create
58
+ attr_reader :api_key, :api_secret, :api_url
59
+
60
+ ##
61
+ # Create a new OpenTok object.
62
+ #
63
+ # @param [String] api_key Your OpenTok API key. See the OpenTok dashboard
64
+ # (https://dashboard.tokbox.com).
65
+ # @param [String] api_secret Your OpenTok API key.
66
+ # @param [String] api_url Do not set this parameter. It is for internal use by TokBox.
67
+ def initialize(api_key, api_secret , api_url = ::OpenTok::API_URL)
68
+ @api_key = api_key.to_s()
69
+ @api_secret = api_secret
70
+ # TODO: do we really need a copy of this in the instance or should we overwrite the module
71
+ # constant so that other objects can access the same copy?
72
+ @api_url = api_url
73
+ end
74
+
75
+ # Creates a new OpenTok session and returns the session ID, which uniquely identifies
76
+ # the session.
77
+ #
78
+ # For example, when using the OpenTok JavaScript library, use the session ID when calling the
79
+ # OT.initSession()</a> method (to initialize an OpenTok session).
80
+ #
81
+ # OpenTok sessions do not expire. However, authentication tokens do expire (see the
82
+ # generateToken() method). Also note that sessions cannot explicitly be destroyed.
83
+ #
84
+ # A session ID string can be up to 255 characters long.
85
+ #
86
+ # Calling this method results in an OpenTokException in the event of an error.
87
+ # Check the error message for details.
88
+ #
89
+ # You can also create a session using the OpenTok REST API (see
90
+ # http://www.tokbox.com/opentok/api/#session_id_production) or the OpenTok dashboard
91
+ # (see https://dashboard.tokbox.com/projects).
92
+ #
93
+ # @param [Hash] opts (Optional) This hash defines options for the session.
94
+ #
95
+ # @option opts [String] :media_mode Determines whether the session will transmit streams the
96
+ # using OpenTok Media Router (<code>:routed</code>) or not (<code>:relayed</code>).
97
+ # By default, sessions use the OpenTok Media Router.
98
+ #
99
+ # With the <code>mediaMode</code> property set to <code>:routed</code>, the session
100
+ # will use the {http://tokbox.com/#multiparty OpenTok Media Router}.
101
+ # The OpenTok Media Router provides the following benefits:
102
+ #
103
+ # * The OpenTok Media Router can decrease bandwidth usage in multiparty sessions.
104
+ # (When the <code>mediaMode</code> property is set to <code>:relayed</code>,
105
+ # each client must send a separate audio-video stream to each client subscribing to
106
+ # it.)
107
+ # * The OpenTok Media Router can improve the quality of the user experience through
108
+ # {http://tokbox.com/#iqc Intelligent Quality Control}. With
109
+ # Intelligent Quality Control, if a client's connectivity degrades to a degree that
110
+ # it does not support video for a stream it's subscribing to, the video is dropped on
111
+ # that client (without affecting other clients), and the client receives audio only.
112
+ # If the client's connectivity improves, the video returns.
113
+ # * The OpenTok Media Router supports the {http://tokbox.com/platform/archiving archiving}
114
+ # feature, which lets you record, save, and retrieve OpenTok sessions.
115
+ #
116
+ # With the <code>mediaMode</code> property set to <code>:relayed</code>, the session
117
+ # will attempt to transmit streams directly between clients. If clients cannot connect due to
118
+ # firewall restrictions, the session uses the OpenTok TURN server to relay audio-video
119
+ # streams.
120
+ #
121
+ # You will be billed for streamed minutes if you use the OpenTok Media Router or if the
122
+ # session uses the OpenTok TURN server to relay streams. For information on pricing, see the
123
+ # {http://www.tokbox.com/pricing OpenTok pricing page}.
124
+ #
125
+ # @option opts [String] :location An IP address that the OpenTok servers will use to
126
+ # situate the session in its global network. If you do not set a location hint,
127
+ # the OpenTok servers will be based on the first client connecting to the session.
128
+ #
129
+ # @return [Session] The Session object. The session_id property of the object is the session ID.
130
+ def create_session(opts={})
131
+
132
+ # normalize opts so all keys are symbols and only include valid_opts
133
+ valid_opts = [ :media_mode, :location ]
134
+ opts = opts.inject({}) do |m,(k,v)|
135
+ if valid_opts.include? k.to_sym
136
+ m[k.to_sym] = v
137
+ end
138
+ m
139
+ end
140
+
141
+ # keep opts around for Session constructor, build REST params
142
+ params = opts.clone
143
+
144
+ # anything other than :relayed sets the REST param to "disabled", in which case we force
145
+ # opts to be :routed. if we were more strict we could raise an error when the value isn't
146
+ # either :relayed or :routed
147
+ if params.delete(:media_mode) == :relayed
148
+ params["p2p.preference"] = "enabled"
149
+ else
150
+ params["p2p.preference"] = "disabled"
151
+ opts[:media_mode] = :routed
152
+ end
153
+ # location is optional, but it has to be an IP address if specified at all
154
+ unless params[:location].nil?
155
+ raise "location must be an IPv4 address" unless params[:location] =~ Resolv::IPv4::Regex
156
+ end
157
+
158
+ response = client.create_session(params)
159
+ Session.new api_key, api_secret, response['sessions']['Session']['session_id'], opts
160
+ end
161
+
162
+ # An Archives object, which lets you work with OpenTok 2.0 archives.
163
+ def archives
164
+ @archives ||= Archives.new client
165
+ end
166
+
167
+ protected
168
+
169
+ def client
170
+ @client ||= Client.new api_key, api_secret, api_url
171
+ end
172
+
173
+ end
174
+ end