From 326c2e125c2c1eda5333858151a36ba4f128142f Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Fri, 20 Feb 2026 16:54:01 -0600 Subject: [PATCH] socket setup --- .vscode/settings.json | 1 + backend/opendock/connection.ts | 23 ------- ...ls.ts => openDockRreleaseMonitor.utils.ts} | 69 +++++++------------ backend/opendock/opendock.utils.ts | 35 ++++++++++ backend/opendock/opendockGetRelease.route.ts | 16 +++-- .../opendock/opendockSocketMonitor.utils.ts | 63 +++++++++++++++++ backend/server.ts | 4 +- backend/system/settingsUpdate.controller.ts | 7 ++ brunoApi/opendock/GetApt.bru | 3 +- 9 files changed, 147 insertions(+), 74 deletions(-) delete mode 100644 backend/opendock/connection.ts rename backend/opendock/{releaseMonitor.utils.ts => openDockRreleaseMonitor.utils.ts} (91%) create mode 100644 backend/opendock/opendock.utils.ts create mode 100644 backend/opendock/opendockSocketMonitor.utils.ts create mode 100644 backend/system/settingsUpdate.controller.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 2e791ac..3c3e745 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -58,6 +58,7 @@ "OCME", "onnotice", "opendock", + "opendocks", "ppoo", "prodlabels" ], diff --git a/backend/opendock/connection.ts b/backend/opendock/connection.ts deleted file mode 100644 index b83f3c7..0000000 --- a/backend/opendock/connection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { io } from "socket.io-client"; - -// NOTE: we assume "accessToken" was already obtained earlier via a call to '/auth/login'. - -// get the -const accessToken = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3MTkyNTQyZS01NzQ5LTRlZTgtYjdjZS0zNTQ4ZjA0NGQwOWIiLCJqdGkiOiI1NzE5ZmQ2OS02NTVkLTQ1MjctYTJjOC1hZWNhMjU0MTQ2MDEiLCJpZCI6IjcxOTI1NDJlLTU3NDktNGVlOC1iN2NlLTM1NDhmMDQ0ZDA5YiIsImVtYWlsIjoiYmxha2UubWF0dGhlc0BhbHBsYS5jb20iLCJvcmdJZCI6IjI2YTE4NjlmLTYwNDktNDM3Mi04ZWMzLTVkZDZlNDIzZjJmNiIsImNvbXBhbnlJZCI6bnVsbCwicm9sZSI6InJvbGVfb3duZXIiLCJpc0VtYWlsVmVyaWZpZWQiOnRydWUsImludmFsaWRMb2dpbkF0dGVtcHRzIjpudWxsLCJpYXQiOjE3NzA4MTE5MTEsImV4cCI6MTc3MTA3MTExMX0.jLHOSIF5RHUGjwq8WvycYxD9HK8_677O6sgRUZeYdUQ"; - -const baseSubspaceUrl = "wss://subspace.opendock.com"; -const url = `${baseSubspaceUrl}?token=${accessToken}`; -const socket = io(url, { transports: ["websocket"] }); // Enforce 'websocket' transport only. - -// socket.on("heartbeat", (data) => { -// console.log(data); -// }); - -socket.on("connection", () => { - console.log("Connected"); -}); - -socket.on("create-Appointment", (data) => { - console.log("appt create:", data); -}); diff --git a/backend/opendock/releaseMonitor.utils.ts b/backend/opendock/openDockRreleaseMonitor.utils.ts similarity index 91% rename from backend/opendock/releaseMonitor.utils.ts rename to backend/opendock/openDockRreleaseMonitor.utils.ts index 0b7b124..1af8b1c 100644 --- a/backend/opendock/releaseMonitor.utils.ts +++ b/backend/opendock/openDockRreleaseMonitor.utils.ts @@ -14,6 +14,7 @@ import { createCronJob } from "../utils/croner.utils.js"; import { delay } from "../utils/delay.utils.js"; import { returnFunc } from "../utils/returnHelper.utils.js"; import { tryCatch } from "../utils/trycatch.utils.js"; +import { getToken, odToken } from "./opendock.utils.js"; let lastCheck = formatInTimeZone( new Date().toISOString(), @@ -36,21 +37,12 @@ type Releases = { CustomerReleaseNumber: string; }; -type ODToken = { - odToken: string | null; - tokenDate: Date | null; -}; - -let odToken: ODToken = { - odToken: null, - tokenDate: new Date(), -}; const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000; const log = createLogger({ module: "opendock", subModule: "releaseMonitor" }); const postRelease = async (release: Releases) => { if (!odToken.odToken) { - log.info("Getting Auth Token"); + log.info({}, "Getting Auth Token"); await getToken(); } @@ -58,7 +50,7 @@ const postRelease = async (release: Releases) => { new Date(odToken.tokenDate || Date.now()).getTime() < Date.now() - TWENTY_FOUR_HOURS ) { - log.info("Refreshing Auth Token"); + log.info({}, "Refreshing Auth Token"); await getToken(); } /** @@ -120,7 +112,7 @@ const postRelease = async (release: Releases) => { name: "intPallet Count", type: "int", label: "Pallet Count", - value: parseInt(release.LoadingUnits, 10), + value: parseInt(release.LoadingUnits, 10), // do we really want to update this if its partial load as it should have been the full amount? description: "How many pallets", placeholder: "22", dropDownValues: [], @@ -207,13 +199,17 @@ const postRelease = async (release: Releases) => { }) .returning(); - log.info(`${release.ReleaseNumber} was updated`); + log.info({}, `${release.ReleaseNumber} was updated`); } catch (e) { - log.error(e); + log.error({ error: e }, "Error updating the release"); } + // biome-ignore lint/suspicious/noExplicitAny: to many possibilities } catch (e: any) { //console.info(newDockApt); - log.error(e.response.data); + log.error( + { error: e.response.data }, + "An error has occurred during patching of the release", + ); return; } @@ -225,7 +221,7 @@ const postRelease = async (release: Releases) => { { headers: { "content-type": "application/json; charset=utf-8", - Authorization: `Bearer ${odToken}`, + Authorization: `Bearer ${odToken.odToken}`, }, }, ); @@ -234,7 +230,7 @@ const postRelease = async (release: Releases) => { // this will be utilized when we are listening for the changes to the apts. that way we can update the state to arrived. we will run our own checks on this guy during the incoming messages. if (response.status === 400) { - log.error(response.data.data.message); + log.error({}, response.data.data.message); return; } @@ -255,12 +251,16 @@ const postRelease = async (release: Releases) => { }) .returning(); - log.info(`${release.ReleaseNumber} was created`); + log.info({}, `${release.ReleaseNumber} was created`); } catch (e) { - log.error(e); + log.error({ error: e }, "Error creating new release"); } + // biome-ignore lint/suspicious/noExplicitAny: to many possibilities } catch (e: any) { - log.error(e.response.data); + log.error( + { error: e?.response?.data }, + "Error posting new release to opendock", + ); return; } @@ -312,8 +312,11 @@ export const monitorReleaseChanges = async () => { } } } catch (e) { - console.error(e); - log.error({ error: e }, "Monitor error"); + console.error( + { error: e }, + "Error occurred while running the monitor job", + ); + log.error({ error: e }, "Error occurred while running the monitor job"); } }); } @@ -349,28 +352,6 @@ export const monitorReleaseChanges = async () => { // } }; -const getToken = async () => { - try { - const { status, data } = await axios.post( - `${process.env.OPENDOCK_URL}/auth/login`, - { - email: "blake.matthes@alpla.com", - password: process.env.OPENDOCK_PASSWORD, - }, - ); - - if (status === 400) { - log.error(data.message); - return; - } - - odToken = { odToken: data.access_token, tokenDate: new Date() }; - log.info("Token added"); - } catch (e) { - log.error(e); - } -}; - // export const monitorReleaseChanges = async () => { // console.log("Starting release monitor", lastCheck); // setInterval(async () => { diff --git a/backend/opendock/opendock.utils.ts b/backend/opendock/opendock.utils.ts new file mode 100644 index 0000000..525fe8b --- /dev/null +++ b/backend/opendock/opendock.utils.ts @@ -0,0 +1,35 @@ +import axios from "axios"; +import { createLogger } from "../logger/logger.controller.js"; + +type ODToken = { + odToken: string | null; + tokenDate: Date | null; +}; + +export let odToken: ODToken = { + odToken: null, + tokenDate: new Date(), +}; + +export const getToken = async () => { + const log = createLogger({ module: "opendock", subModule: "releaseMonitor" }); + try { + const { status, data } = await axios.post( + `${process.env.OPENDOCK_URL}/auth/login`, + { + email: "blake.matthes@alpla.com", + password: process.env.OPENDOCK_PASSWORD, + }, + ); + + if (status === 400) { + log.error(data.message); + return; + } + + odToken = { odToken: data.access_token, tokenDate: new Date() }; + log.info({}, "Token added"); + } catch (e) { + log.error({ error: e }, "Error getting/refreshing token"); + } +}; diff --git a/backend/opendock/opendockGetRelease.route.ts b/backend/opendock/opendockGetRelease.route.ts index 435a8bb..b6ceea8 100644 --- a/backend/opendock/opendockGetRelease.route.ts +++ b/backend/opendock/opendockGetRelease.route.ts @@ -1,6 +1,5 @@ -import { desc, lte, sql } from "drizzle-orm"; +import { desc, gte, sql } from "drizzle-orm"; import { Router } from "express"; -import { open } from "inspector/promises"; import { db } from "../db/db.controller.js"; import { opendockApt } from "../db/schema/opendock.schema.js"; import { apiReturn } from "../utils/returnHelper.utils.js"; @@ -11,11 +10,18 @@ const r = Router(); r.get("/", async (_, res) => { //const limit - const { data, error } = await tryCatch( + const daysCreated = 30; + + const { data } = await tryCatch( db .select() .from(opendockApt) - .where(lte(opendockApt.createdAt, sql.raw(`NOW() - INTERVAL '30 days'`))) + .where( + gte( + opendockApt.createdAt, + sql.raw(`NOW() - INTERVAL '${daysCreated} days'`), + ), + ) .orderBy(desc(opendockApt.createdAt)) .limit(500), ); @@ -25,7 +31,7 @@ r.get("/", async (_, res) => { level: "info", module: "opendock", subModule: "apt", - message: "The first x Apt", + message: `The first ${data?.length} Apt(s) that were created in the last ${daysCreated} `, data: data ?? [], status: 200, }); diff --git a/backend/opendock/opendockSocketMonitor.utils.ts b/backend/opendock/opendockSocketMonitor.utils.ts new file mode 100644 index 0000000..63b08ef --- /dev/null +++ b/backend/opendock/opendockSocketMonitor.utils.ts @@ -0,0 +1,63 @@ +import { io, type Socket } from "socket.io-client"; +import { createLogger } from "../logger/logger.controller.js"; +import { getToken, odToken } from "./opendock.utils.js"; + +const log = createLogger({ module: "opendock", subModule: "releaseMonitor" }); +const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000; +let socket: Socket | null = null; +export const opendockSocketMonitor = async () => { + if (!odToken.odToken) { + log.info({}, "Getting Auth Token"); + await getToken(); + } + + if ( + new Date(odToken.tokenDate || Date.now()).getTime() < + Date.now() - TWENTY_FOUR_HOURS + ) { + log.info({}, "Refreshing Auth Token"); + await getToken(); + } + const baseSubspaceUrl = "wss://subspace.staging.opendock.com"; + const url = `${baseSubspaceUrl}?token=${odToken.odToken}`; + socket = io(url, { transports: ["websocket"] }); // Enforce 'websocket' transport only. + + socket.on("connect", () => { + console.log("Connected"); + }); + + // socket.on("heartbeat", (data) => { + // console.log(data); + // }); + + socket.on("create-Appointment", (data) => { + console.log("appt create:", data); + }); + + socket.on("update-Appointment", (data) => { + console.log("appt update:", data); + }); + + socket.on("error", (data) => { + console.log("Error:", data); + }); + + // socket.onAny((event, ...args) => { + // console.log("Received event:", event, args); + // }); +}; + +export const killOpendockSocket = () => { + if (!socket) { + console.log("No active socket to kill"); + return; + } + + console.log("🛑 Killing socket connection..."); + + socket.removeAllListeners(); // optional but clean + socket.disconnect(); + socket = null; + + console.log("✅ Socket killed"); +}; diff --git a/backend/server.ts b/backend/server.ts index 330bcc3..dcad8ec 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -3,7 +3,8 @@ import os from "node:os"; import createApp from "./app.js"; import { dbCleanup } from "./db/dbCleanup.controller.js"; import { createLogger } from "./logger/logger.controller.js"; -import { monitorReleaseChanges } from "./opendock/releaseMonitor.utils.js"; +import { monitorReleaseChanges } from "./opendock/openDockRreleaseMonitor.utils.js"; +import { opendockSocketMonitor } from "./opendock/opendockSocketMonitor.utils.js"; import { connectProdSql } from "./prodSql/prodSqlConnection.controller.js"; import { setupSocketIORoutes } from "./socket.io/serverSetup.js"; import { createCronJob } from "./utils/croner.utils.js"; @@ -19,6 +20,7 @@ const start = async () => { // start long live processes setTimeout(() => { monitorReleaseChanges(); // this is od monitoring the db for all new releases + opendockSocketMonitor(); createCronJob("JobAuditLogCleanUp", "* 0 5 * * * *", () => dbCleanup("jobs", 30), ); diff --git a/backend/system/settingsUpdate.controller.ts b/backend/system/settingsUpdate.controller.ts new file mode 100644 index 0000000..5239ad4 --- /dev/null +++ b/backend/system/settingsUpdate.controller.ts @@ -0,0 +1,7 @@ +import type { Setting } from "../db/schema/settings.schema.js"; + +export const updateSetting = async (setting: Setting) => { + // TODO: when the setting is a feature setting we will need to have it run each kill switch on the crons well just stop them and during a reset it just wont start them + // TODO: when the setting is a system we will need to force an app restart + // TODO: when the setting is standard we don't do anything. +}; diff --git a/brunoApi/opendock/GetApt.bru b/brunoApi/opendock/GetApt.bru index 59e5862..1693a64 100644 --- a/brunoApi/opendock/GetApt.bru +++ b/brunoApi/opendock/GetApt.bru @@ -5,11 +5,12 @@ meta { } get { - url: + url: {{url}}/lst/api/opendock body: none auth: inherit } settings { encodeUrl: true + timeout: 0 }