From 6c9690818e35b75265ee79e3c0ad839d0ce4b3ae Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Fri, 17 May 2024 01:58:40 +0900 Subject: [PATCH] Specify `build.yml` launching condition --- .github/workflows/build.yml | 12 +++++++- website/out/404.html | 2 +- website/out/404/index.html | 2 +- .../_buildManifest.js | 0 .../_ssgManifest.js | 0 .../static/chunks/nextra-data-en-US.json | 2 +- website/out/api/classes/Communicator.html | 24 ++++++++-------- .../api/classes/SharedWorkerAcceptor-1.html | 24 ++++++++-------- .../api/classes/SharedWorkerConnector-1.html | 26 ++++++++--------- .../out/api/classes/SharedWorkerServer-1.html | 10 +++---- .../out/api/classes/WebSocketAcceptor-1.html | 28 +++++++++---------- .../out/api/classes/WebSocketConnector-1.html | 28 +++++++++---------- website/out/api/classes/WebSocketError.html | 4 +-- .../out/api/classes/WebSocketServer-1.html | 12 ++++---- .../out/api/classes/WorkerConnector-1.html | 28 +++++++++---------- website/out/api/classes/WorkerServer-1.html | 24 ++++++++-------- .../api/enums/WebSocketAcceptor.State.html | 4 +-- .../api/enums/WebSocketConnector.State.html | 4 +-- .../out/api/enums/WebSocketServer.State.html | 4 +-- .../SharedWorkerConnector.compile.html | 2 +- .../SharedWorkerConnector.remove.html | 2 +- .../out/api/interfaces/Invoke.IFunction.html | 8 +++--- .../out/api/interfaces/Invoke.IParameter.html | 4 +-- .../out/api/interfaces/Invoke.IReturn.html | 8 +++--- ...SharedWorkerConnector.IConnectOptions.html | 4 +-- .../WebSocketConnector.IConnectOptions.html | 4 +-- .../WorkerConnector.IConnectOptions.html | 6 ++-- website/out/api/modules/Invoke.html | 2 +- .../out/api/modules/SharedWorkerAcceptor.html | 2 +- .../api/modules/SharedWorkerConnector.html | 2 +- .../out/api/modules/SharedWorkerServer.html | 2 +- .../out/api/modules/WebSocketAcceptor.html | 2 +- .../out/api/modules/WebSocketConnector.html | 2 +- website/out/api/modules/WebSocketServer.html | 2 +- website/out/api/modules/WorkerConnector.html | 2 +- website/out/api/modules/WorkerServer.html | 2 +- website/out/api/modules/default.html | 2 +- website/out/api/types/Driver.html | 2 +- website/out/api/types/Invoke-1.html | 2 +- website/out/api/types/Primitive.html | 2 +- website/out/api/types/Promisive.html | 2 +- website/out/api/variables/Driver-1.html | 2 +- .../docs/examples/nestjs-websocket/index.html | 4 +-- .../object-oriented-network/index.html | 4 +-- .../examples/remote-function-call/index.html | 4 +-- .../examples/remote-object-call/index.html | 4 +-- .../out/docs/features/components/index.html | 4 +-- .../out/docs/features/websocket/index.html | 4 +-- website/out/docs/features/worker/index.html | 4 +-- website/out/docs/index.html | 4 +-- website/out/docs/projects/chat/index.html | 4 +-- website/out/docs/projects/market/index.html | 4 +-- website/out/docs/projects/mutex/index.html | 4 +-- .../out/docs/remote-procedure-call/index.html | 4 +-- website/out/docs/setup/index.html | 4 +-- website/out/index.html | 4 +-- website/out/robots.txt | 9 ++++++ website/out/sitemap-0.xml | 17 +++++++++++ website/out/sitemap.xml | 4 +++ website/public/sitemap-0.xml | 28 +++++++++---------- 60 files changed, 230 insertions(+), 190 deletions(-) rename website/out/_next/static/{-DY3js2CfFHHfLqBGr8ok => ZRUtDjuZZKWFwxpTo6etq}/_buildManifest.js (100%) rename website/out/_next/static/{-DY3js2CfFHHfLqBGr8ok => ZRUtDjuZZKWFwxpTo6etq}/_ssgManifest.js (100%) create mode 100644 website/out/robots.txt create mode 100644 website/out/sitemap-0.xml create mode 100644 website/out/sitemap.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85e8cc7..5e4b9d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,15 @@ name: build -on: [push, pull_request] +on: + push: + paths: + - 'src/**' + - 'test/**' + - 'package.json' + pull_request: + paths: + - 'src/**' + - 'test/**' + - 'package.json' jobs: NodeJS: diff --git a/website/out/404.html b/website/out/404.html index 93cd88d..f5a096e 100644 --- a/website/out/404.html +++ b/website/out/404.html @@ -1 +1 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/website/out/404/index.html b/website/out/404/index.html index 93cd88d..f5a096e 100644 --- a/website/out/404/index.html +++ b/website/out/404/index.html @@ -1 +1 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/website/out/_next/static/-DY3js2CfFHHfLqBGr8ok/_buildManifest.js b/website/out/_next/static/ZRUtDjuZZKWFwxpTo6etq/_buildManifest.js similarity index 100% rename from website/out/_next/static/-DY3js2CfFHHfLqBGr8ok/_buildManifest.js rename to website/out/_next/static/ZRUtDjuZZKWFwxpTo6etq/_buildManifest.js diff --git a/website/out/_next/static/-DY3js2CfFHHfLqBGr8ok/_ssgManifest.js b/website/out/_next/static/ZRUtDjuZZKWFwxpTo6etq/_ssgManifest.js similarity index 100% rename from website/out/_next/static/-DY3js2CfFHHfLqBGr8ok/_ssgManifest.js rename to website/out/_next/static/ZRUtDjuZZKWFwxpTo6etq/_ssgManifest.js diff --git a/website/out/_next/static/chunks/nextra-data-en-US.json b/website/out/_next/static/chunks/nextra-data-en-US.json index 865b2f1..c49e6c5 100644 --- a/website/out/_next/static/chunks/nextra-data-en-US.json +++ b/website/out/_next/static/chunks/nextra-data-en-US.json @@ -1 +1 @@ -{"/docs/projects/chat":{"title":"Chat","data":{"preparing#Preparing":"Preparing the chatting application project documentation.Also, upgrading very old project to be modernized.https://github.com/samchon/tgrid.projects.chat"}},"/docs/projects/market":{"title":"Market","data":{"preparing#Preparing":"Preparing the grid market project documentation.Also, upgrading very old project to be modernized.https://github.com/samchon/tgrid.projects.market"}},"/docs/projects/mutex":{"title":"Mutex","data":{"preparing#Preparing":"Preparing the mutex server project documentation.Also, upgrading very old project to be modernized.https://github.com/samchon/mutex"}},"/docs/setup":{"title":"Setup","data":{"standalone#Standalone":"npm install tgrid\npnpm install tgrid\nyarn add tgrid\nIf you're planning to use TGrid standalone, without NestJS integration, just setup it.","nestjs#NestJS":"Nestia > Guide Documents > SetupOtherwise, you wanna use TGrid with NestJS integration, please refer to the guide documents of nestia.By the way, if you want to setup it right now without reading detailed documents, just run the below commands.\nnpx nestia setup\r\nnpm install tgrid\nnpx nestia setup --manager pnpm\r\npnpm install tgrid\nYarn beery is not supported.\nnpx nestia setup --manager yarn\r\nyarn add tgrid"}},"/":{"title":"Index","data":{"key-features#Key Features":""}},"/docs/examples/nestjs-websocket":{"title":"Nestjs Websocket","data":{"outline#Outline":"If you develop websocket application, I recommend integrate TGrid with NestJS / Nestia.It's because you can manage WebSocket API endpoints much effectively and easily by NestJS controller patterns. Also, you can make your server to support both HTTP and WebSocket protocols at the same time. NestJS controllers are compatible with both HTTP and WebSocket operations.Furthermore, you can generate SDK (Software Development Kit) library for your client application through Nestia. With the automatically generated SDK, client developers no more need to write the WebSocket connection and RPC (Remote Procedure Call) codes manually, so that the client development becomes much easier and safer.\nReferences\nNestia > Guide Documents > Setup\nNestia > Guide Documents > WebSocketRoute\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.nestjs\r\nnpm install\r\nnpm start","server-program#Server Program":"","bootstrap#Bootstrap":"import { WebSocketAdaptor } from \"@nestia/core\";\r\nimport { INestApplication } from \"@nestjs/common\";\r\nimport { NestFactory } from \"@nestjs/core\";\r\n\r\nimport { CalculateModule } from \"./calculate.module\";\r\n\r\nexport const bootstrap = async (): Promise => {\r\n const app: INestApplication = await NestFactory.create(CalculateModule);\r\n await WebSocketAdaptor.upgrade(app);\r\n await app.listen(37_000, \"0.0.0.0\");\r\n return app;\r\n};\nTo integrate TGrid with NestJS, you have to upgrade the NestJS application like above.Just call the WebSocketAdaptor.upgrade(), then you can utilize TGrid in the NestJS server.","controller#Controller":"import { TypedRoute, WebSocketRoute } from \"@nestia/core\";\r\nimport { Controller } from \"@nestjs/common\";\r\nimport { Driver, WebSocketAcceptor } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./api/interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./api/interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./api/interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./api/interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./api/interfaces/IStatisticsCalculator\";\r\n\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\n@Controller(\"calculate\")\r\nexport class CalculateController {\r\n /**\r\n * Health check API (HTTP GET).\r\n */\r\n @TypedRoute.Get(\"health\")\r\n public health(): string {\r\n return \"Health check OK\";\r\n }\r\n\r\n /**\r\n * Prepare a composite calculator.\r\n */\r\n @WebSocketRoute(\"composite\")\r\n public async composite(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n ICompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n @WebSocketRoute.Header() header: ICalcConfig,\r\n @WebSocketRoute.Driver() listener: Driver\r\n ): Promise {\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a simple calculator.\r\n */\r\n @WebSocketRoute(\"simple\")\r\n public async simple(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig, // header\r\n ISimpleCalculator, // provider for remote client\r\n ICalcEventListener // provider from remote client\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: SimpleCalculator = new SimpleCalculator(header, listener);\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a scientific calculator.\r\n */\r\n @WebSocketRoute(\"scientific\")\r\n public async scientific(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IScientificCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a statistics calculator.\r\n */\r\n @WebSocketRoute(\"statistics\")\r\n public async statistics(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IStatisticsCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: IStatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n}\nimport { Module } from \"@nestjs/common\";\r\n\r\nimport { CalculateController } from \"./calculate.controller\";\r\n\r\n@Module({\r\n controllers: [CalculateController],\r\n})\r\nexport class CalculateModule {}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nAs you can see from the above code, CalculateController has many API operations, including both HTTP and WebSocket protocols. The CalculatorController.health() is an HTTP Get method operation, and the others are all WebSocket operations.When defining WebSocket operation, attach @WebSocketRoute() decorator to the target controller method with path specification. Also, the controller method must have the @WebSocketRoute.Acceptor() decorated parameter with WebSocketAcceptor type, because you have to determine whether to WebSocketAcceptor.accept() the client's connection or WebSocketAcceptor.reject() it.With such controller patterned WebSocket operation, you can manage WebSocket API endpoints much effectively and easily. Also, you can generate SDK (Software Development Kit) library for your client application through Nestia. Let's see how to generate SDK library, and how it would be looked like in the next section.","software-development-kit#Software Development Kit":"/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nnpx nestia sdk\nWhen you run npx nestia sdk command, SDK (Software Development Kit) library be generated.Above file is one of the SDK library corresponding to the CalculateController class we've seen in the previous NestJS Controller section. Client developers can utilize the automatically generated SDK functions to connect to the WebSocket server, and interact it type safely. Also, HTTP operation is compatible with the WebSocket operation.Let's see how client developer utilizes the SDK library in the next section.","client-program#Client Program":"import api from \"./api\";\r\nimport { ICalcEvent } from \"./api/interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\n\r\nexport const testCalculateSdk = async () => {\r\n //----\r\n // HTTP PROTOCOL\r\n //---\r\n // CALL HEALTH CHECK API\r\n console.log(\r\n await api.functional.calculate.health({\r\n host: \"http://127.0.0.1:37000\",\r\n })\r\n );\r\n\r\n //----\r\n // WEBSOCKET PROTOCOL\r\n //---\r\n // PROVIDER FOR WEBSOCKET SERVER\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n\r\n // DO CONNECT\r\n const { connector, driver } = await api.functional.calculate.composite(\r\n {\r\n host: \"ws://127.0.0.1:37000\",\r\n headers: {\r\n precision: 2,\r\n },\r\n },\r\n listener\r\n );\r\n\r\n // CALL FUNCTIONS OF REMOTE SERVER\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9) // returns 4.33\r\n );\r\n\r\n // TERMINATE\r\n await connector.close();\r\n console.log(stack);\r\n};\n/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestFactory] Starting Nest application...\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [InstanceLoader] CalculateModule dependencies initialized +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [RoutesResolver] CalculateController {/calculate}: +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestApplication] Nest application successfully started +2ms\r\n\r\nHealth check OK\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nDo import the SDK, and enjoy the type-safe and easy-to-use RPC (Remote Procedure Call).Looking at the above code, the client application is calling a function of the automatically generated SDK (Software Development Kit) library, so that connecting to the websocket server, and starting interaction through RPC (Remote Procedure Call) concept with Driver instance.Doesn't the \"SDK based development\" seems much easier and safer than native websocket classes case? This is the reason why I've recommended to combine with the NestJS when using websocket protocol based network system.This is the integration of TGrid with NestJS.","next-chapter#Next Chapter":"We've learned how to utilize TGrid with many examples.By the way, don't you want to know how to utilize TGrid in the real project?In the next chapter, we'll see how TGrid be utilized in the real world.\nLearn from Projects\nChat Application\nGrid Market\nMutex Server"}},"/docs/examples/object-oriented-network":{"title":"Object Oriented Network","data":{"outline#Outline":"Each remote system is an object.With TGrid, you can easily develop complicated network system, by considering each network system as an object, and interacting with each other through RPC (Remote Procedure Call). TGrid defines this concept as \"Object Oriented Network\".In this chapter, we'll remake the composite calculator system of Remote Object Call chapter again, but replace scientific and statistics calculators to remote system. Therefore, the composite calculator system will be consisted of three remote servers: \"composite server\", \"scientific server\" and \"statistics server\".Let's see how TGrd implements the \"Object Oriented Network\".\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.object-oriented-network\r\nnpm install\r\nnpm start","client-program#Client Program":"import { Driver, WorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\nexport const workerClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n \"process\",\r\n );\r\n await connector.connect(`${__dirname}/composite.${EXTENSION}`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]","server-programs#Server Programs":"import { Driver, WorkerConnector, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { IScientificCalculator } from \"./interfaces/IScientificCalculator\";\r\nimport { IStatisticsCalculator } from \"./interfaces/IStatisticsCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\n/// `CompositeCalculator` has two additional properties\r\n///\r\n/// - `scientific` from remote worker server\r\n/// - `statistics` from remote worker server\r\nclass CompositeCalculator extends SimpleCalculator {\r\n public readonly scientific: Driver;\r\n public readonly statistics: Driver;\r\n\r\n public constructor(props: {\r\n config: ICalcConfig;\r\n listener: Driver;\r\n scientific: Driver;\r\n statistics: Driver;\r\n }) {\r\n super(props.config, props.listener);\r\n this.scientific = props.scientific;\r\n this.statistics = props.statistics;\r\n }\r\n}\r\n\r\n/// connect to remote worker server\r\nconst connect = async (\r\n header: ICalcConfig,\r\n listener: Driver,\r\n file: string,\r\n): Promise> => {\r\n const connector: WorkerConnector =\r\n new WorkerConnector(header, listener, \"process\");\r\n await connector.connect(file);\r\n return connector.getDriver();\r\n};\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n const config: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n\r\n // constructor provider combining with remote worker-servers\r\n const provider: CompositeCalculator = new CompositeCalculator({\r\n config,\r\n listener,\r\n scientific: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/scientific.${EXTENSION}`,\r\n ),\r\n statistics: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/statistics.${EXTENSION}`,\r\n ),\r\n });\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n ScientificCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n StatisticsCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: StatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nCompose Provider with Driver of another remote system.Looking at the \"Composite Server\", it is providing CompositeCalculator to the \"Client Program\". By the way, the CompositeCalculator is different with before chapter Remote Object Call. Properties scientific and statistics are composed with Driver of another remote system.Therefore, if \"Client Program\" calls Driver.scientific.sqrt(2) function, it will be forwarded to the \"Scientific Server\", and \"Composite Server\" only intermediates the remote function call (network communication) between \"Client Program\" and \"Scientific Server\".This is the \"Object Oriented Network\" of TGrid.","next-chapter#Next Chapter":"At next chapter, we'll learn how to integrate TGrid with NestJS.\nLearn from Examples > NestJS Integration\nimport { TypedRoute, WebSocketRoute } from \"@nestia/core\";\r\nimport { Controller } from \"@nestjs/common\";\r\nimport { Driver, WebSocketAcceptor } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./api/interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./api/interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./api/interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./api/interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./api/interfaces/IStatisticsCalculator\";\r\n\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\n@Controller(\"calculate\")\r\nexport class CalculateController {\r\n /**\r\n * Health check API (HTTP GET).\r\n */\r\n @TypedRoute.Get(\"health\")\r\n public health(): string {\r\n return \"Health check OK\";\r\n }\r\n\r\n /**\r\n * Prepare a composite calculator.\r\n */\r\n @WebSocketRoute(\"composite\")\r\n public async composite(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n ICompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n @WebSocketRoute.Header() header: ICalcConfig,\r\n @WebSocketRoute.Driver() listener: Driver\r\n ): Promise {\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a simple calculator.\r\n */\r\n @WebSocketRoute(\"simple\")\r\n public async simple(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig, // header\r\n ISimpleCalculator, // provider for remote client\r\n ICalcEventListener // provider from remote client\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: SimpleCalculator = new SimpleCalculator(header, listener);\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a scientific calculator.\r\n */\r\n @WebSocketRoute(\"scientific\")\r\n public async scientific(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IScientificCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a statistics calculator.\r\n */\r\n @WebSocketRoute(\"statistics\")\r\n public async statistics(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IStatisticsCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: IStatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n}\nimport api from \"./api\";\r\nimport { ICalcEvent } from \"./api/interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\n\r\nexport const testCalculateSdk = async () => {\r\n //----\r\n // HTTP PROTOCOL\r\n //---\r\n // CALL HEALTH CHECK API\r\n console.log(\r\n await api.functional.calculate.health({\r\n host: \"http://127.0.0.1:37000\",\r\n })\r\n );\r\n\r\n //----\r\n // WEBSOCKET PROTOCOL\r\n //---\r\n // PROVIDER FOR WEBSOCKET SERVER\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n\r\n // DO CONNECT\r\n const { connector, driver } = await api.functional.calculate.composite(\r\n {\r\n host: \"ws://127.0.0.1:37000\",\r\n headers: {\r\n precision: 2,\r\n },\r\n },\r\n listener\r\n );\r\n\r\n // CALL FUNCTIONS OF REMOTE SERVER\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9) // returns 4.33\r\n );\r\n\r\n // TERMINATE\r\n await connector.close();\r\n console.log(stack);\r\n};\n/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}"}},"/docs/examples/remote-object-call":{"title":"Remote Object Call","data":{"outline#Outline":"With TGrid, you can call remote system's nested functions as if they are local functions.Such remote procedure calling concept is called as RPC (Remote Procedure Call) in the development world, but it contains not only remote function call, but also contains Object Oriented Network. However, in here chapter, we will focus only on the remote nested function calls.Let's learn how to call remote nested functions with TGrid.\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.remote-object-call\r\nnpm install\r\nnpm start","client-program#Client Program":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nHere is an example websocket client program, calling remote calculator of the websocket server's own.As you can see, the client has constructed a WebSocketConnector instance with the Header and listener objects. The header object represents a Header component which be directly delivered to the remote system when connecting. The listener object is a Provider component provided for the remote websocket server. It means that, the \"Client Program\" configures the header value to precision: 2, and provides ICalcEventListener for the remote \"Server Program\".After that, you can find out the \"Client Program\" is calling the remote calculator's function of \"Server Program\" through Driver typed instance. In the remote function call statements, there is one thing important. It is Driver type supports nested object's funtion calls.This is the \"Remote Object Call\".","server-program#Server Program":"import { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n });\r\n return server;\r\n};\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends CalculatorBase\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nThe \"Server Program\" is providing CompositeCalculator class to the websocket client.By the way, when composing the CompositeCalculator class instance as a Provider, you can find out that it is delivering the Header and Driver typed instances to the construction parameter. By getting the Header value from the \"Client Program\", \"Server Program\" configures precision level of the calculator.Also, if you click the second Providers tab, you can find out that calculators are reporting their calculator operations to the \"Client Program\" through the Driver object. Therefore, whenever the calculator function be called, \"Server Program\" calls remote function of the \"Client Program\" for event reporting.Such two-way remote functions providing and header for initialization, this is the \"Remote Object Call\".","next-chapter#Next Chapter":"Until this chapter, we've learned only about simple structructured network systems. Complexity has only come to the Provider level, and the network systems were always monotonous. Only single type of server and client were existed.By the way, TGrid has said that it is useful for developing complicated network system like grid computing in the README and index page of guide documents. At the next chapter, we will learn about the complicated network system.\nLearn from Examples > Object Oriented Network.\nimport { Driver, WorkerConnector, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { IScientificCalculator } from \"./interfaces/IScientificCalculator\";\r\nimport { IStatisticsCalculator } from \"./interfaces/IStatisticsCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\n/// `CompositeCalculator` has two additional properties\r\n///\r\n/// - `scientific` from remote worker server\r\n/// - `statistics` from remote worker server\r\nclass CompositeCalculator extends SimpleCalculator {\r\n public readonly scientific: Driver;\r\n public readonly statistics: Driver;\r\n\r\n public constructor(props: {\r\n config: ICalcConfig;\r\n listener: Driver;\r\n scientific: Driver;\r\n statistics: Driver;\r\n }) {\r\n super(props.config, props.listener);\r\n this.scientific = props.scientific;\r\n this.statistics = props.statistics;\r\n }\r\n}\r\n\r\n/// connect to remote worker server\r\nconst connect = async (\r\n header: ICalcConfig,\r\n listener: Driver,\r\n file: string,\r\n): Promise> => {\r\n const connector: WorkerConnector =\r\n new WorkerConnector(header, listener, \"process\");\r\n await connector.connect(file);\r\n return connector.getDriver();\r\n};\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n const config: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n\r\n // constructor provider combining with remote worker-servers\r\n const provider: CompositeCalculator = new CompositeCalculator({\r\n config,\r\n listener,\r\n scientific: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/scientific.${EXTENSION}`,\r\n ),\r\n statistics: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/statistics.${EXTENSION}`,\r\n ),\r\n });\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver, WorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\nexport const workerClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n \"process\",\r\n );\r\n await connector.connect(`${__dirname}/composite.${EXTENSION}`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};"}},"/docs/examples/remote-function-call":{"title":"Remote Function Call","data":{"outline#Outline":"With TGrid, you can call remote system's functions as if they are local functions.Such remote procedure calling concept is called as RPC (Remote Procedure Call) in the development world, but it contains not only remote funtion call, but also contains Remote Object Call and Object Oriented Network. However, in here chapter, we will focus only on the remote function calls.Let's learn how to call remote functions with TGrid.\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.remote-function-call\r\nnpm install\r\nnpm start","client-program#Client Program":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalculator } from \"./ICalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const connector: WebSocketConnector =\r\n new WebSocketConnector(\r\n null, // header\r\n null, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.minus(7, 3), // returns 4\r\n await remote.multiply(3, 4), // returns 12\r\n await remote.divide(5, 2), // returns 2.5\r\n );\r\n\r\n await connector.close();\r\n};\r\n\r\ninterface ICalculator {\r\n plus(a: number, b: number): number\r\n minus(a: number, b: number): number\r\n multiply(a: number, b: number): number\r\n divide(a: number, b: number): number\r\n}\n$ npm start\r\n30 4 12 2.5\nHere is an example websocket client program, calling remote calculator of the websocket server's own.As you can see, the client program has written the remote function call statements on the remote instance of Driver type. Also, the Driver typed instance has been composed by the WebSocketConnector.getDriver() method. It's because Driver is a proxy instance hooking the function call expressions, so that delivers them to the remote system, and receives the return value from the remote system.This is the secret of how TGrid has implemented the RPC (Remote Procedure Call). Just call functions of remote Provider to the Driver typed instance with await symbol, as if the Provider instance was your own. Then, TGrid will perform the proper network communications for RPC instead of you.","server-program#Server Program":"import { WebSocketServer } from \"tgrid\";\r\n\r\nimport { Calculator } from \"./Calculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n null, // header\r\n Calculator, // provider for remote client\r\n null // provider from remote client\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n const provider: Calculator = new Calculator();\r\n await acceptor.accept(provider);\r\n });\r\n return server;\r\n};\r\n\r\nclass Calculator {\r\n public plus(x: number, y: number): number {\r\n return x + y;\r\n }\r\n public minus(x: number, y: number): number {\r\n return x - y;\r\n }\r\n public multiply(x: number, y: number): number {\r\n return x * y;\r\n }\r\n public divide(x: number, y: number): number {\r\n return x / y;\r\n }\r\n}\nimport { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalculator } from \"./ICalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const connector: WebSocketConnector =\r\n new WebSocketConnector(\r\n null, // header\r\n null, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.minus(7, 3), // returns 4\r\n await remote.multiply(3, 4), // returns 12\r\n await remote.divide(5, 2), // returns 2.5\r\n );\r\n\r\n await connector.close();\r\n};\r\n\r\ninterface ICalculator {\r\n plus(a: number, b: number): number\r\n minus(a: number, b: number): number\r\n multiply(a: number, b: number): number\r\n divide(a: number, b: number): number\r\n}\nHere is the websocket server program providing Calculator class to the client.Above \"Client Program\" is calling remote functions to the calculator through the remote instance of Driver typed. To make the client program works properly, \"Server Program\" must provide the actual instance implemented the ICalculator type. This \"Server Program\" is serving it providing the Calculator class instance in such reason.By the way, the provided Calculator does not have any asynchronous method, but \"Client Program\" is calling the remote functions with await symbol. It's because remote function calls are actually asynchrounous operations perform by the network communication, and Driver is a type changing every function's return type to be asynchronous (Promise) in such reason.This is the RPC (Remote Procedure Call) of TGrid.","next-chapter#Next Chapter":"In this chapter, we've learned only about one-way remote function calls. By the way, most of real-time network systems need two-way communication. Also, we have not utilized Header, the value directly delivered after the connection, at all.\nLearn from Examples > Remote Object Call chapter.\nimport { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const provider: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n provider, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};"}},"/docs/features/components":{"title":"Components","data":{"outline#Outline":"This chapter describes key components of the TGrid only in the conceptual level.If you're not familar with theoretical stories, it's okay to skip to the next chapter Features > WebSocket Protocol.Even you want to see the example codes, step to the Learn from Examples > Remote Funtion Call chapter.Otherwise, let's study about the key components of the TGrid.\nCommunicator: network communication with remote system\nHeader: header value directly delivered after the connection\nProvider: object provided for remote system\nDriver: proxy instance for calling functions of the remote system's Provider","communicator#Communicator":"Communicates with a remote system.Communicator is a class taking full responsibility to network communication with remote system. You can register a Provider, an object would be provided to the remote system, to the Communicator. Also, Driver, which can access to the remote system's Provider, is created by this Communicator.For reference, actual Communicator is the top-level abstract class, and all the classes responsible for network communication in TGrid are inheriting from this Communicator class. Here is the list of every communicator classes in TGrid.\nProtocol\tClient\tServer\tWeb Socket\tWebSocketConnector\tWebSocketAcceptor\tDedicated Worker\tWorkerConnector\tWorkerServer\tShared Worker\tSharedWorkerConnector\tSharedWorkerAcceptor","header#Header":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nimport { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nimport { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nHeader value delivered after the connection.Header is a value, delivered from client to server directly, after the connection.Server can get the Header value through acceptor's header property.\nWebSocketAcceptor.header\nWorkerServer.getHeader()\nSharedWorkerSever.header","provider#Provider":"import { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nObject provided for remote system.Provider is an object provided for the remote system.The remote system can call the Provider's functions through Driver.","driver#Driver":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nDriver of RPC (Remote Procedure Call).Driver is a proxy instance designed to call functions of the remote system. It has a generic argument Remote which means the type of remote system's Provider, and you can remotely call the functions of the Provider asynchronously through the Drive instance.When you call some function of remote Provider by the Driver instance, it hooks the function call expression, and delivers the function name and arguments (parameter values) to the remote system through the Communicator. If the remote system suceeded to reply the result of the function call, Communicator resolves the promise of the function call expression with the result, so that makes Driver working.Otherwise exception is thrown in the remote Provider function, Communicator deliveries the exception instance instead to the remote system, so that actual exception being thrown from the Driver instance.\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.websocket\r\nnpm install\r\nnpm start"}},"/docs/features/worker":{"title":"Worker","data":{"outline#Outline":"TGrid supports Worker/SharedWorker protocols.With TGrid, you can easily develop Worker programs under the RPC (Remote Procedure Call) concept.TGrid considers Worker as a 1: 1 dedicated server, and SharedWorker as a 1: N multi-client acceptable server running on the local. Therefore, the interfaces of Worker and SharedWorker in the TGrid are similar with WebSocket components. In such reason, if you're developing a complicate WebSocket system, you can simulate it in the local environment by using Worker/SharedWorker components.","worker#Worker":"Available in both Browser/NodeJS.\nYou can utilize RPC (Remote Procedure Call) even in the Worker.","workerconnector#WorkerConnector":"import { Driver, WorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\nexport const workerClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n \"process\",\r\n );\r\n await connector.connect(`${__dirname}/server.${EXTENSION}`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nWorker Connector.The WorkerConnetor is a communicator class, which creates an Worker instance, and interacts with it through RPC (Remote Procedure Call). In other words, WorkerConnector considers the Worker instance as a remote server accepting only one client; WorkerServer.You can create the Worker instance and communicate with it by WorkerConnector.connect() or WorkerConnector.compile() method. The WorkerConnector.connect() method just opens an existing JS (or TS) file, and the WorkerConnector.compile() method writes a temporary JS (TS) file and connects to it. Anyway, the Worker instanced program must open the WorkerServer.By the way, don't forget closing the worker to clean up the resources. If the closing be performed by WorkerServer, you can wait the worker server closing through the WorkerConnector.wait() method.Also, when declaring this WorkerConnector type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target WorkerServer class (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from client to server, and the other Remote means a provider from the remote server to client.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Client is providing ICalcEventListener to the server\nRemote: Server is providing ISimpleCalculator to the client\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.worker\r\nnpm install\r\nnpm start","workerserver#WorkerServer":"import { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nWorker Server.The WorkerServer is a class representing a Worker server which communicate with client (WorkerConnector), through the RPC (Remote Procedure Call).Unlike other servers, WorkerServer can accept only one client (WorkerConnector), because the Worker is dependent on its parent instance (web page, node or parent worker). Thus, WorkerServer does not have any acceptor and communicates with client (its parent) directly.To start communication with the client, call the WorkerServer.open() method with Provider instance. After your business, don't forget closing this Worker instance. If the termination is performed by the WorkerConnector, you can wait the closing signal through the WorkerServer.join() method.Also, when declaring this WorkerServer type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target WorkerConnector class (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the client to server.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Server is providing CompositeCalculator to the client\nRemote: Client is providing ICalcEventListener to the server","shared-worker#Shared Worker":"Available only in the Web Browser.\nIn the Web Browser, you also can perform RPC (Remote Procedure Call) in the SharedWorker.Also, as SharedWorker can accept multiple clients, TGrid considers it as a local server running on the web browser, and its interfaces are similar with WebSocket components.","sharedworkerserver#SharedWorkerServer":"import { Driver, SharedWorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n let pool: number = 0;\r\n const server: SharedWorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new SharedWorkerServer();\r\n await server.open(async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT THE CONNECTION\r\n if (pool >= 8) {\r\n await acceptor.reject(\"Too much connections.\");\r\n } else {\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n ++pool;\r\n await acceptor.join();\r\n --pool;\r\n }\r\n });\r\n};\r\nmain().catch(console.error);\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nShared Worker Server.The SharedWorkerServer is a class representing a server in SharedWorker environment. Clients connecting to the SharedWorkerServer would communicate with this server through SharedWorkerAcceptor instaces using RPC (Remote Procedure Call) concept.To open the server, call the SharedWorkerServer.open() method with your callback function which would be called whenever a SharedWorkerAcceptor has been newly created by a new client's connection.Also, when declaring this SharedWorkerServer type, you have to define three generic arguments; Header, Provider and Remote. Those generic arguments would be propagated to the SharedWorkerAcceptor, so that SharedWorkerAcceptor would have the same generic arguments, too.For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Server is providing CompositeCalculator to the client\nRemote: Client is providing ICalcEventListener to the server","sharedworkeracceptor#SharedWorkerAcceptor":"import { Driver, SharedWorkerAcceptor, SharedWorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n let pool: number = 0;\r\n const server: SharedWorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new SharedWorkerServer();\r\n await server.open(\r\n async (\r\n acceptor: SharedWorkerAcceptor<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n ) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT THE CONNECTION\r\n if (pool >= 8) {\r\n await acceptor.reject(\"Too much connections.\");\r\n } else {\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n ++pool;\r\n await acceptor.join();\r\n --pool;\r\n }\r\n },\r\n );\r\n};\r\nmain().catch(console.error);\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nShared Worker Acceptor.The SharedWorkerAcceptor is a communicator class interacting with the SharedWorkerConnector through RFC (Remote Function Call), created by the SharedWorkerServer class whenever a client connects to the SharedWorker instance.When a remote client connects to the SharedWorkerServer, so that a new SharedworkerAcceptor instance being created, you can determine whether to accept the client's connection or not, reading the SharedWorkerAcceptor.header property. If you've decided to accept the connection, call the SharedWorkerAcceptor.accept() method with Provider instance. Otherwise, reject it thorugh the SharedWorkerAcceptor.reject() method.After accepting the connection, don't forget to closing the connection after your business has been completed to clean up the resources. Otherwise the closing must be performed by the remote client, you can wait the remote client's closing signal by the SharedWorkerAcceptor.join() method.Also, when declaring this SharedworkerAcceptor type, you have to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the SharedWorkerServer class.For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.","sharedworkerconnector#SharedWorkerConnector":"import { Driver, SharedWorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst main = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: SharedWorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new SharedWorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(`./server.js`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n for (const evt of stack) console.log(JSON.stringify(evt));\r\n};\r\nmain().catch(console.error);\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n30 12 1.67 1.41 4.33\r\n{\"type\":\"plus\",\"input\":[10,20],\"output\":30}\r\n{\"type\":\"multiplies\",\"input\":[3,4],\"output\":12}\r\n{\"type\":\"divides\",\"input\":[5,3],\"output\":1.67}\r\n{\"type\":\"sqrt\",\"input\":[2],\"output\":1.41}\r\n{\"type\":\"mean\",\"input\":[1,3,9],\"output\":4.33}\nShared Worker Connector.The SharedWorkerConnector is a communicator class which connects to an SharedWorker instance, and interacts with it through RFC (Remote Function Call) concept.You can connect to the SharedWorkerServer using SharedWorkerConnector.connect() method. The interaction would be started if the server accepts your connection by calling the SharedWorkerAcceptor.accept() method. If the remote server rejects your connection through SharedWorkerAcceptor.reject() method, the exception would be thrown.After the connection, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote shared worker server, you can wait the remote server's closing signal through the SharedWorkerConnector.join() method.Also, when declaring this SharedWorkerConnector type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target SharedWorkerServer and SharedWorkerAcceptor classes (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from client to server, and the other Remote means a provider from the remote server to client.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Client is providing ICalcEventListener to the server\nRemote: Server is providing ISimpleCalculator to the client\nDemonstrationYou can run it on your local machine.\ngit clone https://github.com/samchon/tgrid.example.shared-worker\r\nnpm install\r\nnpm run build\r\nnpm start"}},"/docs":{"title":"Index","data":{"":"TypeScript Grid Computing Framework.TypeScript RPC (Remote Procedure Call) framework for WebSocket and Worker protocols.\nWebSocket\nWorker\nSharedWorker\nNestJS\nAlso, extremely easy even when composing complicated network system like grid computing.\nimport { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"../interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]"}},"/docs/features/websocket":{"title":"Websocket","data":{"outline#Outline":"TGrid supports WebSocket protocol.With TGrid, you can easily develop WebSocket system under the RPC (Remote Procedure Call) concept.By the way, when you're developing WebSocket server natively only with TGrid, you have to construct and open the WebSocket server through WebSocketServer class. Also, you have to access to the WebSocket server with manual WebSocketConnector composition.Instead, if you develop the WebSocket server with NestJS, client can easily interact with the WebSocket server by SDK (Software Development Kit) library generated by Nestia. Also, you can make both http and websocket operations to the NestJS controllers, so that makes the server compatible on both protocols.Therefore, when you develop WebSocket server, I recommend to use NestJS with TGrid for the best development experience.","native-classes#Native Classes":"","websocketserver#WebSocketServer":"import { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nAvailable only in the NodeJS.\nWebSocketServer is a class which can open an websocket server. Clients connecting to the WebSocketServer would communicate with this websocket server through WebSocketAcceptor objects with RPC (Remote Procedure Call) concept.To open the websocket server, call the WebSocketServer.open() method with target port number, and your custom callback function which would be called whenever a WebSocketAcceptor has been newly created by a new client's connection.Also, when declaring WebSocketServer type, you have to specify three generic arguments; Header, Provider and Remote. Those generic arguments would be propagated to the WebSocketAcceptor, so that WebSocketAcceptor would have the same generic arguments, too.For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Server is providing one of below to the client\nSimpleCalculator\nStatisticsCalculator\nScientificCalculator\nRemote: Client is providing ICalcEventListener to the server","websocketacceptor#WebSocketAcceptor":"import { Driver, WebSocketAcceptor, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(\r\n 37_000,\r\n async (\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n >,\r\n ) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n },\r\n );\r\n return server;\r\n};\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nAvailable only in the NodeJS.\nThe WebSocketAcceptor is a communicator class interacting with the remote websocket client through (RPC)(Remote Procedure Call) concept, created by the WebSocketServer class whenever a remote client connects to the websocket server.When the closure function being called by the connection of a remote client, you can determine whether to accept the client's connection or not, reading the WebSocketAcceptor.header or WebSocketAcceptor.path properties. If you've decided to accept the connection, call the WebSocketAcceptor.accept() method with Provider instance. Otherwise, reject it through the WebSocketAcceptor.reject() method.After accepting the connection, don't forget to closing the connection after your business logic has been completed to clean up the resources. Otherwise the closing must be performed by the remote client, you can wait the remote client's closing signal by the WebSocketAcceptor.join() method.","websocketconnector#WebSocketConnector":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"../interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nAvailable in both Browser/NodeJS.\nWeb Socket Connector.The WebSocketConnector is a communicator class which connects to a websocket server and interacts with it through RPC (Remote Procedure Call) concept.You can connect to the websocket server using WebSocketConnector.connect() method. The interaction would be started if the server accepts your connection by calling the WebSocketAcceptor.accept() method. If the remote server rejects your connection through WebSocketAcceptor.reject() method, the exception would be thrown.After the connection, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote websocket server, you can wait the remote server's closing signal through the WebSocketConnector.join() method.Also, when declaring this WebSocketConnector type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target WebSocketServer and WebSocketAcceptor classes (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from client to server, and the other Remote means a provider from the remote server to client.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Client is providing ICalcEventListener to the server\nRemote: Server is providing ISimpleCalculator to the client\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.websocket\r\nnpm install\r\nnpm start","nestjs-integration#NestJS Integration":"If you develop websocket application, I recommend integrate TGrid with NestJS.It's because you can manage WebSocket API endpoints much effectively and easily by NestJS controller patterns. Also, you can make your server to support both HTTP and WebSocket protocols at the same time. NestJS controllers are compatible with both HTTP and WebSocket operations.In the client side, you also can take advantages of automatically generated SDK (Software Development Kit) library for the client developers. With the SDK, client developers no more need to write the WebSocket connection and RPC (Remote Procedure Call) codes manually, so that the client development becomes much easier and safer.","bootstrap#Bootstrap":"import { WebSocketAdaptor } from \"@nestia/core\";\r\nimport { INestApplication } from \"@nestjs/common\";\r\nimport { NestFactory } from \"@nestjs/core\";\r\n\r\nimport { CalculateModule } from \"./calculate.module\";\r\n\r\nexport const bootstrap = async (): Promise => {\r\n const app: INestApplication = await NestFactory.create(CalculateModule);\r\n await WebSocketAdaptor.upgrade(app);\r\n await app.listen(37_000, \"0.0.0.0\");\r\n return app;\r\n};\nTo utilize TGrid in the NestJS, upgrade the NestJS application like above.Just call the WebSocketAdaptor.upgrade() method, then you can utilize TGrid in the NestJS server.\nAbout detailed setup or more detailed informations, please refer below docs:\nNestia > Guide Documents > Setup\nNestia > Guide Documents > WebSocketRoute","nestjs-controller#NestJS Controller":"import { TypedRoute, WebSocketRoute } from \"@nestia/core\";\r\nimport { Controller } from \"@nestjs/common\";\r\nimport { Driver, WebSocketAcceptor } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./api/interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./api/interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./api/interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./api/interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./api/interfaces/IStatisticsCalculator\";\r\n\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\n@Controller(\"calculate\")\r\nexport class CalculateController {\r\n /**\r\n * Health check API (HTTP GET).\r\n */\r\n @TypedRoute.Get(\"health\")\r\n public health(): string {\r\n return \"Health check OK\";\r\n }\r\n\r\n /**\r\n * Prepare a composite calculator.\r\n */\r\n @WebSocketRoute(\"composite\")\r\n public async composite(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n ICompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n @WebSocketRoute.Header() header: ICalcConfig,\r\n @WebSocketRoute.Driver() listener: Driver\r\n ): Promise {\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a simple calculator.\r\n */\r\n @WebSocketRoute(\"simple\")\r\n public async simple(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig, // header\r\n ISimpleCalculator, // provider for remote client\r\n ICalcEventListener // provider from remote client\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: SimpleCalculator = new SimpleCalculator(header, listener);\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a scientific calculator.\r\n */\r\n @WebSocketRoute(\"scientific\")\r\n public async scientific(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IScientificCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a statistics calculator.\r\n */\r\n @WebSocketRoute(\"statistics\")\r\n public async statistics(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IStatisticsCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: IStatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n}\nimport { Module } from \"@nestjs/common\";\r\n\r\nimport { CalculateController } from \"./calculate.controller\";\r\n\r\n@Module({\r\n controllers: [CalculateController],\r\n})\r\nexport class CalculateModule {}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nFrom now on, you can define WebSocket API operations like above.Just import and attach the @WebSocketRoute() decorator function to the target controller methods.Note that, don't forget to define @WebSocketRoute.Acceptor() decorated parameter with WebSocketAcceptor type. It's because the websocket server must determine whether to WebSocketAcceptor.accept() the client's connection or WebSocketAcceptor.reject() it.Also, when declaring the WebSocketAcceptor type, ou have to specify three generic arguments; Header, Provider and Remote. Those generic arguments would be propagated to the automatically generated Software Development Kit for the client, so that the client developers will utilize the same generic types what you've defined (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.\nYou can find more detailed informations about @WebSocketRoute():\nNestia > Guide Documents > WebSocketRoute]","software-development-kit#Software Development Kit":"/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nnpx nestia sdk\nWhen you run npx nestia sdk command, SDK (Software Development Kit) library be generated.Above file is one of the SDK library corresponding to the CalculateController class we've seen in the previous NestJS Controller section. Client developers can utilize the automatically generated SDK functions to connect to the WebSocket server, and interact it type safely. Also, HTTP operation is compatible with the WebSocket operation.Let's see how client developer utilizes the SDK library in the next section.\nYou can find more detailed informations about SDK generator:\nNestia > Guide Documents > S/W Development Kit","client-application#Client Application":"import api from \"./api\";\r\nimport { ICalcEvent } from \"./api/interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\n\r\nexport const testCalculateSdk = async () => {\r\n //----\r\n // HTTP PROTOCOL\r\n //---\r\n // CALL HEALTH CHECK API\r\n console.log(\r\n await api.functional.calculate.health({\r\n host: \"http://127.0.0.1:37000\",\r\n })\r\n );\r\n\r\n //----\r\n // WEBSOCKET PROTOCOL\r\n //---\r\n // PROVIDER FOR WEBSOCKET SERVER\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n\r\n // DO CONNECT\r\n const { connector, driver } = await api.functional.calculate.composite(\r\n {\r\n host: \"ws://127.0.0.1:37000\",\r\n headers: {\r\n precision: 2,\r\n },\r\n },\r\n listener\r\n );\r\n\r\n // CALL FUNCTIONS OF REMOTE SERVER\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9) // returns 4.33\r\n );\r\n\r\n // TERMINATE\r\n await connector.close();\r\n console.log(stack);\r\n};\n/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestFactory] Starting Nest application...\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [InstanceLoader] CalculateModule dependencies initialized +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [RoutesResolver] CalculateController {/calculate}: +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestApplication] Nest application successfully started +2ms\r\n\r\nHealth check OK\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nDo import the SDK, and enjoy the type-safe and easy-to-use RPC.Looking at the above code, the client application is calling a function of the automatically generated SDK (Software Development Kit) library, so that connecting to the websocket server, and starting interaction through RPC (Remote Procedure Call) concept with Driver instance.Doesn't the \"SDK based development\" seems much easier and safer than the previous Natives Classes > WebSocketConnector case? This is the reason why I've recommended to combine with the NestJS when using websocket protocol based network system.For reference, return type of SDK function is a pair WebSocketConnector and Driver instances, but it would be actually returned only when the websocket server accepts your connection. Otherwise, the websocket server rejects your connection, an exception would be thrown.Also, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote websocket server, you can wait the remote server's closing signal through the WebSocketConnector.join() method.\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.nestjs\r\nnpm install\r\nnpm start"}},"/docs/remote-procedure-call":{"title":"Remote Procedure Call","data":{"outline#Outline":"With TGrid, you can call remote procedures of provided by remote system.If remote system provides a function, TGrid lets you call it as if it was a local function own. If remote system provides some functions that are capsuled in hierarchical structured objects, you still can call them as if they were your own. This is the concept of RPC (Remote Procedure Call) what TGrid is saying.By the way, there are many other RPC (Remote Procedure Call) frameworks or libraries in the world. However, TGrid is different from them. RPC of TGrid does not mean only calling and getting returned value from the remote system's procedure, but also ensuring type safety. With the type safety, you can actually feel like that the remote procedure is your own.","demonstration#Demonstration":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nimport { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nHere is the one of example programs that demonstrating the RPC (Remote Procedure Call) of TGrid.At first, looking at the \"Client Program\" tab, you can find out that the \"Client Program\" is calling the \"Server Program\"'s functions as if they were its own, through the Driver typed instance with await symbols.At next, change the tab to \"Server Program\", then you can find out that the \"Server Program\" is serving CompositeCalculator class to the \"Client Program\". Calling the functions of CompositeCalculator in the \"Server Program\" from the \"Client Program\" through the Driver typed instance, this is the RPC (Remote Procedure Call) of TGrid.\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.websocket\r\nnpm install\r\nnpm start","rpc-driver#RPC Driver":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nimport { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nLooking at the above ICompositeCalculator type from the \"Interfaces\" tab, none of the functions are actually asynchrounous. However, the \"Client Program\" is attaching await symbols. It's because every return types of ICompositeCalculator have changed to Promise types through the Driver type.As the Driver typed instance is not a \"Client Program\"'s own, but the \"Server Program\"'s own (CompositeCalculator), the function call must be passed through the asynchronous network communication. In such reason, the remote function calling cannot be synchronous, but asynchronous, and Driver type is casting them.\nTipDescription of Driver type in the Features > Components chatper.Driver is a proxy instance designed to call functions of the remote system. It has a generic argument Remote which means the type of remote system's Provider, and you can remotely call the functions of the Provider asynchronously through the Drive instance.When you call some function of remote Provider by the Driver instance, it hooks the function call expression, and delivers the function name and arguments (parameter values) to the remote system through the Communicator. If the remote system suceeded to reply the result of the function call, Communicator resolves the promise of the function call expression with the result, so that makes Driver working.Otherwise exception is thrown in the remote Provider function, Communicator deliveries the exception instance instead to the remote system, so that actual exception being thrown from the Driver instance.","restrictions#Restrictions":"TGrid has implemented the RPC (Remote Procedure Call) by communicating JSON message. Therefore, if parameters or return values of the remote provided functions are not compatible JSON, you can't use them.For example, JSON does not support bigint type of JavaScript. Therefore, if some of the remote provided functions are using bigint type on their parameters or return value, it would throw an exception.Also, as JSON does not contain class transformation spec, every parameters and return values must be primitive types. If you try to deliver the class instance as a parameter or return value, it would be downgraded to primitive instance in the remote system."}}} \ No newline at end of file +{"/docs/projects/chat":{"title":"Chat","data":{"preparing#Preparing":"Preparing the chatting application project documentation.Also, upgrading very old project to be modernized.https://github.com/samchon/tgrid.projects.chat"}},"/docs/projects/mutex":{"title":"Mutex","data":{"preparing#Preparing":"Preparing the mutex server project documentation.Also, upgrading very old project to be modernized.https://github.com/samchon/mutex"}},"/docs/projects/market":{"title":"Market","data":{"preparing#Preparing":"Preparing the grid market project documentation.Also, upgrading very old project to be modernized.https://github.com/samchon/tgrid.projects.market"}},"/docs/setup":{"title":"Setup","data":{"standalone#Standalone":"npm install tgrid\npnpm install tgrid\nyarn add tgrid\nIf you're planning to use TGrid standalone, without NestJS integration, just setup it.","nestjs#NestJS":"Nestia > Guide Documents > SetupOtherwise, you wanna use TGrid with NestJS integration, please refer to the guide documents of nestia.By the way, if you want to setup it right now without reading detailed documents, just run the below commands.\nnpx nestia setup\r\nnpm install tgrid\nnpx nestia setup --manager pnpm\r\npnpm install tgrid\nYarn beery is not supported.\nnpx nestia setup --manager yarn\r\nyarn add tgrid"}},"/":{"title":"Index","data":{"key-features#Key Features":""}},"/docs/examples/remote-function-call":{"title":"Remote Function Call","data":{"outline#Outline":"With TGrid, you can call remote system's functions as if they are local functions.Such remote procedure calling concept is called as RPC (Remote Procedure Call) in the development world, but it contains not only remote funtion call, but also contains Remote Object Call and Object Oriented Network. However, in here chapter, we will focus only on the remote function calls.Let's learn how to call remote functions with TGrid.\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.remote-function-call\r\nnpm install\r\nnpm start","client-program#Client Program":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalculator } from \"./ICalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const connector: WebSocketConnector =\r\n new WebSocketConnector(\r\n null, // header\r\n null, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.minus(7, 3), // returns 4\r\n await remote.multiply(3, 4), // returns 12\r\n await remote.divide(5, 2), // returns 2.5\r\n );\r\n\r\n await connector.close();\r\n};\r\n\r\ninterface ICalculator {\r\n plus(a: number, b: number): number\r\n minus(a: number, b: number): number\r\n multiply(a: number, b: number): number\r\n divide(a: number, b: number): number\r\n}\n$ npm start\r\n30 4 12 2.5\nHere is an example websocket client program, calling remote calculator of the websocket server's own.As you can see, the client program has written the remote function call statements on the remote instance of Driver type. Also, the Driver typed instance has been composed by the WebSocketConnector.getDriver() method. It's because Driver is a proxy instance hooking the function call expressions, so that delivers them to the remote system, and receives the return value from the remote system.This is the secret of how TGrid has implemented the RPC (Remote Procedure Call). Just call functions of remote Provider to the Driver typed instance with await symbol, as if the Provider instance was your own. Then, TGrid will perform the proper network communications for RPC instead of you.","server-program#Server Program":"import { WebSocketServer } from \"tgrid\";\r\n\r\nimport { Calculator } from \"./Calculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n null, // header\r\n Calculator, // provider for remote client\r\n null // provider from remote client\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n const provider: Calculator = new Calculator();\r\n await acceptor.accept(provider);\r\n });\r\n return server;\r\n};\r\n\r\nclass Calculator {\r\n public plus(x: number, y: number): number {\r\n return x + y;\r\n }\r\n public minus(x: number, y: number): number {\r\n return x - y;\r\n }\r\n public multiply(x: number, y: number): number {\r\n return x * y;\r\n }\r\n public divide(x: number, y: number): number {\r\n return x / y;\r\n }\r\n}\nimport { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalculator } from \"./ICalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const connector: WebSocketConnector =\r\n new WebSocketConnector(\r\n null, // header\r\n null, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.minus(7, 3), // returns 4\r\n await remote.multiply(3, 4), // returns 12\r\n await remote.divide(5, 2), // returns 2.5\r\n );\r\n\r\n await connector.close();\r\n};\r\n\r\ninterface ICalculator {\r\n plus(a: number, b: number): number\r\n minus(a: number, b: number): number\r\n multiply(a: number, b: number): number\r\n divide(a: number, b: number): number\r\n}\nHere is the websocket server program providing Calculator class to the client.Above \"Client Program\" is calling remote functions to the calculator through the remote instance of Driver typed. To make the client program works properly, \"Server Program\" must provide the actual instance implemented the ICalculator type. This \"Server Program\" is serving it providing the Calculator class instance in such reason.By the way, the provided Calculator does not have any asynchronous method, but \"Client Program\" is calling the remote functions with await symbol. It's because remote function calls are actually asynchrounous operations perform by the network communication, and Driver is a type changing every function's return type to be asynchronous (Promise) in such reason.This is the RPC (Remote Procedure Call) of TGrid.","next-chapter#Next Chapter":"In this chapter, we've learned only about one-way remote function calls. By the way, most of real-time network systems need two-way communication. Also, we have not utilized Header, the value directly delivered after the connection, at all.\nLearn from Examples > Remote Object Call chapter.\nimport { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const provider: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n provider, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};"}},"/docs/examples/nestjs-websocket":{"title":"Nestjs Websocket","data":{"outline#Outline":"If you develop websocket application, I recommend integrate TGrid with NestJS / Nestia.It's because you can manage WebSocket API endpoints much effectively and easily by NestJS controller patterns. Also, you can make your server to support both HTTP and WebSocket protocols at the same time. NestJS controllers are compatible with both HTTP and WebSocket operations.Furthermore, you can generate SDK (Software Development Kit) library for your client application through Nestia. With the automatically generated SDK, client developers no more need to write the WebSocket connection and RPC (Remote Procedure Call) codes manually, so that the client development becomes much easier and safer.\nReferences\nNestia > Guide Documents > Setup\nNestia > Guide Documents > WebSocketRoute\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.nestjs\r\nnpm install\r\nnpm start","server-program#Server Program":"","bootstrap#Bootstrap":"import { WebSocketAdaptor } from \"@nestia/core\";\r\nimport { INestApplication } from \"@nestjs/common\";\r\nimport { NestFactory } from \"@nestjs/core\";\r\n\r\nimport { CalculateModule } from \"./calculate.module\";\r\n\r\nexport const bootstrap = async (): Promise => {\r\n const app: INestApplication = await NestFactory.create(CalculateModule);\r\n await WebSocketAdaptor.upgrade(app);\r\n await app.listen(37_000, \"0.0.0.0\");\r\n return app;\r\n};\nTo integrate TGrid with NestJS, you have to upgrade the NestJS application like above.Just call the WebSocketAdaptor.upgrade(), then you can utilize TGrid in the NestJS server.","controller#Controller":"import { TypedRoute, WebSocketRoute } from \"@nestia/core\";\r\nimport { Controller } from \"@nestjs/common\";\r\nimport { Driver, WebSocketAcceptor } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./api/interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./api/interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./api/interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./api/interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./api/interfaces/IStatisticsCalculator\";\r\n\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\n@Controller(\"calculate\")\r\nexport class CalculateController {\r\n /**\r\n * Health check API (HTTP GET).\r\n */\r\n @TypedRoute.Get(\"health\")\r\n public health(): string {\r\n return \"Health check OK\";\r\n }\r\n\r\n /**\r\n * Prepare a composite calculator.\r\n */\r\n @WebSocketRoute(\"composite\")\r\n public async composite(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n ICompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n @WebSocketRoute.Header() header: ICalcConfig,\r\n @WebSocketRoute.Driver() listener: Driver\r\n ): Promise {\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a simple calculator.\r\n */\r\n @WebSocketRoute(\"simple\")\r\n public async simple(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig, // header\r\n ISimpleCalculator, // provider for remote client\r\n ICalcEventListener // provider from remote client\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: SimpleCalculator = new SimpleCalculator(header, listener);\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a scientific calculator.\r\n */\r\n @WebSocketRoute(\"scientific\")\r\n public async scientific(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IScientificCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a statistics calculator.\r\n */\r\n @WebSocketRoute(\"statistics\")\r\n public async statistics(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IStatisticsCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: IStatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n}\nimport { Module } from \"@nestjs/common\";\r\n\r\nimport { CalculateController } from \"./calculate.controller\";\r\n\r\n@Module({\r\n controllers: [CalculateController],\r\n})\r\nexport class CalculateModule {}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nAs you can see from the above code, CalculateController has many API operations, including both HTTP and WebSocket protocols. The CalculatorController.health() is an HTTP Get method operation, and the others are all WebSocket operations.When defining WebSocket operation, attach @WebSocketRoute() decorator to the target controller method with path specification. Also, the controller method must have the @WebSocketRoute.Acceptor() decorated parameter with WebSocketAcceptor type, because you have to determine whether to WebSocketAcceptor.accept() the client's connection or WebSocketAcceptor.reject() it.With such controller patterned WebSocket operation, you can manage WebSocket API endpoints much effectively and easily. Also, you can generate SDK (Software Development Kit) library for your client application through Nestia. Let's see how to generate SDK library, and how it would be looked like in the next section.","software-development-kit#Software Development Kit":"/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nnpx nestia sdk\nWhen you run npx nestia sdk command, SDK (Software Development Kit) library be generated.Above file is one of the SDK library corresponding to the CalculateController class we've seen in the previous NestJS Controller section. Client developers can utilize the automatically generated SDK functions to connect to the WebSocket server, and interact it type safely. Also, HTTP operation is compatible with the WebSocket operation.Let's see how client developer utilizes the SDK library in the next section.","client-program#Client Program":"import api from \"./api\";\r\nimport { ICalcEvent } from \"./api/interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\n\r\nexport const testCalculateSdk = async () => {\r\n //----\r\n // HTTP PROTOCOL\r\n //---\r\n // CALL HEALTH CHECK API\r\n console.log(\r\n await api.functional.calculate.health({\r\n host: \"http://127.0.0.1:37000\",\r\n })\r\n );\r\n\r\n //----\r\n // WEBSOCKET PROTOCOL\r\n //---\r\n // PROVIDER FOR WEBSOCKET SERVER\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n\r\n // DO CONNECT\r\n const { connector, driver } = await api.functional.calculate.composite(\r\n {\r\n host: \"ws://127.0.0.1:37000\",\r\n headers: {\r\n precision: 2,\r\n },\r\n },\r\n listener\r\n );\r\n\r\n // CALL FUNCTIONS OF REMOTE SERVER\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9) // returns 4.33\r\n );\r\n\r\n // TERMINATE\r\n await connector.close();\r\n console.log(stack);\r\n};\n/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestFactory] Starting Nest application...\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [InstanceLoader] CalculateModule dependencies initialized +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [RoutesResolver] CalculateController {/calculate}: +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestApplication] Nest application successfully started +2ms\r\n\r\nHealth check OK\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nDo import the SDK, and enjoy the type-safe and easy-to-use RPC (Remote Procedure Call).Looking at the above code, the client application is calling a function of the automatically generated SDK (Software Development Kit) library, so that connecting to the websocket server, and starting interaction through RPC (Remote Procedure Call) concept with Driver instance.Doesn't the \"SDK based development\" seems much easier and safer than native websocket classes case? This is the reason why I've recommended to combine with the NestJS when using websocket protocol based network system.This is the integration of TGrid with NestJS.","next-chapter#Next Chapter":"We've learned how to utilize TGrid with many examples.By the way, don't you want to know how to utilize TGrid in the real project?In the next chapter, we'll see how TGrid be utilized in the real world.\nLearn from Projects\nChat Application\nGrid Market\nMutex Server"}},"/docs/examples/object-oriented-network":{"title":"Object Oriented Network","data":{"outline#Outline":"Each remote system is an object.With TGrid, you can easily develop complicated network system, by considering each network system as an object, and interacting with each other through RPC (Remote Procedure Call). TGrid defines this concept as \"Object Oriented Network\".In this chapter, we'll remake the composite calculator system of Remote Object Call chapter again, but replace scientific and statistics calculators to remote system. Therefore, the composite calculator system will be consisted of three remote servers: \"composite server\", \"scientific server\" and \"statistics server\".Let's see how TGrd implements the \"Object Oriented Network\".\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.object-oriented-network\r\nnpm install\r\nnpm start","client-program#Client Program":"import { Driver, WorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\nexport const workerClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n \"process\",\r\n );\r\n await connector.connect(`${__dirname}/composite.${EXTENSION}`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]","server-programs#Server Programs":"import { Driver, WorkerConnector, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { IScientificCalculator } from \"./interfaces/IScientificCalculator\";\r\nimport { IStatisticsCalculator } from \"./interfaces/IStatisticsCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\n/// `CompositeCalculator` has two additional properties\r\n///\r\n/// - `scientific` from remote worker server\r\n/// - `statistics` from remote worker server\r\nclass CompositeCalculator extends SimpleCalculator {\r\n public readonly scientific: Driver;\r\n public readonly statistics: Driver;\r\n\r\n public constructor(props: {\r\n config: ICalcConfig;\r\n listener: Driver;\r\n scientific: Driver;\r\n statistics: Driver;\r\n }) {\r\n super(props.config, props.listener);\r\n this.scientific = props.scientific;\r\n this.statistics = props.statistics;\r\n }\r\n}\r\n\r\n/// connect to remote worker server\r\nconst connect = async (\r\n header: ICalcConfig,\r\n listener: Driver,\r\n file: string,\r\n): Promise> => {\r\n const connector: WorkerConnector =\r\n new WorkerConnector(header, listener, \"process\");\r\n await connector.connect(file);\r\n return connector.getDriver();\r\n};\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n const config: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n\r\n // constructor provider combining with remote worker-servers\r\n const provider: CompositeCalculator = new CompositeCalculator({\r\n config,\r\n listener,\r\n scientific: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/scientific.${EXTENSION}`,\r\n ),\r\n statistics: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/statistics.${EXTENSION}`,\r\n ),\r\n });\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n ScientificCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n StatisticsCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: StatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nCompose Provider with Driver of another remote system.Looking at the \"Composite Server\", it is providing CompositeCalculator to the \"Client Program\". By the way, the CompositeCalculator is different with before chapter Remote Object Call. Properties scientific and statistics are composed with Driver of another remote system.Therefore, if \"Client Program\" calls Driver.scientific.sqrt(2) function, it will be forwarded to the \"Scientific Server\", and \"Composite Server\" only intermediates the remote function call (network communication) between \"Client Program\" and \"Scientific Server\".This is the \"Object Oriented Network\" of TGrid.","next-chapter#Next Chapter":"At next chapter, we'll learn how to integrate TGrid with NestJS.\nLearn from Examples > NestJS Integration\nimport { TypedRoute, WebSocketRoute } from \"@nestia/core\";\r\nimport { Controller } from \"@nestjs/common\";\r\nimport { Driver, WebSocketAcceptor } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./api/interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./api/interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./api/interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./api/interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./api/interfaces/IStatisticsCalculator\";\r\n\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\n@Controller(\"calculate\")\r\nexport class CalculateController {\r\n /**\r\n * Health check API (HTTP GET).\r\n */\r\n @TypedRoute.Get(\"health\")\r\n public health(): string {\r\n return \"Health check OK\";\r\n }\r\n\r\n /**\r\n * Prepare a composite calculator.\r\n */\r\n @WebSocketRoute(\"composite\")\r\n public async composite(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n ICompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n @WebSocketRoute.Header() header: ICalcConfig,\r\n @WebSocketRoute.Driver() listener: Driver\r\n ): Promise {\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a simple calculator.\r\n */\r\n @WebSocketRoute(\"simple\")\r\n public async simple(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig, // header\r\n ISimpleCalculator, // provider for remote client\r\n ICalcEventListener // provider from remote client\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: SimpleCalculator = new SimpleCalculator(header, listener);\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a scientific calculator.\r\n */\r\n @WebSocketRoute(\"scientific\")\r\n public async scientific(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IScientificCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a statistics calculator.\r\n */\r\n @WebSocketRoute(\"statistics\")\r\n public async statistics(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IStatisticsCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: IStatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n}\nimport api from \"./api\";\r\nimport { ICalcEvent } from \"./api/interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\n\r\nexport const testCalculateSdk = async () => {\r\n //----\r\n // HTTP PROTOCOL\r\n //---\r\n // CALL HEALTH CHECK API\r\n console.log(\r\n await api.functional.calculate.health({\r\n host: \"http://127.0.0.1:37000\",\r\n })\r\n );\r\n\r\n //----\r\n // WEBSOCKET PROTOCOL\r\n //---\r\n // PROVIDER FOR WEBSOCKET SERVER\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n\r\n // DO CONNECT\r\n const { connector, driver } = await api.functional.calculate.composite(\r\n {\r\n host: \"ws://127.0.0.1:37000\",\r\n headers: {\r\n precision: 2,\r\n },\r\n },\r\n listener\r\n );\r\n\r\n // CALL FUNCTIONS OF REMOTE SERVER\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9) // returns 4.33\r\n );\r\n\r\n // TERMINATE\r\n await connector.close();\r\n console.log(stack);\r\n};\n/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}"}},"/docs/examples/remote-object-call":{"title":"Remote Object Call","data":{"outline#Outline":"With TGrid, you can call remote system's nested functions as if they are local functions.Such remote procedure calling concept is called as RPC (Remote Procedure Call) in the development world, but it contains not only remote function call, but also contains Object Oriented Network. However, in here chapter, we will focus only on the remote nested function calls.Let's learn how to call remote nested functions with TGrid.\nDemonstrationYou can run the example program on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.remote-object-call\r\nnpm install\r\nnpm start","client-program#Client Program":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nHere is an example websocket client program, calling remote calculator of the websocket server's own.As you can see, the client has constructed a WebSocketConnector instance with the Header and listener objects. The header object represents a Header component which be directly delivered to the remote system when connecting. The listener object is a Provider component provided for the remote websocket server. It means that, the \"Client Program\" configures the header value to precision: 2, and provides ICalcEventListener for the remote \"Server Program\".After that, you can find out the \"Client Program\" is calling the remote calculator's function of \"Server Program\" through Driver typed instance. In the remote function call statements, there is one thing important. It is Driver type supports nested object's funtion calls.This is the \"Remote Object Call\".","server-program#Server Program":"import { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n });\r\n return server;\r\n};\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends CalculatorBase\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nThe \"Server Program\" is providing CompositeCalculator class to the websocket client.By the way, when composing the CompositeCalculator class instance as a Provider, you can find out that it is delivering the Header and Driver typed instances to the construction parameter. By getting the Header value from the \"Client Program\", \"Server Program\" configures precision level of the calculator.Also, if you click the second Providers tab, you can find out that calculators are reporting their calculator operations to the \"Client Program\" through the Driver object. Therefore, whenever the calculator function be called, \"Server Program\" calls remote function of the \"Client Program\" for event reporting.Such two-way remote functions providing and header for initialization, this is the \"Remote Object Call\".","next-chapter#Next Chapter":"Until this chapter, we've learned only about simple structructured network systems. Complexity has only come to the Provider level, and the network systems were always monotonous. Only single type of server and client were existed.By the way, TGrid has said that it is useful for developing complicated network system like grid computing in the README and index page of guide documents. At the next chapter, we will learn about the complicated network system.\nLearn from Examples > Object Oriented Network.\nimport { Driver, WorkerConnector, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { IScientificCalculator } from \"./interfaces/IScientificCalculator\";\r\nimport { IStatisticsCalculator } from \"./interfaces/IStatisticsCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\n/// `CompositeCalculator` has two additional properties\r\n///\r\n/// - `scientific` from remote worker server\r\n/// - `statistics` from remote worker server\r\nclass CompositeCalculator extends SimpleCalculator {\r\n public readonly scientific: Driver;\r\n public readonly statistics: Driver;\r\n\r\n public constructor(props: {\r\n config: ICalcConfig;\r\n listener: Driver;\r\n scientific: Driver;\r\n statistics: Driver;\r\n }) {\r\n super(props.config, props.listener);\r\n this.scientific = props.scientific;\r\n this.statistics = props.statistics;\r\n }\r\n}\r\n\r\n/// connect to remote worker server\r\nconst connect = async (\r\n header: ICalcConfig,\r\n listener: Driver,\r\n file: string,\r\n): Promise> => {\r\n const connector: WorkerConnector =\r\n new WorkerConnector(header, listener, \"process\");\r\n await connector.connect(file);\r\n return connector.getDriver();\r\n};\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n const config: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n\r\n // constructor provider combining with remote worker-servers\r\n const provider: CompositeCalculator = new CompositeCalculator({\r\n config,\r\n listener,\r\n scientific: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/scientific.${EXTENSION}`,\r\n ),\r\n statistics: await connect>(\r\n config,\r\n listener,\r\n `${__dirname}/statistics.${EXTENSION}`,\r\n ),\r\n });\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver, WorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\nexport const workerClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n \"process\",\r\n );\r\n await connector.connect(`${__dirname}/composite.${EXTENSION}`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};"}},"/docs/features/components":{"title":"Components","data":{"outline#Outline":"This chapter describes key components of the TGrid only in the conceptual level.If you're not familar with theoretical stories, it's okay to skip to the next chapter Features > WebSocket Protocol.Even you want to see the example codes, step to the Learn from Examples > Remote Funtion Call chapter.Otherwise, let's study about the key components of the TGrid.\nCommunicator: network communication with remote system\nHeader: header value directly delivered after the connection\nProvider: object provided for remote system\nDriver: proxy instance for calling functions of the remote system's Provider","communicator#Communicator":"Communicates with a remote system.Communicator is a class taking full responsibility to network communication with remote system. You can register a Provider, an object would be provided to the remote system, to the Communicator. Also, Driver, which can access to the remote system's Provider, is created by this Communicator.For reference, actual Communicator is the top-level abstract class, and all the classes responsible for network communication in TGrid are inheriting from this Communicator class. Here is the list of every communicator classes in TGrid.\nProtocol\tClient\tServer\tWeb Socket\tWebSocketConnector\tWebSocketAcceptor\tDedicated Worker\tWorkerConnector\tWorkerServer\tShared Worker\tSharedWorkerConnector\tSharedWorkerAcceptor","header#Header":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nimport { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nimport { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nHeader value delivered after the connection.Header is a value, delivered from client to server directly, after the connection.Server can get the Header value through acceptor's header property.\nWebSocketAcceptor.header\nWorkerServer.getHeader()\nSharedWorkerSever.header","provider#Provider":"import { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nObject provided for remote system.Provider is an object provided for the remote system.The remote system can call the Provider's functions through Driver.","driver#Driver":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nDriver of RPC (Remote Procedure Call).Driver is a proxy instance designed to call functions of the remote system. It has a generic argument Remote which means the type of remote system's Provider, and you can remotely call the functions of the Provider asynchronously through the Drive instance.When you call some function of remote Provider by the Driver instance, it hooks the function call expression, and delivers the function name and arguments (parameter values) to the remote system through the Communicator. If the remote system suceeded to reply the result of the function call, Communicator resolves the promise of the function call expression with the result, so that makes Driver working.Otherwise exception is thrown in the remote Provider function, Communicator deliveries the exception instance instead to the remote system, so that actual exception being thrown from the Driver instance.\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.websocket\r\nnpm install\r\nnpm start"}},"/docs":{"title":"Index","data":{"":"TypeScript Grid Computing Framework.TypeScript RPC (Remote Procedure Call) framework for WebSocket and Worker protocols.\nWebSocket\nWorker\nSharedWorker\nNestJS\nAlso, extremely easy even when composing complicated network system like grid computing.\nimport { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"../interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]"}},"/docs/features/websocket":{"title":"Websocket","data":{"outline#Outline":"TGrid supports WebSocket protocol.With TGrid, you can easily develop WebSocket system under the RPC (Remote Procedure Call) concept.By the way, when you're developing WebSocket server natively only with TGrid, you have to construct and open the WebSocket server through WebSocketServer class. Also, you have to access to the WebSocket server with manual WebSocketConnector composition.Instead, if you develop the WebSocket server with NestJS, client can easily interact with the WebSocket server by SDK (Software Development Kit) library generated by Nestia. Also, you can make both http and websocket operations to the NestJS controllers, so that makes the server compatible on both protocols.Therefore, when you develop WebSocket server, I recommend to use NestJS with TGrid for the best development experience.","native-classes#Native Classes":"","websocketserver#WebSocketServer":"import { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nAvailable only in the NodeJS.\nWebSocketServer is a class which can open an websocket server. Clients connecting to the WebSocketServer would communicate with this websocket server through WebSocketAcceptor objects with RPC (Remote Procedure Call) concept.To open the websocket server, call the WebSocketServer.open() method with target port number, and your custom callback function which would be called whenever a WebSocketAcceptor has been newly created by a new client's connection.Also, when declaring WebSocketServer type, you have to specify three generic arguments; Header, Provider and Remote. Those generic arguments would be propagated to the WebSocketAcceptor, so that WebSocketAcceptor would have the same generic arguments, too.For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Server is providing one of below to the client\nSimpleCalculator\nStatisticsCalculator\nScientificCalculator\nRemote: Client is providing ICalcEventListener to the server","websocketacceptor#WebSocketAcceptor":"import { Driver, WebSocketAcceptor, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(\r\n 37_000,\r\n async (\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n >,\r\n ) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n },\r\n );\r\n return server;\r\n};\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nAvailable only in the NodeJS.\nThe WebSocketAcceptor is a communicator class interacting with the remote websocket client through (RPC)(Remote Procedure Call) concept, created by the WebSocketServer class whenever a remote client connects to the websocket server.When the closure function being called by the connection of a remote client, you can determine whether to accept the client's connection or not, reading the WebSocketAcceptor.header or WebSocketAcceptor.path properties. If you've decided to accept the connection, call the WebSocketAcceptor.accept() method with Provider instance. Otherwise, reject it through the WebSocketAcceptor.reject() method.After accepting the connection, don't forget to closing the connection after your business logic has been completed to clean up the resources. Otherwise the closing must be performed by the remote client, you can wait the remote client's closing signal by the WebSocketAcceptor.join() method.","websocketconnector#WebSocketConnector":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"../interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nAvailable in both Browser/NodeJS.\nWeb Socket Connector.The WebSocketConnector is a communicator class which connects to a websocket server and interacts with it through RPC (Remote Procedure Call) concept.You can connect to the websocket server using WebSocketConnector.connect() method. The interaction would be started if the server accepts your connection by calling the WebSocketAcceptor.accept() method. If the remote server rejects your connection through WebSocketAcceptor.reject() method, the exception would be thrown.After the connection, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote websocket server, you can wait the remote server's closing signal through the WebSocketConnector.join() method.Also, when declaring this WebSocketConnector type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target WebSocketServer and WebSocketAcceptor classes (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from client to server, and the other Remote means a provider from the remote server to client.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Client is providing ICalcEventListener to the server\nRemote: Server is providing ISimpleCalculator to the client\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.websocket\r\nnpm install\r\nnpm start","nestjs-integration#NestJS Integration":"If you develop websocket application, I recommend integrate TGrid with NestJS.It's because you can manage WebSocket API endpoints much effectively and easily by NestJS controller patterns. Also, you can make your server to support both HTTP and WebSocket protocols at the same time. NestJS controllers are compatible with both HTTP and WebSocket operations.In the client side, you also can take advantages of automatically generated SDK (Software Development Kit) library for the client developers. With the SDK, client developers no more need to write the WebSocket connection and RPC (Remote Procedure Call) codes manually, so that the client development becomes much easier and safer.","bootstrap#Bootstrap":"import { WebSocketAdaptor } from \"@nestia/core\";\r\nimport { INestApplication } from \"@nestjs/common\";\r\nimport { NestFactory } from \"@nestjs/core\";\r\n\r\nimport { CalculateModule } from \"./calculate.module\";\r\n\r\nexport const bootstrap = async (): Promise => {\r\n const app: INestApplication = await NestFactory.create(CalculateModule);\r\n await WebSocketAdaptor.upgrade(app);\r\n await app.listen(37_000, \"0.0.0.0\");\r\n return app;\r\n};\nTo utilize TGrid in the NestJS, upgrade the NestJS application like above.Just call the WebSocketAdaptor.upgrade() method, then you can utilize TGrid in the NestJS server.\nAbout detailed setup or more detailed informations, please refer below docs:\nNestia > Guide Documents > Setup\nNestia > Guide Documents > WebSocketRoute","nestjs-controller#NestJS Controller":"import { TypedRoute, WebSocketRoute } from \"@nestia/core\";\r\nimport { Controller } from \"@nestjs/common\";\r\nimport { Driver, WebSocketAcceptor } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./api/interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./api/interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./api/interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./api/interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./api/interfaces/IStatisticsCalculator\";\r\n\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\n@Controller(\"calculate\")\r\nexport class CalculateController {\r\n /**\r\n * Health check API (HTTP GET).\r\n */\r\n @TypedRoute.Get(\"health\")\r\n public health(): string {\r\n return \"Health check OK\";\r\n }\r\n\r\n /**\r\n * Prepare a composite calculator.\r\n */\r\n @WebSocketRoute(\"composite\")\r\n public async composite(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n ICompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n @WebSocketRoute.Header() header: ICalcConfig,\r\n @WebSocketRoute.Driver() listener: Driver\r\n ): Promise {\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a simple calculator.\r\n */\r\n @WebSocketRoute(\"simple\")\r\n public async simple(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig, // header\r\n ISimpleCalculator, // provider for remote client\r\n ICalcEventListener // provider from remote client\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: SimpleCalculator = new SimpleCalculator(header, listener);\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a scientific calculator.\r\n */\r\n @WebSocketRoute(\"scientific\")\r\n public async scientific(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IScientificCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: ScientificCalculator = new ScientificCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n\r\n /**\r\n * Prepare a statistics calculator.\r\n */\r\n @WebSocketRoute(\"statistics\")\r\n public async statistics(\r\n @WebSocketRoute.Acceptor()\r\n acceptor: WebSocketAcceptor<\r\n ICalcConfig,\r\n IStatisticsCalculator,\r\n ICalcEventListener\r\n >\r\n ): Promise {\r\n const header: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n const provider: IStatisticsCalculator = new StatisticsCalculator(\r\n header,\r\n listener\r\n );\r\n await acceptor.accept(provider);\r\n }\r\n}\nimport { Module } from \"@nestjs/common\";\r\n\r\nimport { CalculateController } from \"./calculate.controller\";\r\n\r\n@Module({\r\n controllers: [CalculateController],\r\n})\r\nexport class CalculateModule {}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nFrom now on, you can define WebSocket API operations like above.Just import and attach the @WebSocketRoute() decorator function to the target controller methods.Note that, don't forget to define @WebSocketRoute.Acceptor() decorated parameter with WebSocketAcceptor type. It's because the websocket server must determine whether to WebSocketAcceptor.accept() the client's connection or WebSocketAcceptor.reject() it.Also, when declaring the WebSocketAcceptor type, ou have to specify three generic arguments; Header, Provider and Remote. Those generic arguments would be propagated to the automatically generated Software Development Kit for the client, so that the client developers will utilize the same generic types what you've defined (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.\nYou can find more detailed informations about @WebSocketRoute():\nNestia > Guide Documents > WebSocketRoute]","software-development-kit#Software Development Kit":"/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nnpx nestia sdk\nWhen you run npx nestia sdk command, SDK (Software Development Kit) library be generated.Above file is one of the SDK library corresponding to the CalculateController class we've seen in the previous NestJS Controller section. Client developers can utilize the automatically generated SDK functions to connect to the WebSocket server, and interact it type safely. Also, HTTP operation is compatible with the WebSocket operation.Let's see how client developer utilizes the SDK library in the next section.\nYou can find more detailed informations about SDK generator:\nNestia > Guide Documents > S/W Development Kit","client-application#Client Application":"import api from \"./api\";\r\nimport { ICalcEvent } from \"./api/interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./api/interfaces/ICalcEventListener\";\r\n\r\nexport const testCalculateSdk = async () => {\r\n //----\r\n // HTTP PROTOCOL\r\n //---\r\n // CALL HEALTH CHECK API\r\n console.log(\r\n await api.functional.calculate.health({\r\n host: \"http://127.0.0.1:37000\",\r\n })\r\n );\r\n\r\n //----\r\n // WEBSOCKET PROTOCOL\r\n //---\r\n // PROVIDER FOR WEBSOCKET SERVER\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n\r\n // DO CONNECT\r\n const { connector, driver } = await api.functional.calculate.composite(\r\n {\r\n host: \"ws://127.0.0.1:37000\",\r\n headers: {\r\n precision: 2,\r\n },\r\n },\r\n listener\r\n );\r\n\r\n // CALL FUNCTIONS OF REMOTE SERVER\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9) // returns 4.33\r\n );\r\n\r\n // TERMINATE\r\n await connector.close();\r\n console.log(stack);\r\n};\n/**\r\n * @packageDocumentation\r\n * @module api.functional.calculate\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\n//================================================================\r\nimport type { IConnection, Primitive } from \"@nestia/fetcher\";\r\nimport { PlainFetcher } from \"@nestia/fetcher/lib/PlainFetcher\";\r\nimport { WebSocketConnector } from \"tgrid\";\r\nimport type { Driver } from \"tgrid\";\r\n\r\nimport type { ICalcConfig } from \"../../interfaces/ICalcConfig\";\r\nimport type { ICalcEventListener } from \"../../interfaces/ICalcEventListener\";\r\nimport type { ICompositeCalculator } from \"../../interfaces/ICompositeCalculator\";\r\nimport type { IScientificCalculator } from \"../../interfaces/IScientificCalculator\";\r\nimport type { ISimpleCalculator } from \"../../interfaces/ISimpleCalculator\";\r\nimport type { IStatisticsCalculator } from \"../../interfaces/IStatisticsCalculator\";\r\n\r\n/**\r\n * Health check API (HTTP GET).\r\n *\r\n * @controller CalculateController.health\r\n * @path GET /calculate/health\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function health(connection: IConnection): Promise {\r\n return PlainFetcher.fetch(connection, {\r\n ...health.METADATA,\r\n path: health.path(),\r\n });\r\n}\r\nexport namespace health {\r\n export type Output = Primitive;\r\n\r\n export const METADATA = {\r\n method: \"GET\",\r\n path: \"/calculate/health\",\r\n request: null,\r\n response: {\r\n type: \"application/json\",\r\n encrypted: false,\r\n },\r\n status: null,\r\n } as const;\r\n\r\n export const path = () => \"/calculate/health\";\r\n}\r\n\r\n/**\r\n * Prepare a composite calculator.\r\n *\r\n * @controller CalculateController.composite\r\n * @path /calculate/composite\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function composite(\r\n connection: IConnection,\r\n provider: composite.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n composite.Header,\r\n composite.Provider,\r\n composite.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${composite.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace composite {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ICompositeCalculator;\r\n\r\n export const path = () => \"/calculate/composite\";\r\n}\r\n\r\n/**\r\n * Prepare a simple calculator.\r\n *\r\n * @controller CalculateController.simple\r\n * @path /calculate/simple\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function simple(\r\n connection: IConnection,\r\n provider: simple.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n simple.Header,\r\n simple.Provider,\r\n simple.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${simple.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace simple {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = ISimpleCalculator;\r\n\r\n export const path = () => \"/calculate/simple\";\r\n}\r\n\r\n/**\r\n * Prepare a scientific calculator.\r\n *\r\n * @controller CalculateController.scientific\r\n * @path /calculate/scientific\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function scientific(\r\n connection: IConnection,\r\n provider: scientific.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n scientific.Header,\r\n scientific.Provider,\r\n scientific.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${scientific.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace scientific {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IScientificCalculator;\r\n\r\n export const path = () => \"/calculate/scientific\";\r\n}\r\n\r\n/**\r\n * Prepare a statistics calculator.\r\n *\r\n * @controller CalculateController.statistics\r\n * @path /calculate/statistics\r\n * @nestia Generated by Nestia - https://github.com/samchon/nestia\r\n */\r\nexport async function statistics(\r\n connection: IConnection,\r\n provider: statistics.Provider,\r\n): Promise {\r\n const connector: WebSocketConnector<\r\n statistics.Header,\r\n statistics.Provider,\r\n statistics.Listener\r\n > = new WebSocketConnector(connection.headers ?? ({} as any), provider);\r\n await connector.connect(\r\n `${connection.host.endsWith(\"/\") ? connection.host.substring(0, connection.host.length - 1) : connection.host}${statistics.path()}`,\r\n );\r\n const driver: Driver = connector.getDriver();\r\n return {\r\n connector,\r\n driver,\r\n };\r\n}\r\nexport namespace statistics {\r\n export type Output = {\r\n connector: WebSocketConnector;\r\n driver: Driver;\r\n };\r\n export type Header = ICalcConfig;\r\n export type Provider = ICalcEventListener;\r\n export type Listener = IStatisticsCalculator;\r\n\r\n export const path = () => \"/calculate/statistics\";\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestFactory] Starting Nest application...\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [InstanceLoader] CalculateModule dependencies initialized +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [RoutesResolver] CalculateController {/calculate}: +5ms\r\n[Nest] 4328 - 05/15/2024, 3:19:50 AM LOG [NestApplication] Nest application successfully started +2ms\r\n\r\nHealth check OK\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nDo import the SDK, and enjoy the type-safe and easy-to-use RPC.Looking at the above code, the client application is calling a function of the automatically generated SDK (Software Development Kit) library, so that connecting to the websocket server, and starting interaction through RPC (Remote Procedure Call) concept with Driver instance.Doesn't the \"SDK based development\" seems much easier and safer than the previous Natives Classes > WebSocketConnector case? This is the reason why I've recommended to combine with the NestJS when using websocket protocol based network system.For reference, return type of SDK function is a pair WebSocketConnector and Driver instances, but it would be actually returned only when the websocket server accepts your connection. Otherwise, the websocket server rejects your connection, an exception would be thrown.Also, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote websocket server, you can wait the remote server's closing signal through the WebSocketConnector.join() method.\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.nestjs\r\nnpm install\r\nnpm start"}},"/docs/features/worker":{"title":"Worker","data":{"outline#Outline":"TGrid supports Worker/SharedWorker protocols.With TGrid, you can easily develop Worker programs under the RPC (Remote Procedure Call) concept.TGrid considers Worker as a 1: 1 dedicated server, and SharedWorker as a 1: N multi-client acceptable server running on the local. Therefore, the interfaces of Worker and SharedWorker in the TGrid are similar with WebSocket components. In such reason, if you're developing a complicate WebSocket system, you can simulate it in the local environment by using Worker/SharedWorker components.","worker#Worker":"Available in both Browser/NodeJS.\nYou can utilize RPC (Remote Procedure Call) even in the Worker.","workerconnector#WorkerConnector":"import { Driver, WorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst EXTENSION = __filename.endsWith(\".ts\") ? \"ts\" : \"js\";\r\n\r\nexport const workerClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n \"process\",\r\n );\r\n await connector.connect(`${__dirname}/server.${EXTENSION}`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nWorker Connector.The WorkerConnetor is a communicator class, which creates an Worker instance, and interacts with it through RPC (Remote Procedure Call). In other words, WorkerConnector considers the Worker instance as a remote server accepting only one client; WorkerServer.You can create the Worker instance and communicate with it by WorkerConnector.connect() or WorkerConnector.compile() method. The WorkerConnector.connect() method just opens an existing JS (or TS) file, and the WorkerConnector.compile() method writes a temporary JS (TS) file and connects to it. Anyway, the Worker instanced program must open the WorkerServer.By the way, don't forget closing the worker to clean up the resources. If the closing be performed by WorkerServer, you can wait the worker server closing through the WorkerConnector.wait() method.Also, when declaring this WorkerConnector type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target WorkerServer class (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from client to server, and the other Remote means a provider from the remote server to client.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Client is providing ICalcEventListener to the server\nRemote: Server is providing ISimpleCalculator to the client\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.worker\r\nnpm install\r\nnpm start","workerserver#WorkerServer":"import { Driver, WorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n const server: WorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new WorkerServer();\r\n\r\n const header: ICalcConfig = await server.getHeader();\r\n const listener: Driver = server.getDriver();\r\n const provider: CompositeCalculator = new CompositeCalculator(\r\n header,\r\n listener,\r\n );\r\n await server.open(provider);\r\n};\r\nmain().catch((exp) => {\r\n console.error(exp);\r\n process.exit(-1);\r\n});\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nWorker Server.The WorkerServer is a class representing a Worker server which communicate with client (WorkerConnector), through the RPC (Remote Procedure Call).Unlike other servers, WorkerServer can accept only one client (WorkerConnector), because the Worker is dependent on its parent instance (web page, node or parent worker). Thus, WorkerServer does not have any acceptor and communicates with client (its parent) directly.To start communication with the client, call the WorkerServer.open() method with Provider instance. After your business, don't forget closing this Worker instance. If the termination is performed by the WorkerConnector, you can wait the closing signal through the WorkerServer.join() method.Also, when declaring this WorkerServer type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target WorkerConnector class (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the client to server.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Server is providing CompositeCalculator to the client\nRemote: Client is providing ICalcEventListener to the server","shared-worker#Shared Worker":"Available only in the Web Browser.\nIn the Web Browser, you also can perform RPC (Remote Procedure Call) in the SharedWorker.Also, as SharedWorker can accept multiple clients, TGrid considers it as a local server running on the web browser, and its interfaces are similar with WebSocket components.","sharedworkerserver#SharedWorkerServer":"import { Driver, SharedWorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n let pool: number = 0;\r\n const server: SharedWorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new SharedWorkerServer();\r\n await server.open(async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT THE CONNECTION\r\n if (pool >= 8) {\r\n await acceptor.reject(\"Too much connections.\");\r\n } else {\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n ++pool;\r\n await acceptor.join();\r\n --pool;\r\n }\r\n });\r\n};\r\nmain().catch(console.error);\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nShared Worker Server.The SharedWorkerServer is a class representing a server in SharedWorker environment. Clients connecting to the SharedWorkerServer would communicate with this server through SharedWorkerAcceptor instaces using RPC (Remote Procedure Call) concept.To open the server, call the SharedWorkerServer.open() method with your callback function which would be called whenever a SharedWorkerAcceptor has been newly created by a new client's connection.Also, when declaring this SharedWorkerServer type, you have to define three generic arguments; Header, Provider and Remote. Those generic arguments would be propagated to the SharedWorkerAcceptor, so that SharedWorkerAcceptor would have the same generic arguments, too.For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Server is providing CompositeCalculator to the client\nRemote: Client is providing ICalcEventListener to the server","sharedworkeracceptor#SharedWorkerAcceptor":"import { Driver, SharedWorkerAcceptor, SharedWorkerServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\n\r\nconst main = async () => {\r\n let pool: number = 0;\r\n const server: SharedWorkerServer<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n > = new SharedWorkerServer();\r\n await server.open(\r\n async (\r\n acceptor: SharedWorkerAcceptor<\r\n ICalcConfig,\r\n CompositeCalculator,\r\n ICalcEventListener\r\n >,\r\n ) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT THE CONNECTION\r\n if (pool >= 8) {\r\n await acceptor.reject(\"Too much connections.\");\r\n } else {\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n ++pool;\r\n await acceptor.join();\r\n --pool;\r\n }\r\n },\r\n );\r\n};\r\nmain().catch(console.error);\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nShared Worker Acceptor.The SharedWorkerAcceptor is a communicator class interacting with the SharedWorkerConnector through RFC (Remote Function Call), created by the SharedWorkerServer class whenever a client connects to the SharedWorker instance.When a remote client connects to the SharedWorkerServer, so that a new SharedworkerAcceptor instance being created, you can determine whether to accept the client's connection or not, reading the SharedWorkerAcceptor.header property. If you've decided to accept the connection, call the SharedWorkerAcceptor.accept() method with Provider instance. Otherwise, reject it thorugh the SharedWorkerAcceptor.reject() method.After accepting the connection, don't forget to closing the connection after your business has been completed to clean up the resources. Otherwise the closing must be performed by the remote client, you can wait the remote client's closing signal by the SharedWorkerAcceptor.join() method.Also, when declaring this SharedworkerAcceptor type, you have to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the SharedWorkerServer class.For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from server to client, and the other Remote means a provider from the remote client to server.","sharedworkerconnector#SharedWorkerConnector":"import { Driver, SharedWorkerConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nconst main = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: SharedWorkerConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new SharedWorkerConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(`./server.js`);\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await remote.plus(10, 20), // returns 30\r\n await remote.multiplies(3, 4), // returns 12\r\n await remote.divides(5, 3), // returns 1.67\r\n await remote.scientific.sqrt(2), // returns 1.41\r\n await remote.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n for (const evt of stack) console.log(JSON.stringify(evt));\r\n};\r\nmain().catch(console.error);\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n30 12 1.67 1.41 4.33\r\n{\"type\":\"plus\",\"input\":[10,20],\"output\":30}\r\n{\"type\":\"multiplies\",\"input\":[3,4],\"output\":12}\r\n{\"type\":\"divides\",\"input\":[5,3],\"output\":1.67}\r\n{\"type\":\"sqrt\",\"input\":[2],\"output\":1.41}\r\n{\"type\":\"mean\",\"input\":[1,3,9],\"output\":4.33}\nShared Worker Connector.The SharedWorkerConnector is a communicator class which connects to an SharedWorker instance, and interacts with it through RFC (Remote Function Call) concept.You can connect to the SharedWorkerServer using SharedWorkerConnector.connect() method. The interaction would be started if the server accepts your connection by calling the SharedWorkerAcceptor.accept() method. If the remote server rejects your connection through SharedWorkerAcceptor.reject() method, the exception would be thrown.After the connection, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote shared worker server, you can wait the remote server's closing signal through the SharedWorkerConnector.join() method.Also, when declaring this SharedWorkerConnector type, you've to define three generic arguments; Header, Provider and Remote. Those generic arguments must be same with the ones defined in the target SharedWorkerServer and SharedWorkerAcceptor classes (Provider and Remote must be reversed).For reference, the first Header type repersents an initial data from the remote client after the connection. I recommend utilize it as an activation tool for security enhancement. The second generic argument Provider represents a provider from client to server, and the other Remote means a provider from the remote server to client.\nAbove example case:\nHeader: ICalcConfig type\nProvider: Client is providing ICalcEventListener to the server\nRemote: Server is providing ISimpleCalculator to the client\nDemonstrationYou can run it on your local machine.\ngit clone https://github.com/samchon/tgrid.example.shared-worker\r\nnpm install\r\nnpm run build\r\nnpm start"}},"/docs/remote-procedure-call":{"title":"Remote Procedure Call","data":{"outline#Outline":"With TGrid, you can call remote procedures of provided by remote system.If remote system provides a function, TGrid lets you call it as if it was a local function own. If remote system provides some functions that are capsuled in hierarchical structured objects, you still can call them as if they were your own. This is the concept of RPC (Remote Procedure Call) what TGrid is saying.By the way, there are many other RPC (Remote Procedure Call) frameworks or libraries in the world. However, TGrid is different from them. RPC of TGrid does not mean only calling and getting returned value from the remote system's procedure, but also ensuring type safety. With the type safety, you can actually feel like that the remote procedure is your own.","demonstration#Demonstration":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nimport { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"./interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"./interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"./interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\n$ npm start\r\n30 12 1.67 1.41 4.33\r\n[\r\n { type: 'plus', input: [ 10, 20 ], output: 30 },\r\n { type: 'multiplies', input: [ 3, 4 ], output: 12 },\r\n { type: 'divides', input: [ 5, 3 ], output: 1.67 },\r\n { type: 'sqrt', input: [ 2 ], output: 1.41 },\r\n { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 }\r\n]\nHere is the one of example programs that demonstrating the RPC (Remote Procedure Call) of TGrid.At first, looking at the \"Client Program\" tab, you can find out that the \"Client Program\" is calling the \"Server Program\"'s functions as if they were its own, through the Driver typed instance with await symbols.At next, change the tab to \"Server Program\", then you can find out that the \"Server Program\" is serving CompositeCalculator class to the \"Client Program\". Calling the functions of CompositeCalculator in the \"Server Program\" from the \"Client Program\" through the Driver typed instance, this is the RPC (Remote Procedure Call) of TGrid.\nDemonstrationYou can run it on Playground Website, or local machine.\ngit clone https://github.com/samchon/tgrid.example.websocket\r\nnpm install\r\nnpm start","rpc-driver#RPC Driver":"import { Driver, WebSocketConnector } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEvent } from \"./interfaces/ICalcEvent\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"./interfaces/ICompositeCalculator\";\r\n\r\nexport const webSocketClientMain = async () => {\r\n const stack: ICalcEvent[] = [];\r\n const listener: ICalcEventListener = {\r\n on: (evt: ICalcEvent) => stack.push(evt),\r\n };\r\n const connector: WebSocketConnector<\r\n ICalcConfig,\r\n ICalcEventListener,\r\n ICompositeCalculator\r\n > = new WebSocketConnector(\r\n { precision: 2 }, // header\r\n listener, // provider for remote server\r\n );\r\n await connector.connect(\"ws://127.0.0.1:37000/composite\");\r\n\r\n const remote: Driver = connector.getDriver();\r\n console.log(\r\n await driver.plus(10, 20), // returns 30\r\n await driver.multiplies(3, 4), // returns 12\r\n await driver.divides(5, 3), // returns 1.67\r\n await driver.scientific.sqrt(2), // returns 1.41\r\n await driver.statistics.mean(1, 3, 9), // returns 4.33\r\n );\r\n\r\n await connector.close();\r\n console.log(stack);\r\n};\nimport { Driver, WebSocketServer } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"./interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"./interfaces/ICalcEventListener\";\r\nimport { CompositeCalculator } from \"./providers/CompositeCalculator\";\r\nimport { ScientificCalculator } from \"./providers/ScientificCalculator\";\r\nimport { SimpleCalculator } from \"./providers/SimpleCalculator\";\r\nimport { StatisticsCalculator } from \"./providers/StatisticsCalculator\";\r\n\r\nexport const webSocketServerMain = async () => {\r\n const server: WebSocketServer<\r\n ICalcConfig,\r\n | CompositeCalculator\r\n | SimpleCalculator\r\n | StatisticsCalculator\r\n | ScientificCalculator,\r\n ICalcEventListener\r\n > = new WebSocketServer();\r\n await server.open(37_000, async (acceptor) => {\r\n // LIST UP PROPERTIES\r\n const config: ICalcConfig = acceptor.header;\r\n const listener: Driver = acceptor.getDriver();\r\n\r\n // ACCEPT OR REJECT\r\n if (acceptor.path === \"/composite\")\r\n await acceptor.accept(new CompositeCalculator(config, listener));\r\n else if (acceptor.path === \"/simple\")\r\n await acceptor.accept(new SimpleCalculator(config, listener));\r\n else if (acceptor.path === \"/statistics\")\r\n await acceptor.accept(new StatisticsCalculator(config, listener));\r\n else if (acceptor.path === \"/scientific\")\r\n await acceptor.accept(new ScientificCalculator(config, listener));\r\n else await acceptor.reject(1002, `WebSocket API endpoint not found.`);\r\n });\r\n return server;\r\n};\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nimport { Driver } from \"tgrid\";\r\n\r\nimport { ICalcConfig } from \"../interfaces/ICalcConfig\";\r\nimport { ICalcEventListener } from \"../interfaces/ICalcEventListener\";\r\nimport { ICompositeCalculator } from \"../interfaces/ICompositeCalculator\";\r\nimport { IScientificCalculator } from \"../interfaces/IScientificCalculator\";\r\nimport { ISimpleCalculator } from \"../interfaces/ISimpleCalculator\";\r\nimport { IStatisticsCalculator } from \"../interfaces/IStatisticsCalculator\";\r\n\r\nexport abstract class CalculatorBase {\r\n public constructor(\r\n private readonly config: ICalcConfig,\r\n private readonly listener: Driver,\r\n ) {}\r\n\r\n protected compute(type: string, input: number[], output: number): number {\r\n const pow: number = Math.pow(10, this.config.precision);\r\n output = Math.round(output * pow) / pow;\r\n this.listener.on({ type, input, output }).catch(() => {});\r\n return output;\r\n }\r\n}\r\n\r\nexport class SimpleCalculator\r\n extends CalculatorBase\r\n implements ISimpleCalculator\r\n{\r\n public plus(x: number, y: number): number {\r\n return this.compute(\"plus\", [x, y], x + y);\r\n }\r\n public minus(x: number, y: number): number {\r\n return this.compute(\"minus\", [x, y], x - y);\r\n }\r\n public multiplies(x: number, y: number): number {\r\n return this.compute(\"multiplies\", [x, y], x * y);\r\n }\r\n public divides(x: number, y: number): number {\r\n return this.compute(\"divides\", [x, y], x / y);\r\n }\r\n}\r\n\r\nexport class ScientificCalculator\r\n extends CalculatorBase\r\n implements IScientificCalculator\r\n{\r\n public pow(x: number, y: number): number {\r\n return this.compute(\"pow\", [x, y], Math.pow(x, y));\r\n }\r\n public sqrt(x: number): number {\r\n return this.compute(\"sqrt\", [x], Math.sqrt(x));\r\n }\r\n public log(x: number, base: number): number {\r\n return this.compute(\"log\", [x, base], Math.log(x) / Math.log(base));\r\n }\r\n}\r\n\r\nexport class StatisticsCalculator\r\n extends CalculatorBase\r\n implements IStatisticsCalculator\r\n{\r\n public mean(...values: number[]): number {\r\n const sum: number = values.reduce((x, y) => x + y);\r\n return this.compute(\"mean\", values, sum / values.length);\r\n }\r\n public stdev(...values: number[]): number {\r\n const mean: number = values.reduce((x, y) => x + y) / values.length;\r\n const sum: number = values.reduce((x, y) => x + Math.pow(y - mean, 2));\r\n return this.compute(\"stdev\", values, Math.sqrt(sum / values.length));\r\n }\r\n}\r\n\r\nexport class CompositeCalculator\r\n extends SimpleCalculator\r\n implements ICompositeCalculator\r\n{\r\n public readonly scientific: ScientificCalculator;\r\n public readonly statistics: StatisticsCalculator;\r\n\r\n public constructor(\r\n config: ICalcConfig,\r\n listener: Driver,\r\n ) {\r\n super(config, listener);\r\n this.scientific = new ScientificCalculator(config, listener);\r\n this.statistics = new StatisticsCalculator(config, listener);\r\n }\r\n}\nexport interface ICalcConfig {\r\n precision: number;\r\n}\r\nexport interface ICalcEvent {\r\n type: string;\r\n input: number[];\r\n output: number;\r\n}\r\nexport interface ICalcEventListener {\r\n on(event: ICalcEvent): void;\r\n}\r\n\r\nexport interface ICompositeCalculator extends ISimpleCalculator {\r\n scientific: IScientificCalculator;\r\n statistics: IStatisticsCalculator;\r\n}\r\nexport interface ISimpleCalculator {\r\n plus(x: number, y: number): number;\r\n minus(x: number, y: number): number;\r\n multiplies(x: number, y: number): number;\r\n divides(x: number, y: number): number;\r\n}\r\nexport interface IScientificCalculator {\r\n pow(x: number, y: number): number;\r\n sqrt(x: number): number;\r\n log(x: number, base: number): number;\r\n}\r\nexport interface IStatisticsCalculator {\r\n mean(...values: number[]): number;\r\n stdev(...values: number[]): number;\r\n}\nLooking at the above ICompositeCalculator type from the \"Interfaces\" tab, none of the functions are actually asynchrounous. However, the \"Client Program\" is attaching await symbols. It's because every return types of ICompositeCalculator have changed to Promise types through the Driver type.As the Driver typed instance is not a \"Client Program\"'s own, but the \"Server Program\"'s own (CompositeCalculator), the function call must be passed through the asynchronous network communication. In such reason, the remote function calling cannot be synchronous, but asynchronous, and Driver type is casting them.\nTipDescription of Driver type in the Features > Components chatper.Driver is a proxy instance designed to call functions of the remote system. It has a generic argument Remote which means the type of remote system's Provider, and you can remotely call the functions of the Provider asynchronously through the Drive instance.When you call some function of remote Provider by the Driver instance, it hooks the function call expression, and delivers the function name and arguments (parameter values) to the remote system through the Communicator. If the remote system suceeded to reply the result of the function call, Communicator resolves the promise of the function call expression with the result, so that makes Driver working.Otherwise exception is thrown in the remote Provider function, Communicator deliveries the exception instance instead to the remote system, so that actual exception being thrown from the Driver instance.","restrictions#Restrictions":"TGrid has implemented the RPC (Remote Procedure Call) by communicating JSON message. Therefore, if parameters or return values of the remote provided functions are not compatible JSON, you can't use them.For example, JSON does not support bigint type of JavaScript. Therefore, if some of the remote provided functions are using bigint type on their parameters or return value, it would throw an exception.Also, as JSON does not contain class transformation spec, every parameters and return values must be primitive types. If you try to deliver the class instance as a parameter or return value, it would be downgraded to primitive instance in the remote system."}}} \ No newline at end of file diff --git a/website/out/api/classes/Communicator.html b/website/out/api/classes/Communicator.html index 9bff54e..568d2ed 100644 --- a/website/out/api/classes/Communicator.html +++ b/website/out/api/classes/Communicator.html @@ -12,7 +12,7 @@

Author

Jeongho Nam - https://github.com/samchon

Type Parameters

  • Provider extends object | null | undefined

    Type of features provided for remote system.

  • Remote extends object | null

    Type of features supported by remote system, used for getDriver function.

    -

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

  • Destory the communicator.

    +

Returns Communicator<Provider, Remote>

Methods

  • Destory the communicator.

    A destory function must be called when the network communication has been closed. It would destroy all function calls in the remote system (by Driver<Controller>), which are not returned yet.

    The error instance would be thrown to those function calls. If the disconnection is abnormal, then write the detailed reason why into the error instance.

    Parameters

    • Optional error: Error

      An error instance to be thrown to the unreturned functions.

      -

    Returns Promise<void>

Returns Promise<void>

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -43,30 +43,30 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Get current Provider.

    Get an object providing features (functions & objects) for remote system. The remote system would call the features (Provider) by using its Driver<Controller>.

    Returns Provider

    Current Provider object

    -
  • A predicator inspects whether the network communication is on ready.

    Parameters

    • method: string

      The method name for tracing.

      -

    Returns null | Error

  • Join connection.

    +

Returns null | Error

  • Join connection.

    Wait until the connection to be closed.

    -

    Returns Promise<void>

  • Join connection or timeout.

    +

    Returns Promise<void>

  • Join connection or timeout.

    Wait until the connection to be clsoed until timeout.

    Parameters

    • ms: number

      The maximum milliseconds for joining.

    Returns Promise<boolean>

    Whether awaken by disconnection or timeout.

    -
  • Join connection or time expiration.

    +
  • Join connection or time expiration.

    Wait until the connection to be closed until time expiration.

    Parameters

    • at: Date

      The maximum time point to join.

    Returns Promise<boolean>

    Whether awaken by disconnection or time expiration.

    -
  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • A function sending data to the remote system.

    +

Returns void

  • Set Provider

    +

Returns Promise<void>

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/classes/SharedWorkerAcceptor-1.html b/website/out/api/classes/SharedWorkerAcceptor-1.html index f3b227a..9baee6b 100644 --- a/website/out/api/classes/SharedWorkerAcceptor-1.html +++ b/website/out/api/classes/SharedWorkerAcceptor-1.html @@ -28,7 +28,7 @@

Type Parameters

  • Header

    Type of the header containing initial data.

  • Provider extends object | null

    Type of features provided for the remote client.

  • Remote extends object | null

    Type of features provided by remote client.

    -

Hierarchy

Implements

  • IWorkerSystem

Accessors

Hierarchy

Implements

  • IWorkerSystem

Accessors

Methods

accept close @@ -40,7 +40,7 @@ replyData setProvider

Accessors

Methods

Methods

  • Destory the communicator.

    A destory function must be called when the network communication has been closed. It would destroy all function calls in the remote system (by Driver<Controller>), which are not returned yet.

    The error instance would be thrown to those function calls. If the disconnection is abnormal, then write the detailed reason why into the error instance.

    Parameters

    • Optional error: Error

      An error instance to be thrown to the unreturned functions.

      -

    Returns Promise<void>

Returns Promise<void>

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -71,29 +71,29 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Get current Provider.

    Get an object providing features (functions & objects) for remote system. The remote system would call the features (Provider) by using its Driver<Controller>.

    Returns undefined | Provider

    Current Provider object

    -
  • Join connection.

    Wait until the connection to be closed.

    -

    Returns Promise<void>

  • Join connection or timeout.

    +

    Returns Promise<void>

  • Join connection or timeout.

    Wait until the connection to be clsoed until timeout.

    Parameters

    • ms: number

      The maximum milliseconds for joining.

    Returns Promise<boolean>

    Whether awaken by disconnection or timeout.

    -
  • Join connection or time expiration.

    +
  • Join connection or time expiration.

    Wait until the connection to be closed until time expiration.

    Parameters

    • at: Date

      The maximum time point to join.

    Returns Promise<boolean>

    Whether awaken by disconnection or time expiration.

    -
  • Reject connection.

    Reject without acceptance, any interaction. The connection would be closed immediately.

    Parameters

    • reason: string = "Rejected by server"

      Detailed reason of the rejection. Default is "Rejected by server".

      -

    Returns Promise<void>

  • Data Reply Function.

    +

Returns Promise<void>

  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • Set Provider

    +

Returns void

  • Set Provider

    Parameters

    • obj: undefined | Provider

      An object would be provided for remote system.

      -

    Returns void

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/classes/SharedWorkerConnector-1.html b/website/out/api/classes/SharedWorkerConnector-1.html index d71fdcc..ee40dae 100644 --- a/website/out/api/classes/SharedWorkerConnector-1.html +++ b/website/out/api/classes/SharedWorkerConnector-1.html @@ -26,7 +26,7 @@

Type Parameters

  • Header

    Type of the header containing initial data.

  • Provider extends object | null

    Type of features provided for the remote server.

  • Remote extends object | null

    Type of features supported by remote server.

    -

Hierarchy

Implements

  • IWorkerSystem

Constructors

Hierarchy

Implements

  • IWorkerSystem

Constructors

Accessors

Methods

close @@ -40,8 +40,8 @@

Constructors

Accessors

Returns SharedWorkerConnector<Header, Provider, Remote>

Accessors

Methods

Methods

  • Connect to remote server.

    The connect() method tries to connect an SharedWorker instance. If the SharedWorker instance is not created yet, the SharedWorker instance would be newly created. After the creation, the SharedWorker program must open that server using @@ -66,14 +66,14 @@

Parameters

Returns Promise<void>

  • Destory the communicator.

    +

Returns Promise<void>

  • Destory the communicator.

    A destory function must be called when the network communication has been closed. It would destroy all function calls in the remote system (by Driver<Controller>), which are not returned yet.

    The error instance would be thrown to those function calls. If the disconnection is abnormal, then write the detailed reason why into the error instance.

    Parameters

    • Optional error: Error

      An error instance to be thrown to the unreturned functions.

      -

    Returns Promise<void>

Returns Promise<void>

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -86,26 +86,26 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Get current Provider.

    Get an object providing features (functions & objects) for remote system. The remote system would call the features (Provider) by using its Driver<Controller>.

    Returns Provider

    Current Provider object

    -
  • Join connection.

    Wait until the connection to be closed.

    -

    Returns Promise<void>

  • Join connection or timeout.

    +

    Returns Promise<void>

  • Join connection or timeout.

    Wait until the connection to be clsoed until timeout.

    Parameters

    • ms: number

      The maximum milliseconds for joining.

    Returns Promise<boolean>

    Whether awaken by disconnection or timeout.

    -
  • Join connection or time expiration.

    +
  • Join connection or time expiration.

    Wait until the connection to be closed until time expiration.

    Parameters

    • at: Date

      The maximum time point to join.

    Returns Promise<boolean>

    Whether awaken by disconnection or time expiration.

    -
  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • Set Provider

    +

Returns void

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/classes/SharedWorkerServer-1.html b/website/out/api/classes/SharedWorkerServer-1.html index c919c7b..c54465c 100644 --- a/website/out/api/classes/SharedWorkerServer-1.html +++ b/website/out/api/classes/SharedWorkerServer-1.html @@ -22,12 +22,12 @@

Type Parameters

  • Header

    Type of header containing initialization data like activation.

  • Provider extends object | null

    Type of features provided for the remote client.

  • Remote extends object | null

    Type of features provided by remote client.

    -

Implements

Constructors

Implements

Constructors

Accessors

Methods

Constructors

Accessors

Accessors

Methods

Methods

  • Close server.

    Close all connections between its remote clients (SharedWorkerConnectors).

    It destories all RFCs (remote function calls) between this server and remote clients (through Driver<Controller>) that are not returned (completed) yet. The destruction causes all incompleted RFCs to throw exceptions.

    -

    Returns Promise<void>

  • Open shared worker server.

    Open a server through the shared worker protocol, with handler function determining whether to accept the client's connection or not. After the server has been opened, clients can connect to that server by using the @@ -53,4 +53,4 @@ client and reject its connection, just calls the SharedWorkerAcceptor.reject instead.

    Parameters

    • handler: ((acceptor) => Promise<void>)

      Callback function called whenever client connects.

      -

    Returns Promise<void>

\ No newline at end of file +

Returns Promise<void>

\ No newline at end of file diff --git a/website/out/api/classes/WebSocketAcceptor-1.html b/website/out/api/classes/WebSocketAcceptor-1.html index b65bb02..4ad3e4e 100644 --- a/website/out/api/classes/WebSocketAcceptor-1.html +++ b/website/out/api/classes/WebSocketAcceptor-1.html @@ -28,7 +28,7 @@

Type Parameters

  • Header

    Type of the header containing initial data.

  • Provider extends object | null

    Type of features provided for the remote client.

  • Remote extends object | null

    Type of features provided by remote client.

    -

Hierarchy

Implements

  • IWebSocketCommunicator

Accessors

Hierarchy

Implements

  • IWebSocketCommunicator

Accessors

header ip path state @@ -42,9 +42,9 @@ setProvider upgrade

Accessors

Methods

  • Parameters

    • Optional code: number
    • Optional reason: string

    Returns Promise<void>

    Inherit Doc

Methods

  • Parameters

    • Optional code: number
    • Optional reason: string

    Returns Promise<void>

    Inherit Doc

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -68,33 +68,33 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Get current Provider.

    Get an object providing features (functions & objects) for remote system. The remote system would call the features (Provider) by using its Driver<Controller>.

    Returns undefined | Provider

    Current Provider object

    -
  • Join connection.

    Wait until the connection to be closed.

    -

    Returns Promise<void>

  • Join connection or timeout.

    +

    Returns Promise<void>

  • Join connection or timeout.

    Wait until the connection to be clsoed until timeout.

    Parameters

    • ms: number

      The maximum milliseconds for joining.

    Returns Promise<boolean>

    Whether awaken by disconnection or timeout.

    -
  • Join connection or time expiration.

    +
  • Join connection or time expiration.

    Wait until the connection to be closed until time expiration.

    Parameters

    • at: Date

      The maximum time point to join.

    Returns Promise<boolean>

    Whether awaken by disconnection or time expiration.

    -
  • Reject connection.

    Reject without acceptance, any interaction. The connection would be closed immediately.

    Parameters

    • Optional status: number

      Status code.

    • Optional reason: string

      Detailed reason to reject.

      -

    Returns Promise<void>

  • Data Reply Function.

    +

Returns Promise<void>

  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • Set Provider

    +

Returns void

  • Set Provider

    Parameters

    • obj: undefined | Provider

      An object would be provided for remote system.

      -

    Returns void

Returns void

  • Upgrade to WebSocket protocol.

    If you've not opened websocket server from WebSocketServer, you can still compose the WebSocketAcceptor instance by yourself, by upgrading the HTTP connection to the websocket protocol.

    @@ -107,4 +107,4 @@

    Type Parameters

    • Header
    • Provider extends null | object
    • Remote extends null | object

    Parameters

    • request: IncomingMessage

      HTTP incoming message.

    • socket: WebSocket

      WebSocket instance

    • Optional handler: ((acceptor) => Promise<any>)

      A callback function after the connection has been established.

      -

    Returns void

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/classes/WebSocketConnector-1.html b/website/out/api/classes/WebSocketConnector-1.html index cdbeba6..e59d82a 100644 --- a/website/out/api/classes/WebSocketConnector-1.html +++ b/website/out/api/classes/WebSocketConnector-1.html @@ -24,7 +24,7 @@

Type Parameters

  • Header

    Type of the header containing initial data.

  • Provider extends object | null

    Type of features provided for the remote server.

  • Remote extends object | null

    Type of features supported by remote server.

    -

Hierarchy

Implements

  • IWebSocketCommunicator

Constructors

Hierarchy

Implements

  • IWebSocketCommunicator

Constructors

Accessors

header state url @@ -39,8 +39,8 @@

Constructors

Accessors

Returns WebSocketConnector<Header, Provider, Remote>

Accessors

Methods

  • Parameters

    • Optional code: number
    • Optional reason: string

    Returns Promise<void>

    Inherit Doc

Methods

  • Parameters

    • Optional code: number
    • Optional reason: string

    Returns Promise<void>

    Inherit Doc

  • Connect to remote websocket server.

    Try connection to the remote websocket server with its address and waiting for the server to accept the trial. If the server rejects your connection, then exception would be thrown (in Promise.catch, as WebSocketError).

    @@ -59,14 +59,14 @@ connection in time to prevent waste of the server resource.

    Parameters

    Returns Promise<void>

  • Destory the communicator.

    +

Returns Promise<void>

  • Destory the communicator.

    A destory function must be called when the network communication has been closed. It would destroy all function calls in the remote system (by Driver<Controller>), which are not returned yet.

    The error instance would be thrown to those function calls. If the disconnection is abnormal, then write the detailed reason why into the error instance.

    Parameters

    • Optional error: Error

      An error instance to be thrown to the unreturned functions.

      -

    Returns Promise<void>

Returns Promise<void>

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -79,26 +79,26 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Get current Provider.

    Get an object providing features (functions & objects) for remote system. The remote system would call the features (Provider) by using its Driver<Controller>.

    Returns Provider

    Current Provider object

    -
  • Join connection.

    Wait until the connection to be closed.

    -

    Returns Promise<void>

  • Join connection or timeout.

    +

    Returns Promise<void>

  • Join connection or timeout.

    Wait until the connection to be clsoed until timeout.

    Parameters

    • ms: number

      The maximum milliseconds for joining.

    Returns Promise<boolean>

    Whether awaken by disconnection or timeout.

    -
  • Join connection or time expiration.

    +
  • Join connection or time expiration.

    Wait until the connection to be closed until time expiration.

    Parameters

    • at: Date

      The maximum time point to join.

    Returns Promise<boolean>

    Whether awaken by disconnection or time expiration.

    -
  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • Set Provider

    +

Returns void

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/classes/WebSocketError.html b/website/out/api/classes/WebSocketError.html index c08631b..c3506d9 100644 --- a/website/out/api/classes/WebSocketError.html +++ b/website/out/api/classes/WebSocketError.html @@ -1,7 +1,7 @@ WebSocketError | tgrid

Class WebSocketError

Web Socket Error.

Hierarchy

  • Error
    • WebSocketError

Constructors

Hierarchy

  • Error
    • WebSocketError

Constructors

Properties

message name stack? @@ -12,7 +12,7 @@

Author

Jeongho Nam - https://git

Constructors

Properties

message: string
name: string
stack?: string
status: number
prepareStackTrace?: ((err, stackTraces) => any)

Optional override for formatting stack traces

+

Returns WebSocketError

Properties

message: string
name: string
stack?: string
status: number
prepareStackTrace?: ((err, stackTraces) => any)

Optional override for formatting stack traces

Type declaration

    • (err, stackTraces): any
    • Parameters

      • err: Error
      • stackTraces: CallSite[]

      Returns any

stackTraceLimit: number

Methods

  • Create .stack property on a target object

    Parameters

    • targetObject: object
    • Optional constructorOpt: Function

    Returns void

\ No newline at end of file diff --git a/website/out/api/classes/WebSocketServer-1.html b/website/out/api/classes/WebSocketServer-1.html index cf71bfc..5746719 100644 --- a/website/out/api/classes/WebSocketServer-1.html +++ b/website/out/api/classes/WebSocketServer-1.html @@ -22,17 +22,17 @@

Type Parameters

  • Header

    Type of header containing initialization data like activation.

  • Provider extends object | null

    Type of features provided for the remote client.

  • Remote extends object | null

    Type of features provided by remote client.

    -

Implements

Constructors

Implements

Constructors

Accessors

Methods

Constructors

Accessors

Returns WebSocketServer<Header, Provider, Remote>

Accessors

Methods

Methods

  • Close server.

    Close all connections between its remote clients (WebSocketConnectors).

    It destories all RFCs (remote function calls) between this server and remote clients (through Driver<Controller>) that are not returned (completed) yet. The destruction causes all incompleted RFCs to throw exceptions.

    -

    Returns Promise<void>

  • Open websocket server.

    Open a server through the web-socket protocol, with its port number and handler function determining whether to accept the client's connection or not. After the server has been opened, clients can connect to that websocket server by using the WebSocketConnector @@ -58,4 +58,4 @@ WebSocketAcceptor.reject instead.

    Parameters

    • port: number

      Port number to listen.

    • handler: ((acceptor) => Promise<void>)

      Callback function for client connection.

      -

    Returns Promise<void>

\ No newline at end of file +

Returns Promise<void>

\ No newline at end of file diff --git a/website/out/api/classes/WorkerConnector-1.html b/website/out/api/classes/WorkerConnector-1.html index a6e5ccc..c3e79ff 100644 --- a/website/out/api/classes/WorkerConnector-1.html +++ b/website/out/api/classes/WorkerConnector-1.html @@ -23,7 +23,7 @@

Type Parameters

  • Header

    Type of the header containing initial data.

  • Provider extends object | null

    Type of features provided for the remote server.

  • Remote extends object | null

    Type of features supported by remote server.

    -

Hierarchy

Implements

  • IWorkerSystem

Constructors

Hierarchy

Implements

  • IWorkerSystem

Constructors

Accessors

Methods

close @@ -42,8 +42,8 @@

Type Parameters

  • Header
  • Provider extends null | object
  • Remote extends null | object

Parameters

  • header: Header

    An object containing initialization data like activation.

  • provider: Provider

    An object providing features for remote system.

  • Optional type: "process" | "thread"

    You can specify the worker mode when NodeJS. Default is "process".

    -

Returns WorkerConnector<Header, Provider, Remote>

Accessors

Returns WorkerConnector<Header, Provider, Remote>

Accessors

Methods

Methods

  • Compile server and connect to there.

    The compile method tries compile JS source code, creates Worker instance with that code connects to the Worker. To complete the compilation and connection, the Worker program must open that server using the WorkerServer.open() @@ -63,7 +63,7 @@ memory usage and communication channel would not be destroyed and it may cause the memory leak.

    Parameters

    Returns Promise<void>

Returns Promise<void>

Returns Promise<void>

  • Destory the communicator.

    A destory function must be called when the network communication has been closed. It would destroy all function calls in the remote system (by Driver<Controller>), which are not returned yet.

    The error instance would be thrown to those function calls. If the disconnection is abnormal, then write the detailed reason why into the error instance.

    Parameters

    • Optional error: Error

      An error instance to be thrown to the unreturned functions.

      -

    Returns Promise<void>

Returns Promise<void>

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -92,26 +92,26 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Get current Provider.

    Get an object providing features (functions & objects) for remote system. The remote system would call the features (Provider) by using its Driver<Controller>.

    Returns Provider

    Current Provider object

    -
  • Join connection.

    Wait until the connection to be closed.

    -

    Returns Promise<void>

  • Join connection or timeout.

    +

    Returns Promise<void>

  • Join connection or timeout.

    Wait until the connection to be clsoed until timeout.

    Parameters

    • ms: number

      The maximum milliseconds for joining.

    Returns Promise<boolean>

    Whether awaken by disconnection or timeout.

    -
  • Join connection or time expiration.

    +
  • Join connection or time expiration.

    Wait until the connection to be closed until time expiration.

    Parameters

    • at: Date

      The maximum time point to join.

    Returns Promise<boolean>

    Whether awaken by disconnection or time expiration.

    -
  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • Set Provider

    +

Returns void

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/classes/WorkerServer-1.html b/website/out/api/classes/WorkerServer-1.html index 3acca9f..0b1b6b5 100644 --- a/website/out/api/classes/WorkerServer-1.html +++ b/website/out/api/classes/WorkerServer-1.html @@ -23,7 +23,7 @@

Type Parameters

  • Header

    Type of the header containing initial data.

  • Provider extends object | null

    Type of features provided for the client.

  • Remote extends object | null

    Type of features supported by client.

    -

Hierarchy (view full)

Implements

Constructors

Hierarchy (view full)

Implements

Constructors

Accessors

Methods

close destructor @@ -35,14 +35,14 @@ replyData setProvider

Constructors

Accessors

Methods

Accessors

Methods

  • Destory the communicator.

    A destory function must be called when the network communication has been closed. It would destroy all function calls in the remote system (by Driver<Controller>), which are not returned yet.

    The error instance would be thrown to those function calls. If the disconnection is abnormal, then write the detailed reason why into the error instance.

    Parameters

    • Optional error: Error

      An error instance to be thrown to the unreturned functions.

      -

    Returns Promise<void>

Returns Promise<void>

  • Get Driver for RFC (Remote Function Call).

    The Controller is an interface who defines provided functions from the remote system. The Driver is an object who makes to call remote functions, defined in the Controller and provided by Provider in the remote system, possible.

    @@ -55,34 +55,34 @@

    Type Parameters

    • Controller extends object = NonNullable<Remote>

      An interface for provided features (functions & objects) from the remote system (Provider).

    • UseParametric extends boolean = false

      Whether to convert type of function parameters to be compatible with their pritimive.

    Returns Driver<Controller, UseParametric>

    A Driver for the RFC.

    -
  • Open server with Provider.

    Open worker server and start communication with the client (WorkerConnector).

    Note that, after your business, you should terminate this worker to prevent waste of memory leak. Close this worker by yourself (close) or let client to close this worker (WorkerConnector.close).

    Parameters

    • provider: Provider

      An object providing featrues for the client.

      -

    Returns Promise<void>

  • Data Reply Function.

    +

Returns Promise<void>

  • Data Reply Function.

    A function should be called when data has come from the remote system.

    When you receive a message from the remote system, then parse the message with your special protocol and covert it to be an Invoke object. After the conversion, call this method.

    Parameters

    • invoke: Invoke

      Structured data converted by your special protocol.

      -

    Returns void

  • Set Provider

    +

Returns void

\ No newline at end of file +

Returns void

\ No newline at end of file diff --git a/website/out/api/enums/WebSocketAcceptor.State.html b/website/out/api/enums/WebSocketAcceptor.State.html index 801c721..b487435 100644 --- a/website/out/api/enums/WebSocketAcceptor.State.html +++ b/website/out/api/enums/WebSocketAcceptor.State.html @@ -1,8 +1,8 @@ State | tgrid

Enumeration StateConst

Current state type of acceptor.

-

Enumeration Members

Enumeration Members

Enumeration Members

ACCEPTING: 0
CLOSED: 3
CLOSING: 2
NONE: -1
OPEN: 1
REJECTING: -2
\ No newline at end of file +

Enumeration Members

ACCEPTING: 0
CLOSED: 3
CLOSING: 2
NONE: -1
OPEN: 1
REJECTING: -2
\ No newline at end of file diff --git a/website/out/api/enums/WebSocketConnector.State.html b/website/out/api/enums/WebSocketConnector.State.html index fee8090..4cc53a2 100644 --- a/website/out/api/enums/WebSocketConnector.State.html +++ b/website/out/api/enums/WebSocketConnector.State.html @@ -1,7 +1,7 @@ State | tgrid

Enumeration StateConst

Current state type of connector.

-

Enumeration Members

Enumeration Members

Enumeration Members

CLOSED: 3
CLOSING: 2
CONNECTING: 0
NONE: -1
OPEN: 1
\ No newline at end of file +

Enumeration Members

CLOSED: 3
CLOSING: 2
CONNECTING: 0
NONE: -1
OPEN: 1
\ No newline at end of file diff --git a/website/out/api/enums/WebSocketServer.State.html b/website/out/api/enums/WebSocketServer.State.html index eb2bd38..e7f6492 100644 --- a/website/out/api/enums/WebSocketServer.State.html +++ b/website/out/api/enums/WebSocketServer.State.html @@ -1,6 +1,6 @@ -State | tgrid

Enumeration StateConst

Enumeration Members

CLOSED +State | tgrid

Enumeration StateConst

Enumeration Members

Enumeration Members

CLOSED: 3
CLOSING: 2
NONE: -1
OPEN: 1
OPENING: 0
\ No newline at end of file +

Enumeration Members

CLOSED: 3
CLOSING: 2
NONE: -1
OPEN: 1
OPENING: 0
\ No newline at end of file diff --git a/website/out/api/functions/SharedWorkerConnector.compile.html b/website/out/api/functions/SharedWorkerConnector.compile.html index de6d48d..51d5a38 100644 --- a/website/out/api/functions/SharedWorkerConnector.compile.html +++ b/website/out/api/functions/SharedWorkerConnector.compile.html @@ -1,4 +1,4 @@ compile | tgrid
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/functions/SharedWorkerConnector.remove.html b/website/out/api/functions/SharedWorkerConnector.remove.html index d17cbea..549b390 100644 --- a/website/out/api/functions/SharedWorkerConnector.remove.html +++ b/website/out/api/functions/SharedWorkerConnector.remove.html @@ -1,3 +1,3 @@ remove | tgrid
\ No newline at end of file +

Returns Promise<void>

\ No newline at end of file diff --git a/website/out/api/interfaces/Invoke.IFunction.html b/website/out/api/interfaces/Invoke.IFunction.html index 9706e06..0c341cb 100644 --- a/website/out/api/interfaces/Invoke.IFunction.html +++ b/website/out/api/interfaces/Invoke.IFunction.html @@ -1,8 +1,8 @@ IFunction | tgrid

Interface IFunction

Message for Requesting RFC.

-
interface IFunction {
    listener: string;
    parameters: IParameter[];
    uid: number;
}

Hierarchy

  • IBase
    • IFunction

Properties

interface IFunction {
    listener: string;
    parameters: IParameter[];
    uid: number;
}

Hierarchy

  • IBase
    • IFunction

Properties

listener: string

Target function (sometimes calsuled in objects) to call.

-
parameters: IParameter[]

Parameters for the function call.

-
uid: number

Unique identifier.

-
\ No newline at end of file +
parameters: IParameter[]

Parameters for the function call.

+
uid: number

Unique identifier.

+
\ No newline at end of file diff --git a/website/out/api/interfaces/Invoke.IParameter.html b/website/out/api/interfaces/Invoke.IParameter.html index 6a05dca..7bfba38 100644 --- a/website/out/api/interfaces/Invoke.IParameter.html +++ b/website/out/api/interfaces/Invoke.IParameter.html @@ -1,3 +1,3 @@ -IParameter | tgrid

Interface IParameter

interface IParameter {
    type: string;
    value: any;
}

Properties

type +IParameter | tgrid

Interface IParameter

interface IParameter {
    type: string;
    value: any;
}

Properties

Properties

type: string
value: any
\ No newline at end of file +

Properties

type: string
value: any
\ No newline at end of file diff --git a/website/out/api/interfaces/Invoke.IReturn.html b/website/out/api/interfaces/Invoke.IReturn.html index 32d330b..0fba36b 100644 --- a/website/out/api/interfaces/Invoke.IReturn.html +++ b/website/out/api/interfaces/Invoke.IReturn.html @@ -1,8 +1,8 @@ IReturn | tgrid

Interface IReturn

Message for Returning RFC.

-
interface IReturn {
    success: boolean;
    uid: number;
    value: any;
}

Hierarchy

  • IBase
    • IReturn

Properties

interface IReturn {
    success: boolean;
    uid: number;
    value: any;
}

Hierarchy

  • IBase
    • IReturn

Properties

Properties

success: boolean

true -> return, false -> exception.

-
uid: number

Unique identifier.

-
value: any

Returned value or thrown exception.

-
\ No newline at end of file +
uid: number

Unique identifier.

+
value: any

Returned value or thrown exception.

+
\ No newline at end of file diff --git a/website/out/api/interfaces/SharedWorkerConnector.IConnectOptions.html b/website/out/api/interfaces/SharedWorkerConnector.IConnectOptions.html index 0369895..e240df1 100644 --- a/website/out/api/interfaces/SharedWorkerConnector.IConnectOptions.html +++ b/website/out/api/interfaces/SharedWorkerConnector.IConnectOptions.html @@ -1,4 +1,4 @@ IConnectOptions | tgrid

Connection options for the SharedWorkerConnector.connect.

-
interface IConnectOptions {
    timeout: number;
}

Properties

interface IConnectOptions {
    timeout: number;
}

Properties

Properties

timeout: number

Milliseconds to wait the shared-worker server to accept or reject it. If omitted, the waiting would be forever.

-
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/interfaces/WebSocketConnector.IConnectOptions.html b/website/out/api/interfaces/WebSocketConnector.IConnectOptions.html index 48a38a9..ff88add 100644 --- a/website/out/api/interfaces/WebSocketConnector.IConnectOptions.html +++ b/website/out/api/interfaces/WebSocketConnector.IConnectOptions.html @@ -1,4 +1,4 @@ IConnectOptions | tgrid

Connection options for the WebSocketConnector.connect.

-
interface IConnectOptions {
    timeout: number;
}

Properties

interface IConnectOptions {
    timeout: number;
}

Properties

Properties

timeout: number

Milliseconds to wait the web-socket server to accept or reject it. If omitted, the waiting would be forever.

-
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/interfaces/WorkerConnector.IConnectOptions.html b/website/out/api/interfaces/WorkerConnector.IConnectOptions.html index 75cfd10..91db85d 100644 --- a/website/out/api/interfaces/WorkerConnector.IConnectOptions.html +++ b/website/out/api/interfaces/WorkerConnector.IConnectOptions.html @@ -1,6 +1,6 @@ IConnectOptions | tgrid

Interface IConnectOptions

Connection options for the WorkerConnector.connect.

-
interface IConnectOptions {
    execArgv: string[];
    timeout: number;
}

Properties

interface IConnectOptions {
    execArgv: string[];
    timeout: number;
}

Properties

Properties

execArgv: string[]

Arguments only for the NodeJS environments.

-
timeout: number

Milliseconds to wait the worker server to accept or reject it. If omitted, the waiting would be forever.

-
\ No newline at end of file +
timeout: number

Milliseconds to wait the worker server to accept or reject it. If omitted, the waiting would be forever.

+
\ No newline at end of file diff --git a/website/out/api/modules/Invoke.html b/website/out/api/modules/Invoke.html index dfab575..6f19b85 100644 --- a/website/out/api/modules/Invoke.html +++ b/website/out/api/modules/Invoke.html @@ -1,4 +1,4 @@ -Invoke | tgrid

Namespace Invoke

Index

Interfaces

IFunction +Invoke | tgrid
\ No newline at end of file diff --git a/website/out/api/modules/SharedWorkerAcceptor.html b/website/out/api/modules/SharedWorkerAcceptor.html index 8e70a9c..5224f14 100644 --- a/website/out/api/modules/SharedWorkerAcceptor.html +++ b/website/out/api/modules/SharedWorkerAcceptor.html @@ -1,2 +1,2 @@ -SharedWorkerAcceptor | tgrid

Namespace SharedWorkerAcceptor

References

State +SharedWorkerAcceptor | tgrid

Namespace SharedWorkerAcceptor

References

References

Re-exports State
\ No newline at end of file diff --git a/website/out/api/modules/SharedWorkerConnector.html b/website/out/api/modules/SharedWorkerConnector.html index 62faeef..3b6406f 100644 --- a/website/out/api/modules/SharedWorkerConnector.html +++ b/website/out/api/modules/SharedWorkerConnector.html @@ -1,4 +1,4 @@ -SharedWorkerConnector | tgrid

Namespace SharedWorkerConnector

References

State +SharedWorkerConnector | tgrid

Namespace SharedWorkerConnector

References

Interfaces

Functions

compile remove diff --git a/website/out/api/modules/SharedWorkerServer.html b/website/out/api/modules/SharedWorkerServer.html index 46c63da..88dc601 100644 --- a/website/out/api/modules/SharedWorkerServer.html +++ b/website/out/api/modules/SharedWorkerServer.html @@ -1,2 +1,2 @@ -SharedWorkerServer | tgrid

Namespace SharedWorkerServer

References

State +SharedWorkerServer | tgrid

Namespace SharedWorkerServer

References

References

Re-exports State
\ No newline at end of file diff --git a/website/out/api/modules/WebSocketAcceptor.html b/website/out/api/modules/WebSocketAcceptor.html index 7db379c..ed03a68 100644 --- a/website/out/api/modules/WebSocketAcceptor.html +++ b/website/out/api/modules/WebSocketAcceptor.html @@ -1,2 +1,2 @@ -WebSocketAcceptor | tgrid

Namespace WebSocketAcceptor

Index

Enumerations

State +WebSocketAcceptor | tgrid
\ No newline at end of file diff --git a/website/out/api/modules/WebSocketConnector.html b/website/out/api/modules/WebSocketConnector.html index 52a2e36..e116530 100644 --- a/website/out/api/modules/WebSocketConnector.html +++ b/website/out/api/modules/WebSocketConnector.html @@ -1,3 +1,3 @@ -WebSocketConnector | tgrid

Namespace WebSocketConnector

Index

Enumerations

State +WebSocketConnector | tgrid
\ No newline at end of file diff --git a/website/out/api/modules/WebSocketServer.html b/website/out/api/modules/WebSocketServer.html index 0ddce84..8d5ad0c 100644 --- a/website/out/api/modules/WebSocketServer.html +++ b/website/out/api/modules/WebSocketServer.html @@ -1,2 +1,2 @@ -WebSocketServer | tgrid

Namespace WebSocketServer

Index

Enumerations

State +WebSocketServer | tgrid
\ No newline at end of file diff --git a/website/out/api/modules/WorkerConnector.html b/website/out/api/modules/WorkerConnector.html index 5519122..afbcd04 100644 --- a/website/out/api/modules/WorkerConnector.html +++ b/website/out/api/modules/WorkerConnector.html @@ -1,3 +1,3 @@ -WorkerConnector | tgrid

Namespace WorkerConnector

References

State +WorkerConnector | tgrid

Namespace WorkerConnector

References

Interfaces

References

Re-exports State
\ No newline at end of file diff --git a/website/out/api/modules/WorkerServer.html b/website/out/api/modules/WorkerServer.html index bcd91d1..cf18df0 100644 --- a/website/out/api/modules/WorkerServer.html +++ b/website/out/api/modules/WorkerServer.html @@ -1,2 +1,2 @@ -WorkerServer | tgrid

Namespace WorkerServer

References

State +WorkerServer | tgrid

Namespace WorkerServer

References

References

Re-exports State
\ No newline at end of file diff --git a/website/out/api/modules/default.html b/website/out/api/modules/default.html index 253c188..9fbd579 100644 --- a/website/out/api/modules/default.html +++ b/website/out/api/modules/default.html @@ -1,4 +1,4 @@ -default | tgrid

Namespace default

References

Communicator +default | tgrid

Namespace default

References

Communicator Driver Invoke Primitive diff --git a/website/out/api/types/Driver.html b/website/out/api/types/Driver.html index dfb59e9..220f834 100644 --- a/website/out/api/types/Driver.html +++ b/website/out/api/types/Driver.html @@ -11,4 +11,4 @@

Type Parameters

  • Controller extends object

    An interface defining features (functions & objects) provided from the remote system.

  • Parametric extends boolean = false

Template: UseParametric

Whether to convert type of function parameters to be compatible with their pritimive.

Author

Jeongho Nam - https://github.com/samchon

-
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/types/Invoke-1.html b/website/out/api/types/Invoke-1.html index 5cdb2a6..6e6e868 100644 --- a/website/out/api/types/Invoke-1.html +++ b/website/out/api/types/Invoke-1.html @@ -1,3 +1,3 @@ Invoke | tgrid

Type alias Invoke

Invoke: IFunction | IReturn

Message structure for RFC (Remote Function Call).

Author

Jeongho Nam - https://github.com/samchon

-
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/types/Primitive.html b/website/out/api/types/Primitive.html index 44fe8b2..15266c7 100644 --- a/website/out/api/types/Primitive.html +++ b/website/out/api/types/Primitive.html @@ -51,4 +51,4 @@

Author

Jeongho Nam - https://github.com/samchon

Author

Kyungsu Kang - https://github.com/kakasoo

Author

Michael - https://github.com/8471919

-
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/types/Promisive.html b/website/out/api/types/Promisive.html index 3594db0..5910bcb 100644 --- a/website/out/api/types/Promisive.html +++ b/website/out/api/types/Promisive.html @@ -7,4 +7,4 @@

Type Parameters

  • Instance extends object

    An object type to be promised.

  • UseParametric extends boolean = false

    Whether to convert type of function parameters to be compatible with their pritimive.

    -
\ No newline at end of file +
\ No newline at end of file diff --git a/website/out/api/variables/Driver-1.html b/website/out/api/variables/Driver-1.html index 67182ed..78e07eb 100644 --- a/website/out/api/variables/Driver-1.html +++ b/website/out/api/variables/Driver-1.html @@ -1 +1 @@ -Driver | tgrid

Variable Driver

Driver: typeof __class
\ No newline at end of file +Driver | tgrid

Variable Driver

Driver: typeof __class
\ No newline at end of file diff --git a/website/out/docs/examples/nestjs-websocket/index.html b/website/out/docs/examples/nestjs-websocket/index.html index e79a3b9..384a5aa 100644 --- a/website/out/docs/examples/nestjs-websocket/index.html +++ b/website/out/docs/examples/nestjs-websocket/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Examples
NestJS WebSocket

Outline

+
📖 Guide Documents
Learn from Examples
NestJS WebSocket

Outline

If you develop websocket application, I recommend integrate TGrid with NestJS / Nestia.

It's because you can manage WebSocket API endpoints much effectively and easily by NestJS controller patterns. Also, you can make your server to support both HTTP and WebSocket protocols at the same time. NestJS controllers are compatible with both HTTP and WebSocket operations.

Furthermore, you can generate SDK (Software Development Kit) library for your client application through Nestia. With the automatically generated SDK, client developers no more need to write the WebSocket connection and RPC (Remote Procedure Call) codes manually, so that the client development becomes much easier and safer.

@@ -444,4 +444,4 @@

Mutex Server -


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/examples/object-oriented-network/index.html b/website/out/docs/examples/object-oriented-network/index.html index b782a04..1e74369 100644 --- a/website/out/docs/examples/object-oriented-network/index.html +++ b/website/out/docs/examples/object-oriented-network/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Examples
Object Oriented Network

Outline

+
📖 Guide Documents
Learn from Examples
Object Oriented Network

Outline

Object Oriented Network

Each remote system is an object.

With TGrid, you can easily develop complicated network system, by considering each network system as an object, and interacting with each other through RPC (Remote Procedure Call). TGrid defines this concept as "Object Oriented Network".

@@ -265,4 +265,4 @@

); await acceptor.accept(provider); } -}


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +}

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/examples/remote-function-call/index.html b/website/out/docs/examples/remote-function-call/index.html index efe0a48..0cf55ca 100644 --- a/website/out/docs/examples/remote-function-call/index.html +++ b/website/out/docs/examples/remote-function-call/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Examples
Remote Function Call

