packages/editor (React 18, Vite) draws a document as Java FILIUS does: Java's default hardware icons, the device button of JSidebarButton, cables as JCablePanel's quadratic curve between the buttons' middles, wireless cables dashed, documentation items below. The surface moves with mouse and finger (the pointer captured only once it moved) and zooms with Ctrl and the wheel, a trackpad pinch, two fingers and the zoom bar; the first view shows all. German and English catalogs with Java's device names, the dashboard's colour tokens, the bridge with its origin check. packages/doc gets the drawing's light view of a document. Java's Switch.cloud (the Internet in the examples) was lost on reading; it is now read, kept in the model and written, with FlsOracle and the corpus, written and exported checks renewed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
527 lines
23 KiB
TypeScript
527 lines
23 KiB
TypeScript
// Writes `projekt/konfiguration.xml` from Java's view of a project — the
|
||
// counterpart of topology.ts and, for the system software, of
|
||
// systemSoftware.ts. The four values Java's netzwerkLaden reads: the
|
||
// version line, the list of GUIKnotenItem, of GUIKabelItem and of
|
||
// GUIDocuItem. What a node's constructor makes (its interfaces, a switch's
|
||
// ports) is reached through getters and changed there, as XMLEncoder does;
|
||
// what the constructor does not make is added. Cable ends name the port
|
||
// objects of the nodes, so the same cable joins the same ports when Java
|
||
// loads the file.
|
||
//
|
||
// The system software is the one the node's constructor makes; its settings
|
||
// are set through getters. A router's or home router's firewall is reached
|
||
// the way XMLEncoder reaches it: through the web server's `konfig` plug-in,
|
||
// which holds the same object (its key among the installed applications
|
||
// differs: Firewall on a router, NatGateway on a home router). Files are
|
||
// added to the constructor's root, as XMLEncoder adds them — on a router
|
||
// after the files its constructor makes. The installed applications of a PC
|
||
// or notebook follow the files, as in Java's own files: the constructors of
|
||
// the web server, the peer-to-peer application and the e-mail server make
|
||
// their directories only where the files lack them, and the DNS server reads
|
||
// /dns/hosts when it is installed. Each is put under its key and given the
|
||
// system software, as installApp does. A project's own application is
|
||
// written as the file had it (beanCapture.ts).
|
||
//
|
||
// E-mail: the server's domain and bean accounts with their mailboxes, the
|
||
// client's three folders and address book. The client's account is no bean
|
||
// (FILIUS 2.14 has no kontoListe property): it lives in /konten.txt, a file.
|
||
// Java's errors are not copied: a recipient an older file keeps as a string
|
||
// is written as the AddressEntry Java's own AddressEntry(String) makes of it
|
||
// — Java puts the string into the typed list unchecked, and its e-mail
|
||
// window fails on it; a null recipient is left out.
|
||
//
|
||
// Checked by Java: every corpus file, read and written again, loads in Java
|
||
// FILIUS to the same topology and system software (topologyWriter.test.ts,
|
||
// tools/java-oracle).
|
||
|
||
import { withSystemSoftware } from './beanCapture.js';
|
||
import {
|
||
encodeJavaBeans,
|
||
int,
|
||
long,
|
||
object,
|
||
reference,
|
||
type BeanObject,
|
||
type BeanReference,
|
||
type BeanStatement,
|
||
type BeanValue,
|
||
short,
|
||
} from './javaBeansWriter.js';
|
||
import { addressEntry, type JavaAddressEntry, type JavaContact, type JavaEmail, type JavaEmailAccount, type JavaRecipient } from './javaEmail.js';
|
||
import { forwardsByDefault, type FlsApplication, type FlsFileTree, type FlsFirewall, type FlsSystemSoftware } from './systemSoftware.js';
|
||
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNode, FlsNodeClass } from './topology.js';
|
||
|
||
/** The version line of the files this writer makes: the format of FILIUS 2.14. */
|
||
export const WRITTEN_VERSION_LINE = 'Filius version: 2.14.0 (mdg-filius)';
|
||
|
||
/**
|
||
* An installed application with its settings. The e-mail accounts Java reads
|
||
* from files (/mailserver/konten.txt, /konten.txt) are written with the
|
||
* files; an older file's kontoListe, which FILIUS 2.14 does not read, is not
|
||
* written.
|
||
*/
|
||
export type ApplicationToWrite = Omit<FlsApplication, 'source' | 'fileAccounts' | 'fileAccount' | 'legacyAccounts'>;
|
||
|
||
/** The system software's settings, files and applications. */
|
||
export type SystemToWrite = Omit<FlsSystemSoftware, 'applications'> & {
|
||
readonly applications?: readonly ApplicationToWrite[];
|
||
};
|
||
|
||
export type NodeToWrite = Pick<
|
||
FlsNode,
|
||
'javaClass' | 'name' | 'x' | 'y' | 'useIpAsName' | 'useMacAsName' | 'interfaces' | 'portCount'
|
||
> & { readonly system: SystemToWrite; readonly cloud?: boolean };
|
||
|
||
export interface TopologyToWrite {
|
||
readonly nodes: readonly NodeToWrite[];
|
||
readonly links: readonly FlsLink[];
|
||
readonly documentation: readonly FlsDocumentationItem[];
|
||
}
|
||
|
||
/** What each device class's constructor makes, and whether it is a host. */
|
||
const CONSTRUCTED: Record<FlsNodeClass, { count: number; local: boolean; host: boolean }> = {
|
||
Rechner: { count: 1, local: false, host: true },
|
||
Notebook: { count: 1, local: false, host: true },
|
||
Vermittlungsrechner: { count: 1, local: false, host: false },
|
||
Gateway: { count: 2, local: false, host: false },
|
||
Switch: { count: 24, local: true, host: false },
|
||
Modem: { count: 1, local: true, host: false },
|
||
};
|
||
|
||
export function writeTopologyXml(topology: TopologyToWrite): string {
|
||
return encodeJavaBeans(topologyBeans(topology));
|
||
}
|
||
|
||
export function topologyBeans(topology: TopologyToWrite): BeanValue[] {
|
||
const ports: BeanValue[][] = [];
|
||
const items = topology.nodes.map((node, index) => {
|
||
const nodePorts: BeanValue[] = [];
|
||
ports[index] = nodePorts;
|
||
return nodeItem(node, nodePorts);
|
||
});
|
||
const cables = topology.links.map((link) => cableItem(link, items, ports));
|
||
return [
|
||
WRITTEN_VERSION_LINE,
|
||
listOf(items),
|
||
listOf(cables),
|
||
listOf(topology.documentation.map(documentationItem)),
|
||
];
|
||
}
|
||
|
||
function listOf(values: readonly BeanValue[]): BeanObject {
|
||
return object(
|
||
'java.util.LinkedList',
|
||
values.map((value) => ({ call: 'add', args: [value] })),
|
||
);
|
||
}
|
||
|
||
/**
|
||
* A GUIKnotenItem: its label (the position) and its device; `ports`
|
||
* receives the device's port objects. The label's size is Java's to work
|
||
* out when it loads the file; the written 0 × 0 does not move it (measured
|
||
* on the corpus).
|
||
*/
|
||
function nodeItem(node: NodeToWrite, ports: BeanValue[]): BeanObject {
|
||
const label = object('filius.gui.netzwerksicht.JSidebarButton', [
|
||
{ set: 'bounds', value: object('java.awt.Rectangle', [], [int(node.x), int(node.y), int(0), int(0)]) },
|
||
]);
|
||
return object('filius.gui.netzwerksicht.GUIKnotenItem', [
|
||
{ set: 'imageLabel', value: label },
|
||
{ set: 'knoten', value: device(node, ports) },
|
||
]);
|
||
}
|
||
|
||
function device(node: NodeToWrite, ports: BeanValue[]): BeanObject {
|
||
const constructed = CONSTRUCTED[node.javaClass];
|
||
// A switch drawn as a cloud: written only when true, before the name, as XMLEncoder orders Switch's properties.
|
||
const statements: BeanStatement[] = [...(node.cloud === true ? [{ set: 'cloud', value: true }] : []), { set: 'name', value: node.name }];
|
||
if (constructed.host) {
|
||
statements.push({ set: 'useIPAsName', value: node.useIpAsName }, { set: 'useMACAsName', value: node.useMacAsName });
|
||
}
|
||
if (constructed.local) {
|
||
statements.push(
|
||
constructedList('anschluesse', node.portCount, constructed.count, ports, () => ({ statements: [] }), () => {
|
||
const port = object('filius.hardware.Port');
|
||
return { value: port, port };
|
||
}),
|
||
);
|
||
} else {
|
||
statements.push(
|
||
constructedList(
|
||
'netzwerkInterfaces',
|
||
node.interfaces.length,
|
||
constructed.count,
|
||
ports,
|
||
(index) => {
|
||
const port = reference('Port');
|
||
return { statements: [...interfaceStatements(node.interfaces[index]!), { get: 'port', statements: [], as: port }], port };
|
||
},
|
||
(index) => {
|
||
const port = reference('Port');
|
||
const nic = object('filius.hardware.NetzwerkInterface', [
|
||
...interfaceStatements(node.interfaces[index]!),
|
||
{ get: 'port', statements: [], as: port },
|
||
]);
|
||
return { value: nic, port };
|
||
},
|
||
),
|
||
);
|
||
}
|
||
// Named for the applications, which are given it.
|
||
const applicationCount = (node.system.applications?.length ?? 0) + (node.system.ownApplications?.length ?? 0);
|
||
const system = applicationCount > 0 ? reference('SystemSoftware') : undefined;
|
||
const systemStatementList = systemStatements(node.system, node.javaClass, system);
|
||
statements.push(
|
||
system === undefined
|
||
? { get: 'systemSoftware', statements: systemStatementList }
|
||
: { get: 'systemSoftware', statements: systemStatementList, as: system },
|
||
);
|
||
return object(`filius.hardware.knoten.${node.javaClass}`, statements);
|
||
}
|
||
|
||
const WEB_SERVER_CLASS = 'filius.software.www.WebServer';
|
||
|
||
/**
|
||
* The settings the file has, each set on the constructor's system software.
|
||
* A switch's SSID the file lacked stays unwritten, so Java rolls one as it did.
|
||
*/
|
||
function systemStatements(system: SystemToWrite, javaClass: FlsNodeClass, self: BeanReference | undefined): BeanStatement[] {
|
||
const statements: BeanStatement[] = [];
|
||
if (system.firewall !== undefined) {
|
||
statements.push({
|
||
get: 'installierteAnwendungen',
|
||
statements: [
|
||
{
|
||
call: 'get',
|
||
args: [WEB_SERVER_CLASS],
|
||
statements: [
|
||
{ get: 'plugins', statements: [{ call: 'get', args: ['konfig'], statements: [{ get: 'firewall', statements: firewallStatements(system.firewall) }] }] },
|
||
],
|
||
},
|
||
],
|
||
});
|
||
}
|
||
if (system.fileSystem !== undefined) statements.push(fileSystemStatement(system.fileSystem, system.templateFiles !== false));
|
||
if (self !== undefined) {
|
||
statements.push({
|
||
get: 'installierteAnwendungen',
|
||
statements: [
|
||
...(system.applications ?? []).map((application): BeanStatement => ({
|
||
call: 'put',
|
||
args: [application.key, object(application.javaClass, applicationStatements(application, self))],
|
||
})),
|
||
// A project's own: its bean as the file had it, on this node's system software.
|
||
...(system.ownApplications ?? []).map((application): BeanStatement => ({
|
||
call: 'put',
|
||
args: [application.key, withSystemSoftware(application.bean, self)],
|
||
})),
|
||
],
|
||
});
|
||
}
|
||
if (system.dhcpServer !== undefined) {
|
||
const server = system.dhcpServer;
|
||
statements.push({
|
||
get: 'DHCPServer',
|
||
statements: [
|
||
{ set: 'aktiv', value: server.isActive },
|
||
{ set: 'untergrenze', value: server.lowerBound },
|
||
{ set: 'obergrenze', value: server.upperBound },
|
||
{ set: 'gatewayip', value: server.gateway },
|
||
{ set: 'dnsserverip', value: server.dnsServer },
|
||
{ set: 'ownSettings', value: server.useOwnSettings },
|
||
{
|
||
set: 'staticAssignedAddresses',
|
||
value: object(
|
||
'java.util.ArrayList',
|
||
server.staticAssignedAddresses.map(({ mac, ip }) => ({ call: 'add', args: [`${mac} ${ip}`] })),
|
||
),
|
||
},
|
||
],
|
||
});
|
||
}
|
||
if (system.dhcpClient !== undefined) statements.push({ set: 'DHCPKonfiguration', value: system.dhcpClient });
|
||
// Written only where it differs from what Java's constructor sets, as XMLEncoder does.
|
||
if (system.ipForwardingEnabled !== undefined && system.ipForwardingEnabled !== forwardsByDefault(javaClass)) {
|
||
statements.push({ set: 'ipForwardingEnabled', value: system.ipForwardingEnabled });
|
||
}
|
||
if (system.manualRoutes !== undefined) {
|
||
statements.push({ get: 'weiterleitungstabelle', statements: [{ set: 'manuelleTabelle', value: rows(system.manualRoutes) }] });
|
||
}
|
||
if (system.ripEnabled !== undefined) statements.push({ set: 'ripEnabled', value: system.ripEnabled });
|
||
if (system.retentionTime !== undefined) statements.push({ set: 'retentionTime', value: long(system.retentionTime) });
|
||
if (system.staticNAT !== undefined) statements.push({ set: 'staticNAT', value: rows(system.staticNAT) });
|
||
if (system.modem !== undefined) {
|
||
statements.push(
|
||
{ set: 'mode', value: int(system.modem.mode) },
|
||
{ set: 'port', value: int(system.modem.port) },
|
||
{ set: 'ipAdresse', value: system.modem.ipAddress },
|
||
);
|
||
}
|
||
// SwitchFirmware.setSSID, Betriebssystem.setSsid.
|
||
if (system.ssid !== undefined) statements.push({ set: javaClass === 'Switch' ? 'SSID' : 'ssid', value: system.ssid });
|
||
return statements;
|
||
}
|
||
|
||
/**
|
||
* The file system: the root's children added to the constructor's root
|
||
* (named "root", empty on a PC or notebook), or a root of its own that
|
||
* replaces it with the files a router's constructor makes. `arbeitsVerzeichnis`
|
||
* is the property Java writes; `root` names the same field.
|
||
*/
|
||
function fileSystemStatement(root: FlsFileTree, constructedRoot: boolean): BeanStatement {
|
||
if (!constructedRoot) return { get: 'dateisystem', statements: [{ set: 'arbeitsVerzeichnis', value: treeNode(root) }] };
|
||
const statements: BeanStatement[] = [];
|
||
if (!(root.kind === 'directory' && root.name === 'root')) statements.push({ set: 'userObject', value: userObject(root) });
|
||
statements.push(...childStatements(root));
|
||
return { get: 'dateisystem', statements: [{ get: 'arbeitsVerzeichnis', statements }] };
|
||
}
|
||
|
||
function childStatements(tree: FlsFileTree): BeanStatement[] {
|
||
return tree.children.map((child) => ({ call: 'add', args: [treeNode(child)] }));
|
||
}
|
||
|
||
/** A DefaultMutableTreeNode; one of another kind than directory or file is written without a user object. */
|
||
function treeNode(tree: FlsFileTree): BeanObject {
|
||
return object('javax.swing.tree.DefaultMutableTreeNode', childStatements(tree), tree.kind === 'other' ? [] : [userObject(tree)]);
|
||
}
|
||
|
||
/** A directory's name, or a file as `new Datei(name, typ, inhalt)`. */
|
||
function userObject(tree: FlsFileTree): BeanValue {
|
||
if (tree.kind === 'file') return object('filius.software.system.Datei', [], [tree.name, tree.type, tree.content]);
|
||
return tree.kind === 'directory' ? tree.name : null;
|
||
}
|
||
|
||
/**
|
||
* An application's settings, after the system software it runs on. A
|
||
* peer-to-peer application's peer count the file lacked stays unwritten, so
|
||
* Java rolls one as it did.
|
||
*/
|
||
function applicationStatements(application: ApplicationToWrite, system: BeanReference): BeanStatement[] {
|
||
const statements: BeanStatement[] = [{ set: 'systemSoftware', value: system }];
|
||
if (application.isActive !== undefined) statements.push({ set: 'aktiv', value: application.isActive });
|
||
if (application.port !== undefined) statements.push({ set: 'port', value: int(application.port) });
|
||
if (application.targetAddress !== undefined) statements.push({ set: 'zielIPAdresse', value: application.targetAddress });
|
||
if (application.targetPort !== undefined) statements.push({ set: 'zielPort', value: int(application.targetPort) });
|
||
if (application.recursiveResolutionEnabled !== undefined) {
|
||
statements.push({ set: 'recursiveResolutionEnabled', value: application.recursiveResolutionEnabled });
|
||
}
|
||
if (application.useVirtualHosts !== undefined) statements.push({ set: 'useVHost', value: application.useVirtualHosts });
|
||
if (application.maxPeers !== undefined && application.maxPeers !== null) {
|
||
statements.push({ set: 'maxTeilnehmerZahl', value: int(application.maxPeers) });
|
||
}
|
||
if (application.firewall !== undefined) statements.push(...firewallStatements(application.firewall));
|
||
if (application.mailDomain !== undefined) statements.push({ set: 'mailDomain', value: application.mailDomain });
|
||
if (application.beanAccounts !== undefined) {
|
||
statements.push({ set: 'listeBenutzerkonten', value: listOf(application.beanAccounts.map(emailAccount)) });
|
||
}
|
||
if (application.received !== undefined) statements.push({ set: 'empfangeneNachrichten', value: emails(application.received) });
|
||
if (application.sent !== undefined) statements.push({ set: 'gesendeteNachrichten', value: emails(application.sent) });
|
||
if (application.drafts !== undefined) statements.push({ set: 'erstellteNachrichten', value: emails(application.drafts) });
|
||
if (application.addressBook !== undefined) {
|
||
statements.push({
|
||
set: 'adressbuch',
|
||
value: object(
|
||
'java.util.Vector',
|
||
application.addressBook.map((entry) => ({ call: 'add', args: [contact(entry)] })),
|
||
),
|
||
});
|
||
}
|
||
return statements;
|
||
}
|
||
|
||
const EMAIL_PACKAGE = 'filius.software.email';
|
||
|
||
function emailAccount(account: JavaEmailAccount): BeanObject {
|
||
return object(`${EMAIL_PACKAGE}.EmailKonto`, [
|
||
{ set: 'benutzername', value: account.username },
|
||
{ set: 'passwort', value: account.password },
|
||
{ set: 'nachname', value: account.lastName },
|
||
{ set: 'vorname', value: account.firstName },
|
||
{ set: 'emailAdresse', value: account.emailAddress },
|
||
{ set: 'pop3server', value: account.pop3Server },
|
||
{ set: 'pop3port', value: account.pop3Port },
|
||
{ set: 'smtpserver', value: account.smtpServer },
|
||
{ set: 'smtpport', value: account.smtpPort },
|
||
{ set: 'nachrichten', value: emails(account.messages) },
|
||
]);
|
||
}
|
||
|
||
function emails(messages: readonly JavaEmail[]): BeanObject {
|
||
return listOf(
|
||
messages.map((message) =>
|
||
object(`${EMAIL_PACKAGE}.Email`, [
|
||
{ set: 'absender', value: address(message.sender) },
|
||
{ set: 'empfaenger', value: recipients(message.to) },
|
||
{ set: 'cc', value: recipients(message.cc) },
|
||
{ set: 'bcc', value: recipients(message.bcc) },
|
||
{ set: 'betreff', value: message.subject },
|
||
{ set: 'text', value: message.text },
|
||
{ set: 'dateReceived', value: message.dateReceived },
|
||
{ set: 'neu', value: message.isNew },
|
||
{ set: 'delete', value: message.isDeleted },
|
||
{ set: 'versendet', value: message.isSent },
|
||
]),
|
||
),
|
||
);
|
||
}
|
||
|
||
/** A list of AddressEntry: a string read as Java's AddressEntry(String) reads it, null left out. */
|
||
function recipients(entries: readonly JavaRecipient[]): BeanObject {
|
||
return object(
|
||
'java.util.ArrayList',
|
||
entries.flatMap((entry) =>
|
||
entry === null ? [] : [{ call: 'add', args: [address(typeof entry === 'string' ? addressEntry(entry) : entry)] }],
|
||
),
|
||
);
|
||
}
|
||
|
||
function address(entry: JavaAddressEntry): BeanObject {
|
||
const statements: BeanStatement[] = [];
|
||
if (entry.name !== null) statements.push({ set: 'name', value: entry.name });
|
||
if (entry.mailAddress !== null) statements.push({ set: 'mailAddress', value: entry.mailAddress });
|
||
return object(`${EMAIL_PACKAGE}.AddressEntry`, statements);
|
||
}
|
||
|
||
function contact(entry: JavaContact): BeanObject {
|
||
return object(`${EMAIL_PACKAGE}.Kontakt`, [
|
||
{ set: 'name', value: entry.name },
|
||
{ set: 'vorname', value: entry.firstName },
|
||
{ set: 'strasse', value: entry.street },
|
||
{ set: 'hausnr', value: int(entry.houseNumber) },
|
||
{ set: 'plz', value: int(entry.postalCode) },
|
||
{ set: 'wohnort', value: entry.city },
|
||
{ set: 'email', value: entry.email },
|
||
{ set: 'telefon', value: entry.phone },
|
||
]);
|
||
}
|
||
|
||
/** A LinkedList of String arrays: routes, static NAT. */
|
||
function rows(table: readonly (readonly (string | null)[])[]): BeanObject {
|
||
return listOf(table.map((row) => ({ kind: 'array', componentClass: 'java.lang.String', items: [...row] })));
|
||
}
|
||
|
||
function firewallStatements(firewall: FlsFirewall): BeanStatement[] {
|
||
return [
|
||
{ set: 'activated', value: firewall.activated },
|
||
{ set: 'defaultPolicy', value: short(firewall.defaultPolicy) },
|
||
{ set: 'dropICMP', value: firewall.dropICMP },
|
||
{ set: 'filterSYNSegmentsOnly', value: firewall.filterSYNSegmentsOnly },
|
||
{ set: 'filterUdp', value: firewall.filterUdp },
|
||
{
|
||
set: 'ruleset',
|
||
value: object(
|
||
'java.util.Vector',
|
||
firewall.rules.map((rule) => ({
|
||
call: 'add',
|
||
args: [
|
||
object('filius.software.firewall.FirewallRule', [], [
|
||
rule.srcIP,
|
||
rule.srcMask,
|
||
rule.destIP,
|
||
rule.destMask,
|
||
int(rule.port),
|
||
short(rule.protocol),
|
||
short(rule.action),
|
||
]),
|
||
],
|
||
})),
|
||
),
|
||
},
|
||
];
|
||
}
|
||
|
||
/**
|
||
* A list the constructor filled with `constructed` elements: those are
|
||
* changed through `get(index)`, more are added. With fewer, the list is set
|
||
* anew. `ports` receives each element's port, in order.
|
||
*/
|
||
function constructedList(
|
||
property: string,
|
||
count: number,
|
||
constructed: number,
|
||
ports: BeanValue[],
|
||
existing: (index: number) => { statements: BeanStatement[]; port?: BeanReference },
|
||
added: (index: number) => { value: BeanValue; port: BeanValue },
|
||
): BeanStatement {
|
||
if (count < constructed) {
|
||
const values = Array.from({ length: count }, (_, index) => {
|
||
const { value, port } = added(index);
|
||
ports.push(port);
|
||
return value;
|
||
});
|
||
return { set: property, value: listOf(values) };
|
||
}
|
||
const statements: BeanStatement[] = [];
|
||
for (let index = 0; index < count; index++) {
|
||
if (index < constructed) {
|
||
// The element's own port, or — a switch's — the element itself.
|
||
const { statements: inner, port } = existing(index);
|
||
if (port === undefined) {
|
||
const element = reference('Port');
|
||
ports.push(element);
|
||
statements.push({ getIndex: index, statements: inner, as: element });
|
||
} else {
|
||
ports.push(port);
|
||
statements.push({ getIndex: index, statements: inner });
|
||
}
|
||
} else {
|
||
const { value, port } = added(index);
|
||
ports.push(port);
|
||
statements.push({ call: 'add', args: [value] });
|
||
}
|
||
}
|
||
return { get: property, statements };
|
||
}
|
||
|
||
/**
|
||
* A network interface's setters. An address Java's setter rejected (null)
|
||
* is not written: setIp(null) throws, and the constructor's address stays.
|
||
* A MAC the file lacked stays unwritten, so Java rolls one as it did.
|
||
*/
|
||
function interfaceStatements(nic: FlsInterface): BeanStatement[] {
|
||
const statements: BeanStatement[] = [];
|
||
if (nic.ip !== null) statements.push({ set: 'ip', value: nic.ip });
|
||
if (nic.mask !== null) statements.push({ set: 'subnetzMaske', value: nic.mask });
|
||
if (nic.mac !== undefined) statements.push({ set: 'mac', value: nic.mac });
|
||
statements.push({ set: 'gateway', value: nic.gateway }, { set: 'dns', value: nic.dns });
|
||
if (nic.wireless) statements.push({ set: 'wireless', value: true });
|
||
return statements;
|
||
}
|
||
|
||
function cableItem(link: FlsLink, items: readonly BeanObject[], ports: readonly BeanValue[][]): BeanObject {
|
||
const [first, second] = link.ends;
|
||
const end = (reference: { node: number; port: number }) => ports[reference.node]![reference.port]!;
|
||
const cable = object('filius.hardware.Kabel', [
|
||
{ set: 'anschluesse', value: { kind: 'array', componentClass: 'filius.hardware.Port', items: [end(first), end(second)] } },
|
||
...(link.wireless ? [{ set: 'wireless', value: true }] : []),
|
||
]);
|
||
return object('filius.gui.netzwerksicht.GUIKabelItem', [
|
||
{ set: 'dasKabel', value: cable },
|
||
{
|
||
get: 'kabelpanel',
|
||
statements: [
|
||
{ set: 'ziel1', value: items[first.node]! },
|
||
{ set: 'ziel2', value: items[second.node]! },
|
||
],
|
||
},
|
||
]);
|
||
}
|
||
|
||
function documentationItem(item: FlsDocumentationItem): BeanObject {
|
||
const statements: BeanStatement[] = [];
|
||
if (item.color !== null) statements.push({ set: 'color', value: object('java.awt.Color', [], item.color.map(int)) });
|
||
if (item.font !== null) {
|
||
statements.push({ set: 'font', value: object('java.awt.Font', [], [item.font.name, int(item.font.style), int(item.font.size)]) });
|
||
}
|
||
statements.push(
|
||
{ set: 'height', value: int(item.height) },
|
||
{ set: 'text', value: item.text },
|
||
{ set: 'type', value: int(item.type) },
|
||
{ set: 'width', value: int(item.width) },
|
||
{ set: 'x', value: int(item.x) },
|
||
{ set: 'y', value: int(item.y) },
|
||
);
|
||
return object('filius.gui.netzwerksicht.GUIDocuItem', statements);
|
||
}
|
||
|