| 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" |
| 8 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
| 9 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
| 10 #include "mojo/common/url_type_converters.h" | 11 #include "mojo/common/url_type_converters.h" |
| 11 #include "mojo/services/catalog/entry.h" | 12 #include "mojo/services/catalog/entry.h" |
| 12 #include "mojo/services/catalog/store.h" | 13 #include "mojo/services/catalog/store.h" |
| 13 #include "mojo/shell/public/cpp/names.h" | 14 #include "mojo/shell/public/cpp/names.h" |
| 14 #include "mojo/util/filename_util.h" | |
| 15 #include "url/gurl.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 base::FilePath GetManifestPath(const base::FilePath& package_dir, |
| 22 const std::string& name) { |
| 23 // TODO(beng): think more about how this should be done for exe targets. |
| 24 std::string type = mojo::GetNameType(name); |
| 25 std::string path = mojo::GetNamePath(name); |
| 26 if (type == mojo::kNameType_Mojo) |
| 27 return package_dir.AppendASCII(path + "/manifest.json"); |
| 28 if (type == mojo::kNameType_Exe) |
| 29 return package_dir.AppendASCII(path + "_manifest.json"); |
| 30 return base::FilePath(); |
| 31 } |
| 32 |
| 33 base::FilePath GetPackagePath(const base::FilePath& package_dir, |
| 34 const std::string& name) { |
| 35 std::string type = mojo::GetNameType(name); |
| 36 if (type == mojo::kNameType_Mojo) { |
| 37 // It's still a mojo: URL, use the default mapping scheme. |
| 38 const std::string host = mojo::GetNamePath(name); |
| 39 return package_dir.AppendASCII(host + "/" + host + ".mojo"); |
| 40 } |
| 41 if (type == mojo::kNameType_Exe) { |
| 42 #if defined OS_WIN |
| 43 std::string extension = ".exe"; |
| 44 #else |
| 45 std::string extension; |
| 46 #endif |
| 47 return package_dir.AppendASCII(mojo::GetNamePath(name) + extension); |
| 48 } |
| 49 return base::FilePath(); |
| 50 } |
| 51 |
| 52 scoped_ptr<ReadManifestResult> ReadManifest(const base::FilePath& package_dir, |
| 53 const std::string& name) { |
| 54 base::FilePath manifest_path = GetManifestPath(package_dir, name); |
| 55 JSONFileValueDeserializer deserializer(manifest_path); |
| 56 int error = 0; |
| 57 std::string message; |
| 58 // TODO(beng): probably want to do more detailed error checking. This should |
| 59 // be done when figuring out if to unblock connection completion. |
| 60 scoped_ptr<ReadManifestResult> result(new ReadManifestResult); |
| 61 result->manifest_root = deserializer.Deserialize(&error, &message); |
| 62 result->package_dir = package_dir; |
| 63 return result; |
| 64 } |
| 65 |
| 66 } // namespace |
| 67 |
| 68 ReadManifestResult::ReadManifestResult() {} |
| 69 ReadManifestResult::~ReadManifestResult() {} |
| 19 | 70 |
| 20 //////////////////////////////////////////////////////////////////////////////// | 71 //////////////////////////////////////////////////////////////////////////////// |
| 21 // Catalog, public: | 72 // Catalog, public: |
| 22 | 73 |
| 23 Catalog::Catalog(base::TaskRunner* blocking_pool, scoped_ptr<Store> store) | 74 Catalog::Catalog(scoped_ptr<Store> store, base::TaskRunner* file_task_runner) |
| 24 : store_(std::move(store)), | 75 : store_(std::move(store)), |
| 76 file_task_runner_(file_task_runner), |
| 25 weak_factory_(this) { | 77 weak_factory_(this) { |
| 26 PathService::Get(base::DIR_MODULE, &package_path_); | 78 PathService::Get(base::DIR_MODULE, &system_package_dir_); |
| 27 reader_.reset(new Reader(package_path_, blocking_pool)); | |
| 28 DeserializeCatalog(); | 79 DeserializeCatalog(); |
| 29 } | 80 } |
| 30 | 81 |
| 31 Catalog::~Catalog() {} | 82 Catalog::~Catalog() {} |
| 32 | 83 |
| 33 void Catalog::BindResolver(mojom::ResolverRequest request) { | 84 void Catalog::BindResolver(mojom::ResolverRequest request) { |
| 34 resolver_bindings_.AddBinding(this, std::move(request)); | 85 resolver_bindings_.AddBinding(this, std::move(request)); |
| 35 } | 86 } |
| 36 | 87 |
| 37 void Catalog::BindShellResolver( | 88 void Catalog::BindShellResolver( |
| (...skipping 27 matching lines...) Expand all Loading... |
| 65 const mojo::String& scheme, | 116 const mojo::String& scheme, |
| 66 const ResolveProtocolSchemeCallback& callback) { | 117 const ResolveProtocolSchemeCallback& callback) { |
| 67 // TODO(beng): implement. | 118 // TODO(beng): implement. |
| 68 } | 119 } |
| 69 | 120 |
| 70 //////////////////////////////////////////////////////////////////////////////// | 121 //////////////////////////////////////////////////////////////////////////////// |
| 71 // Catalog, mojo::shell::mojom::ShellResolver: | 122 // Catalog, mojo::shell::mojom::ShellResolver: |
| 72 | 123 |
| 73 void Catalog::ResolveMojoName(const mojo::String& mojo_name, | 124 void Catalog::ResolveMojoName(const mojo::String& mojo_name, |
| 74 const ResolveMojoNameCallback& callback) { | 125 const ResolveMojoNameCallback& callback) { |
| 75 std::string resolved_name = mojo_name; | 126 std::string type = mojo::GetNameType(mojo_name); |
| 76 auto alias_iter = mojo_name_aliases_.find(resolved_name); | 127 if (type != "mojo" && type != "exe") { |
| 77 if (alias_iter != mojo_name_aliases_.end()) | 128 scoped_ptr<Entry> entry(new Entry(mojo_name)); |
| 78 resolved_name = alias_iter->second.first; | 129 callback.Run(mojo::shell::mojom::ResolveResult::From(*entry)); |
| 130 return; |
| 131 } |
| 79 | 132 |
| 80 std::string qualifier = mojo::GetNamePath(resolved_name); | 133 auto entry = catalog_.find(mojo_name); |
| 81 auto qualifier_iter = qualifiers_.find(resolved_name); | 134 if (entry != catalog_.end()) { |
| 82 if (qualifier_iter != qualifiers_.end()) | 135 callback.Run(mojo::shell::mojom::ResolveResult::From(*entry->second)); |
| 83 qualifier = qualifier_iter->second; | |
| 84 | |
| 85 if (IsNameInCatalog(resolved_name)) { | |
| 86 CompleteResolveMojoName(resolved_name, qualifier, callback); | |
| 87 } else { | 136 } else { |
| 88 reader_->Read(resolved_name, | 137 base::PostTaskAndReplyWithResult( |
| 89 base::Bind(&Catalog::OnReadEntry, weak_factory_.GetWeakPtr(), | 138 file_task_runner_, FROM_HERE, |
| 90 resolved_name, callback)); | 139 base::Bind(&ReadManifest, system_package_dir_, mojo_name), |
| 140 base::Bind(&Catalog::OnReadManifest, weak_factory_.GetWeakPtr(), |
| 141 mojo_name, callback)); |
| 91 } | 142 } |
| 92 } | 143 } |
| 93 | 144 |
| 94 //////////////////////////////////////////////////////////////////////////////// | 145 //////////////////////////////////////////////////////////////////////////////// |
| 95 // Catalog, mojom::Catalog: | 146 // Catalog, mojom::Catalog: |
| 96 | 147 |
| 97 void Catalog::GetEntries(mojo::Array<mojo::String> names, | 148 void Catalog::GetEntries(mojo::Array<mojo::String> names, |
| 98 const GetEntriesCallback& callback) { | 149 const GetEntriesCallback& callback) { |
| 99 mojo::Map<mojo::String, mojom::CatalogEntryPtr> entries; | 150 mojo::Map<mojo::String, mojom::CatalogEntryPtr> entries; |
| 100 std::vector<mojo::String> names_vec = names.PassStorage(); | 151 std::vector<mojo::String> names_vec = names.PassStorage(); |
| 101 for (const std::string& name : names_vec) { | 152 for (const std::string& name : names_vec) { |
| 102 if (catalog_.find(name) == catalog_.end()) | 153 if (catalog_.find(name) == catalog_.end()) |
| 103 continue; | 154 continue; |
| 104 const Entry& entry = catalog_[name]; | 155 const Entry& entry = *catalog_[name]; |
| 105 mojom::CatalogEntryPtr entry_ptr(mojom::CatalogEntry::New()); | 156 mojom::CatalogEntryPtr entry_ptr(mojom::CatalogEntry::New()); |
| 106 entry_ptr->display_name = entry.display_name(); | 157 entry_ptr->display_name = entry.display_name(); |
| 107 entries[entry.name()] = std::move(entry_ptr); | 158 entries[entry.name()] = std::move(entry_ptr); |
| 108 } | 159 } |
| 109 callback.Run(std::move(entries)); | 160 callback.Run(std::move(entries)); |
| 110 } | 161 } |
| 111 | 162 |
| 112 //////////////////////////////////////////////////////////////////////////////// | 163 //////////////////////////////////////////////////////////////////////////////// |
| 113 // Catalog, private: | 164 // Catalog, private: |
| 114 | 165 |
| 115 void Catalog::CompleteResolveMojoName( | |
| 116 const std::string& resolved_name, | |
| 117 const std::string& qualifier, | |
| 118 const ResolveMojoNameCallback& callback) { | |
| 119 auto entry_iter = catalog_.find(resolved_name); | |
| 120 CHECK(entry_iter != catalog_.end()); | |
| 121 | |
| 122 GURL package_url = mojo::util::AddTrailingSlashIfNeeded( | |
| 123 mojo::util::FilePathToFileURL(package_path_)); | |
| 124 GURL file_url; | |
| 125 std::string type = mojo::GetNameType(resolved_name); | |
| 126 if (type == "mojo") { | |
| 127 // It's still a mojo: URL, use the default mapping scheme. | |
| 128 const std::string host = mojo::GetNamePath(resolved_name); | |
| 129 file_url = package_url.Resolve(host + "/" + host + ".mojo"); | |
| 130 } else if (type == "exe") { | |
| 131 #if defined OS_WIN | |
| 132 std::string extension = ".exe"; | |
| 133 #else | |
| 134 std::string extension; | |
| 135 #endif | |
| 136 file_url = package_url.Resolve( | |
| 137 mojo::GetNamePath(resolved_name) + extension); | |
| 138 } | |
| 139 | |
| 140 mojo::shell::mojom::CapabilitySpecPtr capabilities_ptr = | |
| 141 mojo::shell::mojom::CapabilitySpec::From( | |
| 142 entry_iter->second.capabilities()); | |
| 143 | |
| 144 callback.Run(resolved_name, qualifier, std::move(capabilities_ptr), | |
| 145 file_url.spec()); | |
| 146 } | |
| 147 | |
| 148 bool Catalog::IsNameInCatalog(const std::string& name) const { | |
| 149 return catalog_.find(name) != catalog_.end(); | |
| 150 } | |
| 151 | |
| 152 void Catalog::DeserializeCatalog() { | 166 void Catalog::DeserializeCatalog() { |
| 153 if (!store_) | 167 if (!store_) |
| 154 return; | 168 return; |
| 155 const base::ListValue* catalog = store_->GetStore(); | 169 const base::ListValue* catalog = store_->GetStore(); |
| 156 CHECK(catalog); | 170 CHECK(catalog); |
| 157 // TODO(sky): make this handle aliases. | 171 // TODO(sky): make this handle aliases. |
| 158 for (auto it = catalog->begin(); it != catalog->end(); ++it) { | 172 for (auto it = catalog->begin(); it != catalog->end(); ++it) { |
| 159 const base::DictionaryValue* dictionary = nullptr; | 173 const base::DictionaryValue* dictionary = nullptr; |
| 160 const base::Value* v = *it; | 174 const base::Value* v = *it; |
| 161 CHECK(v->GetAsDictionary(&dictionary)); | 175 CHECK(v->GetAsDictionary(&dictionary)); |
| 162 scoped_ptr<Entry> entry = Entry::Deserialize(*dictionary); | 176 scoped_ptr<Entry> entry = Entry::Deserialize(*dictionary); |
| 163 if (entry) | 177 if (entry) |
| 164 catalog_[entry->name()] = *entry; | 178 catalog_[entry->name()] = std::move(entry); |
| 165 } | 179 } |
| 166 } | 180 } |
| 167 | 181 |
| 168 void Catalog::SerializeCatalog() { | 182 void Catalog::SerializeCatalog() { |
| 169 scoped_ptr<base::ListValue> catalog(new base::ListValue); | 183 scoped_ptr<base::ListValue> catalog(new base::ListValue); |
| 170 for (const auto& entry : catalog_) | 184 for (const auto& entry : catalog_) |
| 171 catalog->Append(entry.second.Serialize()); | 185 catalog->Append(entry.second->Serialize()); |
| 172 if (store_) | 186 if (store_) |
| 173 store_->UpdateStore(std::move(catalog)); | 187 store_->UpdateStore(std::move(catalog)); |
| 174 } | 188 } |
| 175 | 189 |
| 176 // static | 190 // static |
| 177 void Catalog::OnReadEntry(base::WeakPtr<Catalog> catalog, | 191 void Catalog::OnReadManifest(base::WeakPtr<Catalog> catalog, |
| 178 const std::string& name, | 192 const std::string& name, |
| 179 const ResolveMojoNameCallback& callback, | 193 const ResolveMojoNameCallback& callback, |
| 180 scoped_ptr<Entry> entry) { | 194 scoped_ptr<ReadManifestResult> result) { |
| 181 if (!catalog) { | 195 scoped_ptr<Entry> entry(new Entry(name)); |
| 182 callback.Run(name, mojo::GetNamePath(name), nullptr, nullptr); | 196 if (result->manifest_root) { |
| 183 return; | 197 const base::DictionaryValue* dictionary = nullptr; |
| 198 CHECK(result->manifest_root->GetAsDictionary(&dictionary)); |
| 199 entry = Entry::Deserialize(*dictionary); |
| 184 } | 200 } |
| 185 catalog->OnReadEntryImpl(name, callback, std::move(entry)); | 201 entry->set_path(GetPackagePath(result->package_dir, name)); |
| 202 |
| 203 callback.Run(mojo::shell::mojom::ResolveResult::From(*entry)); |
| 204 if (catalog) |
| 205 catalog->AddEntryToCatalog(std::move(entry)); |
| 186 } | 206 } |
| 187 | 207 |
| 188 void Catalog::OnReadEntryImpl(const std::string& name, | 208 void Catalog::AddEntryToCatalog(scoped_ptr<Entry> entry) { |
| 189 const ResolveMojoNameCallback& callback, | 209 DCHECK(entry); |
| 190 scoped_ptr<Entry> entry) { | 210 if (catalog_.end() != catalog_.find(entry->name())) |
| 191 // TODO(beng): evaluate the conditions under which entry is null. | 211 return; |
| 192 if (!entry) { | 212 for (auto child : entry->applications()) |
| 193 entry.reset(new Entry); | 213 AddEntryToCatalog(make_scoped_ptr(child)); |
| 194 entry->set_name(name); | 214 catalog_[entry->name()] = std::move(entry); |
| 195 entry->set_display_name(name); | |
| 196 entry->set_qualifier(mojo::GetNamePath(name)); | |
| 197 } | |
| 198 | |
| 199 if (catalog_.find(entry->name()) == catalog_.end()) { | |
| 200 catalog_[entry->name()] = *entry; | |
| 201 | |
| 202 if (!entry->applications().empty()) { | |
| 203 for (const auto& child : entry->applications()) { | |
| 204 mojo_name_aliases_[child.name()] = | |
| 205 std::make_pair(entry->name(), child.qualifier()); | |
| 206 } | |
| 207 } | |
| 208 qualifiers_[entry->name()] = entry->qualifier(); | |
| 209 } | |
| 210 | |
| 211 SerializeCatalog(); | 215 SerializeCatalog(); |
| 212 | |
| 213 auto qualifier_iter = qualifiers_.find(name); | |
| 214 DCHECK(qualifier_iter != qualifiers_.end()); | |
| 215 std::string qualifier = qualifier_iter->second; | |
| 216 CompleteResolveMojoName(name, qualifier, callback); | |
| 217 } | 216 } |
| 218 | 217 |
| 219 } // namespace catalog | 218 } // namespace catalog |
| OLD | NEW |