Outline

+
📖 Guide Documents
Learn from Examples
Remote Function Call

Outline

With TGrid, you can call remote system's functions as if they are local functions.

Such remote procedure calling concept is called as RPC (Remote Procedure Call) in the development world, but it contains not only remote funtion call, but also contains Remote Object Call and Object Oriented Network. However, in here chapter, we will focus only on the remote function calls.

Let's learn how to call remote functions with TGrid.

@@ -137,4 +137,4 @@

await connector.close(); console.log(stack); -};


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +};

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/examples/remote-object-call/index.html b/website/out/docs/examples/remote-object-call/index.html index 15d564e..8ac1d40 100644 --- a/website/out/docs/examples/remote-object-call/index.html +++ b/website/out/docs/examples/remote-object-call/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Examples
Remote Object Call

Outline

+
📖 Guide Documents
Learn from Examples
Remote Object Call

Outline

Remote Object Call

With TGrid, you can call remote system's nested functions as if they are local functions.

Such remote procedure calling concept is called as RPC (Remote Procedure Call) in the development world, but it contains not only remote function call, but also contains Object Oriented Network. However, in here chapter, we will focus only on the remote nested function calls.

@@ -178,4 +178,4 @@

main().catch((exp) => { console.error(exp); process.exit(-1); -});


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +});

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/features/components/index.html b/website/out/docs/features/components/index.html index 00d09a1..0d45dc7 100644 --- a/website/out/docs/features/components/index.html +++ b/website/out/docs/features/components/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Features
Components

