Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
refactor: refactor backend
Browse files Browse the repository at this point in the history
  • Loading branch information
engsr6982 committed May 31, 2024
1 parent 4af75e9 commit 808d91f
Show file tree
Hide file tree
Showing 9 changed files with 372 additions and 261 deletions.
145 changes: 61 additions & 84 deletions src/Backend/API.cpp
Original file line number Diff line number Diff line change
@@ -1,84 +1,61 @@
// #pragma once
// #include "API.h"
// #include <functional>
// #include <thread>


// namespace pmc::backend {

// This function defined in the header file.
// void startServer() {
// auto& cfg = pmc::config::cfg.network;

// #ifdef DEBUG
// std::cout << "[DBG] Config: " << std::endl;
// std::cout << " Enable: " << cfg.enable << std::endl;
// std::cout << " Listen IP: " << cfg.listenIP << std::endl;
// std::cout << " Listen Port: " << cfg.listenPort << std::endl;
// std::cout << " Allow CORS: " << cfg.allowCORS << std::endl;
// std::cout << " Token: " << cfg.token << std::endl;
// #endif

// if (!cfg.enable) return;


// clang-format off
/*
TODO: We need find a good and header-only's C++ Http library.
The following libraries are excluded:
cpp-httplib
cinatra
drogon
*/
// clang-format on


// Create server instance
// auto& logger = pmc::entry::getInstance().getSelf().getLogger();
// drogon::app()
// .setLogPath("./logs/PermissionCore/net")
// .setLogLevel(trantor::Logger::LogLevel::kInfo)
// .addListener(cfg.listenIP, cfg.listenPort)
// .setThreadNum(4)
// .enableRunAsDaemon();


// drogon::app().registerHandler(
// "/pmc/validate",
// [](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
// string token = req->getHeader("Authorization");
// pmc::entry::getInstance().getSelf().getLogger().warn("Validate token: ", token);
// callback(drogon::HttpResponse::newHttpJsonResponse("hello world"));
// },
// {drogon::Get}
// );


// Set server routes
// svr.set_http_handler<cinatra::GET>(
// "/pmc/validate",
// [](cinatra::request&, cinatra::response& res) {
// res.set_status_and_content(cinatra::status_type::ok, "Hello, world!");
// },
// mCORS{},
// mLog{},
// mAuth{}
// );
// svr.set_http_handler("/pmc/list/all/core", handler_ListCore);
// svr.set_http_handler("/pmc/list/all/plugin", handler_ListPlugn));
// svr.set_http_handler("/pmc/list/all/perm", handler_ListPerm);


// Start server
// logger.info("Try Start server on {}:{}."_tr(cfg.listenIP, cfg.listenPort));
// std::thread([&svr]() {
// auto err = svr.sync_start();
// pmc::entry::getInstance().getSelf().getLogger().error("Fail in \"sync_start\", code: ",
// static_cast<int>(err));
// printf("Fail in \"sync_start\", code: %d\n", static_cast<int>(err));
// }).detach();
// svr.async_start();
// drogon::app().run();
// }

// } // namespace pmc::backend
#include "API.h"
#include "fmt/compile.h"
#include <filesystem>
#include <fstream>
#include <sstream>

using string = std::string;
using ll::i18n_literals::operator""_tr;
using json = nlohmann::json;
namespace fs = std::filesystem;


// 全局定义 HttpService 实例, 保证其生命周期与程序一致
hv::HttpService router;
hv::HttpServer svr;


