3#include <grpcpp/grpcpp.h>
5#include "absl/status/statusor.h"
6#include "absl/strings/escaping.h"
7#include "absl/strings/str_split.h"
8#include "absl/strings/string_view.h"
9#include "absl/time/time.h"
10#include "protos/emulator_service.grpc.pb.h"
22 auto channel = grpc::CreateChannel(
"localhost:50051",
23 grpc::InsecureChannelCredentials());
24 stub_ = agent::EmulatorService::NewStub(channel);
27 template <
typename TRequest,
typename TResponse>
29 grpc::Status (agent::EmulatorService::Stub::*rpc_method)(
30 grpc::ClientContext*, const TRequest&, TResponse*),
31 const TRequest& request) {
33 grpc::ClientContext context;
35 auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(5);
36 context.set_deadline(deadline);
39 (stub_.get()->*rpc_method)(&context, request, &response);
42 return absl::UnavailableError(absl::StrFormat(
43 "RPC failed: (%d) %s", status.error_code(), status.error_message()));
49 std::unique_ptr<agent::EmulatorService::Stub>
stub_;
55 return agent::Button::A;
57 return agent::Button::B;
59 return agent::Button::X;
61 return agent::Button::Y;
63 return agent::Button::L;
65 return agent::Button::R;
67 return agent::Button::SELECT;
69 return agent::Button::START;
71 return agent::Button::UP;
73 return agent::Button::DOWN;
75 return agent::Button::LEFT;
77 return agent::Button::RIGHT;
78 return absl::InvalidArgumentError(absl::StrCat(
"Unknown button: ", s));
88 EmulatorClient client;
91 client.CallRpc(&agent::EmulatorService::Stub::Reset, request);
92 if (!response_or.ok()) {
93 return response_or.status();
95 auto response = response_or.value();
98 formatter.
AddField(
"success", response.success());
99 formatter.
AddField(
"message", response.message());
101 return absl::OkStatus();
107 EmulatorClient client;
108 agent::GameStateRequest request;
109 request.set_include_screenshot(parser.
HasFlag(
"screenshot"));
112 client.CallRpc(&agent::EmulatorService::Stub::GetGameState, request);
113 if (!response_or.ok()) {
114 return response_or.status();
116 auto response = response_or.value();
119 formatter.
AddField(
"game_mode",
static_cast<uint64_t
>(response.game_mode()));
121 static_cast<uint64_t
>(response.link_state()));
123 static_cast<uint64_t
>(response.link_pos_x()));
125 static_cast<uint64_t
>(response.link_pos_y()));
127 static_cast<uint64_t
>(response.link_health()));
128 if (!response.screenshot_png().empty()) {
129 formatter.
AddField(
"screenshot_size",
130 static_cast<uint64_t
>(response.screenshot_png().size()));
133 return absl::OkStatus();
139 EmulatorClient client;
140 agent::MemoryRequest request;
143 if (!absl::SimpleHexAtoi(parser.
GetString(
"address").value(), &address)) {
144 return absl::InvalidArgumentError(
"Invalid address format.");
146 request.set_address(address);
147 request.set_size(parser.
GetInt(
"length").value_or(16));
150 client.CallRpc(&agent::EmulatorService::Stub::ReadMemory, request);
151 if (!response_or.ok()) {
152 return response_or.status();
154 auto response = response_or.value();
157 formatter.
AddHexField(
"address", response.address());
158 formatter.
AddField(
"data_hex", absl::BytesToHexString(response.data()));
160 return absl::OkStatus();
166 EmulatorClient client;
167 agent::MemoryWriteRequest request;
170 if (!absl::SimpleHexAtoi(parser.
GetString(
"address").value(), &address)) {
171 return absl::InvalidArgumentError(
"Invalid address format.");
173 request.set_address(address);
175 std::string data_hex = parser.
GetString(
"data").value();
176 request.set_data(absl::HexStringToBytes(data_hex));
179 client.CallRpc(&agent::EmulatorService::Stub::WriteMemory, request);
180 if (!response_or.ok()) {
181 return response_or.status();
183 auto response = response_or.value();
186 formatter.
AddField(
"success", response.success());
187 formatter.
AddField(
"message", response.message());
189 return absl::OkStatus();
195 EmulatorClient client;
196 agent::ButtonRequest request;
197 std::vector<std::string> buttons =
198 absl::StrSplit(parser.
GetString(
"buttons").value(),
',');
199 for (
const auto& btn_str : buttons) {
200 auto button_or = StringToButton(btn_str);
202 return button_or.status();
203 request.add_buttons(button_or.value());
207 client.CallRpc(&agent::EmulatorService::Stub::PressButtons, request);
208 if (!response_or.ok()) {
209 return response_or.status();
211 auto response = response_or.value();
214 formatter.
AddField(
"success", response.success());
215 formatter.
AddField(
"message", response.message());
217 return absl::OkStatus();
223 EmulatorClient client;
224 agent::ButtonRequest request;
225 std::vector<std::string> buttons =
226 absl::StrSplit(parser.
GetString(
"buttons").value(),
',');
227 for (
const auto& btn_str : buttons) {
228 auto button_or = StringToButton(btn_str);
230 return button_or.status();
231 request.add_buttons(button_or.value());
235 client.CallRpc(&agent::EmulatorService::Stub::ReleaseButtons, request);
236 if (!response_or.ok()) {
237 return response_or.status();
239 auto response = response_or.value();
242 formatter.
AddField(
"success", response.success());
243 formatter.
AddField(
"message", response.message());
245 return absl::OkStatus();
251 EmulatorClient client;
252 agent::ButtonHoldRequest request;
253 std::vector<std::string> buttons =
254 absl::StrSplit(parser.
GetString(
"buttons").value(),
',');
255 for (
const auto& btn_str : buttons) {
256 auto button_or = StringToButton(btn_str);
258 return button_or.status();
259 request.add_buttons(button_or.value());
261 request.set_duration_ms(parser.
GetInt(
"duration").value());
264 client.CallRpc(&agent::EmulatorService::Stub::HoldButtons, request);
265 if (!response_or.ok()) {
266 return response_or.status();
268 auto response = response_or.value();
271 formatter.
AddField(
"success", response.success());
272 formatter.
AddField(
"message", response.message());
274 return absl::OkStatus();
283 formatter.
AddField(
"status",
"not_implemented");
285 return absl::OkStatus();
292 formatter.
AddField(
"status",
"not_implemented");
294 return absl::OkStatus();
301 formatter.
AddField(
"status",
"not_implemented");
303 return absl::OkStatus();
310 formatter.
AddField(
"status",
"not_implemented");
312 return absl::OkStatus();
318 formatter.
BeginObject(
"Emulator Breakpoint Cleared");
319 formatter.
AddField(
"status",
"not_implemented");
321 return absl::OkStatus();
328 formatter.
AddField(
"status",
"not_implemented");
330 return absl::OkStatus();
337 formatter.
AddField(
"status",
"not_implemented");
339 return absl::OkStatus();
346 formatter.
AddField(
"status",
"not_implemented");
348 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::StatusOr< TResponse > CallRpc(grpc::Status(agent::EmulatorService::Stub::*rpc_method)(grpc::ClientContext *, const TRequest &, TResponse *), const TRequest &request)
std::unique_ptr< agent::EmulatorService::Stub > stub_
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
bool HasFlag(const std::string &name) const
Check if a flag is present.
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
absl::StatusOr< agent::Button > StringToButton(absl::string_view s)