Skip to content

Commit

Permalink
Add support for swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
an-tao committed Jul 24, 2021
1 parent 1c04b1a commit a9ecf49
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 1 deletion.
4 changes: 3 additions & 1 deletion drogon_ctl/create.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ std::string create::detail()
"drogon_ctl create project <project_name> //"
"create a project named project_name\n\n"
"drogon_ctl create model <model_path> [--table=<table_name>] [-f]//"
"create model classes in model_path\n";
"create model classes in model_path\n\n"
"drogon_ctl create swagger <swagger_path> //"
"create swagger controller in swagger_path\n\n";
}

void create::handleCommand(std::vector<std::string> &parameters)
Expand Down
8 changes: 8 additions & 0 deletions drogon_ctl/create_project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ static void newModelConfigFile(std::ofstream &configFile)
auto templ = DrTemplateBase::newTemplate("model_json");
configFile << templ->genText();
}
static void newSwaggerConfigFile(std::ofstream &configFile)
{
auto templ = DrTemplateBase::newTemplate("swagger_json");
configFile << templ->genText();
}
static void newTestMainFile(std::ofstream &mainFile)
{
auto templ = DrTemplateBase::newTemplate("test_main");
Expand Down Expand Up @@ -114,13 +119,16 @@ void create_project::createProject(const std::string &projectName)
drogon::utils::createPath("build");
drogon::utils::createPath("models");
drogon::utils::createPath("test");
drogon::utils::createPath("swagger");

std::ofstream gitFile(".gitignore", std::ofstream::out);
newGitIgFile(gitFile);
std::ofstream configFile("config.json", std::ofstream::out);
newConfigFile(configFile);
std::ofstream modelConfigFile("models/model.json", std::ofstream::out);
newModelConfigFile(modelConfigFile);
std::ofstream swaggerConfigFile("swagger/swagger.json", std::ofstream::out);
newSwaggerConfigFile(swaggerConfigFile);
std::ofstream testMainFile("test/test_main.cc", std::ofstream::out);
newTestMainFile(testMainFile);
std::ofstream testCmakeFile("test/CMakeLists.txt", std::ofstream::out);
Expand Down
187 changes: 187 additions & 0 deletions drogon_ctl/create_swagger.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/**
*
* create_swagger.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_swagger.h"
#include <drogon/DrTemplateBase.h>
#include <drogon/utils/Utilities.h>
#include <json/json.h>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _WIN32
#include <unistd.h>
#include <dirent.h>
#include <dlfcn.h>
#else
#include <io.h>
#include <direct.h>
#endif
#include <fstream>

using namespace drogon_ctl;

static void forEachControllerHeaderIn(
const std::string &path,
const std::function<void(const std::string &)> &cb)
{
DIR *dp;
struct dirent *dirp;
struct stat st;

/* open dirent directory */
if ((dp = opendir(path.c_str())) == NULL)
{
// perror("opendir:");
LOG_ERROR << "can't open dir,path:" << path;
return;
}

/**
* read all files in this dir
**/
while ((dirp = readdir(dp)) != NULL)
{
/* ignore hidden files */
if (dirp->d_name[0] == '.')
continue;
/* get dirent status */
std::string filename = dirp->d_name;
if (filename.find(".h") != filename.length() - 2)
continue;
std::string fullname = path;
fullname.append("/").append(filename);
if (stat(fullname.c_str(), &st) == -1)
{
perror("stat");
closedir(dp);
return;
}

/* if dirent is a directory, find files recursively */
if (S_ISDIR(st.st_mode))
{
forEachControllerHeaderIn(fullname, cb);
}
else
{
cb(fullname);
}
}
closedir(dp);
return;
}
static void parseControllerHeader(const std::string &headerFile,
Json::Value &docs)
{
std::ifstream infile(headerFile);

for (std::string buffer; std::getline(infile, buffer);)
{
}
}
static std::string makeSwaggerDocument(const Json::Value &config)
{
Json::Value ret;
ret["swagger"] = "2.0";
ret["info"] = config.get("info", {});
forEachControllerHeaderIn("controllers", [&ret](const std::string &header) {
std::cout << "Parsing " << header << " ...\n";
parseControllerHeader(header, ret);
});
return ret.toStyledString();
}

