# Overview [![Build Status](https://www.bottleneck.me/api/badges/frontwork-vendor/rpclibrary/status.svg)](https://www.bottleneck.me/frontwork-vendor/rpclibrary) [![npm version](https://badge.fury.io/js/rpclibrary.svg)](https://badge.fury.io/js/rpclibrary) rpclibrary is a websocket on steroids! # How to install ``` npm i rpclibrary ``` # Quickstart ```typescript import {RPCServer, RPCSocket} from 'rpclibrary' const port = 1234 const host = 'locahost' const echo = (x) => x const server = new RPCServer(port, [{ name: 'HelloWorldRPCGroup', exportRPCs: () => [ echo, //named function variable function echof(x){ return x }, //named function { name: 'echoExplicit', //describing object call: async (x) => x } ] }]) const client = new RPCSocket(port, host) client.connect().then(async () => { const r0 = await client['HelloWorldRPCGroup'].echo('Hello') const r1 = await client['HelloWorldRPCGroup'].echof('World') const r2 = await client['HelloWorldRPCGroup'].echoExplicit('RPC!') console.log(r0,r1,r2) //Hello World RPC! }) ``` # Using callbacks rpclibrary offers a special type of call that can be used with callbacks. The callback **has to be the last argument** and **may be the only passed function**. In order to function, some metadata has to be included in the return value of hooks. On success, the function is expected to return a `{ result: 'Success', uuid: string }` (Types.SubscriptionResponse) or in case of errors a `{ result: 'Error' }`(Types.ErrorResponse). The uuid, as the name implies, is used to uniquely identify the callback for a given invocation and also dictates the name given to the client-side RPC. Unless you got a preferred way of generating these (e.g. using some kind of unique information important to your task) we recommend [uuid](https://www.npmjs.com/package/uuid) for this purpose. You should unhook the client socket once you're done with it as not to cause security or control flow issues. ```typescript import {RPCServer, RPCSocket} from 'rpclibrary' const port = 1234 const host = 'locahost' const callbacks:Map = new Map() new RPCServer(port, [{ name: 'HelloWorldRPCGroup', exportRPCs: () => [ function triggerCallbacks(...messages){ callbacks.forEach(cb => cb.apply({}, messages)) }, { name: 'subscribe', hook: async (callback) => { const randStr = 'generate_a_random_string_here' callbacks.set(randStr, callback); return { result: 'Success', uuid: randStr} } },{ name: 'unsubscribe', call: async (uuid) => { callbacks.delete(uuid) } } ] }]) const client = new RPCSocket(port, host) client.connect().then(async () => { const res = await client['HelloWorldRPCGroup'].subscribe(async (...args:any) => { console.log.apply(console, args) /* close the callbacks once you're done */ await client['HelloWorldRPCGroup'].unsubscribe(res.uuid) client.unhook(res.uuid) }) await client['HelloWorldRPCGroup'].triggerCallbacks("Hello", "World", "Callbacks") }) ``` If you need to include further response data into your `SubscriptionResponse` you can extend it using the server's first generic parameter `SubResType` ```typescript new RPCServer<{extension: string}>(port, [{ name: 'MyRPCGroup', exportRPCs: () => [{ name: 'subscribe', hook: async (callback) => { return { result: 'Success', uuid: 'very_random_string', extension: 'your_data_here' //tsc will demand this field } } }]} ]) ``` #Experimental typing support It is possible to declare pseudo-interfaces for servers and clients by using server's second generic parameter. This feature is currently still in development and considered **unstable and untested**. Use with caution. ```typescript type MyInterface = { Group1: { triggerCallbacks: (...args:any[]) => Promise, subscribe: (param:string, callback:Function) => Promise>, unsubscribe: (uuid:string) => Promise }, Group2: { echo: (x:string) => Promise } } ``` Create a client using ```typescript RPCSocket.makeSocket(port, host).then((async (client) => { const r = await client.Group2.echo("hee") //tsc knows about available RPCs })) /* OR */ const client = new RPCSocket(port, host) client.connect().then((async (client) => { const r = await client.Group2.echo("hee") //tsc knows about available RPCs })) ``` Create a server using ```typescript new RPCServer<{a:string}, MyInterface>(port, [{ //... },{ name: 'Group2', //Auto completion for names exportRPCs: () => [{ name: 'echo', //this name too! call: async (x) => x+"llo World!" //the paramter and return types are known by tsc }] }] ) ``` # [Full documentation](https://www.versioncontrol.me/frontwork-documentation/rpclibrary)