feat: add frontend app, improve static file serving with lazy loading and root redirect
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
"port": 8000,
|
||||
"pipelines_dir": "./storage/pipelines/",
|
||||
"logs_dir": "./storage/logs/",
|
||||
"web_root": ""
|
||||
"web_root": "../../frontend/build/web/"
|
||||
}
|
||||
|
||||
@@ -81,6 +81,11 @@ bool Server::start() {
|
||||
|
||||
void Server::serveStaticFiles(const PIString & webRoot) {
|
||||
PIDir rootDir(webRoot);
|
||||
if (!rootDir.isExists()) {
|
||||
piCout << "WARNING: web_root does not exist: " << webRoot;
|
||||
return;
|
||||
}
|
||||
|
||||
piCout << "Serving static files from: " << rootDir.absolutePath();
|
||||
|
||||
const auto filelist = PIDir::allEntries(webRoot);
|
||||
@@ -88,23 +93,22 @@ void Server::serveStaticFiles(const PIString & webRoot) {
|
||||
if (!finfo.isFile()) continue;
|
||||
if (finfo.name().startsWith('.')) continue;
|
||||
|
||||
PIString relPath = finfo.dir().removeAll(webRoot) + finfo.name();
|
||||
if (relPath.isEmpty() || relPath[0] != '/') {
|
||||
relPath = "/" + relPath;
|
||||
// Compute relative path, same logic as meshbackend
|
||||
PIString wpath = finfo.dir().removeAll(rootDir.absolutePath()) + finfo.name();
|
||||
if (wpath.isEmpty() || wpath[0] != '/') {
|
||||
wpath = "/" + wpath;
|
||||
}
|
||||
|
||||
PIString ext = finfo.extension().toLowerCase();
|
||||
PIString contentType = StaticContentTypes.value(ext, "application/octet-stream");
|
||||
|
||||
PIByteArray fileData = PIFile::readAll(finfo.path);
|
||||
PIString contentType = StaticContentTypes.value(finfo.extension().toLowerCase(), "application/octet-stream");
|
||||
PIByteArray fileData = PIFile::readAll(rootDir.absolutePath() + wpath);
|
||||
PIString etag = PIDigest::calculate(fileData, PIDigest::Type::BLAKE2s_128).toHex().quote();
|
||||
|
||||
piCout << " Registered: " << relPath << " (" << contentType << ", ETag: " << etag << ")";
|
||||
piCout << " Registered: " << wpath << " (" << contentType << ", " << fileData.size() << " bytes)";
|
||||
|
||||
auto handler = [fileData, contentType, etag](const PIHTTP::MessageConst & request) {
|
||||
auto handler = [wpath, rootLocation = rootDir.absolutePath(), contentType, etag](const PIHTTP::MessageConst & request) {
|
||||
PIHTTP::MessageMutable msg;
|
||||
msg.addHeader(PIHTTP::Header::ContentType, contentType);
|
||||
msg.addHeader(PIHTTP::Header::CacheControl, "max-age=3600");
|
||||
msg.addHeader(PIHTTP::Header::CacheControl, "max-age=100");
|
||||
msg.addHeader(PIHTTP::Header::ETag, etag);
|
||||
|
||||
PIString clientEtag = request.headers().value(PIHTTP::Header::IfNoneMatch, PIString());
|
||||
@@ -113,12 +117,20 @@ void Server::serveStaticFiles(const PIString & webRoot) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg.setBody(fileData);
|
||||
msg.setBody(PIFile::readAll(rootLocation + wpath));
|
||||
return msg;
|
||||
};
|
||||
|
||||
httpserver_->registerPath(relPath, PIHTTP::Method::Get, handler);
|
||||
httpserver_->registerPath(wpath, PIHTTP::Method::Get, handler);
|
||||
}
|
||||
|
||||
// Redirect "/" to "/index.html" (same as meshbackend)
|
||||
httpserver_->registerPath("/", PIHTTP::Method::Get, [](const PIHTTP::MessageConst &) {
|
||||
PIHTTP::MessageMutable msg;
|
||||
msg.setCode(PIHTTP::Code::MovedPermanently);
|
||||
msg.addHeader("Location", "/index.html");
|
||||
return msg;
|
||||
});
|
||||
}
|
||||
|
||||
PIHTTP::MessageMutable Server::listPipelines(const PIHTTP::MessageConst & request) {
|
||||
@@ -327,5 +339,7 @@ PIHTTP::MessageMutable Server::getRunLog(const PIHTTP::MessageConst & request) {
|
||||
|
||||
PIHTTP::MessageMutable Server::unhandledRequest(const PIHTTP::MessageConst & request) {
|
||||
piCout << "Unhandled: " << PIHTTP::methodName(request.method()) << " " << request.path();
|
||||
return MessageUtils::errorReply(PIHTTP::Code::NotFound, "Not found");
|
||||
PIHTTP::MessageMutable msg;
|
||||
msg.setCode(PIHTTP::Code::NotFound);
|
||||
return msg;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user