The app's end of the connection, independent of the transport, which reaches it through Detail::Exchange: one request's way back, safe from any thread and never blocking. - What needs only the session's own state (hello, status, list, log, pause, resume) is answered on the transport thread. What touches the app (calls, get, set, trace, screenshot) queues for the next Pump and runs on the app's thread between frames. Waits and steps reply from the Pump that sees them satisfied, events from the thread that emits them. No request ever holds a thread while it waits. - A request whose timeout passes before Pump is answered Timeout and is guaranteed not to have run, so an agent never wonders whether a command went through; an Async result arrives on the Pump it is ready; requests left when the Session ends are answered ShuttingDown. - Advance() for frame loops and Paused()/TakeSteps() for fixed-step loops hold what the app gates on them; pausing an app that gates nothing is refused instead of silently doing nothing. pause --when stops the frame its condition holds; pause --on-check stops before the next Advance in the frame a check fails, optionally raising SIGTRAP for an attached debugger. - A wait that times out says what its condition's paths were; a log follower gets matching entries in order, from the backlog on, and is dropped when it cannot keep up. - Request parameters go through Codec, so a mistyped request gets the same did-you-mean replies a mistyped command does. The session sets PR_SET_PTRACER_ANY so a debugger the agent starts can attach. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
2.7 KiB
C++
55 lines
2.7 KiB
C++
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
// The wire contract between an app and crafter-debug. A request is one JSON
|
|
// object,
|
|
//
|
|
// {"token": "...", "method": "debug.get", "params": {...}, "timeoutMs": 30000}
|
|
//
|
|
// and its reply one JSON object, either {"result": ...} or
|
|
// {"error": {"code": "...", "message": "..."}}, the envelope 3DForts' debug
|
|
// API used. A streaming request (`debug.log` with follow) is answered by one
|
|
// object per line instead. Methods named debug.* are the session's own; any
|
|
// other method is a command the app registered.
|
|
//
|
|
// `debug.hello` is frozen: every version answers it the same way, so a
|
|
// client can always learn the protocol and source of the app it reached
|
|
// before relying on anything else.
|
|
export module Crafter.Debug.Core:Protocol;
|
|
import std;
|
|
import :Value;
|
|
|
|
export namespace Crafter::Debug {
|
|
// Bumped on any change to a request or reply a client relies on.
|
|
inline constexpr std::uint32_t protocolVersion = 1;
|
|
// The library's own version, which debug.hello reports.
|
|
inline constexpr std::string_view libraryVersion = "0.1.0-dev";
|
|
// The QUIC ALPN: frozen with debug.hello, so a mismatch is reported by
|
|
// hello instead of failing the handshake.
|
|
inline constexpr std::string_view alpn = "crafter-debug/1";
|
|
|
|
// The error codes the session itself answers with; app commands add
|
|
// their own.
|
|
namespace Codes {
|
|
inline constexpr std::string_view unauthorized = "Unauthorized";
|
|
inline constexpr std::string_view unknownMethod = "UnknownMethod";
|
|
inline constexpr std::string_view invalidRequest = "InvalidRequest";
|
|
inline constexpr std::string_view invalidParams = "InvalidParams";
|
|
inline constexpr std::string_view timeout = "Timeout";
|
|
inline constexpr std::string_view notPaused = "NotPaused";
|
|
inline constexpr std::string_view pauseUnsupported = "PauseUnsupported";
|
|
inline constexpr std::string_view noCapture = "NoCapture";
|
|
inline constexpr std::string_view shuttingDown = "ShuttingDown";
|
|
inline constexpr std::string_view exception = "Exception";
|
|
inline constexpr std::string_view readOnly = "ReadOnly";
|
|
inline constexpr std::string_view unknownPath = "UnknownPath";
|
|
inline constexpr std::string_view conditionError = "ConditionError";
|
|
}
|
|
|
|
Value MakeReply(Value result);
|
|
Value MakeErrorReply(std::string_view code, std::string_view message);
|
|
|
|
// Standard base64 with padding, for screenshots in a JSON reply.
|
|
std::string Base64Encode(std::span<const std::byte> bytes);
|
|
std::optional<std::vector<std::byte>> Base64Decode(std::string_view text);
|
|
}
|