// 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/fake_gcm_client.h" #include "base/bind.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/sequenced_task_runner.h" #include "base/sys_byteorder.h" #include "base/time/time.h" #include "google_apis/gcm/base/encryptor.h" #include "net/base/ip_endpoint.h" namespace gcm { FakeGCMClient::FakeGCMClient( StartMode start_mode, const scoped_refptr<base::SequencedTaskRunner>& ui_thread, const scoped_refptr<base::SequencedTaskRunner>& io_thread) : delegate_(NULL), status_(UNINITIALIZED), start_mode_(start_mode), ui_thread_(ui_thread), io_thread_(io_thread), weak_ptr_factory_(this) { } FakeGCMClient::~FakeGCMClient() { } void FakeGCMClient::Initialize( const ChromeBuildInfo& chrome_build_info, const base::FilePath& store_path, const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, scoped_ptr<Encryptor> encryptor, Delegate* delegate) { delegate_ = delegate; } void FakeGCMClient::Start() { DCHECK(io_thread_->RunsTasksOnCurrentThread()); DCHECK_NE(STARTED, status_); if (start_mode_ == DELAY_START) return; DoLoading(); } void FakeGCMClient::DoLoading() { status_ = STARTED; base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::CheckinFinished, weak_ptr_factory_.GetWeakPtr())); } void FakeGCMClient::Stop() { DCHECK(io_thread_->RunsTasksOnCurrentThread()); status_ = STOPPED; delegate_->OnDisconnected(); } void FakeGCMClient::CheckOut() { DCHECK(io_thread_->RunsTasksOnCurrentThread()); status_ = CHECKED_OUT; } void FakeGCMClient::Register(const std::string& app_id, const std::vector<std::string>& sender_ids) { DCHECK(io_thread_->RunsTasksOnCurrentThread()); std::string registration_id = GetRegistrationIdFromSenderIds(sender_ids); base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::RegisterFinished, weak_ptr_factory_.GetWeakPtr(), app_id, registration_id)); } void FakeGCMClient::Unregister(const std::string& app_id) { DCHECK(io_thread_->RunsTasksOnCurrentThread()); base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::UnregisterFinished, weak_ptr_factory_.GetWeakPtr(), app_id)); } void FakeGCMClient::Send(const std::string& app_id, const std::string& receiver_id, const OutgoingMessage& message) { DCHECK(io_thread_->RunsTasksOnCurrentThread()); base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::SendFinished, weak_ptr_factory_.GetWeakPtr(), app_id, message)); } void FakeGCMClient::SetRecording(bool recording) { } void FakeGCMClient::ClearActivityLogs() { } GCMClient::GCMStatistics FakeGCMClient::GetStatistics() const { return GCMClient::GCMStatistics(); } void FakeGCMClient::PerformDelayedLoading() { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); io_thread_->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::DoLoading, weak_ptr_factory_.GetWeakPtr())); } void FakeGCMClient::ReceiveMessage(const std::string& app_id, const IncomingMessage& message) { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); io_thread_->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::MessageReceived, weak_ptr_factory_.GetWeakPtr(), app_id, message)); } void FakeGCMClient::DeleteMessages(const std::string& app_id) { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); io_thread_->PostTask( FROM_HERE, base::Bind(&FakeGCMClient::MessagesDeleted, weak_ptr_factory_.GetWeakPtr(), app_id)); } // static std::string FakeGCMClient::GetRegistrationIdFromSenderIds( const std::vector<std::string>& sender_ids) { // GCMService normalizes 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()); // Simulate the registration_id by concaternating all sender IDs. // Set registration_id to empty to denote an error if sender_ids contains a // hint. std::string registration_id; if (sender_ids.size() != 1 || sender_ids[0].find("error") == std::string::npos) { for (size_t i = 0; i < normalized_sender_ids.size(); ++i) { if (i > 0) registration_id += ","; registration_id += normalized_sender_ids[i]; } } return registration_id; } void FakeGCMClient::CheckinFinished() { delegate_->OnGCMReady(); delegate_->OnConnected(net::IPEndPoint()); } void FakeGCMClient::RegisterFinished(const std::string& app_id, const std::string& registrion_id) { delegate_->OnRegisterFinished( app_id, registrion_id, registrion_id.empty() ? SERVER_ERROR : SUCCESS); } void FakeGCMClient::UnregisterFinished(const std::string& app_id) { delegate_->OnUnregisterFinished(app_id, GCMClient::SUCCESS); } void FakeGCMClient::SendFinished(const std::string& app_id, const OutgoingMessage& message) { delegate_->OnSendFinished(app_id, message.id, SUCCESS); // Simulate send error if message id contains a hint. if (message.id.find("error") != std::string::npos) { SendErrorDetails send_error_details; send_error_details.message_id = message.id; send_error_details.result = NETWORK_ERROR; send_error_details.additional_data = message.data; base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&FakeGCMClient::MessageSendError, weak_ptr_factory_.GetWeakPtr(), app_id, send_error_details), base::TimeDelta::FromMilliseconds(200)); } } void FakeGCMClient::MessageReceived(const std::string& app_id, const IncomingMessage& message) { if (delegate_) delegate_->OnMessageReceived(app_id, message); } void FakeGCMClient::MessagesDeleted(const std::string& app_id) { if (delegate_) delegate_->OnMessagesDeleted(app_id); } void FakeGCMClient::MessageSendError( const std::string& app_id, const GCMClient::SendErrorDetails& send_error_details) { if (delegate_) delegate_->OnMessageSendError(app_id, send_error_details); } } // namespace gcm