Skip to content

Commit

Permalink
Merge pull request #1467 from nicolasnoble/cd-patching-web-server
Browse files Browse the repository at this point in the history
Adding cd iso patching webserver endpoint.
  • Loading branch information
nicolasnoble authored Nov 23, 2023
2 parents f029c42 + c23be7e commit 2ced8d9
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/core/cdrom.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class CDRom {

virtual void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) = 0;

std::shared_ptr<CDRIso> getIso() const { return m_iso; }

protected:
std::shared_ptr<CDRIso> m_iso;
// savestate stuff starts here
Expand Down
111 changes: 103 additions & 8 deletions src/core/web-server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
#include <string>

#include "GL/gl3w.h"
#include "cdrom/cdriso.h"
#include "cdrom/file.h"
#include "cdrom/iso9660-builder.h"
#include "cdrom/iso9660-reader.h"
#include "core/cdrom.h"
#include "core/gpu.h"
#include "core/psxemulator.h"
#include "core/psxmem.h"
Expand Down Expand Up @@ -237,14 +242,7 @@ class FlowExecutor : public PCSX::WebExecutor {
j["isDynarec"] = PCSX::g_emulator->m_cpu->isDynarec();
j["8mb"] = PCSX::g_emulator->settings.get<PCSX::Emulator::Setting8MB>().value;
j["debugger"] = debugSettings.get<PCSX::Emulator::DebugSettings::Debug>().value;

std::string json = j.dump();
std::string message = std::string(
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Content-Length: ") +
std::to_string(json.size()) + std::string("\r\n\r\n") + json;
client->write(std::move(message));
write200(client, j);
return true;
} else if (request.method == PCSX::RequestData::Method::HTTP_POST) {
auto vars = parseQuery(request.urlData.query);
Expand Down Expand Up @@ -400,6 +398,92 @@ class LuaExecutor : public PCSX::WebExecutor {
virtual ~LuaExecutor() = default;
};

class CDExecutor : public PCSX::WebExecutor {
virtual bool match(PCSX::WebClient* client, const PCSX::UrlData& urldata) final {
return PCSX::StringsHelpers::startsWith(urldata.path, c_prefix);
}
virtual bool execute(PCSX::WebClient* client, PCSX::RequestData& request) final {
auto path = request.urlData.path.substr(c_prefix.length());
auto& cdrom = PCSX::g_emulator->m_cdrom;
auto iso = cdrom->getIso();
PCSX::ISO9660Reader reader(iso);

if (request.method == PCSX::RequestData::Method::HTTP_HTTP_GET) {
if (path == "info") {
nlohmann::json j;
j["id"] = cdrom->getCDRomID();
j["label"] = cdrom->getCDRomLabel();
j["iso"]["TN"] = iso->getTN();
for (unsigned t = 0; t <= iso->getTN(); t++) {
if (t != 0) {
j["iso"]["tracktype"][t] = magic_enum::enum_name(iso->getTrackType(t));
}
auto duration = iso->getTD(t);
j["iso"]["TD"][t]["m"] = duration.m;
j["iso"]["TD"][t]["s"] = duration.s;
j["iso"]["TD"][t]["f"] = duration.f;
}
write200(client, j);
return true;
}
return false;
} else if (request.method == PCSX::RequestData::Method::HTTP_POST) {
if (path == "patch") {
auto vars = parseQuery(request.urlData.query);
auto filename = vars.find("filename");
auto sector = vars.find("sector");
auto modeStr = vars.find("mode");
PCSX::SectorMode mode = PCSX::SectorMode::GUESS;
if ((filename == vars.end()) && (sector == vars.end())) {
client->write("HTTP/1.1 400 Bad Request\r\n\r\n");
return true;
}
if ((filename != vars.end()) && (sector != vars.end())) {
client->write("HTTP/1.1 400 Bad Request\r\n\r\n");
return true;
}
if (modeStr != vars.end()) {
auto modeCast = magic_enum::enum_cast<PCSX::SectorMode>(modeStr->second);
if (modeCast.has_value()) {
mode = modeCast.value();
} else {
client->write("HTTP/1.1 400 Bad Request\r\n\r\n");
return true;
}
}

PCSX::IO<PCSX::File> file;

if (filename != vars.end()) {
file = reader.open(filename->second);
}

if (sector != vars.end()) {
auto sectorNumber = std::stoul(sector->second);
file = new PCSX::CDRIsoFile(iso, sectorNumber, request.body.size(), mode);
}

if (file->failed()) {
client->write("HTTP/1.1 404 File Not Found\r\n\r\n");
return true;
}

file->write(request.body.data<uint8_t>(), request.body.size());
iso->getPPF()->save(iso->getIsoPath());
client->write("HTTP/1.1 200 OK\r\n\r\n");
return true;
}
return false;
}
return false;
}

public:
const std::string_view c_prefix = "/api/v1/cd/";
CDExecutor() = default;
virtual ~CDExecutor() = default;
};

} // namespace

std::multimap<std::string, std::string> PCSX::WebExecutor::parseQuery(const std::string& query) {
Expand Down Expand Up @@ -445,13 +529,24 @@ std::string PCSX::WebExecutor::percentDecode(std::string_view str) {
return ret;
}

void PCSX::WebExecutor::write200(PCSX::WebClient* client, const nlohmann::json& j) {
std::string json = j.dump();
std::string message = std::string(
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Content-Length: ") +
std::to_string(json.size()) + std::string("\r\n\r\n") + json;
client->write(std::move(message));
}

PCSX::WebServer::WebServer() : m_listener(g_system->m_eventBus) {
m_executors.push_back(new VramExecutor());
m_executors.push_back(new RamExecutor());
m_executors.push_back(new AssemblyExecutor());
m_executors.push_back(new CacheExecutor());
m_executors.push_back(new FlowExecutor());
m_executors.push_back(new LuaExecutor());
m_executors.push_back(new CDExecutor());
m_listener.listen<Events::SettingsLoaded>([this](const auto& event) {
auto& debugSettings = g_emulator->settings.get<Emulator::SettingDebugSettings>();
if (debugSettings.get<Emulator::DebugSettings::WebServer>() && (m_serverStatus != SERVER_STARTED)) {
Expand Down
2 changes: 2 additions & 0 deletions src/core/web-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <memory>
#include <string>

#include "json.hpp"
#include "support/eventbus.h"
#include "support/list.h"
#include "support/slice.h"
Expand Down Expand Up @@ -93,6 +94,7 @@ class WebExecutor : public Intrusive::List<WebExecutor>::Node {
virtual bool execute(WebClient* client, RequestData&) = 0;
std::multimap<std::string, std::string> parseQuery(const std::string&);
std::string percentDecode(std::string_view);
void write200(WebClient* client, const nlohmann::json& j);
};

class WebClient : public Intrusive::List<WebClient>::Node {
Expand Down

0 comments on commit 2ced8d9

Please sign in to comment.