468 lines
15 KiB
C++
468 lines
15 KiB
C++
/**
|
|
*
|
|
* create_controller.cc
|
|
* An Tao
|
|
*
|
|
* Copyright 2018, An Tao. All rights reserved.
|
|
* https://github.com/an-tao/drogon
|
|
* Use of this source code is governed by a MIT license
|
|
* that can be found in the License file.
|
|
*
|
|
* Drogon
|
|
*
|
|
*/
|
|
|
|
#include "create_controller.h"
|
|
#include "cmd.h"
|
|
#include <drogon/DrTemplateBase.h>
|
|
#include <drogon/utils/Utilities.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <regex>
|
|
|
|
using namespace drogon_ctl;
|
|
|
|
void create_controller::handleCommand(std::vector<std::string> ¶meters)
|
|
{
|
|
// std::cout<<"create!"<<std::endl;
|
|
ControllerType type = Simple;
|
|
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter)
|
|
{
|
|
if ((*iter)[0] == '-')
|
|
{
|
|
if (*iter == "-s" || (*iter == "--simple"))
|
|
{
|
|
parameters.erase(iter);
|
|
break;
|
|
}
|
|
else if (*iter == "-a" || *iter == "-h" || *iter == "--http")
|
|
{
|
|
type = Http;
|
|
parameters.erase(iter);
|
|
break;
|
|
}
|
|
else if (*iter == "-w" || *iter == "--websocket")
|
|
{
|
|
type = WebSocket;
|
|
parameters.erase(iter);
|
|
break;
|
|
}
|
|
else if (*iter == "-r" || *iter == "--restful")
|
|
{
|
|
type = Restful;
|
|
parameters.erase(iter);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
std::cout << ARGS_ERROR_STR << std::endl;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (type != Restful)
|
|
createController(parameters, type);
|
|
else
|
|
{
|
|
std::string resource;
|
|
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter)
|
|
{
|
|
if ((*iter).find("--resource=") == 0)
|
|
{
|
|
resource = (*iter).substr(strlen("--resource="));
|
|
parameters.erase(iter);
|
|
break;
|
|
}
|
|
if ((*iter)[0] == '-')
|
|
{
|
|
std::cerr << "Error parameter for '" << (*iter) << "'"
|
|
<< std::endl;
|
|
exit(1);
|
|
}
|
|
}
|
|
if (parameters.size() > 1)
|
|
{
|
|
std::cerr << "Too many parameters" << std::endl;
|
|
exit(1);
|
|
}
|
|
auto className = parameters[0];
|
|
createARestfulController(className, resource);
|
|
}
|
|
}
|
|
|
|
void create_controller::newSimpleControllerHeaderFile(
|
|
std::ofstream &file,
|
|
const std::string &className)
|
|
{
|
|
file << "#pragma once\n";
|
|
file << "\n";
|
|
file << "#include <drogon/HttpSimpleController.h>\n";
|
|
file << "\n";
|
|
file << "using namespace drogon;\n";
|
|
file << "\n";
|
|
std::string class_name = className;
|
|
std::string namepace_path = "/";
|
|
auto pos = class_name.find("::");
|
|
size_t namespaceCount = 0;
|
|
while (pos != std::string::npos)
|
|
{
|
|
++namespaceCount;
|
|
auto namespaceName = class_name.substr(0, pos);
|
|
class_name = class_name.substr(pos + 2);
|
|
file << "namespace " << namespaceName << "\n";
|
|
namepace_path.append(namespaceName).append("/");
|
|
file << "{\n";
|
|
pos = class_name.find("::");
|
|
}
|
|
file << "class " << class_name << " : public drogon::HttpSimpleController<"
|
|
<< class_name << ">\n";
|
|
file << "{\n";
|
|
file << " public:\n";
|
|
file << " void asyncHandleHttpRequest(const HttpRequestPtr& "
|
|
"req, std::function<void (const HttpResponsePtr &)> &&callback) "
|
|
"override;\n";
|
|
|
|
file << " PATH_LIST_BEGIN\n";
|
|
file << " // list path definitions here;\n";
|
|
file << " "
|
|
"// PATH_ADD(\"/"
|
|
"path\", \"filter1\", \"filter2\", HttpMethod1, HttpMethod2...);\n";
|
|
file << " PATH_LIST_END\n";
|
|
file << "};\n";
|
|
while (namespaceCount > 0)
|
|
{
|
|
--namespaceCount;
|
|
file << "}\n";
|
|
}
|
|
}
|
|
void create_controller::newSimpleControllerSourceFile(
|
|
std::ofstream &file,
|
|
const std::string &className,
|
|
const std::string &filename)
|
|
{
|
|
file << "#include \"" << filename << ".h\"\n";
|
|
file << "\n";
|
|
auto pos = className.rfind("::");
|
|
auto class_name = className;
|
|
if (pos != std::string::npos)
|
|
{
|
|
auto namespacename = className.substr(0, pos);
|
|
file << "using namespace " << namespacename << ";\n";
|
|
file << "\n";
|
|
class_name = className.substr(pos + 2);
|
|
}
|
|
file << "void " << class_name
|
|
<< "::asyncHandleHttpRequest(const HttpRequestPtr& req, "
|
|
"std::function<void (const HttpResponsePtr &)> &&callback)\n";
|
|
file << "{\n";
|
|
file << " // write your application logic here\n";
|
|
file << "}\n";
|
|
}
|
|
|
|
void create_controller::newWebsockControllerHeaderFile(
|
|
std::ofstream &file,
|
|
const std::string &className)
|
|
{
|
|
file << "#pragma once\n";
|
|
file << "\n";
|
|
file << "#include <drogon/WebSocketController.h>\n";
|
|
file << "\n";
|
|
file << "using namespace drogon;\n";
|
|
file << "\n";
|
|
std::string class_name = className;
|
|
std::string namepace_path = "/";
|
|
auto pos = class_name.find("::");
|
|
size_t namespaceCount = 0;
|
|
while (pos != std::string::npos)
|
|
{
|
|
++namespaceCount;
|
|
auto namespaceName = class_name.substr(0, pos);
|
|
class_name = class_name.substr(pos + 2);
|
|
file << "namespace " << namespaceName << "\n";
|
|
namepace_path.append(namespaceName).append("/");
|
|
file << "{\n";
|
|
pos = class_name.find("::");
|
|
}
|
|
file << "class " << class_name << " : public drogon::WebSocketController<"
|
|
<< class_name << ">\n";
|
|
file << "{\n";
|
|
file << " public:\n";
|
|
file << " void handleNewMessage(const WebSocketConnectionPtr&,\n";
|
|
file << " std::string &&,\n";
|
|
file << " const WebSocketMessageType &) "
|
|
"override;\n";
|
|
file << " void handleNewConnection(const HttpRequestPtr &,\n";
|
|
file << " const "
|
|
"WebSocketConnectionPtr&) override;\n";
|
|
file << " void handleConnectionClosed(const "
|
|
"WebSocketConnectionPtr&) override;\n";
|
|
file << " WS_PATH_LIST_BEGIN\n";
|
|
file << " // list path definitions here;\n";
|
|
file << " // WS_PATH_ADD(\"/path\", \"filter1\", \"filter2\", ...);\n";
|
|
file << " WS_PATH_LIST_END\n";
|
|
file << "};\n";
|
|
while (namespaceCount > 0)
|
|
{
|
|
--namespaceCount;
|
|
file << "}\n";
|
|
}
|
|
}
|
|
void create_controller::newWebsockControllerSourceFile(
|
|
std::ofstream &file,
|
|
const std::string &className,
|
|
const std::string &filename)
|
|
{
|
|
file << "#include \"" << filename << ".h\"\n";
|
|
file << "\n";
|
|
auto pos = className.rfind("::");
|
|
auto class_name = className;
|
|
if (pos != std::string::npos)
|
|
{
|
|
auto namespacename = className.substr(0, pos);
|
|
file << "using namespace " << namespacename << ";\n";
|
|
file << "\n";
|
|
class_name = className.substr(pos + 2);
|
|
}
|
|
file << "void " << class_name
|
|
<< "::handleNewMessage(const WebSocketConnectionPtr& wsConnPtr, "
|
|
"std::string &&message, const WebSocketMessageType &type)\n";
|
|
file << "{\n";
|
|
file << " // write your application logic here\n";
|
|
file << "}\n";
|
|
file << "\n";
|
|
file << "void " << class_name
|
|
<< "::handleNewConnection(const HttpRequestPtr &req, const "
|
|
"WebSocketConnectionPtr& wsConnPtr)\n";
|
|
file << "{\n";
|
|
file << " // write your application logic here\n";
|
|
file << "}\n";
|
|
file << "\n";
|
|
file << "void " << class_name
|
|
<< "::handleConnectionClosed(const WebSocketConnectionPtr& "
|
|
"wsConnPtr)\n";
|
|
file << "{\n";
|
|
file << " // write your application logic here\n";
|
|
file << "}\n";
|
|
}
|
|
|
|
void create_controller::newHttpControllerHeaderFile(
|
|
std::ofstream &file,
|
|
const std::string &className)
|
|
{
|
|
file << "#pragma once\n";
|
|
file << "\n";
|
|
file << "#include <drogon/HttpController.h>\n";
|
|
file << "\n";
|
|
file << "using namespace drogon;\n";
|
|
file << "\n";
|
|
std::string class_name = className;
|
|
std::string namepace_path = "/";
|
|
auto pos = class_name.find("::");
|
|
size_t namespaceCount = 0;
|
|
while (pos != std::string::npos)
|
|
{
|
|
++namespaceCount;
|
|
auto namespaceName = class_name.substr(0, pos);
|
|
class_name = class_name.substr(pos + 2);
|
|
file << "namespace " << namespaceName << "\n";
|
|
namepace_path.append(namespaceName).append("/");
|
|
file << "{\n";
|
|
pos = class_name.find("::");
|
|
}
|
|
file << "class " << class_name << " : public drogon::HttpController<"
|
|
<< class_name << ">\n";
|
|
file << "{\n";
|
|
file << " public:\n";
|
|
file << " METHOD_LIST_BEGIN\n";
|
|
file << " // use METHOD_ADD to add your custom processing function "
|
|
"here;\n";
|
|
file << " // METHOD_ADD(" << class_name
|
|
<< "::get, \"/{2}/{1}\", Get);"
|
|
" // path is "
|
|
<< namepace_path << class_name << "/{arg2}/{arg1}\n";
|
|
file << " // METHOD_ADD(" << class_name
|
|
<< "::your_method_name, \"/{1}/{2}/list\", Get);"
|
|
" // path is "
|
|
<< namepace_path << class_name << "/{arg1}/{arg2}/list\n";
|
|
file << " // ADD_METHOD_TO(" << class_name
|
|
<< "::your_method_name, \"/absolute/path/{1}/{2}/list\", Get);"
|
|
" // path is /absolute/path/{arg1}/{arg2}/list\n";
|
|
file << "\n";
|
|
file << " METHOD_LIST_END\n";
|
|
file << " // your declaration of processing function maybe like this:\n";
|
|
file << " // void get(const HttpRequestPtr& req, "
|
|
"std::function<void (const HttpResponsePtr &)> &&callback, int "
|
|
"p1, std::string p2);\n";
|
|
file << " // void your_method_name(const HttpRequestPtr& req, "
|
|
"std::function<void (const HttpResponsePtr &)> &&callback, double "
|
|
"p1, int p2) const;\n";
|
|
file << "};\n";
|
|
while (namespaceCount > 0)
|
|
{
|
|
--namespaceCount;
|
|
file << "}\n";
|
|
}
|
|
}
|
|
void create_controller::newHttpControllerSourceFile(
|
|
std::ofstream &file,
|
|
const std::string &className,
|
|
const std::string &filename)
|
|
{
|
|
file << "#include \"" << filename << ".h\"\n";
|
|
file << "\n";
|
|
auto pos = className.rfind("::");
|
|
auto class_name = className;
|
|
if (pos != std::string::npos)
|
|
{
|
|
auto namespacename = className.substr(0, pos);
|
|
file << "using namespace " << namespacename << ";\n";
|
|
file << "\n";
|
|
class_name = className.substr(pos + 2);
|
|
}
|
|
|
|
file << "// Add definition of your processing function here\n";
|
|
}
|
|
|
|
void create_controller::createController(std::vector<std::string> &httpClasses,
|
|
ControllerType type)
|
|
{
|
|
for (auto iter = httpClasses.begin(); iter != httpClasses.end(); ++iter)
|
|
{
|
|
if ((*iter)[0] == '-')
|
|
{
|
|
std::cout << ARGS_ERROR_STR << std::endl;
|
|
return;
|
|
}
|
|
}
|
|
for (auto const &className : httpClasses)
|
|
{
|
|
createController(className, type);
|
|
}
|
|
}
|
|
|
|
void create_controller::createController(const std::string &className,
|
|
ControllerType type)
|
|
{
|
|
std::regex regex("::");
|
|
std::string ctlName =
|
|
std::regex_replace(className, regex, std::string("_"));
|
|
|
|
std::string headFileName = ctlName + ".h";
|
|
std::string sourceFilename = ctlName + ".cc";
|
|
{
|
|
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
|
|
std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in);
|
|
|
|
if (iHeadFile || iSourceFile)
|
|
{
|
|
std::cout << "The file you want to create already exists, "
|
|
"overwrite it(y/n)?"
|
|
<< std::endl;
|
|
auto in = getchar();
|
|
(void)getchar(); // get the return key
|
|
if (in != 'Y' && in != 'y')
|
|
{
|
|
std::cout << "Abort!" << std::endl;
|
|
exit(0);
|
|
}
|
|
}
|
|
}
|
|
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
|
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
|
|
if (!oHeadFile || !oSourceFile)
|
|
{
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
if (type == Http)
|
|
{
|
|
std::cout << "Create a http controller: " << className << std::endl;
|
|
newHttpControllerHeaderFile(oHeadFile, className);
|
|
newHttpControllerSourceFile(oSourceFile, className, ctlName);
|
|
}
|
|
else if (type == Simple)
|
|
{
|
|
std::cout << "Create a http simple controller: " << className
|
|
<< std::endl;
|
|
newSimpleControllerHeaderFile(oHeadFile, className);
|
|
newSimpleControllerSourceFile(oSourceFile, className, ctlName);
|
|
}
|
|
else if (type == WebSocket)
|
|
{
|
|
std::cout << "Create a websocket controller: " << className
|
|
<< std::endl;
|
|
newWebsockControllerHeaderFile(oHeadFile, className);
|
|
newWebsockControllerSourceFile(oSourceFile, className, ctlName);
|
|
}
|
|
}
|
|
|
|
void create_controller::createARestfulController(const std::string &className,
|
|
const std::string &resource)
|
|
{
|
|
std::regex regex("::");
|
|
std::string ctlName =
|
|
std::regex_replace(className, regex, std::string("_"));
|
|
|
|
std::string headFileName = ctlName + ".h";
|
|
std::string sourceFilename = ctlName + ".cc";
|
|
{
|
|
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
|
|
std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in);
|
|
|
|
if (iHeadFile || iSourceFile)
|
|
{
|
|
std::cout << "The file you want to create already exists, "
|
|
"overwrite it(y/n)?"
|
|
<< std::endl;
|
|
auto in = getchar();
|
|
(void)getchar(); // get the return key
|
|
if (in != 'Y' && in != 'y')
|
|
{
|
|
std::cout << "Abort!" << std::endl;
|
|
exit(0);
|
|
}
|
|
}
|
|
}
|
|
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
|
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
|
|
if (!oHeadFile || !oSourceFile)
|
|
{
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
auto v = utils::splitString(className, "::");
|
|
drogon::DrTemplateData data;
|
|
data.insert("className", v[v.size() - 1]);
|
|
v.pop_back();
|
|
data.insert("namespaceVector", v);
|
|
data.insert("resource", resource);
|
|
data.insert("fileName", ctlName);
|
|
if (resource.empty())
|
|
{
|
|
data.insert("ctlCommand",
|
|
std::string("drogon_ctl create controller -r ") +
|
|
className);
|
|
}
|
|
else
|
|
{
|
|
data.insert("ctlCommand",
|
|
std::string("drogon_ctl create controller -r ") +
|
|
className + " --resource=" + resource);
|
|
}
|
|
try
|
|
{
|
|
auto templ = DrTemplateBase::newTemplate("restful_controller_h.csp");
|
|
oHeadFile << templ->genText(data);
|
|
templ = DrTemplateBase::newTemplate("restful_controller_cc.csp");
|
|
oSourceFile << templ->genText(data);
|
|
}
|
|
catch (const std::exception &err)
|
|
{
|
|
std::cerr << err.what() << std::endl;
|
|
exit(1);
|
|
}
|
|
std::cout << "Create a http restful API controller: " << className
|
|
<< std::endl;
|
|
std::cout << "File name: " << ctlName << ".h and " << ctlName << ".cc"
|
|
<< std::endl;
|
|
} |