Outline

+
📖 Guide Documents
Features
Components

Outline

This chapter describes key components of the TGrid only in the conceptual level.

If you're not familar with theoretical stories, it's okay to skip to the next chapter Features > WebSocket Protocol.

Even you want to see the example codes, step to the Learn from Examples > Remote Funtion Call chapter.

@@ -171,4 +171,4 @@

Otherwise exception is thrown in the remote Provider function, Communicator deliveries the exception instance instead to the remote system, so that actual exception being thrown from the Driver<Remote> instance.

💻

Demonstration

You can run it on Playground Website (opens in a new tab), or local machine.

Terminal
git clone https://github.com/samchon/tgrid.example.websocket
 npm install
-npm start


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +npm start

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/features/websocket/index.html b/website/out/docs/features/websocket/index.html index 86dd9f4..72e5bcd 100644 --- a/website/out/docs/features/websocket/index.html +++ b/website/out/docs/features/websocket/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Features
WebSocket Protocol

Outline

+
📖 Guide Documents
Features
WebSocket Protocol

Outline

TGrid supports WebSocket protocol.

With TGrid, you can easily develop WebSocket system under the RPC (Remote Procedure Call) concept.

By the way, when you're developing WebSocket server natively only with TGrid, you have to construct and open the WebSocket server through WebSocketServer class. Also, you have to access to the WebSocket server with manual WebSocketConnector composition.

