yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
http_server.cc
Go to the documentation of this file.
2
3#include <string>
4
6#include "util/log.h"
7
8#include "httplib.h"
9
10namespace yaze {
11namespace cli {
12namespace api {
13
14HttpServer::HttpServer() : server_(std::make_unique<httplib::Server>()) {}
15
19
20absl::Status HttpServer::Start(int port) {
21 if (is_running_) {
22 return absl::AlreadyExistsError("Server is already running");
23 }
24
25 if (!server_->is_valid()) {
26 return absl::InternalError("HttpServer is not valid");
27 }
28
30
31 port_ = port;
32 is_running_ = true;
33 server_thread_ = std::make_unique<std::thread>([this, port]() {
34 LOG_INFO("HttpServer", "Starting API server on port %d", port);
35 bool ret = server_->listen("0.0.0.0", port);
36 if (!ret) {
37 LOG_ERROR("HttpServer", "Failed to listen on port %d", port);
38 }
39 is_running_ = false;
40 });
41
42 // Publish Bonjour service for LAN discovery by iOS clients.
44 if (bonjour_.IsAvailable()) {
45 if (bonjour_.IsPublished()) {
46 LOG_INFO("HttpServer", "Bonjour discovery published on port %d", port);
47 } else {
48 LOG_ERROR("HttpServer", "Bonjour discovery failed to publish on port %d",
49 port);
50 }
51 } else {
52 LOG_INFO("HttpServer",
53 "Bonjour discovery not available on this platform, skipping");
54 }
55
56 return absl::OkStatus();
57}
58
60 if (is_running_) {
61 LOG_INFO("HttpServer", "Stopping API server...");
63 server_->stop();
64 if (server_thread_ && server_thread_->joinable()) {
65 server_thread_->join();
66 }
67 is_running_ = false;
68 LOG_INFO("HttpServer", "API server stopped");
69 }
70}
71
73 return is_running_;
74}
75
77 server_->set_error_handler(
78 [](const httplib::Request& req, httplib::Response& res) {
79 (void)req;
81 if (!res.body.empty()) {
82 return;
83 }
84 const char* message = "Request failed";
85 switch (res.status) {
86 case 400:
87 message = "Bad request";
88 break;
89 case 404:
90 message = "Not found";
91 break;
92 case 405:
93 message = "Method not allowed";
94 break;
95 case 501:
96 message = "Not implemented";
97 break;
98 case 503:
99 message = "Service unavailable";
100 break;
101 case 500:
102 message = "Internal server error";
103 break;
104 default:
105 break;
106 }
107 std::string body = std::string("{\"error\":\"") + message + "\"}";
108 res.set_content(body, "application/json");
109 });
110
111 server_->Get("/api/v1/health",
112 [this](const httplib::Request& req, httplib::Response& res) {
113 HandleHealth(req, res, &bonjour_);
114 });
115 server_->Get("/api/v1/models", HandleListModels);
116 server_->Options("/api/v1/health", HandleCorsPreflight);
117 server_->Options("/api/v1/models", HandleCorsPreflight);
118
119 server_->Get("/api/v1/symbols",
120 [this](const httplib::Request& req, httplib::Response& res) {
121 emu::debug::SymbolProvider* symbols = nullptr;
122 if (symbol_source_) {
123 symbols = symbol_source_();
124 }
125 HandleGetSymbols(req, res, symbols);
126 });
127 server_->Options("/api/v1/symbols", HandleCorsPreflight);
128
129 server_->Post("/api/v1/navigate", HandleNavigate);
130 server_->Post("/api/v1/breakpoint/hit", HandleBreakpointHit);
131 server_->Post("/api/v1/state/update", HandleStateUpdate);
132 server_->Options("/api/v1/navigate", HandleCorsPreflight);
133 server_->Options("/api/v1/breakpoint/hit", HandleCorsPreflight);
134 server_->Options("/api/v1/state/update", HandleCorsPreflight);
135
136 server_->Post("/api/v1/window/show",
137 [this](const httplib::Request& req, httplib::Response& res) {
139 });
140 server_->Options("/api/v1/window/show", HandleCorsPreflight);
141
142 server_->Post("/api/v1/window/hide",
143 [this](const httplib::Request& req, httplib::Response& res) {
145 });
146 server_->Options("/api/v1/window/hide", HandleCorsPreflight);
147
148 server_->Get("/api/v1/render/dungeon",
149 [this](const httplib::Request& req, httplib::Response& res) {
151 render_source_ ? render_source_() : nullptr;
152 HandleRenderDungeon(req, res, rs);
153 });
154 server_->Options("/api/v1/render/dungeon", HandleCorsPreflight);
155
156 server_->Get("/api/v1/render/dungeon/metadata",
157 [this](const httplib::Request& req, httplib::Response& res) {
159 render_source_ ? render_source_() : nullptr;
160 HandleRenderDungeonMetadata(req, res, rs);
161 });
162 server_->Options("/api/v1/render/dungeon/metadata", HandleCorsPreflight);
163
164 // Command execution endpoints (Phase 3)
165 server_->Post("/api/v1/command/execute",
166 [this](const httplib::Request& req, httplib::Response& res) {
167 Rom* rom = rom_source_ ? rom_source_() : nullptr;
168 HandleCommandExecute(req, res, rom);
169 });
170 server_->Get("/api/v1/command/list", HandleCommandList);
171 server_->Options("/api/v1/command/execute", HandleCorsPreflight);
172 server_->Options("/api/v1/command/list", HandleCorsPreflight);
173
174 // Annotation CRUD endpoints (Phase 4)
175 auto project_path_lambda = [this]() -> std::string {
177 };
178 server_->Get("/api/v1/annotations",
179 [project_path_lambda](const httplib::Request& req,
180 httplib::Response& res) {
181 HandleAnnotationList(req, res, project_path_lambda());
182 });
183 server_->Post("/api/v1/annotations",
184 [project_path_lambda](const httplib::Request& req,
185 httplib::Response& res) {
186 HandleAnnotationCreate(req, res, project_path_lambda());
187 });
188 server_->Put(R"(/api/v1/annotations/(.+))",
189 [project_path_lambda](const httplib::Request& req,
190 httplib::Response& res) {
191 HandleAnnotationUpdate(req, res, project_path_lambda());
192 });
193 server_->Delete(R"(/api/v1/annotations/(.+))",
194 [project_path_lambda](const httplib::Request& req,
195 httplib::Response& res) {
196 HandleAnnotationDelete(req, res, project_path_lambda());
197 });
198 server_->Options("/api/v1/annotations", HandleCorsPreflight);
199 server_->Options(R"(/api/v1/annotations/(.+))", HandleCorsPreflight);
200}
201
202} // namespace api
203} // namespace cli
204} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
void Unpublish()
Stop advertising. Safe to call multiple times.
void Publish(int port, const std::string &rom_title="")
Start advertising. Call after the HTTP server socket is bound.
std::unique_ptr< httplib::Server > server_
Definition http_server.h:94
BonjourPublisher bonjour_
Definition http_server.h:98
RenderServiceSource render_source_
SymbolProviderSource symbol_source_
Definition http_server.h:99
absl::Status Start(int port)
ProjectPathSource project_path_source_
std::unique_ptr< std::thread > server_thread_
Definition http_server.h:95
std::atomic< bool > is_running_
Definition http_server.h:96
Provider for symbol (label) resolution in disassembly.
#define LOG_ERROR(category, format,...)
Definition log.h:109
#define LOG_INFO(category, format,...)
Definition log.h:105
void HandleStateUpdate(const httplib::Request &req, httplib::Response &res)
void ApplyCorsHeaders(httplib::Response &res)
void HandleCorsPreflight(const httplib::Request &req, httplib::Response &res)
void HandleBreakpointHit(const httplib::Request &req, httplib::Response &res)
void HandleListModels(const httplib::Request &req, httplib::Response &res)
void HandleGetSymbols(const httplib::Request &req, httplib::Response &res, yaze::emu::debug::SymbolProvider *symbols)
void HandleNavigate(const httplib::Request &req, httplib::Response &res)
void HandleWindowShow(const httplib::Request &req, httplib::Response &res, const std::function< bool()> &action)
void HandleAnnotationUpdate(const httplib::Request &req, httplib::Response &res, const std::string &project_path)
void HandleRenderDungeonMetadata(const httplib::Request &req, httplib::Response &res, yaze::app::service::RenderService *render_service)
void HandleRenderDungeon(const httplib::Request &req, httplib::Response &res, yaze::app::service::RenderService *render_service)
void HandleCommandExecute(const httplib::Request &req, httplib::Response &res, yaze::Rom *rom)
void HandleAnnotationDelete(const httplib::Request &req, httplib::Response &res, const std::string &project_path)
void HandleAnnotationList(const httplib::Request &req, httplib::Response &res, const std::string &project_path)
void HandleAnnotationCreate(const httplib::Request &req, httplib::Response &res, const std::string &project_path)
void HandleCommandList(const httplib::Request &req, httplib::Response &res)
void HandleWindowHide(const httplib::Request &req, httplib::Response &res, const std::function< bool()> &action)
void HandleHealth(const httplib::Request &req, httplib::Response &res, const BonjourPublisher *bonjour)