おれおれmsgpack-rpc-pythonを作る
MsgPackRPCのpythonバインディング(クライアント側)が必要になったのでmsgpack-rpc-pythonを使ってみたのだが、
GUI(pyqt)に載せて接続制御とエラーハンドリングを細やかに制御したいので俺俺で類似品を作ることにした。
tonado-msgpackと名付けて取り合えず作業開始。
https://github.com/ousttrue/tornado-msgpack
msgpack-rpc-pythonのおかげでtornadoの存在を知ったのだがtornado.ioloopが見れば見るほどboost::asioっぽい。
ということで、c++で作成中のmsgpack-rpc-asioのpython版のような感じのAPIにしてみた。
以下の点を考慮している。
tornado.ioloopを隠さない
tornado.ioloopをスレッドに乗せて回しっぱなしにする
tornado.ioloopひとつで複数の接続を扱う
dispatcherを乗せ換え易くする。
接続ステータスの変化をコールバックで受け取る
非同期リクエストのコールバックを早期にセットする
TCP以外は考慮しない
プロジェクト作成
tonado_msgpack/
setup.py
sample/
sample.py
tonado_msgpack
setup.py
from distutils.core import setup
setup(
name='tonado_msgpack',
version='0.1',
py_modules=['tonado_msgpack'],
)
作業開始
$ python setup.py develop --user
sample/sample.py
#!/usr/bin/env python
import tornado_msgpack
import tornado
if __name__=="__main__":
port=18080
# dispatcher
dispatcher=tornado_msgpack.Dispatcher()
def add(a, b):
return a+b
dispatcher.add_handler("add", add)
# server
server_loop=tornado.ioloop.IOLoop()
def on_receive(msg, session):
result=dispatcher.dispatch(msg)
session.send_async(result)
server=tornado_msgpack.Server(server_loop)
server.listen("localhost", port)
server_thread=threading.Thread(target=lambda : server_loop.start() )
# clinet
client_loop=tornado.ioloop.IOLoop()
client=tornado_msgpack.Client(client_loop)
def on_status_changed(status):
print(status)
clinet.attach_status_callback(on_status_changed)
client.connect("localhost", port)
clinet_thread=threading.Thread(target=lambda : client_loop.start() )
# request
def on_receive(result):
print(result)
future=clinet.call_async_with_callback(on_receive, "add", 1)
future.join()
future=clinet.call_async_with_callback(on_receive, "add", 1, 2)
future.join()
future=clinet.call_async_with_callback(on_receive, "add", 1, 2, 3)
future.join()
print("stop client...")
client_loop.stop()
clinet_thread.join()
print("stop server...")
server_loop.stop()
server_thread.join()
print("done")
とりあえずこんな感じを予定。
./sample/sample.pyでシンタックスエラーが出なくなるところまで確認。
tornado_msgpackを順次実装していく。
Tornado Reference - http://www.tornadoweb.org/en/stable/
だいたい動くようになった。
$ ./sample/sample
connected
<_MainThread(MainThread, started 140102020679424)>:send 9 bytes
<Thread(Thread-1, started 140101931136768)>:on_read
<Thread(Thread-1, started 140101931136768)>:send 48 bytes
<Thread(Thread-2, started 140101918488320)>:on_read
on_receive:[1, 1, True, 'add() takes exactly 2 arguments (1 given)']
<_MainThread(MainThread, started 140102020679424)>:send 10 bytes
<Thread(Thread-1, started 140101931136768)>:on_read
<Thread(Thread-1, started 140101931136768)>:send 5 bytes
<Thread(Thread-2, started 140101918488320)>:on_read
on_receive:[1, 2, False, 3]
<_MainThread(MainThread, started 140102020679424)>:send 11 bytes
<Thread(Thread-1, started 140101931136768)>:on_read
<Thread(Thread-1, started 140101931136768)>:send 59 bytes
<Thread(Thread-2, started 140101918488320)>:on_read
on_receive:[1, 3, True, 'add() takes exactly 2 positional arguments (3 given)']
stop client...
stop server...
done
サーバースレッドのioloopと、クライアントスレッドのioloopが相互にやり取りしている感じでちゃんと動いている。