feat: modular domain driven boilerplate
This commit is contained in:
81
platform/socket/channels.ts
Normal file
81
platform/socket/channels.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import type { Params } from "@valkyr/json-rpc";
|
||||
|
||||
import { SocketRegistry } from "./sockets.ts";
|
||||
|
||||
export class Channels {
|
||||
readonly #channels = new Map<string, SocketRegistry>();
|
||||
|
||||
/**
|
||||
* Add a new channel.
|
||||
*
|
||||
* @param channel
|
||||
*/
|
||||
add(channel: string): this {
|
||||
this.#channels.set(channel, new SocketRegistry());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a channel.
|
||||
*
|
||||
* @param channel
|
||||
*/
|
||||
del(channel: string): this {
|
||||
this.#channels.delete(channel);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add socket to the given channel. If the channel does not exist it is
|
||||
* automatically created.
|
||||
*
|
||||
* @param channel - Channel to add socket to.
|
||||
* @param socket - Socket to add to the channel.
|
||||
*/
|
||||
join(channel: string, socket: WebSocket): this {
|
||||
const sockets = this.#channels.get(channel);
|
||||
if (sockets === undefined) {
|
||||
this.#channels.set(channel, new SocketRegistry().add(socket));
|
||||
} else {
|
||||
sockets.add(socket);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a socket from the given channel.
|
||||
*
|
||||
* @param channel - Channel to leave.
|
||||
* @param socket - Socket to remove from the channel.
|
||||
*/
|
||||
leave(channel: string, socket: WebSocket): this {
|
||||
this.#channels.get(channel)?.del(socket);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a JSON-RPC notification to all sockets in given channel.
|
||||
*
|
||||
* @param channel - Channel to emit method to.
|
||||
* @param method - Method to send the notification to.
|
||||
* @param params - Message data to send to the clients.
|
||||
*/
|
||||
notify(channel: string, method: string, params: Params): this {
|
||||
this.#channels.get(channel)?.notify(method, params);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmits data to all registered WebSocket connections in the given channel.
|
||||
* Data can be a string, a Blob, an ArrayBuffer, or an ArrayBufferView.
|
||||
*
|
||||
* @param channel - Channel to emit message to.
|
||||
* @param data - Data to send to each connected socket in the channel.
|
||||
*/
|
||||
send(channel: string, data: string | ArrayBufferLike | Blob | ArrayBufferView): this {
|
||||
this.#channels.get(channel)?.send(data);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export const channels = new Channels();
|
||||
14
platform/socket/package.json
Normal file
14
platform/socket/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@platform/socket",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"types": "types.d.ts",
|
||||
"dependencies": {
|
||||
"@platform/auth": "workspace:*",
|
||||
"@platform/logger": "workspace:*",
|
||||
"@platform/relay": "workspace:*",
|
||||
"@platform/storage": "workspace:*",
|
||||
"@valkyr/json-rpc": "npm:@jsr/valkyr__json-rpc@1.1.0"
|
||||
}
|
||||
}
|
||||
39
platform/socket/server.ts
Normal file
39
platform/socket/server.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import "./types.d.ts";
|
||||
|
||||
import { InternalServerError } from "@platform/relay";
|
||||
import { context } from "@platform/relay";
|
||||
import { getStorageContext, storage } from "@platform/storage";
|
||||
|
||||
import { SocketRegistry } from "./sockets.ts";
|
||||
|
||||
export const sockets = new SocketRegistry();
|
||||
|
||||
export default {
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
bootstrap: async (): Promise<void> => {
|
||||
Object.defineProperties(context, {
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
sockets: {
|
||||
get() {
|
||||
const sockets = storage.getStore()?.sockets;
|
||||
if (sockets === undefined) {
|
||||
throw new InternalServerError("Sockets not defined.");
|
||||
}
|
||||
return sockets;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
resolve: async (): Promise<void> => {
|
||||
const context = getStorageContext();
|
||||
context.sockets = sockets;
|
||||
},
|
||||
};
|
||||
47
platform/socket/sockets.ts
Normal file
47
platform/socket/sockets.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Params } from "@valkyr/json-rpc";
|
||||
|
||||
export class SocketRegistry {
|
||||
readonly #sockets = new Set<WebSocket>();
|
||||
|
||||
/**
|
||||
* Add a socket to the pool.
|
||||
*
|
||||
* @param socket - WebSocket to add.
|
||||
*/
|
||||
add(socket: WebSocket): this {
|
||||
this.#sockets.add(socket);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a socket from the pool.
|
||||
*
|
||||
* @param socket - WebSocket to remove.
|
||||
*/
|
||||
del(socket: WebSocket): this {
|
||||
this.#sockets.delete(socket);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a JSON-RPC notification to all connected sockets.
|
||||
*
|
||||
* @param method - Method to send the notification to.
|
||||
* @param params - Message data to send to the clients.
|
||||
*/
|
||||
notify(method: string, params: Params): this {
|
||||
this.send(JSON.stringify({ jsonrpc: "2.0", method, params }));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmits data to all registered WebSocket connections. Data can be a string,
|
||||
* a Blob, an ArrayBuffer, or an ArrayBufferView.
|
||||
*
|
||||
* @param data - Data to send to each connected socket.
|
||||
*/
|
||||
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): this {
|
||||
this.#sockets.forEach((socket) => socket.send(data));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
22
platform/socket/types.d.ts
vendored
Normal file
22
platform/socket/types.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import "@platform/relay";
|
||||
import "@platform/storage";
|
||||
|
||||
import { SocketRegistry } from "./sockets.ts";
|
||||
|
||||
declare module "@platform/storage" {
|
||||
interface StorageContext {
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
sockets?: SocketRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "@platform/relay" {
|
||||
export interface ServerContext {
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
sockets: SocketRegistry;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user