// 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