feat: F4.6g2 the DNS server window, its records being /dns/hosts

Oracle DnsWindowRun uses Java's DNS server window as a person does and
asks a computer's resolver after each step. The core's DNS server is a
program its window changes: on and off (its socket on port 53),
recursive resolution, and records that are /dns/hosts, read on every
query as Java's server reads them (the reader moves from fls to the
core). The snapshot carries every installed DNS server with whether it
runs. The room takes the window's actions, sends its view and writes
the server back after the run; the editor shows Java's window with its
three tabs. Not taken from Java: a cell edit spilling into records of
another type, an add losing what another program wrote into the file,
an empty mail domain, a removal hitting the first record of the name.
A table cell no longer takes the room's value over what is being typed
(the web server's too).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 20:36:17 +00:00
co-authored by Claude Opus 5.5
parent e31da62ae0
commit 065b42430d
27 changed files with 2850 additions and 158 deletions
+48 -2
View File
@@ -71,6 +71,7 @@ import {
type Topic,
type EmailClientView,
type EmailServerView,
type DnsServerView,
type EchoServerView,
type SimpleClientView,
type TraceFrame,
@@ -244,6 +245,12 @@ export class SimulationRoom {
active.echoServer = echo.isActive;
settings.echoServer = { port: echo.port };
}
const dns = this.engine.dnsServer(id);
const dnsSettings = setting('dnsServer');
if (dns !== undefined && dnsSettings !== undefined) {
active.dnsServer = dns.isActive;
settings.dnsServer = { ...(dnsSettings as object), recursiveResolutionEnabled: dns.recursiveResolutionEnabled, records: dns.answering };
}
const client = this.engine.simpleClient(id);
if (client !== undefined) settings.simpleClient = { targetAddress: client.targetAddress, targetPort: client.targetPort };
settings.emailClient = snapshot.emailClientsByNodeId.get(id);
@@ -454,6 +461,38 @@ export class SimulationRoom {
return this.actInEchoServer(input);
case 'simpleClient':
return this.actInSimpleClient(input);
case 'dnsServer':
return this.actInDnsServer(input);
default:
return 'unknownAction';
}
}
/** The start button, the box for recursive resolution, a table's "Hinzufügen", "Auswahl entfernen" and a cell written. */
private actInDnsServer(input: Extract<ClientMessage, { kind: 'input' }>): ErrorCode | undefined {
const server = this.engine.dnsServer(input.node);
if (server === undefined) return 'unknownApp';
const { args } = input;
const type = args.type === 'A' || args.type === 'MX' || args.type === 'NS' ? args.type : undefined;
const row = Number.isInteger(args.row) ? (args.row as number) : undefined;
switch (input.action) {
case 'setActive':
if (typeof args.active !== 'boolean') return 'badArgs';
server.setActive(args.active);
return undefined;
case 'setRecursive':
if (typeof args.enabled !== 'boolean') return 'badArgs';
server.setRecursiveResolutionEnabled(args.enabled);
return undefined;
case 'addRecord':
if (type === undefined || typeof args.name !== 'string' || typeof args.data !== 'string') return 'badArgs';
return server.addRecord(type, args.name, args.data) ? undefined : 'badArgs';
case 'removeRecord':
if (type === undefined || row === undefined) return 'badArgs';
return server.removeRecord(type, row) ? undefined : 'badArgs';
case 'changeRecord':
if (type === undefined || row === undefined || (args.column !== 0 && args.column !== 1) || typeof args.value !== 'string') return 'badArgs';
return server.changeRecord(type, row, args.column, args.value) ? undefined : 'badArgs';
default:
return 'unknownAction';
}
@@ -634,6 +673,13 @@ export class SimulationRoom {
const view: EmailClientView = { account: client.account, inbox: client.inbox.map((entry) => entry.mail), sent: client.sent.map((entry) => entry.mail) };
return view;
}
case 'dnsServer': {
const server = this.engine.dnsServer(node);
if (server === undefined) return null;
const rows = (type: 'A' | 'MX' | 'NS') => server.rows(type).map(({ record }) => [record.domainName, record.rdata] as const);
const view: DnsServerView = { active: server.isActive, recursive: server.recursiveResolutionEnabled, rows: { A: rows('A'), MX: rows('MX'), NS: rows('NS') } };
return view;
}
case 'echoServer': {
const server = this.engine.echoServer(node);
if (server === undefined) return null;
@@ -725,8 +771,8 @@ export class SimulationRoom {
client.viewSent.set(topic, key);
client.send(message({ kind: 'view', node: node!, app: app as AppKind, view }));
}
// The browser's lines are its view.
if (app === 'webBrowser') continue;
// The browser's lines are its view; the DNS server's window has none.
if (app === 'webBrowser' || app === 'dnsServer') continue;
}
const sent = client.appSent.get(topic);
if (app === 'terminal') {