169 lines
4.5 KiB
C++
169 lines
4.5 KiB
C++
//
|
|
// Created by s-Kaonnull on 25.05.2021.
|
|
//
|
|
#include "api.hpp"
|
|
#include "tables.hpp"
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <functional>
|
|
|
|
#include <ctre.hpp>
|
|
#include <fmt/ostream.h>
|
|
#include <nlohmann/json.hpp>
|
|
#include <spdlog/spdlog.h>
|
|
|
|
using json = nlohmann::json;
|
|
|
|
Api::Api(soci::session& sql, httplib::Server& server) : sql(sql)
|
|
{
|
|
RegisterServerHandles(server);
|
|
}
|
|
|
|
void Api::RegisterServerHandles(httplib::Server& server)
|
|
{
|
|
spdlog::info("Register api endpoints...");
|
|
|
|
server.Post("/api/add", std::bind_front(&Api::add, this));
|
|
|
|
server.Get("/api/files", std::bind_front(&Api::files, this));
|
|
|
|
server.Get("/api/file/(\\d+)", std::bind_front(&Api::file, this));
|
|
|
|
server.Options("/(.*)", [this](httplib::Request const& rq, httplib::Response& rp) {});
|
|
|
|
server.set_pre_routing_handler([this](httplib::Request const& rq, httplib::Response& rp) {
|
|
this->set_cross_headers(rp);
|
|
spdlog::info("Request {}", rq.method);
|
|
return httplib::Server::HandlerResponse::Unhandled;
|
|
});
|
|
}
|
|
|
|
void Api::add(const httplib::Request& rq, httplib::Response& rs)
|
|
{
|
|
try
|
|
{
|
|
auto data = json::parse(rq.body);
|
|
|
|
File f;
|
|
|
|
|
|
f.url = data["url"];
|
|
f.status = FileStatus::PENDING;
|
|
|
|
sql << "INSERT INTO Files (url, status) values(:url, :status)", soci::use(f.url, "url"),
|
|
soci::use(f.status, "status");
|
|
|
|
long long int tmp;
|
|
sql.get_last_insert_id("Files", tmp);
|
|
f.id = tmp;
|
|
|
|
json jr;
|
|
jr["status"] = "Ok";
|
|
jr["id"] = f.id;
|
|
|
|
spdlog::info("New Task: {}", f);
|
|
|
|
rs.set_content(jr.dump(), "application/json");
|
|
}
|
|
catch (json::exception const& e)
|
|
{
|
|
spdlog::error("Api Error: {}", e.what());
|
|
rs.status = 400;
|
|
rs.set_content(std::format("Json Error: {}", e.what()), "text/plain");
|
|
}
|
|
}
|
|
|
|
void Api::files(httplib::Request const& rq, httplib::Response& rs)
|
|
{
|
|
try
|
|
{
|
|
json res;
|
|
|
|
soci::rowset<File> data = (sql.prepare << "SELECT * FROM Files ORDER BY id DESC");
|
|
|
|
for (auto const& el : data)
|
|
{
|
|
json current;
|
|
current["id"] = el.id;
|
|
current["status"] = magic_enum::enum_name(el.status);
|
|
current["status_id"] = static_cast<int>(el.status);
|
|
current["source"] = el.url;
|
|
current["name"] = fmt::format("File {}", el.id);
|
|
|
|
current["file_name"] = "Unknown";
|
|
|
|
if (el.status == FileStatus::COMPLETE && false)
|
|
{
|
|
std::string filename;
|
|
soci::rowset<std::string> ret =
|
|
(sql.prepare << "SELECT path From Downloads WHERE id=:id",
|
|
soci::use(el.id, "id"));
|
|
|
|
if (ret.begin() != ret.end())
|
|
{
|
|
std::filesystem::path p(*ret.begin());
|
|
|
|
current["file_name"] = p.filename();
|
|
}
|
|
}
|
|
|
|
res["queue"].push_back(current);
|
|
}
|
|
|
|
rs.set_content(res.dump(), "application/json");
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
spdlog::error(e.what());
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
void Api::file(const httplib::Request& rq, httplib::Response& rs)
|
|
{
|
|
if (!rq.matches[1].matched)
|
|
{
|
|
rs.status = 404;
|
|
rs.set_content("Parameter error", "text/plain");
|
|
return;
|
|
}
|
|
|
|
auto file = rq.matches[1];
|
|
|
|
spdlog::info("File Request: {}", file);
|
|
|
|
try
|
|
{
|
|
Download dw;
|
|
sql << fmt::format("SELECT * FROM Downloads WHERE id={};", file), soci::into(dw);
|
|
|
|
|
|
std::ifstream fs(dw.path, std::ios_base::binary);
|
|
fs.seekg(0, std::ios_base::end);
|
|
auto size = fs.tellg();
|
|
fs.seekg(0);
|
|
rs.body.resize(static_cast<size_t>(size));
|
|
fs.read(&rs.body[0], static_cast<std::streamsize>(size));
|
|
|
|
rs.set_header("Content-Disposition", fmt::format("attachment; filename={};", dw.path));
|
|
if (auto [match, type] = ctre::match<R"(.*\.(.*))">(dw.path); match)
|
|
{
|
|
spdlog::debug(type);
|
|
rs.set_header("content-type", fmt::format("application/{}", type.to_view()));
|
|
}
|
|
}
|
|
catch (std::exception const& e)
|
|
{
|
|
spdlog::error(e.what());
|
|
rs.status = 404;
|
|
rs.set_content("File Not Found", "text/plain");
|
|
}
|
|
}
|
|
void Api::set_cross_headers(httplib::Response& rs)
|
|
{
|
|
rs.set_header("Access-Control-Allow-Origin", "*");
|
|
rs.set_header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
|
rs.set_header("Access-Control-Allow-Headers", "Content-Type");
|
|
}
|