feat(core): event queue, Ethernet, switch, ARP, IPv4, ICMP, routing and firewall
First slice of the TypeScript port of the filius-ipad runtime engine, with 29 tests ported from the Swift suite. Parts not ported yet throw NotPortedError instead of guessing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
// Ported from filius-ipad (GPLv2/GPLv3):
|
||||
// ios/FiliusPad/TopologyEditor/Model/TopologyNode.swift
|
||||
// Java counterpart: filius.hardware.knoten.* (port counts per device kind).
|
||||
|
||||
import type { Id } from '../ids.js';
|
||||
|
||||
export type NodeKind =
|
||||
| 'pc'
|
||||
| 'notebook'
|
||||
| 'networkSwitch'
|
||||
| 'router'
|
||||
| 'gateway'
|
||||
| 'remoteLink'
|
||||
| 'unsupported';
|
||||
|
||||
export function isPcClassEndpoint(kind: NodeKind): boolean {
|
||||
return kind === 'pc' || kind === 'notebook';
|
||||
}
|
||||
|
||||
export type HostLabelPolicy = 'manual' | 'ipAddress' | 'macAddress' | 'ipAndMAC';
|
||||
|
||||
export interface PortMetadata {
|
||||
readonly id: Id;
|
||||
label: string;
|
||||
isOccupied: boolean;
|
||||
/** Canonical (upper case, colon separated) or undefined. */
|
||||
readonly importedMacAddress?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The MAC address of a port nobody gave one: `02:` followed by the last ten
|
||||
* hex digits of the port's UUID — stable across saves, locally administered.
|
||||
*/
|
||||
export function stableGeneratedMacAddress(portId: Id): string {
|
||||
const compact = portId.toUpperCase().replaceAll('-', '');
|
||||
const suffix = compact.slice(-10);
|
||||
const octets = ['02'];
|
||||
for (let offset = 0; offset < suffix.length; offset += 2) {
|
||||
octets.push(suffix.slice(offset, offset + 2).toUpperCase());
|
||||
}
|
||||
return octets.join(':');
|
||||
}
|
||||
|
||||
/** Six colon-separated pairs of hex digits, upper-cased; anything else is undefined. */
|
||||
export function canonicalMacAddress(value: string | undefined | null): string | undefined {
|
||||
if (value === undefined || value === null) return undefined;
|
||||
const segments = value.trim().split(':');
|
||||
if (segments.length !== 6) return undefined;
|
||||
if (!segments.every((segment) => /^[0-9A-Fa-f]{2}$/.test(segment))) return undefined;
|
||||
return segments.map((segment) => segment.toUpperCase()).join(':');
|
||||
}
|
||||
|
||||
export function effectiveMacAddress(port: PortMetadata): string {
|
||||
return port.importedMacAddress ?? stableGeneratedMacAddress(port.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name a new device gets. These are the Java FILIUS device names; the
|
||||
* editor shows them translated (packages/editor i18n), the model keeps them
|
||||
* as they appear in a Java .fls file.
|
||||
*/
|
||||
export function defaultDisplayName(kind: NodeKind): string {
|
||||
switch (kind) {
|
||||
case 'pc':
|
||||
return 'Rechner';
|
||||
case 'notebook':
|
||||
return 'Notebook';
|
||||
case 'networkSwitch':
|
||||
return 'Switch';
|
||||
case 'router':
|
||||
return 'Vermittlungsrechner';
|
||||
case 'gateway':
|
||||
return 'Gateway';
|
||||
case 'remoteLink':
|
||||
return 'Remote Link';
|
||||
case 'unsupported':
|
||||
return 'Unbekanntes Gerät';
|
||||
}
|
||||
}
|
||||
|
||||
/** Labels of the ports a new device of this kind has, in order. */
|
||||
export function defaultPortLabels(kind: NodeKind): string[] {
|
||||
switch (kind) {
|
||||
case 'pc':
|
||||
case 'notebook':
|
||||
return ['eth0'];
|
||||
case 'networkSwitch':
|
||||
// Java Switch constructs exactly 24 physical ports.
|
||||
return Array.from({ length: 24 }, (_, index) => `sw${index + 1}`);
|
||||
case 'router':
|
||||
// Java Vermittlungsrechner starts with one configurable network interface.
|
||||
return ['rt1'];
|
||||
case 'gateway':
|
||||
// Java Gateway has fixed WAN (index 0) and LAN (index 1) interfaces.
|
||||
return ['wan0', 'lan0'];
|
||||
case 'remoteLink':
|
||||
// One local physical attachment, matching the Java Modem.
|
||||
return ['remote0'];
|
||||
case 'unsupported':
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user