Outline
This chapter describes key components of the TGrid
only in the conceptual level.
If you're not familiar 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 Function Call chapter.
Otherwise, let's study about the key components of the TGrid
.
Communicator
: network communication with remote systemHeader
: header value directly delivered after the connectionProvider
: object provided for remote systemDriver
: proxy instance for calling functions of the remote system'sProvider
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<Remote>
, 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
.
Protocol | Client | Server |
---|---|---|
Web Socket | WebSocketConnector | WebSocketAcceptor |
Dedicated Worker | WorkerConnector | WorkerServer |
Shared Worker | SharedWorkerConnector | SharedWorkerAcceptor |
Header
import { Driver, WebSocketConnector } from "tgrid";
import { ICalcConfig } from "./interfaces/ICalcConfig";
import { ICalcEvent } from "./interfaces/ICalcEvent";
import { ICalcEventListener } from "./interfaces/ICalcEventListener";
import { ICompositeCalculator } from "./interfaces/ICompositeCalculator";
export const webSocketClientMain = async () => {
const stack: ICalcEvent[] = [];
const listener: ICalcEventListener = {
on: (evt: ICalcEvent) => stack.push(evt),
};
const connector: WebSocketConnector<
ICalcConfig,
ICalcEventListener,
ICompositeCalculator
> = new WebSocketConnector(
{ precision: 2 }, // header
listener, // provider for remote server
);
await connector.connect("ws://127.0.0.1:37000/composite");
const remote: Driver<ICompositeCalculator> = connector.getDriver();
console.log(
await driver.plus(10, 20), // returns 30
await driver.multiplies(3, 4), // returns 12
await driver.divides(5, 3), // returns 1.67
await driver.scientific.sqrt(2), // returns 1.41
await driver.statistics.mean(1, 3, 9), // returns 4.33
);
await connector.close();
console.log(stack);
};
Header 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.
Provider
import { Driver, WebSocketServer } from "tgrid";
import { ICalcConfig } from "./interfaces/ICalcConfig";
import { ICalcEventListener } from "./interfaces/ICalcEventListener";
import { CompositeCalculator } from "./providers/CompositeCalculator";
import { ScientificCalculator } from "./providers/ScientificCalculator";
import { SimpleCalculator } from "./providers/SimpleCalculator";
import { StatisticsCalculator } from "./providers/StatisticsCalculator";
export const webSocketServerMain = async () => {
const server: WebSocketServer<
ICalcConfig,
| CompositeCalculator
| SimpleCalculator
| StatisticsCalculator
| ScientificCalculator,
ICalcEventListener
> = new WebSocketServer();
await server.open(37_000, async (acceptor) => {
// LIST UP PROPERTIES
const config: ICalcConfig = acceptor.header;
const listener: Driver<ICalcEventListener> = acceptor.getDriver();
// ACCEPT OR REJECT
if (acceptor.path === "/composite")
await acceptor.accept(new CompositeCalculator(config, listener));
else if (acceptor.path === "/simple")
await acceptor.accept(new SimpleCalculator(config, listener));
else if (acceptor.path === "/statistics")
await acceptor.accept(new StatisticsCalculator(config, listener));
else if (acceptor.path === "/scientific")
await acceptor.accept(new ScientificCalculator(config, listener));
else {
await acceptor.reject(1002, `WebSocket API endpoint not found.`);
return;
}
// PING REPEATEDLY TO KEEP CONNECTION
acceptor.ping(15_000);
});
return server;
};
Object provided for remote system.
Provider
is an object provided for the remote system.
The remote system can call the Provider
's functions through Driver<Remote>
.
Driver
import { Driver, WebSocketConnector } from "tgrid";
import { ICalcConfig } from "./interfaces/ICalcConfig";
import { ICalcEvent } from "./interfaces/ICalcEvent";
import { ICalcEventListener } from "./interfaces/ICalcEventListener";
import { ICompositeCalculator } from "./interfaces/ICompositeCalculator";
export const webSocketClientMain = async () => {
const stack: ICalcEvent[] = [];
const listener: ICalcEventListener = {
on: (evt: ICalcEvent) => stack.push(evt),
};
const connector: WebSocketConnector<
ICalcConfig,
ICalcEventListener,
ICompositeCalculator
> = new WebSocketConnector(
{ precision: 2 }, // header
listener, // provider for remote server
);
await connector.connect("ws://127.0.0.1:37000/composite");
const remote: Driver<ICompositeCalculator> = connector.getDriver();
console.log(
await driver.plus(10, 20), // returns 30
await driver.multiplies(3, 4), // returns 12
await driver.divides(5, 3), // returns 1.67
await driver.scientific.sqrt(2), // returns 1.41
await driver.statistics.mean(1, 3, 9), // returns 4.33
);
await connector.close();
console.log(stack);
};
Terminal$ npm start 30 12 1.67 1.41 4.33 [ { type: 'plus', input: [ 10, 20 ], output: 30 }, { type: 'multiplies', input: [ 3, 4 ], output: 12 }, { type: 'divides', input: [ 5, 3 ], output: 1.67 }, { type: 'sqrt', input: [ 2 ], output: 1.41 }, { type: 'mean', input: [ 1, 3, 9 ], output: 4.33 } ]
Driver 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<Remote>
instance.
When you call some function of remote Provider by the Driver<Listener>
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 succeeded to reply the result of the function call, Communicator resolves the promise of the function call expression with the result, so that makes Driver<Remote>
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<Remote>
instance.
Demonstration
You can run it on Playground Website (opens in a new tab), or local machine.
git clone https://github.com/samchon/tgrid.example.websocket
npm install
npm start