Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: chrome/browser/extensions/extension_history_api.cc

Issue 313001: Implement the Extension History API, v 0.1.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 "chrome/browser/extensions/extension_history_api.h"
6
7 #include "base/json/json_writer.h"
8 #include "base/message_loop.h"
9 #include "base/string_util.h"
10 #include "base/task.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/extension_history_api_constants.h"
13 #include "chrome/browser/extensions/extension_message_service.h"
14 #include "chrome/browser/history/history.h"
15 #include "chrome/browser/history/history_types.h"
16 #include "chrome/browser/profile.h"
17 #include "chrome/common/notification_type.h"
18 #include "chrome/common/notification_service.h"
19
20 namespace keys = extension_history_api_constants;
21
22 namespace {
23
24 double MilliSecondsFromTime(const base::Time& time) {
25 return 1000 * time.ToDoubleT();
26 }
27
28 void GetHistoryItemDictionary(const history::URLRow& row,
29 DictionaryValue* value) {
30 value->SetString(keys::kIdKey, Int64ToString(row.id()));
31 value->SetString(keys::kUrlKey, row.url().spec());
32 value->SetString(keys::kTitleKey, row.title());
33 value->SetReal(keys::kLastVisitdKey, MilliSecondsFromTime(row.last_visit()));
34 value->SetInteger(keys::kTypedCountKey, row.typed_count());
35 value->SetInteger(keys::kVisitCountKey, row.visit_count());
36 }
37
38 void AddHistoryNode(const history::URLRow& row, ListValue* list) {
39 DictionaryValue* dict = new DictionaryValue();
40 GetHistoryItemDictionary(row, dict);
41 list->Append(dict);
42 }
43
44 void GetVisitInfoDictionary(const history::VisitRow& row,
45 DictionaryValue* value) {
46 value->SetString(keys::kIdKey, Int64ToString(row.url_id));
47 value->SetString(keys::kVisitId, Int64ToString(row.visit_id));
48 value->SetReal(keys::kVisitTime, MilliSecondsFromTime(row.visit_time));
49 value->SetString(keys::kReferringVisitId,
50 Int64ToString(row.referring_visit));
51 value->SetInteger(keys::kTransition,
52 row.transition && PageTransition::CORE_MASK);
53 }
54
55 void AddVisitNode(const history::VisitRow& row, ListValue* list) {
56 DictionaryValue* dict = new DictionaryValue();
57 GetVisitInfoDictionary(row, dict);
58 list->Append(dict);
59 }
60
61 } // namespace
62
63 ExtensionHistoryEventRouter* ExtensionHistoryEventRouter::GetInstance() {
64 return Singleton<ExtensionHistoryEventRouter>::get();
65 }
66
67 void ExtensionHistoryEventRouter::ObserveProfile(Profile* profile) {
68 NotificationSource source = Source<Profile>(profile);
69 if (profiles_.find(source.map_key()) == profiles_.end())
70 profiles_[source.map_key()] = profile;
71
72 if (registrar_.IsEmpty()) {
73 registrar_.Add(this,
74 NotificationType::HISTORY_URL_VISITED,
75 NotificationService::AllSources());
76 registrar_.Add(this,
77 NotificationType::HISTORY_URLS_DELETED,
78 NotificationService::AllSources());
79 }
80 }
81
82 void ExtensionHistoryEventRouter::Observe(NotificationType type,
83 const NotificationSource& source,
84 const NotificationDetails& details) {
85 ProfileMap::iterator it = profiles_.find(source.map_key());
86 if (it != profiles_.end()) {
87 Profile* profile = it->second;
88 switch (type.value) {
89 case NotificationType::HISTORY_URL_VISITED:
90 HistoryUrlVisited(
91 profile,
92 Details<const history::URLVisitedDetails>(details).ptr());
93 break;
94 case NotificationType::HISTORY_URLS_DELETED:
95 HistoryUrlsRemoved(
96 profile,
97 Details<const history::URLsDeletedDetails>(details).ptr());
98 break;
99 default:
100 NOTREACHED();
101 }
102 }
103 }
104
105 void ExtensionHistoryEventRouter::HistoryUrlVisited(
106 Profile* profile,
107 const history::URLVisitedDetails* details) {
108 ListValue args;
109 DictionaryValue* dict = new DictionaryValue();
110 GetHistoryItemDictionary(details->row, dict);
111 args.Append(dict);
112
113 std::string json_args;
114 base::JSONWriter::Write(&args, false, &json_args);
115 DispatchEvent(profile, keys::kOnVisited, json_args);
116 }
117
118 void ExtensionHistoryEventRouter::HistoryUrlsRemoved(
119 Profile* profile,
120 const history::URLsDeletedDetails* details) {
121 ListValue args;
122 DictionaryValue* dict = new DictionaryValue();
123 dict->SetBoolean(keys::kAllHistoryKey, details->all_history);
124 ListValue* urls = new ListValue();
125 for (std::set<GURL>::const_iterator iterator = details->urls.begin();
126 iterator != details->urls.end();
127 ++iterator) {
128 urls->Append(new StringValue(iterator->spec()));
129 }
130 dict->Set(keys::kUrlsKey, urls);
131 args.Append(dict);
132
133 std::string json_args;
134 base::JSONWriter::Write(&args, false, &json_args);
135 DispatchEvent(profile, keys::kOnVisitRemoved, json_args);
136 }
137
138 void ExtensionHistoryEventRouter::DispatchEvent(Profile* profile,
139 const char* event_name,
140 const std::string& json_args) {
141 if (profile && profile->GetExtensionMessageService()) {
142 profile->GetExtensionMessageService()->
143 DispatchEventToRenderers(event_name, json_args);
144 }
145 }
146
147 void HistoryFunction::Run() {
148 if (!RunImpl()) {
149 SendResponse(false);
150 }
151 }
152
153 bool HistoryFunction::GetUrlFromValue(Value* value, GURL* url) {
154 std::string url_string;
155 if (!value->GetAsString(&url_string)) {
156 bad_message_ = true;
157 return false;
158 }
159
160 GURL temp_url(url_string);
161 if (!temp_url.is_valid()) {
162 error_ = keys::kInvalidUrlError;
163 return false;
164 }
165 url->Swap(&temp_url);
166 return true;
167 }
168
169 bool HistoryFunction::GetTimeFromValue(Value* value, base::Time* time) {
170 double ms_from_epoch = 0;
171 if (!value->GetAsReal(&ms_from_epoch)) {
172 return false;
173 }
174 // The history service has seconds resolution, while javascript Date() has
175 // milliseconds resolution.
176 double seconds_from_epoch = ms_from_epoch / 1000;
177 *time = base::Time::FromDoubleT(seconds_from_epoch);
178 return true;
179 }
180
181 bool HistoryFunctionWithCallback::RunImpl() {
182 AddRef(); // Balanced in SendAysncRepose() and below.
183 bool retval = RunAsyncImpl();
184 if (false == retval)
185 Release();
186 return retval;
187 }
188
189 void HistoryFunctionWithCallback::SendAsyncResponse() {
190 MessageLoop::current()->PostTask(
191 FROM_HERE,
192 NewRunnableMethod(
193 this,
194 &HistoryFunctionWithCallback::SendResponseToCallback));
195 }
196
197 void HistoryFunctionWithCallback::SendResponseToCallback() {
198 SendResponse(true);
199 Release(); // Balanced in RunImpl().
200 }
201
202 bool GetVisitsHistoryFunction::RunAsyncImpl() {
203 EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
204 DictionaryValue* json = static_cast<DictionaryValue*>(args_);
205
206 Value* value;
207 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
208
209 GURL url;
210 if (!GetUrlFromValue(value, &url))
211 return false;
212
213 HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
214 hs->QueryURL(url,
215 true, // Retrieve full history of a URL.
216 &cancelable_consumer_,
217 NewCallback(this, &GetVisitsHistoryFunction::QueryComplete));
218
219 return true;
220 }
221
222 void GetVisitsHistoryFunction::QueryComplete(
223 HistoryService::Handle request_service,
224 bool success,
225 const history::URLRow* url_row,
226 history::VisitVector* visits) {
227 ListValue* list = new ListValue();
228 if (visits && !visits->empty()) {
229 for (history::VisitVector::iterator iterator = visits->begin();
230 iterator != visits->end();
231 ++iterator) {
232 AddVisitNode(*iterator, list);
233 }
234 }
235 result_.reset(list);
236 SendAsyncResponse();
237 }
238
239 bool SearchHistoryFunction::RunAsyncImpl() {
240 EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
241 DictionaryValue* json = static_cast<DictionaryValue*>(args_);
242
243 // Initialize the HistoryQuery
244 std::wstring search_text;
245 EXTENSION_FUNCTION_VALIDATE(json->GetString(keys::kSearchKey, &search_text));
246
247 history::QueryOptions options;
248 options.most_recent_visit_only = true;
249 options.SetRecentDayRange(1);
250 options.max_count = 100;
251
252 if (json->HasKey(keys::kStartTimeKey)) { // Optional.
253 Value* value;
254 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kStartTimeKey, &value));
255 EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &options.begin_time));
256 }
257 if (json->HasKey(keys::kEndTimeKey)) { // Optional.
258 Value* value;
259 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kEndTimeKey, &value));
260 EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &options.end_time));
261 }
262 if (json->HasKey(keys::kMaxResultsKey)) { // Optional.
263 EXTENSION_FUNCTION_VALIDATE(json->GetInteger(keys::kMaxResultsKey,
264 &options.max_count));
265 }
266
267 HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
268 hs->QueryHistory(search_text, options, &cancelable_consumer_,
269 NewCallback(this, &SearchHistoryFunction::SearchComplete));
270
271 return true;
272 }
273
274 void SearchHistoryFunction::SearchComplete(
275 HistoryService::Handle request_handle,
276 history::QueryResults* results) {
277 ListValue* list = new ListValue();
278 if (results && !results->empty()) {
279 for (history::QueryResults::URLResultVector::const_iterator iterator =
280 results->begin();
281 iterator != results->end();
282 ++iterator) {
283 AddHistoryNode(**iterator, list);
284 }
285 }
286 result_.reset(list);
287 SendAsyncResponse();
288 }
289
290 bool AddUrlHistoryFunction::RunImpl() {
291 EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
292 DictionaryValue* json = static_cast<DictionaryValue*>(args_);
293
294 Value* value;
295 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
296
297 GURL url;
298 if (!GetUrlFromValue(value, &url))
299 return false;
300
301 HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
302 hs->AddPage(url);
303
304 SendResponse(true);
305 return true;
306 }
307
308 bool DeleteUrlHistoryFunction::RunImpl() {
309 EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
310 DictionaryValue* json = static_cast<DictionaryValue*>(args_);
311
312 Value* value;
313 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
314
315 GURL url;
316 if (!GetUrlFromValue(value, &url))
317 return false;
318
319 HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
320 hs->DeleteURL(url);
321
322 SendResponse(true);
323 return true;
324 }
325
326 bool DeleteRangeHistoryFunction::RunAsyncImpl() {
327 EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
328 DictionaryValue* json = static_cast<DictionaryValue*>(args_);
329
330 Value* value = NULL;
331 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kStartTimeKey, &value));
332 base::Time begin_time;
333 EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &begin_time));
334
335 EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kEndTimeKey, &value));
336 base::Time end_time;
337 EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &end_time));
338
339 HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
340 hs->ExpireHistoryBetween(
341 begin_time,
342 end_time,
343 &cancelable_consumer_,
344 NewCallback(this, &DeleteRangeHistoryFunction::DeleteComplete));
345
346 return true;
347 }
348
349 void DeleteRangeHistoryFunction::DeleteComplete() {
350 SendAsyncResponse();
351 }
352
353 bool DeleteAllHistoryFunction::RunAsyncImpl() {
354 HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
355 hs->ExpireHistoryBetween(
356 base::Time::FromDoubleT(0), // From the beginning of the epoch.
357 base::Time::Now(), // To the current time.
358 &cancelable_consumer_,
359 NewCallback(this, &DeleteAllHistoryFunction::DeleteComplete));
360
361 return true;
362 }
363
364 void DeleteAllHistoryFunction::DeleteComplete() {
365 SendAsyncResponse();
366 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_history_api.h ('k') | chrome/browser/extensions/extension_history_api_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698