testing generic deploy

This commit is contained in:
Devin Zuczek
2026-06-29 21:52:50 -04:00
parent 3affabd280
commit 69b89e2dc4
79 changed files with 399 additions and 307 deletions
+6 -7
View File
@@ -3,9 +3,8 @@ import { DurableObject } from 'cloudflare:workers'
import type { Env } from './context'
/**
* Durable Object hosting the SignalR notifications hub, ported from the C#
* `NotificationsHub` + `NotificationService`. A single global instance plays the
* role of the C# static dictionaries (one process, shared across connections).
* Durable Object hosting the SignalR notifications hub. A single global instance
* holds the shared hub state (one process, shared across connections).
*
* It speaks the SignalR JSON Hub Protocol over a hibernatable WebSocket:
* 1. negotiate happens in the worker; the client then opens a WS to `/hub/v1`.
@@ -15,7 +14,7 @@ import type { Env } from './context'
*
* Connection/subscription state lives in SQLite so it survives hibernation:
* - `subscriptions(connectionId, playerId)` — both the connection→players and
* (queried the other way) the player→connections maps from the C#.
* (queried the other way) the player→connections maps.
* - `pending(id, playerId, payload)` — the per-player queue delivered once a
* player is subscribed.
*/
@@ -136,7 +135,7 @@ export class NotificationsHub extends DurableObject<Env> {
state.handshakeDone = true
ws.serializeAttachment(state)
// C# OnConnectedAsync sends "OnConnect" to the caller after connecting.
// Send "OnConnect" to the caller after connecting.
ws.send(this.invocation('OnConnect', []))
}
@@ -275,8 +274,8 @@ export class NotificationsHub extends DurableObject<Env> {
// ---- Helpers -------------------------------------------------------------
/**
* Build the `Notification` argument: a JSON string `{ Id, Msg }`, matching the
* C# `SendToConnection` (null values are dropped from `Msg`).
* Build the `Notification` argument: a JSON string `{ Id, Msg }`
* (null values are dropped from `Msg`).
*/
private buildNotificationPayload(
notificationType: number,
+5 -6
View File
@@ -8,15 +8,14 @@ import { NotificationsHub } from './notifications-hub'
import type { App } from './context'
/**
* Ported from the C# `NotifyController`, which maps a SignalR hub at `/hub/v1`
* (see `NotificationsHub` / `NotificationService`). The hub itself — WebSocket
* transport, the SignalR JSON Hub Protocol, and the shared connection state —
* Maps a SignalR hub at `/hub/v1`. The hub itself — WebSocket transport, the
* SignalR JSON Hub Protocol, and the shared connection state —
* lives in the `NotificationsHub` Durable Object; this worker handles the
* SignalR negotiate handshake, forwards the WebSocket upgrade to the DO, and
* exposes internal send/broadcast endpoints for other workers.
*/
/** The hub state is global in the C# (static dictionaries) → one DO instance. */
/** The hub state is global → one DO instance. */
const HUB_INSTANCE = 'global'
const app = new Hono<App>()
@@ -57,8 +56,8 @@ const app = new Hono<App>()
})
// ---- Internal service-to-service send/broadcast --------------------------
// Lets other workers push notifications, the way the C# controllers called
// the shared NotificationService. TODO: protect these before production.
// Lets other workers push notifications through the shared hub.
// TODO: protect these before production.
.post('/internal/notify', async (c) => {
const body = await c.req
.json<{ playerId?: number; notificationType?: number; data?: Record<string, unknown> }>()
+2 -2
View File
@@ -3,7 +3,7 @@ import { describe, expect, test } from 'vitest'
import '../../notify.app'
const ORIGIN = 'https://notify.rec.djdevin.net'
const ORIGIN = 'https://example.com'
const RS = '\u001e'
interface HubRecord {
@@ -58,7 +58,7 @@ async function connect(
})
}
// Handshake, then the C# OnConnect callback.
// Handshake, then the OnConnect callback.
ws.send(`{"protocol":"json","version":1}${RS}`)
await waitFor((r) => r.type === 1 && r.target === 'OnConnect')