Files
roro9stack/src/services/irc_service.h
T
twislaandClaude Opus 5.5 70bb2a4137 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
2026-10-06 01:10:55 +02:00

97 lines
3.3 KiB
C++

#pragma once
#include <NetworkClientSecure.h>
#include "platform/counted_client.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <memory>
#include <string>
#include "event_bus.h"
#include "irc_config.h"
#include "irc_session.h"
#include "reconnect_policy.h"
#include "service.h"
#include "services/clock_service.h"
#include "services/storage_service.h"
#include "services/wifi_service.h"
namespace roro {
// Keeps the IRC connection alive in the background once started (see IRC Service in CONTEXT.md):
// connects over TLS while Wi-Fi is Connected, pauses while Monitoring, reconnects with backoff,
// writes Logs and raises Notifications for Mentions. Networking runs on its own task; the
// session is shared with the IRC App under a lock.
class IrcService : public Service {
public:
enum class Status { Stopped, WaitingForWifi, Connecting, Registering, Online, Paused, Retrying };
IrcService(KeyValueStore& store, const std::string& defaultNick, WifiService& wifi, StorageService& storage,
ClockService& clock, EventBus& bus);
const char* name() const override { return "irc"; }
void start() override;
// Starts the session (the IRC App does this when opened, unless you stopped it).
void connect();
// Stops it, from any state: says QUIT if connected, and stops retrying. /quit, `irc stop`.
void disconnect();
bool running() const { return wanted_; }
bool stoppedByUser() const { return stoppedByUser_; }
Status status() const { return status_; }
// Read or act on the session while holding its lock: withSession([](IrcSession& s) { ... }).
template <typename F>
auto withSession(F f) {
Lock l(lock_);
return f(*session_);
}
int totalUnread();
// A copy of the server settings to edit; applyConfig() validates, saves and, if running,
// reconnects with it (a fresh session).
IrcConfig draftConfig();
std::string applyConfig(const IrcConfig& draft);
private:
struct Lock {
explicit Lock(SemaphoreHandle_t m) : m_(m) { xSemaphoreTake(m_, portMAX_DELAY); }
~Lock() { xSemaphoreGive(m_); }
SemaphoreHandle_t m_;
};
static void taskEntry(void* self);
void loop();
bool open();
void close(const std::string& reason);
void readLines();
void flushEffects();
void scheduleRetry(const std::string& why);
IrcConfig config_;
WifiService& wifi_;
StorageService& storage_;
ClockService& clock_;
EventBus& bus_;
std::unique_ptr<IrcSession> session_;
SemaphoreHandle_t lock_ = nullptr;
TaskHandle_t task_ = nullptr;
Counted<NetworkClientSecure> tlsClient_{net::User::Irc}; // counted for the System App (S1, Q121)
Counted<NetworkClient> plainClient_{net::User::Irc};
NetworkClient* conn_ = &tlsClient_; // whichever the config asks for
ReconnectPolicy backoff_;
std::string partial_;
volatile bool wanted_ = false;
volatile bool stoppedByUser_ = false; // a manual stop: opening the App doesn't reconnect
volatile bool stopRequested_ = false;
bool quitSent_ = false; // /quit already queued its QUIT
volatile bool restart_ = false;
volatile Status status_ = Status::Stopped;
bool open_ = false;
uint32_t retryAtMs_ = 0;
uint32_t lastRxMs_ = 0;
bool pingSent_ = false;
};
} // namespace roro