A project's own applications (classes under projekt/anwendungen, installed on a host) are no longer left out. The decoder now keeps the Java type of every primitive — at setters, constructor and call arguments, also through shared ids like Integer0 — and which properties an object's own getter made. beanCapture.ts turns a decoded bean back into what the writer writes, with the node's system software as a mark the writer replaces by the system software it writes; what the format cannot say is refused, not guessed (an unresolved value, a Field, a factory-made object, an object a getter reaches elsewhere in the file). The reader keeps own applications as captured beans; the corpus no longer warns. The capture first took a setter with another object's getter result for an own getter; the round-trip test found it. The Java oracle did not show whether an application runs on its node's system software, so a mutation writing the mark instead survived; it now reports onItsSystem (true for all 192 applications of the corpus). Checked by Java: from the files written again, FILIUS loads Accumulator and Broadcast installed, switched on and on their node's system software, as in the original. The round-trip test covers every primitive, null, a class, an array, shared objects, getter chains, constructed elements, map reads and static constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
522 lines
22 KiB
TypeScript
522 lines
22 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 type { FlsApplication, FlsFileTree, FlsFirewall, 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 };
|
||
|
||
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];
|
||
const statements: BeanStatement[] = [{ 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 });
|
||
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);
|
||
}
|
||
|