Modify dynamic view loading algorithm (#339)

This commit is contained in:
An Tao 2020-02-16 17:19:16 +08:00 committed by GitHub
parent 3c15f65a7f
commit 71b60823da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 112 additions and 24 deletions

View File

@ -127,6 +127,10 @@
"dynamic_views_path": [
"./views"
],
//dynamic_views_output_path: Default by an empty string which means the output path of source
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
//path of the current working directory.
"dynamic_views_output_path": "",
//log: Set log output, drogon output logs to stdout by default
"log": {
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
@ -215,4 +219,4 @@
}],
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
"custom_config": {}
}
}

View File

@ -23,8 +23,8 @@ std::string create::detail()
return "Use create command to create some source files of drogon webapp\n\n"
"Usage:drogon_ctl create <view|controller|filter|project|model> "
"[-options] <object name>\n\n"
"drogon_ctl create view <csp file name> //create HttpView source "
"files from csp file\n\n"
"drogon_ctl create view <csp file name> [-o <output path>]//create "
"HttpView source files from csp file\n\n"
"drogon_ctl create controller [-s] <[namespace::]class_name> //"
"create HttpSimpleController source files\n\n"
"drogon_ctl create controller -h <[namespace::]class_name> //"

View File

@ -298,7 +298,11 @@ int create_view::createViewFile(const std::string &script_filename)
std::ofstream oSourceFile(sourceFilename.c_str(),
std::ofstream::out);
if (!oHeadFile || !oSourceFile)
{
std::cerr << "Can't open " << headFileName << " or "
<< sourceFilename << "\n";
return -1;
}
newViewHeaderFile(oHeadFile, className);
newViewSourceFile(oSourceFile, className, infile);
@ -355,7 +359,8 @@ void create_view::newViewSourceFile(std::ofstream &file,
std::string buffer;
char line[8192];
int import_flag = 0;
std::string layoutName;
std::regex layoutReg("<%layout[ \\t]+(((?!%\\}).)*[^ \\t])[ \\t]*%>");
while (infile.getline(line, sizeof(line)))
{
buffer = line;
@ -369,6 +374,15 @@ void create_view::newViewSourceFile(std::ofstream &file,
lowerBuffer.end(),
lowerBuffer.begin(),
::tolower);
std::smatch results;
if (std::regex_search(buffer, results, layoutReg))
{
if (results.size() > 1)
{
layoutName = results[1].str();
continue;
}
}
if ((pos = lowerBuffer.find(cxx_include)) != std::string::npos)
{
// std::cout<<"haha find it!"<<endl;
@ -421,17 +435,37 @@ void create_view::newViewSourceFile(std::ofstream &file,
// oSrcFile <<"\tstd::string "<<bodyName<<";\n";
file << "\tdrogon::OStringStream " << streamName << ";\n";
file << "\tstd::string layoutName{\"" << layoutName << "\"};\n";
int cxx_flag = 0;
while (infile.getline(line, sizeof(line)))
{
buffer = line;
if (buffer.length() > 0)
{
std::smatch results;
if (std::regex_search(buffer, results, layoutReg))
{
if (results.size() > 1)
{
continue;
}
}
std::regex re("\\{%[ \\t]*(((?!%\\}).)*[^ \\t])[ \\t]*%\\}");
buffer = std::regex_replace(buffer, re, "<%c++$$$$<<$1;%>");
}
parseLine(file, buffer, streamName, viewDataName, cxx_flag);
}
file << "if(layoutName.empty())\n{\n";
file << "std::string ret{std::move(" << streamName << ".str())};\n";
file << "return ret;\n}\n";
file << "return ret;\n}else\n{\n";
file << "auto static templ = DrTemplateBase::newTemplate(layoutName);\n";
file << "if(!templ) return \"\";\n";
file << "HttpViewData data;\n";
file << "auto str = std::move(" << streamName << ".str());\n";
file << "if(!str.empty() && str[str.length()-1] == '\\n') "
"str.resize(str.length()-1);\n";
file << "data[\"\"] = std::move(str);\n";
file << "return templ->genText(data);\n";
file << "}\n}\n";
}

View File

@ -39,7 +39,7 @@ aux_source_directory(filters FILTER_SRC)
aux_source_directory(plugins PLUGIN_SRC)
aux_source_directory(models MODEL_SRC)
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/views/*.csp)
file(GLOB_RECURSE SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/views/*.csp)
foreach(cspFile ${SCP_LIST})
message(STATUS "cspFile:" ${cspFile})
get_filename_component(classname ${cspFile} NAME_WE)

View File

@ -127,6 +127,10 @@
"dynamic_views_path": [
"./views"
],
//dynamic_views_output_path: Default by an empty string which means the output path of source
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
//path of the current working directory.
"dynamic_views_output_path": "",
//log: Set log output, drogon output logs to stdout by default
"log": {
//log_path: Log file path,empty by default,in which case,logs are output to the stdout

View File

@ -6,8 +6,7 @@ The following examples can help you understand how to use Drogon:
2. [client_example](https://github.com/an-tao/drogon/tree/master/examples/client_example/main.cc) - A client example.
3. [simple_example](https://github.com/an-tao/drogon/tree/master/examples/simple_example) - A simple example showing how to create a web application using Drogon.
4. [simple_example_test](https://github.com/an-tao/drogon/tree/master/examples/simple_example_test) - Some tests for the `simple_example`.
5. [simple_reverse_proxy](https://github.com/an-tao/drogon/tree/master/examples/simple_reverse_proxy)
- A Example showing how to use drogon as a http reverse proxy with a simple round robin.
5. [simple_reverse_proxy](https://github.com/an-tao/drogon/tree/master/examples/simple_reverse_proxy) - A Example showing how to use drogon as a http reverse proxy with a simple round robin.
### [TechEmpower Framework Benchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) test suite

View File

@ -684,7 +684,7 @@ class HttpAppFramework : public trantor::NonCopyable
/// Set the path to store uploaded files.
/**
* @param uploadPath is the dictionary where the uploaded files are
* @param uploadPath is the directory where the uploaded files are
* stored. if it isn't prefixed with /, ./ or ../, it is relative path
* of document_root path, The default value is 'uploads'.
*
@ -715,13 +715,19 @@ class HttpAppFramework : public trantor::NonCopyable
*
* @param libPaths is a vactor that contains paths to view files.
*
* @param outputPath is the directory where the output source files locate. if
* it is set to an empty string, drogon use libPaths as output paths. If the
* path isn't prefixed with /, it is relative path of the current working
* directory.
*
* @note
* It is disabled by default.
* This operation can be performed by an option in the configuration file.
*/
#ifndef _WIN32
virtual HttpAppFramework &enableDynamicViewsLoading(
const std::vector<std::string> &libPaths) = 0;
const std::vector<std::string> &libPaths,
const std::string &outputPath = "") = 0;
#endif
/// Set the maximum number of all connections.

View File

@ -326,7 +326,9 @@ static void loadApp(const Json::Value &app)
paths.push_back(viewsPath.asString());
LOG_TRACE << "views path:" << paths.back();
}
drogon::app().enableDynamicViewsLoading(paths);
auto outputPath =
app.get("dynamic_views_output_path", "").asString();
drogon::app().enableDynamicViewsLoading(paths, outputPath);
}
}
#endif