static void createSwaggerHeader(const std::string &path,
const Json::Value &config)
{
drogon::HttpViewData data;
data["docs_url"] = config.get("docs_url", "/swagger").asString();
std::ofstream ctlHeader(path + "/SwaggerCtrl.h", std::ofstream::out);
auto templ = DrTemplateBase::newTemplate("swagger_h.csp");
ctlHeader << templ->genText(data);
}

static void createSwaggerSource(const std::string &path,
const Json::Value &config)
{
drogon::HttpViewData data;
data["docs_string"] = makeSwaggerDocument(config);

std::ofstream ctlSource(path + "/SwaggerCtrl.cc", std::ofstream::out);
auto templ = DrTemplateBase::newTemplate("swagger_cc.csp");
ctlSource << templ->genText(data);
}

static void createSwagger(const std::string &path)
{
#ifndef _WIN32
DIR *dp;
if ((dp = opendir(path.c_str())) == NULL)
{
std::cerr << "No such file or directory : " << path << std::endl;
return;
}
closedir(dp);
#endif
auto configFile = path + "/swagger.json";
#ifdef _WIN32
if (_access(configFile.c_str(), 0) != 0)
#else
if (access(configFile.c_str(), 0) != 0)
#endif
{
std::cerr << "Config file " << configFile << " not found!" << std::endl;
exit(1);
}
#ifdef _WIN32
if (_access(configFile.c_str(), 04) != 0)
#else
if (access(configFile.c_str(), R_OK) != 0)
#endif
{
std::cerr << "No permission to read config file " << configFile
<< std::endl;
exit(1);
}

std::ifstream infile(configFile.c_str(), std::ifstream::in);
if (infile)
{
Json::Value configJsonRoot;
try
{
infile >> configJsonRoot;
createSwaggerHeader(path, configJsonRoot);
createSwaggerSource(path, configJsonRoot);
}
catch (const std::exception &exception)
{
std::cerr << "Configuration file format error! in " << configFile
<< ":" << std::endl;
std::cerr << exception.what() << std::endl;
exit(1);
}
}
}
void create_swagger::handleCommand(std::vector<std::string> &parameters)
{
if (parameters.size() < 1)
{
std::cout << "please input a path to create the swagger controller"
<< std::endl;
exit(1);
}
auto path = parameters[0];
createSwagger(path);
}
31 changes: 31 additions & 0 deletions drogon_ctl/create_swagger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
*
* create_swagger.h
* 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
*
*/

#pragma once

#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create_swagger : public DrObject<create_swagger>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
{
return "create swagger docs controller";
}
};
} // namespace drogon_ctl
22 changes: 22 additions & 0 deletions drogon_ctl/templates/swagger_cc.csp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
*
* SwaggerCtrl.h
* This file is generated by drogon_ctl automatically, do not edit it.
*
*/

#include "SwaggerCtrl.h"

using namespace drogon;
using namespace drogon_swagger;

void SwaggerCtrl::getOpenApiDocs(
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
auto resp = drogon::HttpResponse::newHttpResponse();
resp->setBody(R"([[docs_string]])");
resp->setContentTypeCode(CT_APPLICATION_JSON);
callback(resp);
}
23 changes: 23 additions & 0 deletions drogon_ctl/templates/swagger_h.csp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
*
* SwaggerCtrl.h
* This file is generated by drogon_ctl automatically, do not edit it.
*
*/

#include <drogon/drogon.h>

using namespace drogon;
namespace drogon_swagger
{
class SwaggerCtrl : public drogon::HttpController<SwaggerCtrl>
{
public:
METHOD_LIST_BEGIN
ADD_METHOD_TO(SwaggerCtrl::getOpenApiDocs, "[[docs_url]]", Get);
METHOD_LIST_END
void getOpenApiDocs(
const drogon::HttpRequestPtr &req,
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
};
} // namespace drogon_swagger
16 changes: 16 additions & 0 deletions drogon_ctl/templates/swagger_json.csp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"docs_url": "/swagger",
"info": {
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"version": "1.0.5",
"title": "Swagger Petstore",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "apiteam@swagger.io"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}
}

0 comments on commit a9ecf49

Please sign in to comment.