Eider

Eider is an object-oriented, asynchronous, late-binding, web-first, polyglot RPC protocol. Eider is also the name of the reference implementations in Python and JavaScript.

Out of the box, Eider uses WebSockets for transport and JSON or MessagePack for serialization. The core protocol and concepts are transport- and format-neutral.

With Eider, developing applications that combine server-side, client-side, and in-browser code is duck soup!

Installation

Python

Requires Python 3.4+ and aiohttp. Includes elective support for MessagePack using msgpack-python, if available.

pip install eider

You can also check out the source code on GitHub.

JavaScript

Works in Node.js 6+, modern browsers, and any other environment that supports ES6.

No external libraries are strictly required. Elective support is included for WebSocket creation using ws and MessagePack using msgpack-lite, if available. Implicit remote garbage collection is supported if the weak package is available.

npm install eider-rpc

For the browser: eider-rpc.min.js.

You can also check out the source code on GitHub.

C++

The eider-pybind11 project provides a simple header file that can enable classes implemented in C++ to be served over Eider connections using pybind11.

Getting Started

Here is a simple server in Python (simple_server.py):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import eider

class DuckTester(eider.LocalRoot):
    
    def is_it_a_duck(self, obj):
        return (obj['looks'] == 'like a duck' and
            obj['swims'] == 'like a duck' and
            obj['quacks'] == 'like a duck')

eider.serve(12345, root=DuckTester)

And here is an equivalent server in JavaScript (simple_server.js):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let Eider = require('eider-rpc');

class DuckTester extends Eider.LocalRoot {
    is_it_a_duck(obj) {
        return obj.looks === 'like a duck' &&
            obj.swims === 'like a duck' &&
            obj.quacks === 'like a duck';
    }
}

Eider.serve(12345, {root: DuckTester});

Here is how the core of the Python server could be written in C++ (simple_server.cpp):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <eider_pybind11.hpp>

using namespace eider_pybind11;

struct DuckTester : LocalRoot {
    DuckTester(py::object lsession) {
        LocalRoot::init(lsession);
    }

    bool is_it_a_duck(py::object obj) {
        return std::string(py::str(obj["looks"])) == "like a duck" &&
            std::string(py::str(obj["swims"])) == "like a duck" &&
            std::string(py::str(obj["quacks"])) == "like a duck";
    }
};

PYBIND11_MODULE(ducktest, m) {
    bind(m);

    py::class_<DuckTester, LocalRoot>(m, "DuckTester")
        .def(py::init<py::object>())
        .def("is_it_a_duck", &DuckTester::is_it_a_duck);
}

Here is a client in Python (simple_client.py):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import eider

how = 'like a duck'
obj = {'looks': how, 'swims': how, 'quacks': how}

with eider.BlockingConnection('ws://localhost:12345') as conn:
    with conn.create_session() as duck_tester:
        is_duck = duck_tester.is_it_a_duck(obj)

print("It's probably " + ("" if is_duck else "NOT ") + "a duck.")

And here is an equivalent client in JavaScript (simple_client.html):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<script src="eider-rpc.min.js"></script>
<script type="text/javascript">
    let how = 'like a duck';
    let obj = {looks: how, swims: how, quacks: how};
    Eider.using(Eider.connect('ws://localhost:12345'), conn =>
        Eider.using(conn.createSession(), duckTester =>
            duckTester.is_it_a_duck(obj)
        )
    ).then(isDuck => {
        alert("It's probably " + (isDuck ? '' : 'NOT ') + 'a duck.');
    });
</script>

And finally, here is a Python 3.5+ client using non-blocking APIs (simple_client_async.py):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import asyncio, eider

how = 'like a duck'
obj = {'looks': how, 'swims': how, 'quacks': how}

async def ducktest():
    async with eider.Connection('ws://localhost:12345') as conn:
        with conn.create_session() as duck_tester:
            is_duck = await duck_tester.is_it_a_duck(obj)
    
    print("It's probably " + ("" if is_duck else "NOT ") + "a duck.")

asyncio.get_event_loop().run_until_complete(ducktest())

Blame

Eider began as an internal software library at ON Semiconductor and was open-sourced under the Apache License 2.0 in April 2017.

Bart Robinson is the original author and current maintainer.

King Eider photo by Ron Knight (CC BY 2.0).