namespace pmc::backend {


void startAPIServerThread() {
auto& cfg = pmc::config::cfg.Network;
auto& logger = pmc::entry::getInstance().getSelf().getLogger();
if (!cfg.Enable) return;

// 注册路由
router.GET("/api/validate", [cfg](HttpRequest* req, HttpResponse* res) { CheckToken_RS(req, res, cfg); });

// Query => plugin/perm
router.GET("/api/query/{type}", [cfg](const HttpContextPtr& ctx) {
CheckToken_CTX(ctx, cfg);
string type = ctx->param("type");
hv::Json res;
res["type"] = type;

// 查询指定类型数据
if (type == "plugin") {
res["data"] = pmc::PermissionManager::getInstance().getAllKeys();
} else if (type == "perm") {

} else {
res["status"] = 400;
res["message"] = "Bad Request";
}
// 发送响应
return ctx->sendJson(res);
});


// 启动 HTTP 服务器
svr.port = cfg.Port;
svr.service = &router;
svr.setThreadNum(4); // 分配4个线程处理请求
svr.start();
logger.info("Start api server on 127.0.0.1:{0}."_tr(cfg.Port));
if (cfg.Token == "default_token") {
logger.warn("Token is not set, please set it in config.toml."_tr());
}
}

} // namespace pmc::backend
121 changes: 53 additions & 68 deletions src/Backend/API.h
Original file line number Diff line number Diff line change
@@ -1,68 +1,53 @@
// #pragma once
// #include "ll/api/Logger.h"
// #include "nlohmann/json.hpp"
// #include "string"
// #include <ll/api/i18n/I18n.h>
// #include <stdexcept>
// #include <thread>


// #include "Config/Config.h"
// #include "Entry/Entry.h"
// #include "PermissionCore/Group.h"
// #include "PermissionCore/PermissionCore.h"
// #include "PermissionCore/PermissionManager.h"
// #include "PermissionCore/PermissionRegister.h"
// #include "ServerLog.h"


// namespace pmc::backend {

// using string = std::string;
// using ll::i18n_literals::operator""_tr;
// using json = nlohmann::json;

// void startServer();

// using fn = std::function<void(const httplib::Request&, httplib::Response&)>;

// #ifdef DEBUG
// #define DebugPrintRequest(req) \
// pmc::entry::getInstance().getSelf().getLogger().warn( \
// "[Request]: ", \
// ServerManager::getInstance().headersToString(req.headers) \
// );
// #else
// #define DebugPrintRequest(req) ;
// #endif


// #define AutoHandler(fn) \
// [](const httplib::Request& _req, httplib::Response& _res) { \
// DebugPrintRequest(_req); \
// pmc::entry::getInstance().getSelf().getLogger().warn("[" + _req.method + "] " + _req.path); \
// auto& _manager = ServerManager::getInstance(); \
// const string _reqTime = _manager.getCurrentTimeString(); \
// try { \
// auto _token = _req.get_header_value("Authorization"); \
// if (_token.empty()) { \
// _res.status = httplib::StatusCode::Unauthorized_401; \
// _manager.writeHttpRequestLog(_req, _res, _reqTime); \
// return; \
// } \
// if (_token != pmc::config::cfg.network.token) { \
// _res.status = httplib::StatusCode::Forbidden_403; \
// _manager.writeHttpRequestLog(_req, _res, _reqTime); \
// return; \
// } \
// fn(_req, _res); \
// _manager.writeHttpRequestLog(_req, _res, _reqTime); \
// } catch (...) { \
// _res.status = httplib::StatusCode::InternalServerError_500; \
// _manager.writeHttpRequestLog(_req, _res, _reqTime); \
// throw; \
// } \
// }


// } // namespace pmc::backend
#pragma once
#include "APILogger.h"
#include "Config/Config.h"
#include "Date.h"
#include "Entry/Entry.h"
#include "PermissionCore/Group.h"
#include "PermissionCore/PermissionCore.h"
#include "PermissionCore/PermissionManager.h"
#include "PermissionCore/PermissionRegister.h"
#include "hv/HttpContext.h"
#include "hv/HttpMessage.h"
#include "hv/HttpServer.h"
#include "hv/HttpService.h"
#include "hv/http_content.h"
#include "hv/httpdef.h"
#include "ll/api/Logger.h"
#include "nlohmann/json.hpp"
#include "string"
#include <filesystem>
#include <functional>
#include <ll/api/i18n/I18n.h>
#include <memory>
#include <stdexcept>
#include <thread>


