feat(editor): F4.5b the device sheet for routers and home routers
Measured first: SheetRun now types into FILIUS' router and home router
panels, records five forwarding tables (holeTabelle) and steps in the
panel's table. Java turns a card address that passes the pattern but not
IP.ipCheck (".0.0.1") into null and the router panel throws; an empty
gateway is marked red yet taken; a refused table cell is stored as null;
a home router's DHCP client leaves its DHCP server running. None of the
nulls is adopted. The core's routeTableRows matches all five tables.
- doc: card addresses (the first card mirrored in the device's settings),
router gateway, RIP, manual routes (a new row once all four cells pass,
a cell, removal); the sheet reads cards with what their cable joins and
the whole table
- editor: Java's tabs (general, each card titled by its address, the
forwarding table greyed out under RIP; general, LAN, WAN on a home
router); the open card's cable drawn active in Java's green
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+102
-6
@@ -1,12 +1,24 @@
|
||||
// What the device sheet shows of a device, read straight from the document:
|
||||
// the fields of FILIUS' settings panel of its kind (JHostKonfiguration,
|
||||
// JSwitchKonfiguration, JModemKonfiguration). A router's and a home router's
|
||||
// sheet show their name only, until their own panels follow.
|
||||
// JSwitchKonfiguration, JModemKonfiguration, JVermittlungsrechnerKonfiguration
|
||||
// with its forwarding table, JGatewayConfiguration).
|
||||
|
||||
import * as Y from 'yjs';
|
||||
import { defaultSwitchConfiguration, DEFAULT_SWITCH_RETENTION_MILLISECONDS, forwardsIPv4ByDefault, stableGeneratedMacAddress, type HostLabelPolicy, type NodeKind } from '@mdg-filius/core';
|
||||
import {
|
||||
defaultSwitchConfiguration,
|
||||
DEFAULT_SWITCH_RETENTION_MILLISECONDS,
|
||||
forwardsIPv4ByDefault,
|
||||
routeTableRows,
|
||||
stableGeneratedMacAddress,
|
||||
type HostLabelPolicy,
|
||||
type ManualRoute,
|
||||
type NodeKind,
|
||||
type RouteRow,
|
||||
} from '@mdg-filius/core';
|
||||
import { modemPort } from '@mdg-filius/fls';
|
||||
import { inOrder, ROOTS } from './projectDoc.js';
|
||||
import { fromY } from './values.js';
|
||||
import { nodeLabel } from './view.js';
|
||||
|
||||
export interface HostSheet {
|
||||
readonly kind: 'pc' | 'notebook';
|
||||
@@ -44,16 +56,73 @@ export interface ModemSheet {
|
||||
readonly port: number;
|
||||
}
|
||||
|
||||
/** A router's or home router's card. */
|
||||
export interface InterfaceSheet {
|
||||
readonly portId: string;
|
||||
readonly ipAddress: string;
|
||||
readonly subnetMask: string;
|
||||
readonly macAddress: string;
|
||||
/** The device at the other end of its cable (its label, as Java names it) and the cable; null without one. */
|
||||
readonly connected: { readonly device: string; readonly link: string } | null;
|
||||
}
|
||||
|
||||
export interface RouterSheet {
|
||||
readonly kind: 'router';
|
||||
readonly name: string;
|
||||
readonly gateway: string;
|
||||
readonly rip: boolean;
|
||||
/** Shown, not changed: Java's panel greys it out. */
|
||||
readonly ipForwarding: boolean;
|
||||
readonly interfaces: readonly InterfaceSheet[];
|
||||
/** The manual rows, in their order. */
|
||||
readonly routes: readonly ManualRoute[];
|
||||
/** The whole table as Java shows it (Weiterleitungstabelle.holeTabelle): own addresses and networks, localhost, the manual rows, the gateway. */
|
||||
readonly table: readonly RouteRow[];
|
||||
}
|
||||
|
||||
export interface HomeRouterSheet {
|
||||
readonly kind: 'gateway';
|
||||
readonly name: string;
|
||||
readonly gateway: string;
|
||||
readonly ipForwarding: boolean;
|
||||
/** DHCP for the WAN card. */
|
||||
readonly dhcpClient: boolean;
|
||||
readonly wan: InterfaceSheet;
|
||||
readonly lan: InterfaceSheet;
|
||||
}
|
||||
|
||||
export interface NameSheet {
|
||||
readonly kind: Exclude<NodeKind, 'pc' | 'notebook' | 'networkSwitch' | 'remoteLink'>;
|
||||
readonly kind: 'unsupported';
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
export type DeviceSheet = HostSheet | SwitchSheet | ModemSheet | NameSheet;
|
||||
export type DeviceSheet = HostSheet | SwitchSheet | ModemSheet | RouterSheet | HomeRouterSheet | NameSheet;
|
||||
|
||||
const settingsOf = (node: Y.Map<unknown>) => node.get('settings') as Y.Map<unknown>;
|
||||
const setting = (node: Y.Map<unknown>, key: string) => settingsOf(node).get(key) as Y.Map<unknown> | undefined;
|
||||
|
||||
const text = (map: Y.Map<unknown> | undefined, key: string) => (map?.get(key) as string | undefined) ?? '';
|
||||
|
||||
/** A router's or home router's cards, each with what its cable joins. */
|
||||
function interfacesOf(doc: Y.Doc, id: string, node: Y.Map<unknown>): InterfaceSheet[] {
|
||||
const all = doc.getMap<Y.Map<unknown>>(ROOTS.nodes);
|
||||
const links = inOrder(doc.getMap<Y.Map<unknown>>(ROOTS.links));
|
||||
return (node.get('ports') as Y.Array<Y.Map<unknown>>).toArray().map((port) => {
|
||||
const portId = port.get('id') as string;
|
||||
const config = port.get('config') as Y.Map<unknown> | undefined;
|
||||
const cable = links.find(([, link]) => (link.get('sourceNode') === id && link.get('sourcePort') === portId) || (link.get('targetNode') === id && link.get('targetPort') === portId));
|
||||
const other =
|
||||
cable === undefined ? undefined : all.get((cable[1].get('sourceNode') === id && cable[1].get('sourcePort') === portId ? cable[1].get('targetNode') : cable[1].get('sourceNode')) as string);
|
||||
return {
|
||||
portId,
|
||||
ipAddress: text(config, 'ipAddress'),
|
||||
subnetMask: text(config, 'subnetMask'),
|
||||
macAddress: (port.get('mac') as string | undefined) ?? stableGeneratedMacAddress(portId),
|
||||
connected: cable === undefined || other === undefined ? null : { device: nodeLabel(other), link: cable[0] },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** The sheet of a device, or undefined when the document has no such device. */
|
||||
export function deviceSheet(doc: Y.Doc, id: string): DeviceSheet | undefined {
|
||||
const all = doc.getMap<Y.Map<unknown>>(ROOTS.nodes);
|
||||
@@ -106,7 +175,34 @@ export function deviceSheet(doc: Y.Doc, id: string): DeviceSheet | undefined {
|
||||
}
|
||||
case 'remoteLink':
|
||||
return { kind, name, port: modemPort(setting(node, 'remoteLink')?.get('pairIdentifier') as string | undefined) };
|
||||
default:
|
||||
case 'router': {
|
||||
const interfaces = interfacesOf(doc, id, node);
|
||||
const gateway = text(setting(node, 'device'), 'defaultGateway');
|
||||
const routes = (fromY(settingsOf(node).get('routes')) ?? []) as unknown as ManualRoute[];
|
||||
return {
|
||||
kind,
|
||||
name,
|
||||
gateway,
|
||||
rip: settingsOf(node).get('rip') === true,
|
||||
ipForwarding: (settingsOf(node).get('ipForwarding') as boolean | undefined) ?? forwardsIPv4ByDefault(kind),
|
||||
interfaces,
|
||||
routes,
|
||||
table: routeTableRows(interfaces, routes, gateway),
|
||||
};
|
||||
}
|
||||
case 'gateway': {
|
||||
const [wan, lan] = interfacesOf(doc, id, node);
|
||||
return {
|
||||
kind,
|
||||
name,
|
||||
gateway: text(setting(node, 'device'), 'defaultGateway'),
|
||||
ipForwarding: (settingsOf(node).get('ipForwarding') as boolean | undefined) ?? forwardsIPv4ByDefault(kind),
|
||||
dhcpClient: setting(node, 'dhcpClient')?.get('isEnabled') === true,
|
||||
wan: wan!,
|
||||
lan: lan!,
|
||||
};
|
||||
}
|
||||
case 'unsupported':
|
||||
return { kind, name };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user