| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- "use strict";
- var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.OtaController = void 0;
- const firmware_1 = require("../models/firmware");
- const ota_1 = require("../models/ota");
- const device_1 = require("../models/device");
- const fileUtils_1 = require("../utils/fileUtils");
- const promises_1 = __importDefault(require("fs/promises"));
- const path_1 = __importDefault(require("path"));
- const mqttBrokerService_1 = require("../services/mqttBrokerService");
- const loggerService_1 = require("../services/loggerService");
- const helpers_1 = require("../utils/helpers");
- const systemLog_1 = require("../models/systemLog");
- const firmwareUploadDir = '/home/yangfei/OTA/firmware';
- async function ensureUploadDirExists() {
- try {
- await promises_1.default.access(firmwareUploadDir);
- }
- catch {
- await promises_1.default.mkdir(firmwareUploadDir, { recursive: true });
- }
- }
- ensureUploadDirExists();
- class OtaController {
- static async logOTAToSystemLog(deviceId, message, level = 'info', details) {
- try {
- await systemLog_1.SystemLogModel.create({
- level,
- message,
- source: 'ota',
- module: 'device_ota',
- details: details ? JSON.stringify({ ...details, deviceId }) : JSON.stringify({ deviceId })
- });
- }
- catch (error) {
- console.error('记录OTA系统日志失败:', error);
- }
- }
- static async uploadFirmware(req, res) {
- try {
- const file = req.file;
- if (!file) {
- res.status(400).json({
- success: false,
- message: 'No file uploaded',
- error: 'No file uploaded'
- });
- return;
- }
- if (!file.mimetype.startsWith('application/octet-stream')) {
- res.status(400).json({
- success: false,
- message: 'Invalid file type. Only binary files are allowed.',
- error: 'Invalid file type. Only binary files are allowed.'
- });
- return;
- }
- const version = req.body.version;
- if (!version || !/^\d+\.\d+\.\d+$/.test(version)) {
- res.status(400).json({
- success: false,
- message: 'Invalid version format. Please use semantic versioning (e.g., 1.0.0).',
- error: 'Invalid version format. Please use semantic versioning (e.g., 1.0.0).'
- });
- return;
- }
- const md5sum = await (0, fileUtils_1.generateMD5)(file.path);
- const newFilename = `firmware-${version}.bin`;
- const newFilePath = path_1.default.join(firmwareUploadDir, newFilename);
- await promises_1.default.rename(file.path, newFilePath);
- const firmwareData = {
- version,
- filename: newFilename,
- filepath: newFilePath,
- filesize: file.size,
- md5sum,
- description: req.body.description || '',
- status: req.body.status || 'active',
- created_by: req.user?.id || 'system'
- };
- const firmware = await firmware_1.FirmwareFileModel.create(firmwareData);
- loggerService_1.LoggerService.info('固件上传成功', {
- source: 'ota',
- module: 'upload_firmware',
- details: JSON.stringify({
- firmwareId: firmware.id,
- version,
- filename: newFilename,
- filesize: file.size,
- md5sum,
- createdBy: req.user?.id || 'system'
- })
- }).catch(err => {
- console.error('固件上传成功日志写入失败:', err);
- });
- res.status(201).json({
- success: true,
- message: 'Firmware uploaded successfully',
- data: firmware
- });
- }
- catch (error) {
- console.error('Error uploading firmware:', error);
- loggerService_1.LoggerService.error('固件上传失败', {
- source: 'ota',
- module: 'upload_firmware',
- details: JSON.stringify({
- error: error instanceof Error ? error.message : '未知错误',
- version: req.body.version,
- filename: req.file?.originalname
- })
- }).catch(err => {
- console.error('固件上传失败日志写入失败:', err);
- });
- res.status(500).json({
- success: false,
- message: 'Failed to upload firmware',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async getFirmwareFiles(req, res) {
- try {
- const firmwareFiles = await firmware_1.FirmwareFileModel.getAll();
- res.status(200).json({
- success: true,
- message: '固件文件列表获取成功',
- data: firmwareFiles
- });
- }
- catch (error) {
- console.error('Error getting firmware files:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to get firmware files',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async deleteFirmware(req, res) {
- try {
- const id = parseInt((0, helpers_1.toString)(req.params.id));
- const firmware = await firmware_1.FirmwareFileModel.getById(id);
- if (!firmware) {
- res.status(404).json({
- success: false,
- message: 'Firmware not found',
- error: 'Firmware not found'
- });
- return;
- }
- try {
- await promises_1.default.access(firmware.filepath);
- await promises_1.default.unlink(firmware.filepath);
- }
- catch (error) {
- console.error('Error deleting firmware file:', error);
- }
- await firmware_1.FirmwareFileModel.delete(id);
- res.status(200).json({
- success: true,
- message: 'Firmware deleted successfully'
- });
- }
- catch (error) {
- console.error('Error deleting firmware:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to delete firmware',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async createOTATask(req, res) {
- try {
- const deviceId = (0, helpers_1.toString)(req.params.deviceId);
- const firmwareId = parseInt(req.body.firmwareId);
- const device = await device_1.DeviceModel.getByClientId(deviceId);
- if (!device) {
- res.status(404).json({
- success: false,
- message: 'Device not found',
- error: 'Device not found'
- });
- return;
- }
- const firmware = await firmware_1.FirmwareFileModel.getById(firmwareId);
- if (!firmware) {
- res.status(404).json({
- success: false,
- message: 'Firmware not found',
- error: 'Firmware not found'
- });
- return;
- }
- const taskData = {
- device_id: deviceId,
- firmware_id: firmwareId,
- status: 'pending',
- progress: 0,
- start_time: new Date()
- };
- const task = await ota_1.OTATaskModel.create(taskData);
- await this.logOTAToSystemLog(deviceId, `OTA升级任务已创建,固件版本: ${firmware.version}`, 'info', {
- taskId: task.id,
- firmwareId: firmware.id,
- firmwareVersion: firmware.version,
- status: 'pending'
- });
- if (device.status === 'online') {
- const mqttBroker = mqttBrokerService_1.MqttBrokerService.getInstance();
- let otaServerUrl = process.env.OTA_SERVER_URL || process.env.BACKEND_URL || 'http://localhost:3002';
- otaServerUrl = otaServerUrl.replace(/\/$/, '');
- console.log('OTA Server URL:', otaServerUrl);
- console.log('Environment OTA_SERVER_URL:', process.env.OTA_SERVER_URL);
- console.log('Environment BACKEND_URL:', process.env.BACKEND_URL);
- const otaCommand = {
- act: 'upgrade',
- ver: firmware.version,
- url: `${otaServerUrl}/api/ota/firmware/${firmware.id}`,
- md5: firmware.md5sum,
- tid: task.id
- };
- console.log('OTA升级指令:', JSON.stringify(otaCommand, null, 2));
- console.log('MQTT Topic:', `device/${deviceId}/ota`);
- mqttBroker.publish(`device/${deviceId}/ota`, JSON.stringify(otaCommand));
- loggerService_1.LoggerService.info('OTA升级任务创建成功', {
- source: 'ota',
- module: 'create_ota_task',
- details: JSON.stringify({
- taskId: task.id,
- deviceId,
- deviceName: device.device_name,
- firmwareId: firmware.id,
- firmwareVersion: firmware.version,
- firmwareUrl: `${otaServerUrl}/api/ota/firmware/${firmware.id}`,
- deviceStatus: 'online',
- createdBy: req.user?.id || 'system'
- })
- }).catch(err => {
- console.error('OTA任务创建成功日志写入失败:', err);
- });
- }
- else {
- loggerService_1.LoggerService.info('OTA升级任务已创建(设备离线,等待上线后执行)', {
- source: 'ota',
- module: 'create_ota_task',
- details: JSON.stringify({
- taskId: task.id,
- deviceId,
- deviceName: device.device_name,
- firmwareId: firmware.id,
- firmwareVersion: firmware.version,
- deviceStatus: 'offline'
- })
- }).catch(err => {
- console.error('OTA离线任务创建日志写入失败:', err);
- });
- }
- res.status(201).json({
- success: true,
- message: device.status === 'online' ? 'OTA task created successfully' : 'OTA task created (device offline, will execute when online)',
- data: task
- });
- }
- catch (error) {
- console.error('Error creating OTA task:', error);
- loggerService_1.LoggerService.error('OTA升级任务创建失败', {
- source: 'ota',
- module: 'create_ota_task',
- details: JSON.stringify({
- deviceId: (0, helpers_1.toString)(req.params.deviceId),
- firmwareId: req.body.firmwareId,
- error: error instanceof Error ? error.message : '未知错误'
- })
- }).catch(err => {
- console.error('OTA任务创建失败日志写入失败:', err);
- });
- res.status(500).json({
- success: false,
- message: 'Failed to create OTA task',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async getDeviceOTATasks(req, res) {
- try {
- const deviceId = (0, helpers_1.toString)(req.params.deviceId);
- const tasks = await ota_1.OTATaskModel.getByDeviceId(deviceId);
- res.status(200).json({
- success: true,
- message: 'Device OTA tasks retrieved successfully',
- data: tasks
- });
- }
- catch (error) {
- console.error('Error getting device OTA tasks:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to get device OTA tasks',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async getAllOTATasks(req, res) {
- try {
- const tasks = await ota_1.OTATaskModel.getAll();
- res.status(200).json({
- success: true,
- message: 'All OTA tasks retrieved successfully',
- data: tasks
- });
- }
- catch (error) {
- console.error('Error getting all OTA tasks:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to get all OTA tasks',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async downloadFirmware(req, res) {
- try {
- const id = parseInt((0, helpers_1.toString)(req.params.id));
- const firmware = await firmware_1.FirmwareFileModel.getById(id);
- if (!firmware) {
- res.status(404).json({
- success: false,
- message: 'Firmware not found',
- error: '固件文件不存在'
- });
- return;
- }
- try {
- await promises_1.default.access(firmware.filepath);
- }
- catch {
- res.status(404).json({
- success: false,
- message: 'Firmware file not found on server',
- error: '服务器上不存在固件文件'
- });
- return;
- }
- res.download(firmware.filepath, firmware.filename);
- }
- catch (error) {
- console.error('Error downloading firmware:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to download firmware',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async updateOTATaskStatus(req, res) {
- try {
- const taskId = parseInt((0, helpers_1.toString)(req.params.taskId));
- const { status, progress, error_message } = req.body;
- const task = await ota_1.OTATaskModel.getById(taskId);
- if (!task) {
- res.status(404).json({
- success: false,
- message: 'OTA task not found',
- error: 'OTA任务不存在'
- });
- return;
- }
- if (status && progress !== undefined) {
- await ota_1.OTATaskModel.updateStatusAndProgress(taskId, status, progress);
- await this.logOTAToSystemLog(task.device_id, `OTA升级进度更新: ${progress}%, 状态: ${status}`, 'info', {
- taskId,
- status,
- progress
- });
- }
- if (status === 'success' || status === 'failed') {
- await ota_1.OTATaskModel.updateResult(taskId, status, error_message);
- if (status === 'success') {
- const firmware = await firmware_1.FirmwareFileModel.getById(task.firmware_id);
- if (firmware) {
- await device_1.DeviceModel.update(task.device_id, { firmware_version: firmware.version });
- }
- await this.logOTAToSystemLog(task.device_id, `OTA升级成功,固件版本已更新`, 'info', {
- taskId,
- firmwareId: task.firmware_id,
- status: 'success',
- progress: 100
- });
- loggerService_1.LoggerService.info('OTA升级任务完成', {
- source: 'ota',
- module: 'update_ota_task_status',
- details: JSON.stringify({
- taskId,
- deviceId: task.device_id,
- firmwareId: task.firmware_id,
- status: 'success',
- progress: 100
- })
- }).catch(err => {
- console.error('OTA升级成功日志写入失败:', err);
- });
- }
- else {
- await this.logOTAToSystemLog(task.device_id, `OTA升级失败: ${error_message || '未知错误'}`, 'error', {
- taskId,
- firmwareId: task.firmware_id,
- status: 'failed',
- errorMessage: error_message
- });
- loggerService_1.LoggerService.error('OTA升级任务失败', {
- source: 'ota',
- module: 'update_ota_task_status',
- details: JSON.stringify({
- taskId,
- deviceId: task.device_id,
- firmwareId: task.firmware_id,
- status: 'failed',
- errorMessage: error_message || '未知错误'
- })
- }).catch(err => {
- console.error('OTA升级失败日志写入失败:', err);
- });
- }
- }
- res.status(200).json({
- success: true,
- message: 'OTA task status updated successfully',
- data: { taskId, status, progress }
- });
- }
- catch (error) {
- console.error('Error updating OTA task status:', error);
- loggerService_1.LoggerService.error('OTA任务状态更新失败', {
- source: 'ota',
- module: 'update_ota_task_status',
- details: JSON.stringify({
- taskId: req.params.taskId,
- status: req.body.status,
- progress: req.body.progress,
- error: error instanceof Error ? error.message : '未知错误'
- })
- }).catch(err => {
- console.error('OTA任务状态更新失败日志写入失败:', err);
- });
- res.status(500).json({
- success: false,
- message: 'Failed to update OTA task status',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async cancelOTATask(req, res) {
- try {
- const taskId = parseInt((0, helpers_1.toString)(req.params.taskId));
- const task = await ota_1.OTATaskModel.getById(taskId);
- if (!task) {
- res.status(404).json({
- success: false,
- message: 'OTA task not found',
- error: 'OTA任务不存在'
- });
- return;
- }
- if (!['pending', 'downloading', 'installing'].includes(task.status)) {
- res.status(400).json({
- success: false,
- message: 'Only pending, downloading, or installing tasks can be cancelled',
- error: '只有待处理、下载中或安装中的任务可以取消'
- });
- return;
- }
- await ota_1.OTATaskModel.updateResult(taskId, 'failed', '用户取消');
- await this.logOTAToSystemLog(task.device_id, `OTA升级任务已取消`, 'warn', {
- taskId,
- status: 'failed',
- reason: '用户取消'
- });
- res.status(200).json({
- success: true,
- message: 'OTA task cancelled successfully',
- data: { taskId, status: 'failed' }
- });
- }
- catch (error) {
- console.error('Error cancelling OTA task:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to cancel OTA task',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async retryOTATask(req, res) {
- try {
- const taskId = parseInt((0, helpers_1.toString)(req.params.taskId));
- const task = await ota_1.OTATaskModel.getById(taskId);
- if (!task) {
- res.status(404).json({
- success: false,
- message: 'OTA task not found',
- error: 'OTA任务不存在'
- });
- return;
- }
- if (!['failed', 'pending'].includes(task.status)) {
- res.status(400).json({
- success: false,
- message: 'Only failed or pending tasks can be retried',
- error: '只有失败或待处理的任务可以重试'
- });
- return;
- }
- const device = await device_1.DeviceModel.getByClientId(task.device_id);
- if (!device) {
- res.status(404).json({
- success: false,
- message: 'Device not found',
- error: '设备不存在'
- });
- return;
- }
- const firmware = await firmware_1.FirmwareFileModel.getById(task.firmware_id);
- if (!firmware) {
- res.status(404).json({
- success: false,
- message: 'Firmware not found',
- error: '固件不存在'
- });
- return;
- }
- await ota_1.OTATaskModel.updateStatusAndProgress(taskId, 'pending', 0);
- const mqttBroker = mqttBrokerService_1.MqttBrokerService.getInstance();
- let otaServerUrl = process.env.OTA_SERVER_URL || process.env.BACKEND_URL || 'http://localhost:3002';
- otaServerUrl = otaServerUrl.replace(/\/$/, '');
- const otaCommand = {
- act: 'upgrade',
- ver: firmware.version,
- url: `${otaServerUrl}/api/ota/firmware/${firmware.id}`,
- md5: firmware.md5sum,
- tid: taskId
- };
- console.log('OTA升级指令(重试):', JSON.stringify(otaCommand, null, 2));
- console.log('MQTT Topic:', `device/${task.device_id}/ota`);
- mqttBroker.publish(`device/${task.device_id}/ota`, JSON.stringify(otaCommand));
- await this.logOTAToSystemLog(task.device_id, `OTA升级任务已重试,固件版本: ${firmware.version}`, 'info', {
- taskId,
- firmwareId: firmware.id,
- firmwareVersion: firmware.version,
- status: 'pending'
- });
- res.status(200).json({
- success: true,
- message: 'OTA task retried successfully',
- data: { taskId, status: 'pending' }
- });
- }
- catch (error) {
- console.error('Error retrying OTA task:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to retry OTA task',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async deleteOTATask(req, res) {
- try {
- const taskId = parseInt((0, helpers_1.toString)(req.params.taskId));
- const task = await ota_1.OTATaskModel.getById(taskId);
- if (!task) {
- res.status(404).json({
- success: false,
- message: 'OTA task not found',
- error: 'OTA任务不存在'
- });
- return;
- }
- if (!['pending', 'failed'].includes(task.status)) {
- res.status(400).json({
- success: false,
- message: 'Only pending or failed tasks can be deleted',
- error: '只有待处理或失败的任务可以删除'
- });
- return;
- }
- await ota_1.OTATaskModel.delete(taskId);
- await this.logOTAToSystemLog(task.device_id, `OTA升级任务已删除`, 'info', {
- taskId,
- status: task.status,
- reason: '手动删除'
- });
- res.status(200).json({
- success: true,
- message: 'OTA task deleted successfully',
- data: { taskId }
- });
- }
- catch (error) {
- console.error('Error deleting OTA task:', error);
- res.status(500).json({
- success: false,
- message: 'Failed to delete OTA task',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- static async bulkCreateOTATask(req, res) {
- try {
- const { firmwareId, deviceIds, retryCount = 3, retryInterval = 10000, timeout = 30000 } = req.body;
- if (!Array.isArray(deviceIds) || deviceIds.length === 0) {
- res.status(400).json({
- success: false,
- message: 'Device IDs must be a non-empty array',
- error: '设备ID必须是非空数组'
- });
- return;
- }
- const firmware = await firmware_1.FirmwareFileModel.getById(firmwareId);
- if (!firmware) {
- res.status(404).json({
- success: false,
- message: 'Firmware not found',
- error: '固件不存在'
- });
- return;
- }
- const validDevices = [];
- const invalidDevices = [];
- for (const deviceId of deviceIds) {
- const device = await device_1.DeviceModel.getByClientId(deviceId);
- if (device) {
- validDevices.push(deviceId);
- }
- else {
- invalidDevices.push(deviceId);
- }
- }
- if (validDevices.length === 0) {
- res.status(404).json({
- success: false,
- message: 'No valid devices found',
- error: '未找到有效设备'
- });
- return;
- }
- const createdTasks = [];
- const onlineTasks = [];
- const offlineTasks = [];
- const mqttBroker = mqttBrokerService_1.MqttBrokerService.getInstance();
- const otaServerUrl = process.env.OTA_SERVER_URL || process.env.BACKEND_URL || 'http://localhost:3002';
- for (const deviceId of validDevices) {
- const device = await device_1.DeviceModel.getByClientId(deviceId);
- const taskData = {
- device_id: deviceId,
- firmware_id: firmwareId,
- status: 'pending',
- progress: 0,
- start_time: new Date()
- };
- const task = await ota_1.OTATaskModel.create(taskData);
- createdTasks.push(task);
- if (device && device.status === 'online') {
- onlineTasks.push({ taskId: task.id, deviceId });
- const otaCommand = {
- act: 'upgrade',
- ver: firmware.version,
- url: `${otaServerUrl}/api/ota/firmware/${firmware.id}`,
- md5: firmware.md5sum,
- tid: task.id,
- rc: retryCount,
- ri: retryInterval,
- to: timeout
- };
- console.log('OTA升级指令(批量):', JSON.stringify(otaCommand, null, 2));
- console.log('MQTT Topic:', `device/${deviceId}/ota`);
- mqttBroker.publish(`device/${deviceId}/ota`, JSON.stringify(otaCommand));
- }
- else {
- offlineTasks.push({ taskId: task.id, deviceId });
- console.log(`设备 ${deviceId} 离线,OTA任务 ${task.id} 将在设备上线后自动执行`);
- }
- }
- loggerService_1.LoggerService.info('批量OTA任务创建完成', {
- source: 'ota',
- module: 'bulk_create_ota_task',
- details: JSON.stringify({
- totalTasks: createdTasks.length,
- onlineTasks: onlineTasks.length,
- offlineTasks: offlineTasks.length,
- invalidDevices: invalidDevices.length
- })
- }).catch(err => {
- console.error('批量OTA任务创建日志写入失败:', err);
- });
- res.status(201).json({
- success: true,
- message: `批量OTA任务创建成功(在线设备: ${onlineTasks.length}, 离线设备: ${offlineTasks.length})`,
- data: {
- tasks: createdTasks,
- validDevices: validDevices.length,
- invalidDevices: invalidDevices,
- onlineTasks: onlineTasks.length,
- offlineTasks: offlineTasks.length
- }
- });
- }
- catch (error) {
- console.error('Error creating bulk OTA tasks:', error);
- res.status(500).json({
- success: false,
- message: '批量OTA任务创建失败',
- error: error instanceof Error ? error.message : '未知错误'
- });
- }
- }
- }
- exports.OtaController = OtaController;
- //# sourceMappingURL=otaController.js.map
|