118 lines
2.8 KiB
TypeScript
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}`;
|
|
}
|
|
}
|
|
}
|