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
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 } ]
Here 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<ICompositeCalculator>
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<ICompositeCalculator>
typed instance, this is the RPC (Remote Procedure Call) of TGrid
.
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
RPC 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);
};
Looking 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<R>
types through the Driver<T>
type.
As the Driver<ICompositeCalculator>
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<T>
type is casting them.
Tip
Description 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<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 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<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.
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.