diff --git a/src/oatpp-swagger/AsyncController.hpp b/src/oatpp-swagger/AsyncController.hpp index 9941e98..9626872 100644 --- a/src/oatpp-swagger/AsyncController.hpp +++ b/src/oatpp-swagger/AsyncController.hpp @@ -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( - 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( + 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); + } }; diff --git a/src/oatpp-swagger/Controller.hpp b/src/oatpp-swagger/Controller.hpp index 198fd93..0b7bd8c 100644 --- a/src/oatpp-swagger/Controller.hpp +++ b/src/oatpp-swagger/Controller.hpp @@ -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( - 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( + m_resources->getResource(filename)->openInputStream() + ); + auto resp = OutgoingResponse::createShared(Status::CODE_200, body); resp->putHeader("Content-Type", m_resources->getMimeType(filename)); return resp; } diff --git a/src/oatpp-swagger/Resources.cpp b/src/oatpp-swagger/Resources.cpp index 04d58b3..3059719 100644 --- a/src/oatpp-swagger/Resources.cpp +++ b/src/oatpp-swagger/Resources.cpp @@ -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 #include 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(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); } - - 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& resource) { + m_resources[filename] = resource; +} + +std::shared_ptr 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::getResourceStream(const oatpp::String &filename) { - try { - return std::make_shared(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; +} + }} diff --git a/src/oatpp-swagger/Resources.hpp b/src/oatpp-swagger/Resources.hpp index 3ead962..e02c574 100644 --- a/src/oatpp-swagger/Resources.hpp +++ b/src/oatpp-swagger/Resources.hpp @@ -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 - namespace oatpp { namespace swagger { /** @@ -40,102 +40,64 @@ namespace oatpp { namespace swagger { class Resources { private: oatpp::String m_resDir; - std::unordered_map m_resources; bool m_streaming; + std::unordered_map> 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 loadResources(const oatpp::String& resDir) { - auto res = std::make_shared(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 streamResources(const oatpp::String& resDir) { - auto res = std::make_shared(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 getResourceStream(const oatpp::String& filename); - - /** - * Returns true if this is a streaming ressource instance. + * Legacy function. + * Use std::make_shared(resDir) directly + * @param resDir + * @param streaming * @return */ - bool isStreaming() { - return m_streaming; + static std::shared_ptr loadResources(const oatpp::String& resDir, bool streaming = false) { + return std::make_shared(resDir, false); } + /** + * Override swagger resource. + * @param filename + * @param resource + */ + void overrideResource(const oatpp::String& filename, const std::shared_ptr& resource); + + /** + * Get resource by filename. + * @param filename - name of the resource file. + * @return - &id:oatpp::data::resource::Resource; + */ + std::shared_ptr 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; + }; }} diff --git a/test/oatpp-swagger/ControllerTest.cpp b/test/oatpp-swagger/ControllerTest.cpp index a1f0775..784085b 100644 --- a/test/oatpp-swagger/ControllerTest.cpp +++ b/test/oatpp-swagger/ControllerTest.cpp @@ -50,7 +50,7 @@ namespace { */ OATPP_CREATE_COMPONENT(std::shared_ptr, 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, generatorConfig)([] {