View File

@ -166,7 +166,8 @@ HttpAppFramework &HttpAppFrameworkImpl::setGzipStatic(bool useGzipStatic)
}
#ifndef _WIN32
HttpAppFramework &HttpAppFrameworkImpl::enableDynamicViewsLoading(
const std::vector<std::string> &libPaths)
const std::vector<std::string> &libPaths,
const std::string &outputPath)
{
assert(!running_);
@ -188,6 +189,17 @@ HttpAppFramework &HttpAppFrameworkImpl::enableDynamicViewsLoading(
libFilePaths_.push_back(rootPath_ + "/" + libpath);
}
}
libFileOutputPath_ = outputPath;
if (!libFileOutputPath_.empty())
{
if (drogon::utils::createPath(libFileOutputPath_) == -1)
{
LOG_FATAL << "Can't create " << libFileOutputPath_
<< " path for dynamic views";
exit(-1);
}
}
return *this;
}
#endif
@ -421,7 +433,7 @@ void HttpAppFrameworkImpl::run()
if (!libFilePaths_.empty())
{
sharedLibManagerPtr_ = std::unique_ptr<SharedLibManager>(
new SharedLibManager(getLoop(), libFilePaths_));
new SharedLibManager(getLoop(), libFilePaths_, libFileOutputPath_));
}
#endif
// Create all listeners.

