diff --git a/src/main/java/com/qiniu/pili/PiliDomainManager.java b/src/main/java/com/qiniu/pili/PiliDomainManager.java new file mode 100644 index 00000000..ed0e6b9c --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliDomainManager.java @@ -0,0 +1,195 @@ +package com.qiniu.pili; + +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +import com.qiniu.common.Constants; +import com.qiniu.common.QiniuException; +import com.qiniu.http.Client; +import com.qiniu.http.Response; +import com.qiniu.util.Auth; +import com.qiniu.util.Json; + +public class PiliDomainManager extends PiliManager { + public PiliDomainManager(Auth auth) { + super(auth); + } + + public PiliDomainManager(Auth auth, String server) { + super(auth, server); + } + + public PiliDomainManager(Auth auth, String server, Client client) { + super(auth, server, client); + } + + public PiliDomainManager(Auth auth, String server, Client client, String apihost, String apihttpscheme, + String appname) { + super(auth, server, client, apihost, apihttpscheme, appname); + } + + /** + * 返回目标直播空间下的所有直播域名 + * 参考文档:直播空间下的所有域名 + * GET /v2/hubs//domains + * + * @param hub 直播空间 + * @return 获取直播空间域名列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliDomainModel.DomainsListResult getDomainsList(String hub) throws QiniuException { + String url = super.server + "/v2/hubs/" + hub + "/domains"; + Response response = get(url); + return response.jsonToObject(PiliDomainModel.DomainsListResult.class); + } + + /** + * + * GetDomainInfo 查询域名信息 + * + * @param hub 直播空间 + * + * @param domain 域名 + * + * @return 获取域名信息请求的回复 + * + * @throws QiniuException + */ + public PiliDomainModel.DomainInfoResult getDomainInfo(String hub, String domain) throws QiniuException { + if (Objects.isNull(hub) || Objects.isNull(domain) || hub.isEmpty() || domain.isEmpty()) { + throw new IllegalArgumentException("hub: " + hub + ", domain: " + domain + ", cannot be null or empty!"); + } + + String url = super.server + "/v2/hubs/" + hub + "/domains/" + domain; + Response response = get(url); + return response.jsonToObject(PiliDomainModel.DomainInfoResult.class); + } + + /** + * BindDomain 绑定直播域名 + * 参考文档:参考文档:绑定直播域名 + * POST /v2/hubs//newdomains + * + * @param hub 直播空间 + * @param domain 域名 + * @param type 域名的类型 + * @return 是否绑定成功 + * @throws QiniuException 异常 + */ + public QiniuException bindDomain(String hub, String domain, String type) throws QiniuException { + if (type.equals(PiliDomainModel.PUBLISH_RTMP) || type.equals(PiliDomainModel.LIVE_HDL) + || type.equals(PiliDomainModel.LIVE_HLS) || type.equals(PiliDomainModel.PUBLISH_RTMP)) { + // 是其中一个 + HashMap req = new HashMap<>(); + req.put("hub", hub); + req.put("domain", domain); + req.put("type", type); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + String url = server + "/v2/hubs/" + hub + "/newdomains"; + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } else { + // 不是 + return new QiniuException(null, "Type Error!"); + } + } + + /** + * UnbindDomain 解绑直播域名 + * 参考文档:参考文档:解绑直播域名 + * DELETE /v2/hubs//domains/ + * + * @param hub 直播空间 + * @param domain 域名 + * @return 是否解绑成功 + * @throws QiniuException 异常 + */ + public QiniuException unbindDomain(String hub, String domain) throws QiniuException { + HashMap req = new HashMap<>(); + req.put("hub", hub); + req.put("domain", domain); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + String url = server + "/v2/hubs/" + hub + "/domains/" + domain; + Response response = delete(url); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * BindVodDomain 绑定点播域名 + * 参考文档:参考文档:绑定点播域名 + * POST /v2/hubs//voddomain + * + * @param hub 直播空间 + * @param vodDomain 点播域名 + * @return 是否绑定成功 + * @throws QiniuException 异常 + */ + public QiniuException bindVodDomain(String hub, String vodDomain) throws QiniuException { + HashMap req = new HashMap<>(); + req.put("hub", hub); + req.put("vodDomain", vodDomain); + String url = server + "/v2/hubs/" + hub + "/voddomain"; + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * SetDomainCert 修改域名证书配置 + * 参考文档:参考文档:绑定点播域名 + * POST /v2/hubs//domains//cert + * + * @param hub 直播空间 + * @param domain 域名 + * @param certName 证书名称 + * @return 是否绑定成功 + * @throws QiniuException 异常 + */ + public QiniuException setDomainCert(String hub, String domain, String certName) throws Exception { + HashMap req = new HashMap<>(); + req.put("hub", hub); + req.put("domain", domain); + req.put("certName", certName); + String url = server + "/v2/hubs/" + hub + "/domains/" + domain + "/cert"; + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * SetDomainURLRewrite 修改域名改写规则配置 + * POST /v2/hubs//domains//urlrewrite + * + * 可根据业务需求自定义推拉流URL + * 改写后的URL应符合七牛的直播URL规范: :////[.]? + * 举例 + * 匹配规则: (.+)/live/(.+)/playlist.m3u8 + * 改写规则: ${1}/hub/${2}.m3u8 + * 请求URL: https://live.qiniu.com/live/stream01/playlist.m3u8 ; 改写URL: + * https://live.qiniu.com/hub/stream01.m3u8 + * 请求URL: https://live.qiniu.com/live/stream01.m3u8 ; 与规则不匹配,不做改写 + * + * @param hub 直播空间 + * @param domain 域名 + * @param rules 规则 + * @return 是否修改成功 + * @throws QiniuException + */ + public QiniuException setDomainURLRewrite(String hub, String domain, List rules) + throws Exception { + HashMap req = new HashMap<>(); + req.put("rules", rules); + req.put("hub", hub); + req.put("domain", domain); + String url = server + "/v2/hubs/" + hub + "/domains/" + domain + "/urlrewrite"; + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } +} diff --git a/src/main/java/com/qiniu/pili/PiliDomainModel.java b/src/main/java/com/qiniu/pili/PiliDomainModel.java new file mode 100644 index 00000000..ae22ced5 --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliDomainModel.java @@ -0,0 +1,321 @@ +package com.qiniu.pili; + +import java.util.List; +import java.util.Map; + +/** + * 这里定义了Pili Domain响应相关的类 + */ +public class PiliDomainModel { + private PiliDomainModel() { + + } + + /** + * 查询域名列表返回值 + * 参考文档:域名列表 + */ + public class DomainsListResult { + /** + * Domains 域名列表 + */ + public DomainsListItem[] domains; + } + + /** + * 查询域名列表项 + * 参考文档:域名列表项 + */ + public class DomainsListItem { + /** + * Type 域名类型 + */ + String type; + /** + * Domain 域名 + */ + String domain; + /** + * CNAME CNAME + */ + String cname; + /** + * CertEnable 是否配置 SSL 证书 + */ + Boolean certEnable; + /** + * CertName 证书名称 + */ + String certName; + } + + /** + * 查询域名信息返回值 + * 参考文档:域名信息 + */ + public class DomainInfoResult { + /** + * Domain 域名 + */ + public String domain; + + /** + * Type 域名类型 + */ + public String type; + + /** + * Cname CNAME + */ + public String cname; + + /** + * ConnectCallback 开播回调配置 + */ + public DomainCallbackConfig connectCallback; + + /** + * DisconnectCallback 断播回调配置 + */ + public DomainCallbackConfig disconnectCallback; + + /** + * IPLimit IP 访问限制 + */ + public DomainIPLimit iPLimit; + + /** + * PlaySecurity 时间戳防盗链配置 + */ + public DomainPlaySecurity playSecurity; + + /** + * 断流延迟配置 + * DisconnectDelay 单位:秒,针对直播流短时间内闪断重连的情况,不触发断流回调,避免因为短时间内频繁断流造成大量回调 + */ + public long disconnectDelay; + + /** + * UrlRewrite URL 改写规则 + */ + public DomainUrlRewrite urlRewrite; + + /** + * CertEnable 是否配置 SSL 证书 + */ + public boolean certEnable; + + /** + * CertName 证书名称 + */ + public String certName; + + /** + * Disable 域名是否为禁用状态 + */ + public boolean disable; + } + + public class DomainCallbackConfig { + /** + * Type 回调类型 + * 可选回调类型为 + * 留空: 不开启回调功能 + * GET: 发送GET请求回调,请求参数携带在query中 + * FORM: 发送POST请求回调,请求参数携带在body中,Content-Type 为 + * application/x-www-form-urlencoded + * JSON: 发送POST请求回调,请求参数携带在body中,Content-Type 为 application/json + */ + public String type; + + /** + * URL 回调地址 + * 支持魔法变量 + */ + public String url; + + /** + * Timeout 超时时间 + * 与回调地址的 HTTP 连接超时时间,单位:秒 + * 默认值为 2 秒,配置范围为 0~10 秒 + */ + public long timeout; + + /** + * Vars 请求参数 + * 支持魔法变量,至少需要一组请求参数,规则解析出错误的会设置成空字段 + */ + public Map vars; + + /** + * RetryTimes 重试次数 + * 可选范围 0~5 次 + */ + public int retryTimes; + + /** + * RetryInterval 重试间隔 + * 可选范围 0~5 秒,单位:秒 + */ + public int retryInterval; + + /** + * SuccessCode 回调成功的 http code + * 为 0 表示通配 + */ + public int successCode; + + /** + * FailCode 回调失败的 http code + * 为 0 表示通配,当 SuccessCode 不为 0 的情况下生效 + */ + public int failCode; + } + + public class DomainIPLimit { + /** + * WhiteList 白名单 + * 允许推拉流的 IP 列表,CIDR 类型 + * 配置白名单后,黑名单列表将失效 + */ + public List whitelist; + + /** + * BlackList 黑名单 + * 限制推拉流的 IP 列表,CIDR 类型 + */ + public List blacklist; + } + + public class DomainPlaySecurity { + /** + * Type 防盗链类型 + * 可选防盗链类型为 + * - 留空: 默认类型,表示继承直播空间级别配置 + * - none: 表示关闭鉴权 + * - tsStartMD5: 有效时间从 TsPart 表示的时间戳开始,到 Range 秒后截止 + * - tsExpireMD5: 有效时间从现在当前到 TsPart 表示的时间戳为止 + */ + public String type; + + /** + * Key1 主密钥 + */ + public String key1; + + /** + * Key2 副密钥 + * 两个密钥将同时生效,便于线上业务替换密钥 + */ + public String key2; + + /** + * Range 有效时间 + * 当 Type 为 "tsStartMD5" 时生效,单位:秒 + */ + public int range; + + /** + * Rule 签名规则 + * 支持魔法变量的规则,最终签算结果为所有变量的md5 + * - $(key): 密钥 + * - $(path): URL 中的 path 部分 + * - $(streamKey): URL 中的 hub/stream 部分 + * - $(streamTitle): URL 中的 stream 部分 + * - $(path_): URL 中的 path 部分, 表示 path 层级 + * - $(_): URL 中的 query 字段,举例: key1=val,魔法变量中使用 $(_key1) 表示 val + * 举例: + * 配置Rule为: $(key)$(path)$(_t) + * 魔法变量替换完成后: key/hub/streamTitle1634745600 + * 对结果进行md5计算,最终签算值为:3bc26fe6b35f5c7efab87778c5b27993 + */ + public String rule; + + /** + * Rule2 签名规则 2 + * 两个签名规则将同时生效,便于线上业务更换签名规则 + */ + public String rule2; + + /** + * TsPart 时间戳字段 + * URL中表示时间戳的字段名 + */ + public String tsPart; + + /** + * TsBase 时间戳进制 + * 可选进制格式为 2-36,即 2 进制到 36 进制,默认使用16进制 + */ + public int tsBase; + + /** + * SignPart 签名字段 + * URL中表示token的字段名 + */ + public String signPart; + + /** + * GapDuration 时间误差值 + * 针对 tsExpireMD5 生效,避免因签算方与服务器本地时间误差造成的鉴权失败 + */ + public int gapDuration; + } + + /** + * DomainUrlRewrite URL 改写规则配置 + */ + public class DomainUrlRewrite { + /** + * rewriteRules 需要转换处理的 URL 规则配置 + */ + public List rewriteRules; + } + + /** + * DomainUrlRewriteItem URL 改写规则项 + */ + public static class DomainUrlRewriteItem { + /** + * Pattern 匹配规则 + */ + public String pattern; + + /** + * Replace 改写规则 + */ + public String replace; + } + + public static final String PUBLISH_RTMP = "publishRtmp"; + public static final String LIVE_RTMP = "liveRtmp"; + public static final String LIVE_HLS = "liveHls"; + public static final String LIVE_HDL = "liveHdl"; + + /** + * DomainURLRewriteRule URL 改写规则 + */ + public static class Rules { + /** + * Pattern 匹配规则 + * 针对完整URL的正则表达式,形式如:(.+)/live/(.+)/playlist.m3u8 + * 括号中的内容允许在 Replace 中使用${n}引用(n表示括号顺序) + */ + public String pattern; + + /** + * Replace 改写规则 + * 希望得到的改写结果,形式如:${1}/hub/${2}.m3u8 + * 改写后的URL应符合七牛的直播URL规范: :////[]? + */ + public String replace; + + public Rules(String pattern, String replace) { + this.pattern = pattern; + this.replace = replace; + } + } +} diff --git a/src/main/java/com/qiniu/pili/PiliHubManager.java b/src/main/java/com/qiniu/pili/PiliHubManager.java new file mode 100644 index 00000000..7a547f7f --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliHubManager.java @@ -0,0 +1,137 @@ +package com.qiniu.pili; + +import com.qiniu.common.Constants; +import com.qiniu.common.QiniuException; +import com.qiniu.http.Client; +import com.qiniu.http.Response; +import com.qiniu.util.Auth; +import com.qiniu.util.Json; +import com.qiniu.util.StringMap; + +public class PiliHubManager extends PiliManager { + public PiliHubManager(Auth auth) { + super(auth); + } + + public PiliHubManager(Auth auth, String server) { + super(auth, server); + } + + public PiliHubManager(Auth auth, String server, Client client) { + super(auth, server, client); + } + + public PiliHubManager(Auth auth, String server, Client client, String apihost, String apihttpscheme, String appname) { + super(auth, server, client, apihost, apihttpscheme, appname); + } + + /** + * getHubList 查询直播空间列表 + * 参考文档:直播空间列表 + * GET /v2/hubs + * + * @return 获取直播空间列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliHubModel.HubListResult getHubList() throws QiniuException { + String url = server + "/v2/hubs"; + Response response = get(url); + return response.jsonToObject(PiliHubModel.HubListResult.class); + } + + /** + * getHubInfo 查询直播空间信息 + * 参考文档:查询直播空间信息 + * GET /v2/hubs/ + * + * @param hub 请求直播空间 + * @return 获取直播空间列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliHubModel.HubInfoResult getHubInfo(String hub) throws Exception { + String url = super.server + "/v2/hubs/" + hub; + Response response = get(url); + return response.jsonToObject(PiliHubModel.HubInfoResult.class); + } + + /** + * hubSecurity 修改直播空间推流鉴权配置 + * 参考文档:修改直播空间推流鉴权配置 + * POST /v2/hubs//security + * + * @param hub 请求直播空间名 + * @param publishSecurity 鉴权方式,可选推流鉴权类型为: expiry: 限时鉴权、expiry_sk: 限时鉴权SK + * @param publishKey 密钥 + * @return 修改直播空间推流鉴权配置 是否错误 + * @throws QiniuException 异常 + */ + public QiniuException hubSecurity(String hub, String publishSecurity, String publishKey) throws QiniuException { + StringMap req = new StringMap(); + req.put("hub", hub); + req.put("publishSecurity", publishSecurity); + req.put("publishKey", publishKey); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + + String url = this.server + "/v2/hubs/" + hub + "/security"; + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * hubHlsplus 修改直播空间 hls 低延迟配置 + * 参考文档:修改直播空间 + * hls 低延迟配置 + * POST /v2/hubs//hlsplus + * + * @param hub 请求直播空间名 + * @param HlsPlus 是否开启 hls 低延迟 + * @return 修改直播空间 hls 低延迟配置 是否错误 + * @throws QiniuException 异常 + */ + public QiniuException hubHlsplus(PiliHubModel.HubHlsplusRequest param) throws QiniuException { + byte[] body = Json.encode(param).getBytes(Constants.UTF_8); + String url = this.server + "/v2/hubs/" + param.hub + "/security"; + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * hubPersistence 修改直播空间存储配置 + * 参考文档:修改直播空间存储配置 + * POST /v2/hubs//persistence + * + * @param param.hub 请求直播空间名 + * @param param.storageBucket 存储空间 + * @param param.liveDataExpireDays 存储过期时间 + * @return 修改直播空间存储配置是否错误 + * @throws QiniuException 异常 + */ + public QiniuException hubPersistence(PiliHubModel.HubPersistenceRequest param) throws QiniuException { + byte[] body = Json.encode(param).getBytes(Constants.UTF_8); + String url = this.server + "/v2/hubs/" + param.hub + "/persistence"; + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * hubSnapshot 修改直播空间封面配置 + * 参考文档:修改直播空间存储配置 + * POST /v2/hubs//snapshot + * + * @param param.hub 请求直播空间名 + * @param param.snapshotInterval SnapshotInterval 间隔时间 + * @return 获取直播空间列表请求的回复 + * @throws QiniuException 异常 + */ + public QiniuException hubSnapshot(PiliHubModel.HubSnapshotRequest param) throws QiniuException { + byte[] body = Json.encode(param).getBytes(Constants.UTF_8); + String url = this.server + "/v2/hubs/" + param.hub + "/snapshot"; + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } +} diff --git a/src/main/java/com/qiniu/pili/PiliHubModel.java b/src/main/java/com/qiniu/pili/PiliHubModel.java new file mode 100644 index 00000000..ed0e534d --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliHubModel.java @@ -0,0 +1,224 @@ +package com.qiniu.pili; + +import java.util.List; + +/** + * 这里定义了Pili Hub响应相关的类 + */ +public class PiliHubModel { + /** + * GetHubListResponse 查询直播空间列表返回值 + */ + public class HubListResult { + /** + * Items 直播空间列表 + */ + GetHubListItem[] items; + } + + /** + * GetHubListItem 查询直播空间列表项 + */ + public class GetHubListItem { + /** + * Name 直播空间 + */ + String name; + } + + public class HubInfoResult { + /** + * Name 直播空间名称 + */ + public String name; + + /** + * CreatedAt 创建时间,Unix 时间戳 + */ + public long createdAt; + + /** + * UpdatedAt 更新时间,Unix 时间戳 + */ + public long updatedAt; + + /** + * Domains 直播空间下的域名列表 + */ + public List domains; + + /** + * DefaultDomains 直播空间默认域名 + */ + public List defaultDomains; + + /** + * StorageBucket 存储 bucket + */ + public String storageBucket; + + /** + * LiveDataExpireDays 存储过期时间,单位:天 + */ + public long liveDataExpireDays; + + /** + * PublishSecurity 推流鉴权方式 + */ + public String publishSecurity; + + /** + * Nrop 鉴黄配置信息 + */ + public NropArgs nrop; + + /** + * PassiveCodecProfiles 被动转码配置,形式如:720p + */ + public List passiveCodecProfiles; + + /** + * Converts 主动转码配置,形式如:720p + */ + public List converts; + + /** + * HlsPlus 是否开启 hls 低延迟 + */ + public boolean hlsPlus; + + /** + * VodDomain 点播域名 + */ + public String vodDomain; + + /** + * AccessLog 直播日志保存信息 + */ + public AccessLogOptions accessLog; + + /** + * SnapshotInterval 直播封面的截图间隔,单位:秒 + */ + public int snapshotInterval; + } + + public class HubDomain { + + /** + * Type 域名类型 + */ + public String type; + + /** + * Domain 域名 + */ + public String domain; + + /** + * CNAME + */ + public String cname; + } + + public class DefaultDomain { + + /** + * Type 域名类型 + */ + public String type; + + /** + * Domain 域名 + */ + public String domain; + } + + public class NropArgs { + + /** + * Enable 是否开启直播空间级别鉴黄功能 + */ + public boolean enable; + + /** + * Interval 截帧间隔,每个流隔多久进行截帧并鉴黄,单位:秒 + */ + public int interval; + + /** + * NotifyUrl 回调 URL + */ + public String notifyUrl; + + /** + * NotifyRate 通知阈值,鉴黄结果阈值表示 AI 模型判断当前直播画面有多大的概率涉黄,当鉴黄结果阈值大于或等于通知阈值时,将发送回调信息到回调 URL + */ + public double notifyRate; + } + + public class AccessLogOptions { + + /** + * SaveBucket 存储空间 + */ + public String saveBucket; + + /** + * ExpireDays 过期天数 + */ + public int expireDays; + } + + /** + * HubHlsplusRequest 修改直播空间 hls 低延迟配置请求参数 + */ + public class HubHlsplusRequest { + /** + * Hub 直播空间 + */ + public String hub; + /** + * HlsPlus 是否开启 hls 低延迟 + */ + public Boolean hlsPlus; + } + + /** + * HubPersistenceRequest 修改直播空间存储配置请求参数 + */ + public class HubPersistenceRequest { + /** + * Hub 直播空间 + */ + public String hub; + + /** + * StorageBucket 存储空间 + */ + public String storageBucket; + + /** + * LiveDataExpireDays 存储过期时间 + * 单位:天 + */ + public int liveDataExpireDays; + } + + /** + * HubSnapshotRequest 修改直播空间封面配置请求参数 + */ + public class HubSnapshotRequest { + /** + * Hub 直播空间 + */ + public String hub; + + /** + * SnapshotInterval 间隔时间 + * 单位:秒 + */ + public int snapshotInterval; + } + +} diff --git a/src/main/java/com/qiniu/pili/PiliManager.java b/src/main/java/com/qiniu/pili/PiliManager.java new file mode 100644 index 00000000..1bc63313 --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliManager.java @@ -0,0 +1,107 @@ +package com.qiniu.pili; + +import com.qiniu.common.QiniuException; +import com.qiniu.http.Client; +import com.qiniu.http.MethodType; +import com.qiniu.http.Response; +import com.qiniu.util.Auth; +import com.qiniu.util.StringMap; + +public class PiliManager { + + // APIHost 标准 API 服务器地址 + protected static final String API_HOST = "pili.qiniuapi.com"; + + // IAMAPIHost IAM(权限策略) API 服务器地址 + protected static final String IAMAPIHost = "pili-iam.qiniuapi.com"; + + // APIHTTPScheme HTTP 模式 + protected static final String APIHTTPScheme = "http://"; + + // APIHTTPSScheme HTTPS 模式 + protected static final String APIHTTPSScheme = "https://"; + + // DefaultAppName 默认 AppName 名称 + protected static final String DefaultAppName = "pili"; + + protected final Auth auth; + protected final String server; + protected final Client client; + protected final String apihost; + protected final String apihttpscheme; + + /* + * PiliManager 使用七牛标准的管理鉴权方式 + * + * @param auth - Auth 对象 + */ + public PiliManager(Auth auth) { + this(auth, API_HOST); + } + + public PiliManager(Auth auth, String server) { + this(auth, server, new Client()); + } + + public PiliManager(Auth auth, String server, Client client) { + this(auth, server, client, API_HOST, APIHTTPScheme, DefaultAppName); + } + + public PiliManager(Auth auth, String server, Client client, String apihost, String apihttpscheme, String appname) { + this.auth = auth; + this.server = server; + this.client = client; + + if (!apihost.isEmpty()) { + this.apihost = apihost; + } else { + this.apihost = API_HOST; + } + + if (!apihttpscheme.isEmpty()) { + this.apihttpscheme = apihttpscheme; + } else { + this.apihttpscheme = APIHTTPScheme; + } + + if (!appname.isEmpty()) { + Client.setAppName(appname); + } else { + Client.setAppName(DefaultAppName); + } + } + + /* + * 相关请求的方法列表 + */ + protected Response get(String url) throws QiniuException { + StringMap headers = composeHeader(url, MethodType.GET.toString(), null, Client.FormMime); + return client.get(url, headers); + } + + protected Response get(String url, byte[] body) throws QiniuException { + StringMap headers = composeHeader(url, MethodType.GET.toString(), body, Client.FormMime); + return client.get(url, headers); + } + + protected Response post(String url, byte[] body) throws QiniuException { + StringMap headers = composeHeader(url, MethodType.POST.toString(), body, Client.JsonMime); + return client.post(url, body, headers, Client.JsonMime); + } + + protected Response put(String url, byte[] body) throws QiniuException { + StringMap headers = composeHeader(url, MethodType.PUT.toString(), body, Client.JsonMime); + return client.put(url, body, headers, Client.JsonMime); + } + + protected Response delete(String url) throws QiniuException { + StringMap headers = composeHeader(url, MethodType.DELETE.toString(), null, Client.DefaultMime); + return client.delete(url, headers); + } + + protected StringMap composeHeader(String url, String method, byte[] body, String contentType) { + StringMap headers = auth.authorizationV2(url, method, body, contentType); + headers.put("Content-Type", contentType); + return headers; + } +} diff --git a/src/main/java/com/qiniu/pili/PiliStatManager.java b/src/main/java/com/qiniu/pili/PiliStatManager.java new file mode 100644 index 00000000..a1ef28c9 --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliStatManager.java @@ -0,0 +1,474 @@ +package com.qiniu.pili; + +import com.qiniu.common.QiniuException; +import com.qiniu.http.Client; +import com.qiniu.http.Response; +import com.qiniu.util.Auth; +import com.qiniu.util.StringMap; +import com.qiniu.util.UrlUtils; + +public class PiliStatManager extends PiliManager { + public PiliStatManager(Auth auth) { + super(auth); + } + + public PiliStatManager(Auth auth, String server) { + super(auth, server); + } + + public PiliStatManager(Auth auth, String server, Client client) { + super(auth, server, client); + } + + public PiliStatManager(Auth auth, String server, Client client, String apihost, String apihttpscheme, + String appname) { + super(auth, server, client, apihost, apihttpscheme, appname); + } + + /** + * FlowDefaultSelect 上下行流量默认查询字段 + */ + public static final String FLOW_DEFAULT_SELECT = "flow"; + + /** + * CodecDefaultSelect 转码使用量默认查询字段 + */ + public static final String CODEC_DEFAULT_SELECT = "duration"; + + /** + * NropDefaultSelect 鉴黄使用量默认查询字段 + */ + public static final String NROP_DEFAULT_SELECT = "count"; + + /** + * getStatUpflow 获取上行流量 + * 参考文档:获取上行流量 + * GET + * /statd/upflow?$hub=&$domain=&$area=area&begin=&end=&g=&select=flow + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.select 值字段,用于返回需要查询的数据。可选值为flow,流量,单位:byte。带宽可以从流量转换,公式为 + * 带宽=流量*8/时间粒度,单位:bps + * @param param.where 查询where条件 hub 直播空间 domain 域名 area 区域 + * 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + * @return 获取上行流量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatResponse[] getStatUpflow(PiliStatModel.GetStatUpflowRequest param) throws QiniuException { + if (param.select.isEmpty()) { + param.select = FLOW_DEFAULT_SELECT; + } + + String url = server + "/statd/upflow"; + StringMap queryMap = new StringMap(); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("g", param.commonRequest.g); + queryMap.put("end", param.commonRequest.end); + queryMap.put("select", param.select); + queryMap.putNotNull("hub", param.where.get("hub").toString()); + queryMap.putNotNull("domain", param.where.get("domain").toString()); + queryMap.putNotNull("area", param.where.get("area").toString()); + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + + Response response = get(requestUrl); + if (response == null) { + throw new QiniuException(response); + } + return response.jsonToObject(PiliStatModel.StatResponse[].class); + } + + /** + * groupStatUpflow 分组获取上行流量 + * 参考文档:分组获取上行流量 + * GET + * /statd/upflow?$hub=&$domain=&$area=area&begin=&end=&g=&group=&select=flow + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.group 按特定条件将返回数据分组,可取值为条件字段 + * @param param.select 值字段,用于返回需要查询的数据。可选值为flow,流量,单位:byte。带宽可以从流量转换,公式为 + * 带宽=流量*8/时间粒度,单位:bps + * @param param.where 查询where条件 hub 直播空间 domain 域名 area 区域 + * 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + * @return 获取上行流量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatGroupResponse[] groupStatUpflow(PiliStatModel.GroupStatUpflowRequest param) + throws QiniuException { + + if (param.select.isEmpty()) { + param.select = FLOW_DEFAULT_SELECT; + } + + String url = this.server + "/statd/upflow"; + StringMap queryMap = new StringMap(); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("g", param.commonRequest.g); + queryMap.put("end", param.commonRequest.end); + queryMap.put("select", param.select); + queryMap.putNotNull("group", param.group); + queryMap.putNotNull("hub", param.where.get("hub").toString()); + queryMap.putNotNull("domain", param.where.get("domain").toString()); + queryMap.putNotNull("area", param.where.get("area").toString()); + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + + Response response = get(requestUrl); + if (response == null) { + throw new QiniuException(response); + } + return response.jsonToObject(PiliStatModel.StatGroupResponse[].class); + } + + /** + * getStatUpflow 查询直播下行流量 + * 参考文档:获取直播下行流量 + * GET + * /statd/downflow?$hub=&$domain=&$area=area&begin=&end=&g=&group=&select=flow + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.select 值字段,用于返回需要查询的数据。可选值为flow,流量,单位:byte。带宽可以从流量转换,公式为 + * 带宽=流量*8/时间粒度,单位:bps + * @param param.where 查询where条件 hub 直播空间 domain 域名 area 区域 + * 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + * @return 获取下行流量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatResponse[] getStatDownflow(PiliStatModel.GetStatDownflowRequest param) throws QiniuException { + if (param.select.isEmpty()) { + param.select = FLOW_DEFAULT_SELECT; + } + + String url = this.server + "/statd/downflow"; + StringMap queryMap = new StringMap(); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("g", param.commonRequest.g); + queryMap.put("end", param.commonRequest.end); + queryMap.put("select", param.select); + queryMap.putNotNull("hub", param.where.get("hub").toString()); + queryMap.putNotNull("domain", param.where.get("domain").toString()); + queryMap.putNotNull("area", param.where.get("area").toString()); + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + + Response response = get(requestUrl); + if (response == null) { + throw new QiniuException(response); + } + return response.jsonToObject(PiliStatModel.StatResponse[].class); + } + + /** + * groupStatDownflow 分组获取下行流量 + * 参考文档:获取上行流量 + * GET + * /statd/upflow?$hub=&$domain=&$area=area&begin=&end=&g=&select=flow + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.group 按特定条件将返回数据分组,可取值为条件字段 + * @param param.select 值字段,用于返回需要查询的数据。可选值为flow,流量,单位:byte。带宽可以从流量转换,公式为 + * 带宽=流量*8/时间粒度,单位:bps + * @param param.where 查询where条件 hub 直播空间 domain 域名 area 区域 + * 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + * @return 获取下行流量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatGroupResponse[] groupStatDownflow(PiliStatModel.GroupStatDownflowRequest param) + throws QiniuException { + if (param.select.isEmpty()) { + param.select = FLOW_DEFAULT_SELECT; + } + + String url = server + "/statd/downflow"; + StringMap queryMap = new StringMap(); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("g", param.commonRequest.g); + queryMap.put("end", param.commonRequest.end); + queryMap.put("select", param.select); + queryMap.put("group", param.group); + queryMap.putNotNull("hub", param.where.get("hub").toString()); + queryMap.putNotNull("domain", param.where.get("domain").toString()); + queryMap.putNotNull("area", param.where.get("area").toString()); + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + + Response response = get(requestUrl); + if (response == null) { + throw new QiniuException(response); + } + return response.jsonToObject(PiliStatModel.StatGroupResponse[].class); + } + + /** + * getStatCodec 获取直播转码使用量 + * 参考文档:获取直播转码使用量 + * GET + * /statd/codec?$hub=&$profile=&begin=&end=&g=&group=&select=duration + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.select 值字段,用于返回需要查询的数据。可选值为flow,流量,单位:byte。带宽可以从流量转换,公式为 + * 带宽=流量*8/时间粒度,单位:bps + * @param param.where 查询where条件 hub 直播空间 domain 域名 area 区域 + * 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + * @return 获取直播转码使用量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatResponse[] getStatCodec(PiliStatModel.GetStatCodecRequest param) throws QiniuException { + if (param.select.isEmpty()) { + param.select = CODEC_DEFAULT_SELECT; + } + + String url = this.server + "/statd/codec"; + StringMap queryMap = new StringMap(); + queryMap.put("select", param.select); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("g", param.commonRequest.g); + queryMap.putWhen("end", param.commonRequest.end, !param.commonRequest.end.isEmpty()); + queryMap.putWhen("where", param.where, !param.where.isEmpty()); + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStatModel.StatResponse[].class); + } + + /** + * GroupStatCodec 分组获取直播转码使用量 + * 参考文档:获取直播转码使用量 + * GET + * /statd/codec?$hub=&$profile=&begin=&end=&g=&select=duration + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.group 按特定条件将返回数据分组,可取值为条件字段 + * @param param.select 值字段,用于返回需要查询的数据。 duration 时长,单位:毫秒 + * @param param.where 查询where条件 hub 直播空间 profile 转码规格 + * @return 获取直播转码使用量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatGroupResponse[] groupStatCodec(PiliStatModel.GroupStatCodecRequest param) throws QiniuException { + if (param.select.isEmpty()) { + param.select = CODEC_DEFAULT_SELECT; + } + + String url = this.server + "/statd/codec"; + StringMap queryMap = new StringMap(); + queryMap.put("select", param.select); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("group", param.group); + queryMap.put("g", param.commonRequest.g); + queryMap.putWhen("end", param.commonRequest.end, !param.commonRequest.end.isEmpty()); + queryMap.putWhen("where", param.where, !param.where.isEmpty()); + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStatModel.StatGroupResponse[].class); + } + + /** + * getStatNrop 获取直播鉴黄使用量 + * 参考文档:获取鉴黄使用量 + * GET + * /statd/nrop?$assured=&$hub=&begin=&end=&g=&select=count + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.select 值字段,用于返回需要查询的数据。可选值为flow,流量,单位:byte。带宽可以从流量转换,公式为 + * 带宽=流量*8/时间粒度,单位:bps + * @param param.where 查询where条件 hub 直播空间 domain 域名 area 区域 + * 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + * @return 获取直播鉴黄使用量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatResponse[] getStatNrop(PiliStatModel.GetStatNropRequest param) throws QiniuException { + if (param.select.isEmpty()) { + param.select = NROP_DEFAULT_SELECT; + } + + String url = this.server + "/statd/nrop"; + StringMap queryMap = new StringMap(); + queryMap.put("select", param.select); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("g", param.commonRequest.g); + queryMap.putWhen("end", param.commonRequest.end, !param.commonRequest.end.isEmpty()); + queryMap.putWhen("where", param.where, !param.where.isEmpty()); + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStatModel.StatResponse[].class); + } + + /** + * GroupStatNrop 分组获取直播鉴黄使用量 + * 参考文档:获取直播转码使用量 + * GET + * /statd/nrop?$assured=&$hub=&begin=&end=&g=&group=&select=count + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.group 按特定条件将返回数据分组,可取值为条件字段 + * @param param.select 值字段,用于返回需要查询的数据 count 鉴黄次数 + * @param param.where 查询where条件 hub 直播空间 assured + * 鉴黄结果是否确定,true或false + * @return 获取直播鉴黄使用量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatGroupResponse[] groupStatNrop(PiliStatModel.GroupStatCodecRequest param) throws QiniuException { + if (param.select.isEmpty()) { + param.select = CODEC_DEFAULT_SELECT; + } + + String url = this.server + "/statd/nrop"; + StringMap queryMap = new StringMap(); + queryMap.put("select", param.select); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("group", param.group); + queryMap.put("g", param.commonRequest.g); + queryMap.putWhen("end", param.commonRequest.end, !param.commonRequest.end.isEmpty()); + queryMap.putWhen("where", param.where, !param.where.isEmpty()); + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStatModel.StatGroupResponse[].class); + } + + /** + * getStatCaster 获取导播台使用量 + * 参考文档:获取导播台使用量 + * GET + * /statd/caster?$resolution=&$container=&begin=&end=&g=&select= + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.group 按特定条件将返回数据分组,可取值为条件字段 + * @param param.select 值字段,用于返回需要查询的数据。upflow 上行流量,单位:byte / + * 下行流量,单位:byte / 使用时长,单位:秒 + * @param param.where 查询where条件 container 容器 / resolution 分辨率 + * @return 获取直播鉴黄使用量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatGroupResponse[] groupStatCaster(PiliStatModel.GroupStatCasterRequest param) + throws QiniuException { + String url = this.server + "/statd/caster"; + StringMap queryMap = new StringMap(); + queryMap.put("select", param.select); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("group", param.group); + queryMap.put("g", param.commonRequest.g); + queryMap.putWhen("end", param.commonRequest.end, !param.commonRequest.end.isEmpty()); + queryMap.putWhen("where", param.where, !param.where.isEmpty()); + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStatModel.StatGroupResponse[].class); + } + + /** + * getStatPub 获取Pub服务使用量 + * 参考文档:查询Pub转推服务使用量 + * GET + * /statd/pub?$tp=&begin=&end=&g=&group=&select= + * + * @param param.commonRequest.begin 开始时间,支持格式:20060102、20060102150405 + * @param param.commonRequest.end 结束时间,支持格式:20060102、20060102150405,超过当前时间,则以当前时间为准,时间范围为左闭右开区间 + * @param param.commonRequest.g 时间粒度,可取值为 5min、hour、day、month + * @param param.group 按特定条件将返回数据分组,可取值为条件字段 + * @param param.select count 转推次数 / duration 转推时长,单位:毫秒 + * @param param.where 查询where条件 tp 状态 + * @return 获取直播鉴黄使用量请求的回复 + * @throws QiniuException 异常 + */ + public PiliStatModel.StatGroupResponse[] groupStatPub(PiliStatModel.GroupStatPubRequest param) throws QiniuException { + String url = this.server + "/statd/caster"; + StringMap queryMap = new StringMap(); + queryMap.put("select", param.select); + queryMap.put("begin", param.commonRequest.begin); + queryMap.put("group", param.group); + queryMap.put("g", param.commonRequest.g); + queryMap.putWhen("end", param.commonRequest.end, !param.commonRequest.end.isEmpty()); + queryMap.putWhen("where", param.where, !param.where.isEmpty()); + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStatModel.StatGroupResponse[].class); + } +} diff --git a/src/main/java/com/qiniu/pili/PiliStatModel.java b/src/main/java/com/qiniu/pili/PiliStatModel.java new file mode 100644 index 00000000..c5d46c94 --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliStatModel.java @@ -0,0 +1,373 @@ +package com.qiniu.pili; + +import java.util.Date; +import java.util.Map; + +public class PiliStatModel { + + /** + * 统计接口通用请求参数 + */ + public class GetStatCommonRequest { + /** + * Begin 开始时间 + * 支持格式:20060102、20060102150405 + */ + public String begin; + + /** + * End 结束时间 + * 支持格式:20060102、20060102150405 + * 超过当前时间,则以当前时间为准 + * 时间范围为左闭右开区间 + */ + public String end; + + /** + * g 时间粒度 + * 可选项 5min hour day month,部分接口仅支持部分粒度 + */ + public String g; + } + + /** + * 获取上行流量请求参数 + */ + public class GetStatUpflowRequest { + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Where 查询条件 + * Hub 直播空间 + * Domain 域名 + * Area 区域 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + */ + public Map where; + + /** + * Select 查询值 + * Flow 流量,单位:byte,带宽可以从流量转换,公式为 带宽=流量*8/时间粒度,单位:bps + */ + public String select; + } + + /** + * 分组获取上行流量请求参数 + */ + public class GroupStatUpflowRequest { + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Group 分组 + */ + public String group; + + /** + * Where 查询条件 + * Hub 直播空间 + * Domain 域名 + * Area 区域 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + */ + public Map where; + + /** + * Select 查询值 + * Flow 流量,单位:byte,带宽可以从流量转换,公式为 带宽=流量*8/时间粒度,单位:bps + */ + public String select; + } + + /** + * 获取下行流量请求参数 + */ + public class GetStatDownflowRequest { + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Where 查询条件 + * Hub 直播空间 + * Domain 域名 + * Area 区域 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + */ + public Map where; + + /** + * Select 查询值 + * Flow 流量,单位:byte,带宽可以从流量转换,公式为 带宽=流量*8/时间粒度,单位:bps + */ + public String select; + } + + /** + * GroupStatDownflowRequest 分组获取下行流量请求参数 + */ + public class GroupStatDownflowRequest { + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Group 分组 + */ + public String group; + + /** + * Where 查询条件 + * Hub 直播空间 + * Domain 域名 + * Area 区域 中国大陆(cn)、香港(hk)、台湾(tw)、亚太(apac)、美洲(am)、欧洲/中东/非洲(emea) + */ + public Map where; + + /** + * Select 查询值 + * Flow 流量,单位:byte,带宽可以从流量转换,公式为 带宽=流量*8/时间粒度,单位:bps + */ + public String select; + } + + /** + * GetStatCodecRequest 获取直播转码使用量请求参数 + */ + public class GetStatCodecRequest { + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Where 查询条件 + * Hub 直播空间 + * Profile 转码规格 + */ + public Map where; + /** + * Select 查询值 + * Duration 时长,单位:毫秒 + */ + public String select; + } + + /** + * GroupStatCodecRequest 分组获取直播转码使用量请求参数 + */ + public class GroupStatCodecRequest { + + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Group 分组 + */ + public String group; + + /** + * Where 查询条件 + * Hub 直播空间 + * Profile 转码规格 + */ + public Map where; + + /** + * Select 查询值 + * Duration 时长,单位:毫秒 + */ + public String select; + } + + /** + * GetStatNropRequest 获取直播鉴黄使用量请求参数 + */ + public class GetStatNropRequest { + + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Where 查询条件 + * Hub 直播空间 + * Assured 鉴黄结果是否确定,true或false + */ + public Map where; + + /** + * Select 查询值 + * Count 鉴黄次数 + */ + public String select; + } + + // GroupStatNropRequest 分组获取直播鉴黄使用量请求参数 + public class GroupStatNropRequest { + + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest getStatCommonRequest; + + /** + * Group 分组 + */ + public String group; + + /** + * Where 查询条件 + * Hub 直播空间 + * Assured 鉴黄结果是否确定,true或false + */ + public Map where; + + /** + * Select 查询值 + * Count 鉴黄次数 + */ + public String select; + } + + // GetStatCasterRequest 获取导播台使用量请求参数 + public class GetStatCasterRequest { + + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Where 查询条件 + * Container 容器 + * Resolution 分辨率 + */ + public Map where; + + /** + * Select 查询值 + * Upflow 上行流量,单位:byte + * Downflow 下行流量,单位:byte + * Duration 使用时长,单位:秒 + */ + public String select; + } + + // GroupStatCasterRequest 分组获取导播台使用量请求参数 + public class GroupStatCasterRequest { + + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Group 分组 + */ + public String group; + + /** + * Where 查询条件 + * Container 容器 + * Resolution 分辨率 + */ + public Map where; + + /** + * Select 查询值 + * Upflow 上行流量,单位:byte + * Downflow 下行流量,单位:byte + * Duration 使用时长,单位:秒 + */ + public String select; + } + + /** + * GetStatPubRequest 获取Pub服务使用量请求参数 + */ + public class GetStatPubRequest { + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Where 查询条件 + * Tp 状态 + */ + public Map where; + + /** + * Select 查询值 + * Count 转推次数 + * Duration 转推时长,单位:毫秒 + */ + public String select; + } + + // GroupStatPubRequest 分组获取Pub服务使用量请求参数 + public class GroupStatPubRequest { + + /** + * CommonRequest 通用请求参数 + */ + public GetStatCommonRequest commonRequest; + + /** + * Group 分组 + */ + public String group; + + /** + * Where 查询条件 + * Tp 状态 + */ + public Map where; + + /** + * Select 查询值 + * Count 转推次数 + * Duration 转推时长,单位:毫秒 + */ + public String select; + } + + // StatResponse 统计返回值 + public class StatResponse { + + /** + * Time 时间 + */ + public Date time; + + /** + * Values 数据,形式如:"values":{"flow":4527162977},其中"flow"对应select项 + */ + public Map values; + } + + // StatGroupResponse 分组统计返回值 + public class StatGroupResponse { + + /** + * Time 时间 + */ + public Date time; + + /** + * Values + * 数据,形式如:"values":{"SD":{"duration":4527162977}},其中"SD"对应Group项,"duration"对应Select项 + */ + public Map> values; + } + +} diff --git a/src/main/java/com/qiniu/pili/PiliStreamManager.java b/src/main/java/com/qiniu/pili/PiliStreamManager.java new file mode 100644 index 00000000..96e4c7dc --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliStreamManager.java @@ -0,0 +1,286 @@ +package com.qiniu.pili; + +import java.util.HashMap; + +import com.qiniu.common.Constants; +import com.qiniu.common.QiniuException; +import com.qiniu.http.Client; +import com.qiniu.http.Response; +import com.qiniu.util.Auth; +import com.qiniu.util.Json; +import com.qiniu.util.StringMap; +import com.qiniu.util.UrlSafeBase64; +import com.qiniu.util.UrlUtils; + +public class PiliStreamManager extends PiliManager { + public PiliStreamManager(Auth auth) { + super(auth); + } + + public PiliStreamManager(Auth auth, String server) { + super(auth, server); + } + + public PiliStreamManager(Auth auth, String server, Client client) { + super(auth, server, client); + } + + public PiliStreamManager(Auth auth, String server, Client client, String apihost, String apihttpscheme, + String appname) { + super(auth, server, client, apihost, apihttpscheme, appname); + } + + /** + * getStreamsList + * 参考文档:查询直播流列表 + * GET + * /v2/hubs//streams?liveonly=&prefix=&limit=&marker= + * + * @param hub 请求直播空间 + * @param liveonly 只返回当前在线的流,true 表示查询的是正在直播的流,不指定表示返回所有的流 + * @param prefix 流名称前缀匹配 + * @param limit 返回值数量限制,取值范围0~5000 + * @param marker 游标,表示从该位置开始返回 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliStreamModel.GetStreamsListResponse getStreamsList(String hub, Boolean liveOnly, String prefix, + int limit, String marker) + throws QiniuException { + StringMap queryMap = new StringMap(); + queryMap.put("hub", hub); + queryMap.put("liveonly", liveOnly); + queryMap.put("prefix", prefix); + queryMap.put("limit", limit); + queryMap.put("marker", marker); + String url = server + "/v2/hubs/" + hub; + + String requestUrl = UrlUtils.composeUrlWithQueries(url, queryMap); + Response response = get(requestUrl); + return response.jsonToObject(PiliStreamModel.GetStreamsListResponse.class); + } + + /** + * getStreamBaseInfo 查询直播流信息 + * 参考文档:查询直播流列表 + * GET v2/hubs//streams/ + * + * @param hub 请求直播空间 + * @param stream 流 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliStreamModel.GetStreamBaseInfoResponse getStreamBaseInfo(String hub, String stream) throws QiniuException { + String url = server + "/v2/hubs/" + hub + "/streams/" + encodeStream(stream); + Response response = get(url); + return response.jsonToObject(PiliStreamModel.GetStreamBaseInfoResponse.class); + } + + /** + * streamDisable 禁用直播流 + * 参考文档:禁用直播流 + * POST /v2/hubs//streams//disabled + * + * @param hub 请求直播空间 + * @param stream 直播流名 + * @param disabledTill 禁播结束时间,Unix 时间戳,特殊值含义: -1 永久禁播;0 解除禁播 + * @param disablePeriodSecond 禁播时长,单位:秒,当 disabledTill 为0时,disablePeriodSecond + * 参数生效,值大于0 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public QiniuException streamDisable(String hub, String stream, int disabledTill, int disablePeriodSecond) + throws QiniuException { + String url = server + "/v2/hubs/" + hub + "/streams/" + encodeStream(stream) + "/disabled"; + HashMap req = new HashMap<>(); + req.put("hub", hub); + req.put("encodedStreamTitle", encodeStream(stream)); + req.put("disabledTill", disabledTill); + req.put("disablePeriodSecond", disablePeriodSecond); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * getStreamLiveStatus 查询直播流实时信息 + * 参考文档:查询直播流实时信息 + * GET v2/hubs//streams//live + * + * @param hub 请求直播空间 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliStreamModel.GetStreamLiveStatusResponse getStreamLiveStatus(String hub, String stream) throws QiniuException { + String url = server + "/v2/hubs/" + hub + "/streams/" + encodeStream(stream) + "/live"; + Response response = get(url); + return response.jsonToObject(PiliStreamModel.GetStreamLiveStatusResponse.class); + } + + /** + * batchGetStreamLiveStatus 批量查询直播实时状态 + * 参考文档:批量查询直播实时状态 + * POST /v2/hubs//livestreams + * + * @param hub 请求直播空间 + * @param items 直播流列表,查询直播流列表数量不超过100 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliStreamModel.BatchGetStreamLiveStatusResponse batchGetStreamLiveStatus(String hub, String[] items) + throws QiniuException { + String url = server + "/v2/hubs/" + hub + "/livestreams"; + HashMap req = new HashMap<>(); + req.put("item", items); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.jsonToObject(PiliStreamModel.BatchGetStreamLiveStatusResponse.class); + } + + /** + * getStreamHistory 查询直播流推流记录 + * 参考文档:查询直播流推流记录 + * GET + * /v2/hubs//streams//historyactivity?start=&end= + * + * @param hub 请求直播空间 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliStreamModel.GetStreamHistoryResponse getStreamHistory(long start, long end, String hub, String stream) + throws QiniuException { + String url = server + "/v2/hubs/" + hub + "/streams/" + encodeStream(stream) + "/historyactivity"; + StringMap queryMap = new StringMap(); + queryMap.put("start", start); + queryMap.put("end", end); + Response response = get(url); + if (response == null) { + throw new RuntimeException("Null response!"); + } + return response.jsonToObject(PiliStreamModel.GetStreamHistoryResponse.class); + } + + /** + * streamSaveas 录制直播回放 + * 参考文档:录制直播回放 + * POST /v2/hubs//streams//saveas + * + * @param hub 请求直播空间 + * @param stream 请求流名 + * @param start 开始时间,Unix 时间戳,默认为第一次直播开始时间 + * @param end 结束时间,Unix 时间戳,默认为当前时间 + * @param fname 文件名,为空时会随机生成一个文件名 + * @param format 文件格式,可选文件格式为: + * m3u8: HLS格式,默认值 + * flv: FLV格式,将回放切片转封装为单个flv文件,异步模式 + * mp4: MP4格式,将回放切片转封装为单个mp4文件,异步模式 + * 异步模式下,生成回放文件需要一定时间 + * @param pipeline 异步模式时,指定数据处理的队列,可以将优先级较高的任务配置到独立的队列中进行执行 + * @param notify 回调地址,异步模式完成任务后的回调通知地址,不指定表示不做回调,参考文档:状态查询 + * 同步模式下录制结果直接由接口返回,回调不生效 + * @param expireDays 切片文件的生命周期: + * 0: 默认值,表示修改ts文件生命周期为永久保存 + * >0: 表示修改ts文件的的生命周期为 ExpireDays 参数值 + * -1: 表示不修改ts文件的expire属性,可显著提升接口响应速度 + * @param persistentDeleteAfterDays 生成文件的生命周期: + * 0: 默认值,表示生成文件(m3u8/flv/mp4)永久保存 + * >0: 表示生成文件(m3u8/flv/mp4)的生命周期为 + * PersistentDeleteAfterDays 参数值 + * 注意,对于m3u8文件,只有当ExpireDays为-1时,persistentDeleteAfterDays才会生效,如果设置了切片文件的生命周期,那生成m3u8文件的生命周期会和切片文件ts的生命周期一致 + * @param firstTsType 过滤ts切片文件类型,部分非标准的直播流,在推流初期缺少视频帧或音频帧,过滤功能可以剔除这部分切片, + * 0: 默认值,不做过滤 + * 1: 第一个ts切片需要是纯视频类型,不符合预期的ts切片将被跳过 + * 2: 第一个ts切片需要是纯音频类型,不符合预期的ts切片将被跳过 + * 3: 第一个ts切片需要是音视频类型,不符合预期的ts切片将被跳过 + * @return 获取直播流列表请求的回复 + * @throws QiniuException 异常 + */ + public PiliStreamModel.StreamSaveasResponse streamSaveas(PiliStreamModel.StreamSaveasRequest param) throws QiniuException { + String url = server + "/v2/hubs/" + param.hub + "/streams/" + encodeStream(param.stream) + + "/saveas"; + HashMap req = new HashMap<>(); + req.put("fname", param.fname); + req.put("start", param.start); + req.put("end", param.end); + req.put("format", param.format); + req.put("pipeline", param.pipeline); + req.put("notify", param.notify); + req.put("expireDays", param.expireDays); + req.put("persistentDeleteAfterDays", param.persistentDeleteAfterDays); + req.put("firstTsType", param.firstTsType); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.jsonToObject(PiliStreamModel.StreamSaveasResponse.class); + } + + /** + * streamSnapshot 保存直播截图 + * 参考文档:禁用直播流 + * POST /v2/hubs//streams//snapshot + * + * @param hub 请求直播空间 + * @param stream 直播流名 + * @param time 截图时间,Unix 时间戳,不指定则为当前时间 + * @param fname 文件名,不指定系统会随机生成 + * @param format 文件格式,默认为jpg,可取值为jpg和png + * @param pipeline 异步模式时,指定数据处理的队列,可以将优先级较高的任务配置到独立的队列中进行执行 + * @param notify 回调地址,若指定回调地址,则截图动作为异步模式 + * @param deleteAfterDays 生命周期,- 0: 默认值,表示截图文件永久保存,单位:天 + * @return 获取直播流列表请求的回复 + * @throws StreamSnapshotResponse + */ + public PiliStreamModel.StreamSnapshotResponse streamSnapshot(PiliStreamModel.StreamSnapshotRequest param) + throws QiniuException { + String url = server + "/v2/hubs/" + param.hub + "/streams/" + encodeStream(param.stream) + + "/snapshot"; + HashMap req = new HashMap<>(); + req.put("time", param.time); + req.put("fname", param.fname); + req.put("format", param.format); + req.put("pipeline", param.pipeline); + req.put("notify", param.notify); + req.put("deleteAfterDays", param.deleteAfterDays); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.jsonToObject(PiliStreamModel.StreamSnapshotResponse.class); + } + + /** + * streamConverts 修改直播流转码配置 + * 参考文档:修改直播流转码配置 + * POST /v2/hubs//streams//converts + * + * @param hub 请求直播空间 + * @param stream 直播流名 + * @param time 截图时间,Unix 时间戳,不指定则为当前时间 + * @param fname 文件名,不指定系统会随机生成 + * @param format 文件格式,默认为jpg,可取值为jpg和png + * @param pipeline 异步模式时,指定数据处理的队列,可以将优先级较高的任务配置到独立的队列中进行执行 + * @param notify 回调地址,若指定回调地址,则截图动作为异步模式 + * @param deleteAfterDays 生命周期,- 0: 默认值,表示截图文件永久保存,单位:天 + * @return 获取直播流列表请求的回复 + * @throws QiniuException + */ + public QiniuException streamConverts(String hub, String stream, String[] converts) throws QiniuException { + String url = server + "/v2/hubs/" + hub + "/streams/" + encodeStream(stream) + "/converts"; + HashMap req = new HashMap<>(); + req.put("converts", converts); + byte[] body = Json.encode(req).getBytes(Constants.UTF_8); + Response response = post(url, body); + return response.isOK() ? null : new QiniuException(response); + } + + /** + * 请求流名base64编码 + */ + public static String encodeStream(String str) { + return UrlSafeBase64.encodeToString(str.getBytes()); + } +} diff --git a/src/main/java/com/qiniu/pili/PiliStreamModel.java b/src/main/java/com/qiniu/pili/PiliStreamModel.java new file mode 100644 index 00000000..b713043f --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliStreamModel.java @@ -0,0 +1,548 @@ +package com.qiniu.pili; + +import java.util.List; + +public class PiliStreamModel { + + public PiliStreamModel() { + } + + /** + * 请求查询直播流列表参数 + */ + public class GetStreamListRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * LiveOnly 只返回当前在线的流 + */ + public boolean liveOnly; + + /** + * Prefix 流名称前缀匹配 + */ + public String prefix; + + /** + * Limit 返回值数量限制 + */ + public String limit; + + /** + * Marker 从该位置开始返回 + */ + public String marker; + } + + /** + * 查询直播流列表返回值 + */ + public class GetStreamsListResponse { + /** + * Items 流列表 + */ + public List items; + + /** + * Marker 表示当前位置,若marker为空,表示遍历完成 + */ + public String marker; + } + + public class GetStreamsListResponseItem { + /** + * Key 流名 + */ + public String key; + } + + /** + * 查询直播流信息请求参数 + */ + public class GetStreamBaseInfoRequest { + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + } + + /** + * 查询直播流信息返回值 + */ + public class GetStreamBaseInfoResponse { + + /** + * CreatedAt 直播流创建时间 + * Unix 时间戳,单位:秒 + */ + public long createdAt; + + /** + * UpdatedAt 直播流更新时间 + * Unix 时间戳,单位:秒 + */ + public long updatedAt; + + /** + * ExpireAt 直播流过期时间 + * 默认流过期时间15天,Unix 时间戳,单位:秒 + */ + public long expireAt; + + /** + * DisabledTill 禁用结束时间 + */ + public int disabledTill; + + /** + * Converts 转码配置 + */ + public List converts; + + /** + * Watermark 是否开启水印 + */ + public boolean watermark; + + /** + * PublishSecurity 推流鉴权类型 + */ + public String publishSecurity; + + /** + * PublishKey 推流密钥 + */ + public String publishKey; + + /** + * NropEnable 是否开启鉴黄 + */ + public boolean nropEnable; + } + + /** + * 禁用直播流请求参数 + */ + public class StreamDisabledRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + + /** + * DisabledTill 禁用结束时间 + * Unix 时间戳,单位:秒 + * 特殊值 -1 表示永久禁用;0 解除禁用 + */ + public int disabledTill; + + /** + * DisablePeriodSecond 禁用时长 + * 单位:秒 + * 当 DisabledTill 为0时,DisablePeriodSecond 参数生效 + */ + public int disablePeriodSecond; + } + + /** + * 查询直播流实时信息请求参数 + */ + public class GetStreamLiveStatusRequest { + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + } + + /** + * 直播流实时状态 + */ + public class StreamLiveStatus { + /** + * StartAt 推流开始时间 + * Unix 时间戳,单位:秒 + */ + public long startAt; + + /** + * ClientIP 推流端IP + */ + public String clientIP; + + /** + * ServerIP 服务端IP + */ + public String serverIP; + + /** + * Bps 推流码率 + */ + public int bps; + + /** + * Fps 帧率 + */ + public StreamLiveStatusFPS fps; + + /** + * Key 流名 + */ + public String key; + } + + /** + * 流实时帧率 + */ + public class StreamLiveStatusFPS { + + /** + * Audio 音频帧率 + */ + public int audio; + + /** + * Video 视频帧率 + */ + public int video; + + /** + * Data metadata帧率 + */ + public int data; + } + + /** + * 查询直播流实时信息返回值 + */ + public class GetStreamLiveStatusResponse { + + /** + * StreamLiveStatus 直播流实时状态 + */ + public StreamLiveStatus streamLiveStatus; + + /** + * VideoBitRate 视频码率,单位:bps + */ + public int videoBitRate; + + /** + * AudioBitRate 音频码率,单位:bps + */ + public int audioBitRate; + } + + /** + * 批量查询直播实时状态请求参数 + */ + public class BatchGetStreamLiveStatusRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Items 流列表 查询流列表数量不超过100 + */ + public List items; + } + + /** + * 批量查询直播实时状态返回值 + */ + public class BatchGetStreamLiveStatusResponse { + /** + * Items 流列表 + */ + public List items; + } + + /** + * 查询直播流推流记录请求参数 + */ + public class GetStreamHistoryRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + + /** + * Start 开始时间 + * 单位:秒,默认为0 + */ + public long start; + + /** + * End 结束时间 + * 单位:秒,默认为当前时间 + */ + public long end; + } + + /** + * 查询直播流推流记录返回值 + */ + public class GetStreamHistoryResponse { + + /** + * Items 直播流推流记录列表 + */ + public List items; + } + + /** + * 查询直播流推流记录项 + */ + public class GetStreamHistoryItem { + + /** + * Start 推流开始时间 + */ + public long start; + + /** + * End 推流结束时间 + */ + public long end; + + /** + * ClientIP 推流端IP + */ + public String clientIP; + + /** + * ServerIP 服务端IP + */ + public String serverIP; + } + + /** + * 录制直播回放请求参数 + */ + public class StreamSaveasRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + + /** + * Start 开始时间 + * Unix 时间戳,单位:秒 + */ + public long start; + + /** + * End 结束时间 + * Unix 时间戳,单位:秒,默认为当前时间 + */ + public long end; + + /** + * Fname 文件名 + * 为空时会随机生成一个文件名 + */ + public String fname; + + /** + * Format + * 文件格式 + * 可选文件格式为 + * - m3u8: HLS格式,默认值 + * - flv: FLV格式,将回放切片转封装为单个flv文件,异步模式 + * - mp4: MP4格式,将回放切片转封装为单个mp4文件,异步模式 + * 异步模式下,生成回放文件需要一定时间 + */ + public String format; + + /** + * Pipeline + * 异步模式时,指定数据处理的队列 + * 可以将优先级较高的任务配置到独立的队列中进行执行 + * 参考文档:https://developer.qiniu.com/dora/kb/2500/streaming-media-queue-about-seven-cows + */ + public String pipeline; + + /** + * Notify 回调地址 + * 异步模式完成任务后的回调通知地址,不指定表示不做回调 + */ + public String notify; + + /** + * ExpireDays 切片文件的生命周期 + * - 0: 默认值,表示修改ts文件生命周期为永久保存 + * - >0: 表示修改ts文件的的生命周期为 ExpireDays 参数值 + * - -1: 表示不修改ts文件的expire属性,可显著提升接口响应速度 + */ + public int expireDays; + + /** + * PersistentDeleteAfterDays 生成文件的生命周期 + * - 0: 默认值,表示生成文件(m3u8/flv/mp4)永久保存 + * - >0: 表示生成文件(m3u8/flv/mp4)的生命周期为 PersistentDeleteAfterDays 参数值 + * m3u8文件只有当ExpireDays为-1时生效 + */ + public int persistentDeleteAfterDays; + + /** + * FirstTsType 过滤ts切片文件类型 + * 部分非标准的直播流,在推流初期缺少视频帧或音频帧,过滤功能可以剔除这部分切片 + * - 0: 默认值,不做过滤 + * - 1: 第一个ts切片需要是纯视频类型,不符合预期的ts切片将被跳过 + * - 2: 第一个ts切片需要是纯音频类型,不符合预期的ts切片将被跳过 + * - 3: 第一个ts切片需要是音视频类型,不符合预期的ts切片将被跳过 + */ + public byte firstTsType; + } + + /** + * 录制直播回放返回值 + */ + public class StreamSaveasResponse { + + /** + * Fname 文件名 + */ + public String fname; + + /** + * Start 开始时间 + * Unix 时间戳,单位:秒 + */ + public long start; + + /** + * End 结束时间 + * Unix 时间戳,单位:秒 + */ + public long end; + + /** + * PersistentID 异步任务ID + */ + public String persistentID; + } + + /** + * 保存直播截图请求参数 + */ + public class StreamSnapshotRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + + /** + * Time 截图时间 + * Unix 时间戳,单位:秒,不指定则为当前时间 + */ + public int time; + + /** + * Fname 文件名 + * 不指定系统会随机生成 + */ + public String fname; + + /** + * Format 文件格式 + * 默认为jpg,支持选择jpg/png + */ + public String format; + + /** + * Pipeline 异步模式时,指定数据处理的队列 + * 可以将优先级较高的任务配置到独立的队列中进行执行 + * 参考文档:https://developer.qiniu.com/dora/kb/2500/streaming-media-queue-about-seven-cows + */ + public String pipeline; + + /** + * Notify 回调地址 + * 若指定回调地址,则截图动作为异步模式 + */ + public String notify; + + /** + * DeleteAfterDays 生命周期 + * - 0: 默认值,表示截图文件永久保存,单位:天 + */ + public int deleteAfterDays; + } + + /** + * 保存直播截图返回值 + */ + public class StreamSnapshotResponse { + + /** + * Fname 文件名 + */ + public String fname; + + /** + * PersistentID 异步任务ID + */ + public String persistentID; + } + + /** + * 修改直播流转码配置请求参数 + */ + public class StreamConvertsRequest { + + /** + * Hub 直播空间 + */ + public String hub; + + /** + * Stream 流名 + */ + public String stream; + + /** + * Converts 转码配置 + */ + public String[] converts; + } +} diff --git a/src/main/java/com/qiniu/pili/PiliUrl.java b/src/main/java/com/qiniu/pili/PiliUrl.java new file mode 100644 index 00000000..1b5c9929 --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliUrl.java @@ -0,0 +1,189 @@ +package com.qiniu.pili; + +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +public class PiliUrl { + // RTMPPublishURL 生成 RTMP 推流地址 + public static String rtmpPublishUrl(String hub, String domain, String streamTitle) { + return String.format("rtmp://%s/%s/%s", domain, hub, streamTitle); + } + + /** + * 生成 SRT 推流地址 + * + * @param hub 云直播的 hub 名称 + * @param domain 云直播的推流域名 + * @param streamTitle 流名称 + * @return 生成的 SRT 推流地址 + */ + public static String srtPublishURL(String hub, String domain, String streamTitle) { + // 使用 String.format() 方法格式化字符串,将 domain、SRTPort、hub 和 streamTitle 替换到对应的位置 + return String.format("srt://%s:%s?streamid=#!::h=%s/%s,m=publish,domain=%s", domain, PiliUrlModel.SRTPort, hub, + streamTitle, domain); + } + + /** + * 生成 RTMP 播放地址 + * + * @param hub 云直播的 hub 名称 + * @param domain 云直播的播放域名 + * @param streamTitle 流名称 + * @return 生成的 RTMP 播放地址 + */ + public static String rtmpPlayURL(String hub, String domain, String streamTitle) { + // 使用 String.format() 方法格式化字符串,将 domain、hub 和 streamTitle 替换到对应的位置 + return String.format("rtmp://%s/%s/%s", domain, hub, streamTitle); + } + + /** + * 生成 HLS 播放地址 + * + * @param hub 云直播的 hub 名称 + * @param domain 云直播的播放域名 + * @param streamTitle 流名称 + * @return 生成的 HLS 播放地址 + */ + public static String hlsPlayURL(String hub, String domain, String streamTitle) { + // 使用 String.format() 方法格式化字符串,将 domain、hub 和 streamTitle 替换到对应的位置 + return String.format("https://%s/%s/%s.m3u8", domain, hub, streamTitle); + } + + /** + * 生成 HDL 播放地址 + * + * @param hub 云直播的 hub 名称 + * @param domain 云直播的播放域名 + * @param streamTitle 流名称 + * @return 生成的 HDL 播放地址 + */ + public static String hdlPlayURL(String hub, String domain, String streamTitle) { + // 使用 String.format() 方法格式化字符串,将 domain、hub 和 streamTitle 替换到对应的位置 + return String.format("https://%s/%s/%s.flv", domain, hub, streamTitle); + } + + // 转换 SRT URL + public static String convertSRTURL(URL url, String token) { + Map queryMap = new HashMap<>(); + String path = url.getPath().substring(1); // 去掉开头的斜杠 + for (String queryParam : url.getQuery().split("&")) { + String[] queryPair = queryParam.split("=", 2); + if (queryPair.length == 2) { + queryMap.put(queryPair[0], queryPair[1]); + } + } + queryMap.put("m", "publish"); + if (token != null && !token.isEmpty()) { + queryMap.put("token", token); + } + + List queryPartList = new ArrayList<>(); + for (Map.Entry entry : queryMap.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + try { + String queryPart = key + "=" + URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); + queryPartList.add(queryPart); + } catch (Exception e) { + e.printStackTrace(); + } + } + + String rawQuery = String.join(",", queryPartList); + + String host = url.getHost(); + if (!host.contains(":")) { + host += ":" + PiliUrlModel.SRTPort; + } + + return String.format("srt://%s?streamid=#!::h=%s,%s", host, path, rawQuery); + } + + /** + * 判断对象是否为其类型的零值 + * + * @param obj 待判断对象 + * @return 是否为零值 + */ + public static boolean isZero(Object obj) { + if (obj == null) { + return true; + } else if (obj instanceof Boolean) { + return !((Boolean) obj); + } else if (obj instanceof Number) { + return ((Number) obj).doubleValue() == 0; + } else if (obj instanceof Character) { + return (Character) obj == '\0'; + } else if (obj instanceof CharSequence) { + return ((CharSequence) obj).length() == 0; + } else if (obj.getClass().isArray()) { + for (int i = 0; i < Array.getLength(obj); i++) { + if (!isZero(Array.get(obj, i))) { + return false; + } + } + return true; + } else if (obj instanceof Map) { + return ((Map) obj).isEmpty(); + } else if (obj instanceof Collection) { + return ((Collection) obj).isEmpty(); + } else if (obj instanceof Iterable) { + return !((Iterable) obj).iterator().hasNext(); + } else if (obj instanceof Iterator) { + return !((Iterator) obj).hasNext(); + } else { + return false; + } + } + + /** + * magicCtx 生成魔法变量 + * $(key): 密钥 + * $(path): URL 中的 path 部分 + * $(streamKey): URL 中的 hub/stream 部分 + * $(streamTitle): URL 中的 stream 部分 + * $(path_): URL 中的 path 部分, 表示 path 层级 + * $(_): URL 中的 query 字段,举例: key1=val,魔法变量中使用 $(_key1) 表示 val + */ + public Map magicCtx(URL u, List query, String key) { + String path = u.getPath(); + Map ctx = new HashMap(); + ctx.put("key", key); + ctx.put("path", path); + ctx.put("streamKey", parseStreamKey(path)); + ctx.put("streamTitle", parseStreamTitile(path)); + + for (int k = 1; k <= path.split("/").length; k++) { + ctx.put("path_" + k, path.split("/")[k - 1]); + } + + for (String queryPart : query) { + if (!queryPart.isEmpty()) { + String q = "_" + queryPart.split("=")[0]; + ctx.put(q, queryPart.split("=")[1]); + } + } + return ctx; + } + + public String parseStreamKey(String path) { + String noExt = path.trim().substring(0, path.lastIndexOf(".")); + return noExt.substring(1).trim(); + } + + public String parseStreamTitile(String path) { + String noExt = path.trim().substring(0, path.lastIndexOf(".")); + String noFirstSlash = noExt.substring(1).trim(); + int slash = noFirstSlash.indexOf('/'); + return noFirstSlash.substring(slash + 1); + } + +} diff --git a/src/main/java/com/qiniu/pili/PiliUrlModel.java b/src/main/java/com/qiniu/pili/PiliUrlModel.java new file mode 100644 index 00000000..328f1dde --- /dev/null +++ b/src/main/java/com/qiniu/pili/PiliUrlModel.java @@ -0,0 +1,202 @@ +package com.qiniu.pili; + +public class PiliUrlModel { + private PiliUrlModel() { + + } + + /** + * SRTScheme SRT 协议头 + */ + public static final String SRTScheme = "srt"; + + /** + * SRTPort SRT 协议端口 + * 截止目前,SRT 协议没有 IANA 官方约定的端口号 + * 七牛采用 1935/UDP 作为 SRT 协议端口号 + */ + public static final String SRTPort = "1935"; + + /** + * SecurityTypeStaticKeyPart 静态鉴权密钥字段名 + */ + public static final String SecurityTypeStaticKeyPart = "key"; + + /** + * SecurityTypeExpiryTsPart 推流限时鉴权时间戳字段名 + */ + public static final String SecurityTypeExpiryTsPart = "expire"; + + /** + * SecurityTypeExpirySkTsPart 推流限时鉴权sk时间戳字段名 + */ + public static final String SecurityTypeExpirySkTsPart = "e"; + + /** + * SecurityTypeDynamicNoncePart 动态鉴权随机值字段名 + */ + public static final String SecurityTypeDynamicNoncePart = "nonce"; + + /** + * SecurityTypeTokenPart 鉴权签算字段名 + * 用于 限时鉴权(expiry)、限时鉴权SK(expiry_sk)、动态鉴权(dynamic) + */ + public static final String SecurityTypeTokenPart = "token"; + + /** + * 鉴权类型 + */ + public static final String SecurityTypeNull = ""; + + /** + * SecurityTypeNone 关闭鉴权 + * 用于推流 URL 签算(直播鉴权)和播放 URL 签算(时间戳防盗链) + * 强制关闭鉴权,域名级别鉴权不继承直播空间级别鉴权配置 + */ + public static final String SecurityTypeNone = "none"; + + /** + * SecurityTypeStatic 静态鉴权 + * 用于推流 URL 签算(直播鉴权) + */ + public static final String SecurityTypeStatic = "static"; + + /** + * SecurityTypeExpiry 限时鉴权 + * 用于推流 URL 签算(直播鉴权) + */ + public static final String SecurityTypeExpiry = "expiry"; + + /** + * SecurityTypeExpirySK 限时鉴权SK + * 用于推流 URL 签算(直播鉴权) + */ + public static final String SecurityTypeExpirySK = "expiry_sk"; + + /** + * Deprecated: SecurityTypeDynamic 动态鉴权 + * 用于推流 URL 签算(直播鉴权),该鉴权类型即将移除,不建议使用 + */ + @Deprecated + public static final String SecurityTypeDynamic = "dynamic"; + + /** + * SecurityTypeTsStartMD5 时间戳防盗链开始时间限制 + * 用于播放 URL 签算(时间戳防盗链) + * 签算有效时间从 URL 的时间戳开始,直到超过有效时间(range)范围 + */ + public static final String SecurityTypeTsStartMD5 = "tsStartMD5"; + + /** + * SecurityTypeTsExpireMD5 时间戳防盗链结束时间限制 + * 用于播放 URL 签算(时间戳防盗链) + * 签算有效时间从当前时间开始,直到 URL 的时间戳为止 + */ + public static final String SecurityTypeTsExpireMD5 = "tsExpireMD5"; + + public class SignPublishURLArgs { + /** + * SecurityType + * 鉴权类型 + */ + public String securityType; + + /** + * PublishKey + * 推流鉴权秘钥 + * 静态鉴权(static)、限时鉴权(expiry)、动态鉴权(dynamic) 类型必要参数 + */ + public String publishKey; + + /** + * ExpireAt + * 过期时间 + * 签算URL过期时间,单位:秒 + * 限时鉴权(expiry)、限时鉴权SK(expiry_sk) 类型必要参数 + */ + public long expireAt; + + /** + * Nonce + * 随机数 + * 要求每次推流请求的nonce值需要大于上一次推流请求的nonce值 + * 动态鉴权(dynamic) 鉴权类型必要参数 + */ + public int nonce; + + /** + * AccessKey + * 访问密钥 + * 限时鉴权SK(expiry_sk) 类型必要参数 + */ + public String accessKey; + + /** + * SecretKey + * 安全密钥 + * 限时鉴权SK(expiry_sk) 类型必要参数 + */ + public String secretKey; + } + + public class SignPlayURLArgs { + /** + * SecurityType + * 鉴权类型 + * 支持鉴权类型为 + * - tsStartMD5 时间戳防盗链开始时间限制 + * - tsExpireMD5 时间戳防盗链结束时间限制 + */ + public String securityType; + + /** + * Key + * 密钥 + */ + public String key; + + /** + * Timestamp + * 时间戳 + * 单位:秒 + * 鉴权类型为 tsStartMD5 时,表示鉴权开始时间 + * 鉴权类型为 tsExpireMD5 时,表示鉴权结束时间 + */ + public long timestamp; + + /** + * Rule + * 签名规则 + * 支持魔法变量的规则,最终签算结果为所有变量的md5 + * - $(key): 密钥 + * - $(path): URL 中的 path 部分 + * - $(streamKey): URL 中的 hub/stream 部分 + * - $(streamTitle): URL 中的 stream 部分 + * - $(path_): URL 中的 path 部分, 表示 path 层级 + * - $(_): URL 中的 query 字段,举例: key1=val,魔法变量中使用 $(_key1) 表示 val + * 举例: + * 配置Rule为: $(key)$(path)$(_t) + * 魔法变量替换完成后: key/hub/streamTitle1634745600 + * 对结果进行md5计算,最终签算值为:3bc26fe6b35f5c7efab87778c5b27993 + */ + public String rule; + + /** + * TsPart 时间戳字段 + * URL 中表示时间戳的字段名 + */ + public String tsPart; + + /** + * TsBase 时间戳进制 + * 可选进制格式为 2-36,即 2 进制到 36 进制,默认使用 16 进制 + */ + public int tsBase; + + /** + * SignPart 签名字段 + * URL 中表示 token 的字段名 + */ + public String signPart; + } +} diff --git a/src/test/java/test/com/qiniu/TestConfig.java b/src/test/java/test/com/qiniu/TestConfig.java index e7162328..d79a6895 100644 --- a/src/test/java/test/com/qiniu/TestConfig.java +++ b/src/test/java/test/com/qiniu/TestConfig.java @@ -30,6 +30,18 @@ public final class TestConfig { public static final String smsAccessKey = "test"; public static final String smsSecretKey = "test"; + // pili: ak, sk auth + public static final String piliAccessKey = ""; + public static final String piliSecretKey = ""; + public static final String piliHTTPhost = ""; + public static final String piliTestHub = ""; + public static final String piliTestDomain = ""; + public static final String piliTestVodDomain = ""; + public static final String piliTestCertName = ""; + public static final String piliTestStorageBucket = ""; + public static final String piliTestStream = ""; + + public static final String testDefaultKey = "do_not_delete/1.png"; public static final String getTestDefaultMp4FileKey = "do_not_delete/1.mp4"; public static final String testMp4FileKey = "do_not_delete/1.mp4"; diff --git a/src/test/java/test/com/qiniu/pili/PiliDomainTest.java b/src/test/java/test/com/qiniu/pili/PiliDomainTest.java new file mode 100644 index 00000000..0fb26306 --- /dev/null +++ b/src/test/java/test/com/qiniu/pili/PiliDomainTest.java @@ -0,0 +1,149 @@ +package test.com.qiniu.pili; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import com.qiniu.common.QiniuException; +import com.qiniu.pili.PiliDomainManager; +import com.qiniu.pili.PiliDomainModel; +import com.qiniu.util.Auth; + +import test.com.qiniu.TestConfig; + +public class PiliDomainTest { + private PiliDomainManager domainManager; + + /** + * 初始化 + * + * @throws Exception + */ + @BeforeEach + public void setUp() throws Exception { + this.domainManager = new PiliDomainManager( + Auth.create(TestConfig.piliAccessKey, TestConfig.piliSecretKey), TestConfig.piliHTTPhost); + } + + @Test + @Tag("UnitTest") + public void testGetDomainsList() { + String hub = "test-hub"; + String expectedErr = ""; + try { + PiliDomainModel.DomainsListResult result = domainManager.getDomainsList(hub); + System.out.println(result); + } catch (QiniuException e) { + assertEquals(expectedErr, e.getMessage()); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetDomainInfo() { + String hub = TestConfig.piliTestHub; + String domain = TestConfig.piliTestDomain; + String expectedErr = ""; + + try { + PiliDomainModel.DomainInfoResult response = domainManager.getDomainInfo(hub, + domain); + assertNotNull(response); + } catch (QiniuException e) { + assertEquals(expectedErr, e.getMessage()); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void test_Bind_UnBindDomain() { + String domain = "testbind-" + "2001" + ".fake.qiniu.com"; + String hub = TestConfig.piliTestHub; + String type = "liveHls"; // or "live_hls", "live_hdl", "playback_hls" + + try { + domainManager.bindDomain(hub, domain, type); + } catch (QiniuException e) { + assertNotNull(e); + return; + } + + try { + domainManager.unbindDomain(hub, domain); + } catch (QiniuException e) { + assertNotNull(e); + return; + } + } + + @Test + @Tag("UnitTest") + public void testBindVodDomain() { + String hub = TestConfig.piliTestHub; + String vodDomain = TestConfig.piliTestVodDomain; + + try { + QiniuException exception = domainManager.bindVodDomain(hub, vodDomain); + if (exception != null) { + System.out.println("Failed to unbind domain: " + exception.getMessage()); + } else { + System.out.println("Domain unbind succeeded."); + } + } catch (QiniuException e) { + System.out.println("Error: " + e.getMessage()); + assertNotNull(e); + return; + } + } + + @Test + @Tag("UnitTest") + public void testSetDomainCert() { + String hub = TestConfig.piliTestHub; + String domain = TestConfig.piliTestDomain; + String certName = TestConfig.piliTestCertName; + + try { + QiniuException exception = domainManager.setDomainCert(hub, domain, certName); + if (exception != null) { + System.out.println("Failed to setDomainCert domain: " + exception.getMessage()); + } else { + System.out.println("Domain setDomainCert succeeded."); + } + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testSetDomainURLRewrite() { + String hub = TestConfig.piliTestHub; + String domain = TestConfig.piliTestDomain; + List rules = new ArrayList<>(); + + rules.add(new PiliDomainModel.Rules("(.+)/live/(.+)/playlist.m3u8", "${1}/hub/${2}.m3u8")); + rules.add(new PiliDomainModel.Rules("pattern2", "replacement2")); + + try { + QiniuException exception = domainManager.setDomainURLRewrite(hub, domain, rules); + if (exception != null) { + System.out.println("Failed to setDomainCert domain: " + exception.getMessage()); + } else { + System.out.println("Domain setDomainCert succeeded."); + } + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + assertNull(e); + } + } +} diff --git a/src/test/java/test/com/qiniu/pili/PiliHubTest.java b/src/test/java/test/com/qiniu/pili/PiliHubTest.java new file mode 100644 index 00000000..4f5cebd4 --- /dev/null +++ b/src/test/java/test/com/qiniu/pili/PiliHubTest.java @@ -0,0 +1,136 @@ +package test.com.qiniu.pili; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; + +import com.qiniu.common.QiniuException; +import com.qiniu.pili.PiliHubManager; +import com.qiniu.pili.PiliHubModel; +import com.qiniu.util.Auth; + +import test.com.qiniu.ResCode; +import test.com.qiniu.TestConfig; + +public class PiliHubTest { + private PiliHubManager hubManager; + + /** + * 初始化 + * + * @throws Exception + */ + @BeforeEach + public void setUp() throws Exception { + this.hubManager = new PiliHubManager( + Auth.create(TestConfig.piliAccessKey, TestConfig.piliSecretKey), TestConfig.piliHTTPhost); + } + + @Test + @Tag("UnitTest") + public void testGetHubList() { + try { + PiliHubModel.HubListResult response = hubManager.getHubList(); + assertNotNull(response); + } catch (QiniuException e) { + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetHubInfo() { + try { + PiliHubModel.HubInfoResult response = hubManager.getHubInfo(TestConfig.piliTestHub); + System.out.println("hubManager.getHubInfo: response: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("hubManager.getHubInfo ERROR: response: " + e.getMessage()); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testHubSecurity() { + try { + QiniuException exception = hubManager.hubSecurity(TestConfig.piliTestHub, "static", "qiniu_static_publish_key"); + if (exception != null) { + System.out.println("hubManager.hubSecurity ERROR: " + exception.getMessage()); + } else { + System.out.println("hubManager.hubSecurity succeeded."); + } + } catch (QiniuException e) { + System.out.println("Error: " + e.getMessage()); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testHubHlsplus() { + try { + PiliHubModel model = new PiliHubModel(); + PiliHubModel.HubHlsplusRequest param = model.new HubHlsplusRequest(); + + param.hub = TestConfig.piliTestHub; + param.hlsPlus = true; // 或者 false,根据您的需求设置 + QiniuException exception = hubManager.hubHlsplus(param); + if (exception != null) { + System.out.println("hubManager.hubSecurity ERROR: " + exception.getMessage()); + } else { + System.out.println("hubManager.testHubHlsplus succeeded."); + } + } catch (QiniuException e) { + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testHubPersistenceRequest() { + try { + PiliHubModel model = new PiliHubModel(); + PiliHubModel.HubPersistenceRequest param = model.new HubPersistenceRequest(); + + param.hub = TestConfig.piliTestHub; + param.liveDataExpireDays = 3; + param.storageBucket = ""; + QiniuException exception = hubManager.hubPersistence(param); + if (exception != null) { + System.out.println("hubManager.testHubPersistenceRequest ERROR: " + exception.getMessage()); + } else { + System.out.println("hubManager.testHubPersistenceRequest succeeded."); + } + } catch (QiniuException e) { + assertNull(e); + System.out.println("Error: " + e.getMessage()); + } + } + + @Test + @Tag("UnitTest") + public void testHubSnapshotRequest() { + try { + PiliHubModel model = new PiliHubModel(); + PiliHubModel.HubSnapshotRequest param = model.new HubSnapshotRequest(); + + param.hub = TestConfig.piliTestHub; + param.snapshotInterval = 3; + + QiniuException exception = hubManager.hubSnapshot(param); + if (exception != null) { + System.out.println("hubManager.testHubSnapshotRequest ERROR: " + exception.getMessage()); + } else { + System.out.println("hubManager.testHubSnapshotRequest succeeded."); + } + } catch (QiniuException e) { + assertNull(e); + System.out.println("Error: " + e.getMessage()); + } + } +} diff --git a/src/test/java/test/com/qiniu/pili/PiliStatTest.java b/src/test/java/test/com/qiniu/pili/PiliStatTest.java new file mode 100644 index 00000000..d488f875 --- /dev/null +++ b/src/test/java/test/com/qiniu/pili/PiliStatTest.java @@ -0,0 +1,305 @@ +package test.com.qiniu.pili; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import com.qiniu.common.QiniuException; +import com.qiniu.pili.PiliStatManager; +import com.qiniu.pili.PiliStatModel; +import com.qiniu.util.Auth; + +import test.com.qiniu.ResCode; +import test.com.qiniu.TestConfig; + +public class PiliStatTest { + private PiliStatManager statManager; + private PiliStatModel statModel; + private PiliStatModel.GetStatCommonRequest commentReq; + Map where; + String select; + + /** + * 初始化 + * + * @throws Exception + */ + @BeforeEach + public void setUp() throws Exception { + statManager = new PiliStatManager( + Auth.create(TestConfig.piliAccessKey, TestConfig.piliSecretKey), TestConfig.piliHTTPhost); + statModel = new PiliStatModel(); + commentReq = statModel.new GetStatCommonRequest(); + + commentReq.begin = "20060102"; + commentReq.end = "20060102"; + commentReq.g = "month"; + + where = new HashMap<>(); + where.put("hub", new String[]{TestConfig.piliTestHub}); + where.put("area", new String[]{"!cn", "!hk"}); + select = "flow"; + } + + @Test + @Tag("UnitTest") + public void testGetStatUpflow() { + PiliStatModel.GetStatUpflowRequest param = statModel.new GetStatUpflowRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatResponse[] response = statManager.getStatUpflow(param); + System.out.println("statManager.getStatUpflow: success: " + response); + assertNotNull(response); + } catch (QiniuException e) { + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGroupStatUpflow() { + PiliStatModel.GroupStatUpflowRequest param = statModel.new GroupStatUpflowRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatGroupResponse[] response = statManager.groupStatUpflow(param); + System.out.println("statManager.groupStatUpflow: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStatDownflow() { + PiliStatModel.GetStatDownflowRequest param = statModel.new GetStatDownflowRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatResponse[] response = statManager.getStatDownflow(param); + System.out.println("statManager.getStatDownflow: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGroupStatDownflow() { + PiliStatModel.GroupStatDownflowRequest param = statModel.new GroupStatDownflowRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatGroupResponse[] response = statManager.groupStatDownflow(param); + System.out.println("statManager.groupStatDownflow: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStatCodec() { + PiliStatModel.GetStatCodecRequest param = statModel.new GetStatCodecRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatResponse[] response = statManager.getStatCodec(param); + System.out.println("statManager.getStatCodec: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGroupStatCodec() { + PiliStatModel.GroupStatCodecRequest param = statModel.new GroupStatCodecRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatGroupResponse[] response = statManager.groupStatCodec(param); + System.out.println("statManager.groupStatCodec: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStatNrop() { + PiliStatModel.GetStatNropRequest param = statModel.new GetStatNropRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + commentReq.begin = "20210928"; + commentReq.end = "20210930"; + commentReq.g = "hour"; + + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatResponse[] response = statManager.getStatNrop(param); + System.out.println("statManager.getStatNrop: success: " + response); + assertNotNull(response); + } catch (QiniuException e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGroupStatNrop() { + PiliStatModel.GroupStatCodecRequest param = statModel.new GroupStatCodecRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatGroupResponse[] response = statManager.groupStatNrop(param); + System.out.println("statManager.groupStatNrop: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStatCasterRequest() { + PiliStatModel.GetStatCasterRequest param = statModel.new GetStatCasterRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatResponse[] response = statManager.getStatCaster(param); + System.out.println("statManager.getStatCaster: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGroupStatCaster() { + PiliStatModel.GroupStatCasterRequest param = statModel.new GroupStatCasterRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatGroupResponse[] response = statManager.groupStatCaster(param); + System.out.println("statManager.groupStatCaster: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStatPub() { + PiliStatModel.GetStatPubRequest param = statModel.new GetStatPubRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatResponse[] response = statManager.getStatPub(param); + System.out.println("statManager.getStatPub: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGroupStatPub() { + PiliStatModel.GroupStatPubRequest param = statModel.new GroupStatPubRequest(); + param.commonRequest = statModel.new GetStatCommonRequest(); + param.commonRequest.begin = commentReq.begin; + param.commonRequest.end = commentReq.end; + param.commonRequest.g = commentReq.g; + param.where = where; + param.select = select; + try { + PiliStatModel.StatGroupResponse[] response = statManager.groupStatPub(param); + System.out.println("statManager.groupStatPub: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("statManager.groupStatUpflow: response: "); + System.out.println(e); + assertNull(e); + } + } + +} diff --git a/src/test/java/test/com/qiniu/pili/PiliStreamTest.java b/src/test/java/test/com/qiniu/pili/PiliStreamTest.java new file mode 100644 index 00000000..0ffb2ef7 --- /dev/null +++ b/src/test/java/test/com/qiniu/pili/PiliStreamTest.java @@ -0,0 +1,163 @@ +package test.com.qiniu.pili; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import com.qiniu.common.QiniuException; +import com.qiniu.pili.PiliStreamManager; +import com.qiniu.pili.PiliStreamModel; +import com.qiniu.util.Auth; + +import test.com.qiniu.ResCode; +import test.com.qiniu.TestConfig; + +public class PiliStreamTest { + private PiliStreamManager streamManager; + + /** + * 初始化 + * + * @throws Exception + */ + @BeforeEach + public void setUp() throws Exception { + this.streamManager = new PiliStreamManager( + Auth.create(TestConfig.piliAccessKey, TestConfig.piliSecretKey), TestConfig.piliHTTPhost); + } + + @Test + @Tag("UnitTest") + public void testGetHubList() { + try { + PiliStreamModel.GetStreamsListResponse response = streamManager.getStreamsList(TestConfig.piliTestHub, false, "", + 10, ""); + System.out.println("streamManager.getStatUpflow: success: " + response); + assertNotNull(response); + } catch (QiniuException e) { + System.out.println("streamManager.getStatUpflow: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStreamBaseInfo() { + try { + PiliStreamModel.GetStreamBaseInfoResponse response = streamManager.getStreamBaseInfo(TestConfig.piliTestHub, + TestConfig.piliTestStream); + System.out.println("streamManager.getStreamBaseInfo: success: " + response); + assertNotNull(response); + } catch (QiniuException e) { + System.out.println("streamManager.getStreamBaseInfo: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testStreamDisable() { + try { + QiniuException exception = streamManager.streamDisable(TestConfig.piliTestHub, TestConfig.piliTestStream, 0, 0); + if (exception != null) { + System.out.println("streamManager.streamDisable ERROR: " + exception.getMessage()); + } else { + System.out.println("streamManager.streamDisable succeeded."); + } + } catch (Exception e) { + System.out.println("streamManager.streamDisable: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStreamLiveStatus() { + try { + PiliStreamModel.GetStreamLiveStatusResponse response = streamManager.getStreamLiveStatus(TestConfig.piliTestHub, + TestConfig.piliTestStream); + System.out.println("streamManager.getStreamLiveStatus: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("streamManager.getStreamLiveStatus: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testBatchGetStreamLiveStatus() { + String[] strs = { TestConfig.piliTestStream }; + try { + PiliStreamModel.BatchGetStreamLiveStatusResponse response = streamManager + .batchGetStreamLiveStatus(TestConfig.piliTestHub, strs); + System.out.println("streamManager.batchGetStreamLiveStatus: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("streamManager.batchGetStreamLiveStatus: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testGetStreamHistory() { + + try { + PiliStreamModel.GetStreamHistoryResponse response = streamManager.getStreamHistory(0, 0, TestConfig.piliTestHub, + TestConfig.piliTestStream); + System.out.println("streamManager.getStreamHistory: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("streamManager.getStreamHistory: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testStreamSnapshot() { + PiliStreamModel streamModel = new PiliStreamModel(); + PiliStreamModel.StreamSnapshotRequest param = streamModel.new StreamSnapshotRequest(); + param.stream = TestConfig.piliTestStream; + param.hub = TestConfig.piliTestHub; + + try { + PiliStreamModel.StreamSnapshotResponse response = streamManager.streamSnapshot(param); + System.out.println("streamManager.streamSnapshot: success: " + response); + assertNotNull(response); + } catch (Exception e) { + System.out.println("streamManager.streamSnapshot: Error: "); + System.out.println(e); + assertNull(e); + } + } + + @Test + @Tag("UnitTest") + public void testStreamConverts() { + String[] strs = {}; + try { + QiniuException exception = streamManager.streamConverts(TestConfig.piliTestHub, TestConfig.piliTestStream, strs); + if (exception != null) { + System.out.println("streamManager.streamConverts ERROR: " + exception.getMessage()); + } else { + System.out.println("streamManager.streamConverts succeeded."); + } + } catch (Exception e) { + System.out.println("streamManager.streamConverts: Error: "); + System.out.println(e); + assertNull(e); + } + } +}