Browse Source

Merge branch 'dev_trial' of ssh://gitea.free-sun.vip:2022/free-sun/FS-IOT into dev_trial

release_0.0.2
wenlele 3 years ago
parent
commit
28e2133a7c
  1. 110
      code/VideoAccess-VCMP/api/app/lib/controllers/camera/create.js
  2. 32
      code/VideoAccess-VCMP/api/app/lib/controllers/camera/index.js
  3. 9
      code/VideoAccess-VCMP/api/app/lib/index.js
  4. 17
      code/VideoAccess-VCMP/api/app/lib/models/camera.js
  5. 61
      code/VideoAccess-VCMP/api/app/lib/models/secret_yingshi.js
  6. 14
      code/VideoAccess-VCMP/api/app/lib/routes/camera/index.js
  7. 4
      code/VideoAccess-VCMP/api/app/lib/service/socket.js
  8. 2
      code/VideoAccess-VCMP/api/app/lib/utils/index.js
  9. 47
      code/VideoAccess-VCMP/api/app/lib/utils/rtmp2others.js
  10. 49
      code/VideoAccess-VCMP/api/app/lib/utils/token4yingshi.js
  11. 9
      code/VideoAccess-VCMP/api/config.js
  12. 66
      code/VideoAccess-VCMP/api/sequelize-automate.config.js

110
code/VideoAccess-VCMP/api/app/lib/controllers/camera/create.js

