Add: universal task display
This commit is contained in:
@@ -5,7 +5,9 @@ set(src_files
|
||||
src/api.cpp
|
||||
src/worker.hpp
|
||||
src/worker.cpp
|
||||
src/tables.hpp)
|
||||
src/tables.hpp
|
||||
src/file_status.hpp
|
||||
src/file_status.cpp)
|
||||
|
||||
|
||||
add_executable(localTubeServer ${src_files})
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
|
||||
#include <soci/boost-optional.h>
|
||||
|
||||
@@ -16,6 +17,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "file_status.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
Api::Api(soci::session& sql, httplib::Server& server) : sql(sql)
|
||||
@@ -116,53 +119,10 @@ void Api::files(httplib::Request const& rq, httplib::Response& rs)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto data = TaskInfo::getAll(sql);
|
||||
|
||||
json res;
|
||||
|
||||
// Query incomplete Tasks
|
||||
|
||||
soci::rowset<Task> data = (sql.prepare << "SELECT * "
|
||||
"FROM Tasks "
|
||||
"WHERE status!=2 "
|
||||
"ORDER BY id DESC ");
|
||||
|
||||
for (auto const& el : data)
|
||||
{
|
||||
json current;
|
||||
current["hash"] = el.hash;
|
||||
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["audio_only"] = el.audio_only;
|
||||
current["format"] = el.format.value_or("Source");
|
||||
|
||||
res["queue"].push_back(current);
|
||||
}
|
||||
|
||||
// Downloaded
|
||||
|
||||
soci::rowset<soci::row> files =
|
||||
(sql.prepare
|
||||
<< R"(SELECT Tasks.id, Files.timestamp, Files.hash, audio_only, filename, Files.format
|
||||
FROM Files,
|
||||
Tasks
|
||||
WHERE Tasks.hash == Files.hash
|
||||
ORDER BY Files.timestamp DESC )");
|
||||
|
||||
for (auto const& el : files)
|
||||
{
|
||||
json current;
|
||||
|
||||
std::time_t time = el.get<int>("timestamp");
|
||||
|
||||
current["timestamp"] = fmt::format("{:%Y-%m-%d %H:%M:%S}", *std::localtime(&time));
|
||||
current["hash"] = el.get<std::string>("hash");
|
||||
current["audio_only"] = el.get<int>("audio_only");
|
||||
current["filename"] = el.get<std::string>("filename");
|
||||
current["format"] = el.get<std::string>("format");
|
||||
|
||||
res["files"].push_back(current);
|
||||
}
|
||||
res["files"] = data;
|
||||
|
||||
rs.set_content(res.dump(), "application/json");
|
||||
}
|
||||
@@ -191,14 +151,12 @@ void Api::file(const httplib::Request& rq, httplib::Response& rs)
|
||||
sql << fmt::format("SELECT * FROM Files WHERE hash='{}';", file), soci::into(dw);
|
||||
|
||||
|
||||
auto fs = std::make_shared<std::ifstream>(dw.local_path, std::ios_base::binary | std::ios::in);
|
||||
auto fs =
|
||||
std::make_shared<std::ifstream>(dw.local_path, std::ios_base::binary | std::ios::in);
|
||||
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.filename));
|
||||
|
||||
rs.set_content_provider(
|
||||
@@ -207,7 +165,6 @@ void Api::file(const httplib::Request& rq, httplib::Response& rs)
|
||||
[file = fs](size_t offset, size_t length, httplib::DataSink& sink) mutable {
|
||||
size_t size = std::min(length, (size_t)1024 * 500);
|
||||
|
||||
//spdlog::info("Stream offset {} length {}", offset, length);
|
||||
std::vector<char> data;
|
||||
data.resize(size);
|
||||
|
||||
@@ -237,54 +194,26 @@ void Api::status(httplib::Request const& rq, httplib::Response& rs)
|
||||
|
||||
std::string hash = rq.matches[1];
|
||||
|
||||
boost::optional<Task> data;
|
||||
|
||||
sql << "SELECT * FROM Tasks WHERE hash=:hash", soci::use(hash, "hash"), soci::into(data);
|
||||
|
||||
/*soci::rowset<Task> data = (sql.prepare << "SELECT * "
|
||||
"FROM Tasks "
|
||||
"WHERE hash=:hash ",
|
||||
soci::use(hash, "hash"));*/
|
||||
json response;
|
||||
|
||||
auto& status = response["status"];
|
||||
|
||||
if (data)
|
||||
try
|
||||
{
|
||||
auto const& el = data.value();
|
||||
auto data = TaskInfo::getId(sql, hash);
|
||||
|
||||
status["name"] = fmt::format("Task {}", el.hash);
|
||||
status["source"] = el.url;
|
||||
status["status"] = magic_enum::enum_name(el.status);
|
||||
status["status_id"] = static_cast<int>(el.status);
|
||||
status["timestamp"] = el.timestamp;
|
||||
status["task_file_type"] =
|
||||
fmt::format("{}: {}", el.audio_only ? "Audio" : "Video", el.format.value_or("Auto"));
|
||||
status["id"] = el.hash;
|
||||
|
||||
if (el.status == FileStatus::COMPLETE)
|
||||
if (data)
|
||||
{
|
||||
boost::optional<File> file_data;
|
||||
sql << "SELECT * FROM Files WHERE hash=:hash", soci::use(hash, "hash"),
|
||||
soci::into(file_data);
|
||||
response["status"] = data.value();
|
||||
|
||||
if (file_data)
|
||||
{
|
||||
auto const& file = file_data.value();
|
||||
|
||||
auto& file_status = status["file"];
|
||||
|
||||
file_status["timestamp"] = file.timestamp;
|
||||
file_status["name"] = file.filename;
|
||||
file_status["format"] =
|
||||
fmt::format("{}: {}", el.audio_only ? "Audio" : "Video", file.format);
|
||||
}
|
||||
} else
|
||||
{
|
||||
rs.status = 404;
|
||||
response["error"] = fmt::format("File '{}' not found!", hash);
|
||||
}
|
||||
|
||||
} else
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
spdlog::error("[Api Status] Excepion: {}", e.what());
|
||||
rs.status = 404;
|
||||
response["error"] = fmt::format("File '{}' not found!", hash);
|
||||
response["error"] = fmt::format("Exception: {}", e.what());
|
||||
}
|
||||
rs.set_content(response.dump(), "application/json");
|
||||
}
|
||||
|
||||
76
Modules/Server/src/file_status.cpp
Normal file
76
Modules/Server/src/file_status.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "file_status.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <soci/boost-optional.h>
|
||||
|
||||
#include "tables.hpp"
|
||||
|
||||
std::optional<TaskInfo> TaskInfo::getId(soci::session& sql, std::string_view hash)
|
||||
{
|
||||
auto hash_str = std::string { hash };
|
||||
|
||||
soci::rowset<soci::row> row_data = (sql.prepare << R"(--
|
||||
SELECT Tasks.hash,
|
||||
Tasks.status,
|
||||
Tasks.timestamp AS TaskTimestamp,
|
||||
Tasks.url,
|
||||
Files.timestamp AS FileTimestamp,
|
||||
Files.filename,
|
||||
Files.format
|
||||
FROM Tasks LEFT OUTER JOIN Files ON Files.id = Tasks.id
|
||||
WHERE Tasks.hash = :file_hash ;)",
|
||||
soci::use(hash_str, "file_hash"));
|
||||
|
||||
for (auto const& el : row_data)
|
||||
{
|
||||
return fromRow(el);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<TaskInfo> TaskInfo::getAll(soci::session& sql)
|
||||
{
|
||||
soci::rowset<soci::row> row_data(sql.prepare << R"(--
|
||||
SELECT Tasks.hash,
|
||||
Tasks.status,
|
||||
Tasks.timestamp AS TaskTimestamp,
|
||||
Tasks.url,
|
||||
Files.timestamp AS FileTimestamp,
|
||||
Files.filename,
|
||||
Files.format
|
||||
FROM Tasks LEFT JOIN Files ON Files.id = Tasks.id
|
||||
ORDER BY TaskTimestamp DESC;")");
|
||||
|
||||
std::vector<TaskInfo> data;
|
||||
|
||||
for (auto const& el : row_data)
|
||||
{
|
||||
data.push_back(fromRow(el));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
TaskInfo TaskInfo::fromRow(soci::row const& row)
|
||||
{
|
||||
TaskInfo status;
|
||||
|
||||
|
||||
|
||||
auto file_status = row.get<FileStatus>("status");
|
||||
|
||||
status.hash = row.get<std::string>("hash");
|
||||
status.name = fmt::format("Task {}", status.hash);
|
||||
status.status = magic_enum::enum_name(file_status);
|
||||
status.timestamp = row.get<int>("TaskTimestamp");
|
||||
status.url = row.get<std::string>("url");
|
||||
|
||||
if (file_status == FileStatus::COMPLETE)
|
||||
{
|
||||
status.file = { .timestamp = row.get<int>("FileTimestamp"),
|
||||
.filename = row.get<std::string>("filename"),
|
||||
.format = row.get<std::string>("format") };
|
||||
}
|
||||
return status;
|
||||
}
|
||||
46
Modules/Server/src/file_status.hpp
Normal file
46
Modules/Server/src/file_status.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <soci/session.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct FileInfo
|
||||
{
|
||||
int64_t timestamp;
|
||||
std::string filename;
|
||||
std::string format;
|
||||
};
|
||||
|
||||
struct TaskInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string hash;
|
||||
std::string status;
|
||||
std::string url;
|
||||
int64_t timestamp;
|
||||
std::optional<FileInfo> file;
|
||||
|
||||
static std::optional<TaskInfo> getId(soci::session& sql, std::string_view hash);
|
||||
static std::vector<TaskInfo> getAll(soci::session& sql);
|
||||
|
||||
static TaskInfo fromRow(soci::row const& row);
|
||||
};
|
||||
|
||||
inline void to_json(json& j, const TaskInfo& p)
|
||||
{
|
||||
j = json { { "name", p.name },
|
||||
{ "source", p.url },
|
||||
{ "status", p.status },
|
||||
{ "timestamp", p.timestamp },
|
||||
{ "hash", p.hash } };
|
||||
|
||||
if(p.file)
|
||||
{
|
||||
j["file"]["timestamp"] = p.file.value().timestamp;
|
||||
j["file"]["filename"] = p.file.value().filename;
|
||||
j["file"]["format"] = p.file.value().format;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ int main()
|
||||
File::create_table(sql);
|
||||
}
|
||||
|
||||
Worker worker(sql);
|
||||
//Worker worker(sql);
|
||||
|
||||
httplib::Server srv;
|
||||
srv.set_mount_point("/", "www/");
|
||||
@@ -75,5 +75,7 @@ int main()
|
||||
Api api(sql, srv);
|
||||
|
||||
spdlog::info("Listing on 0.0.0.0 Port 80");
|
||||
srv.listen("0.0.0.0", 80);
|
||||
|
||||
|
||||
srv.listen("0.0.0.0", 8888);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user