#pragma once #include #include #include #include #include // Required for semaphores #include /** * @struct RpcAccessLogEntry * @brief Holds a single access log record to be queued for synchronization. */ struct RpcAccessLogEntry { time_t timestamp; uint32_t rfidId; }; /** * @struct HttpResponse * @brief Encapsulates the result of an HTTP request. */ struct HttpResponse { int httpCode = 0; std::vector payload; }; /** * @class RPC * @brief Manages remote procedure calls (RPC) for device synchronization. * * This class handles queuing access logs, synchronizing them with a server, * and downloading updated data. It uses a background FreeRTOS task for * automatic, periodic synchronization. */ class RPC { public: RPC(); ~RPC(); /** * @brief Performs a full, one-time synchronization cycle. * @param forceDownload If true, the database will be downloaded even if the * server reports no pending changes. * @return true on success, false on failure. */ bool sync(bool forceDownload = false); /** * @brief Adds an access log entry to the queue for the next sync cycle. * If the queue reaches a threshold, a sync may be triggered. * @param rfidId The RFID ID that was accessed. */ void addAccessLog(uint32_t rfidId); /** * @brief Starts or restarts the automatic background synchronization task. * @param intervalMs The sync interval in milliseconds. */ void startAutoSync(uint32_t intervalMs); /** * @brief Stops the automatic synchronization task gracefully. */ void stopAutoSync(); /** * @brief Sets the API key and base URL for server communication. */ void setApiKeyAndBaseUrl(const char* apiKey, const char* baseUrl); /** * @brief Gets the timestamp (from millis()) of the last successful communication. * @return The last connection timestamp, or 0 if never connected. */ time_t getLastConnectTime() const { return lastSyncConnection; } /** * @brief Checks if a sync operation is currently in progress. * @return true if syncing, false otherwise. */ bool isSyncing() const { return isSyncing_; } /** * @brief Sets a callback function to get the current time in seconds since epoch. * This is used to set the lastSync time during sync operations. * @param callback A function that returns the current time as time_t. */ void setNewTimeCallback(std::function callback) { newTimeCallback_ = callback; } private: // --- Member Variables --- // Configuration char apiKey_[65]; // 64 chars + 1 null-terminator char baseUrl_[257]; // 256 chars + 1 null-terminator // State time_t lastSyncTime = 0; time_t lastSyncConnection = 0; bool isSyncing_ = false; // FreeRTOS components QueueHandle_t accessLogQueue = nullptr; TaskHandle_t autoSyncTaskHandle = nullptr; SemaphoreHandle_t syncTriggerSemaphore_ = nullptr; uint32_t syncIntervalMs = 300000; // Default: 5 minutes bool autoSyncRunning = false; // Constants static constexpr uint8_t LOG_SYNC_THRESHOLD = 20; // --- Private Helper Methods --- /** * @brief Sends an HTTP request and returns the full response. * This method is self-contained and manages the HTTPClient lifecycle. */ HttpResponse sendRequest(const String& url, const String& method = "GET", const uint8_t* payload = nullptr, size_t payloadLen = 0, const String& contentType = ""); /** * @brief Streams an HTTP GET response directly to a file on LittleFS. * This is memory-efficient for large files like a database. */ bool downloadDatabaseToFile(const char* filePath); /** * @brief Sends queued logs to the server and checks if updates are pending. * This is the first step in the sync process. */ bool syncLogsAndCheckForUpdates(bool* pendingChanges); /** * @brief Saves the last successful database download timestamp to flash. */ void saveLastSyncTime(time_t timestamp); /** * @brief Loads the last successful database download timestamp from flash. */ time_t loadLastSyncTime(); /** * @brief The static function that runs as the FreeRTOS background task. */ static void autoSyncTask(void* pvParameters); std::function newTimeCallback_; }; extern RPC rpc;