16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file. 46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/extensions/api/copresence/copresence_api.h" 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/lazy_instance.h" 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/memory/linked_ptr.h" 96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/copresence/chrome_whispernet_client.h" 106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/common/chrome_version_info.h" 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/common/extensions/api/copresence.h" 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/copresence/proto/data.pb.h" 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/copresence/proto/enums.pb.h" 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/copresence/proto/rpcs.pb.h" 1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/copresence/public/copresence_manager.h" 166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/copresence/public/whispernet_client.h" 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "content/public/browser/browser_context.h" 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "extensions/browser/event_router.h" 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace extensions { 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace { 236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibase::LazyInstance<BrowserContextKeyedAPIFactory<CopresenceService>> 256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) g_factory = LAZY_INSTANCE_INITIALIZER; 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kInvalidOperationsMessage[] = 286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) "Invalid operation in operations array."; 296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kShuttingDownMessage[] = "Shutting down."; 306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// CopresenceService implementation: 346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CopresenceService::CopresenceService(content::BrowserContext* context) 366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : is_shutting_down_(false), browser_context_(context) {} 376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CopresenceService::~CopresenceService() {} 396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)copresence::CopresenceManager* CopresenceService::manager() { 4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!manager_ && !is_shutting_down_) 4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) manager_ = copresence::CopresenceManager::Create(this); 4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return manager_.get(); 446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)copresence::WhispernetClient* CopresenceService::whispernet_client() { 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!whispernet_client_ && !is_shutting_down_) 486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) whispernet_client_.reset(new ChromeWhispernetClient(browser_context_)); 496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return whispernet_client_.get(); 506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void CopresenceService::Shutdown() { 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) is_shutting_down_ = true; 5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) manager_.reset(); 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) whispernet_client_.reset(); 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void CopresenceService::set_manager_for_testing( 5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scoped_ptr<copresence::CopresenceManager> manager) { 6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) manager_ = manager.Pass(); 6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)BrowserContextKeyedAPIFactory<CopresenceService>* 656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CopresenceService::GetFactoryInstance() { 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return g_factory.Pointer(); 676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void CopresenceService::HandleMessages( 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::string& /* app_id */, 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::string& subscription_id, 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::vector<copresence::Message>& messages) { 736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // TODO(ckehoe): Once the server starts sending back the app ids associated 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // with subscriptions, use that instead of the apps_by_subs registry. 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::string app_id = apps_by_subscription_id_[subscription_id]; 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (app_id.empty()) { 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) LOG(ERROR) << "Skipping message from unrecognized subscription " 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) << subscription_id; 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return; 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int message_count = messages.size(); 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::vector<linked_ptr<api::copresence::Message>> api_messages( 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) message_count); 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (int m = 0; m < message_count; ++m) { 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api_messages[m].reset(new api::copresence::Message); 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api_messages[m]->type = messages[m].type().type(); 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api_messages[m]->payload = messages[m].payload(); 916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DVLOG(2) << "Dispatching message of type " << api_messages[m]->type << ":\n" 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) << api_messages[m]->payload; 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Send the messages to the client app. 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_ptr<Event> event( 976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) new Event(api::copresence::OnMessagesReceived::kEventName, 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api::copresence::OnMessagesReceived::Create(subscription_id, 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api_messages), 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) browser_context_)); 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EventRouter::Get(browser_context_) 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ->DispatchEventToExtension(app_id, event.Pass()); 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DVLOG(2) << "Passed " << api_messages.size() << " messages to app \"" 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) << app_id << "\" for subscription \"" << subscription_id << "\""; 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)net::URLRequestContextGetter* CopresenceService::GetRequestContext() const { 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return browser_context_->GetRequestContext(); 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const std::string CopresenceService::GetPlatformVersionString() const { 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return chrome::VersionInfo().CreateVersionString(); 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const std::string CopresenceService::GetAPIKey() const { 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return api_key_; 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)copresence::WhispernetClient* CopresenceService::GetWhispernetClient() { 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return whispernet_client(); 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)template <> 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)BrowserContextKeyedAPIFactory<CopresenceService>::DeclareFactoryDependencies() { 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// CopresenceExecuteFunction implementation: 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ExtensionFunction::ResponseAction CopresenceExecuteFunction::Run() { 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_ptr<api::copresence::Execute::Params> params( 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api::copresence::Execute::Params::Create(*args_)); 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(params.get()); 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) CopresenceService* service = 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) CopresenceService::GetFactoryInstance()->Get(browser_context()); 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // This can only happen if we're shutting down. In all other cases, if we 13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // don't have a manager, we'll create one. 14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!service->manager()) 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return RespondNow(Error(kShuttingDownMessage)); 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Each execute will correspond to one ReportRequest protocol buffer. 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) copresence::ReportRequest request; 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!PrepareReportRequestProto(params->operations, 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) extension_id(), 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &service->apps_by_subscription_id(), 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &request)) { 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return RespondNow(Error(kInvalidOperationsMessage)); 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) service->manager()->ExecuteReportRequest( 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) request, 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) extension_id(), 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::Bind(&CopresenceExecuteFunction::SendResult, this)); 1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return RespondLater(); 1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void CopresenceExecuteFunction::SendResult( 1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) copresence::CopresenceStatus status) { 1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api::copresence::ExecuteStatus api_status = 1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) (status == copresence::SUCCESS) ? api::copresence::EXECUTE_STATUS_SUCCESS 1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : api::copresence::EXECUTE_STATUS_FAILED; 1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) Respond(ArgumentList(api::copresence::Execute::Results::Create(api_status))); 1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// CopresenceSetApiKeyFunction implementation: 1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ExtensionFunction::ResponseAction CopresenceSetApiKeyFunction::Run() { 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_ptr<api::copresence::SetApiKey::Params> params( 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) api::copresence::SetApiKey::Params::Create(*args_)); 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXTENSION_FUNCTION_VALIDATE(params.get()); 1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // The api key may be set to empty, to clear it. 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) CopresenceService::GetFactoryInstance()->Get(browser_context()) 1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ->set_api_key(params->api_key); 1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return RespondNow(NoArguments()); 1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace extensions 180