@@ -617,4 +617,4 @@

Also, don't forget to closing the connection, if your business logics have been completed, to clean up the resources. Otherwise, the closing must be performed by the remote websocket server, you can wait the remote server's closing signal through the WebSocketConnector.join() method.

💻

Demonstration

You can run it on Playground Website (opens in a new tab), or local machine.

Terminal
git clone https://github.com/samchon/tgrid.example.nestjs
 npm install
-npm start


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +npm start

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/features/worker/index.html b/website/out/docs/features/worker/index.html index 5ced6e7..0ee931d 100644 --- a/website/out/docs/features/worker/index.html +++ b/website/out/docs/features/worker/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Features
Worker Protocol

Outline

+
📖 Guide Documents
Features
Worker Protocol

Outline

TGrid supports Worker/SharedWorker protocols.

With TGrid, you can easily develop Worker programs under the RPC (Remote Procedure Call) concept.

TGrid considers Worker as a 1: 1 dedicated server, and SharedWorker as a 1: N multi-client acceptable server running on the local. Therefore, the interfaces of Worker and SharedWorker in the TGrid are similar with WebSocket components. In such reason, if you're developing a complicate WebSocket system, you can simulate it in the local environment by using Worker/SharedWorker components.

@@ -290,4 +290,4 @@

