-
Notifications
You must be signed in to change notification settings - Fork 9
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
dd0bd58
Address ruff formatting feedback
camdecoster 3fb008d
Add message too large error
camdecoster 813a293
Add utility to serialize messages to unencoded string
camdecoster 7014851
Add large command chunking
camdecoster c9c91dc
Handle additional context identifier, throwOnSideEffect
camdecoster d5bcbb7
Update docstrings
camdecoster 9d1a67d
Add chunking tests
camdecoster ab26a2a
Add large message test to CI
camdecoster 6f1a4fa
Handle trailing newline when wrapping function
camdecoster ddeb178
Expose new error
camdecoster a8db59e
Exclude slow test in debug-test_fn
camdecoster ad9ee84
Address PR feedback
camdecoster 2591ea0
Update changelog
camdecoster File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 |
|---|---|---|
|
|
@@ -41,7 +41,23 @@ 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 encoded as bytes, | ||
| which is the format accepted by Chrome. | ||
| `serialize_str()` exists for callers that need to split a large string | ||
| along character boundaries before encoding as bytes. | ||
|
|
||
| Encoding uses the encoder given to `register_custom_encoder()`, or | ||
| `MultiEncoder` on top of `simplejson` when none is registered. Which one | ||
| is in use decides what counts as serializable. | ||
|
|
||
| Args: | ||
| obj: Any Python object that serializes to JSON. | ||
|
|
||
| """ | ||
| try: | ||
| if not _custom_encoder: | ||
| message = simplejson.dumps( | ||
|
|
@@ -57,10 +73,28 @@ 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: | ||
| """ | ||
| Serialize an object to UTF-8 encoded JSON, ready for the wire. | ||
|
|
||
| Args: | ||
| obj: Any Python object that serializes to JSON. | ||
|
|
||
| """ | ||
| return serialize_str(obj).encode("utf-8") | ||
|
|
||
|
|
||
| def deserialize(message: str) -> Any: | ||
| """ | ||
| Read one JSON message from the browser back into Python objects. | ||
|
|
||
| Args: | ||
| message: One JSON message, already decoded from bytes. | ||
|
|
||
| """ | ||
| try: | ||
| return simplejson.loads(message) | ||
| except sjerrors.JSONDecodeError as e: | ||
|
|
||
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -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? | ||
|
|
||
|
|
||
|
|
@@ -81,18 +94,39 @@ def open(self) -> None: | |
|
|
||
| def write_json(self, obj: Mapping[str, Any]) -> tuple[float, float]: | ||
| """ | ||
| Send one json down the pipe. | ||
| Send one json message down the pipe. | ||
|
|
||
| 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)}.", | ||
|
|
||
This file contains hidden or 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 hidden or 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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
The docstring should probably specify which JSON encoder is used, since that affects whether a given object is JSON-serializable or not.