mirror of
https://github.com/drogonframework/drogon.git
synced 2025-10-05 00:02:58 -04:00
Modify dynamic view loading algorithm (#339)
This commit is contained in:
parent
3c15f65a7f
commit
71b60823da
@ -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": {}
|
||||
}
|
||||
}
|
@ -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> //"
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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};
|
||||
|
Loading…
x
Reference in New Issue
Block a user