Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/services/catalog/catalog.h" | 5 #include "mojo/services/catalog/catalog.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/json/json_file_value_serializer.h" | |
| 9 #include "base/strings/string_split.h" | 8 #include "base/strings/string_split.h" |
| 10 #include "base/task_runner_util.h" | 9 #include "base/task_runner_util.h" |
| 11 #include "mojo/common/url_type_converters.h" | 10 #include "mojo/common/url_type_converters.h" |
| 12 #include "mojo/services/catalog/entry.h" | 11 #include "mojo/services/catalog/entry.h" |
| 13 #include "mojo/services/catalog/store.h" | 12 #include "mojo/services/catalog/store.h" |
| 14 #include "mojo/shell/public/cpp/names.h" | 13 #include "mojo/shell/public/cpp/names.h" |
| 15 #include "mojo/util/filename_util.h" | 14 #include "mojo/util/filename_util.h" |
| 15 #include "url/gurl.h" | |
| 16 #include "url/url_util.h" | 16 #include "url/url_util.h" |
| 17 | 17 |
| 18 namespace catalog { | 18 namespace catalog { |
| 19 namespace { | |
| 20 | |
| 21 scoped_ptr<base::Value> ReadManifest(const base::FilePath& manifest_path) { | |
| 22 JSONFileValueDeserializer deserializer(manifest_path); | |
| 23 int error = 0; | |
| 24 std::string message; | |
| 25 // TODO(beng): probably want to do more detailed error checking. This should | |
| 26 // be done when figuring out if to unblock connection completion. | |
| 27 return deserializer.Deserialize(&error, &message); | |
| 28 } | |
| 29 | |
| 30 } // namespace | |
| 31 | 19 |
| 32 //////////////////////////////////////////////////////////////////////////////// | 20 //////////////////////////////////////////////////////////////////////////////// |
| 33 // Catalog, public: | 21 // Catalog, public: |
| 34 | 22 |
| 35 Catalog::Catalog(base::TaskRunner* blocking_pool, scoped_ptr<Store> store) | 23 Catalog::Catalog(base::TaskRunner* blocking_pool, scoped_ptr<Store> store) |
| 36 : blocking_pool_(blocking_pool), | 24 : store_(std::move(store)), |
| 37 store_(std::move(store)), | |
| 38 weak_factory_(this) { | 25 weak_factory_(this) { |
| 39 base::FilePath shell_dir; | 26 PathService::Get(base::DIR_MODULE, &package_path_); |
| 40 PathService::Get(base::DIR_MODULE, &shell_dir); | 27 reader_.reset(new Reader(package_path_, blocking_pool)); |
| 41 | |
| 42 system_package_dir_ = | |
| 43 mojo::util::FilePathToFileURL(shell_dir).Resolve(std::string()); | |
| 44 system_package_dir_ = | |
| 45 mojo::util::AddTrailingSlashIfNeeded(system_package_dir_); | |
| 46 | |
| 47 DeserializeCatalog(); | 28 DeserializeCatalog(); |
| 48 } | 29 } |
| 49 | 30 |
| 50 Catalog::~Catalog() {} | 31 Catalog::~Catalog() {} |
| 51 | 32 |
| 52 void Catalog::BindResolver(mojom::ResolverRequest request) { | 33 void Catalog::BindResolver(mojom::ResolverRequest request) { |
| 53 resolver_bindings_.AddBinding(this, std::move(request)); | 34 resolver_bindings_.AddBinding(this, std::move(request)); |
| 54 } | 35 } |
| 55 | 36 |
| 56 void Catalog::BindShellResolver( | 37 void Catalog::BindShellResolver( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 std::string resolved_name = mojo_name; | 75 std::string resolved_name = mojo_name; |
| 95 auto alias_iter = mojo_name_aliases_.find(resolved_name); | 76 auto alias_iter = mojo_name_aliases_.find(resolved_name); |
| 96 if (alias_iter != mojo_name_aliases_.end()) | 77 if (alias_iter != mojo_name_aliases_.end()) |
| 97 resolved_name = alias_iter->second.first; | 78 resolved_name = alias_iter->second.first; |
| 98 | 79 |
| 99 std::string qualifier = mojo::GetNamePath(resolved_name); | 80 std::string qualifier = mojo::GetNamePath(resolved_name); |
| 100 auto qualifier_iter = qualifiers_.find(resolved_name); | 81 auto qualifier_iter = qualifiers_.find(resolved_name); |
| 101 if (qualifier_iter != qualifiers_.end()) | 82 if (qualifier_iter != qualifiers_.end()) |
| 102 qualifier = qualifier_iter->second; | 83 qualifier = qualifier_iter->second; |
| 103 | 84 |
| 104 if (IsNameInCatalog(resolved_name)) | 85 if (IsNameInCatalog(resolved_name)) { |
| 105 CompleteResolveMojoName(resolved_name, qualifier, callback); | 86 CompleteResolveMojoName(resolved_name, qualifier, callback); |
| 106 else | 87 } else { |
| 107 AddNameToCatalog(resolved_name, callback); | 88 reader_->Read(resolved_name, |
| 89 base::Bind(&Catalog::OnReadEntry, weak_factory_.GetWeakPtr(), | |
| 90 resolved_name, callback)); | |
| 91 } | |
| 108 } | 92 } |
| 109 | 93 |
| 110 //////////////////////////////////////////////////////////////////////////////// | 94 //////////////////////////////////////////////////////////////////////////////// |
| 111 // Catalog, mojom::Catalog: | 95 // Catalog, mojom::Catalog: |
| 112 | 96 |
| 113 void Catalog::GetEntries(mojo::Array<mojo::String> names, | 97 void Catalog::GetEntries(mojo::Array<mojo::String> names, |
| 114 const GetEntriesCallback& callback) { | 98 const GetEntriesCallback& callback) { |
| 115 mojo::Map<mojo::String, mojom::CatalogEntryPtr> entries; | 99 mojo::Map<mojo::String, mojom::CatalogEntryPtr> entries; |
| 116 std::vector<mojo::String> names_vec = names.PassStorage(); | 100 std::vector<mojo::String> names_vec = names.PassStorage(); |
| 117 for (const std::string& name : names_vec) { | 101 for (const std::string& name : names_vec) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 128 //////////////////////////////////////////////////////////////////////////////// | 112 //////////////////////////////////////////////////////////////////////////////// |
| 129 // Catalog, private: | 113 // Catalog, private: |
| 130 | 114 |
| 131 void Catalog::CompleteResolveMojoName( | 115 void Catalog::CompleteResolveMojoName( |
| 132 const std::string& resolved_name, | 116 const std::string& resolved_name, |
| 133 const std::string& qualifier, | 117 const std::string& qualifier, |
| 134 const ResolveMojoNameCallback& callback) { | 118 const ResolveMojoNameCallback& callback) { |
| 135 auto entry_iter = catalog_.find(resolved_name); | 119 auto entry_iter = catalog_.find(resolved_name); |
| 136 CHECK(entry_iter != catalog_.end()); | 120 CHECK(entry_iter != catalog_.end()); |
| 137 | 121 |
| 122 GURL package_url = mojo::util::AddTrailingSlashIfNeeded( | |
| 123 mojo::util::FilePathToFileURL(package_path_)); | |
|
Ben Goodger (Google)
2016/03/22 22:07:22
I'm going to convert the parameter to a filepath e
| |
| 138 GURL file_url; | 124 GURL file_url; |
| 139 std::string type = mojo::GetNameType(resolved_name); | 125 std::string type = mojo::GetNameType(resolved_name); |
| 140 if (type == "mojo") { | 126 if (type == "mojo") { |
| 141 // It's still a mojo: URL, use the default mapping scheme. | 127 // It's still a mojo: URL, use the default mapping scheme. |
| 142 const std::string host = mojo::GetNamePath(resolved_name); | 128 const std::string host = mojo::GetNamePath(resolved_name); |
| 143 file_url = system_package_dir_.Resolve(host + "/" + host + ".mojo"); | 129 file_url = package_url.Resolve(host + "/" + host + ".mojo"); |
| 144 } else if (type == "exe") { | 130 } else if (type == "exe") { |
| 145 #if defined OS_WIN | 131 #if defined OS_WIN |
| 146 std::string extension = ".exe"; | 132 std::string extension = ".exe"; |
| 147 #else | 133 #else |
| 148 std::string extension; | 134 std::string extension; |
| 149 #endif | 135 #endif |
| 150 file_url = system_package_dir_.Resolve( | 136 file_url = package_url.Resolve( |
| 151 mojo::GetNamePath(resolved_name) + extension); | 137 mojo::GetNamePath(resolved_name) + extension); |
| 152 } | 138 } |
| 153 | 139 |
| 154 mojo::shell::mojom::CapabilitySpecPtr capabilities_ptr = | 140 mojo::shell::mojom::CapabilitySpecPtr capabilities_ptr = |
| 155 mojo::shell::mojom::CapabilitySpec::From( | 141 mojo::shell::mojom::CapabilitySpec::From( |
| 156 entry_iter->second.capabilities()); | 142 entry_iter->second.capabilities()); |
| 157 | 143 |
| 158 callback.Run(resolved_name, qualifier, std::move(capabilities_ptr), | 144 callback.Run(resolved_name, qualifier, std::move(capabilities_ptr), |
| 159 file_url.spec()); | 145 file_url.spec()); |
| 160 } | 146 } |
| 161 | 147 |
| 162 bool Catalog::IsNameInCatalog(const std::string& name) const { | 148 bool Catalog::IsNameInCatalog(const std::string& name) const { |
| 163 return catalog_.find(name) != catalog_.end(); | 149 return catalog_.find(name) != catalog_.end(); |
| 164 } | 150 } |
| 165 | 151 |
| 166 void Catalog::AddNameToCatalog(const std::string& name, | |
| 167 const ResolveMojoNameCallback& callback) { | |
| 168 GURL manifest_url = GetManifestURL(name); | |
| 169 if (manifest_url.is_empty()) { | |
| 170 // The name is of some form that can't be resolved to a manifest (e.g. some | |
| 171 // scheme used for tests). Just pass it back to the caller so it can be | |
| 172 // loaded with a custom loader. | |
| 173 callback.Run(name, mojo::GetNamePath(name), nullptr, nullptr); | |
| 174 return; | |
| 175 } | |
| 176 | |
| 177 std::string type = mojo::GetNameType(name); | |
| 178 CHECK(type == "mojo" || type == "exe"); | |
| 179 base::FilePath manifest_path = mojo::util::UrlToFilePath(manifest_url); | |
| 180 base::PostTaskAndReplyWithResult( | |
| 181 blocking_pool_, FROM_HERE, base::Bind(&ReadManifest, manifest_path), | |
| 182 base::Bind(&Catalog::OnReadManifest, weak_factory_.GetWeakPtr(), | |
| 183 name, callback)); | |
| 184 } | |
| 185 | |
| 186 void Catalog::DeserializeCatalog() { | 152 void Catalog::DeserializeCatalog() { |
| 187 if (!store_) | 153 if (!store_) |
| 188 return; | 154 return; |
| 189 const base::ListValue* catalog = store_->GetStore(); | 155 const base::ListValue* catalog = store_->GetStore(); |
| 190 CHECK(catalog); | 156 CHECK(catalog); |
| 191 // TODO(sky): make this handle aliases. | 157 // TODO(sky): make this handle aliases. |
| 192 for (auto it = catalog->begin(); it != catalog->end(); ++it) { | 158 for (auto it = catalog->begin(); it != catalog->end(); ++it) { |
| 193 const base::DictionaryValue* dictionary = nullptr; | 159 const base::DictionaryValue* dictionary = nullptr; |
| 194 const base::Value* v = *it; | 160 const base::Value* v = *it; |
| 195 CHECK(v->GetAsDictionary(&dictionary)); | 161 CHECK(v->GetAsDictionary(&dictionary)); |
| 196 scoped_ptr<Entry> entry = Entry::Deserialize(*dictionary); | 162 scoped_ptr<Entry> entry = Entry::Deserialize(*dictionary); |
| 197 if (entry.get()) | 163 if (entry) |
| 198 catalog_[entry->name()] = *entry; | 164 catalog_[entry->name()] = *entry; |
| 199 } | 165 } |
| 200 } | 166 } |
| 201 | 167 |
| 202 void Catalog::SerializeCatalog() { | 168 void Catalog::SerializeCatalog() { |
| 203 scoped_ptr<base::ListValue> catalog(new base::ListValue); | 169 scoped_ptr<base::ListValue> catalog(new base::ListValue); |
| 204 for (const auto& entry : catalog_) | 170 for (const auto& entry : catalog_) |
| 205 catalog->Append(entry.second.Serialize()); | 171 catalog->Append(entry.second.Serialize()); |
| 206 if (store_) | 172 if (store_) |
| 207 store_->UpdateStore(std::move(catalog)); | 173 store_->UpdateStore(std::move(catalog)); |
| 208 } | 174 } |
| 209 | 175 |
| 210 scoped_ptr<Entry> Catalog::DeserializeApplication( | 176 // static |
| 211 const base::DictionaryValue* dictionary) { | 177 void Catalog::OnReadEntry(base::WeakPtr<Catalog> catalog, |
| 212 scoped_ptr<Entry> entry = Entry::Deserialize(*dictionary); | 178 const std::string& name, |
| 213 if (!entry) | 179 const ResolveMojoNameCallback& callback, |
| 214 return entry; | 180 scoped_ptr<Entry> entry) { |
| 181 if (!catalog) { | |
| 182 callback.Run(name, mojo::GetNamePath(name), nullptr, nullptr); | |
| 183 return; | |
| 184 } | |
| 185 catalog->OnReadEntryImpl(name, callback, std::move(entry)); | |
| 186 } | |
| 215 | 187 |
| 216 // TODO(beng): move raw dictionary analysis into Deserialize(). | 188 void Catalog::OnReadEntryImpl(const std::string& name, |
| 189 const ResolveMojoNameCallback& callback, | |
| 190 scoped_ptr<Entry> entry) { | |
| 191 // TODO(beng): evaluate the conditions under which entry is null. | |
| 192 if (!entry) { | |
| 193 entry.reset(new Entry); | |
| 194 entry->set_name(name); | |
| 195 entry->set_display_name(name); | |
| 196 entry->set_qualifier(mojo::GetNamePath(name)); | |
| 197 } | |
| 198 | |
| 217 if (catalog_.find(entry->name()) == catalog_.end()) { | 199 if (catalog_.find(entry->name()) == catalog_.end()) { |
| 218 catalog_[entry->name()] = *entry; | 200 catalog_[entry->name()] = *entry; |
| 219 | 201 |
| 220 if (dictionary->HasKey("applications")) { | 202 if (!entry->applications().empty()) { |
| 221 const base::ListValue* applications = nullptr; | 203 for (const auto& child : entry->applications()) { |
| 222 dictionary->GetList("applications", &applications); | 204 mojo_name_aliases_[child.name()] = |
| 223 for (size_t i = 0; i < applications->GetSize(); ++i) { | 205 std::make_pair(entry->name(), child.qualifier()); |
| 224 const base::DictionaryValue* child_value = nullptr; | |
| 225 applications->GetDictionary(i, &child_value); | |
| 226 scoped_ptr<Entry> child = DeserializeApplication(child_value); | |
| 227 if (child) { | |
| 228 mojo_name_aliases_[child->name()] = | |
| 229 std::make_pair(entry->name(), child->qualifier()); | |
| 230 } | |
| 231 } | 206 } |
| 232 } | 207 } |
| 233 qualifiers_[entry->name()] = entry->qualifier(); | 208 qualifiers_[entry->name()] = entry->qualifier(); |
| 234 } | 209 } |
| 235 return entry; | |
| 236 } | |
| 237 | 210 |
| 238 GURL Catalog::GetManifestURL(const std::string& name) { | |
| 239 // TODO(beng): think more about how this should be done for exe targets. | |
| 240 std::string type = mojo::GetNameType(name); | |
| 241 std::string path = mojo::GetNamePath(name); | |
| 242 if (type == "mojo") | |
| 243 return system_package_dir_.Resolve(path + "/manifest.json"); | |
| 244 else if (type == "exe") | |
| 245 return system_package_dir_.Resolve(path + "_manifest.json"); | |
| 246 return GURL(); | |
| 247 } | |
| 248 | |
| 249 // static | |
| 250 void Catalog::OnReadManifest(base::WeakPtr<Catalog> catalog, | |
| 251 const std::string& name, | |
| 252 const ResolveMojoNameCallback& callback, | |
| 253 scoped_ptr<base::Value> manifest) { | |
| 254 if (!catalog) { | |
| 255 // The Catalog was destroyed, we're likely in shutdown. Run the | |
| 256 // callback so we don't trigger a DCHECK. | |
| 257 callback.Run(name, mojo::GetNamePath(name), nullptr, nullptr); | |
| 258 return; | |
| 259 } | |
| 260 catalog->OnReadManifestImpl(name, callback, std::move(manifest)); | |
| 261 } | |
| 262 | |
| 263 void Catalog::OnReadManifestImpl(const std::string& name, | |
| 264 const ResolveMojoNameCallback& callback, | |
| 265 scoped_ptr<base::Value> manifest) { | |
| 266 if (manifest) { | |
| 267 base::DictionaryValue* dictionary = nullptr; | |
| 268 CHECK(manifest->GetAsDictionary(&dictionary)); | |
| 269 DeserializeApplication(dictionary); | |
| 270 } else { | |
| 271 Entry entry; | |
| 272 entry.set_name(name); | |
| 273 entry.set_display_name(name); | |
| 274 catalog_[entry.name()] = entry; | |
| 275 qualifiers_[entry.name()] = mojo::GetNamePath(name); | |
| 276 } | |
| 277 SerializeCatalog(); | 211 SerializeCatalog(); |
| 278 | 212 |
| 279 auto qualifier_iter = qualifiers_.find(name); | 213 auto qualifier_iter = qualifiers_.find(name); |
| 280 DCHECK(qualifier_iter != qualifiers_.end()); | 214 DCHECK(qualifier_iter != qualifiers_.end()); |
| 281 std::string qualifier = qualifier_iter->second; | 215 std::string qualifier = qualifier_iter->second; |
| 282 CompleteResolveMojoName(name, qualifier, callback); | 216 CompleteResolveMojoName(name, qualifier, callback); |
| 283 } | 217 } |
| 284 | 218 |
| 285 } // namespace catalog | 219 } // namespace catalog |
| OLD | NEW |