summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authormirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 23:02:54 +0000
committermirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 23:02:54 +0000
commitea0c98cfa2849f95bf40238c9f476c9cebb22244 (patch)
treeec81fe0c664cb6c0adddbd5d392313e8fbb93ec5 /chrome/browser
parent1f70f0ca51d1c61d3a775507b2b69dcdf60e77df (diff)
downloadchromium_src-ea0c98cfa2849f95bf40238c9f476c9cebb22244.zip
chromium_src-ea0c98cfa2849f95bf40238c9f476c9cebb22244.tar.gz
chromium_src-ea0c98cfa2849f95bf40238c9f476c9cebb22244.tar.bz2
First draft of web resource service; fetches data from a JSON feed
and stores it in user prefs, where it can be used by the new tab page. BUG = http://crbug.com/13363 Review URL: http://codereview.chromium.org/125052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18766 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser_main.cc6
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc14
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h3
-rw-r--r--chrome/browser/dom_ui/web_resource_handler.cc95
-rw-r--r--chrome/browser/dom_ui/web_resource_handler.h56
-rw-r--r--chrome/browser/profile.cc12
-rw-r--r--chrome/browser/profile.h6
-rw-r--r--chrome/browser/utility_process_host.cc17
-rw-r--r--chrome/browser/utility_process_host.h22
-rw-r--r--chrome/browser/views/frame/browser_view.cc8
-rw-r--r--chrome/browser/web_resource/web_resource_service.cc268
-rw-r--r--chrome/browser/web_resource/web_resource_service.h102
12 files changed, 603 insertions, 6 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index bfd77da..e0d37ae 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -110,7 +110,7 @@
#if defined(LINUX2)
#include "chrome/browser/extensions/extension_protocols.h"
-#endif // defined(LINUX2)
+#endif // defined(LINUX2)
#if defined(TOOLKIT_GTK)
#include "chrome/common/gtk_util.h"
@@ -790,6 +790,10 @@ int BrowserMain(const MainFunctionParams& parameters) {
RecordBreakpadStatusUMA(metrics);
// Start up the extensions service. This should happen before Start().
profile->InitExtensions();
+ // Start up the web resource service. This starts loading data after a
+ // short delay so as not to interfere with startup time.
+ if (parsed_command_line.HasSwitch(switches::kWebResources))
+ profile->InitWebResources();
int result_code = ResultCodes::NORMAL_EXIT;
if (parameters.ui_task) {
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc
index 52b0297..e1dd96e 100644
--- a/chrome/browser/dom_ui/new_tab_ui.cc
+++ b/chrome/browser/dom_ui/new_tab_ui.cc
@@ -22,6 +22,7 @@
#include "chrome/browser/dom_ui/dom_ui_theme_source.h"
#include "chrome/browser/dom_ui/downloads_dom_handler.h"
#include "chrome/browser/dom_ui/history_ui.h"
+#include "chrome/browser/dom_ui/web_resource_handler.h"
#include "chrome/browser/history/page_usage_data.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
@@ -291,6 +292,8 @@ void NewTabHTMLSource::StartDataRequest(const std::string& path,
l10n_util::GetString(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE));
localized_strings.SetString(L"attributionintro",
l10n_util::GetString(IDS_NEW_TAB_ATTRIBUTION_INTRO));
+ localized_strings.SetString(L"resourcecache",
+ l10n_util::GetString(IDS_NEW_TAB_WEB_RESOURCE_CACHE));
SetFontAndTextDirection(&localized_strings);
@@ -1380,6 +1383,9 @@ NewTabUI::NewTabUI(TabContents* contents)
downloads_handler->Init();
}
+ if (EnableWebResources())
+ AddMessageHandler(new WebResourceHandler(this));
+
AddMessageHandler(new TemplateURLHandler(this));
AddMessageHandler(new MostVisitedHandler(this));
AddMessageHandler(new RecentlyBookmarkedHandler(this));
@@ -1435,6 +1441,8 @@ void NewTabUI::Observe(NotificationType type,
// static
void NewTabUI::RegisterUserPrefs(PrefService* prefs) {
MostVisitedHandler::RegisterUserPrefs(prefs);
+ if (NewTabUI::EnableWebResources())
+ WebResourceHandler::RegisterUserPrefs(prefs);
}
// static
@@ -1442,3 +1450,9 @@ bool NewTabUI::EnableNewNewTabPage() {
const CommandLine* command_line = CommandLine::ForCurrentProcess();
return command_line->HasSwitch(switches::kNewNewTabPage);
}
+
+bool NewTabUI::EnableWebResources() {
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ return command_line->HasSwitch(switches::kWebResources);
+}
+
diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h
index 6c3a2f1..851dbfa 100644
--- a/chrome/browser/dom_ui/new_tab_ui.h
+++ b/chrome/browser/dom_ui/new_tab_ui.h
@@ -28,6 +28,9 @@ class NewTabUI : public DOMUI,
// Whether we should use the prototype new tab page.
static bool EnableNewNewTabPage();
+ // Whether we should enable the web resources backend service
+ static bool EnableWebResources();
+
private:
void Observe(NotificationType type,
const NotificationSource& source,
diff --git a/chrome/browser/dom_ui/web_resource_handler.cc b/chrome/browser/dom_ui/web_resource_handler.cc
new file mode 100644
index 0000000..7895da4
--- /dev/null
+++ b/chrome/browser/dom_ui/web_resource_handler.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/values.h"
+#include "chrome/browser/dom_ui/web_resource_handler.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/web_resource/web_resource_service.h"
+#include "chrome/common/web_resource/web_resource_unpacker.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+ const int kNumWebResourcesToShow = 2;
+
+ // TODO(mrc): l10n
+ // This title should only appear the very first time Chrome is run with
+ // web resources enabled; otherwise the cache should be populated.
+ static const wchar_t* kWebResourceTitleAtStartup =
+ L"New: Suggestion Box!";
+
+ // This snipp should only appear the very first time Chrome is run with
+ // web resources enabled; otherwise the cache should be populated.
+ static const wchar_t* kWebResourceSnippetAtStartup =
+ L"Tips and recommendations to help you discover interesting websites.";
+}
+
+WebResourceHandler::WebResourceHandler(DOMUI* dom_ui)
+ : DOMMessageHandler(dom_ui),
+ dom_ui_(dom_ui) {
+ dom_ui->RegisterMessageCallback("getNextCachedWebResource",
+ NewCallback(this, &WebResourceHandler::HandleGetCachedWebResource));
+
+ web_resource_cache_ = dom_ui_->GetProfile()->GetPrefs()->
+ GetDictionary(prefs::kNTPWebResourceCache);
+}
+
+void WebResourceHandler::HandleGetCachedWebResource(const Value* content) {
+ // Eventually we will feed more than one web resource datum at a time
+ // to the NTP; for now, this is a list containing one item: the tip
+ // to be displayed.
+ ListValue list_value;
+
+ // Holds the web resource data found in the preferences cache.
+ DictionaryValue* wr_dict;
+
+ // Dictionary which will be sent back in a Javascript call.
+ DictionaryValue* tip_dict = new DictionaryValue();
+
+ // These values hold the data for each web resource item. As the web
+ // resource server solidifies, these may change.
+ std::wstring title;
+ std::wstring thumb;
+ std::wstring source;
+ std::wstring snipp;
+ std::wstring url;
+
+ // This should only be true on the very first Chrome run; otherwise,
+ // the cache should be populated.
+ if (web_resource_cache_ == NULL || web_resource_cache_->GetSize() < 1) {
+ title = kWebResourceTitleAtStartup;
+ snipp = kWebResourceSnippetAtStartup;
+ } else {
+ // Right now, hard-coded to simply get the first item (marked "0") in the
+ // resource data stored in the cache. Fail silently if data is missing.
+ // TODO(mrc): If data is missing, iterate through cache.
+ web_resource_cache_->GetDictionary(L"0", &wr_dict);
+ if (wr_dict &&
+ wr_dict->GetSize() > 0 &&
+ wr_dict->GetString(WebResourceService::kWebResourceTitle, &title) &&
+ wr_dict->GetString(WebResourceService::kWebResourceThumb, &thumb) &&
+ wr_dict->GetString(WebResourceService::kWebResourceSource, &source) &&
+ wr_dict->GetString(WebResourceService::kWebResourceSnippet, &snipp) &&
+ wr_dict->GetString(WebResourceService::kWebResourceURL, &url)) {
+ tip_dict->SetString(WebResourceService::kWebResourceTitle, title);
+ tip_dict->SetString(WebResourceService::kWebResourceThumb, thumb);
+ tip_dict->SetString(WebResourceService::kWebResourceSource, source);
+ tip_dict->SetString(WebResourceService::kWebResourceSnippet, snipp);
+ tip_dict->SetString(WebResourceService::kWebResourceURL, url);
+ }
+ }
+
+ list_value.Append(tip_dict);
+
+ // Send list of snippets back out to the DOM.
+ dom_ui_->CallJavascriptFunction(L"nextWebResource", list_value);
+}
+
+// static
+void WebResourceHandler::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterDictionaryPref(prefs::kNTPWebResourceCache);
+ prefs->RegisterStringPref(prefs::kNTPWebResourceServer,
+ WebResourceService::kDefaultResourceServer);
+}
+
diff --git a/chrome/browser/dom_ui/web_resource_handler.h b/chrome/browser/dom_ui/web_resource_handler.h
new file mode 100644
index 0000000..01157f9
--- /dev/null
+++ b/chrome/browser/dom_ui/web_resource_handler.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This class pulls data from a web resource (such as a JSON feed) which
+// has been stored in the user's preferences file. Used mainly
+// by the suggestions and tips area of the new tab page.
+
+// Current sketch of tip cache format, hardcoded for poptart data in
+// basic text form:
+
+// "web_resource_cache": {
+// "0": {
+// "index": should become time field (or not)
+// "snippet": the text of the item
+// "source": text describing source (i.e., "New York Post")
+// "thumbnail": URL of thumbnail on popgadget server
+// "title": text giving title of item
+// "url": link to item's page
+// },
+// [up to number of items in kMaxWebResourceCacheSize]
+
+#ifndef CHROME_BROWSER_DOM_UI_WEB_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_DOM_UI_WEB_RESOURCE_HANDLER_H_
+
+#include "chrome/browser/dom_ui/dom_ui.h"
+
+class DictionaryValue;
+class DOMUI;
+class PrefService;
+class Value;
+
+class WebResourceHandler : public DOMMessageHandler {
+ public:
+ explicit WebResourceHandler(DOMUI* dom_ui);
+
+ WebResourceHandler();
+
+ // Callback which pulls web resource data from the preferences.
+ void HandleGetCachedWebResource(const Value* content);
+
+ // Register web resource cache with pref service.
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ private:
+ // So we can push data out to the page that has called this handler.
+ DOMUI* dom_ui_;
+
+ // Filled with data from cache in preferences.
+ const DictionaryValue* web_resource_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebResourceHandler);
+};
+
+#endif // CHROME_BROWSER_DOM_UI_WEB_RESOURCE_HANDLER_H_
+
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index 3e8b196..179f506 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -353,6 +353,10 @@ class OffTheRecordProfileImpl : public Profile,
NOTREACHED();
}
+ virtual void InitWebResources() {
+ NOTREACHED();
+ }
+
virtual void ExitedOffTheRecordMode() {
// Drop our download manager so we forget about all the downloads made
// in off-the-record mode.
@@ -480,6 +484,14 @@ void ProfileImpl::InitExtensions() {
extensions_service_->Init();
}
+void ProfileImpl::InitWebResources() {
+ web_resource_service_ = new WebResourceService(
+ this,
+ g_browser_process->file_thread()->message_loop());
+
+ web_resource_service_->StartAfterDelay();
+}
+
ProfileImpl::~ProfileImpl() {
tab_restore_service_ = NULL;
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 0c6179e..c4203db 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -15,6 +15,7 @@
#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
+#include "chrome/browser/web_resource/web_resource_service.h"
#ifdef CHROME_PERSONALIZATION
#include "chrome/personalization/personalization.h"
#endif
@@ -277,6 +278,9 @@ class Profile {
virtual void InitExtensions() = 0;
+ // Start up service that gathers data from web resource feeds.
+ virtual void InitWebResources() = 0;
+
#ifdef UNIT_TEST
// Use with caution. GetDefaultRequestContext may be called on any thread!
static void set_default_request_context(URLRequestContext* c) {
@@ -352,6 +356,7 @@ class ProfileImpl : public Profile,
virtual SpellChecker* GetSpellChecker();
virtual void MarkAsCleanShutdown();
virtual void InitExtensions();
+ virtual void InitWebResources();
#ifdef CHROME_PERSONALIZATION
virtual ProfilePersonalization* GetProfilePersonalization();
#endif
@@ -399,6 +404,7 @@ class ProfileImpl : public Profile,
scoped_ptr<TemplateURLFetcher> template_url_fetcher_;
scoped_ptr<TemplateURLModel> template_url_model_;
scoped_ptr<BookmarkModel> bookmark_bar_model_;
+ scoped_refptr<WebResourceService> web_resource_service_;
#ifdef CHROME_PERSONALIZATION
scoped_ptr<ProfilePersonalization> personalization_;
diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc
index 5dad2c5..e515eeb 100644
--- a/chrome/browser/utility_process_host.cc
+++ b/chrome/browser/utility_process_host.cc
@@ -37,6 +37,14 @@ bool UtilityProcessHost::StartExtensionUnpacker(const FilePath& extension) {
return true;
}
+bool UtilityProcessHost::StartWebResourceUnpacker(const std::string& data) {
+ if (!StartProcess(FilePath()))
+ return false;
+
+ Send(new UtilityMsg_UnpackWebResource(data));
+ return true;
+}
+
bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
if (!CreateChannel())
return false;
@@ -56,7 +64,10 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
base::ProcessHandle process;
#if defined(OS_WIN)
- process = sandbox::StartProcessWithAccess(&cmd_line, exposed_dir);
+ if (exposed_dir.empty())
+ process = sandbox::StartProcess(&cmd_line);
+ else
+ process = sandbox::StartProcessWithAccess(&cmd_line, exposed_dir);
#else
// TODO(port): sandbox
base::LaunchApp(cmd_line, false, false, &process);
@@ -89,5 +100,9 @@ void UtilityProcessHost::Client::OnMessageReceived(
Client::OnUnpackExtensionSucceeded)
IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackExtension_Failed,
Client::OnUnpackExtensionFailed)
+ IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackWebResource_Succeeded,
+ Client::OnUnpackWebResourceSucceeded)
+ IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackWebResource_Failed,
+ Client::OnUnpackWebResourceFailed)
IPC_END_MESSAGE_MAP_EX()
}
diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h
index 03d98c8..86b7935 100644
--- a/chrome/browser/utility_process_host.h
+++ b/chrome/browser/utility_process_host.h
@@ -15,6 +15,7 @@
class CommandLine;
class DictionaryValue;
+class ListValue;
class MessageLoop;
// This class acts as the browser-side host to a utility child process. A
@@ -42,6 +43,17 @@ class UtilityProcessHost : public ChildProcessHost {
// |error_message| contains a description of the problem.
virtual void OnUnpackExtensionFailed(const std::string& error_message) {}
+ // Called when the web resource has been successfully parsed. |json_data|
+ // contains the parsed list of web resource items downloaded from the
+ // web resource server.
+ virtual void OnUnpackWebResourceSucceeded(
+ const ListValue& json_data) {}
+
+ // Called when an error occurred while parsing the resource data.
+ // |error_message| contains a description of the problem.
+ virtual void OnUnpackWebResourceFailed(
+ const std::string& error_message) {}
+
private:
friend class UtilityProcessHost;
void OnMessageReceived(const IPC::Message& message);
@@ -59,8 +71,16 @@ class UtilityProcessHost : public ChildProcessHost {
// location first.
bool StartExtensionUnpacker(const FilePath& extension);
+ // Start a process to unpack and parse a web resource from the given JSON
+ // data. Any links that need to be downloaded from the parsed data
+ // (thumbnails, etc.) will be unpacked in resource_dir.
+ // TODO(mrc): Right now, the unpacker just parses the JSON data, and
+ // doesn't do any unpacking. This should change once we finalize the
+ // web resource server format(s).
+ bool StartWebResourceUnpacker(const std::string& data);
+
private:
- // Starts the process. Returns true iff it succeeded.
+ // Starts a process. Returns true iff it succeeded.
bool StartProcess(const FilePath& exposed_dir);
// IPC messages:
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index 50780f5..8aa44b6 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -837,7 +837,8 @@ void BrowserView::SetDownloadShelfVisible(bool visible) {
GetDownloadShelf();
}
- browser_->UpdateDownloadShelfVisibility(visible);
+ if (browser_ != NULL)
+ browser_->UpdateDownloadShelfVisibility(visible);
}
// SetDownloadShelfVisible can force-close the shelf, so make sure we lay out
@@ -1289,7 +1290,7 @@ int BrowserView::NonClientHitTest(const gfx::Point& point) {
}
gfx::Size BrowserView::GetMinimumSize() {
- // TODO: In theory the tabstrip width should probably be
+ // TODO(noname): In theory the tabstrip width should probably be
// (OTR + tabstrip + caption buttons) width.
gfx::Size tabstrip_size(
browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP) ?
@@ -1367,7 +1368,8 @@ void BrowserView::Init() {
#if defined(OS_WIN)
SetProp(GetWidget()->GetNativeView(), kBrowserViewKey, this);
#else
- g_object_set_data(G_OBJECT(GetWidget()->GetNativeView()), kBrowserViewKey, this);
+ g_object_set_data(G_OBJECT(GetWidget()->GetNativeView()),
+ kBrowserViewKey, this);
#endif
// Start a hung plugin window detector for this browser object (as long as
diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc
new file mode 100644
index 0000000..7402025
--- /dev/null
+++ b/chrome/browser/web_resource/web_resource_service.cc
@@ -0,0 +1,268 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chrome/browser/web_resource/web_resource_service.h"
+
+#include "base/string_util.h"
+#include "base/time.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/net/url_fetcher.h"
+#include "chrome/common/pref_names.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request_status.h"
+
+const wchar_t* WebResourceService::kWebResourceTitle = L"title";
+const wchar_t* WebResourceService::kWebResourceThumb = L"thumbnail";
+const wchar_t* WebResourceService::kWebResourceSource = L"source";
+const wchar_t* WebResourceService::kWebResourceSnippet = L"snippet";
+const wchar_t* WebResourceService::kWebResourceURL = L"url";
+
+class WebResourceService::WebResourceFetcher
+ : public URLFetcher::Delegate {
+ public:
+ explicit WebResourceFetcher(WebResourceService* web_resource_service) :
+ ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_factory_(this)),
+ web_resource_service_(web_resource_service) {
+ }
+
+ // Delay initial load of resource data into cache so as not to interfere
+ // with startup time.
+ void StartAfterDelay(int delay_ms) {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
+ delay_ms);
+ }
+
+ // Initializes the fetching of data from the resource server. Data
+ // load calls OnURLFetchComplete.
+ void StartFetch() {
+ // First, put our next cache load on the MessageLoop.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
+ kCacheUpdateDelay);
+ // If we are still fetching data, exit.
+ if (web_resource_service_->in_fetch_)
+ return;
+
+ url_fetcher_.reset(new URLFetcher(GURL(
+ WideToUTF8(web_resource_service_->web_resource_server_)),
+ URLFetcher::GET, this));
+ // Do not let url fetcher affect existing state in profile (by setting
+ // cookies, for example.
+ url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ url_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
+ url_fetcher_->Start();
+ }
+
+ // From URLFetcher::Delegate.
+ void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ // Delete the URLFetcher when this function exits.
+ scoped_ptr<URLFetcher> clean_up_fetcher(url_fetcher_.release());
+
+ // Don't parse data if attempt to download was unsuccessful.
+ // Stop loading new web resource data, and silently exit.
+ if (!status.is_success() || (response_code != 200))
+ return;
+
+ web_resource_service_->UpdateResourceCache(data);
+ }
+
+ private:
+ // So that we can delay our start so as not to affect start-up time; also,
+ // so that we can schedule future cache updates.
+ ScopedRunnableMethodFactory<WebResourceFetcher> fetcher_factory_;
+
+ // The tool that fetches the url data from the server.
+ scoped_ptr<URLFetcher> url_fetcher_;
+
+ // Our owner and creator.
+ scoped_ptr<WebResourceService> web_resource_service_;
+};
+
+// This class coordinates a web resource unpack and parse task which is run in
+// a separate process. Results are sent back to this class and routed to
+// the WebResourceService.
+class WebResourceService::UnpackerClient
+ : public UtilityProcessHost::Client {
+ public:
+ UnpackerClient(WebResourceService* web_resource_service,
+ const std::string& json_data)
+ : web_resource_service_(web_resource_service),
+ json_data_(json_data) {
+ }
+
+ void Start() {
+ AddRef(); // balanced in Cleanup.
+
+ if (web_resource_service_->resource_dispatcher_host_) {
+ ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
+ web_resource_service_->resource_dispatcher_host_,
+ MessageLoop::current()));
+ } else {
+ // TODO(mrc): unit tests here.
+ }
+ }
+
+ private:
+ virtual void OnUnpackWebResourceSucceeded(const ListValue& parsed_json) {
+ web_resource_service_->OnWebResourceUnpacked(parsed_json);
+ Release();
+ }
+
+ virtual void OnUnpackWebResourceFailed(const std::string& error_message) {
+ web_resource_service_->EndFetch();
+ Release();
+ }
+
+ void StartProcessOnIOThread(ResourceDispatcherHost* rdh,
+ MessageLoop* file_loop) {
+ UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop);
+ // TODO(mrc): get proper file path when we start using web resources
+ // that need to be unpacked.
+ host->StartWebResourceUnpacker(json_data_);
+ }
+
+ scoped_refptr<WebResourceService> web_resource_service_;
+
+ // Holds raw JSON string.
+ const std::string& json_data_;
+};
+
+const wchar_t* WebResourceService::kDefaultResourceServer =
+// L"http://hokiepokie.nyc.corp.google.com:8125/"
+// L"labs/popgadget/world?view=json";
+ L"http://sites.google.com/a/chromium.org/dev/developers/"
+ L"design-documents/web_resources/popgadget_test.json";
+
+const char* WebResourceService::kResourceDirectoryName =
+ "Resources";
+
+WebResourceService::WebResourceService(Profile* profile,
+ MessageLoop* backend_loop) :
+ prefs_(profile->GetPrefs()),
+ web_resource_dir_(profile->GetPath().AppendASCII(kResourceDirectoryName)),
+ backend_loop_(backend_loop),
+ in_fetch_(false) {
+ Init();
+}
+
+WebResourceService::~WebResourceService() { }
+
+void WebResourceService::Init() {
+ resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
+ web_resource_fetcher_ = new WebResourceFetcher(this);
+ prefs_->RegisterStringPref(prefs::kNTPWebResourceCacheUpdate, L"0");
+ // TODO(mrc): make sure server name is valid.
+ web_resource_server_ = prefs_->HasPrefPath(prefs::kNTPWebResourceServer) ?
+ prefs_->GetString(prefs::kNTPWebResourceServer) :
+ kDefaultResourceServer;
+}
+
+void WebResourceService::EndFetch() {
+ in_fetch_ = false;
+}
+
+void WebResourceService::OnWebResourceUnpacked(const ListValue& parsed_json) {
+ // Get dictionary of cached preferences.
+ web_resource_cache_ =
+ prefs_->GetMutableDictionary(prefs::kNTPWebResourceCache);
+ ListValue::const_iterator wr_iter = parsed_json.begin();
+ int wr_counter = 0;
+
+ // These values store the data for each new web resource item.
+ std::wstring result_snippet;
+ std::wstring result_url;
+ std::wstring result_source;
+ std::wstring result_title;
+ std::wstring result_title_type;
+ std::wstring result_thumbnail;
+
+ // Iterate through newly parsed preferences, replacing stale cache with
+ // new data.
+ // TODO(mrc): make this smarter, so it actually only replaces stale data,
+ // instead of overwriting the whole thing every time.
+ while (wr_iter != parsed_json.end() &&
+ wr_counter < kMaxResourceCacheSize) {
+ // Each item is stored in the form of a dictionary.
+ // See web_resource_handler.h for format (this will change until
+ // web resource services are solidified!).
+ if (!(*wr_iter)->IsType(Value::TYPE_DICTIONARY))
+ continue;
+ DictionaryValue* wr_dict =
+ static_cast<DictionaryValue*>(*wr_iter);
+
+ // Get next space for resource in prefs file.
+ Value* current_wr;
+ std::wstring wr_counter_str = IntToWString(wr_counter);
+ // Create space if it doesn't exist yet.
+ if (!web_resource_cache_->Get(wr_counter_str, &current_wr) ||
+ !current_wr->IsType(Value::TYPE_DICTIONARY)) {
+ current_wr = new DictionaryValue();
+ web_resource_cache_->Set(wr_counter_str, current_wr);
+ }
+ DictionaryValue* wr_cache_dict =
+ static_cast<DictionaryValue*>(current_wr);
+
+ // Update the resource cache.
+ wr_cache_dict->SetString(L"index", wr_counter_str);
+
+ if (wr_dict->GetString(kWebResourceSnippet, &result_snippet))
+ wr_cache_dict->SetString(kWebResourceSnippet, result_snippet);
+ if (wr_dict->GetString(kWebResourceSource, &result_source))
+ wr_cache_dict->SetString(kWebResourceSource, result_source);
+ if (wr_dict->GetString(kWebResourceURL, &result_url))
+ wr_cache_dict->SetString(kWebResourceURL, result_url);
+ if (wr_dict->GetString(kWebResourceTitle, &result_title))
+ wr_cache_dict->SetString(kWebResourceTitle, result_title);
+ if (wr_dict->GetString(kWebResourceThumb, &result_thumbnail))
+ wr_cache_dict->SetString(kWebResourceThumb, result_thumbnail);
+
+ wr_counter++;
+ wr_iter++;
+ }
+ EndFetch();
+}
+
+void WebResourceService::StartAfterDelay() {
+ int64 delay = kStartResourceFetchDelay;
+ // Check whether we have ever put a value in the web resource cache;
+ // if so, pull it out and see if it's time to update again.
+ if (prefs_->HasPrefPath(prefs::kNTPWebResourceCacheUpdate)) {
+ std::wstring last_update_pref =
+ prefs_->GetString(prefs::kNTPWebResourceCacheUpdate);
+ int64 ms_since_update =
+ (base::Time::Now() - base::Time::FromDoubleT(
+ StringToDouble(WideToASCII(last_update_pref)))).InMilliseconds();
+
+ delay = kStartResourceFetchDelay +
+ (ms_since_update > kCacheUpdateDelay ?
+ 0 : kCacheUpdateDelay - ms_since_update);
+ }
+
+ // Start fetch and wait for UpdateResourceCache.
+ DCHECK(delay >= kStartResourceFetchDelay &&
+ delay <= kCacheUpdateDelay);
+ web_resource_fetcher_->StartAfterDelay(static_cast<int>(delay));
+}
+
+void WebResourceService::UpdateResourceCache(const std::string& json_data) {
+ UnpackerClient* client = new UnpackerClient(this, json_data);
+ client->Start();
+
+ // Update resource server and cache update time in preferences.
+ prefs_->SetString(prefs::kNTPWebResourceCacheUpdate,
+ DoubleToWString(base::Time::Now().ToDoubleT()));
+ prefs_->SetString(prefs::kNTPWebResourceServer, web_resource_server_);
+}
+
diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h
new file mode 100644
index 0000000..7e50ee5
--- /dev/null
+++ b/chrome/browser/web_resource/web_resource_service.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_RESOURCE_WEB_RESOURCE_SERVICE_H_
+#define CHROME_BROWSER_WEB_RESOURCE_WEB_RESOURCE_SERVICE_H_
+
+#include <string>
+
+#include "chrome/browser/utility_process_host.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/web_resource/web_resource_unpacker.h"
+
+class Profile;
+
+class WebResourceService
+ : public UtilityProcessHost::Client {
+ public:
+ WebResourceService(Profile* profile,
+ MessageLoop* backend_loop);
+ ~WebResourceService();
+
+ // Sleep until cache needs to be updated, but always for at least 5 seconds
+ // so we don't interfere with startup. Then begin updating resources.
+ void StartAfterDelay();
+
+ // We have successfully pulled data from a resource server; now launch
+ // the process that will parse the JSON, and then update the cache.
+ void UpdateResourceCache(const std::string& json_data);
+
+ // Right now, these values correspond to data pulled from the popgadget
+ // JSON feed. Once we have decided on the final format for the
+ // web resources servers, these will probably change.
+ static const wchar_t* kWebResourceTitle;
+ static const wchar_t* kWebResourceThumb;
+ static const wchar_t* kWebResourceSource;
+ static const wchar_t* kWebResourceSnippet;
+ static const wchar_t* kWebResourceURL;
+
+ // Default server from which to gather resources.
+ // For now, hard-coded to test JSON data hosted on chromium.org.
+ // Starting 6/22, poptart server will be ready to host data.
+ // Future: more servers and different kinds of data will be served.
+ static const wchar_t* kDefaultResourceServer;
+
+ private:
+ class WebResourceFetcher;
+ friend class WebResourceFetcher;
+
+ class UnpackerClient;
+
+ void Init();
+
+ // Set in_fetch_ to false, clean up temp directories (in the future).
+ void EndFetch();
+
+ // Puts parsed json data in the right places, and writes to prefs file.
+ void OnWebResourceUnpacked(const ListValue& parsed_json);
+
+ // We need to be able to load parsed resource data into preferences file,
+ // and get proper install directory.
+ PrefService* prefs_;
+
+ FilePath web_resource_dir_;
+
+ // Server from which we are currently pulling web resource data.
+ std::wstring web_resource_server_;
+
+ // Whenever we update resource cache, schedule another task.
+ MessageLoop* backend_loop_;
+
+ WebResourceFetcher* web_resource_fetcher_;
+
+ ResourceDispatcherHost* resource_dispatcher_host_;
+
+ // Gets mutable dictionary attached to user's preferences, so that we
+ // can write resource data back to user's pref file.
+ DictionaryValue* web_resource_cache_;
+
+ // True if we are currently mid-fetch. If we are asked to start a fetch
+ // when we are still fetching resource data, schedule another one in
+ // kCacheUpdateDelay time, and silently exit.
+ bool in_fetch_;
+
+ // Maximum number of cached resources available.
+ static const int kMaxResourceCacheSize = 3;
+
+ // Delay on first fetch so we don't interfere with startup.
+ static const int kStartResourceFetchDelay = 5000;
+
+ // Delay between calls to update the cache (4 hours).
+ static const int kCacheUpdateDelay = 4 * 60 * 60 * 1000;
+
+ // Name of directory inside the profile where we will store resource-related
+ // data (for now, thumbnail images).
+ static const char* kResourceDirectoryName;
+
+ DISALLOW_COPY_AND_ASSIGN(WebResourceService);
+};
+
+#endif // CHROME_BROWSER_WEB_RESOURCE_WEB_RESOURCE_SERVICE_H_
+