node-red-contrib-tcp-escpos 0.1.4 → 0.2.0
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.
- package/nodes/node.js +136 -150
- package/nodes/utilities/encodeText.js +13 -0
- package/nodes/utilities/queue.js +31 -0
- package/nodes/utilities/socketWrite.js +72 -0
- package/package.json +3 -2
package/nodes/node.js
CHANGED
|
@@ -11,22 +11,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
|
-
const
|
|
14
|
+
const enqueue_task_1 = require("enqueue-task");
|
|
15
15
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
16
|
-
const node_net_1 = __importDefault(require("node:net"));
|
|
17
16
|
const node_url_1 = require("node:url");
|
|
18
17
|
const skia_canvas_1 = require("skia-canvas");
|
|
19
18
|
const dither_1 = require("./utilities/dither");
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
socket.once('connect', () => resolve(socket));
|
|
23
|
-
socket.once('error', (error) => reject(error));
|
|
24
|
-
});
|
|
25
|
-
const encodeText = (text) => {
|
|
26
|
-
// Remove all characters that are not letters, numbers, punctuation or whitespace printers cannot handle emojis
|
|
27
|
-
const filtered = text.replaceAll(/[^\p{L}\p{N}\p{P}\p{Z}\n\r×]+/gu, '');
|
|
28
|
-
return iconv_lite_1.default.encode(filtered, 'CP852');
|
|
29
|
-
};
|
|
19
|
+
const encodeText_1 = require("./utilities/encodeText");
|
|
20
|
+
const socketWrite_1 = require("./utilities/socketWrite");
|
|
30
21
|
const allowedPayloadTypes = ['text', 'image', 'buffer'];
|
|
31
22
|
module.exports = function (RED) {
|
|
32
23
|
function TcpEscposNode(configuration) {
|
|
@@ -35,166 +26,161 @@ module.exports = function (RED) {
|
|
|
35
26
|
this.status({});
|
|
36
27
|
});
|
|
37
28
|
this.on('input', (message, _send, done) => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
commands.push(encodeText(String(payload)));
|
|
53
|
-
commands.push(Buffer.from([0x0a])); // New line
|
|
54
|
-
return Buffer.concat(commands);
|
|
29
|
+
const { host, port } = (() => {
|
|
30
|
+
const hostname = message.host || configuration.host || null;
|
|
31
|
+
const url = new node_url_1.URL(`tcp://${hostname}`);
|
|
32
|
+
const { hostname: host } = url;
|
|
33
|
+
const port = Number(url.port) || 9100;
|
|
34
|
+
return { host: hostname ? host : null, port };
|
|
35
|
+
})();
|
|
36
|
+
const error = yield (0, enqueue_task_1.getQueueGroup)(host).enqueueTask(() => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
this.status({ fill: 'yellow', shape: 'dot', text: 'processing…' });
|
|
38
|
+
const error = yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
try {
|
|
41
|
+
if (!host) {
|
|
42
|
+
throw new Error('Host is not defined');
|
|
55
43
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
44
|
+
const cutAfter = (_a = message.cutAfter) !== null && _a !== void 0 ? _a : configuration.cutAfter;
|
|
45
|
+
const dotsPerLine = (_b = message.dotsPerLine) !== null && _b !== void 0 ? _b : configuration.dotsPerLine;
|
|
46
|
+
const payload = yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
const payloadType = allowedPayloadTypes.find((type) => type === message.type) ||
|
|
48
|
+
configuration.payloadType;
|
|
49
|
+
const payload = message.payload || configuration.payload;
|
|
50
|
+
if (payloadType === 'text') {
|
|
51
|
+
const commands = [];
|
|
52
|
+
commands.push(Buffer.from([0x1b, 0x40])); // Initialize printer
|
|
53
|
+
commands.push(Buffer.from([0x1b, 0x74, 18])); // Language options: 18 is CP852 code table
|
|
54
|
+
commands.push(Buffer.from([0x1b, 0x61, 1])); // Center alignment
|
|
55
|
+
commands.push((0, encodeText_1.encodeText)(String(payload)));
|
|
56
|
+
commands.push(Buffer.from([0x0a])); // New line
|
|
57
|
+
return Buffer.concat(commands);
|
|
58
|
+
}
|
|
59
|
+
if (payloadType === 'image') {
|
|
60
|
+
const imageBuffer = yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
if (Buffer.isBuffer(payload)) {
|
|
62
|
+
return payload;
|
|
65
63
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
url.protocol === 'file:') {
|
|
71
|
-
const response = yield fetch(url.toString());
|
|
72
|
-
return Buffer.from(yield response.arrayBuffer());
|
|
64
|
+
if (typeof payload === 'string') {
|
|
65
|
+
if (payload.startsWith('data:image/')) {
|
|
66
|
+
const base64 = payload.split(',', 2)[1];
|
|
67
|
+
return Buffer.from(base64, 'base64');
|
|
73
68
|
}
|
|
74
|
-
}
|
|
75
|
-
catch (_c) { }
|
|
76
|
-
const base64Pattern = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
77
|
-
if (payload.length % 4 === 0 && base64Pattern.test(payload)) {
|
|
78
|
-
return Buffer.from(payload, 'base64');
|
|
79
|
-
}
|
|
80
|
-
const isFilePath = yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
81
69
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
const url = new node_url_1.URL(payload);
|
|
71
|
+
if (url.protocol === 'http:' ||
|
|
72
|
+
url.protocol === 'https:' ||
|
|
73
|
+
url.protocol === 'file:') {
|
|
74
|
+
const response = yield fetch(url.toString());
|
|
75
|
+
return Buffer.from(yield response.arrayBuffer());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (_a) { }
|
|
79
|
+
const base64Pattern = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
80
|
+
if (payload.length % 4 === 0 &&
|
|
81
|
+
base64Pattern.test(payload)) {
|
|
82
|
+
return Buffer.from(payload, 'base64');
|
|
83
|
+
}
|
|
84
|
+
const isFilePath = yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
try {
|
|
86
|
+
yield promises_1.default.access(payload);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
catch (_a) { }
|
|
90
|
+
return false;
|
|
91
|
+
}))();
|
|
92
|
+
if (isFilePath) {
|
|
93
|
+
return promises_1.default.readFile(payload);
|
|
84
94
|
}
|
|
85
|
-
catch (_d) { }
|
|
86
|
-
return false;
|
|
87
|
-
}))();
|
|
88
|
-
if (isFilePath) {
|
|
89
|
-
return promises_1.default.readFile(payload);
|
|
90
95
|
}
|
|
96
|
+
throw new Error('Invalid image payload.');
|
|
97
|
+
}))();
|
|
98
|
+
const image = yield (0, skia_canvas_1.loadImage)(imageBuffer);
|
|
99
|
+
let imageWidth = image.width;
|
|
100
|
+
let imageHeight = image.height;
|
|
101
|
+
if (imageWidth > dotsPerLine) {
|
|
102
|
+
const aspectRatio = image.height / image.width;
|
|
103
|
+
imageWidth = dotsPerLine;
|
|
104
|
+
imageHeight = imageWidth * aspectRatio;
|
|
91
105
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const red = imageData[index];
|
|
124
|
-
const green = imageData[index + 1];
|
|
125
|
-
const blue = imageData[index + 2];
|
|
126
|
-
const alpha = imageData[index + 3];
|
|
127
|
-
const greyscale = red * 0.299 + green * 0.587 + blue * 0.114;
|
|
128
|
-
if (alpha > 127 && greyscale < 128) {
|
|
129
|
-
const byteIndex = y * bytes + (x >> 3);
|
|
130
|
-
const bit = 1 << (7 - (x & 7));
|
|
131
|
-
pixelsGroupedToBytes[byteIndex] |= bit;
|
|
106
|
+
const canvas = new skia_canvas_1.Canvas(imageWidth, imageHeight);
|
|
107
|
+
const context = canvas.getContext('2d');
|
|
108
|
+
context.drawImage(image, 0, 0, imageWidth, imageHeight);
|
|
109
|
+
(0, dither_1.dither)(canvas);
|
|
110
|
+
const payloadParts = [];
|
|
111
|
+
payloadParts.push(Buffer.from([0x1b, 0x40])); // Initialize printer
|
|
112
|
+
payloadParts.push(Buffer.from([0x1b, 0x61, 1])); // Center alignment
|
|
113
|
+
const splitImageByHeightInPixels = 1024; // Splitting image to more smaller ones because Epson printer can't handle one super heigh image
|
|
114
|
+
for (let yOffset = 0; yOffset < canvas.height; yOffset += splitImageByHeightInPixels) {
|
|
115
|
+
const chunkHeight = Math.min(splitImageByHeightInPixels, canvas.height - yOffset);
|
|
116
|
+
const { width, height, data: imageData, } = context.getImageData(0, yOffset, canvas.width, chunkHeight);
|
|
117
|
+
const bytes = (width + 7) >> 3;
|
|
118
|
+
// For xL, xH, yL, yH, see the documentation https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/gs_lv_0.html
|
|
119
|
+
const xL = bytes & 0xff;
|
|
120
|
+
const xH = bytes >> 8;
|
|
121
|
+
const yL = height & 0xff;
|
|
122
|
+
const yH = height >> 8;
|
|
123
|
+
const pixelsGroupedToBytes = Buffer.alloc(bytes * height);
|
|
124
|
+
for (let y = 0; y < height; y++) {
|
|
125
|
+
for (let x = 0; x < width; x++) {
|
|
126
|
+
const index = (y * width + x) * 4;
|
|
127
|
+
const red = imageData[index];
|
|
128
|
+
const green = imageData[index + 1];
|
|
129
|
+
const blue = imageData[index + 2];
|
|
130
|
+
const alpha = imageData[index + 3];
|
|
131
|
+
const greyscale = red * 0.299 + green * 0.587 + blue * 0.114;
|
|
132
|
+
if (alpha > 127 && greyscale < 128) {
|
|
133
|
+
const byteIndex = y * bytes + (x >> 3);
|
|
134
|
+
const bit = 1 << (7 - (x & 7));
|
|
135
|
+
pixelsGroupedToBytes[byteIndex] |= bit;
|
|
136
|
+
}
|
|
132
137
|
}
|
|
133
138
|
}
|
|
139
|
+
payloadParts.push(Buffer.from([0x1d, 0x76, 0x30, 0, xL, xH, yL, yH]));
|
|
140
|
+
payloadParts.push(pixelsGroupedToBytes);
|
|
134
141
|
}
|
|
135
|
-
|
|
136
|
-
payloadParts.push(pixelsGroupedToBytes);
|
|
137
|
-
}
|
|
138
|
-
return Buffer.concat(payloadParts);
|
|
139
|
-
}
|
|
140
|
-
if (payloadType === 'buffer') {
|
|
141
|
-
if (Buffer.isBuffer(payload)) {
|
|
142
|
-
return payload;
|
|
142
|
+
return Buffer.concat(payloadParts);
|
|
143
143
|
}
|
|
144
|
-
if (
|
|
145
|
-
|
|
144
|
+
if (payloadType === 'buffer') {
|
|
145
|
+
if (Buffer.isBuffer(payload)) {
|
|
146
|
+
return payload;
|
|
147
|
+
}
|
|
148
|
+
if (Array.isArray(payload)) {
|
|
149
|
+
return Buffer.from(payload);
|
|
150
|
+
}
|
|
151
|
+
return Buffer.from(payload, 'base64');
|
|
146
152
|
}
|
|
147
|
-
return
|
|
148
|
-
}
|
|
149
|
-
return payloadType;
|
|
150
|
-
}))();
|
|
151
|
-
this.status({ fill: 'yellow', shape: 'dot', text: 'connecting…' });
|
|
152
|
-
const hostname = message.host || configuration.host;
|
|
153
|
-
if (!hostname) {
|
|
154
|
-
throw new Error('Host is not defined');
|
|
155
|
-
}
|
|
156
|
-
const url = new node_url_1.URL(`tcp://${hostname}`);
|
|
157
|
-
const { hostname: host } = url;
|
|
158
|
-
const port = Number(url.port) || 9100;
|
|
159
|
-
const socket = yield connectTcp({ host, port });
|
|
160
|
-
this.status({ fill: 'yellow', shape: 'dot', text: 'sending…' });
|
|
161
|
-
yield new Promise((resolve, reject) => {
|
|
153
|
+
return payloadType;
|
|
154
|
+
}))();
|
|
162
155
|
const commands = Buffer.concat([
|
|
163
156
|
payload,
|
|
164
157
|
...(cutAfter
|
|
165
158
|
? [
|
|
166
|
-
Buffer.from([0x0a, 0x0a, 0x0a, 0x0a, 0x0a]),
|
|
159
|
+
Buffer.from([0x0a, 0x0a, 0x0a, 0x0a, 0x0a]), // New lines
|
|
167
160
|
Buffer.from([0x1b, 0x69]), // Cut
|
|
168
161
|
]
|
|
169
162
|
: []),
|
|
170
163
|
]);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
reject(error);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
resolve();
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
yield new Promise((resolve) => {
|
|
181
|
-
socket.end(resolve);
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
catch (error) {
|
|
185
|
-
if (error instanceof Error) {
|
|
186
|
-
return error;
|
|
164
|
+
this.status({ fill: 'yellow', shape: 'dot', text: 'sending…' });
|
|
165
|
+
yield (0, socketWrite_1.socketWrite)(host, port, commands);
|
|
187
166
|
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (error instanceof Error) {
|
|
169
|
+
return error;
|
|
170
|
+
}
|
|
171
|
+
return new Error('An unknown error occurred');
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}))();
|
|
175
|
+
if (error) {
|
|
176
|
+
this.status({ fill: 'red', shape: 'dot', text: 'failed' });
|
|
177
|
+
this.error(error.message, message);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.status({ fill: 'green', shape: 'dot', text: 'sent' });
|
|
188
181
|
}
|
|
189
|
-
return
|
|
190
|
-
}))
|
|
191
|
-
if (error) {
|
|
192
|
-
this.status({ fill: 'red', shape: 'dot', text: 'failed' });
|
|
193
|
-
this.error(error.message, message);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
this.status({ fill: 'green', shape: 'dot', text: 'sent' });
|
|
197
|
-
}
|
|
182
|
+
return error;
|
|
183
|
+
}));
|
|
198
184
|
done === null || done === void 0 ? void 0 : done(error);
|
|
199
185
|
}));
|
|
200
186
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.encodeText = void 0;
|
|
7
|
+
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
|
8
|
+
const encodeText = (text) => {
|
|
9
|
+
// Remove all characters that are not letters, numbers, punctuation or whitespace printers cannot handle emojis
|
|
10
|
+
const filtered = text.replaceAll(/[^\p{L}\p{N}\p{P}\p{Z}\n\r×]+/gu, '');
|
|
11
|
+
return iconv_lite_1.default.encode(filtered, 'CP852');
|
|
12
|
+
};
|
|
13
|
+
exports.encodeText = encodeText;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.queue = void 0;
|
|
13
|
+
const promises = {};
|
|
14
|
+
exports.queue = {
|
|
15
|
+
start: (host, port) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
var _a, _b, _c, _d, _e;
|
|
17
|
+
console.log('Awaiting', host, port, (_b = (_a = promises[host]) === null || _a === void 0 ? void 0 : _a[port]) === null || _b === void 0 ? void 0 : _b.promise);
|
|
18
|
+
yield ((_d = (_c = promises[host]) === null || _c === void 0 ? void 0 : _c[port]) === null || _d === void 0 ? void 0 : _d.promise);
|
|
19
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
20
|
+
(_e = promises[host]) !== null && _e !== void 0 ? _e : (promises[host] = {});
|
|
21
|
+
promises[host][port] = {
|
|
22
|
+
promise,
|
|
23
|
+
resolve,
|
|
24
|
+
};
|
|
25
|
+
}),
|
|
26
|
+
end: (host, port) => {
|
|
27
|
+
var _a, _b, _c, _d;
|
|
28
|
+
console.log('Resolving', host, port, (_b = (_a = promises[host]) === null || _a === void 0 ? void 0 : _a[port]) === null || _b === void 0 ? void 0 : _b.resolve);
|
|
29
|
+
(_d = (_c = promises[host]) === null || _c === void 0 ? void 0 : _c[port]) === null || _d === void 0 ? void 0 : _d.resolve();
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.socketWrite = void 0;
|
|
16
|
+
const node_net_1 = __importDefault(require("node:net"));
|
|
17
|
+
const sockets = new Map();
|
|
18
|
+
const timeouts = new Map();
|
|
19
|
+
const keepOpenAfterWriteMilliseconds = 100;
|
|
20
|
+
const connectTcp = (options) => new Promise((resolve, reject) => {
|
|
21
|
+
const socket = node_net_1.default.createConnection(options);
|
|
22
|
+
socket.once('connect', () => resolve(socket));
|
|
23
|
+
socket.once('error', (error) => reject(error));
|
|
24
|
+
});
|
|
25
|
+
const clearTimeout = (key) => {
|
|
26
|
+
const timeout = timeouts.get(key);
|
|
27
|
+
if (timeout) {
|
|
28
|
+
globalThis.clearTimeout(timeout);
|
|
29
|
+
timeouts.delete(key);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const socketWrite = (host, port, buffer) => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
|
+
const key = `${host}:${port}`;
|
|
34
|
+
let socket = sockets.get(key);
|
|
35
|
+
if (socket === null || socket === void 0 ? void 0 : socket.destroyed) {
|
|
36
|
+
socket = undefined;
|
|
37
|
+
sockets.delete(key);
|
|
38
|
+
}
|
|
39
|
+
if (!socket) {
|
|
40
|
+
socket = yield connectTcp({ host, port });
|
|
41
|
+
sockets.set(key, socket);
|
|
42
|
+
socket.on('close', () => {
|
|
43
|
+
sockets.delete(key);
|
|
44
|
+
clearTimeout(key);
|
|
45
|
+
});
|
|
46
|
+
socket.on('error', (error) => {
|
|
47
|
+
console.error('Socket error:', error);
|
|
48
|
+
sockets.delete(key);
|
|
49
|
+
clearTimeout(key);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
yield new Promise((resolve, reject) => {
|
|
53
|
+
socket.write(buffer, (error) => {
|
|
54
|
+
if (error) {
|
|
55
|
+
reject(error);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
resolve();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
// Clear previous timeout
|
|
63
|
+
clearTimeout(key);
|
|
64
|
+
// Set a new timeout to close the socket
|
|
65
|
+
timeouts.set(key, setTimeout(() => {
|
|
66
|
+
if (socket) {
|
|
67
|
+
socket.end();
|
|
68
|
+
}
|
|
69
|
+
timeouts.delete(key);
|
|
70
|
+
}, keepOpenAfterWriteMilliseconds));
|
|
71
|
+
});
|
|
72
|
+
exports.socketWrite = socketWrite;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-tcp-escpos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Escpos over TCP/IP node for Node-RED",
|
|
5
5
|
"devDependencies": {
|
|
6
6
|
"@types/node": "^18.14.0",
|
|
7
7
|
"@types/node-red": "^1.2.1",
|
|
8
|
-
"typescript": "^
|
|
8
|
+
"typescript": "^5.9.3"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"enqueue-task": "^0.4.4",
|
|
42
43
|
"iconv-lite": "^0.7.0",
|
|
43
44
|
"skia-canvas": "^3.0.8"
|
|
44
45
|
}
|