feat: F4.6g4 the Gnutella window, measured against Java's
GnutellaWindowRun uses Java's Gnutella window on terminal-net beside the line of GnutellaRun's story "search". The core cancels a search as Java does (every connection of the program's own requests closed, passed-on queries kept), lets the number of peers change and lists /peer2peer's files; the room takes the window's actions and sends its view; the editor shows Java's four tabs with Java's symbols. Not adopted from Java: a number of peers of one digit only, a results table that keeps the last search's rows, a files table that lags behind the folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -49,7 +49,10 @@ import {
|
||||
NetworkRuntimeEngine,
|
||||
captureRows,
|
||||
firewallRuleText,
|
||||
gnutellaPeerCountOfText,
|
||||
gnutellaResultRow,
|
||||
interfaceKey,
|
||||
IP_ADDRESS_PATTERN,
|
||||
portRuleSender,
|
||||
stableGeneratedMacAddress,
|
||||
type CapturedFrame,
|
||||
@@ -76,6 +79,7 @@ import {
|
||||
type DnsServerView,
|
||||
type EchoServerView,
|
||||
type FirewallView,
|
||||
type GnutellaView,
|
||||
type SimpleClientView,
|
||||
type TraceFrame,
|
||||
type WebServerView,
|
||||
@@ -218,7 +222,8 @@ export class SimulationRoom {
|
||||
* What the run left of each node that Java's project keeps: its files (when
|
||||
* they changed since the last write), whether its servers run, a web
|
||||
* server's virtual hosts, an e-mail server's domain and accounts, an
|
||||
* e-mail program's account and folders, a firewall, a DHCP client's address.
|
||||
* e-mail program's account and folders, a firewall, Gnutella's number of
|
||||
* peers, a DHCP client's address.
|
||||
*/
|
||||
private runState(): Map<Id, NodeRunState> {
|
||||
const snapshot = this.engine.state.topologySnapshot;
|
||||
@@ -256,6 +261,8 @@ export class SimulationRoom {
|
||||
}
|
||||
const client = this.engine.simpleClient(id);
|
||||
if (client !== undefined) settings.simpleClient = { targetAddress: client.targetAddress, targetPort: client.targetPort };
|
||||
const gnutella = this.engine.gnutella(id);
|
||||
if (gnutella !== undefined) settings.gnutella = { maximumKnownPeers: gnutella.maximumKnownPeers };
|
||||
settings.emailClient = snapshot.emailClientsByNodeId.get(id);
|
||||
settings.firewall = snapshot.firewallConfigurationsByNodeId.get(id);
|
||||
if (snapshot.dhcpClientConfigurationsByNodeId.get(id)?.isEnabled === true) settings.device = snapshot.deviceConfigurations.get(id);
|
||||
@@ -468,6 +475,8 @@ export class SimulationRoom {
|
||||
return this.actInDnsServer(input);
|
||||
case 'firewall':
|
||||
return this.actInFirewall(input);
|
||||
case 'gnutella':
|
||||
return this.actInGnutella(input);
|
||||
default:
|
||||
return 'unknownAction';
|
||||
}
|
||||
@@ -503,6 +512,44 @@ export class SimulationRoom {
|
||||
}
|
||||
}
|
||||
|
||||
/** The Gnutella window: "Netz beitreten" with the address, "Netz verlassen", "Suchen" with the words, "Stopp!", "Liste leeren", "Herunterladen" of the row chosen, the number of peers saved. */
|
||||
private actInGnutella(input: Extract<ClientMessage, { kind: 'input' }>): ErrorCode | undefined {
|
||||
const peer = this.engine.gnutella(input.node);
|
||||
if (peer === undefined) return 'unknownApp';
|
||||
const { args } = input;
|
||||
switch (input.action) {
|
||||
case 'join':
|
||||
if (typeof args.address !== 'string' || !IP_ADDRESS_PATTERN.test(args.address)) return 'badArgs';
|
||||
peer.join(args.address);
|
||||
return undefined;
|
||||
case 'leave':
|
||||
peer.reset();
|
||||
return undefined;
|
||||
case 'search':
|
||||
if (typeof args.criteria !== 'string') return 'badArgs';
|
||||
peer.search(args.criteria);
|
||||
return undefined;
|
||||
case 'cancelSearch':
|
||||
peer.cancelSearch();
|
||||
return undefined;
|
||||
case 'clearResults':
|
||||
peer.clearResults();
|
||||
return undefined;
|
||||
case 'download':
|
||||
if (!Number.isInteger(args.row) || (args.row as number) < 0 || (args.row as number) >= peer.results.length) return 'badArgs';
|
||||
peer.download(args.row as number);
|
||||
return undefined;
|
||||
case 'setMaximumPeers': {
|
||||
const count = Number.isInteger(args.count) ? gnutellaPeerCountOfText(String(args.count)) : undefined;
|
||||
if (count === undefined) return 'badArgs';
|
||||
peer.setMaximumKnownPeers(count);
|
||||
return undefined;
|
||||
}
|
||||
default:
|
||||
return 'unknownAction';
|
||||
}
|
||||
}
|
||||
|
||||
/** A computer's firewall window: its three boxes, "Hinzufügen" with the port, the protocol and the senders chosen, "Löschen" of the row chosen. */
|
||||
private actInFirewall(input: Extract<ClientMessage, { kind: 'input' }>): ErrorCode | undefined {
|
||||
const configuration = this.engine.personalFirewall(input.node);
|
||||
@@ -715,6 +762,12 @@ export class SimulationRoom {
|
||||
const view: DnsServerView = { active: server.isActive, recursive: server.recursiveResolutionEnabled, rows: { A: rows('A'), MX: rows('MX'), NS: rows('NS') } };
|
||||
return view;
|
||||
}
|
||||
case 'gnutella': {
|
||||
const peer = this.engine.gnutella(node);
|
||||
if (peer === undefined) return null;
|
||||
const view: GnutellaView = { peers: peer.peers, results: peer.results.map(gnutellaResultRow), files: peer.fileRows(), maximumKnownPeers: peer.maximumKnownPeers };
|
||||
return view;
|
||||
}
|
||||
case 'firewall': {
|
||||
const configuration = this.engine.personalFirewall(node);
|
||||
if (configuration === undefined) return null;
|
||||
@@ -817,8 +870,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; the DNS server's window has none.
|
||||
if (app === 'webBrowser' || app === 'dnsServer') continue;
|
||||
// The browser's lines are its view; the DNS server's and Gnutella's windows have none.
|
||||
if (app === 'webBrowser' || app === 'dnsServer' || app === 'gnutella') continue;
|
||||
}
|
||||
const sent = client.appSent.get(topic);
|
||||
if (app === 'terminal') {
|
||||
|
||||
Reference in New Issue
Block a user