namespace pmc::backend {

void startAPIServerThread();

#define CheckToken_RS(req, res, cfg) \
APILogger::log(req); \
if (req->GetHeader("Authorization") != "Bearer " + cfg.Token) { \
res->json["status"] = 401; \
res->json["message"] = "Unauthorized"; \
return 401; \
} \
res->json["status"] = 200; \
res->json["message"] = "OK"; \
return 200;

#define CheckToken_CTX(ctx, cfg) \
APILogger::log(ctx); \
string _token = ctx->header("Authorization"); \
if (_token != "Bearer " + cfg.Token) { \
ctx->setStatus(http_status::HTTP_STATUS_UNAUTHORIZED); \
hv::Json _tres; \
_tres["status"] = 401; \
_tres["message"] = "Unauthorized"; \
return ctx->sendJson(_tres); \
}

} // namespace pmc::backend
87 changes: 87 additions & 0 deletions src/Backend/APILogger.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "APILogger.h"
#include "Date.h"
#include "Entry/Entry.h"
#include <filesystem>
#include <ll/api/i18n/I18n.h>


namespace pmc::backend {

void APILogger::checkAndUpdateCurrTime() {
auto now = utils::Date::now();
mCurrTime = fmt::format(
"{}-{}-{}",
std::to_string(now.getYear()),
std::to_string(now.getMonth()),
std::to_string(now.getDay())
);
}

fs::path APILogger::getAndCreateLogDir() {
auto path = fs::current_path() / "logs" / "PermissionCore";
if (!fs::exists(path)) {
fs::create_directories(path);
}
return path;
}


using ll::i18n_literals::operator""_tr;
void APILogger::openFile() {
checkAndUpdateCurrTime();
auto path = getAndCreateLogDir() / ("Api-" + mCurrTime + ".csv");
if (!fs::exists(path)) {
fs::create_directories(path.parent_path());
}
mOpenedFile.open(path, std::ios::app);
if (!mOpenedFile.is_open()) {
entry::getInstance().getSelf().getLogger().error("Failed to open log file."_tr());
return;
}
mOpenedFile << "time,ip,method,url,token" << std::endl;
}

void APILogger::checkFile() {
// 初次运行,创建并打开日志文件
if (!mOpenedFile.is_open()) {
openFile();
}
// 日志文件过期,创建并打开新的日志文件
auto now = utils::Date::now();
string fNow = fmt::format("{}-{}-{}", now.getYear(), now.getMonth(), now.getDay());
if (fNow == mCurrTime) return;
mOpenedFile.close();
openFile();
}

void APILogger::writeLine(const string& line) {
checkFile();
mOpenedFile << line << std::endl;
}

APILogger& APILogger::getInstance() {
static APILogger instance;
return instance;
}

void APILogger::log(const HttpContextPtr& ctx) {
std::ostringstream oss;
oss << utils::Date{}.toString() << ","; // 请求时间
oss << ctx->ip() << ","; // 来源IP
oss << ctx->method() << ","; // 请求方法
oss << ctx->url() << ","; // 请求路径
oss << ctx->header("Authorization") << ","; // 请求Token
APILogger::getInstance().writeLine(oss.str());
}

void APILogger::log(HttpRequest* req) {
std::ostringstream oss;
oss << utils::Date{}.toString() << ","; // 请求时间
oss << req->host << ","; // 来源IP
oss << req->method << ","; // 请求方法
oss << req->url << ","; // 请求路径
oss << req->GetHeader("Authorization") << ","; // 请求Token
APILogger::getInstance().writeLine(oss.str());
}

} // namespace pmc::backend
35 changes: 35 additions & 0 deletions src/Backend/APILogger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "hv/HttpContext.h"
#include "hv/HttpMessage.h"
#include <filesystem>
#include <fstream>
#include <string>


using string = std::string;
namespace fs = std::filesystem;

namespace pmc::backend {

class APILogger {
private:
string mCurrTime;
std::ofstream mOpenedFile;

void checkAndUpdateCurrTime();

fs::path getAndCreateLogDir();

void openFile();

public:
void checkFile();

void writeLine(const string& line);

static APILogger& getInstance();

static void log(HttpRequest* req);
static void log(const HttpContextPtr& ctx);
};

} // namespace pmc::backend
Loading

0 comments on commit 808d91f

Please sign in to comment.