Home | History | Annotate | Download | only in copresence
      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.
      4 
      5 #include "chrome/browser/extensions/api/copresence/copresence_api.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "base/memory/linked_ptr.h"
      9 #include "chrome/browser/copresence/chrome_whispernet_client.h"
     10 #include "chrome/common/chrome_version_info.h"
     11 #include "chrome/common/extensions/api/copresence.h"
     12 #include "components/copresence/proto/data.pb.h"
     13 #include "components/copresence/proto/enums.pb.h"
     14 #include "components/copresence/proto/rpcs.pb.h"
     15 #include "components/copresence/public/copresence_manager.h"
     16 #include "components/copresence/public/whispernet_client.h"
     17 #include "content/public/browser/browser_context.h"
     18 #include "extensions/browser/event_router.h"
     19 
     20 namespace extensions {
     21 
     22 namespace {
     23 
     24 base::LazyInstance<BrowserContextKeyedAPIFactory<CopresenceService>>
     25     g_factory = LAZY_INSTANCE_INITIALIZER;
     26 
     27 const char kInvalidOperationsMessage[] =
     28     "Invalid operation in operations array.";
     29 const char kShuttingDownMessage[] = "Shutting down.";
     30 
     31 }  // namespace
     32 
     33 // CopresenceService implementation:
     34 
     35 CopresenceService::CopresenceService(content::BrowserContext* context)
     36     : is_shutting_down_(false), browser_context_(context) {}
     37 
     38 CopresenceService::~CopresenceService() {}
     39 
     40 copresence::CopresenceManager* CopresenceService::manager() {
     41   if (!manager_ && !is_shutting_down_)
     42     manager_ = copresence::CopresenceManager::Create(this);
     43   return manager_.get();
     44 }
     45 
     46 copresence::WhispernetClient* CopresenceService::whispernet_client() {
     47   if (!whispernet_client_ && !is_shutting_down_)
     48     whispernet_client_.reset(new ChromeWhispernetClient(browser_context_));
     49   return whispernet_client_.get();
     50 }
     51 
     52 void CopresenceService::Shutdown() {
     53   is_shutting_down_ = true;
     54   manager_.reset();
     55   whispernet_client_.reset();
     56 }
     57 
     58 void CopresenceService::set_manager_for_testing(
     59     scoped_ptr<copresence::CopresenceManager> manager) {
     60   manager_ = manager.Pass();
     61 }
     62 
     63 // static
     64 BrowserContextKeyedAPIFactory<CopresenceService>*
     65 CopresenceService::GetFactoryInstance() {
     66   return g_factory.Pointer();
     67 }
     68 
     69 void CopresenceService::HandleMessages(
     70     const std::string& /* app_id */,
     71     const std::string& subscription_id,
     72     const std::vector<copresence::Message>& messages) {
     73   // TODO(ckehoe): Once the server starts sending back the app ids associated
     74   // with subscriptions, use that instead of the apps_by_subs registry.
     75   std::string app_id = apps_by_subscription_id_[subscription_id];
     76 
     77   if (app_id.empty()) {
     78     LOG(ERROR) << "Skipping message from unrecognized subscription "
     79                << subscription_id;
     80     return;
     81   }
     82 
     83   int message_count = messages.size();
     84   std::vector<linked_ptr<api::copresence::Message>> api_messages(
     85       message_count);
     86 
     87   for (int m = 0; m < message_count; ++m) {
     88     api_messages[m].reset(new api::copresence::Message);
     89     api_messages[m]->type = messages[m].type().type();
     90     api_messages[m]->payload = messages[m].payload();
     91     DVLOG(2) << "Dispatching message of type " << api_messages[m]->type << ":\n"
     92              << api_messages[m]->payload;
     93   }
     94 
     95   // Send the messages to the client app.
     96   scoped_ptr<Event> event(
     97       new Event(api::copresence::OnMessagesReceived::kEventName,
     98                 api::copresence::OnMessagesReceived::Create(subscription_id,
     99                                                             api_messages),
    100                 browser_context_));
    101   EventRouter::Get(browser_context_)
    102       ->DispatchEventToExtension(app_id, event.Pass());
    103   DVLOG(2) << "Passed " << api_messages.size() << " messages to app \""
    104            << app_id << "\" for subscription \"" << subscription_id << "\"";
    105 }
    106 
    107 net::URLRequestContextGetter* CopresenceService::GetRequestContext() const {
    108   return browser_context_->GetRequestContext();
    109 }
    110 
    111 const std::string CopresenceService::GetPlatformVersionString() const {
    112   return chrome::VersionInfo().CreateVersionString();
    113 }
    114 
    115 const std::string CopresenceService::GetAPIKey() const {
    116   return api_key_;
    117 }
    118 
    119 copresence::WhispernetClient* CopresenceService::GetWhispernetClient() {
    120   return whispernet_client();
    121 }
    122 
    123 template <>
    124 void
    125 BrowserContextKeyedAPIFactory<CopresenceService>::DeclareFactoryDependencies() {
    126   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
    127 }
    128 
    129 // CopresenceExecuteFunction implementation:
    130 ExtensionFunction::ResponseAction CopresenceExecuteFunction::Run() {
    131   scoped_ptr<api::copresence::Execute::Params> params(
    132       api::copresence::Execute::Params::Create(*args_));
    133   EXTENSION_FUNCTION_VALIDATE(params.get());
    134 
    135   CopresenceService* service =
    136       CopresenceService::GetFactoryInstance()->Get(browser_context());
    137 
    138   // This can only happen if we're shutting down. In all other cases, if we
    139   // don't have a manager, we'll create one.
    140   if (!service->manager())
    141     return RespondNow(Error(kShuttingDownMessage));
    142 
    143   // Each execute will correspond to one ReportRequest protocol buffer.
    144   copresence::ReportRequest request;
    145   if (!PrepareReportRequestProto(params->operations,
    146                                  extension_id(),
    147                                  &service->apps_by_subscription_id(),
    148                                  &request)) {
    149     return RespondNow(Error(kInvalidOperationsMessage));
    150   }
    151 
    152   service->manager()->ExecuteReportRequest(
    153       request,
    154       extension_id(),
    155       base::Bind(&CopresenceExecuteFunction::SendResult, this));
    156   return RespondLater();
    157 }
    158 
    159 void CopresenceExecuteFunction::SendResult(
    160     copresence::CopresenceStatus status) {
    161   api::copresence::ExecuteStatus api_status =
    162       (status == copresence::SUCCESS) ? api::copresence::EXECUTE_STATUS_SUCCESS
    163                                       : api::copresence::EXECUTE_STATUS_FAILED;
    164   Respond(ArgumentList(api::copresence::Execute::Results::Create(api_status)));
    165 }
    166 
    167 // CopresenceSetApiKeyFunction implementation:
    168 ExtensionFunction::ResponseAction CopresenceSetApiKeyFunction::Run() {
    169   scoped_ptr<api::copresence::SetApiKey::Params> params(
    170       api::copresence::SetApiKey::Params::Create(*args_));
    171   EXTENSION_FUNCTION_VALIDATE(params.get());
    172 
    173   // The api key may be set to empty, to clear it.
    174   CopresenceService::GetFactoryInstance()->Get(browser_context())
    175       ->set_api_key(params->api_key);
    176   return RespondNow(NoArguments());
    177 }
    178 
    179 }  // namespace extensions
    180