S1 #11: bytes read and written, counted per network service

A Counted<> wrapper around the network clients adds what goes through
their buffer read and write to a per-service counter (IRC, Gemini, Debug
Console, Updates); the single-byte calls and print() end up there, so
each byte counts once. `net` prints the totals. For TLS it's the plain
text the service sees.

Checked on the device: a Gemini fetch counts 164,986 in (a 164,970-byte
page and its 16-byte header) and 42 out (the URL and CRLF).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-06 01:10:55 +02:00
co-authored by Claude Opus 5.5
parent 1df94b684a
commit 70bb2a4137
9 changed files with 185 additions and 7 deletions
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include "traffic.h"
namespace roro {
// A NetworkClient (or NetworkClientSecure) that adds what it reads and writes to its service's
// traffic counters (S1, Q121). Only the two buffer calls are overridden: the single-byte ones,
// print() and printf() all go through them, so every byte is counted once.
template <class Base>
class Counted : public Base {
public:
explicit Counted(net::User user) : user_(user) {}
Counted(const Base& accepted, net::User user) : Base(accepted), user_(user) {}
// Overriding the buffer calls hides the single-byte ones; these put them back. They end up in
// the buffer calls below, where the counting happens.
int read() override { return Base::read(); }
size_t write(uint8_t byte) override { return Base::write(byte); }
size_t write(const uint8_t* buf, size_t size) override {
size_t n = Base::write(buf, size);
net::sent(user_, n);
return n;
}
int read(uint8_t* buf, size_t size) override {
int n = Base::read(buf, size);
if (n > 0) net::received(user_, static_cast<size_t>(n));
return n;
}
private:
net::User user_;
};
} // namespace roro