aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/admin/admin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver/admin/admin.cpp')
-rw-r--r--src/zenserver/admin/admin.cpp140
1 files changed, 139 insertions, 1 deletions
diff --git a/src/zenserver/admin/admin.cpp b/src/zenserver/admin/admin.cpp
index 575a10d83..74131e624 100644
--- a/src/zenserver/admin/admin.cpp
+++ b/src/zenserver/admin/admin.cpp
@@ -3,6 +3,7 @@
#include "admin.h"
#include <zencore/compactbinarybuilder.h>
+#include <zencore/jobqueue.h>
#include <zencore/string.h>
#include <zenstore/gc.h>
@@ -10,7 +11,9 @@
namespace zen {
-HttpAdminService::HttpAdminService(GcScheduler& Scheduler) : m_GcScheduler(Scheduler)
+HttpAdminService::HttpAdminService(GcScheduler& Scheduler, JobQueue& BackgroundJobQueue)
+: m_GcScheduler(Scheduler)
+, m_BackgroundJobQueue(BackgroundJobQueue)
{
using namespace std::literals;
@@ -23,6 +26,141 @@ HttpAdminService::HttpAdminService(GcScheduler& Scheduler) : m_GcScheduler(Sched
},
HttpVerb::kGet);
+ m_Router.AddPattern("jobid", "([[:digit:]]+?)");
+
+ m_Router.RegisterRoute(
+ "jobs",
+ [&](HttpRouterRequest& Req) {
+ std::vector<JobQueue::JobInfo> Jobs = m_BackgroundJobQueue.GetJobs();
+ CbObjectWriter Obj;
+ Obj.BeginArray("jobs");
+ for (const auto& Job : Jobs)
+ {
+ Obj.BeginObject();
+ Obj.AddInteger("Id", Job.Id.Id);
+ Obj.AddString("Status", JobQueue::ToString(Job.Status));
+ Obj.EndObject();
+ }
+ Obj.EndArray();
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "jobs/{jobid}",
+ [&](HttpRouterRequest& Req) {
+ const auto& JobIdString = Req.GetCapture(1);
+ std::optional<uint64_t> JobIdArg = ParseInt<uint64_t>(JobIdString);
+ if (!JobIdArg)
+ {
+ Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest);
+ }
+ JobId Id{.Id = JobIdArg.value_or(0)};
+ if (Id.Id == 0)
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest,
+ ZenContentType::kText,
+ fmt::format("Invalid Job Id: {}", Id.Id));
+ }
+
+ std::optional<JobQueue::JobDetails> CurrentState = m_BackgroundJobQueue.Get(Id);
+ if (!CurrentState)
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound);
+ }
+
+ auto WriteState = [](CbObjectWriter& Obj, const JobQueue::State& State) {
+ if (!State.CurrentOp.empty())
+ {
+ Obj.AddString("CurrentOp"sv, State.CurrentOp);
+ Obj.AddInteger("CurrentOpPercentComplete"sv, State.CurrentOpPercentComplete);
+ }
+ if (!State.Messages.empty())
+ {
+ Obj.BeginArray("Messages");
+ for (const std::string& Message : State.Messages)
+ {
+ Obj.AddString(Message);
+ }
+ Obj.EndArray();
+ }
+ };
+
+ auto GetAgeAsSeconds = [](std::chrono::system_clock::time_point Start, std::chrono::system_clock::time_point End) {
+ auto Age = End - Start;
+ auto Milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(Age);
+ return Milliseconds.count() / 1000.0;
+ };
+
+ const std::chrono::system_clock::time_point Now = std::chrono::system_clock::now();
+
+ switch (CurrentState->Status)
+ {
+ case JobQueue::Status::Queued:
+ {
+ CbObjectWriter Obj;
+ Obj.AddString("Status"sv, "Queued"sv);
+ Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, Now));
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
+ }
+ break;
+ case JobQueue::Status::Running:
+ {
+ CbObjectWriter Obj;
+ Obj.AddString("Status"sv, "Running"sv);
+ WriteState(Obj, CurrentState->State);
+ Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime));
+ Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, Now));
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
+ }
+ break;
+ case JobQueue::Status::Aborted:
+ {
+ CbObjectWriter Obj;
+ Obj.AddString("Status"sv, "Aborted"sv);
+ WriteState(Obj, CurrentState->State);
+ Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime));
+ Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, CurrentState->EndTime));
+ Obj.AddFloat("CompleteTimeS", GetAgeAsSeconds(CurrentState->EndTime, Now));
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
+ }
+ break;
+ case JobQueue::Status::Completed:
+ {
+ CbObjectWriter Obj;
+ Obj.AddString("Status"sv, "Complete"sv);
+ WriteState(Obj, CurrentState->State);
+ Obj.AddFloat("QueueTimeS", GetAgeAsSeconds(CurrentState->CreateTime, CurrentState->StartTime));
+ Obj.AddFloat("RunTimeS", GetAgeAsSeconds(CurrentState->StartTime, CurrentState->EndTime));
+ Obj.AddFloat("CompleteTimeS", GetAgeAsSeconds(CurrentState->EndTime, Now));
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save());
+ }
+ break;
+ }
+ },
+ HttpVerb::kGet);
+
+ m_Router.RegisterRoute(
+ "jobs/{jobid}",
+ [&](HttpRouterRequest& Req) {
+ const auto& JobIdString = Req.GetCapture(1);
+ std::optional<uint64_t> JobIdArg = ParseInt<uint64_t>(JobIdString);
+ if (!JobIdArg)
+ {
+ Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest);
+ }
+ JobId Id{.Id = JobIdArg.value_or(0)};
+ if (m_BackgroundJobQueue.CancelJob(Id))
+ {
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK);
+ }
+ else
+ {
+ Req.ServerRequest().WriteResponse(HttpResponseCode::NotFound);
+ }
+ },
+ HttpVerb::kDelete);
+
m_Router.RegisterRoute(
"gc",
[this](HttpRouterRequest& Req) {