Getting started

The current verison of aiosmf only support Python-based smf clients. In order to have a working example we need a server, which can be built using C++, Go, or Java. We’ll be using the C++-based server described in this introductory smf post:

This is the rpc specification for the example server. The Put interface receives a PutRequest and returns a PutResponse. The first step in using aiosmf is compiling this specification.

namespace kvstore.fbs;

table PutRequest {
  key: string;
  value: string;
}

table PutResponse {
  text: string;
}

rpc_service MemoryNode {
  Put(PutRequest):PutResponse;
}

First use the flatbuffers compiler to generate a Python library that implements each of the PutRequest and PutResponse types.

[user@localhost testtest]$ flatc -o . --python kvstore.fbs
[user@localhost testtest]$ ls -l kvstore/fbs/
total 8
-rw-rw-r--. 1 user user    0 Mar 30 08:18 __init__.py
-rw-rw-r--. 1 user user 1277 Mar 30 08:18 PutRequest.py
-rw-rw-r--. 1 user user  939 Mar 30 08:18 PutResponse.py

Next use the smf compiler to generate a Python smf client specific to this service.

[user@localhost testtest]$ smfc --filename kvstore.fbs --language=python
[user@localhost testtest]$ ls -l kvstore/fbs/
total 12
-rw-rw-r--. 1 user user    0 Mar 30 08:18 __init__.py
-rw-rw-r--. 1 user user  420 Mar 30 08:19 kvstore_smf_client.py
-rw-rw-r--. 1 user user 1277 Mar 30 08:18 PutRequest.py
-rw-rw-r--. 1 user user  939 Mar 30 08:18 PutResponse.py

This is the contents of the generated client. The client accepts an smf connection (which we’ll discuss next), and a method for each of the service interfaces. In this case that is a single Put method.

# Generated by smfc.
# Any local changes WILL BE LOST.
# source: kvstore.fbs

import kvstore.fbs.PutResponse

class MemoryNodeClient:
    def __init__(self, conn):
        self._conn = conn

    async def Put(self, x):
        # request id = 504045560 ^ 3345117782
        buf, status = await self._conn.call(x, 3647565230)
        return kvstore.fbs.PutResponse.PutResponse.GetRootAsPutResponse(buf, 0), status

Finally we can begin building a sample client. The first thing that is done is to establish a connection to the smf server, and pass this connection to an instance of the generated client:

import asyncio
import flatbuffers
import kvstore
import aiosmf
from kvstore.fbs.kvstore_smf_client import MemoryNodeClient
import kvstore.fbs.PutRequest

async def main():
    conn = await aiosmf.create_connection("127.0.0.1:20776")
    client = MemoryNodeClient(conn)

Once the connection is established the rpc methods can be invoked. To invoke the Put method we must first create a PutRequest. This is done using the standard flatbuffers api which results in a buffer containing the serialized form of the request:

# build an rpc request buffer
builder = flatbuffers.Builder(32)
key = builder.CreateString("my.key")
value = builder.CreateString("my.value")
kvstore.fbs.PutRequest.PutRequestStart(builder)
kvstore.fbs.PutRequest.PutRequestAddKey(builder, key)
kvstore.fbs.PutRequest.PutRequestAddValue(builder, value)
put = kvstore.fbs.PutRequest.PutRequestEnd(builder)
builder.Finish(put)
buf = builder.Output()

And finally the remote method is invoked and we print out the results.

resp, status = await client.Put(buf)
print(resp.Text(), status)

The client and the connection should be shutdown to cleanup resources:

conn.close()
await conn.wait_closed()

Invoke this sample client using an asyncio loop:

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

If your server uses zstd compression add incoming and outgoing filters to the connection:

conn = await aiosmf.create_connection("127.0.0.1:20776",
    incoming_filters=(aiosmf.ZstdDecompressionFilter(),),
    outgoing_filters=(aiosmf.ZstdCompressionFilter(128),))