blob: a3f0e69f68147338432eed6367e8f85ed7c5c884 [file] [log] [blame]
Yuwei Huang5a84f9532019-02-20 18:29:011// Copyright 2019 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
Yuwei Huang2687b47f2019-04-01 20:57:085#include "remoting/test/ftl_services_playground.h"
Yuwei Huangbdc4a972019-03-01 17:43:066
Yuwei Huang30bac9e2019-03-01 21:28:147#include <inttypes.h>
Yuwei Huangaae881f2019-03-01 23:10:278#include <string>
Yuwei Huangbdc4a972019-03-01 17:43:069#include <utility>
Yuwei Huang98655b92019-03-04 23:41:4110#include <vector>
Yuwei Huangbdc4a972019-03-01 17:43:0611
Yuwei Huangaae881f2019-03-01 23:10:2712#include "base/base64.h"
Yuwei Huang575c32ee2019-02-27 04:41:5613#include "base/bind.h"
Yuwei Huangbdc4a972019-03-01 17:43:0614#include "base/bind_helpers.h"
Yuwei Huang5a84f9532019-02-20 18:29:0115#include "base/command_line.h"
Yuwei Huangbdc4a972019-03-01 17:43:0616#include "base/files/file_path.h"
Yuwei Huangaae881f2019-03-01 23:10:2717#include "base/guid.h"
Yuwei Huang5a84f9532019-02-20 18:29:0118#include "base/logging.h"
Yuwei Huangbdc4a972019-03-01 17:43:0619#include "base/path_service.h"
Yuwei Huang22e0b562019-03-27 20:54:2920#include "base/run_loop.h"
Yuwei Huangb8e1f2d2019-03-22 19:40:2621#include "base/task/post_task.h"
Yuwei Huangbdc4a972019-03-01 17:43:0622#include "remoting/base/oauth_token_getter_impl.h"
Yuwei Huangfeddf232020-07-28 00:27:4923#include "remoting/base/protobuf_http_status.h"
24#include "remoting/base/url_request_context_getter.h"
Yuwei Huang76ce10d2020-07-30 19:59:3225#include "remoting/proto/ftl/v1/ftl_messages.pb.h"
Yuwei Huang41ddec52019-04-02 02:08:1926#include "remoting/test/cli_util.h"
Yuwei Huang1cf68062019-04-11 23:28:4227#include "remoting/test/test_device_id_provider.h"
Yuwei Huang41ddec52019-04-02 02:08:1928#include "remoting/test/test_oauth_token_getter.h"
Yuwei Huang946cebd42019-03-04 22:14:2029#include "remoting/test/test_token_storage.h"
Yuwei Huangfeddf232020-07-28 00:27:4930#include "services/network/public/cpp/shared_url_loader_factory.h"
31#include "services/network/transitional_url_loader_factory_owner.h"
Yuwei Huangbdc4a972019-03-01 17:43:0632
33namespace {
34
35constexpr char kSwitchNameHelp[] = "help";
Yuwei Huang946cebd42019-03-04 22:14:2036constexpr char kSwitchNameUsername[] = "username";
37constexpr char kSwitchNameStoragePath[] = "storage-path";
Yuwei Huangfce958772019-03-30 00:18:1138constexpr char kSwitchNameNoAutoSignin[] = "no-auto-signin";
Yuwei Huangbdc4a972019-03-01 17:43:0639
Yuwei Huangfce958772019-03-30 00:18:1140bool NeedsManualSignin() {
41 return base::CommandLine::ForCurrentProcess()->HasSwitch(
42 kSwitchNameNoAutoSignin);
Yuwei Huangb8e1f2d2019-03-22 19:40:2643}
44
Yuwei Huangbdc4a972019-03-01 17:43:0645} // namespace
Yuwei Huang5a84f9532019-02-20 18:29:0146
Yuwei Huang575c32ee2019-02-27 04:41:5647namespace remoting {
Yuwei Huang5a84f9532019-02-20 18:29:0148
Jeremy Roman7c5cfabd2019-08-12 15:45:2749FtlServicesPlayground::FtlServicesPlayground() {}
Yuwei Huang575c32ee2019-02-27 04:41:5650
Yuwei Huang2687b47f2019-04-01 20:57:0851FtlServicesPlayground::~FtlServicesPlayground() = default;
Yuwei Huang575c32ee2019-02-27 04:41:5652
Yuwei Huang2687b47f2019-04-01 20:57:0853bool FtlServicesPlayground::ShouldPrintHelp() {
Yuwei Huangbdc4a972019-03-01 17:43:0654 return base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchNameHelp);
55}
56
Yuwei Huang2687b47f2019-04-01 20:57:0857void FtlServicesPlayground::PrintHelp() {
Yuwei Huang946cebd42019-03-04 22:14:2058 printf(
Yuwei Huang41ddec52019-04-02 02:08:1959 "Usage: %s [--no-auto-signin] [--auth-code=<auth-code>] "
Yuwei Huangfce958772019-03-30 00:18:1160 "[--storage-path=<storage-path>] [--username=<[email protected]>]\n",
Yuwei Huang946cebd42019-03-04 22:14:2061 base::CommandLine::ForCurrentProcess()
62 ->GetProgram()
63 .MaybeAsASCII()
64 .c_str());
Yuwei Huangbdc4a972019-03-01 17:43:0665}
66
Yuwei Huang2687b47f2019-04-01 20:57:0867void FtlServicesPlayground::StartAndAuthenticate() {
Yuwei Huang946cebd42019-03-04 22:14:2068 DCHECK(!storage_);
Yuwei Huangbdc4a972019-03-01 17:43:0669 DCHECK(!token_getter_);
Yuwei Huangbdc4a972019-03-01 17:43:0670
Yuwei Huang946cebd42019-03-04 22:14:2071 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
72 std::string username = cmd_line->GetSwitchValueASCII(kSwitchNameUsername);
73 base::FilePath storage_path =
74 cmd_line->GetSwitchValuePath(kSwitchNameStoragePath);
75 storage_ = test::TestTokenStorage::OnDisk(username, storage_path);
76
Yuwei Huang41ddec52019-04-02 02:08:1977 token_getter_ = std::make_unique<test::TestOAuthTokenGetter>(storage_.get());
78
Yuwei Huangfce958772019-03-30 00:18:1179 base::RunLoop run_loop;
Yuwei Huang41ddec52019-04-02 02:08:1980 token_getter_->Initialize(
81 base::BindOnce(&FtlServicesPlayground::ResetServices,
82 weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
Yuwei Huangfce958772019-03-30 00:18:1183 run_loop.Run();
Yuwei Huangaae881f2019-03-01 23:10:2784
85 StartLoop();
86}
87
Yuwei Huang2687b47f2019-04-01 20:57:0888void FtlServicesPlayground::StartLoop() {
Yuwei Huang41ddec52019-04-02 02:08:1989 std::vector<test::CommandOption> options{
Yuwei Huang41ddec52019-04-02 02:08:1990 {"PullMessages", base::BindRepeating(&FtlServicesPlayground::PullMessages,
91 weak_factory_.GetWeakPtr())},
92 {"ReceiveMessages",
93 base::BindRepeating(&FtlServicesPlayground::StartReceivingMessages,
94 weak_factory_.GetWeakPtr())},
95 {"SendMessage", base::BindRepeating(&FtlServicesPlayground::SendMessage,
96 weak_factory_.GetWeakPtr())}};
Yuwei Huangfce958772019-03-30 00:18:1197
Yuwei Huang41ddec52019-04-02 02:08:1998 if (NeedsManualSignin()) {
99 options.insert(
100 options.begin(),
101 {"SignInGaia", base::BindRepeating(&FtlServicesPlayground::SignInGaia,
102 weak_factory_.GetWeakPtr())});
Yuwei Huangaae881f2019-03-01 23:10:27103 }
Yuwei Huang41ddec52019-04-02 02:08:19104
Yuwei Huangfeddf232020-07-28 00:27:49105 auto url_request_context_getter =
106 base::MakeRefCounted<URLRequestContextGetter>(
107 base::ThreadTaskRunnerHandle::Get());
108 url_loader_factory_owner_ =
109 std::make_unique<network::TransitionalURLLoaderFactoryOwner>(
110 url_request_context_getter);
111
Yuwei Huang41ddec52019-04-02 02:08:19112 test::RunCommandOptionsLoop(options);
Yuwei Huangbdc4a972019-03-01 17:43:06113}
114
Yuwei Huang2687b47f2019-04-01 20:57:08115void FtlServicesPlayground::ResetServices(base::OnceClosure on_done) {
Yuwei Huang82c01892019-03-28 20:39:40116 registration_manager_ = std::make_unique<FtlRegistrationManager>(
Yuwei Huangfeddf232020-07-28 00:27:49117 token_getter_.get(), url_loader_factory_owner_->GetURLLoaderFactory(),
Yuwei Huang1cf68062019-04-11 23:28:42118 std::make_unique<test::TestDeviceIdProvider>(storage_.get()));
Yuwei Huang968994cb2019-03-21 00:55:27119
120 message_subscription_.reset();
Yuwei Huang82c01892019-03-28 20:39:40121 messaging_client_ = std::make_unique<FtlMessagingClient>(
Yuwei Huang76ce10d2020-07-30 19:59:32122 token_getter_.get(), url_loader_factory_owner_->GetURLLoaderFactory(),
123 registration_manager_.get(), &signaling_tracker_);
Yuwei Huang968994cb2019-03-21 00:55:27124 message_subscription_ = messaging_client_->RegisterMessageCallback(
Yuwei Huang2687b47f2019-04-01 20:57:08125 base::BindRepeating(&FtlServicesPlayground::OnMessageReceived,
Yuwei Huang968994cb2019-03-21 00:55:27126 weak_factory_.GetWeakPtr()));
Yuwei Huangfce958772019-03-30 00:18:11127
128 if (NeedsManualSignin()) {
129 std::move(on_done).Run();
130 } else {
131 SignInGaia(std::move(on_done));
132 }
Yuwei Huang3f1fcd362019-03-11 20:27:17133}
134
Yuwei Huang2687b47f2019-04-01 20:57:08135void FtlServicesPlayground::SignInGaia(base::OnceClosure on_done) {
Yuwei Huange5b94452019-03-23 00:26:05136 DCHECK(registration_manager_);
Yuwei Huangaae881f2019-03-01 23:10:27137 VLOG(0) << "Running SignInGaia...";
Yuwei Huange5b94452019-03-23 00:26:05138 registration_manager_->SignInGaia(
Yuwei Huang2687b47f2019-04-01 20:57:08139 base::BindOnce(&FtlServicesPlayground::OnSignInGaiaResponse,
Yuwei Huang946cebd42019-03-04 22:14:20140 weak_factory_.GetWeakPtr(), std::move(on_done)));
Yuwei Huangaae881f2019-03-01 23:10:27141}
142
Yuwei Huangfeddf232020-07-28 00:27:49143void FtlServicesPlayground::OnSignInGaiaResponse(
144 base::OnceClosure on_done,
145 const ProtobufHttpStatus& status) {
Yuwei Huangfce958772019-03-30 00:18:11146 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32147 HandleStatusError(std::move(on_done), status);
Yuwei Huangfce958772019-03-30 00:18:11148 return;
Yuwei Huang98655b92019-03-04 23:41:41149 }
Yuwei Huangfce958772019-03-30 00:18:11150
151 std::string registration_id_base64;
152 base::Base64Encode(registration_manager_->GetRegistrationId(),
153 &registration_id_base64);
154 printf("Service signed in. registration_id(base64)=%s\n",
155 registration_id_base64.c_str());
Yuwei Huang98655b92019-03-04 23:41:41156 std::move(on_done).Run();
157}
158
Yuwei Huang2687b47f2019-04-01 20:57:08159void FtlServicesPlayground::PullMessages(base::OnceClosure on_done) {
Yuwei Huang968994cb2019-03-21 00:55:27160 DCHECK(messaging_client_);
Yuwei Huang98655b92019-03-04 23:41:41161 VLOG(0) << "Running PullMessages...";
Yuwei Huang3f1fcd362019-03-11 20:27:17162
Yuwei Huang968994cb2019-03-21 00:55:27163 messaging_client_->PullMessages(
Yuwei Huang2687b47f2019-04-01 20:57:08164 base::BindOnce(&FtlServicesPlayground::OnPullMessagesResponse,
Yuwei Huang98655b92019-03-04 23:41:41165 weak_factory_.GetWeakPtr(), std::move(on_done)));
166}
167
Yuwei Huang76ce10d2020-07-30 19:59:32168void FtlServicesPlayground::OnPullMessagesResponse(
169 base::OnceClosure on_done,
170 const ProtobufHttpStatus& status) {
Yuwei Huang98655b92019-03-04 23:41:41171 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32172 HandleStatusError(std::move(on_done), status);
Yuwei Huangfce958772019-03-30 00:18:11173 return;
Yuwei Huang5a84f9532019-02-20 18:29:01174 }
Yuwei Huang575c32ee2019-02-27 04:41:56175 std::move(on_done).Run();
176}
Yuwei Huang5a84f9532019-02-20 18:29:01177
Yuwei Huang2687b47f2019-04-01 20:57:08178void FtlServicesPlayground::SendMessage(base::OnceClosure on_done) {
Yuwei Huang4de60092019-03-22 21:19:44179 DCHECK(messaging_client_);
180 VLOG(0) << "Running SendMessage...";
181
182 printf("Receiver ID: ");
Yuwei Huang41ddec52019-04-02 02:08:19183 std::string receiver_id = test::ReadString();
Yuwei Huang4de60092019-03-22 21:19:44184
185 printf("Receiver registration ID (base64, optional): ");
Yuwei Huang41ddec52019-04-02 02:08:19186 std::string registration_id_base64 = test::ReadString();
Yuwei Huang4de60092019-03-22 21:19:44187
188 std::string registration_id;
189 bool success = base::Base64Decode(registration_id_base64, &registration_id);
190 if (!success) {
191 fprintf(stderr, "Your input can't be base64 decoded.\n");
192 std::move(on_done).Run();
193 return;
194 }
195 DoSendMessage(receiver_id, registration_id, std::move(on_done), true);
196}
197
Yuwei Huang2687b47f2019-04-01 20:57:08198void FtlServicesPlayground::DoSendMessage(const std::string& receiver_id,
199 const std::string& registration_id,
200 base::OnceClosure on_done,
201 bool should_keep_running) {
Yuwei Huang4de60092019-03-22 21:19:44202 if (!should_keep_running) {
203 std::move(on_done).Run();
204 return;
205 }
206
207 printf("Message (enter nothing to quit): ");
Yuwei Huang41ddec52019-04-02 02:08:19208 std::string message = test::ReadString();
Yuwei Huang4de60092019-03-22 21:19:44209
210 if (message.empty()) {
211 std::move(on_done).Run();
212 return;
213 }
214
Yuwei Huang2687b47f2019-04-01 20:57:08215 auto on_continue = base::BindOnce(&FtlServicesPlayground::DoSendMessage,
Yuwei Huang4de60092019-03-22 21:19:44216 weak_factory_.GetWeakPtr(), receiver_id,
217 registration_id, std::move(on_done));
218
Yuwei Huang4c919d142019-04-05 17:05:49219 ftl::ChromotingMessage crd_message;
220 crd_message.mutable_xmpp()->set_stanza(message);
Yuwei Huang4de60092019-03-22 21:19:44221 messaging_client_->SendMessage(
Yuwei Huang4c919d142019-04-05 17:05:49222 receiver_id, registration_id, crd_message,
Yuwei Huang2687b47f2019-04-01 20:57:08223 base::BindOnce(&FtlServicesPlayground::OnSendMessageResponse,
Yuwei Huang4de60092019-03-22 21:19:44224 weak_factory_.GetWeakPtr(), std::move(on_continue)));
225}
226
Yuwei Huang2687b47f2019-04-01 20:57:08227void FtlServicesPlayground::OnSendMessageResponse(
Yuwei Huang4de60092019-03-22 21:19:44228 base::OnceCallback<void(bool)> on_continue,
Yuwei Huang76ce10d2020-07-30 19:59:32229 const ProtobufHttpStatus& status) {
Yuwei Huang4de60092019-03-22 21:19:44230 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32231 HandleStatusError(base::BindOnce(std::move(on_continue), false), status);
Yuwei Huangfce958772019-03-30 00:18:11232 return;
Yuwei Huang4de60092019-03-22 21:19:44233 }
Yuwei Huangfce958772019-03-30 00:18:11234
235 printf("Message successfully sent.\n");
236 std::move(on_continue).Run(true);
Yuwei Huang4de60092019-03-22 21:19:44237}
238
Yuwei Huang2687b47f2019-04-01 20:57:08239void FtlServicesPlayground::StartReceivingMessages(base::OnceClosure on_done) {
Yuwei Huangb8e1f2d2019-03-22 19:40:26240 VLOG(0) << "Running StartReceivingMessages...";
Yuwei Huangce344e32019-04-05 19:31:29241 receive_messages_done_callback_ = std::move(on_done);
Yuwei Huangb8e1f2d2019-03-22 19:40:26242 messaging_client_->StartReceivingMessages(
Yuwei Huangce344e32019-04-05 19:31:29243 base::BindOnce(&FtlServicesPlayground::OnReceiveMessagesStreamReady,
244 weak_factory_.GetWeakPtr()),
245 base::BindOnce(&FtlServicesPlayground::OnReceiveMessagesStreamClosed,
246 weak_factory_.GetWeakPtr()));
Yuwei Huangb8e1f2d2019-03-22 19:40:26247}
248
Yuwei Huang2687b47f2019-04-01 20:57:08249void FtlServicesPlayground::StopReceivingMessages(base::OnceClosure on_done) {
Yuwei Huangb8e1f2d2019-03-22 19:40:26250 messaging_client_->StopReceivingMessages();
251 std::move(on_done).Run();
252}
253
Yuwei Huangc9bb46f2019-04-04 02:19:00254void FtlServicesPlayground::OnMessageReceived(
Yuwei Huang4ef50e732019-05-30 04:30:25255 const ftl::Id& sender_id,
Yuwei Huangc9bb46f2019-04-04 02:19:00256 const std::string& sender_registration_id,
Yuwei Huang4c919d142019-04-05 17:05:49257 const ftl::ChromotingMessage& message) {
258 std::string message_text = message.xmpp().stanza();
Yuwei Huang968994cb2019-03-21 00:55:27259 printf(
260 "Received message:\n"
261 " Sender ID=%s\n"
Yuwei Huangc9bb46f2019-04-04 02:19:00262 " Sender Registration ID=%s\n"
Yuwei Huang968994cb2019-03-21 00:55:27263 " Message=%s\n",
Yuwei Huang4ef50e732019-05-30 04:30:25264 sender_id.id().c_str(), sender_registration_id.c_str(),
265 message_text.c_str());
Yuwei Huang968994cb2019-03-21 00:55:27266}
267
Yuwei Huangce344e32019-04-05 19:31:29268void FtlServicesPlayground::OnReceiveMessagesStreamReady() {
269 printf("Started receiving messages. Press enter to stop streaming...\n");
270 test::WaitForEnterKey(base::BindOnce(
271 &FtlServicesPlayground::StopReceivingMessages, weak_factory_.GetWeakPtr(),
272 std::move(receive_messages_done_callback_)));
273}
274
275void FtlServicesPlayground::OnReceiveMessagesStreamClosed(
Yuwei Huang76ce10d2020-07-30 19:59:32276 const ProtobufHttpStatus& status) {
Yuwei Huangce344e32019-04-05 19:31:29277 base::OnceClosure callback = std::move(receive_messages_done_callback_);
278 bool is_callback_null = callback.is_null();
279 if (is_callback_null) {
280 callback = base::DoNothing::Once();
281 }
Yuwei Huang76ce10d2020-07-30 19:59:32282 if (status.error_code() == ProtobufHttpStatus::Code::CANCELLED) {
Yuwei Huangb8e1f2d2019-03-22 19:40:26283 printf("ReceiveMessages stream canceled by client.\n");
Yuwei Huangce344e32019-04-05 19:31:29284 std::move(callback).Run();
Yuwei Huangb8e1f2d2019-03-22 19:40:26285 return;
286 }
Yuwei Huangfce958772019-03-30 00:18:11287
Yuwei Huangb8e1f2d2019-03-22 19:40:26288 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32289 HandleStatusError(std::move(callback), status);
Yuwei Huangce344e32019-04-05 19:31:29290 } else {
291 printf("Stream closed by server.\n");
292 std::move(callback).Run();
Yuwei Huangb8e1f2d2019-03-22 19:40:26293 }
Yuwei Huangce344e32019-04-05 19:31:29294
295 if (is_callback_null) {
296 // Stream had been started and callback has been passed to wait for the
297 // enter key.
298 printf("Please press enter to continue...\n");
299 }
Yuwei Huangb8e1f2d2019-03-22 19:40:26300}
301
Yuwei Huang76ce10d2020-07-30 19:59:32302void FtlServicesPlayground::HandleStatusError(
303 base::OnceClosure on_done,
304 const ProtobufHttpStatus& status) {
Yuwei Huangfce958772019-03-30 00:18:11305 DCHECK(!status.ok());
Yuwei Huang76ce10d2020-07-30 19:59:32306 if (status.error_code() == ProtobufHttpStatus::Code::UNAUTHENTICATED) {
Yuwei Huangfce958772019-03-30 00:18:11307 if (NeedsManualSignin()) {
308 printf(
309 "Request is unauthenticated. You should run SignInGaia first if "
310 "you haven't done so, otherwise your OAuth token might be expired. \n"
311 "Request for new OAuth token? [y/N]: ");
Yuwei Huangdc86bdf42019-04-18 19:14:10312 if (!test::ReadYNBool()) {
Yuwei Huangfce958772019-03-30 00:18:11313 std::move(on_done).Run();
314 return;
315 }
316 }
Yuwei Huang76ce10d2020-07-30 19:59:32317 VLOG(0) << "Request failed to authenticate. "
Yuwei Huangfce958772019-03-30 00:18:11318 << "Trying to reauthenticate...";
Yuwei Huang41ddec52019-04-02 02:08:19319 token_getter_->ResetWithAuthenticationFlow(
320 base::BindOnce(&FtlServicesPlayground::ResetServices,
321 weak_factory_.GetWeakPtr(), std::move(on_done)));
Yuwei Huangfce958772019-03-30 00:18:11322 return;
323 }
324
325 fprintf(stderr, "RPC failed. Code=%d, Message=%s\n", status.error_code(),
326 status.error_message().c_str());
327 std::move(on_done).Run();
328}
329
Yuwei Huang575c32ee2019-02-27 04:41:56330} // namespace remoting