=Remote Procedure Call=
Databoard RPC is a method call interface.
Server is an object that handles service requests.
The server publishes an [[#Interfaces]] that contains a list of callable methods.
===Network Protocol===
The protocol is very simple. There are two conversing peers, one is ''the client'' and the other ''the server''.
Both parties introduce callable ''network interface''. Typically, the server's has plenty of procedures, and client's
has some callbacks.
The connection starts with handshake and is then followed by repeating conversation of writing ''Requests'' and reading ''Responses''.
In handshake, boths peers write their ''InterfaceDescription'' and message size limits.
(See [[#Definitions|Definitions]]).
Then both parties make a decision to whether accept or reject the other's interface.
=Interfaces=
''A function type'' can be constructed as D -> R, where D is the domain and R the range of the function.
If the function can throw exceptions, it is denoted as D -> R throws E1, ..., Ek, where
Ei is a datatype for an exception. Multi-parameter types can be defined using the tuple notation:
Double -> Double
() -> String
(Integer,Integer) -> Integer
Integer -> Integer throws IndexOutOfRange
''A method definition'' is a combination of name and method type.
The format is following, method M : T, where M is the name and T the type of the method.
T has to be a function type.
method getSamples : TimeSegment -> Sample[],
method read : ReadRequest -> Sample,
method getValueBounds : TimeSegment -> Sample[2]
''Interface'' is a specification of fields and methods the interface has to have.
The interface is defined as a record that contains fields and methods definitions in the curly braces.
interface HistoryRecord = {
records : TimeSeries,
method getSamples : TimeSegment -> Sample[],
method read : ReadRequest -> Sample,
method getValueBounds : TimeSegment -> Sample[2]
}
Interfaces may extend other interfaces. This is denoted as interface I extends B1, ..., Bk { ... }.
interface MutableHistoryRecord extends HistoryRecord = {
method write : Sample[] -> {},
method clear : {} -> {}
}
====Request====
Client sends RequestHeader, followed by a serialization of the message's request argument.
The datatype and thus serialization format of the request argument was defined in MethodType which was informed by the server in the handshake.
The server processes the procedure request.
* On procedure success, ResponseHeader is sent, followed by a serialization of ResponseType. ResponseType serialization format was declared in MethodType.
* On procedure failure, ExecutionError_ is sent, followed by a serialization of ErrorType. ErrorType format was declared in MethodType.
* On unexpected error, Exception_ is sent
* On invalid method number, InvalidMethodError is sent
* On request or response message size exceeded, ResponseTooLargeError is sent
==Definitions==
type Interface = {
methodDefinitions : Map(MethodTypeDefinition, {})
}
type InterfaceDefinition = {
name : String,
type : Interface
}
type MethodType = {
requestType : DataType,
responseType : DataType,
errorType : UnionType
}
type MethodTypeDefinition = {
name : String,
type : MethodType
}
type Handshake = | Version0
type Version0 = {
recvMsgLimit : Integer,
sendMsgLimit : Integer,
methods : MethodTypeDefinition[]
}
type Message = | RequestHeader RequestHeader
| ResponseHeader ResponseHeader
| ExecutionError_ ExecutionError_
| Exception_ Exception_
| InvalidMethodError InvalidMethodError
| ResponseTooLarge ResponseTooLarge
type RequestHeader = {
requestId : Integer,
methodId : Integer
}
type ResponseHeader = {
requestId : Integer
}
type ExecutionError_ = {
requestId : Integer
}
type InvalidMethodError = {
requestId : Integer
}
type Exception_ = {
requestId : Integer,
message : String
}
type ResponseTooLarge = {
requestId : Integer
}