Merge pull request 'Fix build:ts: one text-only error factory in cultnet-ts (6 TS2345 in cultmesh-ts)' (#29) from libby/cultmesh-ts-error-message-sites into main
Some checks failed
CultMesh QUIC native / Build win32-x64 (push) Has been skipped
CultMesh QUIC native / Build linux-x64 (push) Has been skipped
CultMesh QUIC native / Release native binaries (push) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (push) Has been cancelled
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (push) Has been cancelled
Some checks failed
CultMesh QUIC native / Build win32-x64 (push) Has been skipped
CultMesh QUIC native / Build linux-x64 (push) Has been skipped
CultMesh QUIC native / Release native binaries (push) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (push) Has been cancelled
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (push) Has been cancelled
This commit is contained in:
commit
da515b0f5e
5 changed files with 19 additions and 28 deletions
|
|
@ -20,6 +20,7 @@ import {
|
|||
CultNetRudpSocketTransportConnection,
|
||||
rudpClientBindHost,
|
||||
CultNetSchemaCatalog,
|
||||
cultNetTextError,
|
||||
CultNetShardCatalog,
|
||||
cultNetBuiltinSchemaRegistry,
|
||||
decodeRudpPacket,
|
||||
|
|
@ -5577,10 +5578,7 @@ export class CultMesh {
|
|||
switch (message.schemaVersion) {
|
||||
case "cultnet.snapshot_request.v0": {
|
||||
if (!options.getCache) {
|
||||
sendSchemaMessage(record, {
|
||||
schemaVersion: "cultnet.error.v0",
|
||||
error: "CultMesh RUDP document server has no cache for snapshot requests.",
|
||||
});
|
||||
sendSchemaMessage(record, cultNetTextError("CultMesh RUDP document server has no cache for snapshot requests."));
|
||||
return;
|
||||
}
|
||||
let reply: CultNetMessage;
|
||||
|
|
@ -5613,7 +5611,7 @@ export class CultMesh {
|
|||
const unservable = unservablePut(message);
|
||||
if (unservable) {
|
||||
reportError(unservable);
|
||||
sendSchemaMessage(record, { schemaVersion: "cultnet.error.v0", error: unservable.message });
|
||||
sendSchemaMessage(record, cultNetTextError(unservable.message));
|
||||
return;
|
||||
}
|
||||
const receipt = await options.onDocumentPutRaw(normalizeRudpDocumentPut(message, record.remote, options.documents));
|
||||
|
|
@ -5623,29 +5621,20 @@ export class CultMesh {
|
|||
} catch (error) {
|
||||
// The put is stored: the peer must hear that its receipt is not coming.
|
||||
reportError(error);
|
||||
sendSchemaMessage(record, {
|
||||
schemaVersion: "cultnet.error.v0",
|
||||
error: `CultMesh RUDP document server stored a put but could not send its receipt.`,
|
||||
});
|
||||
sendSchemaMessage(record, cultNetTextError(`CultMesh RUDP document server stored a put but could not send its receipt.`));
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
case "cultnet.operation_request.v0":
|
||||
if (!options.onOperationRequest) {
|
||||
sendSchemaMessage(record, {
|
||||
schemaVersion: "cultnet.error.v0",
|
||||
error: "CultMesh RUDP document server has no operation handler.",
|
||||
});
|
||||
sendSchemaMessage(record, cultNetTextError("CultMesh RUDP document server has no operation handler."));
|
||||
return;
|
||||
}
|
||||
sendSchemaMessage(record, await options.onOperationRequest(message, publicSession(record)));
|
||||
return;
|
||||
default:
|
||||
sendSchemaMessage(record, {
|
||||
schemaVersion: "cultnet.error.v0",
|
||||
error: `Unsupported CultMesh RUDP document request ${message.schemaVersion}.`,
|
||||
});
|
||||
sendSchemaMessage(record, cultNetTextError(`Unsupported CultMesh RUDP document request ${message.schemaVersion}.`));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5741,7 +5730,7 @@ export class CultMesh {
|
|||
*/
|
||||
function refuse(record: SessionRecord, text: string): void {
|
||||
if (record.closed) return;
|
||||
const payload = encodeSchemaMessage({ schemaVersion: "cultnet.error.v0", error: text });
|
||||
const payload = encodeSchemaMessage(cultNetTextError(text));
|
||||
for (const packet of record.session.sendMany("schema", payload, {
|
||||
reliable: false,
|
||||
ordered: false,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
CultNetPeer,
|
||||
CultNetRudpSession,
|
||||
cultNetBuiltinSchemaRegistry,
|
||||
cultNetTextError,
|
||||
decodeRudpPacket,
|
||||
defineCultNetDocumentBinding,
|
||||
encodeRudpPacket,
|
||||
|
|
@ -3708,7 +3709,7 @@ test("CultMesh TS RUDP document server answers a peer whose reliable queue is fu
|
|||
while (!refusalIn(rig.inbox) && Date.now() - startedAt < 3_000) await delay(5);
|
||||
const refusal = refusalIn(rig.inbox);
|
||||
assert.ok(refusal, "the refusal reaches the peer");
|
||||
assert.deepEqual(refusal.message, { schemaVersion: "cultnet.error.v0", error: "the snapshot response could not be queued" });
|
||||
assert.deepEqual(refusal.message, cultNetTextError("the snapshot response could not be queued"));
|
||||
for (const part of refusal.parts) {
|
||||
assert.ok(refused.every((sequence) => !acknowledges(part, sequence)), `ack ${part.ack} mask ${part.ackMask}`);
|
||||
}
|
||||
|
|
@ -3725,7 +3726,7 @@ test("CultMesh TS RUDP document server refuses a snapshot with fixed text, never
|
|||
while (!refusalIn(rig.inbox) && Date.now() - startedAt < 3_000) await delay(5);
|
||||
const refusal = refusalIn(rig.inbox);
|
||||
assert.ok(refusal, "the refusal reaches the peer");
|
||||
assert.deepEqual(refusal.message, { schemaVersion: "cultnet.error.v0", error: "the snapshot source failed" });
|
||||
assert.deepEqual(refusal.message, cultNetTextError("the snapshot source failed"));
|
||||
assert.match(rig.errors[0]?.message ?? "", /CANARY-7f3a/);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ All notable changes to `@gamecult/cultnet-ts` are recorded here, following
|
|||
|
||||
### Added
|
||||
|
||||
- `cultNetTextError(error)`: the text-only `cultnet.error.v0` refusal, with `routingHint`, `code` and `details` null. The legacy-union error decode uses it, so there is one place that spells the null members.
|
||||
- `CultNetRudpSocketTransportServer`: one UDP socket serving many peers, each remote address and port with its own reliable session (`peerConnected`, `frame`, `peerDisconnected` events; `send(peer, ...)` answers on the peer a frame came from). A second client no longer replaces the first; Connects beyond `maxPeers` (default 256) are dropped, and `close()` resolves once every peer's goodbye has left the socket. The shape follows the Rust `CultNetRudpServerHub` and C# `CultNetRudpSocketTransportServer`, and the wire format is unchanged. The optional `peerTimeoutMs` (idle peers ended and told so; default off) exists only in TypeScript. `CultNetRudpSocketTransportConnection` in `server` mode still serves exactly one peer.
|
||||
|
||||
- The `cultnet.snapshot_request.v1`, `cultnet.database_subscribe.v1` and `cultnet.snapshot_response_raw.v1` carriers and the selection payload types (`CultNetSelection`, `CultNetRawDocumentHeader`, `CultNetEdge`). `parseCultNetMessage` accepts them (absent members arrive as absent keys; a page carries exactly one of `headers`/`documents`; an empty or blank `schemas`/`keys` entry throws `CultNetSelectionInvalidError` naming its field), and `encodeCultNetMessageForWire` writes the reference's nil-keyed, declaration-ordered map. Judged against bytes the C# reference wrote (`contracts/cultnet/interop/carrier-vectors.cs-written.json`) and the selection vectors C# and Rust wrote. The selection engine (evaluation, cursors, the declaration-dependent door checks) is not ported.
|
||||
|
|
|
|||
|
|
@ -199,6 +199,11 @@ export const CULTNET_ERROR_CODES = [
|
|||
|
||||
export type CultNetErrorCode = (typeof CULTNET_ERROR_CODES)[number];
|
||||
|
||||
/** A refusal that carries text only: `routingHint`, `code` and `details` are written as null, as the reference writes an absent member. */
|
||||
export function cultNetTextError(error: string): CultNetErrorMessage {
|
||||
return { schemaVersion: "cultnet.error.v0", error, routingHint: null, code: null, details: null };
|
||||
}
|
||||
|
||||
export interface CultNetErrorRoutingHint {
|
||||
shard: Record<string, unknown> | null;
|
||||
reason: string;
|
||||
|
|
@ -958,14 +963,8 @@ function parseGameCultNetworkingMessage(input: unknown): CultNetMessage {
|
|||
session: requireLegacyBytes(payload[1], "LoginSuccessMessage.Session"),
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
schemaVersion: "cultnet.error.v0",
|
||||
error: requireLegacyString(payload[0], "ErrorMessage.Error"),
|
||||
// The legacy union ErrorMessage carries only Error; the R-N fields exist on cultnet.schema.v0 alone.
|
||||
routingHint: null,
|
||||
code: null,
|
||||
details: null,
|
||||
};
|
||||
// The legacy union ErrorMessage carries only Error; the R-N fields exist on cultnet.schema.v0 alone.
|
||||
return cultNetTextError(requireLegacyString(payload[0], "ErrorMessage.Error"));
|
||||
case 5:
|
||||
return {
|
||||
schemaVersion: "cultnet.sample.change_name.v0",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export {
|
|||
type CultNetRawDocumentRecord,
|
||||
type CultNetRawPayloadEncoding,
|
||||
CULTNET_ERROR_CODES,
|
||||
cultNetTextError,
|
||||
type CultNetErrorCode,
|
||||
type CultNetErrorDetails,
|
||||
type CultNetErrorMessage,
|
||||
|
|
|
|||
Loading…
Reference in a new issue