之前在做摄像头调试,用nestjs 写的一些测试案例,不完善
qiniu.controller.ts
import { Body, Controller, Post, Get, Query } from '@nestjs/common';
import { QiniuService } from './qiniu.service';
@Controller('qiniu')
export class QiniuController {
constructor(private qiniuService: QiniuService) { }
@Post('/ptz')
// cmd: left(向左), right(向右), up(向上), down(向下), leftup(左上),
// rightup(右上), leftdown(左下), rightdown(右下),
// zoomin(放大), zoomout(缩小),stop(停止PTZ操作)
ptzControll(@Body() { cmd, speed = 5 }) {
return this.qiniuService.ptzControll(cmd, speed)
}
}
qiniu.service.ts
import { Injectable } from '@nestjs/common';
import axios from 'axios';
import { HmacSHA1, enc } from 'crypto-js'
@Injectable()
export class QiniuService {
// key
private ACCESS_KEY = '自己的accesskey'
private SECRET_KEY = '自己的secretkey'
private namespaceId = 'bas-test'
private deviceId = '31011500991320032187'
private host = 'qvs.qiniuapi.com'
// 生成鉴权字符串
getAuthorization(method = 'POST', url = '', body = '') {
console.log(method, url, body)
const data = method + " " + url + "\nHost: " + this.host + "\nContent-Type: " + "application/json" + "\n\n" + body
const encodedSign = enc.Base64url.stringify((HmacSHA1(data, this.SECRET_KEY)));
const authorization = 'Qiniu ' + this.ACCESS_KEY + ':' + encodedSign
return authorization
}
async ptzControll(cmd = 'left', speed = 2) {
const body = {
cmd,
speed,
chId: '',
}
const url = `/v1/namespaces/${this.namespaceId}/devices/${this.deviceId}/ptz`
const austr = this.getAuthorization('POST', url, JSON.stringify(body))
const info = { success: false, msg: '', data: {} }
try {
const { data } = await axios({
method: 'POST',
headers: {
'authorization': austr,
'content-type': 'application/json'
},
data: body,
url: `http://${this.host}${url}`,
})
info.success = true
info.data = data
info.msg = '成功'
} catch (err) {
info.success = false
info.data = err
info.msg = '失败!'
}
return info;
}
}
baidu.controller.ts
import { Body, Controller, Get, HttpCode, Post, Query } from '@nestjs/common';
import { BaiduService } from './baidu.service';
@Controller('baidu')
export class BaiduController {
constructor(private baiduService: BaiduService) { }
@Get('list')
getAllDevices(@Query() { pageNo = 1, pageSize = 10 }) {
return this.baiduService.getAllDevices(pageNo, pageSize)
}
@Get('channel')
getChannel(@Query('deviceId') deviceId) {
return this.baiduService.getChannel(deviceId)
}
@Get('play')
getPlayUrl(@Query('channelId') channelId) {
return this.baiduService.getPlayUrl(channelId)
}
@Post('au')
getAu(@Body() { method, url, requestHeader, query, x_bce_date }) {
return this.baiduService.getAuthorization(method, url, query, x_bce_date, requestHeader)
}
@Post('ptz')
@HttpCode(200)
ptzControl(@Body() { channelId, cmd, speed }) {
return this.baiduService.ptzControl(channelId, cmd, speed)
}
@Post('fi')
@HttpCode(200)
fiControl(@Body() { channelId, cmd, speed }) {
return this.baiduService.fiControl(channelId, cmd, speed)
}
@Get('space')
getSpace(@Query('id') id) {
return this.baiduService.getSpaceInfo(id)
}
@Get('video')
videoList(@Query() {start,end}) {
return this.baiduService.videoList(start,end)
}
}
baidu.service.ts
import { Injectable } from '@nestjs/common';
import axios from 'axios';
import { HmacSHA256, enc } from 'crypto-js'
import * as dayjs from 'dayjs'
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
@Injectable()
export class BaiduService {
private AK = '自己的Accesskey'
private SK = '自己的SecretKey'
private host = 'evs.bj.baidubce.com'
private spaceId = '1006122'
// url 编码
UriEncodeExceptSlash(str) {
const result = encodeURIComponent(str).replace(/%2F/g, '/')
return result
}
// query-string 解析
getCanonicalQueryString(str) {
if (!str) return ''
const list = str.split('&')
if (!list.length) return ''
// 键值对编码
const keyVArr = list.map(v => {
const arr = v.split('=')
if (!arr[1]) return encodeURIComponent(v) + '='
const key = arr[0]
const value = arr[1]
return encodeURIComponent(key) + '=' + encodeURIComponent(value)
})
// 根据ASII码排序
const sortArr = keyVArr.sort((a: string, b: string) => {
let as1 = a.charCodeAt(0)
let as2 = b.charCodeAt(0)
return as1 - as2
})
// & 拼接
return sortArr.join('&')
}
getAuthorization(httpMethod = 'POST', CanonicalURI = '', CanonicalQueryString = '', x_bce_date, requestHeader) {
// 签名有效期 单位为 s
const expirationPeriodInSeconds = 1800
// 前缀字符串
const authStringPrefix = `bce-auth-v1/${this.AK}/${x_bce_date}/${expirationPeriodInSeconds}`
// 字符编码
CanonicalURI = this.UriEncodeExceptSlash(CanonicalURI)
// 字符处理
CanonicalQueryString = this.getCanonicalQueryString(CanonicalQueryString)
// 每项header编码
const headerArr: string[] = []
for (let key in requestHeader) {
const headerName = key.toLowerCase().trim()
const headerVal = encodeURIComponent(requestHeader[key].trim())
headerArr.push(headerName + ':' + headerVal)
}
const resArr = headerArr.sort((a, b) => {
// 字典序排序
return a.charCodeAt(0) - b.charCodeAt(0)
})
const CanonicalHeaders = resArr.join('\n')
// 验证请求头数组
const signedArr = resArr.map(v => {
return v.split(':')[0].trim()
})
// 认证字符串
const signedHeaders = signedArr.join(';')
// console.log('signedHeaders: ' + signedHeaders)
const CanonicalRequest = httpMethod + "\n" + CanonicalURI + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders
// console.log('CanonicalRequest: ' + CanonicalRequest)
// 派生签名密钥
const SigningKey = enc.Hex.stringify(HmacSHA256(authStringPrefix, this.SK))
// console.log(SigningKey)
// 签名
const Signature = enc.Hex.stringify(HmacSHA256(CanonicalRequest, SigningKey))
// console.log('Signature:' + Signature)
// 认证字符串
let authorization = `bce-auth-v1/${this.AK}/${x_bce_date}/${expirationPeriodInSeconds}/${signedHeaders}/${Signature}`
return authorization
}
// 获取所有摄像机
async getAllDevices(pageNo, pageSize) {
let URI = `/v1/device`
let query = `spaceId=${this.spaceId}&pageNo=${pageNo}&pageSize=${pageSize}`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data } = await axios({
method: 'GET',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('GET', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return data
}
// 获取频道
async getChannel(deviceId) {
let URI = `/v1/device/channel`
let query = `deviceId=${deviceId}`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data } = await axios({
method: 'GET',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('GET', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return data
}
// 获取GB28181设备通道播流链接
async getPlayUrl(channelId) {
if (!channelId) return ''
let URI = `/v1/device/channel/${channelId}/signedUrl`
let query = `protocol=webrtc`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: playUrl } = await axios({
method: 'GET',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('GET', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return {
success: true,
data: playUrl,
msg: 'OK'
}
}
// ptz 控制
async ptzControl(channelId, ptzCommand, speed) {
let URI = `/v1/device/channel/${channelId}`
let query = `ptz&ptzCommand=${ptzCommand}&speed=${speed}`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: result } = await axios({
method: 'PUT',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('PUT', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return {
success: true,
msg: result
}
}
// 光圈与变焦
async fiControl(channelId, fiCommand, speed) {
let URI = `/v1/device/channel/${channelId}`
let query = `fi&fiCommand=${fiCommand}&speed=${speed}`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: result } = await axios({
method: 'PUT',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('PUT', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return {
success: true,
msg: result
}
}
// 查询空间
async getSpaceInfo(spaceId) {
if (!spaceId) return ''
let URI = `/v1/space/${spaceId}`
let query = ``
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: res } = await axios({
method: 'GET',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('GET', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return res
}
async videoList(start='2023-09-18',end='2023-09-18') {
// @ts-ignore
const begin = parseInt(new Date(start + ' 09:00').getTime() / 1000)
// @ts-ignore
const endTime = parseInt(new Date(end + ' 18:00').getTime() / 1000)
let URI = `/v1/device/channel/1059306/localRecording`
let query = `begin=${begin}&end=${endTime}&isSync=true`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: res } = await axios({
method: 'GET',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('GET', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return res
}
async cloudVideoList() {
// @ts-ignore
const begin = parseInt(new Date('2023-08-02 17:00').getTime() / 1000)
// @ts-ignore
const end = parseInt(new Date('2023-08-06 19:00').getTime() / 1000)
let URI = `/v1/device/channel/1059306/recording`
let query = `begin=${begin}&end=${end}&pageNo=1&pageSize=10`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: res } = await axios({
method: 'GET',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('GET', URI, query, x_bce_date, requestHeader),
...requestHeader,
}
})
return res
}
async download(key) {
let URI = `/v1/device/channel/1059306/localRecording`
let query = `download`
// 生成签名的时间
// @ts-ignore
const x_bce_date = dayjs().utc().format()
const requestHeader = {
'host': this.host,
'content-type': 'application/json;charset=utf-8',
'x-bce-date': x_bce_date
}
const { data: res } = await axios({
method: 'POST',
url: `http://${this.host}${URI}?${query}`,
headers: {
'authorization': this.getAuthorization('POST', URI, query, x_bce_date, requestHeader),
...requestHeader,
},
data: {
downloadKey: key
}
})
return res
}
}