node-red-contrib-hik-media-buffer 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/hik-media-buffer.js +33 -53
  2. package/package.json +1 -1
@@ -1,20 +1,15 @@
1
- const axios = require('axios');
1
+ const urllib = require('urllib');
2
2
  const https = require('https');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
6
  const { exec } = require('child_process');
7
7
 
8
- // --- STRATEGIA SWITCH: DEFINIZIONE MODALITÀ ---
9
- // Valori possibili: 'digest', 'basic', 'bearer'
10
- const AUTH_MODE = 'digest';
11
-
12
8
  module.exports = function(RED) {
13
9
  function HikMediaBufferNode(config) {
14
10
  RED.nodes.createNode(this, config);
15
11
  const node = this;
16
12
 
17
- // --- ASSEGNAZIONE PROPRIETÀ ---
18
13
  node.name = config.name;
19
14
  node.host = config.host;
20
15
  node.port = config.port || "80";
@@ -30,7 +25,6 @@ module.exports = function(RED) {
30
25
  let nvrOnline = true;
31
26
  let statoCamera = {};
32
27
 
33
- const httpsAgent = new https.Agent({ rejectUnauthorized: false });
34
28
  const tempDir = os.tmpdir();
35
29
  const EventList = ["FieldDetection", "LineDetection"];
36
30
 
@@ -38,7 +32,24 @@ module.exports = function(RED) {
38
32
 
39
33
  function toHikDate(d) { return d.toISOString().split('.')[0] + "Z"; }
40
34
 
41
- // --- PRENDE IL NOME DELLA TELECAMERA ---
35
+ // --- HELPER AGGIORNATO: Solo Urllib con Digest ---
36
+ async function hikRequest(options) {
37
+ const { method, url, data, responseType, user, pass, headers = {} } = options;
38
+
39
+ const res = await urllib.request(url, {
40
+ method: method,
41
+ digestAuth: `${user}:${pass}`,
42
+ content: data,
43
+ headers: headers,
44
+ dataType: responseType === 'arraybuffer' ? 'buffer' : 'text',
45
+ timeout: 15000,
46
+ rejectUnauthorized: false
47
+ });
48
+
49
+ // Urllib restituisce i dati in .data
50
+ return res;
51
+ }
52
+
42
53
  async function getCameraName(cam) {
43
54
  try {
44
55
  const res = await hikRequest({
@@ -47,40 +58,13 @@ module.exports = function(RED) {
47
58
  user: node.user,
48
59
  pass: node.camPass
49
60
  });
50
- const match = res.data.match(/<name>([^<]+)<\/name>/);
61
+ const match = res.data.toString().match(/<name>([^<]+)<\/name>/);
51
62
  return match ? match[1] : `Cam_${cam.channel}`;
52
63
  } catch (e) {
53
- return `Camera_${cam.ip}`; // Fallback se la camera è già offline
64
+ return `Camera_${cam.ip}`;
54
65
  }
55
66
  }
56
67
 
57
- // --- HELPER UNICO PER LE CHIAMATE (STRATEGIA SWITCH) ---
58
- async function hikRequest(options) {
59
- const { method, url, data, responseType, user, pass, headers = {} } = options;
60
-
61
- const requestConfig = {
62
- method,
63
- url,
64
- data,
65
- responseType: responseType || 'data',
66
- httpsAgent: node.protocol === "https" ? httpsAgent : undefined,
67
- timeout: 10000,
68
- headers: { ...headers }
69
- };
70
-
71
- // LOGICA DI AUTENTICAZIONE
72
- if (AUTH_MODE === 'digest' || AUTH_MODE === 'basic') {
73
- // Axios gestisce Basic/Digest internamente se configurato così:
74
- requestConfig.auth = { username: user, password: pass };
75
- } else if (AUTH_MODE === 'bearer') {
76
- // Esempio per Token futuro
77
- requestConfig.headers['Authorization'] = `Bearer ${node.context().get('myToken')}`;
78
- }
79
-
80
- return axios(requestConfig);
81
- }
82
-
83
- // --- CONTROLLO ONLINE TELECAMERE ---
84
68
  async function checkCameras() {
85
69
  if (isClosing) return;
86
70
  for (let cam of node.cameras) {
@@ -123,17 +107,15 @@ module.exports = function(RED) {
123
107
 
124
108
  const heartbeatInterval = setInterval(checkCameras, 30000);
125
109
 
126
- // --- FUNZIONE DOWNLOAD MEDIA ---
127
110
  async function downloadMedia(evento, channelID) {
128
111
  const camera = node.cameras.find(c => c.channel == channelID);
129
- const nomeCamera = await getCameraName(camera);
130
-
131
112
  if (!camera) return;
132
113
 
133
114
  const nowTime = Date.now();
134
115
  if (nowTime - lastTriggerTime < 10000) return;
135
116
  lastTriggerTime = nowTime;
136
117
 
118
+ const nomeCamera = await getCameraName(camera);
137
119
  const referenceTime = new Date();
138
120
  const startTime = toHikDate(new Date(referenceTime.getTime() - (10 * 1000)));
139
121
  const endTime = toHikDate(new Date(referenceTime.getTime() + (10 * 1000)));
@@ -145,6 +127,7 @@ module.exports = function(RED) {
145
127
  let output = { ip: camera.ip, nomeCliente: node.name, nome_telecamera: nomeCamera, channel: channelID, event: evento, videoPath: null, imageBuffer: null };
146
128
 
147
129
  try {
130
+ // RIPRISTINATA LA TUA LOGICA DEI TRACKS
148
131
  const tracks = [{ name: "termicoV", id: "201" }, { name: "termico", id: "203" }];
149
132
  for (let t of tracks) {
150
133
  const searchXml = `<?xml version="1.0" encoding="utf-8"?>
@@ -165,7 +148,7 @@ module.exports = function(RED) {
165
148
  pass: node.camPass
166
149
  });
167
150
 
168
- let xml = resSearch.data.replace(/<(\/?)\w+:/g, "<$1");
151
+ let xml = resSearch.data.toString().replace(/<(\/?)\w+:/g, "<$1");
169
152
  const uriMatch = xml.match(/<playbackURI>([^<]+)</);
170
153
 
171
154
  if (uriMatch) {
@@ -208,26 +191,24 @@ module.exports = function(RED) {
208
191
  updateNodeStatus();
209
192
  }
210
193
 
211
- // --- GESTIONE NVR ALERT STREAM ---
212
194
  function startAlertStream() {
213
195
  if (isClosing) return;
214
196
  const url = `${node.protocol}://${node.host}:${node.port}/ISAPI/Event/notification/alertStream`;
215
197
 
216
- hikRequest({
198
+ urllib.request(url, {
217
199
  method: 'GET',
218
- url: url,
219
- responseType: 'stream',
220
- user: node.user,
221
- pass: node.pass
222
- }).then(response => {
223
- streamRequest = response;
200
+ digestAuth: `${node.user}:${node.pass}`,
201
+ streaming: true,
202
+ timeout: 60000,
203
+ rejectUnauthorized: false
204
+ }).then(res => {
224
205
  if (!nvrOnline) {
225
206
  node.send({ payload: { status: "online", ip: node.host, msg: "NVR Online" } });
226
207
  nvrOnline = true;
227
208
  }
228
209
  updateNodeStatus();
229
210
 
230
- response.data.on('data', (chunk) => {
211
+ res.res.on('data', (chunk) => {
231
212
  const data = chunk.toString().toLowerCase();
232
213
  if (data.includes("active")) {
233
214
  const chMatch = data.match(/<channelid>(\d+)<\/channelid>/i);
@@ -239,8 +220,8 @@ module.exports = function(RED) {
239
220
  }
240
221
  });
241
222
 
242
- response.data.on('error', () => handleNvrError());
243
- response.data.on('end', () => !isClosing && setTimeout(startAlertStream, 5000));
223
+ res.res.on('error', () => handleNvrError());
224
+ res.res.on('end', () => !isClosing && setTimeout(startAlertStream, 5000));
244
225
  }).catch(() => handleNvrError());
245
226
  }
246
227
 
@@ -259,7 +240,6 @@ module.exports = function(RED) {
259
240
  node.on('close', (done) => {
260
241
  isClosing = true;
261
242
  clearInterval(heartbeatInterval);
262
- if (streamRequest && streamRequest.data) streamRequest.data.destroy();
263
243
  done();
264
244
  });
265
245
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-hik-media-buffer",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Ottiene buffer video e immagine da camere Hikvision via ISAPI",
5
5
  "keywords": [
6
6
  "node-red",