blob: 5c6c72c8ce064b3bab95d60a4a16eefa76f5b4c4 [file] [log] [blame]
Avi Drissmand6cdf9b2022-09-15 19:52:531// Copyright 2019 The Chromium Authors
Yuwei Huang5a84f9532019-02-20 18:29:012// 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"
danakjdb9ae7942020-11-11 16:01:3514#include "base/callback_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 Huangbdc4a972019-03-01 17:43:0621#include "remoting/base/oauth_token_getter_impl.h"
Yuwei Huangfeddf232020-07-28 00:27:4922#include "remoting/base/protobuf_http_status.h"
23#include "remoting/base/url_request_context_getter.h"
Yuwei Huang76ce10d2020-07-30 19:59:3224#include "remoting/proto/ftl/v1/ftl_messages.pb.h"
Yuwei Huang41ddec52019-04-02 02:08:1925#include "remoting/test/cli_util.h"
Yuwei Huang1cf68062019-04-11 23:28:4226#include "remoting/test/test_device_id_provider.h"
Yuwei Huang41ddec52019-04-02 02:08:1927#include "remoting/test/test_oauth_token_getter.h"
Yuwei Huang946cebd42019-03-04 22:14:2028#include "remoting/test/test_token_storage.h"
Yuwei Huangfeddf232020-07-28 00:27:4929#include "services/network/public/cpp/shared_url_loader_factory.h"
30#include "services/network/transitional_url_loader_factory_owner.h"
Yuwei Huangbdc4a972019-03-01 17:43:0631
32namespace {
33
34constexpr char kSwitchNameHelp[] = "help";
Yuwei Huang946cebd42019-03-04 22:14:2035constexpr char kSwitchNameUsername[] = "username";
36constexpr char kSwitchNameStoragePath[] = "storage-path";
Yuwei Huangfce958772019-03-30 00:18:1137constexpr char kSwitchNameNoAutoSignin[] = "no-auto-signin";
Yuwei Huangbdc4a972019-03-01 17:43:0638
Yuwei Huangfce958772019-03-30 00:18:1139bool NeedsManualSignin() {
40 return base::CommandLine::ForCurrentProcess()->HasSwitch(
41 kSwitchNameNoAutoSignin);
Yuwei Huangb8e1f2d2019-03-22 19:40:2642}
43
Yuwei Huangbdc4a972019-03-01 17:43:0644} // namespace
Yuwei Huang5a84f9532019-02-20 18:29:0145
Yuwei Huang575c32ee2019-02-27 04:41:5646namespace remoting {
Yuwei Huang5a84f9532019-02-20 18:29:0147
Jeremy Roman7c5cfabd2019-08-12 15:45:2748FtlServicesPlayground::FtlServicesPlayground() {}
Yuwei Huang575c32ee2019-02-27 04:41:5649
Yuwei Huang2687b47f2019-04-01 20:57:0850FtlServicesPlayground::~FtlServicesPlayground() = default;
Yuwei Huang575c32ee2019-02-27 04:41:5651
Yuwei Huang2687b47f2019-04-01 20:57:0852bool FtlServicesPlayground::ShouldPrintHelp() {
Yuwei Huangbdc4a972019-03-01 17:43:0653 return base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchNameHelp);
54}
55
Yuwei Huang2687b47f2019-04-01 20:57:0856void FtlServicesPlayground::PrintHelp() {
Yuwei Huang946cebd42019-03-04 22:14:2057 printf(
Yuwei Huang41ddec52019-04-02 02:08:1958 "Usage: %s [--no-auto-signin] [--auth-code=<auth-code>] "
Yuwei Huangfce958772019-03-30 00:18:1159 "[--storage-path=<storage-path>] [--username=<[email protected]>]\n",
Yuwei Huang946cebd42019-03-04 22:14:2060 base::CommandLine::ForCurrentProcess()
61 ->GetProgram()
62 .MaybeAsASCII()
63 .c_str());
Yuwei Huangbdc4a972019-03-01 17:43:0664}
65
Yuwei Huang2687b47f2019-04-01 20:57:0866void FtlServicesPlayground::StartAndAuthenticate() {
Yuwei Huang946cebd42019-03-04 22:14:2067 DCHECK(!storage_);
Yuwei Huangbdc4a972019-03-01 17:43:0668 DCHECK(!token_getter_);
Yuwei Huangbdc4a972019-03-01 17:43:0669
Yuwei Huang946cebd42019-03-04 22:14:2070 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
71 std::string username = cmd_line->GetSwitchValueASCII(kSwitchNameUsername);
72 base::FilePath storage_path =
73 cmd_line->GetSwitchValuePath(kSwitchNameStoragePath);
74 storage_ = test::TestTokenStorage::OnDisk(username, storage_path);
75
Yuwei Huang41ddec52019-04-02 02:08:1976 token_getter_ = std::make_unique<test::TestOAuthTokenGetter>(storage_.get());
77
Yuwei Huangfce958772019-03-30 00:18:1178 base::RunLoop run_loop;
Yuwei Huang41ddec52019-04-02 02:08:1979 token_getter_->Initialize(
80 base::BindOnce(&FtlServicesPlayground::ResetServices,
81 weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
Yuwei Huangfce958772019-03-30 00:18:1182 run_loop.Run();
Yuwei Huangaae881f2019-03-01 23:10:2783
84 StartLoop();
85}
86
Yuwei Huang2687b47f2019-04-01 20:57:0887void FtlServicesPlayground::StartLoop() {
Yuwei Huang41ddec52019-04-02 02:08:1988 std::vector<test::CommandOption> options{
Yuwei Huang41ddec52019-04-02 02:08:1989 {"ReceiveMessages",
90 base::BindRepeating(&FtlServicesPlayground::StartReceivingMessages,
91 weak_factory_.GetWeakPtr())},
92 {"SendMessage", base::BindRepeating(&FtlServicesPlayground::SendMessage,
93 weak_factory_.GetWeakPtr())}};
Yuwei Huangfce958772019-03-30 00:18:1194
Yuwei Huang41ddec52019-04-02 02:08:1995 if (NeedsManualSignin()) {
96 options.insert(
97 options.begin(),
98 {"SignInGaia", base::BindRepeating(&FtlServicesPlayground::SignInGaia,
99 weak_factory_.GetWeakPtr())});
Yuwei Huangaae881f2019-03-01 23:10:27100 }
Yuwei Huang41ddec52019-04-02 02:08:19101
Yuwei Huangfeddf232020-07-28 00:27:49102 auto url_request_context_getter =
103 base::MakeRefCounted<URLRequestContextGetter>(
Sean Maher5b9af51f2022-11-21 15:32:47104 base::SingleThreadTaskRunner::GetCurrentDefault());
Yuwei Huangfeddf232020-07-28 00:27:49105 url_loader_factory_owner_ =
106 std::make_unique<network::TransitionalURLLoaderFactoryOwner>(
107 url_request_context_getter);
108
Yuwei Huang41ddec52019-04-02 02:08:19109 test::RunCommandOptionsLoop(options);
Yuwei Huangbdc4a972019-03-01 17:43:06110}
111
Yuwei Huang2687b47f2019-04-01 20:57:08112void FtlServicesPlayground::ResetServices(base::OnceClosure on_done) {
Yuwei Huang82c01892019-03-28 20:39:40113 registration_manager_ = std::make_unique<FtlRegistrationManager>(
Yuwei Huangfeddf232020-07-28 00:27:49114 token_getter_.get(), url_loader_factory_owner_->GetURLLoaderFactory(),
Yuwei Huang1cf68062019-04-11 23:28:42115 std::make_unique<test::TestDeviceIdProvider>(storage_.get()));
Yuwei Huang968994cb2019-03-21 00:55:27116
Peter Kasting7ba9440c2020-11-22 01:49:02117 message_subscription_ = {};
Yuwei Huang82c01892019-03-28 20:39:40118 messaging_client_ = std::make_unique<FtlMessagingClient>(
Yuwei Huang76ce10d2020-07-30 19:59:32119 token_getter_.get(), url_loader_factory_owner_->GetURLLoaderFactory(),
Yuwei Huangfebdea62020-09-16 21:55:58120 registration_manager_.get());
Yuwei Huang968994cb2019-03-21 00:55:27121 message_subscription_ = messaging_client_->RegisterMessageCallback(
Yuwei Huang2687b47f2019-04-01 20:57:08122 base::BindRepeating(&FtlServicesPlayground::OnMessageReceived,
Yuwei Huang968994cb2019-03-21 00:55:27123 weak_factory_.GetWeakPtr()));
Yuwei Huangfce958772019-03-30 00:18:11124
125 if (NeedsManualSignin()) {
126 std::move(on_done).Run();
127 } else {
128 SignInGaia(std::move(on_done));
129 }
Yuwei Huang3f1fcd362019-03-11 20:27:17130}
131
Yuwei Huang2687b47f2019-04-01 20:57:08132void FtlServicesPlayground::SignInGaia(base::OnceClosure on_done) {
Yuwei Huange5b94452019-03-23 00:26:05133 DCHECK(registration_manager_);
Yuwei Huangaae881f2019-03-01 23:10:27134 VLOG(0) << "Running SignInGaia...";
Yuwei Huange5b94452019-03-23 00:26:05135 registration_manager_->SignInGaia(
Yuwei Huang2687b47f2019-04-01 20:57:08136 base::BindOnce(&FtlServicesPlayground::OnSignInGaiaResponse,
Yuwei Huang946cebd42019-03-04 22:14:20137 weak_factory_.GetWeakPtr(), std::move(on_done)));
Yuwei Huangaae881f2019-03-01 23:10:27138}
139
Yuwei Huangfeddf232020-07-28 00:27:49140void FtlServicesPlayground::OnSignInGaiaResponse(
141 base::OnceClosure on_done,
142 const ProtobufHttpStatus& status) {
Yuwei Huangfce958772019-03-30 00:18:11143 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32144 HandleStatusError(std::move(on_done), status);
Yuwei Huangfce958772019-03-30 00:18:11145 return;
Yuwei Huang98655b92019-03-04 23:41:41146 }
Yuwei Huangfce958772019-03-30 00:18:11147
148 std::string registration_id_base64;
149 base::Base64Encode(registration_manager_->GetRegistrationId(),
150 &registration_id_base64);
151 printf("Service signed in. registration_id(base64)=%s\n",
152 registration_id_base64.c_str());
Yuwei Huang98655b92019-03-04 23:41:41153 std::move(on_done).Run();
154}
155
Yuwei Huang2687b47f2019-04-01 20:57:08156void FtlServicesPlayground::SendMessage(base::OnceClosure on_done) {
Yuwei Huang4de60092019-03-22 21:19:44157 DCHECK(messaging_client_);
158 VLOG(0) << "Running SendMessage...";
159
160 printf("Receiver ID: ");
Yuwei Huang41ddec52019-04-02 02:08:19161 std::string receiver_id = test::ReadString();
Yuwei Huang4de60092019-03-22 21:19:44162
163 printf("Receiver registration ID (base64, optional): ");
Yuwei Huang41ddec52019-04-02 02:08:19164 std::string registration_id_base64 = test::ReadString();
Yuwei Huang4de60092019-03-22 21:19:44165
166 std::string registration_id;
167 bool success = base::Base64Decode(registration_id_base64, &registration_id);
168 if (!success) {
169 fprintf(stderr, "Your input can't be base64 decoded.\n");
170 std::move(on_done).Run();
171 return;
172 }
173 DoSendMessage(receiver_id, registration_id, std::move(on_done), true);
174}
175
Yuwei Huang2687b47f2019-04-01 20:57:08176void FtlServicesPlayground::DoSendMessage(const std::string& receiver_id,
177 const std::string& registration_id,
178 base::OnceClosure on_done,
179 bool should_keep_running) {
Yuwei Huang4de60092019-03-22 21:19:44180 if (!should_keep_running) {
181 std::move(on_done).Run();
182 return;
183 }
184
185 printf("Message (enter nothing to quit): ");
Yuwei Huang41ddec52019-04-02 02:08:19186 std::string message = test::ReadString();
Yuwei Huang4de60092019-03-22 21:19:44187
188 if (message.empty()) {
189 std::move(on_done).Run();
190 return;
191 }
192
Yuwei Huang2687b47f2019-04-01 20:57:08193 auto on_continue = base::BindOnce(&FtlServicesPlayground::DoSendMessage,
Yuwei Huang4de60092019-03-22 21:19:44194 weak_factory_.GetWeakPtr(), receiver_id,
195 registration_id, std::move(on_done));
196
Yuwei Huang4c919d142019-04-05 17:05:49197 ftl::ChromotingMessage crd_message;
198 crd_message.mutable_xmpp()->set_stanza(message);
Yuwei Huang4de60092019-03-22 21:19:44199 messaging_client_->SendMessage(
Yuwei Huang4c919d142019-04-05 17:05:49200 receiver_id, registration_id, crd_message,
Yuwei Huang2687b47f2019-04-01 20:57:08201 base::BindOnce(&FtlServicesPlayground::OnSendMessageResponse,
Yuwei Huang4de60092019-03-22 21:19:44202 weak_factory_.GetWeakPtr(), std::move(on_continue)));
203}
204
Yuwei Huang2687b47f2019-04-01 20:57:08205void FtlServicesPlayground::OnSendMessageResponse(
Yuwei Huang4de60092019-03-22 21:19:44206 base::OnceCallback<void(bool)> on_continue,
Yuwei Huang76ce10d2020-07-30 19:59:32207 const ProtobufHttpStatus& status) {
Yuwei Huang4de60092019-03-22 21:19:44208 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32209 HandleStatusError(base::BindOnce(std::move(on_continue), false), status);
Yuwei Huangfce958772019-03-30 00:18:11210 return;
Yuwei Huang4de60092019-03-22 21:19:44211 }
Yuwei Huangfce958772019-03-30 00:18:11212
213 printf("Message successfully sent.\n");
214 std::move(on_continue).Run(true);
Yuwei Huang4de60092019-03-22 21:19:44215}
216
Yuwei Huang2687b47f2019-04-01 20:57:08217void FtlServicesPlayground::StartReceivingMessages(base::OnceClosure on_done) {
Yuwei Huangb8e1f2d2019-03-22 19:40:26218 VLOG(0) << "Running StartReceivingMessages...";
Yuwei Huangce344e32019-04-05 19:31:29219 receive_messages_done_callback_ = std::move(on_done);
Yuwei Huangb8e1f2d2019-03-22 19:40:26220 messaging_client_->StartReceivingMessages(
Yuwei Huangce344e32019-04-05 19:31:29221 base::BindOnce(&FtlServicesPlayground::OnReceiveMessagesStreamReady,
222 weak_factory_.GetWeakPtr()),
223 base::BindOnce(&FtlServicesPlayground::OnReceiveMessagesStreamClosed,
224 weak_factory_.GetWeakPtr()));
Yuwei Huangb8e1f2d2019-03-22 19:40:26225}
226
Yuwei Huang2687b47f2019-04-01 20:57:08227void FtlServicesPlayground::StopReceivingMessages(base::OnceClosure on_done) {
Yuwei Huangb8e1f2d2019-03-22 19:40:26228 messaging_client_->StopReceivingMessages();
229 std::move(on_done).Run();
230}
231
Yuwei Huangc9bb46f2019-04-04 02:19:00232void FtlServicesPlayground::OnMessageReceived(
Yuwei Huang4ef50e732019-05-30 04:30:25233 const ftl::Id& sender_id,
Yuwei Huangc9bb46f2019-04-04 02:19:00234 const std::string& sender_registration_id,
Yuwei Huang4c919d142019-04-05 17:05:49235 const ftl::ChromotingMessage& message) {
236 std::string message_text = message.xmpp().stanza();
Yuwei Huang968994cb2019-03-21 00:55:27237 printf(
238 "Received message:\n"
239 " Sender ID=%s\n"
Yuwei Huangc9bb46f2019-04-04 02:19:00240 " Sender Registration ID=%s\n"
Yuwei Huang968994cb2019-03-21 00:55:27241 " Message=%s\n",
Yuwei Huang4ef50e732019-05-30 04:30:25242 sender_id.id().c_str(), sender_registration_id.c_str(),
243 message_text.c_str());
Yuwei Huang968994cb2019-03-21 00:55:27244}
245
Yuwei Huangce344e32019-04-05 19:31:29246void FtlServicesPlayground::OnReceiveMessagesStreamReady() {
247 printf("Started receiving messages. Press enter to stop streaming...\n");
248 test::WaitForEnterKey(base::BindOnce(
249 &FtlServicesPlayground::StopReceivingMessages, weak_factory_.GetWeakPtr(),
250 std::move(receive_messages_done_callback_)));
251}
252
253void FtlServicesPlayground::OnReceiveMessagesStreamClosed(
Yuwei Huang76ce10d2020-07-30 19:59:32254 const ProtobufHttpStatus& status) {
Yuwei Huangce344e32019-04-05 19:31:29255 base::OnceClosure callback = std::move(receive_messages_done_callback_);
256 bool is_callback_null = callback.is_null();
257 if (is_callback_null) {
Daniel Chenge0fc4632021-10-01 00:37:41258 callback = base::DoNothing();
Yuwei Huangce344e32019-04-05 19:31:29259 }
Yuwei Huang76ce10d2020-07-30 19:59:32260 if (status.error_code() == ProtobufHttpStatus::Code::CANCELLED) {
Yuwei Huangb8e1f2d2019-03-22 19:40:26261 printf("ReceiveMessages stream canceled by client.\n");
Yuwei Huangce344e32019-04-05 19:31:29262 std::move(callback).Run();
Yuwei Huangb8e1f2d2019-03-22 19:40:26263 return;
264 }
Yuwei Huangfce958772019-03-30 00:18:11265
Yuwei Huangb8e1f2d2019-03-22 19:40:26266 if (!status.ok()) {
Yuwei Huang76ce10d2020-07-30 19:59:32267 HandleStatusError(std::move(callback), status);
Yuwei Huangce344e32019-04-05 19:31:29268 } else {
269 printf("Stream closed by server.\n");
270 std::move(callback).Run();
Yuwei Huangb8e1f2d2019-03-22 19:40:26271 }
Yuwei Huangce344e32019-04-05 19:31:29272
273 if (is_callback_null) {
274 // Stream had been started and callback has been passed to wait for the
275 // enter key.
276 printf("Please press enter to continue...\n");
277 }
Yuwei Huangb8e1f2d2019-03-22 19:40:26278}
279
Yuwei Huang76ce10d2020-07-30 19:59:32280void FtlServicesPlayground::HandleStatusError(
281 base::OnceClosure on_done,
282 const ProtobufHttpStatus& status) {
Yuwei Huangfce958772019-03-30 00:18:11283 DCHECK(!status.ok());
Yuwei Huang76ce10d2020-07-30 19:59:32284 if (status.error_code() == ProtobufHttpStatus::Code::UNAUTHENTICATED) {
Yuwei Huangfce958772019-03-30 00:18:11285 if (NeedsManualSignin()) {
286 printf(
287 "Request is unauthenticated. You should run SignInGaia first if "
288 "you haven't done so, otherwise your OAuth token might be expired. \n"
289 "Request for new OAuth token? [y/N]: ");
Yuwei Huangdc86bdf42019-04-18 19:14:10290 if (!test::ReadYNBool()) {
Yuwei Huangfce958772019-03-30 00:18:11291 std::move(on_done).Run();
292 return;
293 }
294 }
Yuwei Huang76ce10d2020-07-30 19:59:32295 VLOG(0) << "Request failed to authenticate. "
Yuwei Huangfce958772019-03-30 00:18:11296 << "Trying to reauthenticate...";
Yuwei Huang41ddec52019-04-02 02:08:19297 token_getter_->ResetWithAuthenticationFlow(
298 base::BindOnce(&FtlServicesPlayground::ResetServices,
299 weak_factory_.GetWeakPtr(), std::move(on_done)));
Yuwei Huangfce958772019-03-30 00:18:11300 return;
301 }
302
303 fprintf(stderr, "RPC failed. Code=%d, Message=%s\n", status.error_code(),
304 status.error_message().c_str());
305 std::move(on_done).Run();
306}
307
Yuwei Huang575c32ee2019-02-27 04:41:56308} // namespace remoting