-
Notifications
You must be signed in to change notification settings - Fork 10
feat: Add large command chunking #306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
dd0bd58
3fb008d
813a293
7014851
c9c91dc
d5bcbb7
9d1a67d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,7 +41,17 @@ def default(self, o: Any) -> Any: | |
| return simplejson.JSONEncoder.default(self, o) | ||
|
|
||
|
|
||
| def serialize(obj: Any) -> bytes: | ||
| def serialize_str(obj: Any) -> str: | ||
| """ | ||
| Serialize an object to a JSON string. | ||
|
|
||
| Use `serialize()` to return a value that's ready to send to Chrome. | ||
| This exists for callers that need to slice the string up first. | ||
|
|
||
| Args: | ||
| obj: Any Python object that serializes to JSON. | ||
|
Comment on lines
+46
to
+52
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The docstring should probably specify which JSON encoder is used, since that affects whether a given object is JSON-serializable or not. |
||
|
|
||
| """ | ||
| try: | ||
| if not _custom_encoder: | ||
| message = simplejson.dumps( | ||
|
|
@@ -57,7 +67,11 @@ def serialize(obj: Any) -> bytes: | |
| _logger.debug(f"Serialized: {message[:15]}...{message[-15:]}, size: {len(message)}") | ||
| _logger.debug2(f"Whole message: {message}") | ||
|
|
||
| return message.encode("utf-8") | ||
| return message | ||
|
|
||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add docstring? |
||
| def serialize(obj: Any) -> bytes: | ||
| return serialize_str(obj).encode("utf-8") | ||
|
|
||
|
|
||
| def deserialize(message: str) -> Any: | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -13,7 +13,12 @@ | |||||
| import logistro | ||||||
|
|
||||||
| from . import _wire as wire | ||||||
| from ._errors import BlockWarning, ChannelClosedError, JSONError | ||||||
| from ._errors import ( | ||||||
| BlockWarning, | ||||||
| ChannelClosedError, | ||||||
| JSONError, | ||||||
| MessageTooLargeError, | ||||||
| ) | ||||||
|
|
||||||
| if TYPE_CHECKING: | ||||||
| from typing import Any, Mapping, Sequence | ||||||
|
|
@@ -24,6 +29,14 @@ | |||||
|
|
||||||
| _logger = logistro.getLogger(__name__) | ||||||
|
|
||||||
| MAX_MESSAGE_SIZE = 100 * 1024 * 1024 | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume there's no way to request this value directly from Chrome? |
||||||
| """ | ||||||
| The biggest message Chrome will read off the pipe, in bytes. | ||||||
|
|
||||||
| This mirrors `kReceiveBufferSizeForDevTools` in Chrome's | ||||||
| `content/browser/devtools/devtools_pipe_handler.cc`. | ||||||
| """ | ||||||
|
|
||||||
| # should be closing my ends from the start? | ||||||
|
|
||||||
|
|
||||||
|
|
@@ -84,15 +97,36 @@ def write_json(self, obj: Mapping[str, Any]) -> tuple[float, float]: | |||||
| Send one json down the pipe. | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| Args: | ||||||
| obj: any python object that serializes to json. | ||||||
| obj: Any python object that serializes to JSON. | ||||||
|
|
||||||
| Raises: | ||||||
| ChannelClosedError: If the pipe was never opened or is already | ||||||
| closed, or if the OS write fails. A failed write closes the | ||||||
| pipe, so nothing can be sent after this. | ||||||
| MessageTooLargeError: If the message won't fit in Chrome's buffer. | ||||||
| Nothing is written, so the channel is still good afterwards. | ||||||
| The error carries the serialized message so that callers who | ||||||
| can break it up don't have to serialize it a second time. | ||||||
| TypeError: If `obj` contains something the encoder doesn't know how | ||||||
| to turn into JSON. | ||||||
| UnicodeEncodeError: If the serialized message contains lone | ||||||
| surrogates, which have no UTF-8 representation. | ||||||
|
|
||||||
| """ | ||||||
| if not self.is_ready(): | ||||||
| raise ChannelClosedError( | ||||||
| "The communication channel was either never " | ||||||
| "opened or closed. Was .open() or .close() called?", | ||||||
| ) | ||||||
| encoded_message = wire.serialize(obj) + b"\0" | ||||||
| message = wire.serialize_str(obj) | ||||||
| encoded_message = message.encode("utf-8") + b"\0" | ||||||
| if len(encoded_message) > MAX_MESSAGE_SIZE: | ||||||
| # Don't close(): we haven't written anything, the pipe is fine. | ||||||
| raise MessageTooLargeError( | ||||||
| len(encoded_message), | ||||||
| MAX_MESSAGE_SIZE, | ||||||
| payload=message, | ||||||
| ) | ||||||
| _logger.debug( | ||||||
| f"Writing message {encoded_message[:15]!r}...{encoded_message[-15:]!r}, " | ||||||
| f"size: {len(encoded_message)}.", | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.