@mmote/niimblue-node
Version:
Headless clients for niimbluelib. Command line interface, simple REST server are also included.
150 lines (149 loc) • 5.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scan = exports.print = exports.rfid = exports.info = exports.connected = exports.disconnect = exports.connect = exports.index = exports.setDebug = void 0;
const niimbluelib_1 = require("@mmote/niimbluelib");
const sharp_1 = __importDefault(require("sharp"));
const zod_1 = require("zod");
const headless_ble_impl_1 = require("../client/headless_ble_impl");
const image_encoder_1 = require("../image_encoder");
const utils_1 = require("../utils");
const simple_server_1 = require("./simple_server");
const headless_serial_impl_1 = require("../client/headless_serial_impl");
let client = null;
let debug = false;
const ConnectSchema = zod_1.z.object({
transport: zod_1.z.enum(["serial", "ble"]),
address: zod_1.z.string(),
});
const ScanSchema = zod_1.z.object({
transport: zod_1.z.enum(["serial", "ble"]),
timeout: zod_1.z.number().default(5000),
});
const [firstTask, ...otherTasks] = niimbluelib_1.printTaskNames;
const PrintSchema = zod_1.z
.object({
printDirection: zod_1.z.enum(["left", "top"]).optional(),
printTask: zod_1.z.enum([firstTask, ...otherTasks]).optional(),
quantity: zod_1.z.number().min(1).default(1),
labelType: zod_1.z.number().min(1).default(niimbluelib_1.LabelType.WithGaps),
density: zod_1.z.number().min(1).default(3),
imageBase64: zod_1.z.string().optional(),
imageUrl: zod_1.z.string().optional(),
labelWidth: zod_1.z.number().positive().optional(),
labelHeight: zod_1.z.number().positive().optional(),
threshold: zod_1.z.number().min(1).max(255).default(128),
imagePosition: zod_1.z
.enum(["centre", "top", "right top", "right", "right bottom", "bottom", "left bottom", "left", "left top"])
.default("centre"),
imageFit: zod_1.z.enum(["contain", "cover", "fill", "inside", "outside"]).default("contain"),
})
.refine(({ imageUrl, imageBase64 }) => {
return !!imageUrl !== !!imageBase64;
}, { message: "imageUrl or imageBase64 must be defined", path: ["image"] });
const setDebug = (v) => {
debug = v;
};
exports.setDebug = setDebug;
const assertConnected = () => {
if (!client?.isConnected()) {
throw new simple_server_1.RestError("Not connected", 400);
}
};
const index = () => ({ message: "Server is working" });
exports.index = index;
const connect = async (r) => {
const data = await (0, simple_server_1.readBodyJson)(r, ConnectSchema);
if (client?.isConnected()) {
throw new simple_server_1.RestError("Already connected", 400);
}
client = (0, utils_1.initClient)(data.transport, data.address, debug);
await client.connect();
return { message: "Connected" };
};
exports.connect = connect;
const disconnect = async () => {
assertConnected();
await client.disconnect();
client = null;
return { message: "Disconnected" };
};
exports.disconnect = disconnect;
const connected = async () => {
return { connected: !!client?.isConnected() };
};
exports.connected = connected;
const info = async () => {
assertConnected();
return {
printerInfo: client.getPrinterInfo(),
modelMetadata: client.getModelMetadata(),
detectedPrintTask: client.getPrintTaskType(),
};
};
exports.info = info;
const rfid = async () => {
assertConnected();
const paperRfidInfo = await client.abstraction.rfidInfo();
let ribbonRfidInfo;
try {
ribbonRfidInfo = await client.abstraction.rfidInfo2();
}
catch (ignored) { }
return { paperRfidInfo, ribbonRfidInfo };
};
exports.rfid = rfid;
const print = async (r) => {
assertConnected();
const options = await (0, simple_server_1.readBodyJson)(r, PrintSchema);
let image;
if (options.imageBase64 !== undefined) {
image = await (0, utils_1.loadImageFromBase64)(options.imageBase64);
}
else if (options.imageUrl !== undefined) {
image = await (0, utils_1.loadImageFromUrl)(options.imageUrl);
}
else {
throw new simple_server_1.RestError("Image is not defined", 400);
}
image = image.flatten({ background: "#fff" });
if (options.labelWidth !== undefined && options.labelHeight !== undefined) {
image = image.resize(options.labelWidth, options.labelHeight, {
kernel: sharp_1.default.kernel.nearest,
fit: options.imageFit,
position: options.imagePosition,
background: "#fff",
});
}
image = image.threshold(options.threshold);
// await image.toFile("tmp.png");
const printDirection = options.printDirection ?? client.getModelMetadata()?.printDirection;
const printTask = options.printTask ?? client.getPrintTaskType();
const encoded = await image_encoder_1.ImageEncoder.encodeImage(image, printDirection);
if (printTask === undefined) {
throw new simple_server_1.RestError("Unable to detect print task, please set it manually", 400);
}
if (debug) {
console.log("Print task:", printTask);
}
await (0, utils_1.printImage)(client, printTask, encoded, {
quantity: options.quantity,
labelType: options.labelType,
density: options.density,
});
return { message: "Printed" };
};
exports.print = print;
const scan = async (r) => {
const options = await (0, simple_server_1.readBodyJson)(r, ScanSchema);
if (options.transport === "ble") {
return { devices: await headless_ble_impl_1.NiimbotHeadlessBleClient.scan(options.timeout) };
}
else if (options.transport === "serial") {
return { devices: await headless_serial_impl_1.NiimbotHeadlessSerialClient.scan() };
}
throw new simple_server_1.RestError("Invalid transport", 400);
};
exports.scan = scan;