| #include "tlbmc/sensors/sync_polling_sensor.h" |
| |
| #include <chrono> // NOLINT |
| #include <memory> |
| #include <optional> |
| #include <utility> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "resource.pb.h" |
| #include "sensor.pb.h" |
| #include "tlbmc/sensors/polling_base_sensor.h" |
| |
| namespace milotic_tlbmc { |
| |
| SyncPollingSensor::SyncPollingSensor( |
| SensorAttributesStatic&& sensor_attributes_static, |
| const ThresholdConfigs& threshold_configs, |
| const std::shared_ptr<boost::asio::io_context>& io_context, |
| std::optional<NotificationCb> notification_cb) |
| : PollingBaseSensor(std::move(sensor_attributes_static), threshold_configs, |
| notification_cb), |
| io_context_(io_context) {} |
| |
| void SyncPollingSensor::RefreshOnceAsync( |
| absl::AnyInvocable<void(const std::shared_ptr<const SensorValue>&)> |
| callback) { |
| std::weak_ptr<SyncPollingSensor> self = shared_from_this(); |
| boost::asio::post(*io_context_, [self = std::move(self), |
| callback = std::move(callback)]() mutable { |
| std::shared_ptr<SyncPollingSensor> sensor = self.lock(); |
| if (!sensor) { |
| LOG(WARNING) << "Sensor is destroyed; cancel the refresh."; |
| return; |
| } |
| if (sensor->IsOverridden()) { |
| if (callback) { |
| callback(sensor->GetSensorData()); |
| } |
| return; |
| } |
| std::chrono::steady_clock::time_point last_refresh_start_time = |
| sensor->GetLastRefreshStartTime(); |
| if (last_refresh_start_time != |
| std::chrono::steady_clock::time_point::min()) { |
| sensor->UpdateSoftwarePollingStartMetrics( |
| std::chrono::steady_clock::now() - last_refresh_start_time); |
| } |
| sensor->SetLastRefreshStartTime(std::chrono::steady_clock::now()); |
| |
| // Get the sensor value |
| std::chrono::time_point<std::chrono::steady_clock> start_time = |
| std::chrono::steady_clock::now(); |
| absl::StatusOr<SensorValue> result = sensor->ReadSensorData(); |
| sensor->UpdateHardwarePollingMetrics(std::chrono::steady_clock::now() - |
| start_time); |
| |
| if (!result.ok()) { |
| State state = sensor->GetSensorAttributesDynamic().state(); |
| // Case 1: The sensor implementation (e.g., NicSensor) already updated |
| // its dynamic state with a granular error status (DRIVER_READ_ERROR, |
| // INVALID_DATA, or OTHER_ERROR) before returning the error. In this |
| // case, we preserve the specific root-cause status. |
| // |
| // Case 2 (Otherwise): The sensor failed to read without setting a |
| // granular status (e.g., legacy sensors or tests where state is still |
| // STATUS_READY or STATUS_UNKNOWN). In this case, we fall back to |
| // STATUS_STALE so that a failing sensor is not reported as READY. |
| if (state.status() != STATUS_DRIVER_READ_ERROR && |
| state.status() != STATUS_INVALID_DATA && |
| state.status() != STATUS_OTHER_ERROR) { |
| state.set_status(STATUS_STALE); |
| } |
| state.set_status_message(result.status().message()); |
| sensor->UpdateState(std::move(state)); |
| if (callback) { |
| callback(sensor->GetSensorData()); |
| } |
| } else { |
| sensor->StoreSensorData( |
| std::make_shared<const SensorValue>(std::move(*result))); |
| State state; |
| state.set_status(STATUS_READY); |
| sensor->UpdateState(std::move(state)); |
| |
| if (callback) { |
| callback(sensor->GetSensorData()); |
| } |
| } |
| std::chrono::steady_clock::time_point last_refresh_end_time = |
| sensor->GetLastRefreshEndTime(); |
| if (last_refresh_end_time != std::chrono::steady_clock::time_point::min()) { |
| sensor->UpdateSoftwarePollingEndMetrics(std::chrono::steady_clock::now() - |
| last_refresh_end_time); |
| } |
| sensor->SetLastRefreshEndTime(std::chrono::steady_clock::now()); |
| }); |
| } |
| |
| } // namespace milotic_tlbmc |