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 {
|
export class HostManager {
|
||||||
constructor(socketClient) {
|
constructor(socketClient) {
|
||||||
this.socketClient = 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 { io } from "socket.io-client";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
// Load configuration
|
// Load configuration
|
||||||
import { loadConfig, saveConfig } from "../config.js";
|
import { loadConfig } from "../config.js";
|
||||||
import { getDeviceInfo } from "../utils.js";
|
|
||||||
import { sendIPC } from "../desktop/notify.js";
|
import { sendIPC } from "../desktop/notify.js";
|
||||||
import { PrinterManager } from "../printer/printermanager.js";
|
import { PrinterManager } from "../printer/printermanager.js";
|
||||||
import { HostManager } from "../host/hostmanager.js";
|
import { HostManager } from "../host/hostmanager.js";
|
||||||
@ -23,8 +22,6 @@ export class SocketClient {
|
|||||||
this.authenticated = false;
|
this.authenticated = false;
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.host = null;
|
|
||||||
this.id = null;
|
|
||||||
this.reconnectTimeout = null;
|
this.reconnectTimeout = null;
|
||||||
this.hostManager = new HostManager(this);
|
this.hostManager = new HostManager(this);
|
||||||
this.fileManager = new FileManager(this);
|
this.fileManager = new FileManager(this);
|
||||||
@ -38,6 +35,14 @@ export class SocketClient {
|
|||||||
sendIPC("setLoading", false);
|
sendIPC("setLoading", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.hostManager.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get host() {
|
||||||
|
return this.hostManager.host;
|
||||||
|
}
|
||||||
|
|
||||||
setupSocketEventHandlers() {
|
setupSocketEventHandlers() {
|
||||||
this.socket.on("connect", this.handleConnect.bind(this));
|
this.socket.on("connect", this.handleConnect.bind(this));
|
||||||
this.socket.on("connect_error", this.handleError.bind(this));
|
this.socket.on("connect_error", this.handleError.bind(this));
|
||||||
@ -61,42 +66,6 @@ export class SocketClient {
|
|||||||
}, 3000);
|
}, 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() {
|
async connect() {
|
||||||
try {
|
try {
|
||||||
await stopWaiting();
|
await stopWaiting();
|
||||||
@ -120,7 +89,7 @@ export class SocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
disconnect() {
|
disconnect() {
|
||||||
this.unsubscribeFromObjectEvents();
|
this.hostManager.unsubscribeFromObjectEvents();
|
||||||
this.socket.disconnect();
|
this.socket.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,109 +123,12 @@ export class SocketClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async authenticateWithOtp(otp, options = {}) {
|
authenticateWithOtp(otp, options) {
|
||||||
const { retryOnFailure = false, logs = true } = options;
|
return this.hostManager.authenticateWithOtp(otp, options);
|
||||||
|
|
||||||
if (!otp) {
|
|
||||||
return { valid: false, error: "OTP is required" };
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.waitForConnection();
|
|
||||||
return this.authenticate({ otp }, { retryOnFailure, logs });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async authenticate(authenticationData, options = {}) {
|
authenticate(authenticationData, options) {
|
||||||
const { retryOnFailure = true, logs = true } = options;
|
return this.hostManager.authenticate(authenticationData, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleObjectAction(data, callback) {
|
handleObjectAction(data, callback) {
|
||||||
@ -266,7 +138,7 @@ export class SocketClient {
|
|||||||
const action = data.action;
|
const action = data.action;
|
||||||
|
|
||||||
if (id == this.id && objectType == "host") {
|
if (id == this.id && objectType == "host") {
|
||||||
this.handleHostAction(action, callback);
|
this.hostManager.handleAction(action, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectType == "printer") {
|
if (objectType == "printer") {
|
||||||
@ -290,7 +162,7 @@ export class SocketClient {
|
|||||||
data._id,
|
data._id,
|
||||||
);
|
);
|
||||||
if (data.objectType == "host") {
|
if (data.objectType == "host") {
|
||||||
this.handleHostUpdate(data);
|
this.hostManager.handleUpdate(data);
|
||||||
}
|
}
|
||||||
if (data.objectType == "documentPrinter") {
|
if (data.objectType == "documentPrinter") {
|
||||||
this.documentPrinterManager.handleDocumentPrinterUpdate(
|
this.documentPrinterManager.handleDocumentPrinterUpdate(
|
||||||
@ -318,18 +190,7 @@ export class SocketClient {
|
|||||||
this.reconnectTimeout = null;
|
this.reconnectTimeout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const otpRequired =
|
this.hostManager.onConnect();
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleError(error) {
|
async handleError(error) {
|
||||||
@ -345,14 +206,6 @@ export class SocketClient {
|
|||||||
this.scheduleReconnect();
|
this.scheduleReconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
sendDeviceInfo() {
|
|
||||||
logger.debug("Sending device info...");
|
|
||||||
const deviceInfo = getDeviceInfo();
|
|
||||||
this.socket.emit("updateHost", {
|
|
||||||
host: { deviceInfo: deviceInfo },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async listObjects({
|
async listObjects({
|
||||||
objectType,
|
objectType,
|
||||||
populate,
|
populate,
|
||||||
@ -818,14 +671,6 @@ export class SocketClient {
|
|||||||
emitUnsubscribe();
|
emitUnsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleHostChildUpdate(data) {
|
|
||||||
if (data.parentType == "printer") {
|
|
||||||
this.printerManager.reloadPrinters();
|
|
||||||
} else if (data.parentType == "documentPrinter") {
|
|
||||||
this.documentPrinterManager.reloadDocumentPrinters();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleObjectEvent({ objectType, _id, event }) {
|
async handleObjectEvent({ objectType, _id, event }) {
|
||||||
logger.debug("Received object event...", {
|
logger.debug("Received object event...", {
|
||||||
objectType,
|
objectType,
|
||||||
@ -853,7 +698,7 @@ export class SocketClient {
|
|||||||
objectType == "host" &&
|
objectType == "host" &&
|
||||||
_id == this.id
|
_id == this.id
|
||||||
) {
|
) {
|
||||||
await this.handleHostChildUpdate(data);
|
await this.hostManager.handleChildEvent(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user