json-rpc

  1. json-rpc
    1. Description
    2. Author
    3. Requirements
    4. Repository
    5. Documentation and examples
      1. Client
        1. Short explanation
        2. And in more detail
      2. Server responses
      3. Server
    6. Real life example
    7. Version history
    8. License

Description

An implementation of the JSON-RPC 2.0 protocol.

Note: There is only a client implementation for now.

With this egg you can setup a connection to a JSON-RPC server and send a JSON-RPC valid string without the overhead of having to build the correctly formatted JSON string yourself. Once a connection is established, the egg will listen on the specified input port for public messages from the server and will present server responses or errors to you in CHICKEN data.

Author

Tim van der Linden

Requirements

Repository

The code is hosted on an external repository and can be found here.

Documentation and examples

Client

[procedure] (json-rpc-server [input-port] [output-port] #!key version #!key full-data #!key public-receiver #!key test-mode)
Short explanation

In short, this will return a procedure that accepts a method (as a STRING) and optional params (as KEYWORD ARGUMENTS).

Once called, this method will send a valid JSON-RPC formatted string to the server. If applicable, a server response or server error will be returned to the user.

And in more detail

You can define the connection to your JSON-RPC server with the above procedure.

When defining your connection, you have to give an OUTPUT PORT and INPUT PORT. This implementation is made for version 2.0, so the version string is already set for you as a keyword argument. If a future version is released, I'll try to make it compatible.

The following (keyword) arguments are set with a sensible default, but could be overridden when defining your connection:

For demonstration purposes: Let's define a connection to a XBMC media center, which uses JSON-RPC for its remote calls:

(define xbmc
  (json-rpc-server input output))

Once setup, this will return a procedure that accepts a method and optional params. You can then call this procedure to actually send a valid JSON-RPC formatted string to the server.

Important to note is that the method can either be given as a string or a symbol:

A notification is a way to tell the server you do not need a response to your call, as laid out in the JSON-RPC 2 spec.

Let's ask the server for a listing of the current active players:

(xbmc "Player.GetActivePlayers")

This will build the following CHICKEN data type:

((jsonrpc . 2.0)
 (method . Player.GetActivePlayers)
 (id . 1))

Then it will get formatted to valid JSON and send to the server.

The transformation from CHICKEN data types to JSON (and back) is done trough the wonderful Medea.

You can optionally include params to be send with your method. The JSON-RPC spec defines two types of params:

Let's see this in action on the same XBMC connection.

Take, for instance, sending a command to play or pause your XBMC box. Here you not only need to send the method, but also send which player you wish to pause or play. This would look something like the following:

(xbmc "Player.PlayPause" playerid: 0)

Which will be represented like so:

((jsonrpc . 2.0)
 (method . Player.PlayPause)
 (params (playerid . 0))
 (id . 1))

And finally, you can nest your params.

We now want to know the title, album and artist of a certain playlist. For this we can use a vector inside a listing of keyword arguments:

(xbmc "Playlist.GetItems" properties: '#("title" "album" "artist") playlistid: 0)

And this will become:

((jsonrpc . 2.0)
 (method . Playlist.GetItems)
 (params
  (properties: . #(title album artist)) 
  (playlistid: . 0)) 
 (id . 1))

One more, just for fun.

After getting bored of listening to music, we get an urge to make a selection of available television shows. Here we don't use a vector, but we nest keyword arguments:

(xbmc "VideoLibrary.GetTVShows" filter: '((field: . "playcount")(operator: . "is")(value: . "0")))

After transformation:

((jsonrpc . 2.0)
 (method . VideoLibrary.GetTVShows)
 (params
  (filter: 
    (field: . playcount)
    (operator: . is)
    (value: . 0)))
 (id . 1))

Server responses

By default the JSON-RPC server will respond to all requests made, unless the request is set to be a notification. The server response will be parsed and returned to you immediately as CHICKEN data.

A JSON-RPC server is also allowed to send public messages at any given point in time. The JSON-RPC egg will capture these message for you as soon as they are broadcast, but it is up to the user of this egg to decide what to do with them. For this the user can set a procedure when defining a server connection using the public-receiver keyword argument.

Server

There is no server implementation for now.

Real life example

Below is a short, start to finish example of how you can use this egg: how you can setup an input and output port, setup your connection and actually send something over that connection.

;Load in the TCP Unit and this egg
(use tcp json-rpc-client)

;Create an input and output port to a server listening at 192.168.0.10 on port 9090
(define-values (input output) 
  (tcp-connect "192.168.0.10" 9090))

;Define the connection to the server (called xbmc here)
(define xbmc
  (json-rpc-server input output))

;Send an actual, non-notification command over the connection you just made
(xbmc "Player.PlayPause" playerid: 0)

; > ((item (label . "Numina - Cold Shine") (type . "Relax music"))) ; Possible server response

;Or send the same command, but as a notification (Give the method as a symbol instead of a string)
(xbmc 'Player.PlayPause playerid: 0)

Version history

0.1.7
Implemented mailbox-threads for continuous port listening and message dispatching
0.1.6
Refactored the notification setting trough a tiny hack, giving a sensible default
0.1.5
Added JSON-RPC 2.0 spec compliant "notification" flag when sending client requests
0.1.4
Removed 'filter' and added 'remove' instead, tests now up and running correctly
0.1.3
Fixed wrong version setup number, removed 'append' and added 'filter' instead
0.1.2
Code cleanup and made 'version' an implicit argument
0.1.1
Fixed erroneous dependency.
0.1
Initial Chicken 4 release.

License

 Copyright (c) 2013, Tim van der Linden
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
 met:
 
 Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.
 
 Redistributions in binary form must reproduce the above copyright
 notice, this list of conditions and the following disclaimer in the
 documentation and/or other materials provided with the distribution.
 
 Neither the name of the author nor the names of its contributors may
 be used to endorse or promote products derived from this software
 without specific prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.