|
1 | | -import asyncio |
2 | | -from typing import Callable, Type, Awaitable |
| 1 | +from typing import Callable, Awaitable, Type |
3 | 2 |
|
4 | 3 | import attrs |
5 | | -from nasdaq_protocols.common import DispatchableMessageQueue, logable |
6 | 4 | from nasdaq_protocols import soup |
| 5 | +from nasdaq_protocols.soup_app.session import BaseClientSession, SessionId |
7 | 6 | from .core import Message |
8 | 7 |
|
9 | | - |
10 | 8 | __all__ = [ |
11 | 9 | 'OnItchMessageCoro', |
12 | 10 | 'OnItchCloseCoro', |
13 | 11 | 'ItchSessionId', |
14 | 12 | 'ClientSession' |
15 | 13 | ] |
| 14 | + |
16 | 15 | OnItchMessageCoro = Callable[[Type[Message]], Awaitable[None]] |
17 | 16 | OnItchCloseCoro = Callable[[], Awaitable[None]] |
18 | 17 |
|
19 | 18 |
|
20 | 19 | @attrs.define(auto_attribs=True) |
21 | | -class ItchSessionId: |
| 20 | +class ItchSessionId(SessionId): |
22 | 21 | soup_session_id: soup.SoupSessionId = None |
23 | | - |
24 | | - def __str__(self): |
25 | | - if self.soup_session_id: |
26 | | - return f'itch-{self.soup_session_id}' |
27 | | - return 'itch-nosoup' |
| 22 | + protocol_name: str = "itch" |
28 | 23 |
|
29 | 24 |
|
30 | 25 | @attrs.define(auto_attribs=True) |
31 | | -@logable |
32 | | -class ClientSession: |
33 | | - soup_session: soup.SoupClientSession |
34 | | - on_msg_coro: OnItchMessageCoro = None |
35 | | - on_close_coro: OnItchCloseCoro = None |
36 | | - closed: bool = False |
37 | | - _session_id: ItchSessionId = None |
38 | | - _close_event: asyncio.Event = None |
39 | | - _message_queue: DispatchableMessageQueue = None |
40 | | - |
41 | | - def __attrs_post_init__(self): |
42 | | - self._session_id = ItchSessionId(self.soup_session.session_id) |
43 | | - self._message_queue = DispatchableMessageQueue(self._session_id, self.on_msg_coro) |
44 | | - self.soup_session.set_handlers(on_msg_coro=self._on_soup_message, on_close_coro=self._on_soup_close) |
45 | | - self.soup_session.start_dispatching() |
46 | | - |
47 | | - async def receive_message(self): |
48 | | - """ |
49 | | - Asynchronously receive a message from the itch session. |
50 | | -
|
51 | | - This method blocks until a message is received by the session. |
52 | | - """ |
53 | | - return await self._message_queue.get() |
54 | | - |
55 | | - async def close(self): |
56 | | - """ |
57 | | - Asynchronously close the itch session. |
58 | | - """ |
59 | | - if self._close_event or self.closed: |
60 | | - self.log.debug('%s> closing in progress..', self._session_id) |
61 | | - return |
62 | | - self._close_event = asyncio.Event() |
63 | | - self.soup_session.initiate_close() |
64 | | - await self._close_event.wait() |
65 | | - self.log.debug('%s> closed.', self._session_id) |
| 26 | +class ClientSession(BaseClientSession): |
| 27 | + """ITCH protocol client session implementation.""" |
66 | 28 |
|
67 | | - async def _on_soup_message(self, message: soup.SoupMessage): |
68 | | - if isinstance(message, soup.SequencedData): |
69 | | - self.log.debug('%s> incoming sequenced bytes_', self._session_id) |
70 | | - await self._message_queue.put( |
71 | | - self.decode(message.data)[1] |
72 | | - ) |
| 29 | + def _create_session_id(self): |
| 30 | + return ItchSessionId(self.soup_session.session_id) |
73 | 31 |
|
74 | | - async def _on_soup_close(self): |
75 | | - await self._message_queue.stop() |
76 | | - if self.on_close_coro is not None: |
77 | | - await self.on_close_coro() |
78 | | - if self._close_event: |
79 | | - self._close_event.set() |
80 | | - self.closed = True |
| 32 | + def send_message(self, msg: Message): |
| 33 | + raise NotImplementedError("ITCH protocol does not support sending messages") |
81 | 34 |
|
82 | 35 | @classmethod |
83 | | - def decode(cls, bytes_: bytes): |
| 36 | + def decode(cls, bytes_: bytes): # pylint: disable=W0221 |
84 | 37 | """ |
85 | | - Decode the given bytes into an itch message. |
| 38 | + Decode the given bytes into an ITCH message. |
86 | 39 | """ |
87 | 40 | return Message.from_bytes(bytes_) |
0 commit comments