1212#include < functional>
1313#include < exception>
1414#include < unordered_map>
15+ #include < utility>
1516
1617#include < nlohmann/json.hpp>
1718
@@ -47,37 +48,91 @@ namespace foundry_local::detail {
4748 return core->call (command, logger, &payload, callback, userData);
4849 }
4950
51+ inline bool TryParseFloatToken (std::string_view token, float & value) {
52+ if (token.empty ()) {
53+ return false ;
54+ }
55+
56+ const std::string text (token);
57+ size_t processed = 0 ;
58+ try {
59+ value = std::stof (text, &processed);
60+ }
61+ catch (...) {
62+ return false ;
63+ }
64+
65+ return processed == text.size ();
66+ }
67+
68+ inline bool TryParseDoubleToken (std::string_view token, double & value) {
69+ if (token.empty ()) {
70+ return false ;
71+ }
72+
73+ const std::string text (token);
74+ size_t processed = 0 ;
75+ try {
76+ value = std::stod (text, &processed);
77+ }
78+ catch (...) {
79+ return false ;
80+ }
81+
82+ return processed == text.size ();
83+ }
84+
5085 // Serialize + call with a streaming chunk handler.
5186 // Wraps the caller-supplied onChunk with the native callback boilerplate
5287 // (null/length checks, exception capture, rethrow after the call).
5388 // The errorContext string is used to prefix any core-layer error message.
5489 inline CoreResponse CallWithStreamingCallback (Internal::IFoundryLocalCore* core, std::string_view command,
55- const std::string& payload, ILogger& logger,
56- const std::function<void (const std::string&)>& onChunk,
57- std::string_view errorContext) {
90+ const std::string* payload, ILogger& logger,
91+ const std::function<void (const std::string&)>& onChunk,
92+ std::string_view errorContext,
93+ CancellationCallback isCancellationRequested = nullptr) {
5894 struct State {
5995 const std::function<void (const std::string&)>* cb;
96+ CancellationCallback isCancellationRequested;
97+ bool cancellationObserved = false ;
6098 std::exception_ptr exception;
61- } state{&onChunk, nullptr };
62-
63- auto nativeCallback = [](void * data, int32_t len, void * user) {
64- if (!data || len <= 0 )
65- return ;
99+ } state{&onChunk, std::move (isCancellationRequested), false , nullptr };
66100
101+ auto nativeCallback = [](const void * data, int32_t len, void * user) -> int32_t {
67102 auto * st = static_cast <State*>(user);
68- if (st->exception )
69- return ;
103+ if (!st) {
104+ return 0 ;
105+ }
106+
107+ if (st->exception || st->cancellationObserved ) {
108+ return 1 ;
109+ }
110+
111+ if (!data || len <= 0 )
112+ return 0 ;
70113
71114 try {
115+ if (st->isCancellationRequested && st->isCancellationRequested ()) {
116+ st->cancellationObserved = true ;
117+ return 1 ;
118+ }
119+
72120 std::string chunk (static_cast <const char *>(data), static_cast <size_t >(len));
73121 (*(st->cb ))(chunk);
74122 }
75123 catch (...) {
76124 st->exception = std::current_exception ();
125+ return 1 ;
77126 }
127+
128+ return 0 ;
78129 };
79130
80- auto response = core->call (command, logger, &payload, +nativeCallback, &state);
131+ auto response = core->call (command, logger, payload, +nativeCallback, &state);
132+ if (state.cancellationObserved ) {
133+ throw Exception (" Operation cancelled" , logger);
134+ }
135+
81136 if (response.HasError ()) {
82137 throw Exception (std::string (errorContext) + response.error , logger);
83138 }
@@ -89,6 +144,15 @@ namespace foundry_local::detail {
89144 return response;
90145 }
91146
147+ inline CoreResponse CallWithStreamingCallback (Internal::IFoundryLocalCore* core, std::string_view command,
148+ const std::string& payload, ILogger& logger,
149+ const std::function<void (const std::string&)>& onChunk,
150+ std::string_view errorContext,
151+ CancellationCallback isCancellationRequested = nullptr) {
152+ return CallWithStreamingCallback (core, command, &payload, logger, onChunk, errorContext,
153+ std::move (isCancellationRequested));
154+ }
155+
92156 // Overload: allow Params object directly
93157 inline CoreResponse CallWithParams (Internal::IFoundryLocalCore* core, std::string_view command,
94158 const nlohmann::json& params, ILogger& logger) {
0 commit comments