clboss/Boss/Mod/SwapReporter.cpp

209 lines
4.9 KiB
C++
Raw Normal View History

#include"Boss/Mod/SwapReporter.hpp"
#include"Boss/Msg/CommandRequest.hpp"
#include"Boss/Msg/CommandResponse.hpp"
#include"Boss/Msg/DbResource.hpp"
#include"Boss/Msg/ManifestCommand.hpp"
#include"Boss/Msg/Manifestation.hpp"
#include"Boss/Msg/ProvideStatus.hpp"
#include"Boss/Msg/SolicitStatus.hpp"
#include"Boss/Msg/SwapCompleted.hpp"
#include"Ev/Io.hpp"
#include"Ev/now.hpp"
#include"Json/Out.hpp"
#include"S/Bus.hpp"
#include"Sqlite3.hpp"
#include"Util/date.hpp"
#include"Util/make_unique.hpp"
namespace Boss { namespace Mod {
class SwapReporter::Impl {
private:
S::Bus& bus;
Sqlite3::Db db;
void start() {
bus.subscribe<Msg::DbResource
>([this](Msg::DbResource const& m) {
db = m.db;
return db.transact().then([](Sqlite3::Tx tx) {
tx.query_execute(R"QRY(
CREATE TABLE IF NOT EXISTS
"SwapReporter"
( id INTEGER PRIMARY KEY
, time REAL NOT NULL
, amount_sent INTEGER NOT NULL
, amount_received INTEGER NOT NULL
, provider_name TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS
"SwapReporter_time_idx"
ON "SwapReporter"(time)
;
)QRY");
tx.commit();
return Ev::lift();
});
});
bus.subscribe<Msg::SwapCompleted
>([](Msg::SwapCompleted const& m) {
/* Record it in our own table, using the transaction
* that SwapManager is keeping open.
*/
m.dbtx->query(R"QRY(
INSERT INTO "SwapReporter"
VALUES( NULL -- id, autogenerated
, :time
, :amount_sent
, :amount_received
, :provider_name
);
)QRY")
.bind(":time", Ev::now())
.bind( ":amount_sent"
, m.amount_sent.to_msat()
)
.bind( ":amount_received"
, m.amount_received.to_msat()
)
.bind( ":provider_name"
, m.provider_name
)
.execute()
;
return Ev::lift();
});
/* `clboss-status` */
bus.subscribe<Msg::SolicitStatus
>([this](Msg::SolicitStatus const& _) {
return db.transact().then([this](Sqlite3::Tx tx) {
auto report = make_report(tx);
tx.commit();
return bus.raise(Msg::ProvideStatus{
"swap_report",
std::move(report)
});
});
});
/* `clboss-swaps` */
bus.subscribe<Msg::Manifestation
>([this](Msg::Manifestation const& _) {
return bus.raise(Msg::ManifestCommand{
"clboss-swaps", "",
"Report about offchain-to-onchain swaps",
false
});
});
bus.subscribe<Msg::CommandRequest
>([this](Msg::CommandRequest const& r) {
if (r.command != "clboss-swaps")
return Ev::lift();
auto id = r.id;
if (!db)
return bus.raise(Msg::CommandResponse{
id,
Json::Out()
.start_object()
.field("error", "db not yet available")
.end_object()
});
return db.transact().then([this, id](Sqlite3::Tx tx) {
auto report = make_report(tx);
tx.commit();
return bus.raise(Msg::CommandResponse{
id, report
});
});
});
}
Json::Out make_report(Sqlite3::Tx& tx) {
auto total_amount_sent = Ln::Amount::sat(0);
auto total_amount_received = Ln::Amount::sat(0);
auto delta = Ln::Amount::sat(0);
auto percent = double();
auto rv = Json::Out();
auto obj = rv.start_object();
auto scan = tx.query(R"QRY(
SELECT time, amount_sent, amount_received, provider_name
FROM "SwapReporter"
ORDER BY time ASC;
)QRY").execute();
auto arr = obj.start_array("swaps");
for (auto& r : scan) {
auto time = r.get<double>(0);
auto amount_sent = Ln::Amount::msat(
r.get<std::uint64_t>(1)
);
auto amount_received = Ln::Amount::msat(
r.get<std::uint64_t>(2)
);
auto amount_lost = amount_sent - amount_received;
auto provider_name = r.get<std::string>(3);
total_amount_sent += amount_sent;
total_amount_received += amount_received;
arr
.start_object()
.field("time", time)
.field("time_human", Util::date(time))
.field( "amount_sent"
, std::string(amount_sent)
)
.field( "amount_received"
, std::string(amount_received)
)
.field( "amount_lost"
, std::string(amount_lost)
)
.field("provider", provider_name)
.end_object()
;
}
arr.end_array();
delta = total_amount_sent - total_amount_received;
if (total_amount_sent > Ln::Amount::sat(0))
percent = 100.0 * (delta / total_amount_sent);
obj
.field( "total_amount_sent"
, std::string(total_amount_sent)
)
.field( "total_amount_received"
, std::string(total_amount_received)
)
.field( "loss"
, std::string(delta)
)
.field( "percent_loss"
, percent
)
;
obj.end_object();
return rv;
}
public:
Impl() =delete;
Impl(Impl&&) =delete;
explicit
Impl(S::Bus& bus_) : bus(bus_) { start(); }
};
SwapReporter::SwapReporter(SwapReporter&&) =default;
SwapReporter::~SwapReporter() =default;
SwapReporter::SwapReporter(S::Bus& bus)
: pimpl(Util::make_unique<Impl>(bus)) { }
}}