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/fake_gcm_client.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/sequenced_task_runner.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/sys_byteorder.h" 13 #include "base/time/time.h" 14 #include "google_apis/gcm/base/encryptor.h" 15 #include "google_apis/gcm/engine/account_mapping.h" 16 #include "net/base/ip_endpoint.h" 17 18 namespace gcm { 19 20 FakeGCMClient::FakeGCMClient( 21 StartMode start_mode, 22 const scoped_refptr<base::SequencedTaskRunner>& ui_thread, 23 const scoped_refptr<base::SequencedTaskRunner>& io_thread) 24 : delegate_(NULL), 25 sequence_id_(0), 26 status_(UNINITIALIZED), 27 start_mode_(start_mode), 28 ui_thread_(ui_thread), 29 io_thread_(io_thread), 30 weak_ptr_factory_(this) { 31 } 32 33 FakeGCMClient::~FakeGCMClient() { 34 } 35 36 void FakeGCMClient::Initialize( 37 const ChromeBuildInfo& chrome_build_info, 38 const base::FilePath& store_path, 39 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 40 const scoped_refptr<net::URLRequestContextGetter>& 41 url_request_context_getter, 42 scoped_ptr<Encryptor> encryptor, 43 Delegate* delegate) { 44 delegate_ = delegate; 45 } 46 47 void FakeGCMClient::Start() { 48 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 49 DCHECK_NE(STARTED, status_); 50 51 if (start_mode_ == DELAY_START) 52 return; 53 DoLoading(); 54 } 55 56 void FakeGCMClient::DoLoading() { 57 status_ = STARTED; 58 base::MessageLoop::current()->PostTask( 59 FROM_HERE, 60 base::Bind(&FakeGCMClient::CheckinFinished, 61 weak_ptr_factory_.GetWeakPtr())); 62 } 63 64 void FakeGCMClient::Stop() { 65 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 66 status_ = STOPPED; 67 delegate_->OnDisconnected(); 68 } 69 70 void FakeGCMClient::CheckOut() { 71 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 72 status_ = CHECKED_OUT; 73 sequence_id_++; 74 } 75 76 void FakeGCMClient::Register(const std::string& app_id, 77 const std::vector<std::string>& sender_ids) { 78 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 79 80 std::string registration_id = GetRegistrationIdFromSenderIds(sender_ids); 81 base::MessageLoop::current()->PostTask( 82 FROM_HERE, 83 base::Bind(&FakeGCMClient::RegisterFinished, 84 weak_ptr_factory_.GetWeakPtr(), 85 app_id, 86 registration_id)); 87 } 88 89 void FakeGCMClient::Unregister(const std::string& app_id) { 90 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 91 92 base::MessageLoop::current()->PostTask( 93 FROM_HERE, 94 base::Bind(&FakeGCMClient::UnregisterFinished, 95 weak_ptr_factory_.GetWeakPtr(), 96 app_id)); 97 } 98 99 void FakeGCMClient::Send(const std::string& app_id, 100 const std::string& receiver_id, 101 const OutgoingMessage& message) { 102 DCHECK(io_thread_->RunsTasksOnCurrentThread()); 103 104 base::MessageLoop::current()->PostTask( 105 FROM_HERE, 106 base::Bind(&FakeGCMClient::SendFinished, 107 weak_ptr_factory_.GetWeakPtr(), 108 app_id, 109 message)); 110 } 111 112 void FakeGCMClient::SetRecording(bool recording) { 113 } 114 115 void FakeGCMClient::ClearActivityLogs() { 116 } 117 118 GCMClient::GCMStatistics FakeGCMClient::GetStatistics() const { 119 return GCMClient::GCMStatistics(); 120 } 121 122 void FakeGCMClient::SetAccountsForCheckin( 123 const std::map<std::string, std::string>& account_tokens) { 124 } 125 126 void FakeGCMClient::UpdateAccountMapping( 127 const AccountMapping& account_mapping) { 128 } 129 130 void FakeGCMClient::RemoveAccountMapping(const std::string& account_id) { 131 } 132 133 void FakeGCMClient::PerformDelayedLoading() { 134 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 135 136 io_thread_->PostTask( 137 FROM_HERE, 138 base::Bind(&FakeGCMClient::DoLoading, weak_ptr_factory_.GetWeakPtr())); 139 } 140 141 void FakeGCMClient::ReceiveMessage(const std::string& app_id, 142 const IncomingMessage& message) { 143 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 144 145 io_thread_->PostTask( 146 FROM_HERE, 147 base::Bind(&FakeGCMClient::MessageReceived, 148 weak_ptr_factory_.GetWeakPtr(), 149 app_id, 150 message)); 151 } 152 153 void FakeGCMClient::DeleteMessages(const std::string& app_id) { 154 DCHECK(ui_thread_->RunsTasksOnCurrentThread()); 155 156 io_thread_->PostTask( 157 FROM_HERE, 158 base::Bind(&FakeGCMClient::MessagesDeleted, 159 weak_ptr_factory_.GetWeakPtr(), 160 app_id)); 161 } 162 163 std::string FakeGCMClient::GetRegistrationIdFromSenderIds( 164 const std::vector<std::string>& sender_ids) const { 165 // GCMService normalizes the sender IDs by making them sorted. 166 std::vector<std::string> normalized_sender_ids = sender_ids; 167 std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end()); 168 169 // Simulate the registration_id by concaternating all sender IDs. 170 // Set registration_id to empty to denote an error if sender_ids contains a 171 // hint. 172 std::string registration_id; 173 if (sender_ids.size() != 1 || 174 sender_ids[0].find("error") == std::string::npos) { 175 for (size_t i = 0; i < normalized_sender_ids.size(); ++i) { 176 if (i > 0) 177 registration_id += ","; 178 registration_id += normalized_sender_ids[i]; 179 } 180 registration_id += base::IntToString(sequence_id_); 181 } 182 return registration_id; 183 } 184 185 void FakeGCMClient::CheckinFinished() { 186 delegate_->OnGCMReady(std::vector<AccountMapping>()); 187 delegate_->OnConnected(net::IPEndPoint()); 188 } 189 190 void FakeGCMClient::RegisterFinished(const std::string& app_id, 191 const std::string& registrion_id) { 192 delegate_->OnRegisterFinished( 193 app_id, registrion_id, registrion_id.empty() ? SERVER_ERROR : SUCCESS); 194 } 195 196 void FakeGCMClient::UnregisterFinished(const std::string& app_id) { 197 delegate_->OnUnregisterFinished(app_id, GCMClient::SUCCESS); 198 } 199 200 void FakeGCMClient::SendFinished(const std::string& app_id, 201 const OutgoingMessage& message) { 202 delegate_->OnSendFinished(app_id, message.id, SUCCESS); 203 204 // Simulate send error if message id contains a hint. 205 if (message.id.find("error") != std::string::npos) { 206 SendErrorDetails send_error_details; 207 send_error_details.message_id = message.id; 208 send_error_details.result = NETWORK_ERROR; 209 send_error_details.additional_data = message.data; 210 base::MessageLoop::current()->PostDelayedTask( 211 FROM_HERE, 212 base::Bind(&FakeGCMClient::MessageSendError, 213 weak_ptr_factory_.GetWeakPtr(), 214 app_id, 215 send_error_details), 216 base::TimeDelta::FromMilliseconds(200)); 217 } else if(message.id.find("ack") != std::string::npos) { 218 base::MessageLoop::current()->PostDelayedTask( 219 FROM_HERE, 220 base::Bind(&FakeGCMClient::SendAcknowledgement, 221 weak_ptr_factory_.GetWeakPtr(), 222 app_id, 223 message.id), 224 base::TimeDelta::FromMilliseconds(200)); 225 226 } 227 } 228 229 void FakeGCMClient::MessageReceived(const std::string& app_id, 230 const IncomingMessage& message) { 231 if (delegate_) 232 delegate_->OnMessageReceived(app_id, message); 233 } 234 235 void FakeGCMClient::MessagesDeleted(const std::string& app_id) { 236 if (delegate_) 237 delegate_->OnMessagesDeleted(app_id); 238 } 239 240 void FakeGCMClient::MessageSendError( 241 const std::string& app_id, 242 const GCMClient::SendErrorDetails& send_error_details) { 243 if (delegate_) 244 delegate_->OnMessageSendError(app_id, send_error_details); 245 } 246 247 void FakeGCMClient::SendAcknowledgement(const std::string& app_id, 248 const std::string& message_id) { 249 if (delegate_) 250 delegate_->OnSendAcknowledged(app_id, message_id); 251 } 252 253 } // namespace gcm 254