💻

Demonstration

You can run it on your local machine.

Terminal
git clone https://github.com/samchon/tgrid.example.shared-worker
 npm install
 npm run build
-npm start


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +npm start

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/index.html b/website/out/docs/index.html index c7b87b0..93300db 100644 --- a/website/out/docs/index.html +++ b/website/out/docs/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
🙋🏻‍♂️ Introduction

TGrid Logo

+
-

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/projects/chat/index.html b/website/out/docs/projects/chat/index.html index 5055bf1..3a9dbfa 100644 --- a/website/out/docs/projects/chat/index.html +++ b/website/out/docs/projects/chat/index.html @@ -19,8 +19,8 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Projects
Chat Application

Preparing

+

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +

https://github.com/samchon/tgrid.projects.chat (opens in a new tab)


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/projects/market/index.html b/website/out/docs/projects/market/index.html index 67148fc..f63be79 100644 --- a/website/out/docs/projects/market/index.html +++ b/website/out/docs/projects/market/index.html @@ -19,8 +19,8 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Projects
Grid Market

Preparing

+

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +

https://github.com/samchon/tgrid.projects.market (opens in a new tab)


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/projects/mutex/index.html b/website/out/docs/projects/mutex/index.html index 9046474..ae5c7b3 100644 --- a/website/out/docs/projects/mutex/index.html +++ b/website/out/docs/projects/mutex/index.html @@ -19,8 +19,8 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
Learn from Projects
Mutex Server

