Usage
object: rpc (Remote Procedure Call)
rpc object exposes trust-safe properties, functions and events to provide reliable two-way messaging (request-response) between multiple endpoints allowing you to build sophisticated asynchronous interactions.
Concepts
- Client application allows you to execute RPC functions exposed by server applications.
- Client application is called CALLEE and the server application is called CALLER.
- Client application will execute a remote function by passing IN.paramter, and a timeout
- The server application's corresponding function will be invoked with the IN.parameter and it will respond with response() or exception() which will be delivered back to the CALLEE client application by dataBridges network completing the request-response communication.
- Client application need not be aware about RPC servers identity and will only interact with RPC server namespace. The dataBridges network will intelligently route and load balance RPC call() to the RPC server application. The dataBridges network will automatically load balance multiple instance of server application exposing the same RPC endpoints.
- Trust-tokens are supported by RPC as well. You will need to pass a trust-token when you connect to the access controlled RPC endpoint. A trust-token is a JWT document created using a combination of rpc server endpoint / server name + sessionid + app.secret.
- Use your existing access control, authorization and session identification rule-set, process and methods to create a trust-token instructing the dataBridges router to accept the pvt: prs: rpc endpoint/server connection of from client application.
- Trust-tokens allows you to enable secured, access controlled and compliance driven reliable two-way messaging (request-response) in your existing and new initiative applications.
Connect to Server
To use rpc functions, the application has to connect to the rpc endpoint/server. This is done using connect()
function explained below.
connect()
The default method for connecting to a rpc endpoint/server involves invoking the rpc.connect
function of your dataBridges object.
Parameter | Rules | Description |
---|---|---|
string | serverName **OR* pvt:**serverName **OR **prs:**serverName* | *server*Name to which connection to be done. |
Return Type | Description |
---|---|
object | rpcObject which events and related functions can be bound to. |
Exceptions:
Source | Code | Message | Description |
---|---|---|---|
DBLIB_RPC_CONNECT | INVALID_SERVERNAME | Applicable for below conditions 1. serverName is not defined. 2. serverName validation error, length of serverName greater than 64 3. serverName validation error, serverName fails a-zA-Z0-9\.:_- validation.4. serverName contains : and first token is not pvt,prs . | |
DBLIB_RPC_CONNECT | NETWORK_DISCONNECTED | Connection to dataBridges network is not active. | |
DBNET_RPC_CONNECT | ERR_FAIL_ERROR | dataBridges network encountered error during current operation. | |
DBNET_RPC_CONNECT | ERR_ACCESS_DENIED | dataBridges network reported access violation with access_token function during current operation.Verify if appKey has sufficient publish grants. Login to management portal. Select Edit Key option and check Allow key to access RPC functions is selected. |
Server Information
isOnline()
rpcObject provides a function to check if the channel is online.
Parameter | Rules | Description |
---|---|---|
string | serverName **OR* pvt:**serverName **OR **prs:**serverName* | *server*Name to which subscription to be done. |
Return Values | Description |
---|---|
boolean | Is the current status of server connection online or offline. |
getServerName()
rpcObject provides a function to get the serverName.
Return Type | Description |
---|---|
string | serverName of connected rpcServer. |
Execute Remote Procedure Call
call()
rpcObject call() function allows you to execute a remote function hosted by RPC endpoint / server using dataBridges server library
- passing function parameter as parameter
- while setting an time to live (TTL) for the response
The RPC call() functions supports multi-part response (where the RPC function can send back multiple responses to a single RPC function call) along with exception routine.
rpcClient.call(functionName, parameter, ttlms, (response) => {
console.log('multipart response',response)
}).then((response) => {
console.log('end response', response);
}).catch((err) => {
console.log('exception',err.source, err.code, err.message);
});
//Below example how a client can connect to a RPC endpoint / Server called mathServer and use add, multiply functions.
try {
const myMathServer = dbridge.rpc.connect('mathServer');
} catch (err) {
console.log(err.source, err.code, err.message);
}
let obj = { "num1":44.5, "num2":30};
let inparam = JSON.stringify(obj);
myMathServer.call(add, inparam, ttlms, (response) => {
}).then((response) => {
console.log('response: ', JSON.parse(response));
}).catch((err) => {
console.log('exception',err.source, err.code, err.message);
});
myMathServer.call(multiply, inparam, ttlms, (response) => {
}).then((response) => {
console.log('response: ', JSON.parse(response));
}).catch((err) => {
console.log('exception',err.source, err.code, err.message);
});
rpcClient.call(functionName, parameter, ttlms, (response) => {
console.log('multipart response',response)
}).then((response) => {
console.log('end response', response);
}).catch((err) => {
console.log('exception',err.source, err.code, err.message);
});
//Below example how a client can connect to a RPC endpoint / Server called mathServer and use add, multiply functions.
try {
const myMathServer = dbridge.rpc.connect('mathServer');
} catch (err) {
console.log(err.source, err.code, err.message);
}
let obj = { "num1":44.5, "num2":30};
let inparam = JSON.stringify(obj);
myMathServer.call(add, inparam, ttlms, (response) => {
}).then((response) => {
console.log('response: ', JSON.parse(response));
}).catch((err) => {
console.log('exception',err.source, err.code, err.message);
});
myMathServer.call(multiply, inparam, ttlms, (response) => {
}).then((response) => {
console.log('response: ', JSON.parse(response));
}).catch((err) => {
console.log('exception',err.source, err.code, err.message);
});
def progress(response):
print("multipart: " , response)
def onResult(response):
print("response: ", response)
def onError(error):
print(error.code, error.source, error.message)
try:
p = await rpcClient.call("functionName" , parameter , 10000, progress)
p.then(onResult).catch(onError)
except dBError as e:
print(e.code, e.source, e.message)
# Below example how a application can connect to a RPC endpoint / Server called mathServer and use add, multiply functions.
try:
myMathServer = dbridge.rpc.connect('mathServer');
except dBError as e:
print(e.code, e.source, e.message)
obj = { "num1":44.5, "num2":30};
inparam = json.dumps(obj);
try:
p = await myMathServer.call(add , inparam , 10000, progress)
p.then(onResult).catch(onError)
q = await myMathServer.call(multiply , inparam , 10000, progress)
q.then(onResult).catch(onError)
except dBError as e:
print(e.code, e.source, e.message)
using RSG;
using dBridges.remoteprocedure;
Action<object> iprogress;
IPromise<object> p = rpcClient.call(functionName, parameter, ttlms, iprogress = (response) => {
Console.WriteLine("multipart response {0}",response)
});
p.Then((response) => {
Console.WriteLine("end response {0}", response)
}).Catch((err) => {
Console.WriteLine("exception {0}", err);
});
//Below example how a application can connect to a RPC endpoint / Server called mathServer and use add, multiply functions.
try {
CrpCaller myMathServer = dbridge.rpc.connect('mathServer');
}catch (dBError err) {
Console.WriteLine("{0} , {1} , {2}" , err.source, err.code, err.message);
}
Dictionary<string , int> obj = new Dictionary<string,int32>() { {"num1",44.5} , {"num2",30} };
inparam = new JavaScriptSerializer().Serialize(obj);
Action<object> iprogress;
IPromise<object> p = myMathServer.call("add", inparam, ttlms, iprogress = (response) => {
Console.WriteLine("multipart response {0}",response)
});
p.Then((response) => {
Console.WriteLine("end response {0}", response)
}).Catch((err) => {
Console.WriteLine("exception {0}", err);
});
Action<object> iprogress;
IPromise<object> p = myMathServer.call("multiply", inparam, ttlms, iprogress = (response) => {
Console.WriteLine("multipart response {0}",response)
});
p.Then((response) => {
Console.WriteLine("end response {0}", response)
}).Catch((err) => {
Console.WriteLine("exception {0}", err);
});
rpcClient.call(functionName, parameter, 2000, new callResponse() {
@Override
public void onResult(String response, boolean isEnd) {
if(!isEnd){
Log.i("inprogress response :" , response)
}else{
Log.i("final response:" , response)
}
}
@Override
public void onError(dBError dberror) {
Log.d("Main", "Exception :" + dberror.code + " , " + dberror.source);
}
});
//Below example how a application can connect to a RPC endpoint / Server called mathServer and use add, multiply functions.
try {
rpCaller myMathServer = dbridge.rpc.connect("mathServer");
} catch (dBError dberror) {
Log.d("Main", " exception: " + dberror.code + "::" + dberror.source);
}
JSONObject obj = new JSONObject()
obj.put("num1", 44.5);
obj.put("num2", 30);
String inparam = obj.toString();
myMathServer.call(add, inparam, 2000, new callResponse() {
@Override
public void onResult(String response, boolean isEnd) {
if(!isEnd){
Log.i("inprogress response :" , response)
}else{
Log.i("final response:" , response)
}
}
@Override
public void onError(dBError dberror) {
Log.d("Main", "Exception :" + dberror.code + " , " + dberror.source);
}
});
myMathServer.call(multiply, inparam, 2000, new callResponse() {
@Override
public void onResult(String response, boolean isEnd) {
if(!isEnd){
Log.i("inprogress response :" , response)
}else{
Log.i("final response:" , response)
}
}
@Override
public void onError(dBError dberror) {
Log.d("Main", "Exception :" + dberror.code + " , " + dberror.source);
}
});
do {
rpcClient.call(functionName, "", 10000, { (response: Any) in
print("inprogress response: \(response)")
}).done((response:Any) => {
print("response: \( response)")
}).catch(err:Any) {
print("\(err.source), \(err.code), \(err.message)")
})
} catch {
let db = error as? dBError
print(db?.ToString() ?? "unknown")
}
//Below example how a client can connect to a RPC endpoint / Server called mathServer and use add, multiply functions.
do {
var mathServer:rpcClient = dbridge.rpc.connect("mathServer")
} catch (error) {
let dberror = error as? dBError
print("Main", " exception: " + dberror.code + "::" + dberror.source)
}
let obj:[String:Double] = { "num1":44.5, "num2":30};
do {
let data = try JSONSerialization.data(withJSONObject: obj, options: JSONSerialization.WritingOptions.prettyPrinted)
let inparam = String(data: data, encoding: String.Encoding.utf8)
print(convertedString ?? "defaultvalue")
} catch let myJSONError {
print(myJSONError)
}
do {
mathServer.call(add, inparam, 2000, { (response: Any) in
print("inprogress response: \(response)")
}).done((response:Any) => {
print("response: \( response)")
}).catch(err:Any) {
print("\(err.source), \(err.code), \(err.message)")
})
} catch {
let db = error as? dBError
print(db?.ToString() ?? "unknown")
}
do {
mathServer.call(multiply, inparam, 2000, { (response: Any) in
print("inprogress response: \(response)")
}).done((response:Any) => {
print("response: \( response)")
}).catch(err:Any) {
print("\(err.source), \(err.code), \(err.message)")
})
} catch {
let db = error as? dBError
print(db?.ToString() ?? "unknown")
}
Parameter | Expected Value | Description |
---|---|---|
functionName | functionname | (string) Function name as defined in rpc endpoint/ Server . Note - RPC endpoint / server can expose multiple rpc functions. |
parameter | function parameter | (string) if multiple parameters to be passed, This can be done by putting it into array or json and stringify the object. |
ttlms | 1000 | (integer) Time to live in millisecond, timeout value before the call() function throws error timeout. |
Return Values | Description |
---|---|
string | Multi-part or final response. in case of error, dberror object is returned. |
Exceptions:
Source | Code | Description |
---|---|---|
DBNET_RPC_CALL | NETWORK_DISCONNECTED | Connection to dataBridges network is not active. |
DBNET_RPC_CALL | RESPONSE_TIMEOUT | call() response not received within defined ttlms . |
DBLIB_RPC_CALL | ID_GENERATION_FAILED | Internal Library error. |
DBNET_RPC_CALL | ERR_ACCESS_DENIED | dataBridges network reported access violation with access_token function during current operation.Verify if appKey has sufficient publish grants. Login to management portal. Select Edit Key option and check Allow key to access RPC functions is selected. |
DBRPCCALLEE_RPC_CALL | ERR_error_code | This indicates an exception encountered by the remote RPC function. ERR_error_code will have the details. |
DBNET_RPC_CALL | CLE_NR_10865 | rpc endpoint / server disconnected from dataBridges network. Try again. |
DBNET_RPC_CALL | CLE_NR_30391 | rpc endpoint / server disconnected from dataBridges network. Try again. |
DBNET_RPC_CALL | CLE_QX_41074 | Cannot process the call() because the RPC server (in this case CALLEE) has exceeded outstanding pending rpc call() queue limit. |
DBNET_RPC_CALL | CLE_QX_49467 | Cannot process the call() because the RPC server (in this case CALLEE) has exceeded outstanding pending rpc call() queue limit. |
DBNET_RPC_CALL | CLR_QX_39305 | Cannot process the call() because the application (in this case CALLER) has exceeded outstanding pending rpc call() queue limit. |
DBNET_RPC_CALL | CLR_QX_39824 | Cannot process the call() because the application (in this case CALLER) has exceeded outstanding pending rpc call() queue limit. |
DBNET_RPC_CALL | RE_28710 | rpc endpoint / server disconnected from dataBridges network. Try again. |
DBNET_RPC_CALL | AD_48621 | Application does not have access to execute rpc functions. |
System events for rpc object
There are a number of events which are triggered internally by the library, but can also be of use elsewhere. Below are the list of all events triggered by the library.
Below syntax is same for all system events.
// Binding to systemevent on rpcObject
try {
rpcObject.bind('eventName', (payload, metadata) => {
console.log( payload, metadata);
});
} catch(err) {
console.log(err.source, err.code, err.message);
}
// Binding to systemevent on dbridgeObject
try {
dbridge.channel.bind('eventName', (payload, metadata) => {
console.log( payload, metadata);
});
} catch(err) {
console.log(err.source, err.code, err.message);
}
// Binding to systemevent on rpcObject
try {
rpcObject.bind('eventName', (payload, metadata) => {
console.log( payload, metadata);
});
} catch(err) {
console.log(err.source, err.code, err.message);
}
// Binding to systemevent on dbridgeObject
try {
dbridge.channel.bind('eventName', (payload, metadata) => {
console.log( payload, metadata);
});
} catch(err) {
console.log(err.source, err.code, err.message);
}
// Binding to systemevent on rpcObject
try {
Action<object ,object> ieventstatus;
rpcClient.bind('eventName', ieventstatus = (object payload, object metadata) => {
Console.WriteLine("{0} , {1}", payload, metadata);
});
} catch (dBError err) {
Console.WriteLine("{0} , {1} , {2}" , err.source, err.code, err.message);
}
// Binding to systemevent on dbridgeObject
try {
Action<object ,object> ieventstatus;
dbridge.rpc.bind('eventName', ieventstatus = (object payload, object metadata) => {
Console.WriteLine("{0} , {1}", payload, metadata);
});
} catch (dBError err) {
Console.WriteLine("{0} , {1} , {2}" , err.source, err.code, err.message);
}
// Binding to systemevent on channelObject
rpcClient.bind("eventName" , new eventHandler() {
@Override
public void onEvent(Object message, metaData metadata) {
Log.i("event: ", message);
Log.i("event: ", metadata);
}
});
// Binding to systemevent on dbridgeObject
dbridge.rpc.bind("eventName" , new eventHandler() {
@Override
public void onEvent(Object message, metaData metadata) {
Log.i("event: ", message);
Log.i("event: ", metadata);
}
});
// Binding to systemevent on rpcObject
rpcClient.bind('eventName' , { (message: Any , metadata: Any ) in
print("event: ", message)
print("event: ", metadata)
})
// Binding to systemevent on dbridgeObject
dbridge.rpc.bind('eventName' , { (message: Any , metadata: Any ) in
print("event: ", message)
print("event: ", metadata)
})
Callback out parameter payload, metadata
details are explained with each event below in this document.
Exceptions:
Source | Code | Description |
---|---|---|
DBLIB_RPC_BIND | INVALID_EVENTNAME | Invalid Event name. Not in default events. |
DBLIB_RPC_BIND | INVALID_CALLBACK | Callback is not a function or is not defined. |
bind_all
and unbind_all
bind_all
and unbind_all
work much like bind
and unbind
, but instead of only firing callbacks on a specific event, they fire callbacks on any event, and provide that event in the metadata to the handler along with the payload.
// Binding to all rpc events on rpcObject
try {
rpcObject.bind_all((payload, metadata) => {
console.log(payload, metadata);
});
} catch(err){
console.log(err.source, err.code, err.message);
}
// Binding to all rpc events on dbridgeObject
try {
dbridge.rpc.bind_all((payload, metadata) => {
console.log(payload, metadata);
});
} catch(err){
console.log(err.source, err.code, err.message);
}
// Binding to all rpc events on rpcObject
try {
rpcObject.bind_all((payload, metadata) => {
console.log(payload, metadata);
});
} catch(err){
console.log(err.source, err.code, err.message);
}
// Binding to all rpc events on dbridgeObject
try {
dbridge.rpc.bind_all((payload, metadata) => {
console.log(payload, metadata);
});
} catch(err){
console.log(err.source, err.code, err.message);
}
# Binding to rpc events on rpcObject
def eventFunction(payload , metadata):
print(payload , metadata)
try:
rpcObject.bind_all('event', eventFunction)
except dBError as e:
print(e.code, e.source, e.message)
# Binding to rpc events on dbridgeObject
try {
dbridge.rpc.bind_all('event', eventFunction)
except dBError as e:
print(e.code, e.source, e.message)
// Binding to all rpc events on rpcObject
try {
Action<object , object> irpcstatus;
rpcObject.bind_all(irpcstatus = (payload, metadata) => {
Console.WriteLine("{0} , {1} " , payload, metadata);
});
} catch (dBError err) {
Console.WriteLine("{0} , {1} , {2}" , err.source, err.code, err.message);
}
// Binding to all rpc events on dbridgeObject
try {
Action<object , object> irpcstatus;
dbridge.rpc.bind_all(irpcstatus = (payload, metadata) => {
Console.WriteLine("{0} , {1} " , payload, metadata);
});
} catch (dBError err) {
Console.WriteLine("{0} , {1} , {2}" , err.source, err.code, err.message);
}
// Binding to rpc events on rpcObject
rpcObject.bind_all(event , new eventHandler() {
@Override
public void onEvent(Object message, metaData metadata) {
Log.i("event: ", message);
Log.i("event: ", metadata);
}
});
// Binding to rpc events on dbridgeObject
dbridge.rpc.bind_all(event , new eventHandler() {
@Override
public void onEvent(Object message, metaData metadata) {
Log.i("event: ", message);
Log.i("event: ", metadata);
}
});
// Binding to rpc events on rpcObject
rpcObject.bind_all(event , { (message: Any , metadata: Any ) in
print("event: ", message)
print("event: ", metadata)
})
// Binding to rpc events on dbridgeObject
dbridge.rpc.bind_all(event , { (message: Any , metadata: Any ) in
print("event: ", message)
print("event: ", metadata)
})
Callback out parameter payload, metadata
details are explained with each event below in this document.
Exceptions:
Source | Code | Description |
---|---|---|
DBLIB_CONNECT_BIND | INVALID_CALLBACK | If "callback function" is not declared or typeof() variable defined is not a "function". |
unbind_all
works similarly to unbind
.
// Remove just `handler` across the rpc server
rpcObject.unbind_all(handler);
//Remove all handlers for the all event in the subscribed/connected rpc server
rpcObject.unbind_all();
// Remove `handler` across the subscribed/connected rpc servers
dbridge.rpc.unbind_all(handler);
// Remove all handlers for all events across all subscribed/connected rpc servers
dbridge.rpc.unbind_all();
// Remove just `handler` across the rpc server
rpcObject.unbind_all(handler);
//Remove all handlers for the all event in the subscribed/connected rpc server
rpcObject.unbind_all();
// Remove `handler` across the subscribed/connected rpc servers
dbridge.rpc.unbind_all(handler);
// Remove all handlers for all events across all subscribed/connected rpc servers
dbridge.rpc.unbind_all();
# Remove just `handler` across the rpc server
rpcObject.unbind_all(handler)
# Remove all handlers for the all event in the subscribed/connected rpc server
rpcObject.unbind_all()
# Remove `handler` across the subscribed/connected rpc servers
dbridge.rpc.unbind_all(handler)
# Remove all handlers for all events across all subscribed/connected rpc servers
dbridge.rpc.unbind_all()
// Remove just `handler` across the rpc server
rpcObject.unbind_all(handler);
//Remove all handlers for the all event in the subscribed/connected rpc server
rpcObject.unbind_all();
// Remove `handler` across the subscribed/connected rpc servers
dbridge.rpc.unbind_all(handler);
// Remove all handlers for all events across all subscribed/connected rpc servers
dbridge.rpc.unbind_all();
// Remove just `handler` across the rpc server
rpcObject.unbind_all(eventHandler)
// Remove all handlers for the all event in the subscribed/connected rpc server
rpcObject.unbind_all()
// Remove `handler` across the subscribed/connected rpc servers
dbridge.rpc.unbind_all(eventHandler)
// Remove all handlers for all events across all subscribed/connected rpc servers
dbridge.rpc.unbind_all()
// Remove just `handler` across the rpc server
rpcObject.unbind_all(eventHandler)
// Remove all handlers for the all event in the subscribed/connected rpc server
rpcObject.unbind_all()
// Remove `handler` across the subscribed/connected rpc servers
dbridge.rpc.unbind_all(eventHandler)
// Remove all handlers for all events across all subscribed/connected rpc servers
dbridge.rpc.unbind_all()
dridges:rpc.server.connect.success
Callback parameters
payload:
null
metadata (dict)
:
{
"servername": "serverName" , // (string) serverName to which connection is done.
"eventname": "dbridges:rpc.server.connect.success", // (string) eventName
}
dbridges:rpc.server.connect.fail
Callback parameters
payload: (dberror object)
{
"source": "DBLIB_RPC_CONNECT" , // (string) Error source
"code": "ACCESS_TOKEN_FAIL", // (string) Error code
"message": "" // (string) Error message if applicable.
}
metadata (dict)
:
{
"servername": "serverName" , // (string) serverName to which connection is done.
"eventname": "dbridges:rpc.server.connect.fail",// (string) eventName
}
dbridges:rpc.server.online
Callback parameters
payload:
null
metadata (dict)
:
{
"servername": "serverName" , // (string) serverName to which connection is done.
"eventname": "dbridges:rpc.server.online", // (string) eventName
}
dbridges:rpc.server.offline
Callback parameters
payload:
null
metadata (dict)
:
{
"servername": "serverName" , // (string) serverName to which connection is done.
"eventname": "dbridges:rpc.server.offline",// (string) eventName
}
dberror:
Source | Code | Message | Description |
---|---|---|---|
DBLIB_RPC_CONNECT | ACCESS_TOKEN_FAIL | Specific to private (pvt:) or presence (prs: ) rpc call. Access token validation failed at dataBridges network. | |
DBLIB_RPC_CONNECT | ACCESS_DENIED | error_message | Specific to private (pvt:) or presence (prs: ) rpc call. This is returned by the access_token function execution before call() is made. |