blob: 622fed5d2519b995fe776a23c9cd0fbaed2ba4ab [file] [log] [blame] [edit]
/*
* Copyright 2021 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef CAMERA_COMMON_RELOADABLE_CONFIG_FILE_H_
#define CAMERA_COMMON_RELOADABLE_CONFIG_FILE_H_
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/file_path_watcher.h>
#include <base/functional/callback_helpers.h>
#include <base/memory/scoped_refptr.h>
#include <base/synchronization/lock.h>
#include <base/task/sequenced_task_runner.h>
#include <base/values.h>
#include "cros-camera/common.h"
#include "cros-camera/export.h"
namespace cros {
// An abstraction for a JSON-based config file. ReloadableConfigFile by default
// loads the config from a given default path, which usually resides in the root
// filesystem and is read-only. ReloadableConfigFile can be further configured
// to monitor an override config file and it will reload new configs from the
// override config file when the file content changes.
class CROS_CAMERA_EXPORT ReloadableConfigFile {
public:
struct Options {
// The path to the default config file. The config is read from
// |default_config_file_path| first if the path exists.
base::FilePath default_config_file_path;
// The path to the override config file. |override_config_file_path| will be
// actively monitored at run-time, and we will overwrite the existing
// |options_| values with the ones present in the override config file. The
// config in the override file doesn't have to include all the options and
// it can update only a subset of the options.
base::FilePath override_config_file_path = base::FilePath();
};
using OptionsUpdateCallback =
base::RepeatingCallback<void(const base::Value::Dict&)>;
explicit ReloadableConfigFile(const Options& options);
ReloadableConfigFile(const ReloadableConfigFile& other) = delete;
ReloadableConfigFile& operator=(const ReloadableConfigFile& other) = delete;
~ReloadableConfigFile();
// Set the callback to be called when the config file changes. |callback|
// will either be called synchronously before this returns, or be called on
// the sequence that the constructor of this ReloadableConfigFile is called.
void SetCallback(OptionsUpdateCallback callback);
// Stops the file path watcher for the override config file. By default the
// watcher is destructed along with the ReloadableConfigFile instance.
void StopOverrideFileWatcher();
void UpdateOption(std::string key, base::Value value);
base::Value::Dict CloneJsonValues() const;
bool IsValid() const;
private:
void ReadConfigFileLocked(const base::FilePath& file_path);
void WriteConfigFileLocked(const base::FilePath& file_path);
void OnConfigFileUpdated(const base::FilePath& file_path, bool error);
OptionsUpdateCallback options_update_callback_ = base::NullCallback();
// The default config file path. Usually this points to the device-specific
// tuning file shipped with the OS image.
base::FilePath default_config_file_path_;
// The override config file path. The override config is used to override the
// default config at run-time for development or debugging purposes.
base::FilePath override_config_file_path_;
std::unique_ptr<base::FilePathWatcher> override_file_path_watcher_;
scoped_refptr<base::SequencedTaskRunner> file_path_watcher_runner_;
// Stores JSON values from |default_config_file_path_| if the path is not
// empty. Otherwise, |default_json_values_| is an empty dict.
base::Value::Dict default_json_values_;
base::Lock options_lock_;
std::optional<base::Value::Dict> json_values_ GUARDED_BY(options_lock_);
};
// Helper functions to look up |key| in |json_values| and, if key exists, load
// the corresponding value into |output|. Returns true if |output| is loaded
// with the value found, false otherwise.
CROS_CAMERA_EXPORT bool LoadIfExist(const base::Value::Dict& json_values,
const char* key,
float* output);
CROS_CAMERA_EXPORT bool LoadIfExist(const base::Value::Dict& json_values,
const char* key,
int* output);
CROS_CAMERA_EXPORT bool LoadIfExist(const base::Value::Dict& json_values,
const char* key,
bool* output);
template <typename T>
bool LoadIfExist(const base::Value::Dict& json_values,
const char* key,
std::vector<T>* output) {
static_assert(std::is_same<T, float>::value ||
std::is_same<T, double>::value || std::is_same<T, int>::value);
auto value = json_values.FindList(key);
if (!output) {
LOGF(ERROR) << "output cannot be nullptr";
return false;
}
if (!value) {
return false;
}
output->clear();
for (const auto& v : *value) {
if (std::is_same<T, double>::value || std::is_same<T, float>::value) {
output->push_back(v.GetDouble());
} else if (std::is_same<T, int>::value) {
output->push_back(v.GetInt());
}
}
return true;
}
} // namespace cros
#endif // CAMERA_COMMON_RELOADABLE_CONFIG_FILE_H_