TODO: add Brokers for both SSLTerminationFS and Manual, complete broker manager init
Co-authored-by: Oscar Urselli <oscar0urselli@users.noreply.github.com>
This commit is contained in:
parent
f23cb0e1d2
commit
3eda2cf0a1
@ -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<boolean> {
|
||||
|
||||
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<boolean> {
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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};`
|
||||
|
||||
@ -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<string, string> {
|
||||
const confLines = conf.split("\n")
|
||||
|
||||
const headerProbableLines = confLines.slice(CUSTOM_HEADER_START)
|
||||
const keyValueMap = new Map<string, string>()
|
||||
|
||||
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
|
||||
}
|
||||
@ -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<IEndpoint[]> {
|
||||
// UGLY: parse
|
||||
return await EndpointBrokerManagerFS.getAll()
|
||||
|
||||
const endpoints = await EndpointBrokerManagerFS.getAll()
|
||||
|
||||
return endpoints.map( (endpoint) => {
|
||||
return endpoint.toIEndpoint()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,12 @@ export enum EndpointType {
|
||||
|
||||
}
|
||||
|
||||
|
||||
export enum EndpointStatus {
|
||||
ACTIVE,
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
export function matchEndpoint(label: string) {
|
||||
|
||||
switch(label) {
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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"
|
||||
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
|
||||
@ -79,6 +79,10 @@ export class FileHandle {
|
||||
this.fd = null
|
||||
}
|
||||
|
||||
public async delete() {
|
||||
await Node.unlink(this.path)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
8
src/lib/shared/utils/path-utils.ts
Normal file
8
src/lib/shared/utils/path-utils.ts
Normal file
@ -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")
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
};
|
||||
@ -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);
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
};
|
||||
9
src/routes/api/program/endpoint/status/+server.ts
Normal file
9
src/routes/api/program/endpoint/status/+server.ts
Normal file
@ -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 });
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user