@ -1,30 +1,129 @@
'use strict'; 'use strict';
const moment = require('moment')
async function createYingshi (ctx) { async function createYingshi (ctx) {
let errMsg = '添加萤石摄像头失败'
try { try {
const { models } = ctx.fs.dc const { models } = ctx.fs.dc
const { userId, token } = ctx.fs.api const { userId, token } = ctx.fs.api
const { utils: { token4yingshi } } = ctx.app.fs
const {
id, name, cloudControl, highDefinition, memoryCard,
voice, kindId, abilityId, rtmp, serialNo, longitude, latitude,
} = ctx.request.body;
const serialNo_ = String(serialNo).toUpperCase()
const secretRes = await models.SecretYingshi.findAll()
let cameraBeloneSecretId = null
for (let s of secretRes) {
const tokenYingshi = await token4yingshi(s.dataValues)
// 检测设备所属
const cameraState = await ctx.app.fs.yingshiRequest.post('lapp/device/info', {
query: {
accessToken: tokenYingshi,
deviceSerial: serialNo_
}
})
if (cameraState.code == 200) {
cameraBeloneSecretId = s.dataValues.id
break
}
}
const { id, name, cloudControl, highDefinition, memoryCard, if (!cameraBeloneSecretId) {
voice, kindId, abilityId, rtmp, } = ctx.request.body errMsg = '请联系管理员核验或新增萤石云权限'
throw errMsg
}
let storageData = { let storageData = {
type: 'yingshi', name, cloudControl, highDefinition, memoryCard, type: 'yingshi', name, cloudControl, highDefinition, memoryCard,
voice, longitude, latitude, kindId, abilityId, rtmp, voice, longitude, latitude, kindId, abilityId, rtmp,
yingshiSecretId: cameraBeloneSecretId
} }
if (id) { if (id) {
await models.Camera.update(storageData, {
where: {
id,
}
})
} else {
storageData.createTime = moment().format() storageData.createTime = moment().format()
storageData.createUserId = userId storageData.createUserId = userId
storageData.forbidden = false
await models.Camera.create(storageData)
}
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: errMsg
}
}
}
async function getNvrSteam (ctx) {
try {
const { models } = ctx.fs.dc
const { userId, token } = ctx.fs.api
ctx.status = 200;
ctx.body = {}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function createNvrCamera (ctx) {
try {
const { models } = ctx.fs.dc
const { userId, token } = ctx.fs.api
ctx.status = 200;
ctx.body = {}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function createIpcCamera (ctx) {
try {
const { models } = ctx.fs.dc
const { userId, token } = ctx.fs.api
const { utils: { token4yingshi } } = ctx.app.fs
const {
id, name, cloudControl, memoryCard,
voice, longitude, latitude, rtmp,
serialNo, kindId, abilityId,
} = ctx.request.body;
let storageData = {
type: 'ipc', name, cloudControl, memoryCard,
voice, longitude, latitude, rtmp,
serialNo, kindId, abilityId,
}
if (id) {
await models.Camera.update(storageData, { await models.Camera.update(storageData, {
where: { where: {
id, id,
} }
}) })
} else { } else {
storageData.createTime = moment().format()
storageData.createUserId = userId
storageData.forbidden = false
await models.Camera.create(storageData) await models.Camera.create(storageData)
} }
ctx.status = 204; ctx.status = 204;
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
@ -34,5 +133,8 @@ async function createYingshi (ctx) {
} }
module.exports = { module.exports = {
createYingshi,
getNvrSteam,
createNvrCamera,
createIpcCamera,
}; };

32
code/VideoAccess-VCMP/api/app/lib/controllers/camera/index.js

@ -236,6 +236,36 @@ async function del (ctx) {
} }
} }
async function getAbility (ctx) {
try {
const { models } = ctx.fs.dc;
const abilityRes = await models.CameraAbility.findAll()
ctx.status = 200;
ctx.body = abilityRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function getKind (ctx) {
try {
const { models } = ctx.fs.dc;
const kindRes = await models.CameraKind.findAll()
ctx.status = 200;
ctx.body = kindRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
module.exports = { module.exports = {
getCameraProject, getCameraProject,
getCamera, getCamera,
@ -243,4 +273,6 @@ module.exports = {
detail, detail,
banned, banned,
del, del,
getAbility,
getKind,
}; };

9
code/VideoAccess-VCMP/api/app/lib/index.js

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const routes = require('./routes');
const utils = require('./utils') const utils = require('./utils')
const routes = require('./routes');
const redisConnect = require('./service/redis') const redisConnect = require('./service/redis')
const socketConect = require('./service/socket') const socketConect = require('./service/socket')
const paasRequest = require('./service/paasRequest'); const paasRequest = require('./service/paasRequest');
@ -16,9 +16,6 @@ module.exports.entry = function (app, router, opts) {
app.fs.api.authAttr = app.fs.api.authAttr || {}; app.fs.api.authAttr = app.fs.api.authAttr || {};
app.fs.api.logAttr = app.fs.api.logAttr || {}; app.fs.api.logAttr = app.fs.api.logAttr || {};
// 工具类函数
utils(app, opts)
// 顺序固定 ↓ // 顺序固定 ↓
redisConnect(app, opts) redisConnect(app, opts)
socketConect(app, opts) socketConect(app, opts)
@ -26,6 +23,9 @@ module.exports.entry = function (app, router, opts) {
// 实例其他平台请求方法 // 实例其他平台请求方法
paasRequest(app, opts) paasRequest(app, opts)
// 工具类函数
utils(app, opts)
// 鉴权中间件 // 鉴权中间件
router.use(authenticator(app, opts)); router.use(authenticator(app, opts));
@ -41,5 +41,6 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
require('./models/camera')(dc); require('./models/camera')(dc);
require('./models/nvr')(dc); require('./models/nvr')(dc);
require('./models/vender')(dc); require('./models/vender')(dc);
require('./models/secret_yingshi')(dc);
require('./models/ax_project')(dc); require('./models/ax_project')(dc);
}; };

17
code/VideoAccess-VCMP/api/app/lib/models/camera.js

@ -157,7 +157,7 @@ module.exports = dc => {
forbidden: { forbidden: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: false,
comment: "是否禁用", comment: "是否禁用",
primaryKey: false, primaryKey: false,
field: "forbidden", field: "forbidden",
@ -184,7 +184,7 @@ module.exports = dc => {
delete: { delete: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: false,
comment: "是否彻底删除", comment: "是否彻底删除",
primaryKey: false, primaryKey: false,
field: "delete", field: "delete",
@ -246,6 +246,19 @@ module.exports = dc => {
key: "id", key: "id",
model: "cameraAbility" model: "cameraAbility"
} }
},
yingshiSecretId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "yingshi_secret_id",
autoIncrement: false,
references: {
key: "id",
model: "secretYingshi"
}
} }
}, { }, {
tableName: "camera", tableName: "camera",

61
code/VideoAccess-VCMP/api/app/lib/models/secret_yingshi.js

@ -0,0 +1,61 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const SecretYingshi = sequelize.define("secretYingshi", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "secret_yingshi_id_uindex"
},
key: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "key",
autoIncrement: false
},
secret: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "secret",
autoIncrement: false
},
token: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "token",
autoIncrement: false
},
expire: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "expire",
autoIncrement: false
}
}, {
tableName: "secret_yingshi",
comment: "",
indexes: []
});
dc.models.SecretYingshi = SecretYingshi;
return SecretYingshi;
};

14
code/VideoAccess-VCMP/api/app/lib/routes/camera/index.js

@ -1,8 +1,16 @@
'use strict'; 'use strict';
const camera = require('../../controllers/camera'); const camera = require('../../controllers/camera');
const cameraCreate = require('../../controllers/camera/create')
module.exports = function (app, router, opts) { module.exports = function (app, router, opts) {
// 摄像头创建
app.fs.api.logAttr['POST/camera/create/yingshi'] = { content: '创建萤石摄像头', visible: false };
router.post('/camera/create/yingshi', cameraCreate.createYingshi);
// 摄像头创建 END
app.fs.api.logAttr['GET/camera/project'] = { content: '获取摄像头列表及项目绑定信息', visible: false }; app.fs.api.logAttr['GET/camera/project'] = { content: '获取摄像头列表及项目绑定信息', visible: false };
router.get('/camera/project', camera.getCameraProject); router.get('/camera/project', camera.getCameraProject);
@ -20,4 +28,10 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['DEL/camera'] = { content: '删除摄像头', visible: false }; app.fs.api.logAttr['DEL/camera'] = { content: '删除摄像头', visible: false };
router.delete('/camera', camera.del); router.delete('/camera', camera.del);
app.fs.api.logAttr['GET/camera/ability'] = { content: '获取摄像头能力列表', visible: false };
router.get('/camera/ability', camera.getAbility);
app.fs.api.logAttr['GET/camera/kind'] = { content: '获取摄像头种类列表', visible: false };
router.get('/camera/kind', camera.getKind);
}; };

4
code/VideoAccess-VCMP/api/app/lib/service/socket.js

@ -3,9 +3,9 @@
module.exports = async function factory (app, opts) { module.exports = async function factory (app, opts) {
app.socket.on('connection', async (socket) => { app.socket.on('connection', async (socket) => {
console.info('WEB_SOCKET ' + socket.handshake.query.token + ' 已连接:' + socket.id); // console.info('WEB_SOCKET ' + socket.handshake.query.token + ' 已连接:' + socket.id);
socket.on('disconnecting', async (reason) => { socket.on('disconnecting', async (reason) => {
console.info('WEB_SOCKET ' + socket.handshake.query.token + ' 已断开连接:' + reason); // console.info('WEB_SOCKET ' + socket.handshake.query.token + ' 已断开连接:' + reason);
}) })
}) })

2
code/VideoAccess-VCMP/api/app/lib/utils/index.js

@ -6,7 +6,7 @@ const fs = require('fs');
module.exports = async function (app, opts) { module.exports = async function (app, opts) {
fs.readdirSync(__dirname).forEach((filename) => { fs.readdirSync(__dirname).forEach((filename) => {
if (filename != 'index.js') { if (filename != 'index.js') {
const utils = require(`./${filename}`) const utils = require(`./${filename}`)(app, opts)
app.fs.utils = { app.fs.utils = {
...app.fs.utils, ...app.fs.utils,
...utils, ...utils,

47
code/VideoAccess-VCMP/api/app/lib/utils/rtmp2others.js

@ -1,31 +1,34 @@
'use strict'; 'use strict';
async function rtmp2others (rtmp) {
return { module.exports = function (app, opts) {
liveUrl: { async function rtmp2others (rtmp) {
hd: {// 高清
rtmp: 'xx', return {
hls: 'xx', liveUrl: {// 直播
flv: 'xx', hd: {// 高清
ezopen: 'xx', rtmp: 'xx',
onvif: 'xx', hls: 'xx',
flv: 'xx',
ezopen: 'xx',
onvif: 'xx',
},
sd: {// 标清
rtmp: 'xx',
hls: 'xx',
flv: 'xx',
ezopen: 'xx',
onvif: 'xx',
}
}, },
sd: {// 标清 replayUrl: {// 回放
rtmp: 'xx', cloud: 'xx',
hls: 'xx', local: 'xx',
flv: 'xx',
ezopen: 'xx',
onvif: 'xx',
} }
},
replayUrl: {
cloud: 'xx',
local: 'xx',
} }
} }
}
module.exports = { return {
rtmp2others, rtmp2others
}
} }

49
code/VideoAccess-VCMP/api/app/lib/utils/token4yingshi.js

@ -0,0 +1,49 @@
'use strict';
const moment = require('moment')
module.exports = function (app, opts) {
async function token4yingshi ({ key, secret, token, expire } = {}) {
const { models } = app.fs.dc
if (!key || !secret) {
throw '参数 { key, secret } 缺一不可'
}
if (token && expire && moment().isBefore(moment(expire))) {
return token
} else {
const secretRes = await models.SecretYingshi.findOne({
where: { key, secret }
})
if (secretRes && secretRes.expire && secretRes.token && moment().isBefore(moment(secretRes.expire))) {
return secretRes.token
}
}
// 也可以做基于 redis 的缓存
const tokenRes = await app.fs.yingshiRequest.post(`lapp/token/get`, {
query: {
appKey: key,
appSecret: secret
}
})
if (tokenRes.code == 200) {
const { accessToken, expireTime } = tokenRes.data
await models.SecretYingshi.update({
token: accessToken,
expire: expireTime
}, {
where: {
key, secret
}
})
return accessToken
} else {
throw tokenRes
}
}
return {
token4yingshi
}
}

9
code/VideoAccess-VCMP/api/config.js

@ -32,6 +32,7 @@ const IOT_AUTH_API = process.env.IOT_AUTH_API || flags.iotAuthApi;
const AXY_API_URL = process.env.AXY_API_URL || flags.axyApiUrl; const AXY_API_URL = process.env.AXY_API_URL || flags.axyApiUrl;
const GOD_URL = process.env.GOD_URL || flags.godUrl || 'https://restapi.amap.com/v3'; const GOD_URL = process.env.GOD_URL || flags.godUrl || 'https://restapi.amap.com/v3';
const GOD_KEY = process.env.GOD_KEY || flags.godKey; const GOD_KEY = process.env.GOD_KEY || flags.godKey;
const YINGSHI_URL = process.env.YINGSHI_URL || flags.yingshiUrl || 'https://open.ys7.com/api';
if (!IOT_VIDEO_ACCESS_DB || !IOTA_REDIS_SERVER_HOST || !IOTA_REDIS_SERVER_PORT || !GOD_KEY) { if (!IOT_VIDEO_ACCESS_DB || !IOTA_REDIS_SERVER_HOST || !IOTA_REDIS_SERVER_PORT || !GOD_KEY) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
@ -76,6 +77,14 @@ const product = {
key: GOD_KEY key: GOD_KEY
} }
} }
}, {
name: 'yingshiRequest',
root: YINGSHI_URL,
params: {
query: {
key: GOD_KEY
}
}
},] },]
} }
} }

66
code/VideoAccess-VCMP/api/sequelize-automate.config.js

@ -1,35 +1,35 @@
module.exports = { module.exports = {
// 数据库配置 与 sequelize 相同 // 数据库配置 与 sequelize 相同
dbOptions: { dbOptions: {
database: 'video_access', database: 'video_access',
username: 'postgres', username: 'postgres',
password: '123', password: '123',
dialect: 'postgres', dialect: 'postgres',
host: '10.8.30.32', host: '10.8.30.32',
port: 5432, port: 5432,
define: { define: {
underscored: false, underscored: false,
freezeTableName: false, freezeTableName: false,
charset: 'utf8mb4', charset: 'utf8mb4',
timezone: '+00: 00', timezone: '+00: 00',
dialectOptions: { dialectOptions: {
collate: 'utf8_general_ci', collate: 'utf8_general_ci',
}, },
timestamps: false, timestamps: false,
}, },
}, },
options: { options: {
type: 'freesun', // 指定 models 代码风格 type: 'freesun', // 指定 models 代码风格
camelCase: true, // Models 文件中代码是否使用驼峰命名 camelCase: true, // Models 文件中代码是否使用驼峰命名
modalNameSuffix: false, // 模型名称是否带 ‘Model’ 后缀 modalNameSuffix: false, // 模型名称是否带 ‘Model’ 后缀
fileNameCamelCase: false, // Model 文件名是否使用驼峰法命名,默认文件名会使用表名,如 `user_post.js`;如果为 true,则文件名为 `userPost.js` fileNameCamelCase: false, // Model 文件名是否使用驼峰法命名,默认文件名会使用表名,如 `user_post.js`;如果为 true,则文件名为 `userPost.js`
dir: './app/lib/models', // 指定输出 models 文件的目录 dir: './app/lib/models', // 指定输出 models 文件的目录
typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义 typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义
emptyDir: true, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir` emptyDir: false, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir`
tables: null, // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性 tables: ['secret_yingshi'], // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性
skipTables: [], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性 skipTables: [], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性
tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中 tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中
ignorePrefix: [], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面 ignorePrefix: [], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面
attrLength: false, // 在生成模型的字段中 是否生成 如 var(128)这种格式,公司一般使用 String ,则配置为 false attrLength: false, // 在生成模型的字段中 是否生成 如 var(128)这种格式,公司一般使用 String ,则配置为 false
}, },
} }
Loading…
Cancel
Save