Preparing

+

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +

https://github.com/samchon/mutex (opens in a new tab)


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/remote-procedure-call/index.html b/website/out/docs/remote-procedure-call/index.html index 5a9b365..1781d2a 100644 --- a/website/out/docs/remote-procedure-call/index.html +++ b/website/out/docs/remote-procedure-call/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
📡 Remote Procedure Call

Outline

+
📖 Guide Documents
📡 Remote Procedure Call

Outline

With TGrid, you can call remote procedures of provided by remote system.

If remote system provides a function, TGrid lets you call it as if it was a local function own. If remote system provides some functions that are capsuled in hierarchical structured objects, you still can call them as if they were your own. This is the concept of RPC (Remote Procedure Call) what TGrid is saying.

By the way, there are many other RPC (Remote Procedure Call) frameworks or libraries in the world. However, TGrid is different from them. RPC of TGrid does not mean only calling and getting returned value from the remote system's procedure, but also ensuring type safety. With the type safety, you can actually feel like that the remote procedure is your own.

@@ -116,4 +116,4 @@

Restrictions

TGrid has implemented the RPC (Remote Procedure Call) by communicating JSON message. Therefore, if parameters or return values of the remote provided functions are not compatible JSON, you can't use them.

For example, JSON does not support bigint type of JavaScript. Therefore, if some of the remote provided functions are using bigint type on their parameters or return value, it would throw an exception.

