VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
StatusService.cpp
Go to the documentation of this file.
3#include <format>
4#include <map>
5#include <string>
6#include <string_view>
7#include <tier0/dbg.h>
8#include <tier1/convar.h>
9
10namespace VoltMod
11{
12
14{
15 for (auto& [existing, existingProvider] : _sections)
16 {
17 if (existing == name)
18 {
19 existingProvider = std::move(provider);
20 return;
21 }
22 }
23 _sections.emplace_back(std::move(name), std::move(provider));
24}
25
27{
28 return !_healthy || _healthy();
29}
30
31std::string StatusService::BuildJson() const
32{
33 // Providers already return JSON. Replace invalid payloads so one section cannot corrupt the report.
34 std::map<std::string, glz::raw_json> out;
35 for (const auto& [name, provider] : _sections)
36 {
37 std::string section = provider();
38 out[name] = glz::validate_json(section) ? glz::raw_json{R"({"error":"provider returned invalid JSON"})"}
39 : glz::raw_json{std::move(section)};
40 }
41 out["healthy"] = glz::raw_json{IsHealthy() ? "true" : "false"};
42 return Json::Write(out);
43}
44
45std::string StatusService::BuildText() const
46{
47 std::string out;
48 for (const auto& [name, provider] : _sections)
49 {
50 out += name;
51 out += ":\n";
52 const auto section = Json::ParseDocument(provider());
53 if (!section)
54 {
55 out += " <invalid JSON from provider>\n";
56 }
57 else if (section->is_object())
58 {
59 for (const auto& [key, value] : section->get_object())
60 {
61 std::string rendered = value.is_string() ? value.get_string() : value.dump().value_or(std::string{});
62 out += std::format(" {}: {}\n", key, rendered);
63 }
64 }
65 else
66 {
67 out += std::format(" {}\n", section->dump().value_or(std::string{}));
68 }
69 }
70 if (!out.empty() && out.back() == '\n')
71 {
72 out.pop_back();
73 }
74 return out;
75}
76
77void StatusService::InstallCommand(std::string_view name, std::string_view helpText, HealthCheck healthy)
78{
79 _healthy = std::move(healthy);
80 // The member-owned command unregisters before destruction.
81 _command.emplace(name, helpText, [this, name = std::string(name)](const CCommand& args, int) {
82 if (args.ArgC() > 1 && std::string_view(args.Arg(1)) == "json")
83 {
84 Msg("STATUS_JSON %s\n", BuildJson().c_str());
85 return;
86 }
87 Msg("=== %s (healthy: %s) ===\n%s\n", name.c_str(), IsHealthy() ? "yes" : "no", BuildText().c_str());
88 });
89}
90
91} // namespace VoltMod
static std::string Write(const T &value)
Serialize value as compact JSON.
Definition Json.hpp:96
static Result< glz::generic > ParseDocument(std::string_view text)
Parse free-form JSON whose shape is not known at compile time.
Definition Json.hpp:108
std::function< std::string()> Provider
Returns this section's payload as JSON text (an object or scalar).
void InstallCommand(std::string_view name, std::string_view helpText, HealthCheck healthy={})
Install the server command that reports this status.
std::string BuildJson() const
One JSON object with a key per section, plus a top-level healthy flag.
bool IsHealthy() const
The registered health result, or true when no predicate is registered.
std::function< bool()> HealthCheck
Optional plugin-specific health predicate.
std::string BuildText() const
Human-readable multi-line rendering of the same sections.
void RegisterSection(std::string name, Provider provider)
Add a section, replacing any existing one with the same name.
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56