Merge pull request #11 from Start9Labs/feat/more-iface

add hasPrimary and disabled to network interfaces
This commit is contained in:
Matt Hill
2023-05-31 15:24:31 -06:00
committed by GitHub
10 changed files with 120 additions and 34 deletions

View File

@@ -41,12 +41,6 @@ export const customSmtp = Config.of<ConfigSpecOf<SmtpValue>, never>({
required: false,
masked: true,
}),
tls: Value.toggle({
name: "Require Transport Security",
default: true,
description:
"Require TLS transport security. If disabled, email will use plaintext by default and TLS via STARTTLS <strong>if the SMTP server supports it</strong>. If enabled, email will refuse to connect unless the server supports STARTTLS.",
}),
})
/**

View File

@@ -21,6 +21,8 @@ export class NetworkInterfaceBuilder {
name: string
id: string
description: string
hasPrimary: boolean
disabled: boolean
ui: boolean
username: null | string
path: string
@@ -39,7 +41,17 @@ export class NetworkInterfaceBuilder {
async export<Origins extends Origin<Host>[]>(
origins: Origins,
): Promise<Address[] & AddressReceipt> {
const { name, description, id, ui, username, path, search } = this.options
const {
name,
description,
hasPrimary,
disabled,
id,
ui,
username,
path,
search,
} = this.options
const addresses = Array.from(origins).map((o) =>
o.build({ username, path, search, scheme: null }),
@@ -49,6 +61,8 @@ export class NetworkInterfaceBuilder {
interfaceId: id,
name,
description,
hasPrimary,
disabled,
addresses,
ui,
})

View File

@@ -1,8 +1,6 @@
import { MultiHost } from "../interfaces/Host"
import { NetworkInterfaceBuilder } from "../interfaces/NetworkInterfaceBuilder"
import { Effects } from "../types"
import { createUtils } from "../util"
import { sdk } from "./output.sdk"
describe("host", () => {
test("Testing that the types work", () => {
@@ -15,6 +13,8 @@ describe("host", () => {
name: "Foo",
id: "foo",
description: "A Foo",
hasPrimary: false,
disabled: false,
ui: true,
username: "bar",
path: "/baz",

View File

@@ -0,0 +1,20 @@
import { getHostname } from "../util/getNetworkInterface"
describe("getHostname ", () => {
const inputToExpected = [
["http://localhost:3000", "localhost"],
["http://localhost", "localhost"],
["localhost", "localhost"],
["http://127.0.0.1/", "127.0.0.1"],
["http://127.0.0.1/testing/1234?314345", "127.0.0.1"],
["127.0.0.1/", "127.0.0.1"],
["http://mail.google.com/", "mail.google.com"],
["mail.google.com/", "mail.google.com"],
]
for (const [input, expectValue] of inputToExpected) {
test(`should return ${expectValue} for ${input}`, () => {
expect(getHostname(input)).toEqual(expectValue)
})
}
})

View File

@@ -2,6 +2,7 @@ export * as configTypes from "./config/configTypes"
import { InputSpec } from "./config/configTypes"
import { DependenciesReceipt } from "./config/setupConfig"
import { PortOptions } from "./interfaces/Host"
import { UrlString } from "./util/getNetworkInterface"
export type ExportedAction = (options: {
effects: Effects
@@ -143,7 +144,6 @@ export type SmtpValue = {
from: string
login: string
password: string | null | undefined
tls: boolean
}
export type CommandType<A extends string> =
@@ -185,12 +185,16 @@ export type NetworkInterface = {
name: string
/** Human readable description, used as tooltip usually */
description: string
/** Whether or not one address must be the primary address */
hasPrimary: boolean
/** Disabled interfaces do not serve, but they retain their metadata and addresses */
disabled: boolean
/** All URIs */
addresses: Address[]
/** Defaults to false, but describes if this address can be opened in a browser as an
* ui interface
*/
ui?: boolean
ui: boolean
}
// prettier-ignore
export type ExposeAllServicePaths<Store, PreviousPath extends string = ""> =
@@ -370,6 +374,16 @@ export type Effects = {
callback: () => void
}): Promise<NetworkInterface>
/**
* The user sets the primary url for a interface
* @param options
*/
getPrimaryUrl(options: {
packageId?: PackageId
interfaceId: InterfaceId
callback: () => void
}): Promise<UrlString | null>
/**
* There are times that we want to see the addresses that where exported
* @param options.addressId If we want to filter the address id

View File

@@ -4,6 +4,16 @@ import * as regexes from "./regexes"
export type UrlString = string
export type HostId = string
const getHostnameRegex = /^(\w+:\/\/)?([^\/\:]+)(:\d{1,3})?(\/)?/
export const getHostname = (url: string): HostName | null => {
const founds = url.match(getHostnameRegex)?.[2]
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
}
export type Filled = {
hostnames: HostName[]
onionHostnames: HostName[]
@@ -30,12 +40,19 @@ export type NetworkInterfaceFilled = {
name: string
/** Human readable description, used as tooltip usually */
description: string
/** Whether or not the interface has a primary URL */
hasPrimary: boolean
/** Whether or not the interface disabled */
disabled: boolean
/** All URIs */
addresses: FilledAddress[]
/** Defaults to false, but describes if this address can be opened in a browser as an
* ui interface
*/
ui?: boolean
ui: boolean
primaryHostname: HostName | null
primaryUrl: UrlString | null
} & Filled
const either =
<A>(...args: ((a: A) => boolean)[]) =>
@@ -118,6 +135,7 @@ export const filledAddress = (
export const networkInterfaceFilled = (
interfaceValue: NetworkInterface,
primaryUrl: UrlString | null,
addresses: FilledAddress[],
): NetworkInterfaceFilled => {
return {
@@ -147,6 +165,10 @@ export const networkInterfaceFilled = (
get allHostnames() {
return unique(addresses.flatMap((x) => x.allHostnames))
},
get primaryHostname() {
if (primaryUrl == null) return null
return getHostname(primaryUrl)
},
get urls() {
return unique(addresses.flatMap((x) => x.urls))
},
@@ -171,6 +193,7 @@ export const networkInterfaceFilled = (
get allUrls() {
return unique(addresses.flatMap((x) => x.allUrls))
},
primaryUrl,
}
}
const makeInterfaceFilled = async ({
@@ -189,24 +212,32 @@ const makeInterfaceFilled = async ({
packageId,
callback,
})
const hostIdsRecord: { [hostId: HostId]: HostName[] } = Object.fromEntries(
await Promise.all(
unique(interfaceValue.addresses.map((x) => x.hostId)).map(
async (hostId) => [
const hostIdsRecord = Promise.all(
unique(interfaceValue.addresses.map((x) => x.hostId)).map(
async (hostId) =>
[
hostId,
effects.getHostnames({
await effects.getHostnames({
packageId,
hostId,
callback,
}),
],
),
] as const,
),
)
const primaryUrl = effects.getPrimaryUrl({
interfaceId,
packageId,
callback,
})
const fillAddress = filledAddress.bind(null, hostIdsRecord)
const fillAddress = filledAddress.bind(
null,
Object.fromEntries(await hostIdsRecord),
)
const interfaceFilled: NetworkInterfaceFilled = networkInterfaceFilled(
interfaceValue,
await primaryUrl,
interfaceValue.addresses.map(fillAddress),
)
return interfaceFilled

View File

@@ -19,30 +19,39 @@ const makeManyInterfaceFilled = async ({
packageId,
callback,
})
const hostIdsRecord: { [hostId: HostId]: HostName[] } = Object.fromEntries(
const hostIdsRecord = Object.fromEntries(
await Promise.all(
Array.from(
new Set(
interfaceValues.flatMap((x) => x.addresses).map((x) => x.hostId),
),
).map(async (hostId) => [
hostId,
effects.getHostnames({
packageId,
hostId,
callback,
}),
]),
).map(
async (hostId) =>
[
hostId,
await effects.getHostnames({
packageId,
hostId,
callback,
}),
] as const,
),
),
)
const fillAddress = filledAddress.bind(null, hostIdsRecord)
const interfacesFilled: NetworkInterfaceFilled[] = interfaceValues.map(
(interfaceValue) =>
const interfacesFilled: NetworkInterfaceFilled[] = await Promise.all(
interfaceValues.map(async (interfaceValue) =>
networkInterfaceFilled(
interfaceValue,
await effects.getPrimaryUrl({
interfaceId: interfaceValue.interfaceId,
packageId,
callback,
}),
interfaceValue.addresses.map(fillAddress),
),
),
)
return interfacesFilled
}

View File

@@ -56,6 +56,8 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
name: string
id: string
description: string
hasPrimary: boolean
disabled: boolean
ui: boolean
username: null | string
path: string
@@ -114,6 +116,8 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
name: string
id: string
description: string
hasPrimary: boolean
disabled: boolean
ui: boolean
username: null | string
path: string