Files
backroad/app/react/docker/containers/CreateView/BaseForm/PortsMappingField.viewModel.ts

118 lines
2.8 KiB
TypeScript

import { PortMap } from 'docker-types/generated/1.41';
import _ from 'lodash';
import { Protocol, Values } from './PortsMappingField';
export type Range = {
start: number;
end: number;
};
export function toViewModel(portBindings: PortMap): Values {
const parsedPorts = parsePorts(portBindings);
const sortedPorts = sortPorts(parsedPorts);
return combinePorts(sortedPorts);
function isProtocol(value: string): value is Protocol {
return value === 'tcp' || value === 'udp';
}
function parsePorts(portBindings: PortMap): Array<{
hostPort: number;
protocol: Protocol;
containerPort: number;
}> {
return Object.entries(portBindings).flatMap(([key, bindings]) => {
const [containerPort, protocol] = key.split('/');
if (!isProtocol(protocol)) {
throw new Error(`Invalid protocol: ${protocol}`);
}
if (!bindings) {
return [];
}
return bindings.map((binding) => ({
hostPort: parseInt(binding.HostPort || '0', 10),
protocol,
containerPort: parseInt(containerPort, 10),
}));
});
}
function sortPorts(
ports: Array<{
hostPort: number;
protocol: Protocol;
containerPort: number;
}>
) {
return _.sortBy(ports, ['containerPort', 'hostPort', 'protocol']);
}
function combinePorts(
ports: Array<{
hostPort: number;
protocol: Protocol;
containerPort: number;
}>
) {
return ports
.reduce(
(acc, port) => {
const lastPort = acc[acc.length - 1];
if (
lastPort &&
lastPort.containerPort.end === port.containerPort - 1 &&
lastPort.hostPort.end === port.hostPort - 1 &&
lastPort.protocol === port.protocol
) {
lastPort.containerPort.end = port.containerPort;
lastPort.hostPort.end = port.hostPort;
return acc;
}
return [
...acc,
{
hostPort: {
start: port.hostPort,
end: port.hostPort,
},
containerPort: {
start: port.containerPort,
end: port.containerPort,
},
protocol: port.protocol,
},
];
},
[] as Array<{
hostPort: Range;
containerPort: Range;
protocol: Protocol;
}>
)
.map(({ protocol, containerPort, hostPort }) => ({
hostPort: getRange(hostPort.start, hostPort.end),
containerPort: getRange(containerPort.start, containerPort.end),
protocol,
}));
function getRange(start: number, end: number): string {
if (start === end) {
if (start === 0) {
return '';
}
return start.toString();
}
return `${start}-${end}`;
}
}
}