Resources: use oatpp::data::resource::File/InMemoryData

This commit is contained in:
Leonid Stryzhevskyi 2024-06-05 02:13:23 +03:00
parent f39e6a5fa3
commit 8cb460b546
5 changed files with 111 additions and 193 deletions

View File

@ -124,16 +124,7 @@ public:
ENDPOINT_ASYNC_INIT(GetUIRoot)
Action act() override {
std::string ui;
if(controller->m_resources->isStreaming()) {
v_char8 buffer[1024];
auto fileStream = controller->m_resources->getResourceStream("index.html");
oatpp::data::stream::BufferOutputStream s(1024);
oatpp::data::stream::transfer(fileStream, &s, 0, buffer, 1024);
ui = s.toString();
} else {
ui = * controller->m_resources->getResource("index.html"); // * - copy of the index.html
}
auto ui = controller->m_resources->getResourceData("index.html");
return _return(controller->createResponse(Status::CODE_200, ui));
}
@ -144,16 +135,7 @@ public:
ENDPOINT_ASYNC_INIT(GetInitializer)
Action act() override {
std::string ui;
if(controller->m_resources->isStreaming()) {
v_char8 buffer[1024];
auto fileStream = controller->m_resources->getResourceStream("swagger-initializer.js");
oatpp::data::stream::BufferOutputStream s(1024);
oatpp::data::stream::transfer(fileStream, &s, 0, buffer, 1024);
ui = s.toString();
} else {
ui = * controller->m_resources->getResource("swagger-initializer.js"); // * - copy of the index.html
}
std::string ui = controller->m_resources->getResourceData("swagger-initializer.js");
ui.replace(ui.find("%%API.JSON%%"), 12, controller->m_paths.apiJson);
return _return(controller->createResponse(Status::CODE_200, ui));
}
@ -167,18 +149,14 @@ public:
Action act() override {
auto filename = request->getPathVariable("filename");
OATPP_ASSERT_HTTP(filename, Status::CODE_400, "filename should not be null")
if(controller->m_resources->isStreaming()) {
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
controller->m_resources->getResourceStream(filename->c_str())
);
auto resp = OutgoingResponse::createShared(Status::CODE_200, body);
resp->putHeader("Content-Type", controller->m_resources->getMimeType(filename));
return _return(resp);
}
auto resp = controller->createResponse(Status::CODE_200,
controller->m_resources->getResource(filename->c_str()));
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
controller->m_resources->getResource(filename)->openInputStream()
);
auto resp = OutgoingResponse::createShared(Status::CODE_200, body);
resp->putHeader("Content-Type", controller->m_resources->getMimeType(filename));
return _return(resp);
}
};

View File

@ -112,44 +112,20 @@ public:
}
ENDPOINT("GET", m_paths.ui, getUIRoot) {
std::string ui;
if(m_resources->isStreaming()) {
v_char8 buffer[1024];
auto fileStream = m_resources->getResourceStream("index.html");
oatpp::data::stream::BufferOutputStream s(1024);
oatpp::data::stream::transfer(fileStream, &s, 0, buffer, 1024);
ui = s.toString();
} else {
ui = *m_resources->getResource("index.html"); // * - copy of the index.html
}
return createResponse(Status::CODE_200, ui);
return createResponse(Status::CODE_200, m_resources->getResourceData("index.html"));
}
ENDPOINT("GET", m_paths.initializer, getInitializer) {
std::string ui;
if(m_resources->isStreaming()) {
v_char8 buffer[1024];
auto fileStream = m_resources->getResourceStream("swagger-initializer.js");
oatpp::data::stream::BufferOutputStream s(1024);
oatpp::data::stream::transfer(fileStream, &s, 0, buffer, 1024);
ui = s.toString();
} else {
ui = *m_resources->getResource("swagger-initializer.js"); // * - copy of the index.html
}
std::string ui = m_resources->getResourceData("swagger-initializer.js");
ui.replace(ui.find("%%API.JSON%%"), 12, m_paths.apiJson);
return createResponse(Status::CODE_200, ui);
}
ENDPOINT("GET", m_paths.uiResources, getUIResource, PATH(String, filename)) {
if(m_resources->isStreaming()) {
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
m_resources->getResourceStream(filename->c_str())
);
auto resp = OutgoingResponse::createShared(Status::CODE_200, body);
resp->putHeader("Content-Type", m_resources->getMimeType(filename));
return resp;
}
auto resp = createResponse(Status::CODE_200, m_resources->getResource(filename->c_str()));
auto body = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
m_resources->getResource(filename)->openInputStream()
);
auto resp = OutgoingResponse::createShared(Status::CODE_200, body);
resp->putHeader("Content-Type", m_resources->getMimeType(filename));
return resp;
}

