Skip to content
Source
Sign inSign up
Open History to see the last commit

deviceHostsSettings.logic.ts

84 lines3.1 KB

1import type { EnvironmentId, SshDeviceHostConfig } from "@t3tools/contracts";
2​
3export interface DeviceHostEnvironment {
4 readonly environmentId: EnvironmentId;
5 readonly label: string;
6 readonly hosts: ReadonlyArray<SshDeviceHostConfig>;
7}
8​
9export interface DeviceHostGroup {
10 readonly host: SshDeviceHostConfig;
11 readonly members: Array<{
12 readonly environmentId: EnvironmentId;
13 readonly label: string;
14 readonly host: SshDeviceHostConfig;
15 }>;
17​
18/** Only combine matching configurations; ambiguous identities keep their machine's list. */
19export function groupDeviceHosts(
20 environments: ReadonlyArray<DeviceHostEnvironment>,
21): ReadonlyArray<DeviceHostGroup> | null {
22 const groups = new Map<string, DeviceHostGroup>();
23 const identities = new Map<string, string>();
24 const configurations = new Map<string, string>();
25 for (const environment of environments) {
26 const destinations = new Set<string>();
27 for (const host of environment.hosts) {
28 const destination = JSON.stringify([host.target, host.port, host.identityFile]);
29 const configuration = JSON.stringify([host.label, host.target, host.port, host.identityFile]);
30 const previousConfiguration = identities.get(host.id);
31 const targetConfiguration = configurations.get(host.target);
32 const group = groups.get(destination);
33 if (
34 destinations.has(destination) ||
35 (previousConfiguration !== undefined && previousConfiguration !== configuration) ||
36 (targetConfiguration !== undefined && targetConfiguration !== configuration)
37 ) {
38 return null;
39 }
40 destinations.add(destination);
41 identities.set(host.id, configuration);
42 configurations.set(host.target, configuration);
43 const member = {
44 environmentId: environment.environmentId,
45 label: environment.label,
46 host,
47 };
48 if (group) group.members.push(member);
49 else groups.set(destination, { host, members: [member] });
50 }
51 }
52 return [...groups.values()];
54​
55export function updateDeviceHosts(
56 hosts: ReadonlyArray<SshDeviceHostConfig>,
57 host: SshDeviceHostConfig,
58 remove: boolean,
59 original = host,
60): ReadonlyArray<SshDeviceHostConfig> {
61 const sameDestination = (candidate: SshDeviceHostConfig, other: SshDeviceHostConfig) =>
62 candidate.target === other.target &&
63 candidate.port === other.port &&
64 candidate.identityFile === other.identityFile;
65 const findDestination = (destination: SshDeviceHostConfig) => {
66 const matches = hosts.filter((candidate) => sameDestination(candidate, destination));
67 if (matches.length > 1) {
68 throw new Error(
69 "Multiple hosts match this SSH destination. Select the environment to edit its hosts.",
70 );
71 }
72 return matches[0];
73 };
74 const existing =
75 hosts.find((candidate) => candidate.id === original.id) ??
76 findDestination(original) ??
77 (remove ? undefined : findDestination(host));
78 if (remove) return hosts.filter((candidate) => candidate.id !== existing?.id);
79 return existing
80 ? hosts.map((candidate) =>
81 candidate.id === existing.id ? { ...host, id: existing.id } : candidate,
82 )
83 : [...hosts, host];