refactor(broker): merge HTTP+WS to single port, populate senderPubkey on push
Single-port refactor: - Drop the BROKER_PORT+1 HTTP side-port. Use `ws` with noServer:true and attach to a single node:http server via the 'upgrade' event. - Clients connect to ws://host:PORT/ws - Hook POSTs go to http://host:PORT/hook/set-status - Health probe at http://host:PORT/health - One port = one Traefik label, one cert, one deploy route. Matches the Coolify/VPS operational constraints. senderPubkey on push: - drainForMember now joins mesh.message_queue → mesh.member to return the sender's peerPubkey alongside each envelope. No extra round-trip, no cache invalidation needed (option A from review). - index.ts populates WSPushMessage.senderPubkey from the join result instead of the empty-string placeholder. - Receivers can now identify who sent a message directly from the push. README updated with a routes table for the single-port layout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -369,13 +369,17 @@ function deliverablePriorities(status: PeerStatus): Priority[] {
|
||||
|
||||
/**
|
||||
* Drain deliverable messages addressed to a specific member in a mesh.
|
||||
* Marks them delivered and returns the envelopes for the caller to
|
||||
* push over WebSocket. Does NOT handle targetSpec routing — that's the
|
||||
* responsibility of the ingress fanout (see queueForTargets).
|
||||
* Joins mesh.member so each envelope carries the sender's pubkey, which
|
||||
* the receiving client needs to identify who sent it. Marks drained
|
||||
* rows as delivered and returns the envelopes for WS push.
|
||||
*
|
||||
* targetSpec routing: matches either the member's pubkey directly or
|
||||
* the broadcast wildcard ("*"). Channel/tag resolution is per-mesh
|
||||
* config that lives outside this function.
|
||||
*/
|
||||
export async function drainForMember(
|
||||
meshId: string,
|
||||
memberId: string,
|
||||
_memberId: string,
|
||||
memberPubkey: string,
|
||||
status: PeerStatus,
|
||||
): Promise<
|
||||
@@ -386,13 +390,10 @@ export async function drainForMember(
|
||||
ciphertext: string;
|
||||
createdAt: Date;
|
||||
senderMemberId: string;
|
||||
senderPubkey: string;
|
||||
}>
|
||||
> {
|
||||
const priorities = deliverablePriorities(status);
|
||||
|
||||
// A message is deliverable to this member if its targetSpec
|
||||
// addresses them directly (pubkey match) or is a broadcast.
|
||||
// Channel/tag resolution is a per-mesh concern layered on top.
|
||||
const targetFilter = or(
|
||||
eq(messageQueue.targetSpec, memberPubkey),
|
||||
eq(messageQueue.targetSpec, "*"),
|
||||
@@ -406,8 +407,10 @@ export async function drainForMember(
|
||||
ciphertext: messageQueue.ciphertext,
|
||||
createdAt: messageQueue.createdAt,
|
||||
senderMemberId: messageQueue.senderMemberId,
|
||||
senderPubkey: memberTable.peerPubkey,
|
||||
})
|
||||
.from(messageQueue)
|
||||
.innerJoin(memberTable, eq(memberTable.id, messageQueue.senderMemberId))
|
||||
.where(
|
||||
and(
|
||||
eq(messageQueue.meshId, meshId),
|
||||
@@ -432,6 +435,7 @@ export async function drainForMember(
|
||||
ciphertext: r.ciphertext,
|
||||
createdAt: r.createdAt,
|
||||
senderMemberId: r.senderMemberId,
|
||||
senderPubkey: r.senderPubkey,
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user