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 "components/gcm_driver/gcm_driver.h" 6 7#include <algorithm> 8 9#include "base/logging.h" 10#include "components/gcm_driver/gcm_app_handler.h" 11 12namespace gcm { 13 14GCMDriver::GCMDriver() { 15} 16 17GCMDriver::~GCMDriver() { 18} 19 20void GCMDriver::Register(const std::string& app_id, 21 const std::vector<std::string>& sender_ids, 22 const RegisterCallback& callback) { 23 DCHECK(!app_id.empty()); 24 DCHECK(!sender_ids.empty()); 25 DCHECK(!callback.is_null()); 26 27 GCMClient::Result result = EnsureStarted(); 28 if (result != GCMClient::SUCCESS) { 29 callback.Run(std::string(), result); 30 return; 31 } 32 33 // If previous un/register operation is still in progress, bail out. 34 if (IsAsyncOperationPending(app_id)) { 35 callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING); 36 return; 37 } 38 39 // Normalize the sender IDs by making them sorted. 40 std::vector<std::string> normalized_sender_ids = sender_ids; 41 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); 42 43 register_callbacks_[app_id] = callback; 44 45 RegisterImpl(app_id, normalized_sender_ids); 46} 47 48void GCMDriver::Unregister(const std::string& app_id, 49 const UnregisterCallback& callback) { 50 DCHECK(!app_id.empty()); 51 DCHECK(!callback.is_null()); 52 53 GCMClient::Result result = EnsureStarted(); 54 if (result != GCMClient::SUCCESS) { 55 callback.Run(result); 56 return; 57 } 58 59 // If previous un/register operation is still in progress, bail out. 60 if (IsAsyncOperationPending(app_id)) { 61 callback.Run(GCMClient::ASYNC_OPERATION_PENDING); 62 return; 63 } 64 65 unregister_callbacks_[app_id] = callback; 66 67 UnregisterImpl(app_id); 68} 69 70void GCMDriver::Send(const std::string& app_id, 71 const std::string& receiver_id, 72 const GCMClient::OutgoingMessage& message, 73 const SendCallback& callback) { 74 DCHECK(!app_id.empty()); 75 DCHECK(!receiver_id.empty()); 76 DCHECK(!callback.is_null()); 77 78 GCMClient::Result result = EnsureStarted(); 79 if (result != GCMClient::SUCCESS) { 80 callback.Run(std::string(), result); 81 return; 82 } 83 84 // If the message with send ID is still in progress, bail out. 85 std::pair<std::string, std::string> key(app_id, message.id); 86 if (send_callbacks_.find(key) != send_callbacks_.end()) { 87 callback.Run(message.id, GCMClient::INVALID_PARAMETER); 88 return; 89 } 90 91 send_callbacks_[key] = callback; 92 93 SendImpl(app_id, receiver_id, message); 94} 95 96void GCMDriver::RegisterFinished(const std::string& app_id, 97 const std::string& registration_id, 98 GCMClient::Result result) { 99 std::map<std::string, RegisterCallback>::iterator callback_iter = 100 register_callbacks_.find(app_id); 101 if (callback_iter == register_callbacks_.end()) { 102 // The callback could have been removed when the app is uninstalled. 103 return; 104 } 105 106 RegisterCallback callback = callback_iter->second; 107 register_callbacks_.erase(callback_iter); 108 callback.Run(registration_id, result); 109} 110 111void GCMDriver::UnregisterFinished(const std::string& app_id, 112 GCMClient::Result result) { 113 std::map<std::string, UnregisterCallback>::iterator callback_iter = 114 unregister_callbacks_.find(app_id); 115 if (callback_iter == unregister_callbacks_.end()) 116 return; 117 118 UnregisterCallback callback = callback_iter->second; 119 unregister_callbacks_.erase(callback_iter); 120 callback.Run(result); 121} 122 123void GCMDriver::SendFinished(const std::string& app_id, 124 const std::string& message_id, 125 GCMClient::Result result) { 126 std::map<std::pair<std::string, std::string>, SendCallback>::iterator 127 callback_iter = send_callbacks_.find( 128 std::pair<std::string, std::string>(app_id, message_id)); 129 if (callback_iter == send_callbacks_.end()) { 130 // The callback could have been removed when the app is uninstalled. 131 return; 132 } 133 134 SendCallback callback = callback_iter->second; 135 send_callbacks_.erase(callback_iter); 136 callback.Run(message_id, result); 137} 138 139void GCMDriver::Shutdown() { 140 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin(); 141 iter != app_handlers_.end(); ++iter) { 142 iter->second->ShutdownHandler(); 143 } 144 app_handlers_.clear(); 145} 146 147void GCMDriver::AddAppHandler(const std::string& app_id, 148 GCMAppHandler* handler) { 149 DCHECK(!app_id.empty()); 150 DCHECK(handler); 151 DCHECK_EQ(app_handlers_.count(app_id), 0u); 152 app_handlers_[app_id] = handler; 153} 154 155void GCMDriver::RemoveAppHandler(const std::string& app_id) { 156 DCHECK(!app_id.empty()); 157 app_handlers_.erase(app_id); 158} 159 160GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) { 161 // Look for exact match. 162 GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id); 163 if (iter != app_handlers_.end()) 164 return iter->second; 165 166 // Ask the handlers whether they know how to handle it. 167 for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) { 168 if (iter->second->CanHandle(app_id)) 169 return iter->second; 170 } 171 172 return &default_app_handler_; 173} 174 175bool GCMDriver::HasRegisterCallback(const std::string& app_id) { 176 return register_callbacks_.find(app_id) != register_callbacks_.end(); 177} 178 179void GCMDriver::ClearCallbacks() { 180 register_callbacks_.clear(); 181 unregister_callbacks_.clear(); 182 send_callbacks_.clear(); 183} 184 185bool GCMDriver::IsAsyncOperationPending(const std::string& app_id) const { 186 return register_callbacks_.find(app_id) != register_callbacks_.end() || 187 unregister_callbacks_.find(app_id) != unregister_callbacks_.end(); 188} 189 190} // namespace gcm 191