/**
|
* MQTT服务模块
|
* 处理MQTT消息的接收和发送,包括设备管理、人员管理、权限管理等功能
|
*/
|
import common from "../../dxmodules/dxCommon.js";
|
import config from "../../dxmodules/dxConfig.js";
|
import logger from "../../dxmodules/dxLogger.js";
|
import ota from "../../dxmodules/dxOta.js";
|
import std from "../../dxmodules/dxStd.js";
|
import dxMap from '../../dxmodules/dxMap.js'
|
import driver from "../driver.js";
|
import configService from "./configService.js";
|
import sqliteService from "./sqliteService.js";
|
import sqlite from "../../dxmodules/dxSqlite.js";
|
import utils from '../common/utils/utils.js'
|
|
const mqttService = {}
|
let map = dxMap.get("faceAccesss")
|
|
/**
|
* 接收MQTT消息并处理
|
* @param {object} data - MQTT消息数据
|
* @param {string} data.topic - 消息主题
|
* @param {string} data.payload - 消息载荷
|
*/
|
mqttService.receiveMsg = function (data) {
|
// {"topic":"ddddd","payload":"{\n \"msg\": \"world\"\n}"}
|
logger.info('[mqttService] receiveMsg :' + JSON.stringify(data.topic))
|
// 提取主题的最后部分作为函数名
|
if (typeof mqttService[data.topic.match(/[^/]+$/)[0]] == 'function') {
|
mqttService[data.topic.match(/[^/]+$/)[0]](data)
|
} else {
|
logger.error("未实现的topic", data.topic)
|
}
|
}
|
|
// =================================权限增删改查=================================
|
/**
|
* 添加权限
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.insertPermission = function (event) {
|
try {
|
logger.info('[mqttService] 接收到insertPermission命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.insertPermissionAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] insertPermission失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] insertPermission成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] insertPermission error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 添加权限通用协议格式
|
* @param {array} data - 权限数据数组
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.insertPermissionAgreement = function (data) {
|
let permissions = []
|
for (let i = 0; i < data.length; i++) {
|
const permission = data[i];
|
if (!permission.permissionId || !permission.userId) {
|
return "id or userId cannot be empty"
|
}
|
if (!permission.extra) {
|
permission.extra = ""
|
}
|
if (!permission.time) {
|
return "time and type cannot be empty"
|
}
|
if (permission.time.type != 0 && permission.time.type != 1 && permission.time.type != 2 && permission.time.type != 3) {
|
return "time type is not supported"
|
}
|
let record = {}
|
record.permissionId = permission.permissionId
|
record.userId = permission.userId
|
record.door = isEmpty(permission.index) ? 0 : permission.index
|
record.extra = isEmpty(permission.extra) ? JSON.stringify({}) : JSON.stringify(permission.extra)
|
record.timeType = permission.time.type
|
record.beginTime = permission.time.type == 0 ? 0 : permission.time.range.beginTime
|
record.endTime = permission.time.type == 0 ? 0 : permission.time.range.endTime
|
record.repeatBeginTime = permission.time.type != 2 ? 0 : permission.time.beginTime
|
record.repeatEndTime = permission.time.type != 2 ? 0 : permission.time.endTime
|
record.period = permission.time.type != 3 ? 0 : JSON.stringify(permission.time.weekPeriodTime)
|
let ret = sqliteService.d1_permission.save(record)
|
if (ret != 0) {
|
// 如果保存失败,尝试删除后重新保存
|
sqliteService.d1_permission.deleteByPermissionId(record.permissionId)
|
ret = sqliteService.d1_permission.save(record)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
} else {
|
continue
|
}
|
}
|
}
|
return true
|
}
|
|
/**
|
* 查询权限
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getPermission = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getPermission命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data))
|
let res = this.getPermissionAgreement(data)
|
logger.info('[mqttService] 查询结果:', JSON.stringify(res))
|
return reply(event, res)
|
} catch (error) {
|
logger.error('[mqttService] getPermission error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 查询权限通用协议格式
|
* @param {object} data - 查询参数
|
* @returns {object} 查询结果
|
*/
|
mqttService.getPermissionAgreement = function (data) {
|
try {
|
// 确保data参数不为undefined
|
data = data || {}
|
data.page = isEmpty(data.page) ? 0 : data.page
|
data.size = isEmpty(data.size) ? 10 : data.size
|
let totalCount = sqliteService.d1_permission.count(data)
|
let permissions = sqliteService.d1_permission.findAll(data)
|
// 构建返回结果
|
let content = permissions.map(permission => ({
|
permissionId: permission.permissionId,
|
userId: permission.userId,
|
extra: JSON.parse(permission.extra ? permission.extra : "{}"),
|
time: {
|
type: permission.timeType,
|
beginTime: permission.timeType != 2 ? undefined : permission.repeatBeginTime,
|
endTime: permission.timeType != 2 ? undefined : permission.repeatEndTime,
|
range: permission.timeType === 0 ? undefined : { beginTime: permission.beginTime, endTime: permission.endTime },
|
weekPeriodTime: permission.timeType != 3 ? undefined : JSON.parse(permission.period)
|
}
|
}))
|
return {
|
content: content,
|
page: data.page,
|
size: data.size,
|
total: totalCount,
|
totalPage: Math.ceil(totalCount / data.size),
|
count: content.length
|
}
|
} catch (error) {
|
logger.error('[mqttService] getPermissionAgreement error:', error)
|
throw error
|
}
|
}
|
|
/**
|
* 删除权限
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.delPermission = function (event) {
|
try {
|
logger.info('[mqttService] 接收到delPermission命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.delPermissionAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] delPermission失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] delPermission成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] delPermission error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 删除权限通用协议格式
|
* @param {object} data - 删除参数
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.delPermissionAgreement = function (data) {
|
if (data.permissionIds && data.permissionIds.length > 0) {
|
let ret = sqliteService.d1_permission.deleteByPermissionIdInBatch(data.permissionIds)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
}
|
}
|
if (data.userIds && data.userIds.length > 0) {
|
let ret = sqliteService.d1_permission.deleteByUserIdInBatch(data.userIds)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
}
|
}
|
return true
|
}
|
|
/**
|
* 清空权限
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.clearPermission = function (event) {
|
try {
|
logger.info('[mqttService] 接收到clearPermission命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let ret = sqliteService.d1_permission.deleteAll()
|
if (ret == 0) {
|
logger.info('[mqttService] clearPermission成功')
|
return reply(event)
|
} else {
|
logger.error('[mqttService] clearPermission失败:', "sql error ret:" + ret)
|
return reply(event, "sql error ret:" + ret, CODE.E_100)
|
}
|
} catch (error) {
|
logger.error('[mqttService] clearPermission error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
|
// =================================人员增删改查=================================
|
/**
|
* 添加人员
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.insertUser = function (event) {
|
try {
|
logger.info('[mqttService] 接收到insertUser命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : []
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.insertUserAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] insertUser失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] insertUser成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] insertUser error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 添加人员通用协议格式
|
* @param {array} data - 人员数据数组
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.insertUserAgreement = function (data) {
|
let persons = []
|
for (let i = 0; i < data.length; i++) {
|
const person = data[i];
|
// 严格检查数据格式
|
if (!person.userId || !person.name || person.type === undefined || !person.idCard) {
|
return "数据格式错误,缺少必要字段(userId、name、type、idCard)"
|
}
|
// 检查type字段类型
|
if (typeof person.type !== 'number') {
|
return "数据格式错误,type字段必须是数字"
|
}
|
// 检查type字段值范围
|
if (person.type < 0 || person.type > 1) {
|
return "数据格式错误,type字段值必须在0-1之间"
|
}
|
let record = {}
|
record.userId = person.userId
|
record.name = person.name
|
// 处理人员类型字段和身份证号
|
let extra = {}
|
extra.type = person.type
|
extra.idCard = person.idCard
|
record.extra = JSON.stringify(extra)
|
persons.push(record)
|
|
// 处理人脸信息
|
if (person.face) {
|
try {
|
logger.info('[mqttService] 开始处理人脸信息:', person.userId)
|
|
let faceFilePath = person.face
|
|
// 检查是否是base64编码的图片数据
|
if (person.face.startsWith('data:image/')) {
|
logger.info('[mqttService] 检测到base64编码的图片数据')
|
// 提取base64数据
|
let base64Data = person.face.split(',')[1]
|
// 创建临时文件
|
faceFilePath = '/app/data/user/temp_face_' + person.userId + '.jpg'
|
std.ensurePathExists(faceFilePath)
|
// 将base64数据转换为文件
|
common.base64_2binfile(faceFilePath, base64Data)
|
logger.info('[mqttService] 已将base64数据保存为文件:', faceFilePath)
|
} else {
|
return "数据格式错误,face字段必须是base64编码的图片数据"
|
}
|
|
// 检查文件是否存在
|
let fileExists = common.systemWithRes(`test -e "${faceFilePath}" && echo "OK" || echo "NO"`, 2)
|
logger.info('[mqttService] 人脸图片文件存在:', fileExists.includes('OK'))
|
|
if (fileExists.includes('OK')) {
|
// 注册人脸
|
logger.info('[mqttService] 开始注册人脸:', person.userId)
|
let ret = driver.face.registerFaceByPicFile(person.userId, faceFilePath)
|
logger.info('[mqttService] 注册人脸结果:', ret)
|
|
if (ret == 0) {
|
// 注册成功后移动图片到用户目录
|
let src = "/app/data/user/" + person.userId + "/register.jpg"
|
std.ensurePathExists(src)
|
logger.info('[mqttService] 移动人脸图片到用户目录:', faceFilePath, '->', src)
|
common.systemBrief('mv ' + faceFilePath + " " + src)
|
|
// 保存人脸凭证
|
logger.info('[mqttService] 保存人脸凭证:', person.userId)
|
let voucherRet = sqliteService.d1_voucher.save({
|
keyId: std.genRandomStr(32),
|
type: "300",
|
code: src,
|
userId: person.userId,
|
extra: JSON.stringify({ faceType: 0 })
|
});
|
logger.info('[mqttService] 保存人脸凭证结果:', voucherRet)
|
} else {
|
logger.error('[mqttService] 注册人脸失败,返回码:', ret)
|
}
|
} else {
|
logger.error('[mqttService] 人脸图片文件不存在:', faceFilePath)
|
}
|
} catch (error) {
|
logger.error('[mqttService] 处理人脸信息错误:', error)
|
return "处理人脸信息错误: " + error.message
|
} finally {
|
logger.info('[mqttService] 人脸信息处理完成:', person.userId)
|
}
|
}
|
}
|
let ret = sqliteService.d1_person.saveAll(persons)
|
if (ret != 0) {
|
//失败了 把这些人全都删除后在新增一下
|
let userIds = persons.map(obj => obj.userId);
|
sqliteService.d1_person.deleteByUserIdInBatch(userIds)
|
//重新新增
|
let ret = sqliteService.d1_person.saveAll(persons)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
}
|
}
|
|
// 为用户添加对应权限
|
for (let i = 0; i < data.length; i++) {
|
const person = data[i];
|
let userId = person.userId
|
let userType = person.type
|
|
// 只有保管员(0)和科长(1)需要添加权限
|
if (userType == 0 || userType == 1) {
|
try {
|
// 检查是否已存在权限记录
|
let existingPermissions = sqliteService.d1_permission.findByUserId(userId)
|
if (existingPermissions && existingPermissions.length == 0) {
|
// 添加永久权限
|
let permissionRet = sqliteService.d1_permission.save({
|
permissionId: std.genRandomStr(32),
|
userId: userId,
|
timeType: 0, // 永久权限
|
beginTime: 0,
|
endTime: 0,
|
repeatBeginTime: 0,
|
repeatEndTime: 0,
|
period: ""
|
});
|
logger.info('[mqttService] 为用户添加权限结果:', permissionRet)
|
} else {
|
logger.info('[mqttService] 用户已存在权限记录,跳过权限添加:', userId)
|
}
|
} catch (error) {
|
logger.error('[mqttService] 添加权限时出错:', error)
|
}
|
}
|
}
|
|
return true
|
|
}
|
|
/**
|
* 查询人员
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getUser = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getUser命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
let res = this.getUserAgreement(data)
|
logger.info('[mqttService] 查询结果:', JSON.stringify(res))
|
return reply(event, res)
|
} catch (error) {
|
logger.error('[mqttService] getUser error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 查询人员通用协议格式
|
* @param {object} data - 查询参数
|
* @returns {object} 查询结果
|
*/
|
mqttService.getUserAgreement = function (data) {
|
try {
|
data.page = isEmpty(data.page) ? 0 : data.page
|
data.size = isEmpty(data.size) ? 10 : data.size
|
let totalCount = sqliteService.d1_person.count(data)
|
let persons = sqliteService.d1_person.findAll(data)
|
// 解析 extra 字段,JSON字符串转化为JSON对象,消除转义字符
|
persons.forEach(person => {
|
try {
|
if (person.extra) {
|
person.extra = JSON.parse(person.extra)
|
}
|
} catch (error) {
|
logger.error('[mqttService] 解析 extra 字段错误:', error)
|
}
|
})
|
|
let result = {
|
content: persons,
|
page: data.page,
|
size: data.size,
|
total: totalCount,
|
totalPage: Math.ceil(totalCount / data.size),
|
count: persons.length
|
}
|
|
return result
|
} catch (error) {
|
logger.error('[mqttService] getUserAgreement error:', error)
|
throw error
|
}
|
}
|
|
/**
|
* 删除人员
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.delUser = function (event) {
|
try {
|
logger.info('[mqttService] 接收到delUser命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : []
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.delUserAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] delUser失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] delUser成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] delUser error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 删除人员通用协议格式
|
* @param {array} data - 人员ID数组
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.delUserAgreement = function (data) {
|
if (data && data.length > 0) {
|
sqliteService.transaction()
|
let ret1 = sqliteService.d1_person.deleteByUserIdInBatch(data)
|
let ret2 = sqliteService.d1_permission.deleteByUserIdInBatch(data)
|
let ret3 = sqliteService.d1_voucher.deleteByUserIdInBatch(data)
|
if (ret1 != 0 || ret2 != 0 || ret3 != 0) {
|
sqliteService.rollback()
|
return "sql error"
|
}
|
sqliteService.commit()
|
// 删除人员的人脸数据
|
data.forEach(element => {
|
driver.face.delete(element)
|
});
|
}
|
return true
|
}
|
|
|
/**
|
* 清空人员
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.clearUser = function (event) {
|
try {
|
logger.info('[mqttService] 接收到clearUser命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let persons = sqliteService.d1_person.findAll()
|
// 删除所有人员的人脸数据
|
logger.info('[mqttService] 开始删除人脸数据,共', persons.length, '条')
|
persons.forEach(element => {
|
driver.face.delete(element.userId)
|
});
|
let ret1 = sqliteService.d1_person.deleteAll()
|
let ret2 = sqliteService.d1_permission.deleteAll()
|
let ret3 = sqliteService.d1_voucher.deleteAll()
|
if (ret1 == 0 && ret2 == 0 && ret3 == 0) {
|
logger.info('[mqttService] clearUser成功')
|
return reply(event)
|
} else {
|
let errorMsg = "sql error ret: " + ret1 + ", " + ret2 + ", " + ret3
|
logger.error('[mqttService] clearUser失败:', errorMsg)
|
return reply(event, errorMsg, CODE.E_100)
|
}
|
} catch (error) {
|
logger.error('[mqttService] clearUser error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
// =================================凭证增删改查=================================
|
/**
|
* 添加凭证
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.insertKey = function (event) {
|
try {
|
logger.info('[mqttService] 接收到insertKey命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.insertKeyAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] insertKey失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] insertKey成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] insertKey error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 添加凭证通用协议格式
|
* @param {array} data - 凭证数据数组
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.insertKeyAgreement = function (data) {
|
let vouchers = []
|
for (let i = 0; i < data.length; i++) {
|
const voucher = data[i];
|
if (!voucher.keyId || !voucher.type || !voucher.code || !voucher.userId) {
|
return "keyId or type or code or userId cannot be empty"
|
}
|
|
// 凭证重复
|
let ret = sqliteService.d1_voucher.findAllBycode(voucher.code)
|
if (ret.length != 0) {
|
return "Duplicate vouchers"
|
}
|
|
if (voucher.type == 300) {
|
if (voucher.extra) {
|
if (voucher.extra.faceType != 0 && voucher.extra.faceType != 1) {
|
return "faceType Incorrect format"
|
}
|
} else {
|
return "faceType is required"
|
}
|
}
|
let record = {}
|
record.keyId = voucher.keyId
|
record.type = voucher.type
|
if (voucher.type == "400") {
|
if (voucher.code.length > 6) {
|
return "Password length cannot exceed 6 digits"
|
}
|
}
|
if (voucher.type == "300") {
|
if (voucher.extra.faceType == 0) {
|
record.code = `/app/data/user/${voucher.userId}/register.jpg`
|
// 保存base64图片
|
std.ensurePathExists(record.code)
|
common.base64_2binfile(record.code, voucher.code)
|
// 注册人脸
|
let weq = driver.face.registerFaceByPicFile(voucher.userId, record.code)
|
if (weq == 0) {
|
logger.info("注册人脸成功")
|
} else {
|
logger.info("第一次人脸注册失败")
|
//删除重新注册
|
driver.face.delete(voucher.userId)
|
let res = driver.face.registerFaceByPicFile(voucher.userId, record.code)
|
if (res == 0) {
|
logger.info("第二次注册人脸成功")
|
sqliteService.d1_voucher.deleteByKeyId(record.keyId)
|
} else {
|
return "Face registration failed"
|
}
|
}
|
} else {
|
record.code = voucher.code
|
//特征值注册
|
let res = driver.face.reg(voucher.userId, voucher.code)
|
if (res != 0) {
|
return "Face registration failed"
|
}
|
}
|
} else {
|
record.code = voucher.code
|
let ret = sqliteService.d1_voucher.findAllByCodeAndType(voucher.code, voucher.type)
|
if (ret.length != 0) {
|
return "Duplicate vouchers"
|
}
|
}
|
|
record.userId = voucher.userId
|
record.extra = isEmpty(voucher.extra) ? JSON.stringify({ type: 0 }) : JSON.stringify(voucher.extra)
|
vouchers.push(record)
|
}
|
let ret = sqliteService.d1_voucher.saveAll(vouchers)
|
if (ret == 0) {
|
return true
|
} else {
|
return "sql error ret:" + ret
|
}
|
}
|
|
/**
|
* 查询凭证
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getKey = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getKey命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data))
|
let res = this.getKeyAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] getKey失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] 查询结果:', JSON.stringify(res))
|
return reply(event, res)
|
} catch (error) {
|
logger.error('[mqttService] getKey error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 查询凭证通用协议格式
|
* @param {object} data - 查询参数
|
* @returns {object|string} 查询结果或错误信息
|
*/
|
mqttService.getKeyAgreement = function (data) {
|
if (!data.type) {
|
return "type is required"
|
}
|
if (data.type == 300) {
|
data.size = 1
|
} else {
|
data.page = isEmpty(data.page) ? 0 : data.page
|
data.size = isEmpty(data.size) ? 10 : data.size
|
}
|
let totalCount = sqliteService.d1_voucher.count(data)
|
let vouchers = sqliteService.d1_voucher.findAll(data)
|
vouchers.forEach(element => {
|
if (element.type == 300 && element.extra && JSON.parse(element.extra).faceType == 0) {
|
//人脸特殊处理一下
|
element.code = driver.face.fileToBase64(element.code)
|
}
|
});
|
return {
|
content: vouchers,
|
page: data.page,
|
size: data.size,
|
total: totalCount,
|
totalPage: Math.ceil(totalCount / data.size),
|
count: vouchers.length
|
}
|
}
|
|
/**
|
* 删除凭证
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.delKey = function (event) {
|
try {
|
logger.info('[mqttService] 接收到delKey命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.delKeyAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] delKey失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] delKey成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] delKey error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 删除凭证通用协议格式
|
* @param {object} data - 删除参数
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.delKeyAgreement = function (data) {
|
if (data.keyIds && data.keyIds.length > 0) {
|
let userIds = []
|
for (let i = 0; i < data.keyIds.length; i++) {
|
const element = data.keyIds[i];
|
let res = sqliteService.d1_voucher.findAllByKeyId(element)
|
if (res.length <= 0) {
|
continue
|
}
|
if (res[0].type == 300) {
|
userIds.push(res[0].userId)
|
}
|
}
|
let ret = sqliteService.d1_voucher.deleteByKeyIdInBatch(data.keyIds)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
}
|
// 删除人脸数据
|
userIds.forEach(element => {
|
driver.face.delete(element)
|
});
|
}
|
if (data.userIds && data.userIds.length > 0) {
|
let ret = sqliteService.d1_voucher.deleteByUserIdInBatch(data.userIds)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
}
|
// 删除人脸数据
|
data.userIds.forEach(element => {
|
driver.face.delete(element)
|
});
|
}
|
return true
|
}
|
|
/**
|
* 清空凭证
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.clearKey = function (event) {
|
try {
|
logger.info('[mqttService] 接收到clearKey命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let res = sqliteService.d1_voucher.findAll()
|
let userIds = []
|
res.forEach(element => {
|
if (element.type == 300) {
|
userIds.push(element.userId)
|
}
|
});
|
logger.info('[mqttService] 找到需要删除的人脸数据,共', userIds.length, '条')
|
let ret = sqliteService.d1_voucher.deleteAll()
|
if (ret == 0) {
|
// 删除人脸数据
|
logger.info('[mqttService] 开始删除人脸数据')
|
userIds.forEach((element, index) => {
|
driver.face.delete(element)
|
});
|
logger.info('[mqttService] clearKey成功')
|
reply(event)
|
} else {
|
logger.error('[mqttService] clearKey失败:', "sql error ret:" + ret)
|
reply(event, "sql error ret:" + ret, CODE.E_100)
|
}
|
} catch (error) {
|
logger.error('[mqttService] clearKey error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
// =================================应急开仓密码增删改查=================================
|
/**
|
* 添加应急开仓密码
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.insertEmergencyPassword = function (event) {
|
try {
|
logger.info('[mqttService] 接收到insertEmergencyPassword命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.insertEmergencyPasswordAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] insertEmergencyPassword失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] insertEmergencyPassword成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] insertEmergencyPassword error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 添加应急开仓密码通用协议格式
|
* @param {object} data - 应急开仓密码数据对象
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.insertEmergencyPasswordAgreement = function (data) {
|
// 应急开仓密码在设备中仅有唯一的1个,所以先清空表
|
let deleteRet = sqliteService.d1_emergency_password.deleteAll()
|
if (deleteRet != 0) {
|
return "清空旧密码失败: " + deleteRet
|
}
|
|
// 检查密码是否有效
|
if (!data.password) {
|
return "password cannot be empty"
|
}
|
|
// 检查密码长度是否大于等于8位
|
if (data.password.length < 8) {
|
return "Password length must be at least 8 digits"
|
}
|
|
// 构建密码记录
|
let record = {}
|
record.id = data.id || 'emergency_' + Date.now() // 如果没有id,自动生成
|
record.password = data.password
|
record.description = data.description || ""
|
record.createTime = Date.now()
|
record.updateTime = Date.now()
|
record.status = data.status || 1
|
|
// 保存密码
|
let ret = sqliteService.d1_emergency_password.save(record)
|
if (ret == 0) {
|
return true
|
} else {
|
return "sql error ret:" + ret
|
}
|
}
|
|
/**
|
* 查询应急开仓密码
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getEmergencyPassword = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getEmergencyPassword命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let res = this.getEmergencyPasswordAgreement()
|
logger.info('[mqttService] 查询结果:', JSON.stringify(res))
|
return reply(event, res)
|
} catch (error) {
|
logger.error('[mqttService] getEmergencyPassword error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 时间戳转日期字符串
|
* @param {number} timestamp - 时间戳
|
* @returns {string} 日期字符串,格式:YYYY-MM-DD HH:MM:SS
|
*/
|
function timestampToDateString(timestamp) {
|
const date = new Date(timestamp);
|
const year = date.getFullYear();
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
const day = String(date.getDate()).padStart(2, '0');
|
const hours = String(date.getHours()).padStart(2, '0');
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
}
|
|
/**
|
* 查询应急开仓密码通用协议格式
|
* @returns {object} 查询结果
|
*/
|
mqttService.getEmergencyPasswordAgreement = function () {
|
let passwords = sqliteService.d1_emergency_password.findAll()
|
if (passwords && passwords.length > 0) {
|
let password = passwords[0];
|
// 转换时间戳为字符串格式
|
password.createTime = timestampToDateString(password.createTime);
|
password.updateTime = timestampToDateString(password.updateTime);
|
return password;
|
}
|
return {};
|
}
|
|
|
/**
|
* 清空应急开仓密码
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.clearEmergencyPassword = function (event) {
|
try {
|
logger.info('[mqttService] 接收到clearEmergencyPassword命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let ret = sqliteService.d1_emergency_password.deleteAll()
|
if (ret == 0) {
|
logger.info('[mqttService] clearEmergencyPassword成功')
|
return reply(event)
|
} else {
|
logger.error('[mqttService] clearEmergencyPassword失败:', "sql error ret:" + ret)
|
return reply(event, "sql error ret:" + ret, CODE.E_100)
|
}
|
} catch (error) {
|
logger.error('[mqttService] clearEmergencyPassword error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
// =================================密钥增删改查=================================
|
/**
|
* 添加密钥
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.insertSecurity = function (event) {
|
try {
|
logger.info('[mqttService] 接收到insertSecurity命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.insertSecurityAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] insertSecurity失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] insertSecurity成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] insertSecurity error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 添加密钥通用协议格式
|
* @param {array} data - 密钥数据数组
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.insertSecurityAgreement = function (data) {
|
let securities = []
|
for (let i = 0; i < data.length; i++) {
|
const security = data[i];
|
let record = []
|
record.securityId = security.securityId
|
record.type = security.type
|
record.key = security.key
|
record.value = security.value
|
record.startTime = security.startTime
|
record.endTime = security.endTime
|
securities.push(record)
|
}
|
let ret = sqliteService.d1_security.saveAll(securities)
|
if (ret == 0) {
|
return true
|
} else {
|
return "sql error ret:" + ret
|
}
|
}
|
|
/**
|
* 查询密钥
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getKey = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getKey命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data))
|
let res = this.getKeyAgreement(data)
|
logger.info('[mqttService] 查询结果:', JSON.stringify(res))
|
return reply(event, res)
|
} catch (error) {
|
logger.error('[mqttService] getKey error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 查询密钥通用协议格式
|
* @param {object} data - 查询参数
|
* @returns {object} 查询结果
|
*/
|
mqttService.getSecurityAgreement = function (data) {
|
data.page = isEmpty(data.page) ? 0 : data.page
|
data.size = isEmpty(data.size) ? 10 : data.size
|
let totalCount = sqliteService.d1_security.count(data)
|
let securities = sqliteService.d1_security.findAll(data)
|
return {
|
content: securities,
|
page: data.page,
|
size: data.size,
|
total: totalCount,
|
totalPage: Math.ceil(totalCount / data.size),
|
count: securities.length
|
}
|
}
|
|
/**
|
* 删除密钥
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.delSecurity = function (event) {
|
try {
|
logger.info('[mqttService] 接收到delSecurity命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.delSecurityAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] delSecurity失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] delSecurity成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] delSecurity error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 删除密钥通用协议格式
|
* @param {array} data - 密钥ID数组
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.delSecurityAgreement = function (data) {
|
if (data.length > 0) {
|
let ret = sqliteService.d1_security.deleteBySecurityIdInBatch(data)
|
if (ret != 0) {
|
return "sql error ret:" + ret
|
}
|
}
|
return true
|
}
|
|
/**
|
* 清空密钥
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.clearSecurity = function (event) {
|
try {
|
logger.info('[mqttService] 接收到clearSecurity命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let ret = sqliteService.d1_key.deleteAll()
|
if (ret == 0) {
|
logger.info('[mqttService] clearSecurity成功')
|
return reply(event)
|
} else {
|
logger.error('[mqttService] clearSecurity失败:', "sql error ret:" + ret)
|
return reply(event, "sql error ret:" + ret, CODE.E_100)
|
}
|
} catch (error) {
|
logger.error('[mqttService] clearSecurity error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 远程控制
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.control = function (event) {
|
try {
|
logger.info('[mqttService] 接收到control命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload.data || {}
|
switch (data.command) {
|
case 0:
|
//重启
|
logger.info('[mqttService] 执行重启命令')
|
reply(event)
|
common.asyncReboot(2)
|
return
|
case 1:
|
//远程开门
|
logger.info('[mqttService] 执行远程开门命令')
|
driver.gpio.open()
|
break
|
case 4:
|
//重置
|
logger.info('[mqttService] 执行重置命令')
|
common.systemBrief("rm -rf /app/data/config/*")
|
common.systemBrief("rm -rf /app/data/db/*")
|
common.systemBrief("rm -rf /app/data/user/*")
|
common.systemBrief("rm -rf /app/data/user/*")
|
common.systemBrief("rm -rf /vgmj.db")
|
reply(event)
|
common.asyncReboot(2)
|
return
|
case 5:
|
//播放语音
|
logger.info('[mqttService] 执行播放语音命令')
|
if (data.extra) {
|
let res = common.systemWithRes(`test -e "/app/code/resource/wav/${data.extra.wav}.wav" && echo "OK" || echo "NO"`, 2)
|
if (res.includes('OK')) {
|
driver.alsa.play(`/app/code/resource/wav/${data.extra.wav}.wav`)
|
}
|
}
|
break
|
case 6:
|
// 6:屏幕展示图片
|
// TODO
|
logger.info('[mqttService] 执行屏幕展示图片命令')
|
break
|
case 7:
|
// 7:屏幕展示文字
|
// TODO
|
logger.info('[mqttService] 执行屏幕展示文字命令')
|
break
|
case 10:
|
logger.info('[mqttService] 执行二维码展示命令')
|
if (!isEmpty(data.extra.qrCodeBase64) && typeof data.extra.qrCodeBase64 == 'string') {
|
//base64转图片保存
|
let src = `/app/code/resource/image/app_qrcode.png`
|
std.ensurePathExists(src)
|
common.base64_2binfile(src, data.extra.qrCodeBase64)
|
logger.info('[mqttService] 二维码保存成功')
|
return reply(event)
|
}
|
break
|
default:
|
logger.info('[mqttService] 未知命令:', data.command)
|
break
|
}
|
logger.info('[mqttService] control命令执行完成')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] control error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 查询配置
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getConfig = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getConfig命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let configAll = config.getAll()
|
let res = {}
|
// 配置分组
|
for (const key in configAll) {
|
const value = configAll[key];
|
const keys = key.split(".")
|
if (keys.length == 2) {
|
if (!res[keys[0]]) {
|
res[keys[0]] = {}
|
}
|
res[keys[0]][keys[1]] = value
|
} else {
|
res[keys[0]] = value
|
}
|
}
|
res.sys = {
|
// 保留原有的 sysInfo 中的其他值
|
...res.sys,
|
totalmem: common.getTotalmem(),
|
freemem: common.getFreemem(),
|
totaldisk: common.getTotaldisk(),
|
freedisk: common.getFreedisk(),
|
freecpu: common.getFreecpu()
|
};
|
if (isEmpty(data) || typeof data != "string" || data == "") {
|
// 查询全部
|
logger.info('[mqttService] getConfig成功,返回全部配置,配置数量:', Object.keys(res).length)
|
return reply(event, res)
|
}
|
// 单条件查询"data": "mqttInfo.clientId"
|
let keys = data.split(".")
|
let search = {}
|
if (keys.length == 2) {
|
if (res[keys[0]]) {
|
search[keys[0]] = {}
|
search[keys[0]][keys[1]] = res[keys[0]][keys[1]]
|
}
|
} else {
|
search[keys[0]] = res[keys[0]]
|
}
|
logger.info('[mqttService] getConfig成功,返回指定配置:', JSON.stringify(search))
|
return reply(event, search)
|
} catch (error) {
|
logger.error('[mqttService] getConfig error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 修改配置
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.setConfig = function (event) {
|
try {
|
logger.info('[mqttService] 接收到setConfig命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
if (!data || typeof data != 'object') {
|
logger.error('[mqttService] setConfig失败: data should not be empty')
|
return reply(event, "data should not be empty", CODE.E_100)
|
}
|
let res = configService.configVerifyAndSave(data)
|
if (typeof res != 'boolean') {
|
// 返回错误信息
|
logger.error('[mqttService] setConfig失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
if (res) {
|
logger.info('[mqttService] setConfig成功')
|
return reply(event)
|
} else {
|
logger.error('[mqttService] setConfig失败: unknown failure')
|
return reply(event, "unknown failure", CODE.E_100)
|
}
|
} catch (error) {
|
logger.error('[mqttService] setConfig error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 升级固件
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.upgradeFirmware = function (event) {
|
try {
|
logger.info('[mqttService] 接收到upgradeFirmware命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
if (!data || typeof data != 'object' || typeof data.type != 'number' || typeof data.url != 'string' || typeof data.md5 != 'string') {
|
logger.error('[mqttService] upgradeFirmware失败: data\'s params error')
|
return reply(event, "data's params error", CODE.E_100)
|
}
|
|
if (data.type == 0) {
|
try {
|
logger.info('[mqttService] 开始固件升级,url:', data.url, 'md5:', data.md5)
|
driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgrading" })
|
ota.updateHttp(data.url, data.md5, 300)
|
driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeSuccess" })
|
logger.info('[mqttService] 固件升级成功')
|
reply(event)
|
common.asyncReboot(3)
|
return
|
} catch (error) {
|
logger.error('[mqttService] 固件升级失败:', error)
|
driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeFail" })
|
return reply(event, "upgrade failure", CODE.E_100)
|
}
|
}
|
|
logger.error('[mqttService] upgradeFirmware失败: 不支持的升级类型')
|
return reply(event, "upgrade failure", CODE.E_100)
|
} catch (error) {
|
logger.error('[mqttService] upgradeFirmware error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 查询识别记录
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.getRecords = function (event) {
|
try {
|
logger.info('[mqttService] 接收到getRecords命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data))
|
let res = this.getRecordsAgreement(data)
|
logger.info('[mqttService] 查询结果:', JSON.stringify(res))
|
return reply(event, res)
|
} catch (error) {
|
logger.error('[mqttService] getRecords error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 将日期字符串转换为时间戳(秒)
|
* @param {string} dateString - 日期字符串,格式:YYYY-MM-DD HH:MM:SS
|
* @returns {number} 时间戳(秒)
|
*/
|
function dateStringToTimestamp(dateString) {
|
if (!dateString) return null
|
// 将YYYY-MM-DD HH:MM:SS格式转换为YYYY-MM-DDTHH:MM:SS格式,以便new Date()正确解析
|
const formattedDateString = dateString.replace(' ', 'T')
|
const date = new Date(formattedDateString)
|
return Math.floor(date.getTime() / 1000)
|
}
|
|
/**
|
* 查询识别记录通用协议格式
|
* @param {object} data - 查询参数
|
* @returns {object} 查询结果
|
*/
|
mqttService.getRecordsAgreement = function (data) {
|
data.page = isEmpty(data.page) ? 0 : data.page
|
data.size = isEmpty(data.size) ? 10 : data.size
|
|
// 处理时间参数,将字符串格式转换为时间戳
|
let startTime = null
|
let endTime = null
|
if (data.startTime) {
|
if (typeof data.startTime === 'string') {
|
startTime = dateStringToTimestamp(data.startTime)
|
} else {
|
startTime = Math.floor(data.startTime / 1000) // 转换为秒级时间戳
|
}
|
}
|
if (data.endTime) {
|
if (typeof data.endTime === 'string') {
|
endTime = dateStringToTimestamp(data.endTime)
|
} else {
|
endTime = Math.floor(data.endTime / 1000) // 转换为秒级时间戳
|
}
|
}
|
|
// 构建查询条件
|
let queryData = {}
|
let nameFilter = null
|
// 复制其他查询参数
|
for (const key in data) {
|
if (key !== 'startTime' && key !== 'endTime' && key !== 'name') {
|
queryData[key] = data[key]
|
} else if (key === 'name') {
|
nameFilter = data[key]
|
}
|
}
|
|
// 构建SQL条件
|
let whereClause = ''
|
if (startTime) {
|
whereClause += `time >= ${startTime} `
|
}
|
if (endTime) {
|
if (whereClause) {
|
whereClause += `AND `
|
}
|
whereClause += `time <= ${endTime} `
|
}
|
|
// 复制其他条件
|
for (const key in queryData) {
|
if (key !== 'page' && key !== 'size') {
|
if (whereClause) {
|
whereClause += `AND `
|
}
|
if (typeof queryData[key] === 'string') {
|
whereClause += `${key} = '${queryData[key]}' `
|
} else {
|
whereClause += `${key} = ${queryData[key]} `
|
}
|
}
|
}
|
|
// 执行查询
|
let totalCount = 0
|
let securities = []
|
try {
|
// 构建count SQL
|
let countSql = `SELECT COUNT(*) FROM d1_pass_record `
|
if (whereClause) {
|
countSql += `WHERE ${whereClause} `
|
}
|
countSql += `;`
|
let countResult = sqlite.select(countSql)
|
if (countResult && countResult[0] && countResult[0]['COUNT(*)']) {
|
totalCount = countResult[0]['COUNT(*)']
|
}
|
|
// 构建findAll SQL
|
let findSql = `SELECT * FROM d1_pass_record `
|
if (whereClause) {
|
findSql += `WHERE ${whereClause} `
|
}
|
findSql += `ORDER BY time DESC `
|
if (queryData.page !== undefined && queryData.size !== undefined) {
|
findSql += `LIMIT ${queryData.size} OFFSET ${queryData.page * queryData.size} `
|
}
|
findSql += `;`
|
securities = sqlite.select(findSql)
|
} catch (error) {
|
logger.error('[mqttService] 查询记录失败:', error)
|
}
|
|
// 处理每条记录
|
let processedSecurities = securities.map(record => {
|
// 解析extra字段
|
let extraData = {}
|
try {
|
if (record.extra && record.extra !== '') {
|
extraData = JSON.parse(record.extra)
|
}
|
} catch (error) {
|
logger.error('[mqttService] 解析extra失败:', error)
|
}
|
|
// 解析extra2字段
|
let extra2Data = {}
|
try {
|
if (record.extra2 && record.extra2 !== '') {
|
extra2Data = JSON.parse(record.extra2)
|
}
|
} catch (error) {
|
logger.error('[mqttService] 解析extra2失败:', error)
|
}
|
|
// 构建新记录
|
return {
|
id: record.id,
|
keyId: record.keyId,
|
permissionId: record.permissionId,
|
permissionId2: record.permissionId2,
|
userId: record.userId,
|
userId2: record.userId2,
|
type: record.type,
|
code: record.code,
|
door: record.door,
|
time: timestampToDateString(record.time * 1000), // 将秒级时间戳转换为毫秒级,再转换为日期字符串
|
result: record.result,
|
name: extraData.name || '',
|
idCard: extraData.idCard || '',
|
name2: extra2Data.name || '',
|
idCard2: extra2Data.idCard || '',
|
message: record.message
|
}
|
})
|
|
// 应用name过滤
|
if (nameFilter) {
|
processedSecurities = processedSecurities.filter(record =>
|
record.name.toLowerCase().includes(nameFilter.toLowerCase())
|
)
|
// 更新总数和总页数
|
totalCount = processedSecurities.length
|
}
|
|
return {
|
content: processedSecurities,
|
page: data.page,
|
size: data.size,
|
total: totalCount,
|
totalPage: Math.ceil(totalCount / data.size),
|
count: processedSecurities.length
|
}
|
}
|
|
/**
|
* 删除记录
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.delRecords = function (event) {
|
try {
|
logger.info('[mqttService] 接收到delRecords命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
let data = payload.payload && payload.payload.data ? payload.payload.data : {}
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(data))
|
let res = this.delRecordsAgreement(data)
|
if (typeof res == 'string') {
|
logger.error('[mqttService] delRecords失败:', res)
|
return reply(event, res, CODE.E_100)
|
}
|
logger.info('[mqttService] delRecords成功')
|
return reply(event)
|
} catch (error) {
|
logger.error('[mqttService] delRecords error:', error)
|
return reply(event, { error: error.message }, CODE.E_100)
|
}
|
}
|
|
/**
|
* 删除记录通用协议格式
|
* @param {object} data - 删除参数
|
* @returns {boolean|string} true表示成功,string表示错误信息
|
*/
|
mqttService.delRecordsAgreement = function (data) {
|
|
// 根据时间范围删除记录
|
if (data.startTime || data.endTime) {
|
logger.info('[mqttService] 时间范围: startTime=' + data.startTime + ', endTime=' + data.endTime)
|
|
try {
|
// 构建查询条件
|
let query = {};
|
if (data.startTime) {
|
query.startTime = data.startTime;
|
}
|
if (data.endTime) {
|
query.endTime = data.endTime;
|
}
|
|
// 使用getRecordsAgreement函数的查询逻辑来获取符合条件的记录
|
let result = mqttService.getRecordsAgreement(query);
|
let records = result.content || [];
|
|
// 逐个删除记录
|
let deletedCount = 0;
|
for (let record of records) {
|
// 如果是人脸记录,删除对应的图片文件
|
if (record.type == 300 && record.code) {
|
try {
|
common.systemBrief(`rm -rf ${record.code}`);
|
} catch (error) {
|
logger.error('[mqttService] 删除图片文件出错: ' + error.message);
|
}
|
}
|
// 删除记录
|
sqliteService.d1_pass_record.delete({ id: record.id });
|
deletedCount++;
|
}
|
|
logger.info('[mqttService] 成功删除 ' + deletedCount + ' 条记录');
|
} catch (error) {
|
logger.error('[mqttService] 删除记录出错: ' + error.message);
|
// 忽略错误,返回成功
|
}
|
}
|
|
return true
|
}
|
/**
|
* 通行上报回复
|
* @param {object} event - MQTT事件对象
|
*/
|
mqttService.access_reply = function (event) {
|
try {
|
logger.info('[mqttService] 接收到access_reply命令:', JSON.stringify(event.topic))
|
logger.info('[mqttService] 命令payload:', event.payload)
|
let payload = JSON.parse(event.payload)
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(payload))
|
let serialNo = map.get(payload.serialNo)
|
if (serialNo) {
|
logger.info('[mqttService] 清理临时文件:', serialNo)
|
common.systemBrief(`rm -rf ${serialNo}`)
|
map.del(payload.serialNo)
|
}
|
logger.info('[mqttService] 清空通行记录')
|
sqliteService.d1_pass_record.deleteAll()
|
logger.info('[mqttService] access_reply处理完成')
|
} catch (error) {
|
logger.error('[mqttService] access_reply error:', error)
|
}
|
}
|
|
/**
|
* 在线验证回复
|
* @param {object} raw - MQTT事件对象
|
*/
|
mqttService.access_online_reply = function (raw) {
|
try {
|
logger.info('[mqttService] 接收到access_online_reply命令:', JSON.stringify(raw.topic))
|
logger.info('[mqttService] 命令payload:', raw.payload)
|
let payload = JSON.parse(raw.payload)
|
logger.info('[mqttService] 解析后的参数:', JSON.stringify(payload))
|
let map = dxMap.get("VERIFY")
|
let data = map.get(payload.serialNo)
|
if (data) {
|
logger.info('[mqttService] 处理在线验证回复,serialNo:', payload.serialNo)
|
map.del(payload.serialNo)
|
driver.mqtt.getOnlinecheckReply(payload)
|
}
|
logger.info('[mqttService] access_online_reply处理完成')
|
} catch (error) {
|
logger.error('[mqttService] access_online_reply error:', error)
|
}
|
}
|
|
/**
|
* 错误代码定义
|
*/
|
const CODE = {
|
// 成功
|
S_000: "000000",
|
// 未知错误
|
E_100: "100000",
|
// 设备已被禁用
|
E_101: "100001",
|
// 设备正忙,请稍后再试
|
E_102: "100002",
|
// 签名检验失败
|
E_103: "100003",
|
// 超时错误
|
E_104: "100004",
|
// 设备离线
|
E_105: "100005",
|
}
|
mqttService.CODE = CODE
|
|
/**
|
* 上报设备信息和通行记录
|
*/
|
mqttService.report = function () {
|
// 在线上报
|
let payloadReply = mqttReply(std.genRandomStr(10), {
|
mac: config.get("sys.mac") || '',
|
version: config.get("sys.version"),
|
appVersion: config.get("sys.version"),
|
releaseTime: config.get("sys.createTime"),
|
type: config.get("net.type"),
|
}, CODE.S_000)
|
driver.mqtt.send("access_device/v2/event/connect", JSON.stringify(payloadReply))
|
|
//通行记录上报 - 已关闭
|
// let res = sqliteService.d1_pass_record.findAll()
|
// if (res.length <= 0) {
|
// return
|
// }
|
// // 筛选出 type === 300 的对象(人脸记录)
|
// let faceArray = res.filter(item => item.type == 300);
|
// // 筛选出 type !== 300 的对象(其他记录)
|
// let recordArray = res.filter(item => item.type != 300);
|
// if (recordArray.length > 0) {
|
// driver.mqtt.send("access_device/v2/event/access", JSON.stringify(mqttReply(std.genRandomStr(10), recordArray, CODE.S_000)))
|
// }
|
// if (faceArray.length > 0) {
|
// let index = 0
|
// let timer = std.setInterval(() => {
|
// let serialNo = std.genRandomStr(10)
|
// //缓存放入要删除的人脸照片 src
|
// map.del(serialNo)
|
// map.put(serialNo, faceArray[index].code)
|
//
|
// // 检查faceArray[index].code是否有效
|
// if (faceArray[index].code) {
|
// faceArray[index].code = driver.face.fileToBase64(faceArray[index].code)
|
// } else {
|
// faceArray[index].code = ""
|
// logger.info("人脸记录中code字段为空,跳过Base64转换")
|
// }
|
//
|
// driver.mqtt.send("access_device/v2/event/access", JSON.stringify(mqttReply(serialNo, [faceArray[index]], CODE.S_000)))
|
// index++
|
// if (!faceArray[index]) {
|
// std.clearInterval(saveTimer)
|
// std.clearInterval(timer)
|
// }
|
// }, 1000)
|
// // 每隔500ms检查一次mqtt连接状态,如果断开,则停止上报
|
// let saveTimer = std.setInterval(() => {
|
// if (!driver.mqtt.getStatus()) {
|
// std.clearInterval(saveTimer)
|
// std.clearInterval(timer)
|
// }
|
// }, 500)
|
// }
|
}
|
|
/**
|
* mqtt请求统一回复
|
* @param {object} event - MQTT事件对象
|
* @param {any} data - 回复数据
|
* @param {string} code - 错误代码
|
*/
|
function reply(event, data, code) {
|
try {
|
let topic = getReplyTopic(event)
|
let payload = JSON.parse(event.payload)
|
let serialNo = payload.serialNo || std.genRandomStr(10)
|
let reply = JSON.stringify(mqttReply(serialNo, data, isEmpty(code) ? CODE.S_000 : code))
|
driver.mqtt.send(topic, reply)
|
} catch (error) {
|
logger.error('[mqttService] reply error:', error)
|
}
|
}
|
|
/**
|
* 获取回复主题
|
* @param {object} data - MQTT事件对象
|
* @returns {string} 回复主题
|
*/
|
function getReplyTopic(data) {
|
// return data.topic.replace("/" + config.get("sys.sn"), '') + "_reply";
|
try {
|
let sn = config.get("mqtt.clientId")
|
return data.topic.replace("/" + sn, '') + "_reply";
|
} catch (error) {
|
logger.error('[mqttService] getReplyTopic error:', error)
|
// 回退到使用固定格式
|
return data.topic + "_reply"
|
}
|
}
|
|
/**
|
* mqtt回复格式构建
|
* @param {string} serialNo - 序列号
|
* @param {any} data - 回复数据
|
* @param {string} code - 错误代码
|
* @returns {object} 回复格式对象
|
*/
|
function mqttReply(serialNo, data, code) {
|
// 生成当前时间的字符串格式
|
const now = new Date();
|
const year = now.getFullYear();
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
const day = String(now.getDate()).padStart(2, '0');
|
const hours = String(now.getHours()).padStart(2, '0');
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
const seconds = String(now.getSeconds()).padStart(2, '0');
|
const timeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
return {
|
serialNo: serialNo,
|
uuid: config.get("sys.uuid"),
|
sign: '',
|
code: code,
|
data: data,
|
time: timeString
|
}
|
}
|
mqttService.mqttReply = mqttReply
|
|
/**
|
* 获取所有订阅的topic
|
* @returns {array} 订阅的topic列表
|
*/
|
mqttService.getTopics = function () {
|
// 获取所有订阅的topic
|
let sn = config.get("mqtt.clientId")
|
const topics = [
|
"control", "getConfig", "setConfig", "upgradeFirmware", "test",
|
"getPermission", "insertPermission", "delPermission", "clearPermission",
|
"getKey", "insertKey", "delKey", "clearKey",
|
"getUser", "insertUser", "delUser", "clearUser",
|
"getSecurity", "insertSecurity", "delSecurity", "clearSecurity", "getRecords", "delRecords",
|
"insertEmergencyPassword", "delEmergencyPassword", "clearEmergencyPassword", "getEmergencyPassword"
|
]
|
const eventReplies = ["connect_reply", "alarm_reply", "access_reply", "access_online_reply"]
|
|
let flag = 'access_device/v2/cmd/' + sn + "/"
|
let eventFlag = 'access_device/v2/event/' + sn + "/"
|
return topics.map(item => flag + item).concat(eventReplies.map(item => eventFlag + item));
|
}
|
|
/**
|
* 判空函数
|
* @param {any} value - 要判断的值
|
* @returns {boolean} 是否为空
|
*/
|
function isEmpty(value) {
|
return value === undefined || value === null || value === ""
|
}
|
|
export default mqttService
|
|
/*
|
`mqttService.getTopics()` 函数返回的所有 topic 如下:
|
|
### 命令 topic(用于接收服务器下发的命令):
|
- `access_device/v2/cmd/{sn}/control` - 控制命令
|
- `access_device/v2/cmd/{sn}/getConfig` - 获取配置
|
- `access_device/v2/cmd/{sn}/setConfig` - 设置配置
|
- `access_device/v2/cmd/{sn}/upgradeFirmware` - 固件升级
|
- `access_device/v2/cmd/{sn}/test` - 测试命令
|
- `access_device/v2/cmd/{sn}/getPermission` - 获取权限
|
- `access_device/v2/cmd/{sn}/insertPermission` - 插入权限
|
- `access_device/v2/cmd/{sn}/delPermission` - 删除权限
|
- `access_device/v2/cmd/{sn}/clearPermission` - 清除权限
|
- `access_device/v2/cmd/{sn}/getKey` - 获取密钥
|
- `access_device/v2/cmd/{sn}/insertKey` - 插入密钥
|
- `access_device/v2/cmd/{sn}/delKey` - 删除密钥
|
- `access_device/v2/cmd/{sn}/clearKey` - 清除密钥
|
- `access_device/v2/cmd/{sn}/getUser` - 获取用户
|
- `access_device/v2/cmd/{sn}/insertUser` - 插入用户
|
- `access_device/v2/cmd/{sn}/delUser` - 删除用户
|
- `access_device/v2/cmd/{sn}/clearUser` - 清除用户
|
- `access_device/v2/cmd/{sn}/getSecurity` - 获取安全信息
|
- `access_device/v2/cmd/{sn}/insertSecurity` - 插入安全信息
|
- `access_device/v2/cmd/{sn}/delSecurity` - 删除安全信息
|
- `access_device/v2/cmd/{sn}/clearSecurity` - 清除安全信息
|
- `access_device/v2/cmd/{sn}/getRecords` - 获取记录
|
- `access_device/v2/cmd/{sn}/delRecords` - 删除记录
|
|
### 事件回复 topic(用于接收服务器对事件的回复):
|
- `access_device/v2/event/{sn}/connect_reply` - 连接回复
|
- `access_device/v2/event/{sn}/alarm_reply` - 告警回复
|
- `access_device/v2/event/{sn}/access_reply` - 通行回复
|
- `access_device/v2/event/{sn}/access_online_reply` - 在线验证回复
|
|
其中 `{sn}` 是设备的序列号,会被替换为实际的设备序列号。
|
*/
|