jaysonrpc

Search:
Group by:
Source   Edit  

This is an implementation of the JSON-RPC protocol.

Example:

import jaysonrpc
import std/sugar # for collect:

var rpc = initExecutor[JsonNode, void]()

rpc.on("hello") do (x: string) -> string:
  return x

# Data then needs to come in as a string
let rawJson = $ %* {"jsonrpc": "2.0", "method": "hello", "params": ["world"], "id": 1}
# You get a series of calls from the json
let calls = rpc.getCalls(rawJson)
assert calls.len == 1 # This is not a batch call, so we have one call
# These functions can be called however you want, they are thread safe and handle everything themselves
let responses = collect:
  for call in calls:
    call()
# Once you collect them back, you can send back a response
echo calls.dump(responses)

Types

ConstructedCall[R] = object
Call that has parameters applied, can then be called without needing the original request. If this returns none then a response shouldn't be sent Source   Edit  
Context[C] = object
  data*: C                   ## Optional metadata attached to the request by the server
Source   Edit  
Error = object
  code*: RPCErrorCode        ## Code relating to the error
  message*: string           ## Message providing a human description of the message
  data*: JsonNode            ## Extra metadata to store about the message
Error object. Can store extra metadata in data that is understood by the handler Source   Edit  
Executor[R; C] = object
Executor stores all the functions, this can then be queried later to get the function to then pass to your favourite executor Source   Edit  
ID {..} = object of CaseObject[IDTag_553648149]
  case kind*: IDTag_553648149
  of Numeric:
    numeric*: tuple[Numeric: int]
  of String:
    string*: tuple[String: string]
  of Null:
    null*: tuple[]
Source   Edit  
IDTag_553648149 = enum
  Numeric, String, Null
Source   Edit  
MethodDef[A; R] = object
  name*: string              ## Name of the method getting called
This is a definition of a method. Used to enforce a spec or for calling a pre-defined method. This has the benefit of being able to share defintions between server and client.
  • A tuple representing the args to send
Source   Edit  
Request = object
  jsonrpc* = "2.0"           ## Version, only 2.0 is implemented
  id*: Option[ID]            ## ID of the request. If missing then its a notification
  meth*: string              ## Method getting called
  params*: SentParameters
A request sent to the server Source   Edit  
Response = object
  id*: ID                    ## A response always has an ID since notifications have nothing sent
  result*: RPCResult         ## Either the result of the call or any error that occured
Response sent back to the caller. Is possible that it contains an error Source   Edit  
RPCError = object of CatchableError
  code*: RPCErrorCode        ## Corresponding error code defined in the spec
  id*: Option[ID]            ## Request that the failure occured in.
                             ## "If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null."
Exception to throw about an error Source   Edit  
RPCErrorCode = distinct int
Error codes for JSONRPC. Stored as distinct int instead of enum so that it can be extended Source   Edit  
RPCResult = Result[JsonNode, Error]
Source   Edit  
TypedRequest[R] = distinct Request
Request but has type info associated on what the expected return type is. Used when sending a call to a remote server Source   Edit  

Consts

InvalidParams = -32602
Parameters passed were invalid Source   Edit  
InvalidRequest = -32600
Request object was invalid Source   Edit  
MethodNotFound = -32601
Executor couldn't find the method Source   Edit  
ParseError = -32700
Error when trying to parse incoming JSON Source   Edit  
ServerError = -32603
Error from internal handler Source   Edit  

Procs

