4986bfda2e
* Database schema and migrations for schedules * Added schedules to the side menu * The pagination can optionally hide the page numbers for a compactive mode * Filters for the schedule page * Added triggerSource (“STANDARD”, “SCHEDULED”) to BackgroundWorkerTask * Added the ability to disabled a LinkButton * Started work on the schedule page * Environment buttons * The new schedule form styles * Added a cxouple of extra fields * Allow a checkbox to have a rich label * Added cronstrue package to the webapp * WIP creating tasks using the form * Improved the form styling * Creating schedules is working in the UI * Minor improvements * Basic schedule table is displaying * Creating tasks with triggerSource = scheduled. Refactored how task metadata is stored and accessed to be cleaner * Resource route * Fixes in the form * Added a gap between the environments * WIP on OpenAI generating CRON expressions * AI generated CRON expressions is working * Fix for the CRON field being uneditable after an AI generation * Improvements * Table padding * useThrottle now behaves correctly * Added filtering to the schedules list * Improved the layout and fixed CRON search * Fixed pagination for the schedules list. Just use a regular Prisma query * Page size of 20 * Added links to the schedule rows * Get rid of the Last run column for now * Implement triggered scheduled tasks Also implemented superjson payloads and dev runtime environment “presence” with RuntimeEnvironmentSession * Move CronPattern and CreateSchedule into a common client-accessible file * Latest UI changes * Fix for creating a task schedule with a blank dedup key * Refactor the human to cron stuff into a separate file and use json_object OpenAI response format * Fix for trying to use a hook on the server-side… * A couple of fixes to the new schedule form * WIP on viewing a scheduled run * Make the filters all optional * Use the RunListPresenter from the schedule presenter * Display a table of runs… the wrong runs but still * Runs from the schedule * Deleting schedules from the UI * Tidied imports and fixed name of options object * Disabling a schedule * Editing schedules * Tidied imports * Added icons to the task list, needs some design love * Added a tooltip for CRON pattersn * Show the last run in the schedules table * Some tweaks * Added a placeholder to the CRON AI field * Improved the trigger source icon * Dim out disabled schedules * Scheduled tasks have the correct icon in a run * Added the task source icon to the test task list * Added the date field component to storybook * Style improvements to the date field * Implement Task Schedule API * added a medium sized variant to the date field * Fixed replay run for superjson payload types Also now linking from the replaying run to the original run (using span links) Also added a project metrics prometheus endpoint to detect the state of the queues * WIP on allowing different forms for testing * If you pass a string to prettyPrintPacket which is json or superjson, safeParse it first * Test page, deal json and superjson. Started splitting UI for schedules * WIP on schedule form * Removed the Label from the DateField * WIP on test schedule form * Fix for the runs page showing the wrong message when there are no runs from time filtering * Removed labels from the DateField * Fixes for the form * Test runs are working for schedules * Fix for nextScheduledTimestamps in triggerScheduledTask * Implement idempotency key support and fix issue with cancelled runs causing concurrency usage * Added API documentation for the schedule API * Remove log * Removed console log from runs page * Transform the recent runs test data on the server * Fix for hydration mismatch * Current date as the default for the test form * Recent payloads working * Delete schedule modal * Deal with empty strings from the form * Set the initial value for the scheduled test form * Add option to print console logs in the dev CLI locally (issue #1014) * Export queue from the SDK * Fix for schedules list when you have no schedule tasks * Blank states improved * Make task schedules more generic, to support additional schedule generators in the future * Removed log from maqrs * Removed “v3/schedules” export from the SDK --------- Co-authored-by: Eric Allam <eallam@icloud.com> Co-authored-by: James Ritchie <james@jamesritchie.co.uk>
80 lines
2.3 KiB
TypeScript
80 lines
2.3 KiB
TypeScript
import { IncomingMessage } from "node:http";
|
|
import { WebSocketServer, type WebSocket } from "ws";
|
|
import { authenticateApiKey } from "~/services/apiAuth.server";
|
|
import { logger } from "~/services/logger.server";
|
|
import { singleton } from "../utils/singleton";
|
|
import { AuthenticatedSocketConnection } from "./authenticatedSocketConnection.server";
|
|
import { Gauge } from "prom-client";
|
|
import { metricsRegister } from "~/metrics.server";
|
|
|
|
export const wss = singleton("wss", initalizeWebSocketServer);
|
|
|
|
let authenticatedConnections: Map<string, AuthenticatedSocketConnection>;
|
|
|
|
function initalizeWebSocketServer() {
|
|
const server = new WebSocketServer({ noServer: true });
|
|
|
|
server.on("connection", handleWebSocketConnection);
|
|
|
|
authenticatedConnections = new Map();
|
|
|
|
new Gauge({
|
|
name: "dev_authenticated_connections",
|
|
help: "Number of authenticated dev connections",
|
|
collect() {
|
|
this.set(authenticatedConnections.size);
|
|
},
|
|
registers: [metricsRegister],
|
|
});
|
|
|
|
return server;
|
|
}
|
|
|
|
async function handleWebSocketConnection(ws: WebSocket, req: IncomingMessage) {
|
|
logger.debug("Handle websocket connection", {
|
|
ipAddress: req.headers["x-forwarded-for"] || req.socket.remoteAddress,
|
|
});
|
|
|
|
const authHeader = req.headers.authorization;
|
|
|
|
if (!authHeader || typeof authHeader !== "string") {
|
|
ws.close(1008, "Missing Authorization header");
|
|
return;
|
|
}
|
|
|
|
const [authType, apiKey] = authHeader.split(" ");
|
|
|
|
if (authType !== "Bearer" || !apiKey) {
|
|
ws.close(1008, "Invalid Authorization header");
|
|
return;
|
|
}
|
|
|
|
const authenticationResult = await authenticateApiKey(apiKey);
|
|
|
|
if (!authenticationResult) {
|
|
ws.close(1008, "Invalid API key");
|
|
return;
|
|
}
|
|
|
|
const authenticatedEnv = authenticationResult.environment;
|
|
|
|
const authenticatedConnection = new AuthenticatedSocketConnection(
|
|
ws,
|
|
authenticatedEnv,
|
|
req.headers["x-forwarded-for"] ?? req.socket.remoteAddress ?? "unknown"
|
|
);
|
|
|
|
authenticatedConnections.set(authenticatedConnection.id, authenticatedConnection);
|
|
|
|
authenticatedConnection.onClose.attachOnce((closeEvent) => {
|
|
logger.debug("Websocket closed", {
|
|
closeEvent,
|
|
authenticatedConnectionId: authenticatedConnection.id,
|
|
});
|
|
|
|
authenticatedConnections.delete(authenticatedConnection.id);
|
|
});
|
|
|
|
await authenticatedConnection.initialize();
|
|
}
|