View File

@ -24,87 +24,85 @@
#include "Resources.hpp"
#include "oatpp/data/resource/File.hpp"
#include "oatpp/data/resource/InMemoryData.hpp"
#include "oatpp/base/Log.hpp"
#include <stdio.h>
#include <fstream>
namespace oatpp { namespace swagger {
Resources::Resources(const oatpp::String& resDir, bool streaming) {
if(!resDir || resDir->size() == 0) {
Resources::Resources(const oatpp::String& resDir, bool streaming)
: m_resDir(resDir)
, m_streaming(streaming)
{
if(!resDir || resDir->empty()) {
throw std::runtime_error("[oatpp::swagger::Resources::Resources()]: Invalid resDir path. Please specify full path to oatpp-swagger/res folder");
}
m_resDir = resDir;
if(m_resDir->data()[m_resDir->size() - 1] != '/') {
m_resDir = m_resDir + "/";
}
m_streaming = streaming;
addResource("favicon-16x16.png");
addResource("favicon-32x32.png");
addResource("index.css");
addResource("index.html");
addResource("oauth2-redirect.html");
addResource("swagger-initializer.js");
addResource("swagger-ui-bundle.js");
addResource("swagger-ui-bundle.js.map");
addResource("swagger-ui-es-bundle-core.js");
addResource("swagger-ui-es-bundle-core.js.map");
addResource("swagger-ui-es-bundle.js");
addResource("swagger-ui-es-bundle.js.map");
addResource("swagger-ui-standalone-preset.js");
addResource("swagger-ui-standalone-preset.js.map");
addResource("swagger-ui.css");
addResource("swagger-ui.css.map");
addResource("swagger-ui.js");
addResource("swagger-ui.js.map");
}
void Resources::cacheResource(const char* fileName) {
m_resources[fileName] = loadFromFile(fileName);
}
oatpp::String Resources::loadFromFile(const char* fileName) {
auto fullFilename = m_resDir + fileName;
std::ifstream file (fullFilename->c_str(), std::ios::in|std::ios::binary|std::ios::ate);
if (file.is_open()) {
auto result = oatpp::String((v_int32) file.tellg());
file.seekg(0, std::ios::beg);
file.read((char*)result->data(), result->size());
file.close();
return result;
void Resources::addResource(const oatpp::String& fileName) {
if(m_streaming) {
m_resources[fileName] = std::make_shared<data::resource::File>(m_resDir, fileName);
} else {
auto path = data::resource::File::concatDirAndName(m_resDir, fileName);
auto data = oatpp::String::loadFromFile(path->c_str());
if(!data) {
OATPP_LOGe("oatpp::swagger::Resources::addResource()", "Can't load file '{}'", path);
throw std::runtime_error("[oatpp::swagger::Resources::addResource()]: Can't load file. Please make sure you specified full path to oatpp-swagger/res folder");
}
m_resources[fileName] = std::make_shared<data::resource::InMemoryData>(data);
}
OATPP_LOGe("oatpp::swagger::Resources::loadFromFile()", "Can't load file '{}'", fullFilename);
throw std::runtime_error("[oatpp::swagger::Resources::loadFromFile(...)]: Can't load file. Please make sure you specified full path to oatpp-swagger/res folder");
}
oatpp::String Resources::getResource(const oatpp::String& filename) {
void Resources::overrideResource(const oatpp::String& filename, const std::shared_ptr<data::resource::Resource>& resource) {
m_resources[filename] = resource;
}
std::shared_ptr<data::resource::Resource> Resources::getResource(const oatpp::String& filename) const {
auto it = m_resources.find(filename);
if(it != m_resources.end()) {
return it->second;
}
throw std::runtime_error(
"[oatpp::swagger::Resources::getResource(...)]: Resource file not found. "
throw std::runtime_error("[oatpp::swagger::Resources::getResource()]: Resource file not found. "
"Please make sure: "
"1. You are using correct version of oatpp-swagger. "
"2. oatpp-swagger/res is not empty. "
"3. You specified correct full path to oatpp-swagger/res folder"
);
"3. You specified correct full path to oatpp-swagger/res folder");
}
std::shared_ptr<Resources::ReadCallback> Resources::getResourceStream(const oatpp::String &filename) {
try {
return std::make_shared<ReadCallback>(m_resDir + filename);
} catch(std::runtime_error &e) {
throw std::runtime_error(
"[oatpp::swagger::Resources::getResource(...)]: Resource file not found. "
"Please make sure: "
"1. You are using correct version of oatpp-swagger. "
"2. oatpp-swagger/res is not empty. "
"3. You specified correct full path to oatpp-swagger/res folder"
);
oatpp::String Resources::getResourceData(const oatpp::String& filename) const {
auto resource = getResource(filename);
if(resource->getInMemoryData() && resource->getKnownSize() > 0) {
return resource->getInMemoryData();
}
}
Resources::ReadCallback::ReadCallback(const oatpp::String &file) : m_file(file), m_stream(file->c_str())
{}
v_io_size Resources::ReadCallback::read(void *buffer, v_buff_size count, async::Action& action) {
return m_stream.read(buffer, count, action);
v_char8 buffer[1024];
oatpp::data::stream::BufferOutputStream ss(1024);
oatpp::data::stream::transfer(resource->openInputStream(), &ss, 0, buffer, 1024);
return ss.toString();
}
bool Resources::hasEnding(std::string fullString, std::string const &ending) const {
@ -129,4 +127,8 @@ std::string Resources::getMimeType(const std::string &filename) const {
return "text/plain";
}
bool Resources::isStreaming() const {
return m_streaming;
}
}}

View File

@ -28,10 +28,10 @@
#include "oatpp/Types.hpp"
#include "oatpp/data/stream/BufferStream.hpp"
#include "oatpp/data/stream/FileStream.hpp"
#include "oatpp/data/resource/Resource.hpp"
#include <unordered_map>
namespace oatpp { namespace swagger {
/**
@ -40,102 +40,64 @@ namespace oatpp { namespace swagger {
class Resources {
private:
oatpp::String m_resDir;
std::unordered_map<oatpp::String, oatpp::String> m_resources;
bool m_streaming;
std::unordered_map<oatpp::String, std::shared_ptr<data::resource::Resource>> m_resources;
private:
oatpp::String loadFromFile(const char* fileName);
void cacheResource(const char* fileName);
void addResource(const oatpp::String& fileName);
bool hasEnding(std::string fullString, std::string const &ending) const;
class ReadCallback : public oatpp::data::stream::ReadCallback {
private:
oatpp::String m_file;
oatpp::data::stream::FileInputStream m_stream;
public:
ReadCallback(const oatpp::String& file);
v_io_size read(void *buffer, v_buff_size count, async::Action& action) override;
};
public:
/**
* Constructor.
* @param resDir - directory containing swagger-ui resources.
* @param streaming - whether to stream resources from file or to cache in-memory
*/
Resources(const oatpp::String& resDir, bool streaming = false);
public:
/**
* Load and cache Swagger-UI resources.
* @param resDir - directory containing swagger-ui resources.
* @return - `std::shared_ptr` to Resources.
*/
static std::shared_ptr<Resources> loadResources(const oatpp::String& resDir) {
auto res = std::make_shared<Resources>(resDir);
res->cacheResource("favicon-16x16.png");
res->cacheResource("favicon-32x32.png");
res->cacheResource("index.css");
res->cacheResource("index.html");
res->cacheResource("oauth2-redirect.html");
res->cacheResource("swagger-initializer.js");
res->cacheResource("swagger-ui-bundle.js");
res->cacheResource("swagger-ui-bundle.js.map");
res->cacheResource("swagger-ui-es-bundle-core.js");
res->cacheResource("swagger-ui-es-bundle-core.js.map");
res->cacheResource("swagger-ui-es-bundle.js");
res->cacheResource("swagger-ui-es-bundle.js.map");
res->cacheResource("swagger-ui-standalone-preset.js");
res->cacheResource("swagger-ui-standalone-preset.js.map");
res->cacheResource("swagger-ui.css");
res->cacheResource("swagger-ui.css.map");
res->cacheResource("swagger-ui.js");
res->cacheResource("swagger-ui.js.map");
return res;
}
/**
* Stream Swagger-UI resources directly from disk.
* @param resDir - directory containing swagger-ui resources.
* @return - `std::shared_ptr` to Resources.
*/
static std::shared_ptr<Resources> streamResources(const oatpp::String& resDir) {
auto res = std::make_shared<Resources>(resDir, true);
return res;
}
/**
* Get cached resource by filename.
* @param filename - name of the resource file.
* @return - &id:oatpp::String; containing resource binary data.
*/
oatpp::String getResource(const oatpp::String& filename);
/**
* Get streamed resource by filename.
* @param filename - name of the resource file.
* @return - `std::shared_ptr` to &id:oatpp::data::stream::ReadCallback; containing resource binary data stream."
*/
std::shared_ptr<ReadCallback> getResourceStream(const oatpp::String& filename);
/**
* Returns true if this is a streaming ressource instance.
* Legacy function.
* Use std::make_shared<Resources>(resDir) directly
* @param resDir
* @param streaming
* @return
*/
bool isStreaming() {
return m_streaming;
static std::shared_ptr<Resources> loadResources(const oatpp::String& resDir, bool streaming = false) {
return std::make_shared<Resources>(resDir, false);
}
/**
* Override swagger resource.
* @param filename
* @param resource
*/
void overrideResource(const oatpp::String& filename, const std::shared_ptr<data::resource::Resource>& resource);
/**
* Get resource by filename.
* @param filename - name of the resource file.
* @return - &id:oatpp::data::resource::Resource;
*/
std::shared_ptr<data::resource::Resource> getResource(const oatpp::String& filename) const;
/**
* Get resource data.
* @param filename
* @return
*/
oatpp::String getResourceData(const oatpp::String& filename) const;
/**
* Returns the MIME type for a given filename
* @param filename to return the MIME type
* @return a MIME type
*/
std::string getMimeType(const std::string &filename) const;
/**
* Returns true if this is a streaming ressource instance.
* @return
*/
bool isStreaming() const;
};
}}

View File

@ -50,7 +50,7 @@ namespace {
*/
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::swagger::Resources>, swaggerResources)([] {
// Make sure to specify correct full path to oatpp-swagger/res folder !!!
return oatpp::swagger::Resources::streamResources(OATPP_SWAGGER_RES_PATH);
return oatpp::swagger::Resources::loadResources(OATPP_SWAGGER_RES_PATH, true);
}());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::swagger::Generator::Config>, generatorConfig)([] {