Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / copresence / copresence_api.cc
blobedfd5095c1d703f3a1cb795cd7a9910740808d27
1 // Copyright 2014 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.
5 #include "chrome/browser/extensions/api/copresence/copresence_api.h"
7 #include "base/lazy_instance.h"
8 #include "base/memory/linked_ptr.h"
9 #include "base/prefs/pref_service.h"
10 #include "chrome/browser/copresence/chrome_whispernet_client.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/services/gcm/gcm_profile_service.h"
13 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
14 #include "chrome/common/channel_info.h"
15 #include "chrome/common/extensions/api/copresence.h"
16 #include "chrome/common/extensions/manifest_handlers/copresence_manifest.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/copresence/copresence_manager_impl.h"
19 #include "components/copresence/proto/data.pb.h"
20 #include "components/copresence/proto/enums.pb.h"
21 #include "components/copresence/proto/rpcs.pb.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "content/public/browser/browser_context.h"
24 #include "extensions/browser/event_router.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/manifest_constants.h"
29 using user_prefs::PrefRegistrySyncable;
31 namespace extensions {
33 namespace {
35 base::LazyInstance<BrowserContextKeyedAPIFactory<CopresenceService>>
36 g_factory = LAZY_INSTANCE_INITIALIZER;
38 const char kInvalidOperationsMessage[] =
39 "Invalid operation in operations array.";
40 const char kShuttingDownMessage[] = "Shutting down.";
42 const std::string GetPrefName(bool authenticated) {
43 return authenticated ? prefs::kCopresenceAuthenticatedDeviceId
44 : prefs::kCopresenceAnonymousDeviceId;
47 } // namespace
49 namespace Execute = api::copresence::Execute;
50 namespace OnMessagesReceived = api::copresence::OnMessagesReceived;
51 namespace OnStatusUpdated = api::copresence::OnStatusUpdated;
52 namespace SetApiKey = api::copresence::SetApiKey;
53 namespace SetAuthToken = api::copresence::SetAuthToken;
55 // Public functions.
57 CopresenceService::CopresenceService(content::BrowserContext* context)
58 : is_shutting_down_(false), browser_context_(context) {}
60 CopresenceService::~CopresenceService() {}
62 void CopresenceService::Shutdown() {
63 is_shutting_down_ = true;
64 manager_.reset();
65 whispernet_client_.reset();
68 copresence::CopresenceManager* CopresenceService::manager() {
69 if (!manager_ && !is_shutting_down_)
70 manager_.reset(new copresence::CopresenceManagerImpl(this));
71 return manager_.get();
74 const std::string CopresenceService::auth_token(const std::string& app_id)
75 const {
76 // This won't be const if we use map[]
77 const auto& key = auth_tokens_by_app_.find(app_id);
78 return key == auth_tokens_by_app_.end() ? std::string() : key->second;
81 void CopresenceService::set_api_key(const std::string& app_id,
82 const std::string& api_key) {
83 DCHECK(!app_id.empty());
84 api_keys_by_app_[app_id] = api_key;
87 void CopresenceService::set_auth_token(const std::string& app_id,
88 const std::string& token) {
89 DCHECK(!app_id.empty());
90 auth_tokens_by_app_[app_id] = token;
93 void CopresenceService::set_manager_for_testing(
94 scoped_ptr<copresence::CopresenceManager> manager) {
95 manager_ = manager.Pass();
98 void CopresenceService::ResetState() {
99 DVLOG(2) << "Deleting copresence state";
100 GetPrefService()->ClearPref(prefs::kCopresenceAuthenticatedDeviceId);
101 GetPrefService()->ClearPref(prefs::kCopresenceAnonymousDeviceId);
102 manager_ = nullptr;
105 // static
106 void CopresenceService::RegisterProfilePrefs(PrefRegistrySyncable* registry) {
107 registry->RegisterStringPref(prefs::kCopresenceAuthenticatedDeviceId,
108 std::string());
109 registry->RegisterStringPref(prefs::kCopresenceAnonymousDeviceId,
110 std::string());
113 // static
114 BrowserContextKeyedAPIFactory<CopresenceService>*
115 CopresenceService::GetFactoryInstance() {
116 return g_factory.Pointer();
120 // Private functions.
122 void CopresenceService::HandleMessages(
123 const std::string& /* app_id */,
124 const std::string& subscription_id,
125 const std::vector<copresence::Message>& messages) {
126 // TODO(ckehoe): Once the server starts sending back the app ids associated
127 // with subscriptions, use that instead of the apps_by_subs registry.
128 std::string app_id = apps_by_subscription_id_[subscription_id];
130 if (app_id.empty()) {
131 LOG(ERROR) << "Skipping message from unrecognized subscription "
132 << subscription_id;
133 return;
136 int message_count = messages.size();
137 std::vector<linked_ptr<api::copresence::Message>> api_messages(
138 message_count);
140 for (int m = 0; m < message_count; ++m) {
141 api_messages[m].reset(new api::copresence::Message);
142 api_messages[m]->type = messages[m].type().type();
143 api_messages[m]->payload.assign(messages[m].payload().begin(),
144 messages[m].payload().end());
145 DVLOG(2) << "Dispatching message of type " << api_messages[m]->type << ":\n"
146 << messages[m].payload();
149 // Send the messages to the client app.
150 scoped_ptr<Event> event(new Event(
151 events::COPRESENCE_ON_MESSAGES_RECEIVED, OnMessagesReceived::kEventName,
152 OnMessagesReceived::Create(subscription_id, api_messages),
153 browser_context_));
154 EventRouter::Get(browser_context_)
155 ->DispatchEventToExtension(app_id, event.Pass());
156 DVLOG(2) << "Passed " << api_messages.size() << " messages to app \""
157 << app_id << "\" for subscription \"" << subscription_id << "\"";
160 void CopresenceService::HandleStatusUpdate(
161 copresence::CopresenceStatus status) {
162 DCHECK_EQ(copresence::AUDIO_FAIL, status);
163 scoped_ptr<Event> event(new Event(
164 events::COPRESENCE_ON_STATUS_UPDATED, OnStatusUpdated::kEventName,
165 OnStatusUpdated::Create(api::copresence::STATUS_AUDIOFAILED),
166 browser_context_));
167 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
168 DVLOG(2) << "Sent Audio Failed status update.";
171 net::URLRequestContextGetter* CopresenceService::GetRequestContext() const {
172 return browser_context_->GetRequestContext();
175 const std::string CopresenceService::GetPlatformVersionString() const {
176 return chrome::GetVersionString();
179 const std::string
180 CopresenceService::GetAPIKey(const std::string& app_id) const {
181 // Check first if the app has set its key via the API.
182 const auto& key = api_keys_by_app_.find(app_id);
183 if (key != api_keys_by_app_.end())
184 return key->second;
186 // If no key was found, look in the manifest.
187 if (!app_id.empty()) {
188 const Extension* extension = ExtensionRegistry::Get(browser_context_)
189 ->GetExtensionById(app_id, ExtensionRegistry::ENABLED);
190 DCHECK(extension) << "Invalid extension ID";
191 CopresenceManifestData* manifest_data =
192 static_cast<CopresenceManifestData*>(
193 extension->GetManifestData(manifest_keys::kCopresence));
194 if (manifest_data)
195 return manifest_data->api_key;
198 return std::string();
201 audio_modem::WhispernetClient* CopresenceService::GetWhispernetClient() {
202 if (!whispernet_client_ && !is_shutting_down_)
203 whispernet_client_.reset(new ChromeWhispernetClient(browser_context_));
204 return whispernet_client_.get();
207 gcm::GCMDriver* CopresenceService::GetGCMDriver() {
208 gcm::GCMProfileService* gcm_service =
209 gcm::GCMProfileServiceFactory::GetForProfile(browser_context_);
210 return gcm_service ? gcm_service->driver() : nullptr;
213 const std::string CopresenceService::GetDeviceId(bool authenticated) {
214 std::string id = GetPrefService()->GetString(GetPrefName(authenticated));
215 DVLOG(3) << "Retrieved device ID \"" << id << "\", "
216 << "authenticated = " << authenticated;
217 return id;
220 void CopresenceService::SaveDeviceId(bool authenticated,
221 const std::string& device_id) {
222 DVLOG(3) << "Storing device ID \"" << device_id << "\", "
223 << "authenticated = " << authenticated;
224 if (device_id.empty())
225 GetPrefService()->ClearPref(GetPrefName(authenticated));
226 else
227 GetPrefService()->SetString(GetPrefName(authenticated), device_id);
230 PrefService* CopresenceService::GetPrefService() {
231 return Profile::FromBrowserContext(browser_context_)->GetPrefs();
234 template <>
235 void
236 BrowserContextKeyedAPIFactory<CopresenceService>::DeclareFactoryDependencies() {
237 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
240 // CopresenceExecuteFunction implementation.
241 ExtensionFunction::ResponseAction CopresenceExecuteFunction::Run() {
242 scoped_ptr<Execute::Params> params(Execute::Params::Create(*args_));
243 EXTENSION_FUNCTION_VALIDATE(params.get());
245 CopresenceService* service =
246 CopresenceService::GetFactoryInstance()->Get(browser_context());
248 // This can only happen if we're shutting down. In all other cases, if we
249 // don't have a manager, we'll create one.
250 if (!service->manager())
251 return RespondNow(Error(kShuttingDownMessage));
253 // Each execute will correspond to one ReportRequest protocol buffer.
254 copresence::ReportRequest request;
255 if (!PrepareReportRequestProto(params->operations,
256 extension_id(),
257 &service->apps_by_subscription_id(),
258 &request)) {
259 return RespondNow(Error(kInvalidOperationsMessage));
262 service->manager()->ExecuteReportRequest(
263 request,
264 extension_id(),
265 service->auth_token(extension_id()),
266 base::Bind(&CopresenceExecuteFunction::SendResult, this));
267 return RespondLater();
270 void CopresenceExecuteFunction::SendResult(
271 copresence::CopresenceStatus status) {
272 api::copresence::ExecuteStatus api_status =
273 (status == copresence::SUCCESS) ? api::copresence::EXECUTE_STATUS_SUCCESS
274 : api::copresence::EXECUTE_STATUS_FAILED;
275 Respond(ArgumentList(Execute::Results::Create(api_status)));
278 // CopresenceSetApiKeyFunction implementation.
279 ExtensionFunction::ResponseAction CopresenceSetApiKeyFunction::Run() {
280 scoped_ptr<SetApiKey::Params> params(SetApiKey::Params::Create(*args_));
281 EXTENSION_FUNCTION_VALIDATE(params.get());
283 LOG(WARNING) << "copresence.setApiKey() is deprecated. "
284 << "Put the key in the manifest at copresence.api_key instead.";
286 // The api key may be set to empty, to clear it.
287 CopresenceService::GetFactoryInstance()->Get(browser_context())
288 ->set_api_key(extension_id(), params->api_key);
289 return RespondNow(NoArguments());
292 // CopresenceSetAuthTokenFunction implementation
293 ExtensionFunction::ResponseAction CopresenceSetAuthTokenFunction::Run() {
294 scoped_ptr<SetAuthToken::Params> params(SetAuthToken::Params::Create(*args_));
295 EXTENSION_FUNCTION_VALIDATE(params.get());
297 // The token may be set to empty, to clear it.
298 CopresenceService::GetFactoryInstance()->Get(browser_context())
299 ->set_auth_token(extension_id(), params->token);
300 return RespondNow(NoArguments());
303 } // namespace extensions