feat(core): programs' threads, and FILIUS' echo server and generic client after Java, measured against Java

Programs run as generators that yield what they wait for (threads.ts); the
engine resumes them after every event. TCP connect, send, receive, accept
and name resolution exist as such steps; the blocking calls wrap them.
EchoRun records eight stories in Java FILIUS, frames, tables and each
program's window lines; echoJava.test.ts plays them card by card. Not
taken from Java: a connection without a route hangs for ever; a server
switched off leaves its connections' last FIN unanswered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 16:27:44 +00:00
co-authored by Claude Opus 5.5
parent 0abce60aef
commit de3a1d4dfe
24 changed files with 13454 additions and 28 deletions
+23
View File
@@ -726,6 +726,29 @@ describe('importProject rules', () => {
expect([...projectSnapshot(project).dnsServerConfigurationsByNodeId.keys()]).toEqual([on]);
});
it('runs every echo server, switched on or off, and every generic client (projectSnapshot)', () => {
const source = flsNode('Rechner').source;
const echoServer = (isActive: boolean, port: number): FlsApplication => ({ key: 'echo', javaClass: 'filius.software.clientserver.ServerBaustein', source, isActive, port });
const client: FlsApplication = { key: 'client', javaClass: 'filius.software.clientserver.ClientBaustein', source, targetAddress: '10.0.0.1', targetPort: 7 };
const project = importProject(
topology({
nodes: [
flsNode('Rechner', { interfaces: [nic('10.0.0.1')], system: { applications: [echoServer(true, 55555)] } }),
flsNode('Rechner', { interfaces: [nic('10.0.0.2')], system: { applications: [echoServer(false, 7), client] } }),
],
}),
counter(),
);
const [on, off] = project.graph.nodes.map((node) => node.id);
const snapshot = projectSnapshot(project);
expect([...snapshot.echoServersByNodeId]).toEqual([
[on, { port: 55555, isActive: true }],
[off, { port: 7, isActive: false }],
]);
expect([...snapshot.simpleClientsByNodeId]).toEqual([[off, { targetAddress: '10.0.0.1', targetPort: 7 }]]);
});
it("keeps a node's IP forwarding where it differs from its kind's: a host that forwards, a router that does not", () => {
const system = (ipForwardingEnabled: boolean) => ({ manualRoutes: [], ipForwardingEnabled });
const project = importProject(