mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Move TachyonExpressSignallingMessenger into mediums/webrtc.
PiperOrigin-RevId: 919882997
This commit is contained in:
committed by
Copybara-Service
parent
c9c7e6ee57
commit
b536c8da3a
@@ -144,6 +144,37 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "tachyon_express_signaling_messenger",
|
||||
srcs = ["tachyon_express_signaling_messenger.cc"],
|
||||
hdrs = ["tachyon_express_signaling_messenger.h"],
|
||||
visibility = [
|
||||
"//connections:__subpackages__",
|
||||
"//internal/platform/implementation:__subpackages__",
|
||||
"//internal/test:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//internal/account",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
"//internal/platform:types",
|
||||
"//internal/platform/implementation:webrtc_platform",
|
||||
"//internal/proto:messaging_cc_grpc_proto",
|
||||
"//internal/proto:tachyon_cc_proto",
|
||||
"//internal/rpc:utils",
|
||||
"//location/nearby/sharing/lib/account:account_manager",
|
||||
"//third_party/gloop/util/random:mt_random",
|
||||
"//third_party/grpc:gpr",
|
||||
"//third_party/grpc:grpc++",
|
||||
"//util/random:util",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "fake_webrtc",
|
||||
testonly = True,
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "connections/implementation/mediums/webrtc/tachyon_express_signaling_messenger.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "third_party/gloop/util/random/mt_random.h"
|
||||
#include "third_party/grpc/include/grpc/support/time.h"
|
||||
#include "third_party/grpc/include/grpcpp/channel.h"
|
||||
#include "third_party/grpc/include/grpcpp/client_context.h"
|
||||
#include "third_party/grpc/include/grpcpp/create_channel.h"
|
||||
#include "third_party/grpc/include/grpcpp/security/credentials.h"
|
||||
#include "third_party/grpc/include/grpcpp/support/client_callback.h"
|
||||
#include "third_party/grpc/include/grpcpp/support/status.h"
|
||||
#include "internal/account/account_manager_impl.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/count_down_latch.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "internal/proto/messaging.grpc.pb.h"
|
||||
#include "internal/proto/tachyon.proto.h"
|
||||
#include "internal/proto/tachyon_common.proto.h"
|
||||
#include "internal/proto/tachyon_enums.proto.h"
|
||||
#include "internal/rpc/utils.h"
|
||||
#include "util/random/util.h"
|
||||
|
||||
namespace nearby::connections::mediums {
|
||||
|
||||
namespace {
|
||||
using ::google::internal::communications::instantmessaging::v1::ClientInfo;
|
||||
using ::google::internal::communications::instantmessaging::v1::Id;
|
||||
using ::google::internal::communications::instantmessaging::v1::
|
||||
LocationStandard;
|
||||
using ::google::internal::communications::instantmessaging::v1::
|
||||
ReceiveMessagesResponse;
|
||||
using ::google::internal::communications::instantmessaging::v1::RequestHeader;
|
||||
using ::google::internal::communications::instantmessaging::v1::
|
||||
SendMessageExpressRequest;
|
||||
using ::google::internal::communications::instantmessaging::v1::
|
||||
SendMessageExpressResponse;
|
||||
|
||||
constexpr absl::string_view kApp = "Nearby";
|
||||
constexpr absl::string_view kTachyonAddress =
|
||||
"instantmessaging-pa.googleapis.com:443";
|
||||
|
||||
// It is unclear to me where these magic numbers are from but they are used
|
||||
// across both the Android and CrOS implementations.
|
||||
// See:
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/nearby_sharing/tachyon_ice_config_fetcher.cc;l=53
|
||||
constexpr int kMajorVersion = 1;
|
||||
constexpr int kMinorVersion = 24;
|
||||
constexpr int kPointVersion = 0;
|
||||
|
||||
void InitId(Id& id, absl::string_view id_str,
|
||||
const location::nearby::connections::LocationHint& location_hint) {
|
||||
id.set_id(id_str);
|
||||
id.set_app(kApp);
|
||||
id.set_type(google::internal::communications::instantmessaging::v1::IdType::
|
||||
NEARBY_ID);
|
||||
auto* request_location_hint = id.mutable_location_hint();
|
||||
request_location_hint->set_location(location_hint.location());
|
||||
if (location_hint.format() ==
|
||||
location::nearby::connections::LocationStandard::E164_CALLING) {
|
||||
request_location_hint->set_format(LocationStandard::E164_CALLING);
|
||||
} else if (location_hint.format() ==
|
||||
location::nearby::connections::LocationStandard::
|
||||
ISO_3166_1_ALPHA_2) {
|
||||
request_location_hint->set_format(LocationStandard::ISO_3166_1_ALPHA_2);
|
||||
} else {
|
||||
request_location_hint->set_format(LocationStandard::UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void InitRequestHeader(
|
||||
RequestHeader& header, absl::string_view self_id,
|
||||
const location::nearby::connections::LocationHint& location_hint) {
|
||||
ClientInfo* client_info = header.mutable_client_info();
|
||||
client_info->set_platform_type(google::internal::communications::
|
||||
instantmessaging::v1::Platform::DESKTOP);
|
||||
|
||||
client_info->set_major(kMajorVersion);
|
||||
client_info->set_minor(kMinorVersion);
|
||||
client_info->set_point(kPointVersion);
|
||||
|
||||
client_info->set_api_version(
|
||||
google::internal::communications::instantmessaging::v1::ApiVersion::V4);
|
||||
|
||||
// Generate a random message identifier.
|
||||
MTRandom rand;
|
||||
header.set_request_id(util_random::RandomString(&rand, /*length=*/13,
|
||||
util::random::kWebsafe64));
|
||||
header.set_app(kApp);
|
||||
|
||||
InitId(*header.mutable_requester_id(), self_id, location_hint);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool TachyonExpressSignalingMessenger::ReceiveMessagesReader::Start(
|
||||
google::internal::communications::instantmessaging::v1::grpc::Messaging::
|
||||
StubInterface* stub,
|
||||
absl::string_view self_id,
|
||||
const location::nearby::connections::LocationHint& location_hint,
|
||||
absl::string_view access_token,
|
||||
absl::AnyInvocable<void()> on_fast_path_ready_callback,
|
||||
absl::AnyInvocable<void(const ByteArray&)> on_inbox_message_callback,
|
||||
absl::AnyInvocable<void(bool)> on_complete_callback) {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
if (is_receiving_messages_) {
|
||||
return false;
|
||||
}
|
||||
is_receiving_messages_ = true;
|
||||
}
|
||||
|
||||
on_fast_path_ready_callback_ = std::move(on_fast_path_ready_callback);
|
||||
on_inbox_message_callback_ = std::move(on_inbox_message_callback);
|
||||
on_complete_callback_ = std::move(on_complete_callback);
|
||||
const std::shared_ptr<grpc::CallCredentials> call_creds =
|
||||
grpc::AccessTokenCredentials(std::string(access_token));
|
||||
context_.set_credentials(call_creds);
|
||||
gpr_timespec deadline = gpr_now(GPR_CLOCK_MONOTONIC);
|
||||
timespec timespec = absl::ToTimespec(absl::Seconds(30));
|
||||
deadline.tv_sec += timespec.tv_sec;
|
||||
deadline.tv_nsec += timespec.tv_nsec;
|
||||
context_.set_deadline(deadline);
|
||||
|
||||
InitRequestHeader(*request_.mutable_header(), self_id, location_hint);
|
||||
stub->async()->ReceiveMessagesExpress(&context_, &request_, this);
|
||||
StartRead(&response_);
|
||||
StartCall();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TachyonExpressSignalingMessenger::ReceiveMessagesReader::OnReadDone(
|
||||
bool ok) {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
if (!is_receiving_messages_) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
switch (response_.body_case()) {
|
||||
case ReceiveMessagesResponse::kFastPathReady:
|
||||
on_fast_path_ready_callback_();
|
||||
break;
|
||||
case ReceiveMessagesResponse::kInboxMessage:
|
||||
on_inbox_message_callback_(
|
||||
ByteArray(response_.inbox_message().message()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
StartRead(&response_);
|
||||
}
|
||||
}
|
||||
|
||||
void TachyonExpressSignalingMessenger::ReceiveMessagesReader::OnDone(
|
||||
const grpc::Status& s) {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
if (!is_receiving_messages_) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!s.ok()) {
|
||||
LOG(ERROR) << "ReceiveMessagesExpress failed: "
|
||||
<< rpc::GrpcStatusToAbslStatus(s);
|
||||
}
|
||||
on_complete_callback_(s.ok());
|
||||
}
|
||||
|
||||
void TachyonExpressSignalingMessenger::ReceiveMessagesReader::TryCancel() {
|
||||
{
|
||||
absl::MutexLock lock(mutex_);
|
||||
if (!is_receiving_messages_) {
|
||||
return;
|
||||
}
|
||||
is_receiving_messages_ = false;
|
||||
}
|
||||
context_.TryCancel();
|
||||
}
|
||||
|
||||
TachyonExpressSignalingMessenger::TachyonExpressSignalingMessenger(
|
||||
absl::string_view self_id,
|
||||
const location::nearby::connections::LocationHint& location_hint)
|
||||
: self_id_(self_id),
|
||||
location_hint_(location_hint),
|
||||
account_manager_(AccountManagerImpl::Factory::instance()) {
|
||||
std::shared_ptr<grpc::Channel> channel =
|
||||
grpc::CreateChannel(std::string(kTachyonAddress),
|
||||
grpc::SslCredentials(grpc::SslCredentialsOptions()));
|
||||
messaging_stub_ = google::internal::communications::instantmessaging::v1::
|
||||
grpc::Messaging::NewStub(channel);
|
||||
}
|
||||
|
||||
struct StartState {
|
||||
CountDownLatch latch{1};
|
||||
bool success = false;
|
||||
};
|
||||
|
||||
bool TachyonExpressSignalingMessenger::StartReceivingMessages(
|
||||
OnSignalingMessageCallback on_message_callback,
|
||||
OnSignalingCompleteCallback on_complete_callback) {
|
||||
auto state = std::make_shared<StartState>();
|
||||
|
||||
account_manager_->GetAccessToken(
|
||||
[this, state, on_message_callback = std::move(on_message_callback),
|
||||
on_complete_callback = std::move(on_complete_callback)](
|
||||
absl::StatusOr<std::string> token) mutable {
|
||||
if (!token.ok()) {
|
||||
state->success = false;
|
||||
state->latch.CountDown();
|
||||
return;
|
||||
}
|
||||
auto reader = std::make_shared<ReceiveMessagesReader>();
|
||||
|
||||
reader_ = reader;
|
||||
|
||||
std::weak_ptr<StartState> weak_state = state;
|
||||
|
||||
bool started = reader->Start(
|
||||
messaging_stub_.get(), self_id_, location_hint_, token.value(),
|
||||
/*on_fast_path_ready_callback=*/
|
||||
[state] {
|
||||
LOG(INFO) << "Received fast path ready message from tachyon.";
|
||||
state->success = true;
|
||||
state->latch.CountDown();
|
||||
},
|
||||
std::move(on_message_callback),
|
||||
[reader, weak_state,
|
||||
cb = std::move(on_complete_callback)](bool s) mutable {
|
||||
LOG(INFO) << "Finished receiving messages from tachyon.";
|
||||
cb(s);
|
||||
if (auto state = weak_state.lock()) {
|
||||
state->success = false;
|
||||
state->latch.CountDown();
|
||||
}
|
||||
});
|
||||
|
||||
if (!started) {
|
||||
state->success = false;
|
||||
state->latch.CountDown();
|
||||
}
|
||||
});
|
||||
state->latch.Await();
|
||||
if (state->success) {
|
||||
LOG(INFO) << "Receiving messages from tachyon.";
|
||||
} else {
|
||||
LOG(ERROR) << "Failed to start receiving messages from tachyon.";
|
||||
reader_.reset();
|
||||
}
|
||||
return state->success;
|
||||
}
|
||||
|
||||
void TachyonExpressSignalingMessenger::StopReceivingMessages() {
|
||||
if (reader_) {
|
||||
reader_->TryCancel();
|
||||
reader_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool TachyonExpressSignalingMessenger::SendMessage(absl::string_view peer_id,
|
||||
const ByteArray& message) {
|
||||
auto rpc_state =
|
||||
std::make_shared<rpc::AsyncRpcArgs<SendMessageExpressRequest,
|
||||
SendMessageExpressResponse>>();
|
||||
|
||||
InitRequestHeader(*rpc_state->request.mutable_header(), self_id_,
|
||||
location_hint_);
|
||||
InitId(*rpc_state->request.mutable_dest_id(), peer_id, location_hint_);
|
||||
|
||||
auto* request_message = rpc_state->request.mutable_message();
|
||||
request_message->set_message(message.string_data());
|
||||
request_message->set_message_type(
|
||||
google::internal::communications::instantmessaging::v1::InboxMessage::
|
||||
BASIC);
|
||||
request_message->set_message_class(
|
||||
google::internal::communications::instantmessaging::v1::InboxMessage::
|
||||
EPHEMERAL);
|
||||
MTRandom rand;
|
||||
request_message->set_message_id(util_random::RandomString(
|
||||
&rand, /*length=*/13, util::random::kWebsafe64));
|
||||
|
||||
CountDownLatch latch(1);
|
||||
bool success = false;
|
||||
account_manager_->GetAccessToken(
|
||||
[this, &latch, &success, rpc_state](absl::StatusOr<std::string> token) {
|
||||
if (!token.ok()) {
|
||||
success = false;
|
||||
latch.CountDown();
|
||||
return;
|
||||
}
|
||||
|
||||
const std::shared_ptr<grpc::CallCredentials> call_creds =
|
||||
grpc::AccessTokenCredentials(token.value());
|
||||
rpc_state->context.set_credentials(call_creds);
|
||||
gpr_timespec deadline = gpr_now(GPR_CLOCK_MONOTONIC);
|
||||
timespec timespec = absl::ToTimespec(absl::Seconds(30));
|
||||
deadline.tv_sec += timespec.tv_sec;
|
||||
deadline.tv_nsec += timespec.tv_nsec;
|
||||
rpc_state->context.set_deadline(deadline);
|
||||
|
||||
// `rpc_state` is captured to ensure its lifetime is valid until the
|
||||
// callback is executed.
|
||||
messaging_stub_->async()->SendMessageExpress(
|
||||
&rpc_state->context, &rpc_state->request, &rpc_state->response,
|
||||
[&success, &latch, rpc_state](grpc::Status status) {
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "SendMessageExpress failed: "
|
||||
<< rpc::GrpcStatusToAbslStatus(status);
|
||||
}
|
||||
success = status.ok();
|
||||
latch.CountDown();
|
||||
});
|
||||
});
|
||||
latch.Await();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace nearby::connections::mediums
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_TACHYON_MESSAGING_CLIENT_H_
|
||||
#define CORE_INTERNAL_MEDIUMS_WEBRTC_TACHYON_MESSAGING_CLIENT_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "location/nearby/sharing/lib/account/account_manager.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "third_party/grpc/include/grpcpp/client_context.h"
|
||||
#include "third_party/grpc/include/grpcpp/support/client_callback.h"
|
||||
#include "third_party/grpc/include/grpcpp/support/status.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/implementation/webrtc.h"
|
||||
#include "internal/proto/messaging.grpc.pb.h"
|
||||
|
||||
namespace nearby::connections::mediums {
|
||||
|
||||
// Interface for the messaging Tachyon service. See
|
||||
// third_party/nearby/internal/proto/messaging.proto
|
||||
class TachyonExpressSignalingMessenger : public api::WebRtcSignalingMessenger {
|
||||
public:
|
||||
explicit TachyonExpressSignalingMessenger(
|
||||
absl::string_view self_id,
|
||||
const location::nearby::connections::LocationHint& location_hint);
|
||||
|
||||
class ReceiveMessagesReader
|
||||
: public grpc::ClientReadReactor<
|
||||
google::internal::communications::instantmessaging::v1::
|
||||
ReceiveMessagesResponse> {
|
||||
public:
|
||||
ReceiveMessagesReader() = default;
|
||||
|
||||
void OnReadDone(bool ok) override;
|
||||
void OnDone(const grpc::Status& s) override;
|
||||
|
||||
bool Start(
|
||||
google::internal::communications::instantmessaging::v1::grpc::
|
||||
Messaging::StubInterface* stub,
|
||||
absl::string_view self_id,
|
||||
const location::nearby::connections::LocationHint& location_hint,
|
||||
absl::string_view access_token,
|
||||
absl::AnyInvocable<void()> on_fast_path_ready_callback,
|
||||
absl::AnyInvocable<void(const ByteArray&)> on_inbox_message_callback,
|
||||
absl::AnyInvocable<void(bool)> on_complete_callback);
|
||||
void TryCancel();
|
||||
|
||||
private:
|
||||
grpc::ClientContext context_;
|
||||
google::internal::communications::instantmessaging::v1::
|
||||
ReceiveMessagesExpressRequest request_;
|
||||
google::internal::communications::instantmessaging::v1::
|
||||
ReceiveMessagesResponse response_;
|
||||
absl::AnyInvocable<void()> on_fast_path_ready_callback_;
|
||||
absl::AnyInvocable<void(const ByteArray&)> on_inbox_message_callback_;
|
||||
absl::AnyInvocable<void(bool)> on_complete_callback_;
|
||||
|
||||
absl::Mutex mutex_;
|
||||
bool is_receiving_messages_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
};
|
||||
|
||||
bool SendMessage(absl::string_view peer_id,
|
||||
const ByteArray& message) override;
|
||||
|
||||
bool StartReceivingMessages(
|
||||
OnSignalingMessageCallback on_message_callback,
|
||||
OnSignalingCompleteCallback on_complete_callback) override;
|
||||
|
||||
void StopReceivingMessages() override;
|
||||
|
||||
private:
|
||||
std::string self_id_;
|
||||
location::nearby::connections::LocationHint location_hint_;
|
||||
std::unique_ptr<google::internal::communications::instantmessaging::v1::grpc::
|
||||
Messaging::StubInterface>
|
||||
messaging_stub_;
|
||||
nearby::sharing::AccountManager* const account_manager_;
|
||||
std::shared_ptr<ReceiveMessagesReader> reader_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace nearby::connections::mediums
|
||||
|
||||
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_TACHYON_MESSAGING_CLIENT_H_
|
||||
Reference in New Issue
Block a user