View File

@ -215,7 +215,8 @@ class HttpAppFrameworkImpl : public HttpAppFramework
const std::vector<std::string> &types) override;
#ifndef _WIN32
virtual HttpAppFramework &enableDynamicViewsLoading(
const std::vector<std::string> &libPaths) override;
const std::vector<std::string> &libPaths,
const std::string &outputPath) override;
#endif
virtual HttpAppFramework &setMaxConnectionNum(
size_t maxConnections) override;
@ -470,8 +471,9 @@ class HttpAppFrameworkImpl : public HttpAppFramework
std::atomic_bool running_{false};
size_t threadNum_{1};
std::vector<std::string> libFilePaths_;
#ifndef _WIN32
std::vector<std::string> libFilePaths_;
std::string libFileOutputPath_;
std::unique_ptr<SharedLibManager> sharedLibManagerPtr_;
#endif

View File

@ -56,10 +56,15 @@ static void forEachFileIn(
return;
}
/* if dirent is a directory, continue */
/* if dirent is a directory, find files recursively */
if (S_ISDIR(st.st_mode))
continue;
cb(fullname, st);
{
forEachFileIn(fullname, cb);
}
else
{
cb(fullname, st);
}
}
closedir(dp);
return;
@ -67,8 +72,9 @@ static void forEachFileIn(
using namespace drogon;
SharedLibManager::SharedLibManager(trantor::EventLoop *loop,
const std::vector<std::string> &libPaths)
: loop_(loop), libPaths_(libPaths)
const std::vector<std::string> &libPaths,
const std::string &outputPath)
: loop_(loop), libPaths_(libPaths), outputPath_(outputPath)
{
timeId_ = loop_->runEvery(5.0, [=]() { managerLibs(); });
}
@ -121,21 +127,38 @@ void SharedLibManager::managerLibs()
std::ofstream fout(lockFile);
}
std::string cmd = "drogon_ctl create view ";
cmd.append(filename).append(" -o ").append(libPath);
if (!outputPath_.empty())
{
cmd.append(filename).append(" -o ").append(
outputPath_);
}
else
{
cmd.append(filename).append(" -o ").append(libPath);
}
LOG_TRACE << cmd;
auto r = system(cmd.c_str());
// TODO: handle r
(void)(r);
auto srcFile = filename.substr(0, pos);
if (!outputPath_.empty())
{
pos = srcFile.rfind("/");
if (pos != std::string::npos)
{
srcFile = srcFile.substr(pos + 1);
}
srcFile = outputPath_ + "/" + srcFile;
}
srcFile.append(".cc");
DLStat dlStat;
dlStat.handle = loadLibs(srcFile, oldHandle);
#ifdef __linux__
dlStat.mTime = st.st_mtim;
#elif defined _WIN32
dlStat.mTime.tv_sec = st.st_mtime;
dlStat.mTime.tv_sec = st.st_mtime;
#else
dlStat.mTime = st.st_mtimespec;
dlStat.mTime = st.st_mtimespec;
#endif
if (dlStat.handle)
{

View File

@ -24,13 +24,15 @@ class SharedLibManager : public trantor::NonCopyable
{
public:
SharedLibManager(trantor::EventLoop *loop,
const std::vector<std::string> &libPaths);
const std::vector<std::string> &libPaths,
const std::string &outputPath);
~SharedLibManager();
private:
void managerLibs();
trantor::EventLoop *loop_;
std::vector<std::string> libPaths_;
std::string outputPath_;
struct DLStat
{
void *handle{nullptr};