feat(fls): a project's own applications through the editor model
The model carries the captured beans of a project's own applications (ownApplicationsByNodeId); the export writes them again on the system software of their node, and their classes go with the archive's other entries. Checked by Java: from the exported files FILIUS loads Accumulator and Broadcast as from the original; the export test no longer leaves own applications out, and a probe that drops them is caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,8 @@
|
||||
// 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.
|
||||
// Java's does. A project's own applications are written as their beans,
|
||||
// as the file had them; their classes go with the archive's other entries.
|
||||
//
|
||||
// E-mail: the server's domain and accounts with their mailboxes, the client's
|
||||
// folders and address book, as Java's beans. The account files are written
|
||||
@@ -114,7 +115,7 @@ import {
|
||||
import { writeFlsArchive } from './archive.js';
|
||||
import { EMAIL_CLIENT_FILE, EMAIL_SERVER_FILE, type JavaAddressEntry, type JavaContact, type JavaEmail } from './javaEmail.js';
|
||||
import { PROGRAM_OF_CLASS } from './importProject.js';
|
||||
import type { FlsApplicationClass, FlsDhcpServer, FlsFileTree, FlsFirewall } from './systemSoftware.js';
|
||||
import type { FlsApplicationClass, FlsDhcpServer, FlsFileTree, FlsFirewall, FlsOwnApplication } from './systemSoftware.js';
|
||||
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNodeClass } from './topology.js';
|
||||
import { writeTopologyXml, type ApplicationToWrite, type NodeToWrite, type SystemToWrite, type TopologyToWrite } from './topologyWriter.js';
|
||||
|
||||
@@ -145,6 +146,8 @@ export interface ProjectToExport {
|
||||
readonly documentationItems: readonly DocumentationItem[];
|
||||
/** The archive's other entries (the project's own applications), written unchanged. */
|
||||
readonly archiveEntries?: ReadonlyMap<string, Uint8Array>;
|
||||
/** A project's own applications on a PC or notebook, written as their beans. */
|
||||
readonly ownApplicationsByNodeId?: ReadonlyMap<Id, readonly FlsOwnApplication[]>;
|
||||
}
|
||||
|
||||
export interface ExportedTopology {
|
||||
@@ -286,7 +289,13 @@ function exportSystem(node: TopologyNode, project: ProjectToExport, servingModem
|
||||
const server = project.installedPrograms.get(id)?.has('emailServer') === true ? project.emailServerConfigurations.get(id) : undefined;
|
||||
if (client?.account != null) putFile(root, EMAIL_CLIENT_FILE, 'text/txt', clientAccountFile(client, warn));
|
||||
if (server !== undefined) putFile(root, EMAIL_SERVER_FILE, 'txt', serverAccountsFile(server, warn));
|
||||
return { ...system, ssid: ssid === '' ? null : ssid, fileSystem: root, applications: exportPrograms(id, project) };
|
||||
return {
|
||||
...system,
|
||||
ssid: ssid === '' ? null : ssid,
|
||||
fileSystem: root,
|
||||
applications: exportPrograms(id, project),
|
||||
ownApplications: [...(project.ownApplicationsByNodeId?.get(id) ?? [])],
|
||||
};
|
||||
}
|
||||
case 'router':
|
||||
return {
|
||||
|
||||
@@ -101,7 +101,7 @@ import { readFlsArchive } from './archive.js';
|
||||
import { dnsRecordsOf, javaHostsFileContent, readDnsHosts } from './dnsHosts.js';
|
||||
import { decodeJavaBeans } from './javabeans.js';
|
||||
import { emailClientConfiguration, emailServerConfiguration } from './importEmail.js';
|
||||
import type { FlsApplicationClass, FlsFileTree, FlsFirewall } from './systemSoftware.js';
|
||||
import type { FlsApplicationClass, FlsFileTree, FlsFirewall, FlsOwnApplication } from './systemSoftware.js';
|
||||
import { readTopology, type FlsDocumentationItem, type FlsInterface, type FlsNode, type FlsNodeClass, type FlsTopology } from './topology.js';
|
||||
|
||||
export interface ImportedProject {
|
||||
@@ -140,6 +140,12 @@ export interface ImportedProject {
|
||||
* they cannot run here, but must not be lost.
|
||||
*/
|
||||
archiveEntries: ReadonlyMap<string, Uint8Array>;
|
||||
/**
|
||||
* A project's own applications on a PC or notebook, as their beans
|
||||
* (beanCapture.ts): they cannot run here, but are written again as the
|
||||
* file had them. Their classes are among the archive's entries.
|
||||
*/
|
||||
ownApplicationsByNodeId: Map<Id, FlsOwnApplication[]>;
|
||||
/** The topology's warnings, then this step's. */
|
||||
warnings: string[];
|
||||
}
|
||||
@@ -188,6 +194,7 @@ export function importProject(
|
||||
echoServerConfigurations: new Map(),
|
||||
simpleClientConfigurations: new Map(),
|
||||
};
|
||||
const ownApplicationsByNodeId = new Map<Id, FlsOwnApplication[]>();
|
||||
const nodes = topology.nodes.map((source) => {
|
||||
const node = importNode(source, newId, warnings);
|
||||
registerConfigurations(source, node, deviceConfigurations, interfaceConfigurations);
|
||||
@@ -196,6 +203,8 @@ export function importProject(
|
||||
if (node.kind === 'pc' || node.kind === 'notebook') {
|
||||
system.virtualFileSystems.set(node.id, importFileSystem(source.system.fileSystem, node.displayName, warnings));
|
||||
registerPrograms(source, node, system, warnings);
|
||||
const own = source.system.ownApplications ?? [];
|
||||
if (own.length > 0) ownApplicationsByNodeId.set(node.id, own);
|
||||
}
|
||||
return node;
|
||||
});
|
||||
@@ -249,6 +258,7 @@ export function importProject(
|
||||
...system,
|
||||
documentationItems: inDeterministicRenderOrder(documentationItems),
|
||||
archiveEntries,
|
||||
ownApplicationsByNodeId,
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import {
|
||||
type ProjectToExport,
|
||||
} from '../src/index.js';
|
||||
import { writeTopologyXml } from '../src/topologyWriter.js';
|
||||
import { withoutOwnApplications } from './ownApplications.js';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const corpusRoot = join(here, '../../../corpus');
|
||||
@@ -350,8 +349,7 @@ describe('the editor model exported, as Java loads it', () => {
|
||||
return nic.mac === derived ? derived : undefined;
|
||||
}),
|
||||
);
|
||||
// The model does not install own applications yet (B2).
|
||||
const source = withoutOwnApplications(original[name]!);
|
||||
const source = original[name]!;
|
||||
const nodeIds = project.graph.nodes.map((node) => node.id);
|
||||
const pairs = nodeIds.map((id) => project.remoteLinkConfigurations.get(id)?.pairIdentifier);
|
||||
// The account files of each host the export writes anew, by path, as the file has them.
|
||||
|
||||
@@ -8100,7 +8100,15 @@
|
||||
"directory": "root",
|
||||
"children": []
|
||||
},
|
||||
"applications": [],
|
||||
"applications": [
|
||||
{
|
||||
"key": "filius.software.clientserver.Accumulator",
|
||||
"class": "filius.software.clientserver.Accumulator",
|
||||
"onItsSystem": true,
|
||||
"aktiv": true,
|
||||
"port": 55555
|
||||
}
|
||||
],
|
||||
"dhcpClient": false,
|
||||
"dhcpServer": {
|
||||
"aktiv": false,
|
||||
@@ -8309,7 +8317,7 @@
|
||||
}
|
||||
],
|
||||
"documentation": [],
|
||||
"sha256": "955edc9322d1de6bae59ce05221b94ab18983c46193db034cf37fd18f0146a48"
|
||||
"sha256": "acca8f9fe5b317e12472b5e975d0463d367b90896e14a07df46e24fc71feef38"
|
||||
},
|
||||
"java-examples/dhcp_test_scenario.fls": {
|
||||
"success": true,
|
||||
@@ -13346,6 +13354,13 @@
|
||||
"children": []
|
||||
},
|
||||
"applications": [
|
||||
{
|
||||
"key": "filius.software.clientserver.Broadcast",
|
||||
"class": "filius.software.clientserver.Broadcast",
|
||||
"onItsSystem": true,
|
||||
"aktiv": true,
|
||||
"port": 55555
|
||||
},
|
||||
{
|
||||
"key": "filius.software.clientserver.ServerBaustein",
|
||||
"class": "filius.software.clientserver.ServerBaustein",
|
||||
@@ -13585,7 +13600,7 @@
|
||||
}
|
||||
],
|
||||
"documentation": [],
|
||||
"sha256": "b860d1bdf773a92b90f63ff6c7c76e9d0ee2c9b342e6042c3e39f61acf6697e3"
|
||||
"sha256": "4f1a87256f67f1d09a25db7eb2f964663b4728b43592731952a0a30e562cf702"
|
||||
},
|
||||
"java-examples/nat.fls": {
|
||||
"success": true,
|
||||
|
||||
@@ -11,7 +11,7 @@ export const OWN_APPLICATION_FILES = ['java-examples/anwendung_komplett.fls', 'j
|
||||
type View = { nodes?: { system: Record<string, unknown> }[] };
|
||||
|
||||
/** Java's view without the applications FILIUS does not ship. */
|
||||
export function withoutOwnApplications<T>(view: T): T {
|
||||
function withoutOwnApplications<T>(view: T): T {
|
||||
const { nodes } = view as View;
|
||||
if (nodes === undefined) return view;
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user