-

Also, as JSON does not contain class transformation spec, every parameters and return values must be primitive types. If you try to deliver the class instance as a parameter or return value, it would be downgraded to primitive instance in the remote system.


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +

Also, as JSON does not contain class transformation spec, every parameters and return values must be primitive types. If you try to deliver the class instance as a parameter or return value, it would be downgraded to primitive instance in the remote system.


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/docs/setup/index.html b/website/out/docs/setup/index.html index 15260a9..c22e5bd 100644 --- a/website/out/docs/setup/index.html +++ b/website/out/docs/setup/index.html @@ -19,7 +19,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
📖 Guide Documents
📦 Setup

Standalone

+
📖 Guide Documents
📦 Setup

Standalone

Terminal
npm install tgrid

If you're planning to use TGrid standalone, without NestJS integration, just setup it.

NestJS

@@ -27,4 +27,4 @@

Otherwise, you wanna use TGrid with NestJS integration, please refer to the guide documents of nestia.

By the way, if you want to setup it right now without reading detailed documents, just run the below commands.

Terminal
npx nestia setup
-npm install tgrid


Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +npm install tgrid

Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/index.html b/website/out/index.html index cc9c98e..a3f2331 100644 --- a/website/out/index.html +++ b/website/out/index.html @@ -19,6 +19,6 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -

