-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor framed I/O and harden server paths #8
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
Changes from all commits
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 |
---|---|---|
|
@@ -60,7 +60,7 @@ def create_script( | |
"namespace": namespace, | ||
"scriptType": script_type, | ||
} | ||
if contents is not None: | ||
if contents: | ||
params["encodedContents"] = base64.b64encode(contents.encode("utf-8")).decode("utf-8") | ||
params["contentsEncoded"] = True | ||
params = {k: v for k, v in params.items() if v is not None} | ||
|
@@ -107,7 +107,7 @@ def manage_script( | |
- Edits should use apply_text_edits. | ||
|
||
Args: | ||
action: Operation ('create', 'read', 'update', 'delete'). | ||
action: Operation ('create', 'read', 'delete'). | ||
name: Script name (no .cs extension). | ||
path: Asset path (default: "Assets/"). | ||
contents: C# code for 'create'/'update'. | ||
|
@@ -132,8 +132,8 @@ def manage_script( | |
} | ||
|
||
# Base64 encode the contents if they exist to avoid JSON escaping issues | ||
if contents is not None: | ||
if action in ['create', 'update']: | ||
if contents: | ||
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. logic: Same truthiness change here - verify that empty string contents for non-create actions should be ignored rather than processed. |
||
if action == 'create': | ||
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. Bug: Empty Scripts Fail Base64 EncodingThe Additional Locations (1) |
||
params["encodedContents"] = base64.b64encode(contents.encode('utf-8')).decode('utf-8') | ||
params["contentsEncoded"] = True | ||
else: | ||
|
@@ -143,22 +143,22 @@ def manage_script( | |
|
||
response = send_command_with_retry("manage_script", params) | ||
|
||
if isinstance(response, dict) and response.get("success"): | ||
if response.get("data", {}).get("contentsEncoded"): | ||
decoded_contents = base64.b64decode(response["data"]["encodedContents"]).decode('utf-8') | ||
response["data"]["contents"] = decoded_contents | ||
del response["data"]["encodedContents"] | ||
del response["data"]["contentsEncoded"] | ||
|
||
return { | ||
"success": True, | ||
"message": response.get("message", "Operation successful."), | ||
"data": response.get("data"), | ||
} | ||
return response if isinstance(response, dict) else { | ||
"success": False, | ||
"message": str(response), | ||
} | ||
if isinstance(response, dict): | ||
if response.get("success"): | ||
if response.get("data", {}).get("contentsEncoded"): | ||
decoded_contents = base64.b64decode(response["data"]["encodedContents"]).decode('utf-8') | ||
response["data"]["contents"] = decoded_contents | ||
del response["data"]["encodedContents"] | ||
del response["data"]["contentsEncoded"] | ||
|
||
return { | ||
"success": True, | ||
"message": response.get("message", "Operation successful."), | ||
"data": response.get("data"), | ||
} | ||
return response | ||
|
||
return {"success": False, "message": str(response)} | ||
|
||
except Exception as e: | ||
return { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,12 +49,23 @@ def connect(self) -> bool: | |
self.use_framing = True | ||
logger.debug('Unity MCP handshake received: FRAMING=1 (strict)') | ||
else: | ||
try: | ||
msg = b'Unity MCP requires FRAMING=1' | ||
header = struct.pack('>Q', len(msg)) | ||
self.sock.sendall(header + msg) | ||
except Exception: | ||
pass | ||
raise ConnectionError(f'Unity MCP requires FRAMING=1, got: {text!r}') | ||
finally: | ||
self.sock.settimeout(config.connection_timeout) | ||
return True | ||
except Exception as e: | ||
logger.error(f"Failed to connect to Unity: {str(e)}") | ||
try: | ||
if self.sock: | ||
self.sock.close() | ||
except Exception: | ||
pass | ||
self.sock = None | ||
return False | ||
|
||
|
@@ -83,7 +94,7 @@ def receive_full_response(self, sock, buffer_size=config.buffer_size) -> bytes: | |
try: | ||
header = self._read_exact(sock, 8) | ||
payload_len = struct.unpack('>Q', header)[0] | ||
if payload_len == 0 or payload_len > (64 * 1024 * 1024): | ||
if payload_len > (64 * 1024 * 1024): | ||
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. |
||
raise Exception(f"Invalid framed length: {payload_len}") | ||
payload = self._read_exact(sock, payload_len) | ||
logger.info(f"Received framed response ({len(payload)} bytes)") | ||
|
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.
logic: Changing from
if contents is not None:
toif contents:
means empty strings will now be treated as falsy. This could break existing functionality if empty script creation was previously supported.