1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromecast/common/chromecast_config.h"
6
7#include <string>
8
9#include "base/command_line.h"
10#include "base/files/file_util.h"
11#include "base/logging.h"
12#include "base/path_service.h"
13#include "base/prefs/json_pref_store.h"
14#include "base/prefs/pref_registry_simple.h"
15#include "base/prefs/pref_service_factory.h"
16#include "base/prefs/pref_store.h"
17#include "base/strings/string_number_conversions.h"
18#include "chromecast/common/cast_paths.h"
19#include "chromecast/common/pref_names.h"
20#include "chromecast/metrics/cast_metrics_prefs.h"
21
22namespace chromecast {
23
24namespace {
25
26// Config file IO worker constants.
27const int kNumOfConfigFileIOWorkers = 1;
28const char kNameOfConfigFileIOWorkers[] = "ConfigFileIO";
29
30void UserPrefsLoadError(
31    PersistentPrefStore::PrefReadError* error_val,
32    PersistentPrefStore::PrefReadError error) {
33  DCHECK(error_val);
34  *error_val = error;
35}
36
37base::FilePath GetConfigPath() {
38  base::FilePath config_path;
39  CHECK(PathService::Get(FILE_CAST_CONFIG, &config_path));
40  return config_path;
41}
42
43}  // namespace
44
45// static
46ChromecastConfig* ChromecastConfig::g_instance_ = NULL;
47
48// static
49void ChromecastConfig::Create(PrefRegistrySimple* registry) {
50  DCHECK(g_instance_ == NULL);
51  g_instance_ = new ChromecastConfig();
52  g_instance_->Load(registry);
53}
54
55// static
56ChromecastConfig* ChromecastConfig::GetInstance() {
57  DCHECK(g_instance_ != NULL);
58  return g_instance_;
59}
60
61ChromecastConfig::ChromecastConfig()
62    : config_path_(GetConfigPath()),
63      worker_pool_(new base::SequencedWorkerPool(kNumOfConfigFileIOWorkers,
64                                                 kNameOfConfigFileIOWorkers)) {
65}
66
67ChromecastConfig::~ChromecastConfig() {
68  // Explict writing before worker_pool shutdown.
69  pref_service_->CommitPendingWrite();
70  worker_pool_->Shutdown();
71}
72
73bool ChromecastConfig::Load(PrefRegistrySimple* registry) {
74  DCHECK(thread_checker_.CalledOnValidThread());
75  VLOG(1) << "Loading config from " << config_path_.value();
76  registry->RegisterIntegerPref(prefs::kRemoteDebuggingPort, 0);
77
78  metrics::RegisterPrefs(registry);
79  RegisterPlatformPrefs(registry);
80
81  PersistentPrefStore::PrefReadError prefs_read_error =
82      PersistentPrefStore::PREF_READ_ERROR_NONE;
83  base::PrefServiceFactory prefServiceFactory;
84  scoped_refptr<base::SequencedTaskRunner> task_runner =
85      JsonPrefStore::GetTaskRunnerForFile(config_path_, worker_pool_.get());
86  prefServiceFactory.SetUserPrefsFile(config_path_, task_runner.get());
87  prefServiceFactory.set_async(false);
88  prefServiceFactory.set_read_error_callback(
89      base::Bind(&UserPrefsLoadError, &prefs_read_error));
90  pref_service_ = prefServiceFactory.Create(registry);
91
92  if (prefs_read_error == PersistentPrefStore::PREF_READ_ERROR_NONE) {
93    return true;
94  } else {
95    LOG(ERROR) << "Cannot initialize chromecast config: "
96               << config_path_.value()
97               << ", pref_error=" << prefs_read_error;
98    return false;
99  }
100}
101
102void ChromecastConfig::Save() const {
103  DCHECK(thread_checker_.CalledOnValidThread());
104  VLOG(1) << "Saving config to: " << config_path_.value();
105  pref_service_->CommitPendingWrite();
106}
107
108const std::string ChromecastConfig::GetValue(const std::string& key) const {
109  DCHECK(thread_checker_.CalledOnValidThread());
110  return pref_service_->GetString(key.c_str());
111}
112
113const int ChromecastConfig::GetIntValue(const std::string& key) const {
114  return pref_service_->GetInteger(key.c_str());
115}
116
117void ChromecastConfig::SetValue(
118    const std::string& key,
119    const std::string& value) const {
120  DCHECK(thread_checker_.CalledOnValidThread());
121  if (pref_service_->IsUserModifiablePreference(key.c_str())) {
122    VLOG(1) << "Set config: key=" << key << ", value=" << value;
123    pref_service_->SetString(key.c_str(), value);
124  } else {
125    LOG(ERROR) << "Cannot set read-only config: key=" << key
126               << ", value=" << value;
127  }
128}
129
130void ChromecastConfig::SetIntValue(const std::string& key, int value) const {
131  DCHECK(thread_checker_.CalledOnValidThread());
132  if (pref_service_->IsUserModifiablePreference(key.c_str())) {
133    VLOG(1) << "Set config: key=" << key << ", value=" << value;
134    pref_service_->SetInteger(key.c_str(), value);
135  } else {
136    LOG(ERROR) << "Cannot set read-only config: key=" << key
137               << ", value=" << value;
138  }
139}
140
141bool ChromecastConfig::HasValue(const std::string& key) const {
142  DCHECK(thread_checker_.CalledOnValidThread());
143  return pref_service_->HasPrefPath(key.c_str());
144}
145
146}  // namespace chromecast
147