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 |