The Web Socket related components would be implemented by extending and utilizing the Communicator and Driver classes.
Components
WebServer
namespace tgrid.protocols.web
{
export class WebServer
{
/* ----------------------------------------------------------------
CONSTRUCTORS
---------------------------------------------------------------- */
/**
* Default Constructor for the `ws` server.
*
* Create an websocket server (`ws://`).
*/
public constructor();
/**
* Initializer Constructor for the `wss` server.
*
* Create a secured websocket server (`wss://`).
*
* @param key Key string.
* @param cert Certification string.
*/
public constructor(key: string, cert: string);
/* ----------------------------------------------------------------
OPERATIONS
---------------------------------------------------------------- */
/**
* Open server.
*
* @param port Port number to listen.
* @param cb Callback function whenever client connects.
*/
public open<Ret>(port: number, cb: (acceptor: WebAcceptor) => Ret): Promise<void>;
/**
* Close server.
*/
public close(): Promise<void>;
/**
* Current state.
*/
public get state(): WebServer.State;
}
export namespace WebServer
{
export const enum State
{
NONE = -1,
OPENING,
OPEN,
CLOSING,
CLOSED
}
}
}
WebAcceptor
namespace tgrid.protocols.web
{
export class WebAcceptor
extends basic.CommunicatorBase
{
/* ----------------------------------------------------------------
CONSTRUCTORS
---------------------------------------------------------------- */
/**
* Hidden Constructor.
*
* You can't create WebAcceptor by yourself. It would be created only by the WebServer.
*/
private constructor(request);
/**
* Close connection.
*/
public close(): Promise<void>;
/* ----------------------------------------------------------------
HANDSHAKES
---------------------------------------------------------------- */
/**
* Accept connection.
*
* @param protocol Protocol you want to specialize.
* @param allowOrigin If you want to restrict connection origin, then specialize it.
* @param cookies Cookies to make client storing it.
*/
public accept(protocol?: string, allowOrigin?: string, cookies?: ICookie[]): Promise<void>;
/**
* Reject connection.
*
* @param status Status code.
* @param reason Detailed reason to reject.
* @param extraHeaders Extra heaaders if required.
*/
public reject(status?: number, reason?: string, extraHeaders?: object): Promise<void>;
/**
* Start listening.
*
* Start listening data (function requests) from the remote client.
*
* @param provider An object to provide functions for the remote client.
*/
public listen<Provider extends object>
(provider: Provider): Promise<void>;
/* ----------------------------------------------------------------
ACCESSORS
---------------------------------------------------------------- */
/**
* Get driver for remote controller.
*
* @return A driver for the remote Controller.
*/
public getDriver<Controller extends object>(): Driver<Controller>;
/**
* Join connection.
*/
public join(): Promise<void>;
//----
// PROPERTIES
//----
public get state(): State;
public get secured(): boolean;
public get path(): string;
public get protocol(): string;
public get extensions(): string;
}
export namespace WebAcceptor
{
export interface ICookie { ... };
export const enum State { ... }
}
}
WebConnector
namespace tgrid.protocols.web
{
export class WebConnector<Provider extends object>
extends basic.CommunicatorBase<Provider>
{
/* ----------------------------------------------------------------
CONSTRUCTORS
---------------------------------------------------------------- */
/**
* Initializer Constructor.
*
* @param provider A provider for server.
*/
public constructor(provier?: Provider);
/**
* Connect to remote web socket server.
*
* @param url URL address to connect.
* @param protocols Candidate protocols to specialize.
*/
public connect(url: string, protocols?: string | string[]): Promise<void>;
/**
* Close connection.
*
* @param code Closing code.
* @param reason Reason why.
*/
public close(code?: number, reason?: string): Promise<void>;
/* ----------------------------------------------------------------
ACCCSSORS
---------------------------------------------------------------- */
/**
* Get driver for remote controller.
*
* @return A driver for the remote Controller.
*/
public getDriver<Controller extends object>(): Driver<Controller>;
/**
* Wait server to provide.
*
* Wait server to specify its `Provider`.
*/
public wait(): Promise<void>;
/**
* Join connection.
*/
public join(): Promise<void>;
//----
// PROPERTIES
//----
public get state(): WebConnector.State;
public get url(): string;
public get protocol(): string;
public get extensions(): string;
}
export namespace WebConnector
{
export const enum State
{
NONE = -1,
CONNECTING,
OPEN,
CLOSING,
CLOSED
}
}
}
Sample Code
server.ts
import * as std from "tstl";
import * as tgrid from "tgrid";
import { Calculator } from ".internal/Calculator";
async function main(): Promise<void>
{
let server: WebServer = new WebServer();
await server.open(PORT, async acceptor =>
{
await acceptor.accept(); // ALLOW CONNECTION
await acceptor.listen(/calculator/.test(acceptor.path)
? new Calculator()
: new std.Vector<number>()); // SET LISTENER
});
}
client-vector.ts
import { Vector } from "tstl/container";
import { WebConnector } from "tgrid/protocols/web";
import { Driver } from "tgrid/basic";
type IVector<T> = Pick<Vector<T>, "size" | "at" | "push_back">;
async function main(): Promise<void>
{
let connector: WebConnector = new WebConnector();
await connector.connect("ws://127.0.0.1:10100");
let vec: Driver<IVector<number>> = connector.getDriver<IVector<number>>();
for (let i: number = 0; i < 5; ++i)
await vec.push_back(i);
console.log("size:", await vec.size());
for (let i: number = 0; i < await vec.size(); ++i)
console.log(" element:", await vec.at(i));
}
main();
client-calculator.ts
import { WebConnector } from "tgrid/protocols/web";
import { Driver } from "tgrid/basic";
import { ICalculator } from "./internal/Calculator";
async function main(): Promise<void>
{
//----
// PREPARES
//----
// DO CONNECT
let connector: WebConnector = new WebConnector();
await connector.connect("ws://127.0.0.1:10102");
// GET DRIVER
let calc: Driver<ICalculator> = connector.getDriver<ICalculator>();
//----
// CALL FUNCTIONS
//----
// FUNCTIONS IN THE ROOT SCOPE
console.log("1 + 6 =", await calc.plus(1, 6));
console.log("7 * 2 =", await calc.multiplies(7, 2));
// FUNCTIONS IN AN OBJECT (SCIENTIFIC)
console.log("3 ^ 4 =", await calc.scientific.pow(3, 4));
console.log("log (2, 32) =", await calc.scientific.log(2, 32));
try
{
// TO CATCH EXCEPTION IS STILL POSSIBLE
await calc.scientific.sqrt(-4);
}
catch (err)
{
console.log("SQRT (-4) -> Error:", err.message);
}
// FUNCTIONS IN AN OBJECT (STATISTICS)
console.log("Mean (1, 2, 3, 4) =", await calc.statistics.mean(1, 2, 3, 4));
console.log("Stdev. (1, 2, 3, 4) =", await calc.statistics.stdev(1, 2, 3, 4));
//----
// TERMINATE
//----
await connector.close();
}
main();
internal/Calculator.ts
/* ----------------------------------------------------------------
INTERFACES
---------------------------------------------------------------- */
export interface ICalculator
{
scientific: IScientific;
statistics: IStatistics;
plus(x: number, y: number): number;
minus(x: number, y: number): number;
multiplies(x: number, y: number): number;
divides(x: number, y: number): number;
}
export interface IScientific
{
pow(x: number, y: number): number;
sqrt(x: number): number;
log(x: number, y: number): number;
}
export interface IStatistics
{
mean(...elems: number[]): number;
stdev(...elems: number[]): number;
}
/* ----------------------------------------------------------------
CLASSES
---------------------------------------------------------------- */
export class Calculator implements ICalculator
{
public scientific = new Scientific();
public statistics = new Statistics();
public plus(x: number, y: number): number
{
return x + y;
}
public minus(x: number, y: number): number
{
return x - y;
}
public multiplies(x: number, y: number): number
{
return x * y;
}
public divides(x: number, y: number): number
{
if (y === 0)
throw new Error("Divided by zero.");
return x / y;
}
}
class Scientific implements IScientific
{
public pow(x: number, y: number): number
{
return Math.pow(x, y);
}
public log(x: number, y: number): number
{
if (x < 0 || y < 0)
throw new Error("Negative value on log.");
return Math.log(y) / Math.log(x);
}
public sqrt(x: number): number
{
if (x < 0)
throw new Error("Negative value on sqaure.");
return Math.sqrt(x);
}
}
class Statistics implements IStatistics
{
public mean(...elems: number[]): number
{
let ret: number = 0;
for (let val of elems)
ret += val;
return ret / elems.length;
}
public stdev(...elems: number[]): number
{
let mean: number = this.mean(...elems);
let ret: number = 0;
for (let val of elems)
ret += Math.pow(val - mean, 2);
return Math.sqrt(ret / elems.length);
}
}
Outline
TGrid will support the Web Socket protocol.
The Web Socket related components would be implemented by extending and utilizing the Communicator and Driver classes.
Components
WebServer
WebAcceptor
WebConnector
Sample Code
server.ts
client-vector.ts
client-calculator.ts
internal/Calculator.ts