Connectors: fetch command type and payload in a single round-trip (getCommandInfo)#311
Open
biohazardxxx wants to merge 10 commits into
Open
Connectors: fetch command type and payload in a single round-trip (getCommandInfo)#311biohazardxxx wants to merge 10 commits into
biohazardxxx wants to merge 10 commits into
Conversation
convertSystemString copied at most 1000 wchars into the caller's MQL string buffer regardless of its actual capacity and never wrote a null terminator (stale content from a previous, longer error message could leak into reused buffers). Command payloads longer than 1000 characters arrived truncated in the EA and failed JSON parsing. - convertSystemString now takes the destination capacity, bounds the copy and always null-terminates. - getPayload keeps its signature but honors the EA's real 5000-wchar payload buffer (StringInit(payload, 5000, 0)) instead of 1000. - New size-aware export getPayload2(handle, res, capacity, err) returns the full payload length (or -1 on error) and copies at most capacity-1 chars, so callers can re-allocate and fetch payloads of any size. Applies to both MT5Connector and MTConnector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GetJsonPayload now asks the connector for the payload with an explicit buffer capacity and re-allocates when the reported size exceeds the default 5000-character buffer, removing the previous hard cap on inbound command payloads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same change as the MQL5 expert: GetJsonPayload re-allocates its buffer based on the size reported by getPayload2, removing the inbound payload cap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fetching a command from the EA costs two blocking packaged_task round-trips to the io thread today (GetCommandType + GetCommandPayload). GetCommandInfo pops the next task and returns its type and payload in one posted task, halving the cross-thread latency per command. Queue empty yields command type 0 (MT_COMMAND_TYPE_EMPTY) and an empty payload. Existing methods are unchanged; everything touching MtExpert state still runs on the single io_context thread. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New export combining getCommandType and getPayload2 into one call: pops the next command, writes its type into the by-ref parameter and copies at most capacity-1 payload characters (always null-terminated). Returns the full payload length in wchar_t (excluding the terminator) or -1 on error. Oversized payloads can be re-fetched via the existing getPayload2, which reads the already popped current task without popping the queue again. getCommandType/getPayload/getPayload2 stay exported and functional, so older experts keep working with the new DLLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
executeCommand now uses getCommandInfo to receive the command type and payload together, storing the payload in a global that GetJsonPayload parses instead of calling back into the DLL. Payloads larger than the default 5000-char buffer are re-fetched via getPayload2 after re-allocating. Handlers are untouched; empty payloads still make GetJsonPayload return NULL with the same errors as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same change as the MQL5 expert: ExecuteCommand uses getCommandInfo and GetJsonPayload parses the globally stored payload instead of calling the DLL again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both compiled with 0 errors, 0 warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
getCommandInfo pops the command before converting the payload; a conversion failure (e.g. invalid UTF-8 / non-BMP characters) previously returned without dispatching, silently dropping the popped command and leaving the client waiting for the full CommandTimeout. Now the EA clears the payload and dispatches anyway, so the handler sends the same immediate "Failed to get payload" error response the old two-call path produced. Review finding. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4 tasks
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Fetching one command currently costs two blocking cross-thread round-trips into the connector's io thread:
getCommandType(posts a packaged_task, blocks) thengetPayloadinside the handler (posts another, blocks). This PR merges them into one:GetCommandInfo(handle, int& type, std::string& payload)— a single packaged_task that pops the next command AND returns its payload. Existing methods untouched; everything touching expert state still runs on the single io thread._command_payload;GetJsonPayload()parses that instead of calling the DLL — allExecute_*handlers untouched. Oversized payloads re-fetch viagetPayload2(safe:GetCommandPayloadreadscurrent_task_non-destructively; the command is not re-popped).getCommandType/getPayload/getPayload2remain exported and functional — old.ex4/.ex5binaries keep working with the new DLLs (live-verified, see Testing).Implementation notes
_getCommandInfo@20), no stale-payload leakage across commands.Testing
getCommandInfopresent in both DLLs' export tables (dumpbin). Both EAs compileResult: 0 errors, 0 warnings; recompiled.ex5/.ex4included.Print(exercising the oversized re-fetch path): both returntrue..ex5on the same new DLL answered commands normally via the old exports.🤖 Generated with Claude Code