From 3eda2cf0a11cfb9f2f38aee80c6acea00a713463 Mon Sep 17 00:00:00 2001 From: Christian Risi <75698846+CnF-Gris@users.noreply.github.com> Date: Thu, 3 Jul 2025 21:34:58 +0000 Subject: [PATCH] TODO: add Brokers for both SSLTerminationFS and Manual, complete broker manager init Co-authored-by: Oscar Urselli --- .../broker-utils/FileSystem/Endpoint.ts | 202 ++++++++++++++++-- .../FileSystem/endpoints/endpoints.ts | 3 + .../FileSystem/endpoints/manual-fs.ts | 10 + .../FileSystem/endpoints/ssltermination-fs.ts | 114 ++++++++-- .../server/broker-utils/FileSystem/utils.ts | 59 ++++- ...enpoint-manager.ts => endpoint-manager.ts} | 22 +- src/lib/server/enums/endpoints.ts | 6 + src/lib/server/enums/protocols.ts | 46 +++- src/lib/server/utils/constants.ts | 5 +- src/lib/server/utils/filesystem-utils.ts | 4 + src/lib/shared/utils/path-utils.ts | 8 + .../api/program/endpoint/activate/+server.ts | 19 +- .../api/program/endpoint/all/+server.ts | 8 +- .../program/endpoint/deactivate/+server.ts | 21 ++ .../api/program/endpoint/status/+server.ts | 9 + 15 files changed, 484 insertions(+), 52 deletions(-) rename src/lib/server/classes/endpoints/{enpoint-manager.ts => endpoint-manager.ts} (68%) create mode 100644 src/lib/shared/utils/path-utils.ts create mode 100644 src/routes/api/program/endpoint/status/+server.ts diff --git a/src/lib/server/broker-utils/FileSystem/Endpoint.ts b/src/lib/server/broker-utils/FileSystem/Endpoint.ts index 74cfe5c..85552b8 100644 --- a/src/lib/server/broker-utils/FileSystem/Endpoint.ts +++ b/src/lib/server/broker-utils/FileSystem/Endpoint.ts @@ -1,10 +1,11 @@ import type { FSHeader, IEndpointFS } from "$lib/server/broker-utils/FileSystem/endpoints/endpoints" -import { NGINX_BASE } from "$lib/server/utils/constants" +import { NGINX_ACTIVE, NGINX_BASE, NGINX_INACTIVE, NGINX_TRACKED } from "$lib/server/utils/constants" import { doesFileExist, isDir, loadFile } from "$lib/server/utils/filesystem-utils" import { watch, type FSWatcher } from "node:fs" import { parseConf } from "./utils" import { logger } from "$lib/server/utils/logger" -import { EndpointType } from "$lib/server/enums/endpoints" +import { EndpointStatus, EndpointType } from "$lib/server/enums/endpoints" +import { validatePath } from "$lib/shared/utils/path-utils" export class EndpointBrokerManagerFS { @@ -22,35 +23,169 @@ export class EndpointBrokerManagerFS { return EndpointBrokerManagerFS.initialized } - public static init() { + public static async init() { + + if (EndpointBrokerManagerFS.ready) { + // UGLY: be specific + throw new Error("Broker already initialized") + } // TODO: Read all files // TODO: QUICK parse them + parseConf() // TODO: Initialize a file watcher - + EndpointBrokerManagerFS.watcher = EndpointBrokerManagerFS.watchNginxDirectory() + EndpointBrokerManagerFS.initialized = true } public static async createEndpoint(endpoint: IEndpointFS) { - + if (endpoint.type === EndpointType.MANUAL) { + // UGLY: be specific + throw new Error("You can't create a manual conf automatically") + } + + const REAL_PATH = `${NGINX_TRACKED}/${endpoint.path}` + + if (await doesFileExist(REAL_PATH) ) { + // UGLY: be specific + throw new Error("File already existant") + } + + const file = await loadFile(REAL_PATH, true) + await file.lock() + await file.write(endpoint.toConf()) + await file.release() + + } + + public static async deleteEndpoint(path: string) { + + validatePath(path) + + const REAL_PATH = `${NGINX_TRACKED}/${path}` + + if (! await doesFileExist(REAL_PATH)) { + // UGLY: be specific + throw new Error("This path does not exist") + } + + const file = await loadFile(REAL_PATH) + await file.delete() + EndpointBrokerManagerFS.endpoints.delete( + path + ) + } public static async changeEndpoint(path: string, newEndpoint: IEndpointFS) { + validatePath(path) + + const REAL_PATH = `${NGINX_TRACKED}/${path}` + + if (! await doesFileExist(REAL_PATH)) { + // UGLY: more specific + throw new Error("The requested file does not exist") + } + + const epFile = await loadFile(REAL_PATH) + await epFile.lock() + + await epFile.write( + newEndpoint.toConf() + ) + + await epFile.release() + + EndpointBrokerManagerFS.endpoints.set(path, newEndpoint) + + const status = await EndpointBrokerManagerFS.getStatus(path) + + if (status === EndpointStatus.ACTIVE) { + await this.activateEndpoint(path) + } + + + } public static async activateEndpoint(path: string): Promise { + + validatePath(path) + + + const endpoint = EndpointBrokerManagerFS.getEndpointByPath(path) + + if (!endpoint) { + // UGLY: be specific + throw new Error("This specified endpoint doesn't exist") + } + + const activePath = `${NGINX_ACTIVE}/${path}` + + if (! await doesFileExist(activePath)) { + const file = await loadFile(activePath, true) + await file.write( + endpoint.toConf() + ) + + return true + } + + const file = await loadFile(activePath) + await file.lock() + + const fileHash = await file.hash() + + if (endpoint.hash === fileHash) { + await file.release() + return false + } + + await file.write( + endpoint.toConf() + ) + + await file.release() return true + + } + public static async deactivateEndpoint(path: string): Promise { + + validatePath(path) + + const endpoint = EndpointBrokerManagerFS.getEndpointByPath(path) + + if (!endpoint) { + // UGLY: be specific + throw new Error("This specified endpoint doesn't exist") + } + + const activePath = `${NGINX_ACTIVE}/${path}` + + if (! await doesFileExist(activePath)) { + return false + } + + const file = await loadFile(activePath) + await file.delete() + return true + + + } public static getEndpointByPath(path: string): IEndpointFS | null { - const endpoint = EndpointBrokerManagerFS.endpoints.get( + validatePath(path) + + const endpoint = EndpointBrokerManagerFS.endpoints.get( path ) @@ -67,6 +202,26 @@ export class EndpointBrokerManagerFS { return Array.from(EndpointBrokerManagerFS.endpoints.values()) } + public static async getStatus(path: string) { + + validatePath(path) + + const REAL_ACTIVE_PATH = `${NGINX_ACTIVE}/${path}` + const REAL_TRACKED_PATH = `${NGINX_TRACKED}/${path}` + + if (await doesFileExist(REAL_ACTIVE_PATH)) { + return EndpointStatus.ACTIVE + } + + if (await doesFileExist(REAL_TRACKED_PATH)) { + return EndpointStatus.INACTIVE + } + + // UGLY: more specific + throw new Error("This path is non existant") + + } + // MARK: private methods @@ -83,15 +238,22 @@ export class EndpointBrokerManagerFS { recursive: true } - const WATCHER = watch(NGINX_BASE, OPTIONS, async (eventType, filename) => { + const NGINX_TRACK = NGINX_TRACKED + + const WATCHER = watch(NGINX_TRACK, OPTIONS, async (eventType, filename) => { + + if (!filename) { + return + } const RELATIVE_PATH = filename - const FULL_PATH = `${NGINX_BASE}/${RELATIVE_PATH}` + const FULL_PATH = `${NGINX_TRACK}/${RELATIVE_PATH}` + // TODO: check if it's a directory, if so, skip if (await isDir(FULL_PATH)) { - return + return } // UGLY: there may be race conditions, rarely, but @@ -105,21 +267,21 @@ export class EndpointBrokerManagerFS { case "change": { const oldEndpoint = EndpointBrokerManagerFS.endpoints.get( - FULL_PATH + RELATIVE_PATH ) if (!oldEndpoint) { logger.debug(`File changed but was never tracked\nPATH: ${FULL_PATH}`, "EP Manager") - return - } - - // Nothing to do, it's not managed by us - if(oldEndpoint.type === EndpointType.MANUAL) { return } - + // Nothing to do, it's not managed by us + if (oldEndpoint.type === EndpointType.MANUAL) { + return + } + + const file = await loadFile(FULL_PATH) await file.lock() @@ -127,7 +289,7 @@ export class EndpointBrokerManagerFS { const newHash = await file.hash() const oldHash = oldEndpoint.hash - + if (newHash === oldHash) { // Files are equal // or we are very unlucky @@ -143,7 +305,7 @@ export class EndpointBrokerManagerFS { const fsHeader: FSHeader = { name: filename!.split("/").pop()!, stats: stats, - path: FULL_PATH, + path: RELATIVE_PATH, hash: hash } @@ -182,7 +344,7 @@ export class EndpointBrokerManagerFS { // UGLY: not checking for false values // UGLY: hints that something went wrong EndpointBrokerManagerFS.endpoints.delete( - FULL_PATH + RELATIVE_PATH ) } @@ -210,7 +372,7 @@ export class EndpointBrokerManagerFS { const endpoint = parseConf(fsHeader, conf) EndpointBrokerManagerFS.endpoints.set( - FULL_PATH, + RELATIVE_PATH, endpoint ) diff --git a/src/lib/server/broker-utils/FileSystem/endpoints/endpoints.ts b/src/lib/server/broker-utils/FileSystem/endpoints/endpoints.ts index a7d45ed..8ec01ce 100644 --- a/src/lib/server/broker-utils/FileSystem/endpoints/endpoints.ts +++ b/src/lib/server/broker-utils/FileSystem/endpoints/endpoints.ts @@ -1,3 +1,4 @@ +import type { IEndpoint } from "$lib/server/classes/endpoints/endpoints-interfaces"; import { EndpointType } from "$lib/server/enums/endpoints"; import type { FileStats } from "$lib/server/utils/filesystem-utils"; @@ -28,6 +29,8 @@ export interface IEndpointFS { headerHash(): string + toIEndpoint(): IEndpoint + } export type FSHeader = { diff --git a/src/lib/server/broker-utils/FileSystem/endpoints/manual-fs.ts b/src/lib/server/broker-utils/FileSystem/endpoints/manual-fs.ts index fb98d5f..ddaa603 100644 --- a/src/lib/server/broker-utils/FileSystem/endpoints/manual-fs.ts +++ b/src/lib/server/broker-utils/FileSystem/endpoints/manual-fs.ts @@ -1,6 +1,8 @@ import { EndpointType } from "$lib/server/enums/endpoints"; import type { Stats } from "fs"; import type { FSHeader, IEndpointFS } from "./endpoints"; +import type { IEndpoint } from "$lib/server/classes/endpoints/endpoints-interfaces"; +import { Manual } from "$lib/server/classes/endpoints/manual-endpoint"; // TODO: add broker implementation @@ -33,6 +35,14 @@ export class ManualFS implements IEndpointFS { this.path = path this.body = body } + toIEndpoint(): IEndpoint { + + return new Manual( + this.name, + this.path, + this.body + ) + } toConf(): string { return this.body diff --git a/src/lib/server/broker-utils/FileSystem/endpoints/ssltermination-fs.ts b/src/lib/server/broker-utils/FileSystem/endpoints/ssltermination-fs.ts index 93fcc8a..b7e0661 100644 --- a/src/lib/server/broker-utils/FileSystem/endpoints/ssltermination-fs.ts +++ b/src/lib/server/broker-utils/FileSystem/endpoints/ssltermination-fs.ts @@ -1,10 +1,12 @@ import { EndpointType } from "$lib/server/enums/endpoints" -import { httpVersion, proxyProtocol, secureProtocol, type NginxProtocol } from "$lib/server/enums/protocols" +import { httpVersion, protocolToString, proxyProtocol, secureProtocol, stringToProtocol, type NginxProtocol } from "$lib/server/enums/protocols" import { validatePort } from "$lib/server/utils/ports-utils" import type { Stats } from "fs" import type { FSHeader, IEndpointFS } from "./endpoints" -import { createHeader } from "../utils" +import { createHeader, parseDefaultHeader, parseGenericHeader } from "../utils" import { hashUtil } from "$lib/server/utils/filesystem-utils" +import type { IEndpoint } from "$lib/server/classes/endpoints/endpoints-interfaces" +import { SSLTermination } from "$lib/server/classes/endpoints/ssl-termination-endpoint" // TODO: add broker implementation @@ -20,7 +22,9 @@ export class SSLTerminationFS implements IEndpointFS { public name: string public stats: Stats - public path: string + public get path() { + return `${this.protocol}/name.conf` + } public hash: string public sslPort: number public clearPort: number @@ -35,7 +39,6 @@ export class SSLTerminationFS implements IEndpointFS { constructor( name: string, stats: Stats, - path: string, hash: string, sslPort: number, clearPort: number, @@ -48,7 +51,6 @@ export class SSLTerminationFS implements IEndpointFS { this.name = name this.stats = stats - this.path = path this.hash = hash this.sslPort = sslPort this.clearPort = clearPort @@ -60,6 +62,20 @@ export class SSLTerminationFS implements IEndpointFS { } + public toIEndpoint(): IEndpoint { + return new SSLTermination( + this.name, + this.path, + this.sslPort, + this.clearPort, + this.servicePort, + this.serviceEndpoint, + this.protocol, + this.certificateURI, + this.privateKeyURI + ) + } + headerHash(): string { return hashUtil( @@ -68,7 +84,7 @@ export class SSLTerminationFS implements IEndpointFS { } toConf(): string { - + const HEADER = this.createHeader() const SSL_SERVER = this.createSSLServer() const CLEAR_SERVER = this.createClearServer() @@ -78,7 +94,7 @@ export class SSLTerminationFS implements IEndpointFS { return CONF } - ports(): number[]{ + ports(): number[] { return [ this.sslPort, @@ -87,8 +103,78 @@ export class SSLTerminationFS implements IEndpointFS { } - public static parseConf(fsHeader: FSHeader, conf: string) : SSLTerminationFS { + public static parseConf(fsHeader: FSHeader, conf: string): SSLTerminationFS { // TODO: parse header + const defHeader = parseDefaultHeader(conf) + + const keyValue = parseGenericHeader(conf) + + const name = keyValue.get("NAME") + + if (!name) { + throw new Error("Could not parse") + } + + const protocol = stringToProtocol( + keyValue.get("PROTOCOL") ?? "" + ) + + const sslPort = Number.parseInt( + keyValue.get( + "SSL_PORT" + ) ?? "" + ) + + validatePort(sslPort) + + const clearPort = Number.parseInt( + keyValue.get( + "CLEAR_PORT" + ) ?? "" + ) + + validatePort(clearPort) + + const servicePort = Number.parseInt( + keyValue.get( + "SERVICE_PORT" + ) ?? "" + ) + + validatePort(servicePort) + + const serviceEndpoint = keyValue.get("SERVICE_ENDPOINT") + + if (!serviceEndpoint) { + throw new Error("Could not parse") + } + + const certificateURI = keyValue.get("CERTIFICATE_PATH") + + if (!certificateURI) { + throw new Error("Could not parse") + } + + const privateKeyURI = keyValue.get("KEY_PATH") + + if (!privateKeyURI) { + throw new Error("Could not parse") + } + + return new SSLTerminationFS( + name, + fsHeader.stats, + fsHeader.hash, + sslPort, + clearPort, + servicePort, + serviceEndpoint, + protocol, + certificateURI, + privateKeyURI + ) + + } @@ -101,8 +187,8 @@ export class SSLTerminationFS implements IEndpointFS { value: this.name }, { - key: "PROTOCOL", - value: this.protocol + key: "PROTOCOL", + value: protocolToString(this.protocol) }, { key: "SSL_PORT", @@ -133,14 +219,14 @@ export class SSLTerminationFS implements IEndpointFS { } // UGLY: refactor into a flexible method - private createSSLServer() { + private createSSLServer() { const CLEAR_PROTOCOL = `${this.protocol}` const HTTP_VERSION = httpVersion(this.protocol) const PROXY_OPTION = proxyProtocol(this.protocol) // UGLY: put to constants - let conf = [ + let conf = [ "server {\n", "\tmore_clear_headers Server;\n", `\tlisten ${this.sslPort};` @@ -169,14 +255,14 @@ export class SSLTerminationFS implements IEndpointFS { return conf.join("\n") } - private createClearServer() { + private createClearServer() { const SSL_PROTOCOL = secureProtocol(this.protocol) const HTTP_VERSION = httpVersion(this.protocol) const PROXY_OPTION = proxyProtocol(this.protocol) // UGLY: put to constants - let conf = [ + let conf = [ "server {\n", "\tmore_clear_headers Server;\n", `\tlisten ${this.clearPort};` diff --git a/src/lib/server/broker-utils/FileSystem/utils.ts b/src/lib/server/broker-utils/FileSystem/utils.ts index ba349cf..8b3d0b0 100644 --- a/src/lib/server/broker-utils/FileSystem/utils.ts +++ b/src/lib/server/broker-utils/FileSystem/utils.ts @@ -6,18 +6,26 @@ import { SSLTerminationFS } from "./endpoints/ssltermination-fs" export const HEADER_BOUNDARY = "**********************************************************" export const HEADER_UPPER = `/*${HEADER_BOUNDARY}` export const HEADER_LOWER = `${HEADER_BOUNDARY}*/` +export const SPLITTING = ": " +export const DEFAULT_HEADER_LEN = 5 +export const CUSTOM_HEADER_START = DEFAULT_HEADER_LEN + 1 export type HeaderKeyValueFS = { key: string, value: any } +export type DefaultHeader = { + type: EndpointType, + name: string +} + export function parseConf( fsHeader: FSHeader, conf: string ): IEndpointFS { - const TYPE = parseDefaultConf(conf) + const TYPE = getType(conf) switch (TYPE) { @@ -44,7 +52,7 @@ export function createHeader(endpoint: IEndpointFS, variables?: HeaderKeyValueFS for (const variable of variables) { header.push( - `${variable.key}: ${variable.value}` + `${variable.key}${SPLITTING}${variable.value}` ) } @@ -54,7 +62,7 @@ export function createHeader(endpoint: IEndpointFS, variables?: HeaderKeyValueFS } -function parseDefaultConf(conf: string): EndpointType { +function getType(conf: string): EndpointType { /** Row (remember array order) where we find the type */ const TYPE_DATA_ROW = 2 /** What separator was used */ @@ -76,4 +84,49 @@ function parseDefaultConf(conf: string): EndpointType { return matchEndpoint(label) +} + +export function parseDefaultHeader(conf: string) : DefaultHeader { + + const confLines = conf.split("\n") + + const HEADER = confLines.slice(0, DEFAULT_HEADER_LEN + 1) + + const type = matchEndpoint(HEADER[2].split(" ")[1]) + const name = HEADER[3].split(" ")[1] + + return { + type: type, + name: name + } +} + +export function parseGenericHeader(conf: string) : Map { + const confLines = conf.split("\n") + + const headerProbableLines = confLines.slice(CUSTOM_HEADER_START) + const keyValueMap = new Map() + + let index = 0 + let parsed = false + + while (!parsed) { + const line = headerProbableLines[index] + + if (line === HEADER_LOWER) { + parsed = true + continue + } + + const keyValue = line.split(SPLITTING) + + keyValueMap.set( + keyValue[0], + keyValue[1] + ) + + index++ + } + + return keyValueMap } \ No newline at end of file diff --git a/src/lib/server/classes/endpoints/enpoint-manager.ts b/src/lib/server/classes/endpoints/endpoint-manager.ts similarity index 68% rename from src/lib/server/classes/endpoints/enpoint-manager.ts rename to src/lib/server/classes/endpoints/endpoint-manager.ts index 237390a..fd300c2 100644 --- a/src/lib/server/classes/endpoints/enpoint-manager.ts +++ b/src/lib/server/classes/endpoints/endpoint-manager.ts @@ -33,17 +33,31 @@ export class EndpointManagerApp { return await EndpointBrokerManagerFS.deactivateEndpoint(path) } + public static async getStatus(path: string) { + return await EndpointBrokerManagerFS.getStatus(path) + } + public static getEndpointByPath(path: string): IEndpoint | null { - // UGLY: parse - return EndpointBrokerManagerFS.getEndpointByPath(path) + + const endpoint = EndpointBrokerManagerFS.getEndpointByPath(path) + + if(!endpoint) { + return null + } + + return endpoint.toIEndpoint() } public static async getAll(): Promise { - // UGLY: parse - return await EndpointBrokerManagerFS.getAll() + + const endpoints = await EndpointBrokerManagerFS.getAll() + + return endpoints.map( (endpoint) => { + return endpoint.toIEndpoint() + }) } diff --git a/src/lib/server/enums/endpoints.ts b/src/lib/server/enums/endpoints.ts index e98fe31..6433aa7 100644 --- a/src/lib/server/enums/endpoints.ts +++ b/src/lib/server/enums/endpoints.ts @@ -5,6 +5,12 @@ export enum EndpointType { } + +export enum EndpointStatus { + ACTIVE, + INACTIVE +} + export function matchEndpoint(label: string) { switch(label) { diff --git a/src/lib/server/enums/protocols.ts b/src/lib/server/enums/protocols.ts index 852b316..61eb807 100644 --- a/src/lib/server/enums/protocols.ts +++ b/src/lib/server/enums/protocols.ts @@ -1,14 +1,14 @@ export enum NginxProtocol { - HTTP = "http", - HTTP2 = "http", - QUIC = "http", - GRPC = "grpc" + HTTP = "http", + HTTP2 = "http", + QUIC = "http", + GRPC = "grpc" } // UGLY: move these fnction into utils export function httpVersion(protocol: NginxProtocol): number { - - switch(protocol) { + + switch (protocol) { case NginxProtocol.HTTP2: case NginxProtocol.GRPC: return 2 @@ -19,12 +19,44 @@ export function httpVersion(protocol: NginxProtocol): number { } } +export function protocolToString(procotol: NginxProtocol) { + switch (procotol) { + case NginxProtocol.HTTP: + return "HTTP" + case NginxProtocol.HTTP2: + return "HTTP2" + case NginxProtocol.QUIC: + return "QUIC" + case NginxProtocol.GRPC: + return "GRPC" + } +} + +export function stringToProtocol(label: string) { + switch (label) { + case "HTTP": + return NginxProtocol.HTTP + + case "HTTP2": + return NginxProtocol.HTTP2 + + case "QUIC": + return NginxProtocol.QUIC + + case "GRPC": + return NginxProtocol.GRPC + default: + // UGLY: be specific + throw new Error("Protocol not found") + } +} + export function secureProtocol(protocol: NginxProtocol) { return `${protocol}s` } export function proxyProtocol(protocol: NginxProtocol) { - switch(protocol) { + switch (protocol) { case NginxProtocol.GRPC: return "grpc_pass" default: diff --git a/src/lib/server/utils/constants.ts b/src/lib/server/utils/constants.ts index 8dba53f..14228ac 100644 --- a/src/lib/server/utils/constants.ts +++ b/src/lib/server/utils/constants.ts @@ -7,4 +7,7 @@ export const SERVER_PUBLIC_KEY_PATH = `${SERVER_PRIVATE_DIR}/pub.pem` export const DEBUG = import.meta.env.DEV // NGINX -export const NGINX_BASE = "/etc/nginx" \ No newline at end of file +export const NGINX_BASE = "/etc/nginx" +export const NGINX_INACTIVE = `${NGINX_BASE}/inactive` +export const NGINX_ACTIVE = `${NGINX_BASE}/active` +export const NGINX_TRACKED = NGINX_INACTIVE \ No newline at end of file diff --git a/src/lib/server/utils/filesystem-utils.ts b/src/lib/server/utils/filesystem-utils.ts index 236f05f..f3feb1b 100644 --- a/src/lib/server/utils/filesystem-utils.ts +++ b/src/lib/server/utils/filesystem-utils.ts @@ -79,6 +79,10 @@ export class FileHandle { this.fd = null } + public async delete() { + await Node.unlink(this.path) + } + } diff --git a/src/lib/shared/utils/path-utils.ts b/src/lib/shared/utils/path-utils.ts new file mode 100644 index 0000000..f62ca59 --- /dev/null +++ b/src/lib/shared/utils/path-utils.ts @@ -0,0 +1,8 @@ +export function validatePath(path: string) { + + const regex = new RegExp(".*\.\..*") + if (regex.test(path)) { + // UGLY: be specific + throw new Error("Thi spath is invalid") + } +} \ No newline at end of file diff --git a/src/routes/api/program/endpoint/activate/+server.ts b/src/routes/api/program/endpoint/activate/+server.ts index 7e7b198..2880169 100644 --- a/src/routes/api/program/endpoint/activate/+server.ts +++ b/src/routes/api/program/endpoint/activate/+server.ts @@ -1,6 +1,21 @@ -import { RequestHandler } from "@sveltejs/kit"; +import { EndpointManagerApp } from "$lib/server/classes/endpoints/endpoint-manager"; +import { validatePath } from "$lib/shared/utils/path-utils"; +import { type RequestHandler, error } from "@sveltejs/kit"; -export const PATCH: RequestHandler = ({ url }) => { +export const PATCH: RequestHandler = async ({ request }) => { + let path = await request.json(); + try { + validatePath(path); + + let res = await EndpointManagerApp.activateEndpoint(path); + + return new Response(null, { + status: res ? 200 : 304 + }); + } + catch (e) { + return error(400, "Bad Request"); + } }; \ No newline at end of file diff --git a/src/routes/api/program/endpoint/all/+server.ts b/src/routes/api/program/endpoint/all/+server.ts index 0cc850c..06f2365 100644 --- a/src/routes/api/program/endpoint/all/+server.ts +++ b/src/routes/api/program/endpoint/all/+server.ts @@ -1,3 +1,9 @@ -export const GET: RequestHandler = ({}) => { +import { EndpointManagerApp } from "$lib/server/classes/endpoints/endpoint-manager"; +import { type RequestHandler, json } from "@sveltejs/kit"; + + +export const GET: RequestHandler = async ({ }) => { + let endpoints = await EndpointManagerApp.getAll(); + return json(endpoints); } \ No newline at end of file diff --git a/src/routes/api/program/endpoint/deactivate/+server.ts b/src/routes/api/program/endpoint/deactivate/+server.ts index e69de29..726f526 100644 --- a/src/routes/api/program/endpoint/deactivate/+server.ts +++ b/src/routes/api/program/endpoint/deactivate/+server.ts @@ -0,0 +1,21 @@ +import { EndpointManagerApp } from "$lib/server/classes/endpoints/endpoint-manager"; +import { validatePath } from "$lib/shared/utils/path-utils"; +import { type RequestHandler, error } from "@sveltejs/kit"; + + +export const PATCH: RequestHandler = async ({ request }) => { + let path = await request.json(); + + try { + validatePath(path); + + let res = await EndpointManagerApp.deactivateEndpoint(path); + + return new Response(null, { + status: res ? 200 : 304 + }); + } + catch (e) { + return error(400, "Bad Request"); + } +}; \ No newline at end of file diff --git a/src/routes/api/program/endpoint/status/+server.ts b/src/routes/api/program/endpoint/status/+server.ts new file mode 100644 index 0000000..88ac0b0 --- /dev/null +++ b/src/routes/api/program/endpoint/status/+server.ts @@ -0,0 +1,9 @@ +import { EndpointManagerApp } from "$lib/server/classes/endpoints/endpoint-manager"; +import { type RequestHandler, error, json } from "@sveltejs/kit"; + + +export const GET: RequestHandler = async ({}) => { + let status = await EndpointManagerApp.getStatus(); + + return json({ status }); +}; \ No newline at end of file