proc `$`(code: RPCErrorCode): string {.borrow, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc `%`(code: RPCErrorCode): JsonNode {.borrow, ...raises: [], tags: [],
    forbids: [].}
Source   Edit  
func `()`[R](call: ConstructedCall[R]): Option[R]
Helper function that calls the internal proc Source   Edit  
func `==`(a, b: RPCErrorCode): bool {.borrow, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc call[A, R](def: MethodDef[A, R]; args: A): TypedRequest[R] {.inline.}
Returns the proc for calling a method Source   Edit  
func call[R](call: ConstructedCall[R]): ConstructedCallProc[R]
Returns the proc that you call to get the response Source   Edit  
func cancel(ctx: Context; id: ID)
Cancels an in-progress request. Does nothing if there is no request associated with that ID Source   Edit  
func checkedGet[T](data: JsonNode; key: string; into: typedesc[T]): T
Performs a checked get to access key from data and converts into T Source   Edit  
func dump(calls: RPCCalls; responses: openArray[Option[JsonNode]]): Option[
    string]
Forms a response from the responses. Responses be from the calls in calls. If return val is none() then you MUST not send a response back Source   Edit  
func fromJsonHook(id: out ID; data: JsonNode) {....raises: [RPCError], tags: [],
    forbids: [].}
Hook for parsing an ID Source   Edit  
func fromJsonHook(params: out SentParameters; data: JsonNode) {.
    ...raises: [ValueError], tags: [], forbids: [].}
Source   Edit  
func fromJsonHook(request: out Request; data: JsonNode) {.
    ...raises: [RPCError, KeyError, Exception, ValueError], tags: [RootEffect],
    forbids: [].}
Hook for parsing the JSON Source   Edit  
func fromJsonHook(response: out Response; data: JsonNode) {.
    ...raises: [RPCError, KeyError, ValueError, JsonKindError], tags: [RootEffect],
    forbids: [].}
Source   Edit  
proc getCalls[R, C](exec: Executor[R, C]; json: string; ctx: C | typedesc[void]): RPCCalls[
    R]
Returns all the calls stored in a JSON message. Once all have been ran, they should be sent back to dump Source   Edit  
proc getCalls[R](exec: Executor[R, void]; json: string): RPCCalls[R]
Source   Edit  
func id(ctx: Context): Option[ID]
Returns ID for current request Source   Edit  
func id=[R](request: var TypedRequest[R]; id: int | string)
Sets the ID for a request Source   Edit  
func initExecutor[R, C](): Executor[R, C]
Source   Edit  
func inProgress(exec: Executor): int
Returns the number of requests that are registered to be executed Source   Edit  
func isCancelled(ctx: Context): bool
Checks if the current request has been cancelled. Source   Edit  
func isCancelled(ctx: Context; requestId: ID): bool
Source   Edit  
func isNotification(x: Request): bool {....raises: [], tags: [], forbids: [].}
Checks if a request is a notification Source   Edit  
func isRunning(this: Executor): bool
Returns true if the server is considered to still be running Source   Edit  
func len(calls: RPCCalls): int
Number of calls stored Source   Edit  
func name(call: ConstructedCall): string
Returns the method that a constructed call handles Source   Edit  
func names(calls: RPCCalls): HashSet[string]
Returns the names of RPC calls Source   Edit  
proc notify[A, R](def: MethodDef[A, R]; args: A): Notification {.inline.}
Creates a notification call that can be sent Source   Edit  
proc on[R, C](exec: var Executor[R, C]; meth: string; handler: proc)
Adds a method into the executor. Overwrites a method if it already exists Source   Edit  
func shutdown(exec: Executor)
Shutdowns the executor by cancelling all in progress requests Source   Edit  
func toJsonHook(id: sink ID): JsonNode {....raises: [], tags: [], forbids: [].}
Converts an ID to JSON Source   Edit  
func toJsonHook(parameters: SentParameters): JsonNode {....raises: [], tags: [],
    forbids: [].}
Source   Edit  
func toJsonHook(request: sink Request): JsonNode {....raises: [], tags: [],
    forbids: [].}
Source   Edit  
func toJsonHook(response: sink Response): JsonNode {....raises: [KeyError],
    tags: [], forbids: [].}
Source   Edit  

Iterators

iterator items[R](calls: RPCCalls[R]): ConstructedCall[R]
Source   Edit  

Macros

macro call(prc: proc; args: tuple): untyped
Calls a proc using arguments from tuple

Example:

proc foo(a, b: int): int = a + b

assert foo.call((a: 1, b: 2)) == 3
Source   Edit