131 lines
4.9 KiB
Plaintext
131 lines
4.9 KiB
Plaintext
|
#ifndef SERVICELOGIC_INL
|
||
|
#define SERVICELOGIC_INL
|
||
|
|
||
|
#include "BoostLog.h"
|
||
|
#include "ServiceLogic.h"
|
||
|
#include "WeChatContext/WeChatContext.h"
|
||
|
#include <boost/beast/http/empty_body.hpp>
|
||
|
#include <boost/beast/http/file_body.hpp>
|
||
|
#include <boost/json/parse.hpp>
|
||
|
#include <boost/json/serialize.hpp>
|
||
|
#include <boost/nowide/fstream.hpp>
|
||
|
#include <boost/url.hpp>
|
||
|
#include <filesystem>
|
||
|
|
||
|
namespace ServiceLogic {
|
||
|
|
||
|
template <class Send>
|
||
|
static void onGetBlogImage(SharedStatePtr state, StringRequest &&request, Send &&send) {
|
||
|
using namespace boost::beast;
|
||
|
boost::urls::url url(request.target());
|
||
|
if (url.path().size() < 12) return;
|
||
|
auto file = url.path().substr(12);
|
||
|
|
||
|
auto root = state->notebookRoot();
|
||
|
auto path = ResponseUtility::pathCat(root, file);
|
||
|
|
||
|
boost::nowide::ifstream ifs(path, boost::nowide::ifstream::binary);
|
||
|
std::vector<char> file_string(std::istreambuf_iterator<char>{ifs}, std::istreambuf_iterator<char>{});
|
||
|
boost::beast::error_code ec;
|
||
|
http::response<boost::beast::http::vector_body<char>> s;
|
||
|
s.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||
|
s.set(http::field::content_type, ResponseUtility::mimeType(path));
|
||
|
s.keep_alive(request.keep_alive());
|
||
|
s.body() = std::move(file_string);
|
||
|
s.prepare_payload();
|
||
|
return send(std::move(s));
|
||
|
}
|
||
|
|
||
|
template <class Send>
|
||
|
static void onGetBlogContent(SharedStatePtr state, StringRequest &&request, Send &&send, const std::string &prefix) {
|
||
|
using namespace boost::beast;
|
||
|
boost::urls::url url(request.target());
|
||
|
auto file = url.path().substr(prefix.length());
|
||
|
|
||
|
auto root = state->notebookRoot();
|
||
|
auto path = ResponseUtility::pathCat(root, file);
|
||
|
LOG(info) << "get file: " << path;
|
||
|
|
||
|
if (!std::filesystem::exists(path)) {
|
||
|
return send(notFound(request));
|
||
|
}
|
||
|
boost::nowide::ifstream ifs(path);
|
||
|
std::string file_string(std::istreambuf_iterator<char>{ifs}, std::istreambuf_iterator<char>{});
|
||
|
http::response<boost::beast::http::string_body> s;
|
||
|
s.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||
|
s.set(http::field::content_type, "text/markdown;charset=UTF-8");
|
||
|
s.keep_alive(request.keep_alive());
|
||
|
s.body() = file_string;
|
||
|
s.prepare_payload();
|
||
|
return send(std::move(s));
|
||
|
}
|
||
|
|
||
|
template <class Send>
|
||
|
void onDownload(SharedStatePtr state, StringRequest &&request, Send &&send) {
|
||
|
LOG(info) << "onDownload";
|
||
|
using namespace boost::beast;
|
||
|
std::string_view file;
|
||
|
if (request.target() == "/download") {
|
||
|
auto requestData = boost::json::parse(request.body());
|
||
|
file = requestData.as_object()["file"].as_string();
|
||
|
} else {
|
||
|
file = request.target().substr(9);
|
||
|
}
|
||
|
auto path = ResponseUtility::pathCat(state->fileRoot(), file);
|
||
|
LOG(info) << "get file: " << path;
|
||
|
|
||
|
// Attempt to open the file
|
||
|
boost::beast::error_code ec;
|
||
|
http::file_body::value_type body;
|
||
|
body.open(path.c_str(), boost::beast::file_mode::scan, ec);
|
||
|
|
||
|
// Handle the case where the file doesn't exist
|
||
|
if (ec == boost::system::errc::no_such_file_or_directory) {
|
||
|
return send(notFound(request));
|
||
|
} else if (ec) { // Handle an unknown error
|
||
|
return send(serverError(request, ec.message()));
|
||
|
}
|
||
|
|
||
|
// Cache the size since we need it after the move
|
||
|
auto const size = body.size();
|
||
|
|
||
|
// Respond to GET request
|
||
|
http::response<http::file_body> res{std::piecewise_construct, std::make_tuple(std::move(body)),
|
||
|
std::make_tuple(http::status::ok, request.version())};
|
||
|
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||
|
res.set(http::field::content_type, ResponseUtility::mimeType(path));
|
||
|
res.set(http::field::content_description, file);
|
||
|
res.set(http::field::accept_charset, "utf-8");
|
||
|
res.content_length(size);
|
||
|
res.keep_alive(request.keep_alive());
|
||
|
|
||
|
return send(std::move(res));
|
||
|
}
|
||
|
|
||
|
template <class Send>
|
||
|
static void onWechat(SharedStatePtr state, const StringRequest &request, Send &&send) {
|
||
|
using namespace boost::beast;
|
||
|
boost::urls::url url(request.target());
|
||
|
auto context = Amass::Singleton<WeChatContext>::instance();
|
||
|
http::response<boost::beast::http::string_body> response;
|
||
|
if (request.count("Content-Type") > 0 && request.at("Content-Type") == "text/xml") {
|
||
|
response.body() = context->reply(request.body());
|
||
|
} else {
|
||
|
auto query = url.params();
|
||
|
if (auto iterator = query.find("echostr"); iterator != query.end()) {
|
||
|
response.body() = (*iterator)->value;
|
||
|
}
|
||
|
}
|
||
|
boost::beast::error_code ec;
|
||
|
|
||
|
response.set(http::field::server, BOOST_BEAST_VERSION_STRING);
|
||
|
response.set(http::field::content_type, "text/xml;charset=UTF-8");
|
||
|
response.keep_alive(request.keep_alive());
|
||
|
|
||
|
response.prepare_payload();
|
||
|
return send(std::move(response));
|
||
|
}
|
||
|
} // namespace ServiceLogic
|
||
|
|
||
|
#endif // SERVICELOGIC_INL
|