Add animesoul client & rpc server
This commit is contained in:
commit
792edb4c88
6 changed files with 163 additions and 0 deletions
33
README.md
Normal file
33
README.md
Normal 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
22
jaken/__init__.py
Normal 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
5
jaken/__main__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
import asyncio
|
||||
|
||||
from jaken import main
|
||||
|
||||
asyncio.run(main())
|
30
jaken/rpc.py
Normal file
30
jaken/rpc.py
Normal 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
71
jaken/soul.py
Normal 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
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
python-socketio[asyncio_client]==4.6.0
|
||||
aiomas==2.0.1
|
Loading…
Reference in a new issue