agora-ruby 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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +56 -0
- data/LICENSE.txt +21 -0
- data/README.md +187 -0
- data/Rakefile +6 -0
- data/agora-ruby.gemspec +29 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/lib/agora/cloud_recording/client.rb +139 -0
- data/lib/agora/config.rb +12 -0
- data/lib/agora/dynamic_key/access_token.rb +55 -0
- data/lib/agora/dynamic_key/rtc_token_builder.rb +112 -0
- data/lib/agora/dynamic_key/rtm_token_builder.rb +46 -0
- data/lib/agora/dynamic_key/sign.rb +73 -0
- data/lib/agora/dynamic_key.rb +13 -0
- data/lib/agora/dynamic_key2/access_token.rb +220 -0
- data/lib/agora/dynamic_key2/apaas_token_builder.rb +73 -0
- data/lib/agora/dynamic_key2/chat_token_builder.rb +42 -0
- data/lib/agora/dynamic_key2/education_token_builder.rb +73 -0
- data/lib/agora/dynamic_key2/fpa_token_builder.rb +21 -0
- data/lib/agora/dynamic_key2/rtc_token_builder.rb +215 -0
- data/lib/agora/dynamic_key2/rtm_token_builder.rb +22 -0
- data/lib/agora/dynamic_key2/util.rb +60 -0
- data/lib/agora/dynamic_key2.rb +12 -0
- data/lib/agora/errors.rb +14 -0
- data/lib/agora/version.rb +3 -0
- data/lib/agora-ruby.rb +18 -0
- data/sample/README.md +12 -0
- data/sample/apaas_token_builder_sample.rb +29 -0
- data/sample/chat_token_builder_sample.rb +23 -0
- data/sample/education_token_builder_sample.rb +29 -0
- data/sample/fpa_token_builder_sample.rb +16 -0
- data/sample/rtc_token_builder2_sample.rb +55 -0
- data/sample/rtc_token_builder_sample.rb +40 -0
- data/sample/rtm_token_builder_sample.rb +27 -0
- data/token_compare.md +143 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4086d655e80b6377412e1830af2f16b3b7f4fc2f5cc746c9e50a1cc56cee72dc
|
4
|
+
data.tar.gz: c28cf48f91c5e343b03c3ce1eaedb92bdc8774bae19a68b82a6cde0c9aaa52ce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7a8ffc3b500fae010a7971a30a59be3aa3cbcce48bc735adbb92f8c3c1d488b0add121e10640a1995c7bf561a94caadd84b1e03c2a4be9a023e3449e1c1348ad
|
7
|
+
data.tar.gz: c36b354a9f070c5c09b8f9425260c9a28bcbc97d6db08063a29e3e779300a64eb3c3e93d1238e486da412794c152cefbf58ba00b2402371d3feb5d38724739e6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
agora-ruby (0.1.0)
|
5
|
+
httparty (~> 0.20)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.8.7)
|
11
|
+
public_suffix (>= 2.0.2, < 7.0)
|
12
|
+
bigdecimal (3.1.9)
|
13
|
+
crack (1.0.0)
|
14
|
+
bigdecimal
|
15
|
+
rexml
|
16
|
+
csv (3.3.4)
|
17
|
+
diff-lcs (1.4.4)
|
18
|
+
hashdiff (1.1.2)
|
19
|
+
httparty (0.23.1)
|
20
|
+
csv
|
21
|
+
mini_mime (>= 1.0.0)
|
22
|
+
multi_xml (>= 0.5.2)
|
23
|
+
mini_mime (1.1.5)
|
24
|
+
multi_xml (0.6.0)
|
25
|
+
public_suffix (5.1.1)
|
26
|
+
rake (13.0.6)
|
27
|
+
rexml (3.4.1)
|
28
|
+
rspec (3.10.0)
|
29
|
+
rspec-core (~> 3.10.0)
|
30
|
+
rspec-expectations (~> 3.10.0)
|
31
|
+
rspec-mocks (~> 3.10.0)
|
32
|
+
rspec-core (3.10.1)
|
33
|
+
rspec-support (~> 3.10.0)
|
34
|
+
rspec-expectations (3.10.1)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.10.0)
|
37
|
+
rspec-mocks (3.10.2)
|
38
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
39
|
+
rspec-support (~> 3.10.0)
|
40
|
+
rspec-support (3.10.2)
|
41
|
+
webmock (3.25.1)
|
42
|
+
addressable (>= 2.8.0)
|
43
|
+
crack (>= 0.3.2)
|
44
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
45
|
+
|
46
|
+
PLATFORMS
|
47
|
+
ruby
|
48
|
+
|
49
|
+
DEPENDENCIES
|
50
|
+
agora-ruby!
|
51
|
+
rake (~> 13.0)
|
52
|
+
rspec (~> 3.0)
|
53
|
+
webmock (~> 3.0)
|
54
|
+
|
55
|
+
BUNDLED WITH
|
56
|
+
2.1.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 yfscret
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
# 声网(Agora)Ruby 客户端
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/agora-ruby) <!-- 发布后可更新 -->
|
4
|
+
|
5
|
+
本 Ruby gem 提供了对接声网 Agora RESTful API 的客户端,当前聚焦于云端录制功能。它简化了录制任务的发起、停止、查询,以及录制文件上传到第三方云存储平台(如阿里云 OSS、Amazon S3 等)的流程。
|
6
|
+
|
7
|
+
## 安装
|
8
|
+
|
9
|
+
在你的 Gemfile 中添加:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'agora-ruby'
|
13
|
+
```
|
14
|
+
|
15
|
+
然后执行:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
或者直接安装:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ gem install agora-ruby
|
25
|
+
```
|
26
|
+
|
27
|
+
## 配置
|
28
|
+
|
29
|
+
在使用本 gem 前,你需要配置声网和第三方云存储的相关参数。推荐在 Rails 项目中放在 `config/initializers/agora.rb`,普通 Ruby 项目可在初始化阶段配置:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
Agora.configure do |config|
|
33
|
+
# 声网相关配置(必填)
|
34
|
+
config.app_id = '你的声网 App ID'
|
35
|
+
config.customer_key = '你的声网 RESTFUL API 客户 ID'
|
36
|
+
config.customer_secret = '你的声网 RESTFUL API 客户密钥'
|
37
|
+
|
38
|
+
# 第三方云存储平台配置(必填,vendor 需根据实际平台填写)
|
39
|
+
# 支持的 vendor 及编号如下:
|
40
|
+
# 1:Amazon S3
|
41
|
+
# 2:阿里云 OSS
|
42
|
+
# 3:腾讯云 COS
|
43
|
+
# 5:Microsoft Azure
|
44
|
+
# 6:谷歌云 GCS
|
45
|
+
# 7:华为云 OBS
|
46
|
+
# 8:百度智能云 BOS
|
47
|
+
config.oss_vendor = 2 # 2 表示阿里云 OSS
|
48
|
+
config.oss_region = 1 # 区域编号,具体见官方文档 https://doc.shengwang.cn/doc/cloud-recording/restful/api/reference
|
49
|
+
config.oss_bucket = '你的云存储 bucket 名称'
|
50
|
+
config.oss_access_key = '你的云存储 Access Key'
|
51
|
+
config.oss_secret_key = '你的云存储 Secret Key'
|
52
|
+
config.oss_filename_prefix = ["directory1","directory2"] # 录制文件在第三方云存储中的存储位置, directory1/directory2/xxx.m3u8
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
**安全提示:** 强烈建议通过环境变量或 Rails credentials 等安全方式管理密钥,不要将密钥明文写入代码。
|
57
|
+
|
58
|
+
## 使用方法
|
59
|
+
|
60
|
+
配置完成后,可通过 `Agora::CloudRecording::Client` 管理云端录制。
|
61
|
+
|
62
|
+
### 典型场景:直播连线录制
|
63
|
+
|
64
|
+
假设你在直播间(频道名:`"live-chat-123"`)与用户连线,需要录制用户的视频、用户音频和你的音频,录制文件自动上传到阿里云 OSS。
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
# 确保已完成上述配置
|
68
|
+
begin
|
69
|
+
client = Agora::CloudRecording::Client.new
|
70
|
+
cname = "live-chat-123"
|
71
|
+
my_uid = "1888" # 你的 UID
|
72
|
+
recording_bot_uid = "#{my_uid}#{rand(1000)}" # 录制机器人 UID,需唯一
|
73
|
+
record_uid = "110560" # 需要录制的用户 UID
|
74
|
+
|
75
|
+
# 1. 获取录制资源 resourceId
|
76
|
+
# acquire 的 clientRequest 可为空,除非有特殊需求
|
77
|
+
puts "获取录制资源..."
|
78
|
+
acquire_response = client.acquire(cname, recording_bot_uid)
|
79
|
+
resource_id = acquire_response["resourceId"]
|
80
|
+
puts "resourceId: #{resource_id}"
|
81
|
+
|
82
|
+
# 2. 获取 token
|
83
|
+
# 你需要为 recording_bot_uid 生成一个有效的声网 Token(可用你自己的 Token 服务)
|
84
|
+
app_id = 'xxxxxxx'
|
85
|
+
app_certificate = 'xxxxxxxx'
|
86
|
+
token_expiration_in_seconds = 3600 * 24
|
87
|
+
privilege_expiration_in_seconds = 3600 * 24
|
88
|
+
token = Agora::AgoraDynamicKey2::RtcTokenBuilder.build_token_with_uid(
|
89
|
+
app_id, app_certificate, cname, recording_bot_uid,
|
90
|
+
Agora::AgoraDynamicKey2::RtcTokenBuilder::ROLE_PUBLISHER,
|
91
|
+
token_expiration_in_seconds, privilege_expiration_in_seconds
|
92
|
+
)
|
93
|
+
|
94
|
+
# 3. 启动录制
|
95
|
+
recording_config = {
|
96
|
+
streamTypes: 2, # 录制音视频
|
97
|
+
channelType: 1, # 直播模式
|
98
|
+
audioProfile: 2, # 音频质量, 音频编码,双声道,编码码率约 192 Kbps。
|
99
|
+
# 只录制指定用户的视频,和你与用户的音频
|
100
|
+
subscribeVideoUids: [record_uid],
|
101
|
+
subscribeAudioUids: [my_uid, record_uid],
|
102
|
+
transcodingConfig: {
|
103
|
+
width: 720,
|
104
|
+
height: 1280,
|
105
|
+
bitrate: 3420,
|
106
|
+
fps: 30
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
recording_file_config = {
|
111
|
+
avFileType: ["hls", "mp4"] # 同时录制 HLS 和 MP4
|
112
|
+
}
|
113
|
+
|
114
|
+
puts "启动录制..."
|
115
|
+
start_response = client.start(
|
116
|
+
resource_id,
|
117
|
+
cname,
|
118
|
+
recording_bot_uid,
|
119
|
+
token,
|
120
|
+
'mix', # 合流录制,若需单流录制可用 'individual'
|
121
|
+
recording_config,
|
122
|
+
recording_file_config
|
123
|
+
)
|
124
|
+
sid = start_response["sid"] # 录制会话 ID
|
125
|
+
puts "录制已启动,SID: #{sid}"
|
126
|
+
|
127
|
+
# 录制中(实际业务中可根据需求控制时长)
|
128
|
+
puts "录制中..."
|
129
|
+
|
130
|
+
# 4. 可选:查询录制状态
|
131
|
+
puts "查询录制状态..."
|
132
|
+
query_response = client.query(resource_id, sid)
|
133
|
+
puts "状态查询结果: #{query_response}"
|
134
|
+
# 可根据 query_response["serverResponse"]["status"] 判断录制状态
|
135
|
+
|
136
|
+
# 5. 停止录制
|
137
|
+
puts "停止录制..."
|
138
|
+
stop_response = client.stop(resource_id, sid, cname, recording_bot_uid, 'mix', client_request = { async_stop: true })
|
139
|
+
puts "停止结果: #{stop_response}"
|
140
|
+
# 文件上传 OSS 可能有延迟,可通过 stop_response["serverResponse"]["fileList"] 获取文件列表
|
141
|
+
|
142
|
+
puts "录制流程结束,请到 OSS 查看文件: #{Agora.config.oss_bucket}/#{stop_response["serverResponse"]["fileList"][0]['fileName']}"
|
143
|
+
|
144
|
+
rescue Agora::Errors::ConfigurationError => e
|
145
|
+
puts "配置错误: #{e.message}"
|
146
|
+
rescue Agora::Errors::APIError => e
|
147
|
+
puts "API 错误: #{e.message}"
|
148
|
+
puts "响应码: #{e.response&.code}"
|
149
|
+
puts "响应体: #{e.response&.body}"
|
150
|
+
rescue StandardError => e
|
151
|
+
puts "发生未知错误: #{e.message}"
|
152
|
+
puts e.backtrace.join("\n")
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
### API 方法说明
|
157
|
+
|
158
|
+
`Agora::CloudRecording::Client` 提供如下方法:
|
159
|
+
|
160
|
+
* `acquire(cname, uid, client_request = {})`:获取录制资源 resourceId。
|
161
|
+
* `start(resource_id, cname, uid, token, mode = 'mix', recording_config = {}, recording_file_config = {}, storage_config = {})`:启动录制。
|
162
|
+
* `mode`:'mix'(合流,默认)或 'individual'(单流)。
|
163
|
+
* `recording_config`:录制参数(如 streamTypes、subscribeVideoUids、subscribeAudioUids、transcodingConfig 等,详见官方文档)。
|
164
|
+
* `recording_file_config`:输出文件类型(如 avFileType: ["hls", "mp4"])。
|
165
|
+
* `storage_config`:云存储参数(如 fileNamePrefix,可覆盖默认值)。
|
166
|
+
* `query(resource_id, sid, mode = 'mix')`:查询录制状态。
|
167
|
+
* `stop(resource_id, sid, cname, uid, mode = 'mix', client_request = {})`:停止录制。
|
168
|
+
|
169
|
+
详细参数和更多高级用法请参考 [声网云端录制 RESTful API 文档](https://doc.shengwang.cn/doc/cloud-recording/restful/cloud-recording/overview)。
|
170
|
+
|
171
|
+
## 开发与贡献
|
172
|
+
|
173
|
+
克隆本仓库后,运行 `bin/setup` 安装依赖。测试可用 `rake spec`(建议补充测试用例)。你也可以用 `bin/console` 进入交互式环境。
|
174
|
+
|
175
|
+
本地安装 gem 可用 `bundle exec rake install`。如需发布新版本,修改 `version.rb` 后执行 `bundle exec rake release`,会自动打 tag 并推送到 RubyGems(需先配置好发布信息)。
|
176
|
+
|
177
|
+
## 贡献
|
178
|
+
|
179
|
+
欢迎通过 Pull Request 或 Issue 反馈和贡献代码,详见 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)。
|
180
|
+
|
181
|
+
## 许可证
|
182
|
+
|
183
|
+
本项目基于 [MIT License](https://opensource.org/licenses/MIT) 开源。
|
184
|
+
|
185
|
+
## 行为准则
|
186
|
+
|
187
|
+
所有参与本项目的人都需遵守 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)。
|
data/Rakefile
ADDED
data/agora-ruby.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'lib/agora/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "agora-ruby"
|
5
|
+
spec.version = Agora::VERSION
|
6
|
+
spec.authors = ["yfscret"]
|
7
|
+
spec.email = ["yfscret@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{A Ruby client for Agora.io RESTful APIs, starting with Cloud Recording.}
|
10
|
+
spec.description = %q{This gem provides an easy-to-use interface for interacting with Agora.io's RESTful services, initially focusing on cloud recording functionalities, including uploading to Aliyun OSS.}
|
11
|
+
spec.homepage = "https://rubygems.org/gems/agora-ruby"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/yfscret/agora-ruby"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/yfscret/agora-ruby"
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_dependency "httparty", "~> 0.20"
|
29
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
6
|
+
# with your gem easier. You can also use a different console, if you like.
|
7
|
+
|
8
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
9
|
+
# require "pry"
|
10
|
+
# Pry.start
|
11
|
+
|
12
|
+
require "irb"
|
13
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Agora
|
5
|
+
module CloudRecording
|
6
|
+
class Client
|
7
|
+
include HTTParty
|
8
|
+
# base_uri 通过 Agora.config.base_url 设置
|
9
|
+
|
10
|
+
attr_reader :app_id, :customer_key, :customer_secret, :oss_vendor, :oss_region, :oss_bucket, :oss_access_key, :oss_secret_key, :oss_filename_prefix
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@config = Agora.config # 使用 Agora.config 获取配置实例
|
14
|
+
unless @config && @config.app_id && @config.customer_key && @config.customer_secret
|
15
|
+
raise Agora::Errors::ConfigurationError, "声网 App ID, Customer ID, 和 Customer Certificate 必须配置。"
|
16
|
+
end
|
17
|
+
unless @config.oss_bucket && @config.oss_access_key && @config.oss_secret_key && @config.oss_region && @config.oss_vendor
|
18
|
+
raise Agora::Errors::ConfigurationError, "云存储的 Bucket, Access Key, Secret Key, Region, 和 Vendor 必须配置。"
|
19
|
+
end
|
20
|
+
|
21
|
+
self.class.base_uri @config.base_url # 设置 base_uri
|
22
|
+
|
23
|
+
@app_id = @config.app_id
|
24
|
+
@customer_key = @config.customer_key
|
25
|
+
@customer_secret = @config.customer_secret
|
26
|
+
@oss_vendor = @config.oss_vendor
|
27
|
+
@oss_region = @config.oss_region
|
28
|
+
@oss_bucket = @config.oss_bucket
|
29
|
+
@oss_access_key = @config.oss_access_key
|
30
|
+
@oss_secret_key = @config.oss_secret_key
|
31
|
+
@oss_filename_prefix = @config.oss_filename_prefix
|
32
|
+
end
|
33
|
+
|
34
|
+
def acquire(cname, uid, client_request = {})
|
35
|
+
path = "/v1/apps/#{@app_id}/cloud_recording/acquire"
|
36
|
+
body = {
|
37
|
+
cname: cname,
|
38
|
+
uid: uid,
|
39
|
+
clientRequest: client_request
|
40
|
+
}.to_json
|
41
|
+
|
42
|
+
headers = {
|
43
|
+
'Authorization' => basic_auth_header,
|
44
|
+
'Content-Type' => 'application/json'
|
45
|
+
}
|
46
|
+
# 注意:HTTParty 的 post/get 方法是类方法
|
47
|
+
handle_response(self.class.post(path, body: body, headers: headers))
|
48
|
+
end
|
49
|
+
|
50
|
+
def start(resource_id, cname, uid, token, mode = 'mix', recording_config = {}, recording_file_config = {}, storage_config = {})
|
51
|
+
path = "/v1/apps/#{@app_id}/cloud_recording/resourceid/#{resource_id}/mode/#{mode}/start"
|
52
|
+
|
53
|
+
default_storage_config = {
|
54
|
+
vendor: @oss_vendor,
|
55
|
+
region: @oss_region,
|
56
|
+
bucket: @oss_bucket,
|
57
|
+
accessKey: @oss_access_key,
|
58
|
+
secretKey: @oss_secret_key,
|
59
|
+
fileNamePrefix: @oss_filename_prefix
|
60
|
+
}
|
61
|
+
|
62
|
+
body = {
|
63
|
+
cname: cname,
|
64
|
+
uid: uid,
|
65
|
+
clientRequest: {
|
66
|
+
token: token,
|
67
|
+
recordingConfig: default_recording_config.merge(recording_config),
|
68
|
+
recordingFileConfig: default_recording_file_config.merge(recording_file_config),
|
69
|
+
storageConfig: default_storage_config.merge(storage_config)
|
70
|
+
}
|
71
|
+
}.to_json
|
72
|
+
|
73
|
+
headers = {
|
74
|
+
'Authorization' => basic_auth_header,
|
75
|
+
'Content-Type' => 'application/json'
|
76
|
+
}
|
77
|
+
handle_response(self.class.post(path, body: body, headers: headers))
|
78
|
+
end
|
79
|
+
|
80
|
+
def query(resource_id, sid, mode = 'mix')
|
81
|
+
path = "/v1/apps/#{@app_id}/cloud_recording/resourceid/#{resource_id}/sid/#{sid}/mode/#{mode}/query"
|
82
|
+
headers = { 'Authorization' => basic_auth_header }
|
83
|
+
handle_response(self.class.get(path, headers: headers))
|
84
|
+
end
|
85
|
+
|
86
|
+
def stop(resource_id, sid, cname, uid, mode = 'mix', client_request = {})
|
87
|
+
path = "/v1/apps/#{@app_id}/cloud_recording/resourceid/#{resource_id}/sid/#{sid}/mode/#{mode}/stop"
|
88
|
+
body = {
|
89
|
+
cname: cname,
|
90
|
+
uid: uid,
|
91
|
+
clientRequest: client_request
|
92
|
+
}.to_json
|
93
|
+
|
94
|
+
headers = {
|
95
|
+
'Authorization' => basic_auth_header,
|
96
|
+
'Content-Type' => 'application/json'
|
97
|
+
}
|
98
|
+
handle_response(self.class.post(path, body: body, headers: headers))
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def basic_auth_header
|
104
|
+
"Basic " + Base64.strict_encode64("#{@customer_key}:#{@customer_secret}")
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_response(response)
|
108
|
+
if response.success?
|
109
|
+
response.parsed_response
|
110
|
+
else
|
111
|
+
error_message = "声网 API 错误: #{response.code}"
|
112
|
+
parsed_body = response.parsed_response
|
113
|
+
if parsed_body.is_a?(Hash)
|
114
|
+
reason = parsed_body['reason']
|
115
|
+
message = parsed_body['message']
|
116
|
+
error_message += " - 原因: #{reason}" if reason
|
117
|
+
error_message += " - 信息: #{message}" if message && message != reason # 避免重复信息
|
118
|
+
end
|
119
|
+
raise Agora::Errors::APIError.new(error_message, response)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def default_recording_config
|
124
|
+
{
|
125
|
+
maxIdleTime: 30,
|
126
|
+
streamTypes: 2,
|
127
|
+
channelType: 1,
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def default_recording_file_config
|
132
|
+
{
|
133
|
+
avFileType: ["hls", "mp4"]
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/agora/config.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Agora
|
2
|
+
class Config
|
3
|
+
attr_accessor :app_id, :customer_key, :customer_secret,
|
4
|
+
:oss_vendor, :oss_region, :oss_bucket,
|
5
|
+
:oss_access_key, :oss_secret_key,
|
6
|
+
:base_url, :oss_filename_prefix
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@base_url = 'https://api.sd-rtn.com'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Agora::AgoraDynamicKey
|
2
|
+
module Privilege
|
3
|
+
JOIN_CHANNEL = 1
|
4
|
+
PUBLISH_AUDIO_STREAM = 2
|
5
|
+
PUBLISH_VIDEO_STREAM = 3
|
6
|
+
PUBLISH_DATA_STREAM = 4
|
7
|
+
RTM_LOGIN = 1000 # for RTM Only
|
8
|
+
end
|
9
|
+
|
10
|
+
class AccessToken
|
11
|
+
VERSION = "006"
|
12
|
+
|
13
|
+
ONE_DAY = 864_00
|
14
|
+
SEED = 2 ** 32 - 1
|
15
|
+
|
16
|
+
attr_accessor :app_id, :channel_name, :app_certificate,
|
17
|
+
:uid, :privileges, :privilege_expired_ts,
|
18
|
+
:salt, :expired_ts
|
19
|
+
|
20
|
+
def initialize args={}
|
21
|
+
@app_id = args[:app_id]
|
22
|
+
@channel_name = args.fetch(:channel_name, "")
|
23
|
+
@app_certificate = args[:app_certificate]
|
24
|
+
@uid = "#{args.fetch(:uid, "")}"
|
25
|
+
@privileges = {}
|
26
|
+
@privilege_expired_ts = args[:privilege_expired_ts]
|
27
|
+
@salt = SecureRandom.rand(SEED)
|
28
|
+
@expired_ts = Time.now.to_i + ONE_DAY
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_privilege privilege, ts
|
32
|
+
privileges[privilege] = ts
|
33
|
+
end
|
34
|
+
|
35
|
+
alias grant add_privilege
|
36
|
+
|
37
|
+
def build
|
38
|
+
Sign.encode self
|
39
|
+
end
|
40
|
+
|
41
|
+
def build!
|
42
|
+
Sign.encode! self
|
43
|
+
end
|
44
|
+
|
45
|
+
def from_string token
|
46
|
+
Sign.decode token
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.generate! payload={}, &block
|
50
|
+
token = AccessToken.new payload
|
51
|
+
block.call token
|
52
|
+
token.build!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|