mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 10:21:55 +00:00
feat: Effects that shouldn't be needed removed from utils
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Effects } from "../../types"
|
||||
import { createUtils } from "../../util"
|
||||
import { stringFromStdErrOut } from "../../util/stringFromStdErrOut"
|
||||
import { CheckResult } from "./CheckResult"
|
||||
export function containsAddress(x: string, port: number) {
|
||||
const readPorts = x
|
||||
@@ -32,10 +33,17 @@ export async function checkPortListening(
|
||||
Promise.resolve().then(async () => {
|
||||
const hasAddress =
|
||||
containsAddress(
|
||||
await utils.runCommand(`cat /proc/net/tcp`, {}),
|
||||
await utils.childProcess
|
||||
.exec(`cat /proc/net/tcp`, {})
|
||||
.then(stringFromStdErrOut),
|
||||
port,
|
||||
) ||
|
||||
containsAddress(await utils.runCommand("cat /proc/net/udp", {}), port)
|
||||
containsAddress(
|
||||
await utils.childProcess
|
||||
.exec("cat /proc/net/udp", {})
|
||||
.then(stringFromStdErrOut),
|
||||
port,
|
||||
)
|
||||
if (hasAddress) {
|
||||
return { status: "passing", message: options.successMessage }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CommandType, Effects } from "../../types"
|
||||
import { createUtils } from "../../util"
|
||||
import { stringFromStdErrOut } from "../../util/stringFromStdErrOut"
|
||||
import { CheckResult } from "./CheckResult"
|
||||
import { timeoutPromise } from "./index"
|
||||
|
||||
@@ -22,7 +23,7 @@ export const runHealthScript = async (
|
||||
): Promise<CheckResult> => {
|
||||
const utils = createUtils(effects)
|
||||
const res = await Promise.race([
|
||||
utils.runCommand(runCommand, { timeout }),
|
||||
utils.childProcess.exec(runCommand, { timeout }).then(stringFromStdErrOut),
|
||||
timeoutPromise(timeout),
|
||||
]).catch((e) => {
|
||||
console.warn(errorMessage)
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types"
|
||||
import { createUtils } from "../util"
|
||||
type Daemon<Ids extends string, Command extends string, Id extends string> = {
|
||||
id: "" extends Id ? never : Id
|
||||
command: string
|
||||
command: ValidIfNoStupidEscape<Command> | [string, ...string[]]
|
||||
env?: Record<string, string>
|
||||
ready: {
|
||||
display: string | null
|
||||
|
||||
38
lib/test/utils.splitCommand.test.ts
Normal file
38
lib/test/utils.splitCommand.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { getHostname } from "../util/getNetworkInterface"
|
||||
import { splitCommand } from "../util/splitCommand"
|
||||
|
||||
describe("splitCommand ", () => {
|
||||
const inputToExpected = [
|
||||
["cat", ["cat"]],
|
||||
[["cat"], ["cat"]],
|
||||
[
|
||||
["cat", "hello all my homies"],
|
||||
["cat", "hello all my homies"],
|
||||
],
|
||||
["cat hello world", ["cat", "hello", "world"]],
|
||||
["cat hello 'big world'", ["cat", "hello", "big world"]],
|
||||
[`cat hello "big world"`, ["cat", "hello", "big world"]],
|
||||
// Too many spaces
|
||||
["cat ", ["cat"]],
|
||||
[["cat "], ["cat "]],
|
||||
[
|
||||
["cat ", "hello all my homies "],
|
||||
["cat ", "hello all my homies "],
|
||||
],
|
||||
["cat hello world ", ["cat", "hello", "world"]],
|
||||
[
|
||||
" cat hello 'big world' ",
|
||||
["cat", "hello", "big world"],
|
||||
],
|
||||
[
|
||||
` cat hello "big world" `,
|
||||
["cat", "hello", "big world"],
|
||||
],
|
||||
]
|
||||
|
||||
for (const [input, expectValue] of inputToExpected) {
|
||||
test(`should return ${expectValue} for ${input}`, () => {
|
||||
expect(splitCommand(input as any)).toEqual(expectValue)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -10,7 +10,6 @@ export const getHostname = (url: string): HostName | null => {
|
||||
if (!founds) return null
|
||||
const parts = founds.split("@")
|
||||
const last = parts[parts.length - 1] as HostName | null
|
||||
console.log({ url, parts, founds, last })
|
||||
return last
|
||||
}
|
||||
|
||||
|
||||
17
lib/util/splitCommand.ts
Normal file
17
lib/util/splitCommand.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { arrayOf, string } from "ts-matches"
|
||||
import { ValidIfNoStupidEscape } from "../types"
|
||||
|
||||
export const splitCommand = <A>(
|
||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||
): string[] => {
|
||||
if (arrayOf(string).test(command)) return command
|
||||
return String(command)
|
||||
.split('"')
|
||||
.flatMap((x, i) =>
|
||||
i % 2 !== 0
|
||||
? [x]
|
||||
: x.split("'").flatMap((x, i) => (i % 2 !== 0 ? [x] : x.split(" "))),
|
||||
)
|
||||
.map((x) => x.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
6
lib/util/stringFromStdErrOut.ts
Normal file
6
lib/util/stringFromStdErrOut.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export async function stringFromStdErrOut(x: {
|
||||
stdout: string
|
||||
stderr: string
|
||||
}) {
|
||||
return x?.stderr ? Promise.reject(x.stderr) : x.stdout
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import FileHelper from "./fileHelper"
|
||||
import nullIfEmpty from "./nullIfEmpty"
|
||||
import {
|
||||
CheckResult,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
ExtractStore,
|
||||
InterfaceId,
|
||||
PackageId,
|
||||
ValidIfNoStupidEscape,
|
||||
} from "../types"
|
||||
import { GetSystemSmtp } from "./GetSystemSmtp"
|
||||
import { DefaultString } from "../config/configTypes"
|
||||
@@ -34,8 +34,14 @@ import {
|
||||
GetNetworkInterfaces,
|
||||
getNetworkInterfaces,
|
||||
} from "./getNetworkInterfaces"
|
||||
import * as CP from "node:child_process"
|
||||
import { promisify } from "node:util"
|
||||
import { splitCommand } from "./splitCommand"
|
||||
|
||||
import { exec } from "node:child_process"
|
||||
const childProcess = {
|
||||
exec: promisify(CP.exec),
|
||||
execFile: promisify(CP.execFile),
|
||||
}
|
||||
|
||||
export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
checkPortListening(
|
||||
@@ -55,6 +61,7 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
errorMessage?: string
|
||||
},
|
||||
): Promise<CheckResult>
|
||||
childProcess: typeof childProcess
|
||||
createInterface: (options: {
|
||||
name: string
|
||||
id: string
|
||||
@@ -93,15 +100,10 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
}) => GetNetworkInterfaces & WrapperOverWrite
|
||||
}
|
||||
nullIfEmpty: typeof nullIfEmpty
|
||||
readFile: <A>(fileHelper: FileHelper<A>) => ReturnType<FileHelper<A>["read"]>
|
||||
runDaemon: (
|
||||
command: string,
|
||||
runDaemon: <A extends string>(
|
||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||
options: { env?: Record<string, string> },
|
||||
) => Promise<DaemonReturned>
|
||||
runCommand: (
|
||||
command: string,
|
||||
options: { env?: Record<string, string>; timeout?: number },
|
||||
) => Promise<string>
|
||||
store: {
|
||||
get: <Path extends string>(
|
||||
packageId: string,
|
||||
@@ -115,10 +117,6 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
value: ExtractStore<Store, Path>,
|
||||
) => Promise<void>
|
||||
}
|
||||
writeFile: <A>(
|
||||
fileHelper: FileHelper<A>,
|
||||
data: A,
|
||||
) => ReturnType<FileHelper<A>["write"]>
|
||||
}
|
||||
export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
effects: Effects,
|
||||
@@ -135,6 +133,7 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
path: string
|
||||
search: Record<string, string>
|
||||
}) => new NetworkInterfaceBuilder({ ...options, effects }),
|
||||
childProcess,
|
||||
getSystemSmtp: () =>
|
||||
new GetSystemSmtp(effects) as GetSystemSmtp & WrapperOverWrite,
|
||||
|
||||
@@ -143,9 +142,6 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
single: (id: string) => new SingleHost({ id, effects }),
|
||||
multi: (id: string) => new MultiHost({ id, effects }),
|
||||
},
|
||||
readFile: <A>(fileHelper: FileHelper<A>) => fileHelper.read(effects),
|
||||
writeFile: <A>(fileHelper: FileHelper<A>, data: A) =>
|
||||
fileHelper.write(data, effects),
|
||||
nullIfEmpty,
|
||||
|
||||
networkInterface: {
|
||||
@@ -178,45 +174,39 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
) => effects.store.set<Store, Path>({ value, path: path as any }),
|
||||
},
|
||||
|
||||
runDaemon: async (
|
||||
command: string,
|
||||
runDaemon: async <A extends string>(
|
||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||
options: { env?: Record<string, string> },
|
||||
): Promise<DaemonReturned> => {
|
||||
let childProcess: null | {
|
||||
kill(signal?: number | string): void
|
||||
} = null
|
||||
const answer = new Promise<string>(
|
||||
(resolve, reject) =>
|
||||
(childProcess = exec(command, options, (error, stdout, stderr) => {
|
||||
if (error) return reject(error.toString())
|
||||
if (stderr) return reject(stderr.toString())
|
||||
return resolve(stdout.toString())
|
||||
})),
|
||||
)
|
||||
const commands = splitCommand(command)
|
||||
const childProcess = CP.spawn(commands[0], commands.slice(1), options)
|
||||
const answer = new Promise<string>((resolve, reject) => {
|
||||
const output: string[] = []
|
||||
childProcess.stdout.on("data", (data) => {
|
||||
output.push(data.toString())
|
||||
})
|
||||
const outputError: string[] = []
|
||||
childProcess.stderr.on("data", (data) => {
|
||||
outputError.push(data.toString())
|
||||
})
|
||||
|
||||
childProcess.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
return resolve(output.join(""))
|
||||
}
|
||||
return reject(outputError.join(""))
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
wait() {
|
||||
return answer
|
||||
},
|
||||
async term() {
|
||||
childProcess?.kill()
|
||||
childProcess.kill()
|
||||
},
|
||||
}
|
||||
},
|
||||
runCommand: async (
|
||||
command: string,
|
||||
options: { env?: Record<string, string>; timeout?: number },
|
||||
): Promise<string> => {
|
||||
const answer = new Promise<string>((resolve, reject) =>
|
||||
exec(command, options, (error, stdout, stderr) => {
|
||||
if (error) return reject(error.toString())
|
||||
if (stderr) return reject(stderr.toString())
|
||||
return resolve(stdout.toString())
|
||||
}),
|
||||
)
|
||||
|
||||
return answer
|
||||
},
|
||||
checkPortListening: checkPortListening.bind(null, effects),
|
||||
checkWebUrl: checkWebUrl.bind(null, effects),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user