This commit is contained in:
seb
2026-10-31 20:28:37 +01:00
parent 8fece9d916
commit 72d05a34d0
27 changed files with 1546 additions and 181 deletions

View File

@@ -0,0 +1,171 @@
import { emit } from '../api/sse.js';
import { createLogger } from '../util/logger.js';
const log = createLogger('printer');
/**
* Global in-memory registry of live printer states per company.
* Structure: Map<companyId, Map<agentId, Array<LivePrinter>>>
*
* @typedef {object} LivePrinter
* @property {number} agentId
* @property {string|null} agentName
* @property {string} updatedAt
* @property {string} [model]
* @property {string} [serial]
* @property {string} [name]
* @property {string} [ip]
* @property {string} [address]
* @property {number} [labelLength]
* @property {object} [errors]
* @property {boolean} [ready]
* @property {string} [status]
*/
/** @type {Map<number, Map<number, LivePrinter[]>>} */
const companyAgents = new Map();
/**
* Normalizes an array of printer objects reported by an agent and registers them for the given company.
* Broadcasts the updated whole company printer state via SSE.
*
* @param {number} companyId
* @param {number} agentId
* @param {string|null} agentName
* @param {Array<object>} rawPrinters
* @returns {LivePrinter[]} The complete list of live printers for this company across all agents.
*/
export function updateAgentPrinters(companyId, agentId, agentName, rawPrinters) {
const cId = Number(companyId);
const aId = Number(agentId);
if (!Number.isInteger(cId) || cId <= 0 || !Number.isInteger(aId) || aId <= 0) {
return [];
}
if (!companyAgents.has(cId)) {
companyAgents.set(cId, new Map());
}
const now = new Date().toISOString();
const printerList = Array.isArray(rawPrinters) ? rawPrinters : [];
const normalized = printerList.map((p) => ({
...p,
agentId: aId,
agentName: agentName || null,
updatedAt: now,
}));
companyAgents.get(cId).set(aId, normalized);
const allCompanyPrinters = getCompanyPrinters(cId);
log.info(`Updated ${normalized.length} live printer(s) for company ${cId} (agent ${aId}, total ${allCompanyPrinters.length})`);
broadcastCompanyPrinters(cId, allCompanyPrinters);
return allCompanyPrinters;
}
/**
* Removes all printers associated with a disconnected agent and broadcasts the updated company printer state.
*
* @param {number} companyId
* @param {number} agentId
* @returns {LivePrinter[]} The remaining live printers for this company.
*/
export function removeAgentPrinters(companyId, agentId) {
const cId = Number(companyId);
const aId = Number(agentId);
if (!Number.isInteger(cId) || cId <= 0 || !Number.isInteger(aId) || aId <= 0) {
return [];
}
const agentsMap = companyAgents.get(cId);
if (!agentsMap || !agentsMap.has(aId)) {
return getCompanyPrinters(cId);
}
const removedCount = agentsMap.get(aId)?.length || 0;
agentsMap.delete(aId);
if (agentsMap.size === 0) {
companyAgents.delete(cId);
}
const remainingPrinters = getCompanyPrinters(cId);
log.info(`Removed ${removedCount} live printer(s) for disconnected agent ${aId} from company ${cId} (${remainingPrinters.length} remaining)`);
broadcastCompanyPrinters(cId, remainingPrinters);
return remainingPrinters;
}
/**
* Returns all active discovered printers for a company across all reporting agents.
*
* @param {number} companyId
* @returns {LivePrinter[]}
*/
export function getCompanyPrinters(companyId) {
const cId = Number(companyId);
const agentsMap = companyAgents.get(cId);
if (!agentsMap) return [];
const result = [];
for (const printers of agentsMap.values()) {
result.push(...printers);
}
return result;
}
/**
* Finds a single live printer by ID, serial, IP/address, or name.
*
* @param {number} companyId
* @param {string|number} identifier
* @returns {LivePrinter|null}
*/
export function getCompanyPrinter(companyId, identifier) {
if (identifier == null) return null;
const key = String(identifier).trim().toLowerCase();
if (!key) return null;
const printers = getCompanyPrinters(companyId);
return printers.find((p) => {
if (p.id != null && String(p.id).toLowerCase() === key) return true;
if (p.serial && String(p.serial).toLowerCase() === key) return true;
if (p.ip && String(p.ip).toLowerCase() === key) return true;
if (p.address && String(p.address).toLowerCase() === key) return true;
if (p.name && String(p.name).toLowerCase() === key) return true;
return false;
}) || null;
}
/**
* Broadcasts the current live printer list for a company to all connected subscribers via SSE.
* Emits both `printer` (with data `{ printers }`) and `printerstate`.
*
* @param {number} companyId
* @param {LivePrinter[]} [printers]
*/
export function broadcastCompanyPrinters(companyId, printers) {
const cId = Number(companyId);
if (!Number.isInteger(cId) || cId <= 0) return;
const list = printers ?? getCompanyPrinters(cId);
const payload = { printers: list };
emit('printer', { companyId: cId, data: payload });
emit('printerstate', { companyId: cId, data: payload });
}
/**
* Clears all live printers for a company (e.g. on company deletion).
*
* @param {number} companyId
*/
export function clearCompanyPrinters(companyId) {
const cId = Number(companyId);
if (companyAgents.has(cId)) {
companyAgents.delete(cId);
broadcastCompanyPrinters(cId, []);
}
}