Docs
Some checks failed
CI / Native Windows Build And Tests (push) Failing after 7s
CI / React UI Build (push) Has been cancelled
CI / Windows Release Package (push) Has been cancelled

This commit is contained in:
2026-05-03 12:11:53 +10:00
parent eeb8f294bf
commit cccb7a3aa3
7 changed files with 74 additions and 7 deletions

View File

@@ -54,6 +54,8 @@ std::string GuessContentType(const std::filesystem::path& assetPath)
return "text/css";
if (extension == ".json")
return "application/json";
if (extension == ".yaml" || extension == ".yml")
return "application/yaml";
if (extension == ".svg")
return "image/svg+xml";
if (extension == ".png")
@@ -78,9 +80,10 @@ ControlServer::~ControlServer()
Stop();
}
bool ControlServer::Start(const std::filesystem::path& uiRoot, unsigned short preferredPort, const Callbacks& callbacks, std::string& error)
bool ControlServer::Start(const std::filesystem::path& uiRoot, const std::filesystem::path& docsRoot, unsigned short preferredPort, const Callbacks& callbacks, std::string& error)
{
mUiRoot = uiRoot;
mDocsRoot = docsRoot;
mCallbacks = callbacks;
if (!InitializeWinsock(error))
@@ -246,6 +249,12 @@ ControlServer::HttpResponse ControlServer::ServeGetRequest(const HttpRequest& re
if (request.path == "/api/state")
return { "200 OK", "application/json", mCallbacks.getStateJson ? mCallbacks.getStateJson() : "{}" };
if (request.path == "/openapi.yaml" || request.path == "/docs/openapi.yaml")
return ServeOpenApiSpec();
if (request.path == "/docs" || request.path == "/docs/")
return ServeSwaggerDocs();
if (request.path.size() > 1)
{
const HttpResponse assetResponse = ServeUiAsset(request.path.substr(1));
@@ -265,6 +274,35 @@ ControlServer::HttpResponse ControlServer::ServeUiAsset(const std::string& relat
: HttpResponse{ "200 OK", contentType, body };
}
ControlServer::HttpResponse ControlServer::ServeOpenApiSpec() const
{
const std::filesystem::path specPath = mDocsRoot / "openapi.yaml";
const std::string body = LoadTextFile(specPath);
return body.empty()
? HttpResponse{ "404 Not Found", "text/plain", "OpenAPI spec not found" }
: HttpResponse{ "200 OK", GuessContentType(specPath), body };
}
ControlServer::HttpResponse ControlServer::ServeSwaggerDocs() const
{
std::ostringstream html;
html << "<!doctype html>\n"
<< "<html lang=\"en\">\n"
<< "<head>\n"
<< " <meta charset=\"utf-8\">\n"
<< " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
<< " <title>Video Shader Toys API Docs</title>\n"
<< " <link rel=\"stylesheet\" href=\"https://unpkg.com/swagger-ui-dist@5/swagger-ui.css\">\n"
<< "</head>\n"
<< "<body>\n"
<< " <div id=\"swagger-ui\"></div>\n"
<< " <script src=\"https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js\"></script>\n"
<< " <script>SwaggerUIBundle({url:'/docs/openapi.yaml',dom_id:'#swagger-ui'});</script>\n"
<< "</body>\n"
<< "</html>\n";
return { "200 OK", "text/html", html.str() };
}
ControlServer::HttpResponse ControlServer::HandleApiPost(const HttpRequest& request)
{
JsonValue root;
@@ -449,12 +487,16 @@ std::string ControlServer::LoadUiAsset(const std::string& relativePath, std::str
return std::string();
const std::filesystem::path assetPath = mUiRoot / sanitizedPath;
std::ifstream input(assetPath, std::ios::binary);
contentType = GuessContentType(assetPath);
return LoadTextFile(assetPath);
}
std::string ControlServer::LoadTextFile(const std::filesystem::path& path) const
{
std::ifstream input(path, std::ios::binary);
if (!input)
return std::string();
contentType = GuessContentType(assetPath);
std::ostringstream buffer;
buffer << input.rdbuf();
return buffer.str();