| // Copyright 2014 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 "components/gcm_driver/gcm_driver.h" |
| |
| #include <algorithm> |
| |
| #include "base/logging.h" |
| #include "components/gcm_driver/gcm_app_handler.h" |
| |
| namespace gcm { |
| |
| GCMDriver::GCMDriver() { |
| } |
| |
| GCMDriver::~GCMDriver() { |
| } |
| |
| void GCMDriver::Register(const std::string& app_id, |
| const std::vector<std::string>& sender_ids, |
| const RegisterCallback& callback) { |
| DCHECK(!app_id.empty()); |
| DCHECK(!sender_ids.empty()); |
| DCHECK(!callback.is_null()); |
| |
| GCMClient::Result result = EnsureStarted(); |
| if (result != GCMClient::SUCCESS) { |
| callback.Run(std::string(), result); |
| return; |
| } |
| |
| // If previous un/register operation is still in progress, bail out. |
| if (IsAsyncOperationPending(app_id)) { |
| callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); |
| return; |
| } |
| |
| // Normalize the sender IDs by making them sorted. |
| std::vector<std::string> normalized_sender_ids = sender_ids; |
| std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); |
| |
| register_callbacks_[app_id] = callback; |
| |
| RegisterImpl(app_id, normalized_sender_ids); |
| } |
| |
| void GCMDriver::Unregister(const std::string& app_id, |
| const UnregisterCallback& callback) { |
| DCHECK(!app_id.empty()); |
| DCHECK(!callback.is_null()); |
| |
| GCMClient::Result result = EnsureStarted(); |
| if (result != GCMClient::SUCCESS) { |
| callback.Run(result); |
| return; |
| } |
| |
| // If previous un/register operation is still in progress, bail out. |
| if (IsAsyncOperationPending(app_id)) { |
| callback.Run(GCMClient::ASYNC_OPERATION_PENDING); |
| return; |
| } |
| |
| unregister_callbacks_[app_id] = callback; |
| |
| UnregisterImpl(app_id); |
| } |
| |
| void GCMDriver::Send(const std::string& app_id, |
| const std::string& receiver_id, |
| const GCMClient::OutgoingMessage& message, |
| const SendCallback& callback) { |
| DCHECK(!app_id.empty()); |
| DCHECK(!receiver_id.empty()); |
| DCHECK(!callback.is_null()); |
| |
| GCMClient::Result result = EnsureStarted(); |
| if (result != GCMClient::SUCCESS) { |
| callback.Run(std::string(), result); |
| return; |
| } |
| |
| // If the message with send ID is still in progress, bail out. |
| std::pair<std::string, std::string> key(app_id, message.id); |
| if (send_callbacks_.find(key) != send_callbacks_.end()) { |
| callback.Run(message.id, GCMClient::INVALID_PARAMETER); |
| return; |
| } |
| |
| send_callbacks_[key] = callback; |
| |
| SendImpl(app_id, receiver_id, message); |
| } |
| |
| void GCMDriver::RegisterFinished(const std::string& app_id, |
| const std::string& registration_id, |
| GCMClient::Result result) { |
| std::map<std::string, RegisterCallback>::iterator callback_iter = |
| register_callbacks_.find(app_id); |
| if (callback_iter == register_callbacks_.end()) { |
| // The callback could have been removed when the app is uninstalled. |
| return; |
| } |
| |
| RegisterCallback callback = callback_iter->second; |
| register_callbacks_.erase(callback_iter); |
| callback.Run(registration_id, result); |
| } |
| |
| void GCMDriver::UnregisterFinished(const std::string& app_id, |
| GCMClient::Result result) { |
| std::map<std::string, UnregisterCallback>::iterator callback_iter = |
| unregister_callbacks_.find(app_id); |
| if (callback_iter == unregister_callbacks_.end()) |
| return; |
| |
| UnregisterCallback callback = callback_iter->second; |
| unregister_callbacks_.erase(callback_iter); |
| callback.Run(result); |
| } |
| |
| void GCMDriver::SendFinished(const std::string& app_id, |
| const std::string& message_id, |
| GCMClient::Result result) { |
| std::map<std::pair<std::string, std::string>, SendCallback>::iterator |
| callback_iter = send_callbacks_.find( |
| std::pair<std::string, std::string>(app_id, message_id)); |
| if (callback_iter == send_callbacks_.end()) { |
| // The callback could have been removed when the app is uninstalled. |
| return; |
| } |
| |
| SendCallback callback = callback_iter->second; |
| send_callbacks_.erase(callback_iter); |
| callback.Run(message_id, result); |
| } |
| |
| void GCMDriver::Shutdown() { |
| for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin(); |
| iter != app_handlers_.end(); ++iter) { |
| iter->second->ShutdownHandler(); |
| } |
| app_handlers_.clear(); |
| } |
| |
| void GCMDriver::AddAppHandler(const std::string& app_id, |
| GCMAppHandler* handler) { |
| DCHECK(!app_id.empty()); |
| DCHECK(handler); |
| DCHECK_EQ(app_handlers_.count(app_id), 0u); |
| app_handlers_[app_id] = handler; |
| } |
| |
| void GCMDriver::RemoveAppHandler(const std::string& app_id) { |
| DCHECK(!app_id.empty()); |
| app_handlers_.erase(app_id); |
| } |
| |
| GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) { |
| // Look for exact match. |
| GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id); |
| if (iter != app_handlers_.end()) |
| return iter->second; |
| |
| // Ask the handlers whether they know how to handle it. |
| for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) { |
| if (iter->second->CanHandle(app_id)) |
| return iter->second; |
| } |
| |
| return &default_app_handler_; |
| } |
| |
| bool GCMDriver::HasRegisterCallback(const std::string& app_id) { |
| return register_callbacks_.find(app_id) != register_callbacks_.end(); |
| } |
| |
| void GCMDriver::ClearCallbacks() { |
| register_callbacks_.clear(); |
| unregister_callbacks_.clear(); |
| send_callbacks_.clear(); |
| } |
| |
| bool GCMDriver::IsAsyncOperationPending(const std::string& app_id) const { |
| return register_callbacks_.find(app_id) != register_callbacks_.end() || |
| unregister_callbacks_.find(app_id) != unregister_callbacks_.end(); |
| } |
| |
| } // namespace gcm |