feat(fls): export the editor model's programs
exportProject.ts, step X4a: each installed program of a PC or notebook as the FILIUS application of its class, keyed by that class name as Java keys them, with its settings: servers switched on as the model has them, a web server's port and virtual hosts, the DNS server's recursion on port 53, the echo server's port, the generic client's target (none as null, as its constructor leaves it), the peer count, the personal firewall. E-mail contents are the next step. The model lost a web server's virtual hosts switch (useVHost, on for 3 web servers in the corpus); Swift sets it off on import. The core now has WebServerConfiguration.virtualHosts (Swift's name), the import carries Java's value, and the Swift comparison names Swift's error. Checked by Java: every corpus file, imported, exported and written, loads with the programs of the original, with no new departure. In the synthetic model the PC has every program with settings away from the defaults, the notebook programs without settings (Java's defaults, 3 peers), where Java makes /peer2peer itself. 12 mutation probes, each loaded by Java, were all caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,17 @@
|
||||
// Java's root, each file a Datei of the type Java's importer reads it by —
|
||||
// text by its extension (else "text"), an image or binary data by its media
|
||||
// type, in Base64 as FILIUS's Base64.encodeBytes writes it (javaBase64). A router or home
|
||||
// router keeps the files its constructor makes; the model holds none for it. System software, files and programs
|
||||
// router keeps the files its constructor makes; the model holds none for it.
|
||||
//
|
||||
// The programs of a PC or notebook: each installed program as the FILIUS
|
||||
// application of its class, under that class name as Java keys them, with
|
||||
// its settings — a server switched on as the model has it, a web server's
|
||||
// port and virtual hosts, the DNS server's recursion (on port 53, where the
|
||||
// model keeps it), the echo server's port, the generic client's target, the
|
||||
// peer count, the personal firewall. A DNS server's records are in
|
||||
// /dns/hosts, one of the files, and it forwards to the host's DNS server as
|
||||
// Java's does. E-mail accounts, messages and address books are a later
|
||||
// step. System software, files and programs
|
||||
// follow in later steps.
|
||||
//
|
||||
// What the model keeps is written as it keeps it, and so differs from the
|
||||
@@ -40,7 +50,9 @@
|
||||
// derives from the node's id;
|
||||
// - files in the model's order (directories first, then by name) and of the
|
||||
// type their kind says, not the one the file named; a router's own files
|
||||
// (a web server's www.conf) are not in the model.
|
||||
// (a web server's www.conf) are not in the model;
|
||||
// - a peer-to-peer application's peer count the file lacked (Java rolls
|
||||
// 3, 4 or 5) is the model's 3.
|
||||
//
|
||||
// Checked by Java: every corpus file, imported, exported and written, loads in
|
||||
// Java FILIUS to the topology of the original up to those departures.
|
||||
@@ -52,10 +64,17 @@ import {
|
||||
effectiveMacAddress,
|
||||
firewallConfiguration,
|
||||
FIREWALL_PROTOCOL,
|
||||
JAVA_PERSONAL_FIREWALL_DEFAULTS,
|
||||
interfaceKey,
|
||||
type DeviceConfiguration,
|
||||
type DhcpClientConfiguration,
|
||||
type DhcpServerConfiguration,
|
||||
type DnsServerConfiguration,
|
||||
type EchoServerConfiguration,
|
||||
type GnutellaConfiguration,
|
||||
type InstallableProgram,
|
||||
type SimpleClientConfiguration,
|
||||
type WebServerConfiguration,
|
||||
type FirewallConfiguration,
|
||||
type GatewayPortForwardingRow,
|
||||
type ManualRoute,
|
||||
@@ -72,9 +91,10 @@ import {
|
||||
type TopologyNode,
|
||||
type VirtualFileSystem,
|
||||
} from '@mdg-filius/core';
|
||||
import type { FlsDhcpServer, FlsFileTree, FlsFirewall } from './systemSoftware.js';
|
||||
import { PROGRAM_OF_CLASS } from './importProject.js';
|
||||
import type { FlsApplicationClass, FlsDhcpServer, FlsFileTree, FlsFirewall } from './systemSoftware.js';
|
||||
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNodeClass } from './topology.js';
|
||||
import type { NodeToWrite, SystemToWrite, TopologyToWrite } from './topologyWriter.js';
|
||||
import type { ApplicationToWrite, NodeToWrite, SystemToWrite, TopologyToWrite } from './topologyWriter.js';
|
||||
|
||||
/** The parts of the editor model the topology is made of. */
|
||||
export interface ProjectToExport {
|
||||
@@ -91,6 +111,13 @@ export interface ProjectToExport {
|
||||
readonly portForwardingRowsByNodeId: ReadonlyMap<Id, readonly GatewayPortForwardingRow[]>;
|
||||
readonly remoteLinkConfigurations: ReadonlyMap<Id, RemoteLinkConfiguration>;
|
||||
readonly virtualFileSystems: ReadonlyMap<Id, VirtualFileSystem>;
|
||||
readonly installedPrograms: ReadonlyMap<Id, ReadonlySet<InstallableProgram>>;
|
||||
readonly activePrograms: ReadonlyMap<Id, ReadonlySet<InstallableProgram>>;
|
||||
readonly webServerConfigurations: ReadonlyMap<Id, WebServerConfiguration>;
|
||||
readonly gnutellaConfigurations: ReadonlyMap<Id, GnutellaConfiguration>;
|
||||
readonly dnsServerConfigurations: ReadonlyMap<Id, DnsServerConfiguration>;
|
||||
readonly echoServerConfigurations: ReadonlyMap<Id, EchoServerConfiguration>;
|
||||
readonly simpleClientConfigurations: ReadonlyMap<Id, SimpleClientConfiguration>;
|
||||
readonly documentationItems: readonly DocumentationItem[];
|
||||
}
|
||||
|
||||
@@ -223,6 +250,7 @@ function exportSystem(node: TopologyNode, project: ProjectToExport, servingModem
|
||||
...system,
|
||||
ssid: ssid === '' ? null : ssid,
|
||||
fileSystem: { kind: 'directory', name: 'root', children: files === undefined ? [] : fileTrees(files, '/') },
|
||||
applications: exportPrograms(id, project),
|
||||
};
|
||||
}
|
||||
case 'router':
|
||||
@@ -245,6 +273,51 @@ function exportSystem(node: TopologyNode, project: ProjectToExport, servingModem
|
||||
}
|
||||
}
|
||||
|
||||
const CLASS_OF_PROGRAM = Object.fromEntries(
|
||||
Object.entries(PROGRAM_OF_CLASS).map(([javaClass, program]) => [program, javaClass]),
|
||||
) as Readonly<Record<InstallableProgram, FlsApplicationClass>>;
|
||||
|
||||
const DNS_PORT = 53;
|
||||
const ECHO_PORT = 55_555;
|
||||
|
||||
function exportPrograms(id: Id, project: ProjectToExport): ApplicationToWrite[] {
|
||||
const active = project.activePrograms.get(id);
|
||||
return [...(project.installedPrograms.get(id) ?? [])].map((program): ApplicationToWrite => {
|
||||
const javaClass = CLASS_OF_PROGRAM[program];
|
||||
const application = { key: javaClass, javaClass };
|
||||
const isActive = active?.has(program) === true;
|
||||
switch (program) {
|
||||
case 'webServer': {
|
||||
const web = project.webServerConfigurations.get(id);
|
||||
return { ...application, isActive, port: web?.port ?? 80, useVirtualHosts: web?.virtualHosts === true };
|
||||
}
|
||||
case 'dnsServer':
|
||||
return {
|
||||
...application,
|
||||
isActive,
|
||||
port: DNS_PORT,
|
||||
recursiveResolutionEnabled: project.dnsServerConfigurations.get(id)?.recursiveResolutionEnabled === true,
|
||||
};
|
||||
case 'echoServer':
|
||||
return { ...application, isActive, port: project.echoServerConfigurations.get(id)?.port ?? ECHO_PORT };
|
||||
case 'simpleClient': {
|
||||
const client = project.simpleClientConfigurations.get(id);
|
||||
// No target is null, as ClientBaustein's constructor leaves it.
|
||||
const target = client?.targetAddress ?? '';
|
||||
return { ...application, targetAddress: target === '' ? null : target, targetPort: client?.targetPort ?? ECHO_PORT };
|
||||
}
|
||||
case 'gnutella':
|
||||
return { ...application, maxPeers: project.gnutellaConfigurations.get(id)?.maximumKnownPeers ?? 3 };
|
||||
case 'firewall':
|
||||
return { ...application, firewall: exportFirewall(project.firewallConfigurationsByNodeId.get(id) ?? JAVA_PERSONAL_FIREWALL_DEFAULTS) };
|
||||
case 'emailServer':
|
||||
return { ...application, isActive };
|
||||
default:
|
||||
return application;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** The text types Java's importer reads as text, named by a file's extension. */
|
||||
const TEXT_EXTENSIONS = new Set(['txt', 'html', 'htm', 'css', 'xml', 'csv', 'conf', 'log']);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user