๐Ÿ“– 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.

๐Ÿ’ป

Demonstration

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

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

Client Program

examples/remote-function-call/src/client.ts
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

examples/remote-function-call/src/server.ts
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);
  });
  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 asynchrounous 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.

examples/websocket/src/client.ts
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);
};