Add animesoul client & rpc server

This commit is contained in:
Henry 2020-10-23 12:00:36 +01:00
commit 792edb4c88
6 changed files with 163 additions and 0 deletions

33
README.md Normal file
View file

@ -0,0 +1,33 @@
# jaken
Python component of Kirara, responds to RPC
## Setup
```sh
python3 -m venv env
./env/bin/pip install -r requirements.txt
# running the server
./env/bin/python -m jaken
```
## RPC directory
### `soul`
Searching for cards:
```js
rpc.remote.soul.search_cards("blake").then((cards) => {
// `cards` is an array of cards
});
```
Fetching a specific card by ID:
```js
rpc.remote.soul.get_card("5f2b3701a5a84e32a258df1b", /* with_users: */ true)
.then((data) => {
// `data.card` is a Card
// if with_users is true, `data.users` is an array of users
});
```

22
jaken/__init__.py Normal file
View file

@ -0,0 +1,22 @@
from jaken.rpc import SoulServer
import aiomas
import asyncio
async def main():
soul_service = SoulServer()
await soul_service.connect()
root_service = aiomas.rpc.ServiceDict({
"soul": soul_service,
})
rpc_server = await aiomas.rpc.start_server(('localhost', 5444), root_service)
try:
await soul_service.soul_client.run()
finally:
rpc_server.close()
if __name__ == "__main__":
asyncio.run(main())

5
jaken/__main__.py Normal file
View file

@ -0,0 +1,5 @@
import asyncio
from jaken import main
asyncio.run(main())

30
jaken/rpc.py Normal file
View file

@ -0,0 +1,30 @@
import aiomas
from jaken.soul import SoulClient, Card
class SoulServer:
router = aiomas.rpc.Service()
def __init__(self):
self.soul_client = SoulClient()
async def connect(self):
await self.soul_client.connect()
@router.expose
async def search_cards(self, search_term):
r = await self.soul_client.call("cardindex", {"search": search_term})
cards = [Card(doc).to_dict() for doc in r['data']['docs']]
return cards
@router.expose
async def get_card(self, card_id, with_users=False):
r = await self.soul_client.call("cardview", {"cardid": card_id})
card = Card(r['card']).to_dict()
users = r['users']
if with_users:
return dict(card=card, users=users)
else:
return dict(card=card)

71
jaken/soul.py Normal file
View file

@ -0,0 +1,71 @@
import asyncio
import socketio
class PatchedAsyncClient(socketio.AsyncClient):
async def _handle_event(self, namespace, id, data):
namespace = namespace or '/'
await super()._handle_event(namespace, id, data)
await self._trigger_event('message', namespace, *data[1:])
class SoulClient:
def __init__(self):
self.sio = PatchedAsyncClient(logger=True)
self.sio.on('connect', self._on_connect)
self.sio.on('message', self._on_message)
self.call_lock = asyncio.Lock()
self.callback = None
async def _on_connect(self, namespace=None):
await self.call('init')
async def _on_message(self, msg):
if self.call_lock.locked():
self.call_lock.release()
if self.callback:
self.callback.set_result(msg)
async def connect(self):
await self.sio.connect("wss://animesoul.com/socket.io/", transports=['websocket'])
async def run(self):
await self.sio.wait()
async def cast(self, event_name, data=None):
await self.sio.emit(event_name, data)
async def call(self, event_name, data=None):
await self.call_lock.acquire()
await self.sio.emit(event_name, data)
self.callback = asyncio.get_event_loop().create_future()
return await self.callback
class Card:
IMAGE_CDN = "https://cdn.animesoul.com/images/cards"
def __init__(self, kwargs):
self.pk = kwargs.get("_id")
self.name = kwargs.get("name")
self.slug = kwargs.get("slug")
self.tier = kwargs.get("tier")
self.claim_count = kwargs.get("claim_count")
extra = kwargs.get("category")
try:
self.anime = extra[0]
except IndexError:
self.anime = None
self.filename = kwargs.get("file")
self.url = f"{self.IMAGE_CDN}/{self.tier}/{self.filename}"
def to_dict(self):
return {
"id": self.pk,
"name": self.name,
"tier": self.tier,
"anime": self.anime,
"link": self.url,
"claim_count": self.claim_count,
}

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
python-socketio[asyncio_client]==4.6.0
aiomas==2.0.1