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 function 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
.
Demonstration
You can run the example program on Playground Website (opens in a new tab), or local machine.
git clone https://github.com/samchon/tgrid.example.remote-function-call
npm install
npm start
Client Program
import { Driver, WebSocketConnector } from "tgrid";
export const webSocketClientMain = async () => {
const connector: WebSocketConnector<null, null, ICalculator> =
new WebSocketConnector(
null, // header
null, // provider for remote server
);
await connector.connect("ws://127.0.0.1:37000/composite");
const remote: Driver<ICalculator> = connector.getDriver();
console.log(
await remote.plus(10, 20), // returns 30
await remote.minus(7, 3), // returns 4
await remote.multiply(3, 4), // returns 12
await remote.divide(5, 2), // returns 2.5
);
await connector.close();
};
interface ICalculator {
plus(a: number, b: number): number
minus(a: number, b: number): number
multiply(a: number, b: number): number
divide(a: number, b: number): number
}
Terminal$ npm start 30 4 12 2.5
Here 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<ICalculator>
type. Also, the Driver<ICalculator>
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
import { WebSocketServer } from "tgrid";
export const webSocketServerMain = async () => {
const server: WebSocketServer<
null, // header
Calculator, // provider for remote client
null // provider from remote client
> = new WebSocketServer();
await server.open(37_000, async (acceptor) => {
const provider: Calculator = new Calculator();
await acceptor.accept(provider); // ACCEPT CONNECTION
acceptor.ping(15_000); // PING REPEATEDLY TO KEEP CONNECTION
});
return server;
};
class Calculator {
public plus(x: number, y: number): number {
return x + y;
}
public minus(x: number, y: number): number {
return x - y;
}
public multiply(x: number, y: number): number {
return x * y;
}
public divide(x: number, y: number): number {
return x / y;
}
}
Here 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<ICalculator>
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 asynchronous operations perform by the network communication, and Driver
is a type changing every function's return type to be asynchronous (Promise<R>
) in such reason.
This is the RPC (Remote Procedure Call) of TGrid
.
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.
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 provider: ICalcEventListener = {
on: (evt: ICalcEvent) => stack.push(evt),
};
const connector: WebSocketConnector<
ICalcConfig,
ICalcEventListener,
ICompositeCalculator
> = new WebSocketConnector(
{ precision: 2 }, // header
provider, // 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);
};