#pragma once #include #include #include #include #include #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); /quit stops it. void connect(); bool running() const { return wanted_; } Status status() const { return status_; } // Read or act on the session while holding its lock: withSession([](IrcSession& s) { ... }). template auto withSession(F f) { Lock l(lock_); return f(*session_); } int totalUnread(); IrcConfig& config() { return config_; } // Saves the config; takes effect at the next connection. std::string saveConfig(); 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 session_; SemaphoreHandle_t lock_ = nullptr; TaskHandle_t task_ = nullptr; NetworkClientSecure tlsClient_; NetworkClient plainClient_; NetworkClient* conn_ = &tlsClient_; // whichever the config asks for ReconnectPolicy backoff_; std::string partial_; volatile bool wanted_ = false; volatile Status status_ = Status::Stopped; bool open_ = false; uint32_t retryAtMs_ = 0; uint32_t lastRxMs_ = 0; bool pingSent_ = false; }; } // namespace roro