Refactor HostManager and SocketClient for improved authentication and event handling
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
- Introduced a dedicated `HostManager` class to encapsulate host-related logic, including authentication and event subscription. - Enhanced authentication methods in `HostManager` to handle OTP and standard authentication processes. - Updated `SocketClient` to delegate host-related actions to `HostManager`, streamlining the connection and event handling workflow. - Improved logging and configuration management during host authentication and updates. - Removed redundant code from `SocketClient`, enhancing maintainability and clarity.
This commit is contained in:
parent
d5fe978361
commit
d04e722366
@ -1,5 +1,210 @@
|
||||
import log4js from "log4js";
|
||||
import { loadConfig, saveConfig } from "../config.js";
|
||||
import { getDeviceInfo } from "../utils.js";
|
||||
import { sendIPC } from "../desktop/notify.js";
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
const logger = log4js.getLogger("Host Manager");
|
||||
logger.level = config.logLevel;
|
||||
|
||||
export class HostManager {
|
||||
constructor(socketClient) {
|
||||
this.socketClient = socketClient;
|
||||
this.host = null;
|
||||
this.id = null;
|
||||
}
|
||||
|
||||
isOtpRequired() {
|
||||
return (
|
||||
config.host?.id == undefined ||
|
||||
config.host?.id == "" ||
|
||||
config.host?.authCode == undefined ||
|
||||
config.host?.authCode == ""
|
||||
);
|
||||
}
|
||||
|
||||
subscribeToObjectEvents() {
|
||||
const { id } = this;
|
||||
this.socketClient.subscribeToObjectEvent({
|
||||
objectType: "host",
|
||||
_id: id,
|
||||
eventType: "childUpdate",
|
||||
});
|
||||
this.socketClient.subscribeToObjectEvent({
|
||||
objectType: "host",
|
||||
_id: id,
|
||||
eventType: "childDelete",
|
||||
});
|
||||
this.socketClient.subscribeToObjectEvent({
|
||||
objectType: "host",
|
||||
_id: id,
|
||||
eventType: "childNew",
|
||||
});
|
||||
}
|
||||
|
||||
unsubscribeFromObjectEvents() {
|
||||
if (!this.id) {
|
||||
return;
|
||||
}
|
||||
const { id } = this;
|
||||
this.socketClient.unsubscribeFromObjectEvent({
|
||||
objectType: "host",
|
||||
_id: id,
|
||||
eventType: "childUpdate",
|
||||
});
|
||||
this.socketClient.unsubscribeFromObjectEvent({
|
||||
objectType: "host",
|
||||
_id: id,
|
||||
eventType: "childDelete",
|
||||
});
|
||||
this.socketClient.unsubscribeFromObjectEvent({
|
||||
objectType: "host",
|
||||
_id: id,
|
||||
eventType: "childNew",
|
||||
});
|
||||
}
|
||||
|
||||
async authenticateWithOtp(otp, options = {}) {
|
||||
const { retryOnFailure = false, logs = true } = options;
|
||||
|
||||
if (!otp) {
|
||||
return { valid: false, error: "OTP is required" };
|
||||
}
|
||||
|
||||
await this.socketClient.waitForConnection();
|
||||
return this.authenticate({ otp }, { retryOnFailure, logs });
|
||||
}
|
||||
|
||||
async authenticate(authenticationData, options = {}) {
|
||||
const { logs = true } = options;
|
||||
|
||||
await this.socketClient.waitForConnection();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const { socket } = this.socketClient;
|
||||
if (!socket?.connected) {
|
||||
reject(new Error("Socket client is not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (logs) {
|
||||
logger.debug("Host authenticating...");
|
||||
}
|
||||
socket.emit(
|
||||
"authenticate",
|
||||
authenticationData,
|
||||
async (verifyResult) => {
|
||||
if (verifyResult.valid == false) {
|
||||
this.socketClient.authenticated = false;
|
||||
sendIPC("setAuthenticated", false);
|
||||
if (logs) {
|
||||
logger.error("Host not authenticated:", verifyResult.error);
|
||||
}
|
||||
|
||||
resolve({ valid: false, error: verifyResult.error });
|
||||
return;
|
||||
}
|
||||
|
||||
if (logs) {
|
||||
logger.info("Host authenticated.");
|
||||
}
|
||||
await this.onAuthenticated(verifyResult.host);
|
||||
resolve({ valid: true, host: this.host });
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async onAuthenticated(hostData) {
|
||||
this.socketClient.authenticated = true;
|
||||
sendIPC("setAuthenticated", true);
|
||||
sendIPC("setLoading", false);
|
||||
this.socketClient.loading = false;
|
||||
|
||||
if (this.host) {
|
||||
sendIPC("setHost", {
|
||||
...this.host,
|
||||
online: false,
|
||||
state: { type: "offline" },
|
||||
});
|
||||
}
|
||||
|
||||
this.host = {
|
||||
...hostData,
|
||||
state: { type: "online" },
|
||||
online: true,
|
||||
};
|
||||
sendIPC("setHost", this.host);
|
||||
this.id = this.host._id;
|
||||
|
||||
config.host = { id: this.id, authCode: this.host.authCode };
|
||||
await saveConfig(config);
|
||||
|
||||
this.sendDeviceInfo();
|
||||
this.subscribeToObjectEvents();
|
||||
this.socketClient.subscribeToObjectUpdates({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
});
|
||||
this.socketClient.documentPrinterManager.reloadDocumentPrinters();
|
||||
this.socketClient.printerManager.reloadPrinters();
|
||||
await this.socketClient.fileManager.updateFiles();
|
||||
}
|
||||
|
||||
onConnect() {
|
||||
if (this.isOtpRequired()) {
|
||||
logger.info("An OTP code is required to setup this host.");
|
||||
this.socketClient.authenticated = false;
|
||||
sendIPC("setAuthenticated", false);
|
||||
return;
|
||||
}
|
||||
this.authenticate({
|
||||
id: config.host.id,
|
||||
authCode: config.host.authCode,
|
||||
});
|
||||
}
|
||||
|
||||
handleAction(action, callback) {
|
||||
switch (action.type) {
|
||||
case "reloadPrinters":
|
||||
this.socketClient.printerManager.updatePrinters().catch((error) => {
|
||||
logger.error("Failed to reload printers:", error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
callback({ success: true });
|
||||
}
|
||||
|
||||
async handleUpdate(data) {
|
||||
if (data._id != this.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Handling host update for id:", data._id);
|
||||
const { online, state } = this.host;
|
||||
this.host = { ...this.host, ...data.object, online, state };
|
||||
sendIPC("setHost", this.host);
|
||||
|
||||
if (data.object?.authCode) {
|
||||
config.host = { id: this.id, authCode: data.object.authCode };
|
||||
await saveConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
async handleChildEvent(data) {
|
||||
if (data.parentType == "printer") {
|
||||
this.socketClient.printerManager.reloadPrinters();
|
||||
} else if (data.parentType == "documentPrinter") {
|
||||
this.socketClient.documentPrinterManager.reloadDocumentPrinters();
|
||||
}
|
||||
}
|
||||
|
||||
sendDeviceInfo() {
|
||||
logger.debug("Sending device info...");
|
||||
const deviceInfo = getDeviceInfo();
|
||||
this.socketClient.socket.emit("updateHost", {
|
||||
host: { deviceInfo: deviceInfo },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,7 @@ import { WebSocketScanner } from "../network/websocketScanner.js";
|
||||
import { io } from "socket.io-client";
|
||||
import axios from "axios";
|
||||
// Load configuration
|
||||
import { loadConfig, saveConfig } from "../config.js";
|
||||
import { getDeviceInfo } from "../utils.js";
|
||||
import { loadConfig } from "../config.js";
|
||||
import { sendIPC } from "../desktop/notify.js";
|
||||
import { PrinterManager } from "../printer/printermanager.js";
|
||||
import { HostManager } from "../host/hostmanager.js";
|
||||
@ -23,8 +22,6 @@ export class SocketClient {
|
||||
this.authenticated = false;
|
||||
this.connected = false;
|
||||
this.loading = false;
|
||||
this.host = null;
|
||||
this.id = null;
|
||||
this.reconnectTimeout = null;
|
||||
this.hostManager = new HostManager(this);
|
||||
this.fileManager = new FileManager(this);
|
||||
@ -38,6 +35,14 @@ export class SocketClient {
|
||||
sendIPC("setLoading", false);
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.hostManager.id;
|
||||
}
|
||||
|
||||
get host() {
|
||||
return this.hostManager.host;
|
||||
}
|
||||
|
||||
setupSocketEventHandlers() {
|
||||
this.socket.on("connect", this.handleConnect.bind(this));
|
||||
this.socket.on("connect_error", this.handleError.bind(this));
|
||||
@ -61,42 +66,6 @@ export class SocketClient {
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
subscribeToObjectEvents() {
|
||||
this.subscribeToObjectEvent({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
eventType: "childUpdate",
|
||||
});
|
||||
this.subscribeToObjectEvent({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
eventType: "childDelete",
|
||||
});
|
||||
this.subscribeToObjectEvent({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
eventType: "childNew",
|
||||
});
|
||||
}
|
||||
|
||||
unsubscribeFromObjectEvents() {
|
||||
this.unsubscribeFromObjectEvent({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
eventType: "childUpdate",
|
||||
});
|
||||
this.unsubscribeFromObjectEvent({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
eventType: "childDelete",
|
||||
});
|
||||
this.unsubscribeFromObjectEvent({
|
||||
objectType: "host",
|
||||
_id: this.id,
|
||||
eventType: "childNew",
|
||||
});
|
||||
}
|
||||
|
||||
async connect() {
|
||||
try {
|
||||
await stopWaiting();
|
||||
@ -120,7 +89,7 @@ export class SocketClient {
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.unsubscribeFromObjectEvents();
|
||||
this.hostManager.unsubscribeFromObjectEvents();
|
||||
this.socket.disconnect();
|
||||
}
|
||||
|
||||
@ -154,109 +123,12 @@ export class SocketClient {
|
||||
});
|
||||
}
|
||||
|
||||
async authenticateWithOtp(otp, options = {}) {
|
||||
const { retryOnFailure = false, logs = true } = options;
|
||||
|
||||
if (!otp) {
|
||||
return { valid: false, error: "OTP is required" };
|
||||
}
|
||||
|
||||
await this.waitForConnection();
|
||||
return this.authenticate({ otp }, { retryOnFailure, logs });
|
||||
authenticateWithOtp(otp, options) {
|
||||
return this.hostManager.authenticateWithOtp(otp, options);
|
||||
}
|
||||
|
||||
async authenticate(authenticationData, options = {}) {
|
||||
const { retryOnFailure = true, logs = true } = options;
|
||||
|
||||
await this.waitForConnection();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.socket?.connected) {
|
||||
reject(new Error("Socket client is not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (logs) {
|
||||
logger.debug("Host authenticating...");
|
||||
}
|
||||
this.socket.emit(
|
||||
"authenticate",
|
||||
authenticationData,
|
||||
async (verifyResult) => {
|
||||
if (verifyResult.valid == false) {
|
||||
this.authenticated = false;
|
||||
sendIPC("setAuthenticated", false);
|
||||
if (logs) {
|
||||
logger.error("Host not authenticated:", verifyResult.error);
|
||||
}
|
||||
|
||||
resolve({ valid: false, error: verifyResult.error });
|
||||
return;
|
||||
}
|
||||
|
||||
if (logs) {
|
||||
logger.info("Host authenticated.");
|
||||
}
|
||||
this.authenticated = true;
|
||||
sendIPC("setAuthenticated", true);
|
||||
sendIPC("setLoading", false);
|
||||
this.loading = false;
|
||||
if (this.host) {
|
||||
sendIPC("setHost", {
|
||||
...this.host,
|
||||
online: false,
|
||||
state: { type: "offline" },
|
||||
});
|
||||
}
|
||||
this.host = {
|
||||
...verifyResult.host,
|
||||
state: { type: "online" },
|
||||
online: true,
|
||||
};
|
||||
sendIPC("setHost", this.host);
|
||||
this.id = this.host._id;
|
||||
|
||||
config.host = { id: this.id, authCode: this.host.authCode };
|
||||
|
||||
await saveConfig(config);
|
||||
|
||||
this.sendDeviceInfo();
|
||||
this.subscribeToObjectEvents();
|
||||
this.subscribeToObjectUpdates({ objectType: "host", _id: this.id });
|
||||
this.documentPrinterManager.reloadDocumentPrinters();
|
||||
this.printerManager.reloadPrinters();
|
||||
await this.fileManager.updateFiles();
|
||||
resolve({ valid: true, host: this.host });
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
handleHostAction(action, callback) {
|
||||
switch (action.type) {
|
||||
case "reloadPrinters":
|
||||
this.printerManager.updatePrinters().catch((error) => {
|
||||
logger.error("Failed to reload printers:", error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
callback({ success: true });
|
||||
}
|
||||
|
||||
async handleHostUpdate(data) {
|
||||
if (data._id != this.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Handling host update for id:", data._id);
|
||||
const { online, state } = this.host;
|
||||
this.host = { ...this.host, ...data.object, online, state };
|
||||
sendIPC("setHost", this.host);
|
||||
|
||||
if (data.object?.authCode) {
|
||||
config.host = { id: this.id, authCode: data.object.authCode };
|
||||
await saveConfig(config);
|
||||
}
|
||||
authenticate(authenticationData, options) {
|
||||
return this.hostManager.authenticate(authenticationData, options);
|
||||
}
|
||||
|
||||
handleObjectAction(data, callback) {
|
||||
@ -266,7 +138,7 @@ export class SocketClient {
|
||||
const action = data.action;
|
||||
|
||||
if (id == this.id && objectType == "host") {
|
||||
this.handleHostAction(action, callback);
|
||||
this.hostManager.handleAction(action, callback);
|
||||
}
|
||||
|
||||
if (objectType == "printer") {
|
||||
@ -290,7 +162,7 @@ export class SocketClient {
|
||||
data._id,
|
||||
);
|
||||
if (data.objectType == "host") {
|
||||
this.handleHostUpdate(data);
|
||||
this.hostManager.handleUpdate(data);
|
||||
}
|
||||
if (data.objectType == "documentPrinter") {
|
||||
this.documentPrinterManager.handleDocumentPrinterUpdate(
|
||||
@ -318,18 +190,7 @@ export class SocketClient {
|
||||
this.reconnectTimeout = null;
|
||||
}
|
||||
|
||||
const otpRequired =
|
||||
config.host?.id == undefined ||
|
||||
config.host?.id == "" ||
|
||||
config.host?.authCode == undefined ||
|
||||
config.host?.authCode == "";
|
||||
if (otpRequired) {
|
||||
logger.info("An OTP code is required to setup this host.");
|
||||
this.authenticated = false;
|
||||
sendIPC("setAuthenticated", false);
|
||||
return;
|
||||
}
|
||||
this.authenticate({ id: config.host.id, authCode: config.host.authCode });
|
||||
this.hostManager.onConnect();
|
||||
}
|
||||
|
||||
async handleError(error) {
|
||||
@ -345,14 +206,6 @@ export class SocketClient {
|
||||
this.scheduleReconnect();
|
||||
}
|
||||
|
||||
sendDeviceInfo() {
|
||||
logger.debug("Sending device info...");
|
||||
const deviceInfo = getDeviceInfo();
|
||||
this.socket.emit("updateHost", {
|
||||
host: { deviceInfo: deviceInfo },
|
||||
});
|
||||
}
|
||||
|
||||
async listObjects({
|
||||
objectType,
|
||||
populate,
|
||||
@ -818,14 +671,6 @@ export class SocketClient {
|
||||
emitUnsubscribe();
|
||||
}
|
||||
|
||||
async handleHostChildUpdate(data) {
|
||||
if (data.parentType == "printer") {
|
||||
this.printerManager.reloadPrinters();
|
||||
} else if (data.parentType == "documentPrinter") {
|
||||
this.documentPrinterManager.reloadDocumentPrinters();
|
||||
}
|
||||
}
|
||||
|
||||
async handleObjectEvent({ objectType, _id, event }) {
|
||||
logger.debug("Received object event...", {
|
||||
objectType,
|
||||
@ -853,7 +698,7 @@ export class SocketClient {
|
||||
objectType == "host" &&
|
||||
_id == this.id
|
||||
) {
|
||||
await this.handleHostChildUpdate(data);
|
||||
await this.hostManager.handleChildEvent(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user