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