farmcontrol-server/src/printer/printermanager.js

190 lines
5.6 KiB
JavaScript

// printer-manager.js - Manages multiple printer connections through MongoDB
import { PrinterClient } from "./printerclient.js";
import { printerModel } from "../database/printer.schema.js"; // Import your printer model
import { printSubJobModel } from "../database/printsubjob.schema.js"; // Import your subjob model
import { loadConfig } from "../config.js";
import log4js from "log4js";
import { printJobModel } from "../database/printjob.schema.js";
// Load configuration
const config = loadConfig();
const logger = log4js.getLogger("Printer Manager");
logger.level = config.server.logLevel;
export class PrinterManager {
constructor(config) {
this.config = config;
this.printerClientConnections = new Map();
this.statusCheckInterval = null;
this.initializePrinterConnections();
}
async initializePrinterConnections() {
try {
// Get all printers from the database
const printers = await printerModel.find({}).populate({ path: "currentFilamentStock",
populate: {
path: "filament",
},});
for (const printer of printers) {
await this.connectToPrinter(printer);
}
logger.info(`Initialized connections to ${printers.length} printers`);
} catch (error) {
logger.error(`Error initializing printer connections: ${error.message}`);
}
}
async connectToPrinter(printer) {
// Create and store the connection
const printerClientConnection = new PrinterClient(
printer,
this,
this.socketManager,
);
this.printerClientConnections.set(printer.id, printerClientConnection);
// Connect to the printer
await printerClientConnection.connect();
logger.info(`Connected to printer: ${printer.name} (${printer.id})`);
return true;
}
getPrinterClient(printerId) {
return this.printerClientConnections.get(printerId);
}
getAllPrinterClients() {
return this.printerClientConnections.values();
}
// Process command for a specific printer
async processPrinterCommand(command) {
const printerId = command.params.printerId;
const printerClientConnection =
this.printerClientConnections.get(printerId);
if (!printerClientConnection) {
return {
success: false,
error: `Printer with ID ${printerId} not found`,
};
}
return await printerClientConnection.sendPrinterCommand(command);
}
async updateSubscription(printerId, socketId, mergedSubscription) {
const printerClientConnection =
this.printerClientConnections.get(printerId);
if (!printerClientConnection) {
return {
success: false,
error: `Printer with ID ${printerId} not found`,
};
}
printerClientConnection.subscriptions.set(socketId, mergedSubscription);
return await printerClientConnection.updateSubscriptions();
}
// Close all printer connections
closeAllConnections() {
for (const printerClientConnection of this.printerClientConnections.values()) {
if (printerClientConnection.socket) {
printerClientConnection.socket.close();
}
}
}
setSocketManager(socketManager) {
this.socketManager = socketManager;
}
async downloadGCODE(gcodeFileId) {
logger.info(`Downloading G-code file ${gcodeFileId}`);
try {
// Download the G-code file with authentication
const url = `http://localhost:8080/gcodefiles/${gcodeFileId}/content/`;
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${this.socketManager.socketClientConnections.values().next().value.socket.handshake.auth.token}`,
},
});
if (!response.ok) {
throw new Error(
`Failed to download G-code file: ${response.statusText}`,
);
}
const gcodeContent = await response.blob();
logger.info(`G-code file ${gcodeFileId} downloaded!`);
return gcodeContent;
} catch (error) {
logger.error("Error in deployGcodeToAllPrinters:", error);
return {
success: false,
error: error.message,
};
}
}
async deployPrintJob(printJobId) {
logger.info(`Deploying print job ${printJobId}`);
const printJob = await printJobModel
.findById(printJobId)
.populate("printers")
.populate("subJobs");
if (!printJob) {
throw new Error("Print job not found");
}
if (!printJob.gcodeFile) {
throw new Error("No G-code file associated with this print job");
}
const gcodeFileId = printJob.gcodeFile.toString();
const fileName = `${printJob.id}.gcode`;
const gcodeFile = await this.downloadGCODE(gcodeFileId);
for (const printer of printJob.printers) {
const printerClient = this.getPrinterClient(printer.id);
if (!printerClient) {
throw new Error(`Printer with ID ${printer.id} not found`);
return false;
}
await printerClient.uploadGcodeFile(gcodeFile, fileName);
await printerClient.deploySubJobs(printJob.id);
}
printJob.state = { type: "queued" };
printJob.updatedAt = new Date();
await printJob.save();
this.socketManager.broadcast("notify_job_update", {
id: printJob.id,
state: { type: "queued" },
});
return true;
}
async cancelSubJob(subJobId) {
logger.info(`Canceling sub job ${subJobId}`);
const subJob = await printSubJobModel.findById(subJobId);
if (!subJob) {
throw new Error("Sub job not found");
}
const printerClient = this.getPrinterClient(subJob.printer.toString());
if (!printerClient) {
throw new Error(`Printer with ID ${printer.id} not found`);
return false;
}
await printerClient.cancelSubJob(subJob.subJobId);
return true;
}
}