Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create core to store some utility classes. cleans up dispatcher a tad.
- Loading branch information
Showing
8 changed files
with
197 additions
and
147 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
from typing import Dict, Generic, List, Optional, Type, TypeVar, cast | ||
|
||
from .exceptions import InternalDriverError, MaximumStreamsException | ||
|
||
# from .protocol import RequestMessage # noqa: F401 | ||
|
||
|
||
class SBytes(bytes): | ||
_index: int = 0 | ||
|
||
def __new__(cls: Type[bytes], val: bytes) -> "SBytes": | ||
return cast(SBytes, super().__new__(cls, val)) # type: ignore # https://github.com/python/typeshed/issues/2630 | ||
|
||
def hex(self) -> str: | ||
return "0x" + super().hex() | ||
|
||
def grab(self, count: int) -> bytes: | ||
assert self._index is not None | ||
if self._index + count > len(self): | ||
raise InternalDriverError( | ||
f"cannot go beyond {len(self)} count={count} index={self._index} sbytes={self!r}" | ||
) | ||
curindex = self._index | ||
self._index += count | ||
return self[curindex : curindex + count] | ||
|
||
def at_end(self) -> bool: | ||
return self._index == len(self) | ||
|
||
@property | ||
def remaining(self) -> bytes: | ||
return self[self._index :] | ||
|
||
|
||
T = TypeVar("T") | ||
|
||
|
||
class Streams(Generic[T]): | ||
def __init__(self) -> None: | ||
self._last_stream_id: Optional[int] = None | ||
self._streams: Dict[int, Optional[T]] = {} | ||
|
||
def items(self) -> List[int]: | ||
return list(self._streams.keys()) | ||
|
||
def remove(self, stream_id: int) -> T: | ||
try: | ||
store = self._streams.pop(stream_id) | ||
assert store is not None | ||
return store | ||
except KeyError: | ||
raise InternalDriverError( | ||
f"stream_id={stream_id} is not open", stream_id=stream_id | ||
) | ||
|
||
def create(self) -> int: | ||
maxstream = 2 ** 15 | ||
last_id = self._last_stream_id | ||
if len(self._streams) > maxstream: | ||
raise MaximumStreamsException( | ||
f"too many streams last_id={last_id} length={len(self._streams)}" | ||
) | ||
next_id = 0x00 | ||
if last_id is not None: | ||
next_id = last_id + 1 | ||
while True: | ||
if next_id > maxstream: | ||
next_id = 0x00 | ||
if next_id not in self._streams: | ||
break | ||
next_id = next_id + 1 | ||
# store will come in later | ||
self._streams[next_id] = None | ||
self._last_stream_id = next_id | ||
return next_id | ||
|
||
def update(self, stream_id: int, store: T) -> None: | ||
if stream_id not in self._streams: | ||
raise InternalDriverError(f"stream_id={stream_id} not being tracked") | ||
if store is None: | ||
raise InternalDriverError("cannot store empty request") | ||
self._streams[stream_id] = store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import pytest | ||
|
||
from pysandra.core import SBytes, Streams | ||
from pysandra.exceptions import InternalDriverError, MaximumStreamsException | ||
|
||
|
||
def test_max_streams(): | ||
with pytest.raises( | ||
MaximumStreamsException, match=r"too many streams last_id=31159 length=32769" | ||
): | ||
streams: Streams[int] = Streams() | ||
move = 0 | ||
while True: | ||
move += 1 | ||
stream_id = streams.create() | ||
streams.update(stream_id, 3) | ||
if (move % 19) == 0: | ||
streams.remove(stream_id) | ||
|
||
|
||
def test_streams_list(): | ||
streams: Streams[int] = Streams() | ||
streams.create() | ||
streams.create() | ||
assert streams.items() == [0, 1] | ||
|
||
|
||
def test_streams_update(): | ||
streams: Streams[int] = Streams() | ||
stream_id = streams.create() | ||
stream_id2 = streams.create() | ||
streams.update(stream_id, "FOO") | ||
streams.update(stream_id2, "BAR") | ||
streams.remove(stream_id2) | ||
assert streams.remove(stream_id) == "FOO" | ||
|
||
|
||
def test_streams_update_fail_found(): | ||
with pytest.raises(InternalDriverError, match=r"not being tracked"): | ||
streams: Streams[int] = Streams() | ||
stream_id = streams.create() | ||
streams.update(stream_id + 1, "FOO") | ||
|
||
|
||
def test_streams_update_fail_null(): | ||
with pytest.raises(InternalDriverError, match=r"empty request"): | ||
streams: Streams[int] = Streams() | ||
stream_id = streams.create() | ||
streams.update(stream_id, None) | ||
|
||
|
||
def test_streams_error(): | ||
with pytest.raises(InternalDriverError, match=r"is not open"): | ||
streams: Streams[int] = Streams() | ||
stream_id = streams.create() | ||
streams.remove(stream_id + 1) | ||
|
||
|
||
def test_sbytes_at_end(): | ||
t = SBytes(b"12345") | ||
print(f"{t.grab(1)!r}{t.at_end()}") | ||
print(f"{t.grab(3)!r}{t.at_end()}") | ||
print(f"{t.grab(1)!r}{t.at_end()}") | ||
assert t.at_end() | ||
|
||
|
||
def test_sbytes_hex(): | ||
t = SBytes(b"\x03\13\45") | ||
assert t.hex() == "0x030b25" | ||
|
||
|
||
def test_sbytes_remaining(): | ||
t = SBytes(b"\x03\13\45") | ||
t.grab(2) | ||
|
||
assert t.remaining == b"%" | ||
|
||
|
||
def test_sbytes_not_end(): | ||
t = SBytes(b"12345") | ||
print(f"{t.grab(1)!r}{t.at_end()}") | ||
print(f"{t.grab(3)!r}{t.at_end()}") | ||
assert not t.at_end() | ||
|
||
|
||
def test_sbytes_overflow(): | ||
with pytest.raises(InternalDriverError, match=r"cannot go beyond"): | ||
t = SBytes(b"12345") | ||
print(f"{t.grab(1)!r}{t.at_end()}") | ||
print(f"{t.grab(3)!r}{t.at_end()}") | ||
print(f"{t.grab(2)!r}{t.at_end()}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,6 @@ | ||
import pytest | ||
|
||
from pysandra.dispatcher import Dispatcher | ||
from pysandra.exceptions import MaximumStreamsException | ||
|
||
|
||
def test_max_streams(): | ||
with pytest.raises( | ||
MaximumStreamsException, match=r"too many streams last_id=31159 length=32769" | ||
): | ||
client = Dispatcher("blank", "", False, 0) | ||
move = 0 | ||
while True: | ||
move += 1 | ||
streamid = client._new_stream_id() | ||
client._update_stream_id( | ||
streamid, ("something", "else", "entirely"), | ||
) | ||
if (move % 19) == 0: | ||
client._rm_stream_id(streamid) | ||
d = Dispatcher("blank", "", False, 0) | ||
print(f"({d})") |
Oops, something went wrong.