feat(core): FILIUS' web server and web browser after Java, measured against Java
The servers share ServerAnwendung's frame (server.ts); the web server serves /webserver with virtual hosts, the browser loads a page and its images over one connection to port 80 (web.ts); HTTP in Java's text form (http.ts). WebRun records eleven stories on the new web-lan network, with the server's files; webJava.test.ts plays them card by card. A program's close is a request, as Java's schliessen. Not taken from Java: /../ serving any file of the host; an unreadable request closing the connection without a word. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,7 @@ import { EMPTY_TOPOLOGY_SNAPSHOT, withSnapshot, type NodeSnapshot, type Topology
|
||||
import { RuntimeSpeed } from './speed.js';
|
||||
import { ApplicationThreads, waitUntil, type Steps, type Wait } from './threads.js';
|
||||
import { EchoServer, SimpleClient } from './apps/echo.js';
|
||||
import { WebBrowser, WebServer } from './apps/web.js';
|
||||
import {
|
||||
PRODUCTION_TRACE_RETENTION,
|
||||
type HeaderField,
|
||||
@@ -154,6 +155,8 @@ export type ScheduledEventKind =
|
||||
/** The lookups waiting for an address wake up, after what else happens at that time. */
|
||||
| { readonly kind: 'arpAnswered'; readonly nodeId: Id; readonly ipAddress: string; readonly macAddress: string }
|
||||
| { readonly kind: 'tcpTimeout'; readonly sessionId: Id }
|
||||
/** A program asked its socket to close (requestTcpClose): the socket's thread does it. */
|
||||
| { readonly kind: 'tcpClose'; readonly socketId: Id }
|
||||
/** A program's thread waited until this time (threads.ts). */
|
||||
| { readonly kind: 'applicationWake'; readonly wakeId: number }
|
||||
/** A DNS query waited five round trips for its answer (DNSQueryAgent). */
|
||||
@@ -883,6 +886,8 @@ export class NetworkRuntimeEngine {
|
||||
/** The programs, by node (initializePrograms). */
|
||||
private readonly echoServersByNodeId = new Map<Id, EchoServer>();
|
||||
private readonly simpleClientsByNodeId = new Map<Id, SimpleClient>();
|
||||
private readonly webServersByNodeId = new Map<Id, WebServer>();
|
||||
private readonly webBrowsersByNodeId = new Map<Id, WebBrowser>();
|
||||
/** Accepted connections a program has taken (acceptTcpSteps). */
|
||||
private readonly handedOutTcpSocketIds = new Set<Id>();
|
||||
private nextApplicationWakeId = 1;
|
||||
@@ -997,6 +1002,8 @@ export class NetworkRuntimeEngine {
|
||||
this.handedOutTcpSocketIds.clear();
|
||||
this.echoServersByNodeId.clear();
|
||||
this.simpleClientsByNodeId.clear();
|
||||
this.webServersByNodeId.clear();
|
||||
this.webBrowsersByNodeId.clear();
|
||||
this.arpLookups = [];
|
||||
this.protocolThreads.clear();
|
||||
this.dnsQueriesBySocketId.clear();
|
||||
@@ -1051,6 +1058,16 @@ export class NetworkRuntimeEngine {
|
||||
return this.simpleClientsByNodeId.get(nodeId);
|
||||
}
|
||||
|
||||
/** The node's web server while the simulation runs, if it has one installed. */
|
||||
webServer(nodeId: Id): WebServer | undefined {
|
||||
return this.webServersByNodeId.get(nodeId);
|
||||
}
|
||||
|
||||
/** The node's web browser while the simulation runs, if it has one installed. */
|
||||
webBrowser(nodeId: Id): WebBrowser | undefined {
|
||||
return this.webBrowsersByNodeId.get(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each node's programs start with the simulation (Betriebssystem.starten),
|
||||
* from the snapshot; what they show starts empty.
|
||||
@@ -1059,11 +1076,18 @@ export class NetworkRuntimeEngine {
|
||||
const snapshot = this.stateValue.topologySnapshot;
|
||||
this.echoServersByNodeId.clear();
|
||||
this.simpleClientsByNodeId.clear();
|
||||
this.webServersByNodeId.clear();
|
||||
this.webBrowsersByNodeId.clear();
|
||||
for (const node of snapshot.nodes) {
|
||||
const echoServer = snapshot.echoServersByNodeId.get(node.id);
|
||||
if (echoServer !== undefined) this.echoServersByNodeId.set(node.id, new EchoServer(this, node.id, echoServer));
|
||||
const simpleClient = snapshot.simpleClientsByNodeId.get(node.id);
|
||||
if (simpleClient !== undefined) this.simpleClientsByNodeId.set(node.id, new SimpleClient(this, node.id, simpleClient));
|
||||
const webServer = snapshot.webServersByNodeId.get(node.id);
|
||||
if (webServer !== undefined) {
|
||||
this.webServersByNodeId.set(node.id, new WebServer(this, node.id, webServer, snapshot.fileSystemsByNodeId.get(node.id)));
|
||||
}
|
||||
if (snapshot.webBrowserNodeIds.has(node.id)) this.webBrowsersByNodeId.set(node.id, new WebBrowser(this, node.id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1261,6 +1285,9 @@ export class NetworkRuntimeEngine {
|
||||
case 'tcpTimeout':
|
||||
this.handleTcpTimeout(kind.sessionId);
|
||||
return;
|
||||
case 'tcpClose':
|
||||
this.closeTcpSocket(kind.socketId);
|
||||
return;
|
||||
case 'applicationWake': {
|
||||
const wake = this.applicationWakes.get(kind.wakeId);
|
||||
this.applicationWakes.delete(kind.wakeId);
|
||||
@@ -2089,6 +2116,16 @@ export class NetworkRuntimeEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TCPSocket.schliessen from a program: it only asks; the socket's own
|
||||
* thread leaves its loop and closes (sends the FIN) after what the
|
||||
* program does next at that time.
|
||||
*/
|
||||
requestTcpClose(socketId: Id): void {
|
||||
if (this.stateValue.phase !== 'running') return;
|
||||
this.schedule(this.stateValue.currentTimeMilliseconds, { kind: 'tcpClose', socketId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Java's close: the FIN goes once, never again; the first wait counts from
|
||||
* handing it down (the timeout transmitTcpSegment schedules).
|
||||
|
||||
Reference in New Issue
Block a user