TGrid

Remote Procedure Call

TypeScript Grid Computing Framework


await driver.method(...params)




Guide Documents
Github Repository
arrow down
+

TGrid

Remote Procedure Call

TypeScript Grid Computing Framework


await driver.method(...params)




Guide Documents
Github Repository
arrow down

Key Features

-


Remote Procedure Call

await driver.method(...params)


You can call remote system's functions


Provider: functions for remote system


Driver<Remote>: remote function caller



Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file +


Remote Procedure Call

await driver.method(...params)


You can call remote system's functions


Provider: functions for remote system


Driver<Remote>: remote function caller



Released under the MIT License.

Copyright 2018 - 2024 Samchon & Contributors
\ No newline at end of file diff --git a/website/out/robots.txt b/website/out/robots.txt new file mode 100644 index 0000000..d66f2a1 --- /dev/null +++ b/website/out/robots.txt @@ -0,0 +1,9 @@ +# * +User-agent: * +Allow: / + +# Host +Host: https://tgrid.com + +# Sitemaps +Sitemap: https://tgrid.com/sitemap.xml diff --git a/website/out/sitemap-0.xml b/website/out/sitemap-0.xml new file mode 100644 index 0000000..00d78d6 --- /dev/null +++ b/website/out/sitemap-0.xml @@ -0,0 +1,17 @@ + + +https://tgrid.com/2024-05-16T16:55:13.863Zdaily0.7 +https://tgrid.com/docs/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/examples/nestjs-websocket/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/examples/object-oriented-network/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/examples/remote-function-call/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/examples/remote-object-call/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/features/components/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/features/websocket/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/features/worker/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/projects/chat/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/projects/market/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/projects/mutex/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/remote-procedure-call/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/docs/setup/2024-05-16T16:55:13.864Zdaily0.7 + \ No newline at end of file diff --git a/website/out/sitemap.xml b/website/out/sitemap.xml new file mode 100644 index 0000000..4298b9d --- /dev/null +++ b/website/out/sitemap.xml @@ -0,0 +1,4 @@ + + +https://tgrid.com/sitemap-0.xml + \ No newline at end of file diff --git a/website/public/sitemap-0.xml b/website/public/sitemap-0.xml index 00d78d6..918d187 100644 --- a/website/public/sitemap-0.xml +++ b/website/public/sitemap-0.xml @@ -1,17 +1,17 @@ -https://tgrid.com/2024-05-16T16:55:13.863Zdaily0.7 -https://tgrid.com/docs/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/examples/nestjs-websocket/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/examples/object-oriented-network/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/examples/remote-function-call/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/examples/remote-object-call/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/features/components/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/features/websocket/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/features/worker/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/projects/chat/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/projects/market/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/projects/mutex/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/remote-procedure-call/2024-05-16T16:55:13.864Zdaily0.7 -https://tgrid.com/docs/setup/2024-05-16T16:55:13.864Zdaily0.7 +https://tgrid.com/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/examples/nestjs-websocket/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/examples/object-oriented-network/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/examples/remote-function-call/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/examples/remote-object-call/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/features/components/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/features/websocket/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/features/worker/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/projects/chat/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/projects/market/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/projects/mutex/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/remote-procedure-call/2024-05-16T16:56:56.067Zdaily0.7 +https://tgrid.com/docs/setup/2024-05-16T16:56:56.067Zdaily0.7 \ No newline at end of file