mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
Merge branch 'master' into release
Change-Id: I56ea2217899e92bdd9d6cb56797ac9895e194fff
This commit is contained in:
@@ -25,6 +25,7 @@ cc_library(
|
||||
"future.h",
|
||||
"input_file.h",
|
||||
"listenable_future.h",
|
||||
"log_message.h",
|
||||
"mutex.h",
|
||||
"output_file.h",
|
||||
"scheduled_executor.h",
|
||||
@@ -76,12 +77,14 @@ cc_library(
|
||||
"platform.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/base:__pkg__",
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
"//platform_v2/public:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":comm",
|
||||
":types",
|
||||
"//platform_v2/base",
|
||||
"//absl/strings",
|
||||
"//absl/types:any",
|
||||
],
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
#ifndef PLATFORM_V2_API_ATOMIC_REFERENCE_H_
|
||||
#define PLATFORM_V2_API_ATOMIC_REFERENCE_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// An object reference that may be updated atomically.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
|
||||
template <typename T>
|
||||
class AtomicReference {
|
||||
// Type that allows 32-bit atomic reads and writes.
|
||||
class AtomicUint32 {
|
||||
public:
|
||||
virtual ~AtomicReference() = default;
|
||||
virtual ~AtomicUint32() = default;
|
||||
|
||||
virtual T Get() const & = 0;
|
||||
virtual T Get() && = 0;
|
||||
virtual void Set(const T& value) = 0;
|
||||
virtual void Set(T&& value) = 0;
|
||||
// Atomically reads and returns stored value.
|
||||
virtual std::uint32_t Get() const = 0;
|
||||
|
||||
// Atomically stores value.
|
||||
virtual void Set(std::uint32_t value) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define PLATFORM_V2_API_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -29,10 +30,19 @@ class ConditionVariable {
|
||||
public:
|
||||
virtual ~ConditionVariable() {}
|
||||
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify--
|
||||
// Notifies all the waiters that condition state has changed.
|
||||
virtual void Notify() = 0;
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--
|
||||
virtual Exception Wait() = 0; // throws Exception::kInterrupted
|
||||
|
||||
// Waits indefinitely for Notify to be called.
|
||||
// May return prematurely in case of interrupt, if supported by platform.
|
||||
// Returns kSuccess, or kInterrupted on interrupt.
|
||||
virtual Exception Wait() = 0;
|
||||
|
||||
// Waits while timeout has not expired for Notify to be called.
|
||||
// May return prematurely in case of interrupt, if supported by platform.
|
||||
// Returns kSuccess, or kInterrupted on interrupt.
|
||||
// If Timeout expired, and Notify was not called, returns kTimeout.
|
||||
virtual Exception Wait(absl::Duration timeout) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef PLATFORM_V2_API_LOG_MESSAGE_H_
|
||||
#define PLATFORM_V2_API_LOG_MESSAGE_H_
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A log message that prints to appropraite destination when ~LogMessage() is
|
||||
// called.
|
||||
class LogMessage {
|
||||
public:
|
||||
enum class Severity {
|
||||
kInfo = 0,
|
||||
kWarning = 1,
|
||||
kError = 2,
|
||||
kFatal = 3, // Terminates the process after logging
|
||||
};
|
||||
|
||||
// Configures minimum severity to be logged.
|
||||
static void SetMinLogSeverity(Severity severity);
|
||||
|
||||
// Returns if a log with |severity| should be logged based on
|
||||
// SetMinLogSeverity and additional platform requirements.
|
||||
static bool ShouldCreateLogMessage(Severity severity);
|
||||
|
||||
virtual ~LogMessage() = default;
|
||||
|
||||
// Printf like logging.
|
||||
virtual void Print(const char* format, ...) = 0;
|
||||
|
||||
// Returns a stream for std::cout like logging.
|
||||
virtual std::ostream& Stream() = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_API_LOG_MESSAGE_H_
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "platform_v2/api/count_down_latch.h"
|
||||
#include "platform_v2/api/crypto.h"
|
||||
#include "platform_v2/api/input_file.h"
|
||||
#include "platform_v2/api/log_message.h"
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/api/output_file.h"
|
||||
#include "platform_v2/api/scheduled_executor.h"
|
||||
@@ -39,8 +40,8 @@
|
||||
#include "platform_v2/api/webrtc.h"
|
||||
#include "platform_v2/api/wifi.h"
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/payload_id.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -58,18 +59,32 @@ class ImplementationPlatform {
|
||||
// - Future<T> : to synchronize on Callable<T> schduled to execute.
|
||||
// - CountDownLatch : to ensure at least N threads are waiting.
|
||||
// - file I/O
|
||||
static std::unique_ptr<AtomicReference<absl::any>> CreateAtomicReferenceAny(
|
||||
absl::any initial_value);
|
||||
static std::unique_ptr<SettableFuture<absl::any>> CreateSettableFutureAny();
|
||||
// - Logging
|
||||
|
||||
// Atomics:
|
||||
// =======
|
||||
|
||||
// Atomic boolean: special case. Uses native platform atomics.
|
||||
// Does not use locking.
|
||||
// Does not use dynamic memory allocations in operations.
|
||||
static std::unique_ptr<AtomicBoolean> CreateAtomicBoolean(bool initial_value);
|
||||
|
||||
// Supports enums and integers up to 32-bit.
|
||||
// Does not use locking, if platform supports 32-bit atimics natively.
|
||||
// Does not use dynamic memory allocations in operations.
|
||||
static std::unique_ptr<AtomicUint32>
|
||||
CreateAtomicUint32(std::uint32_t value);
|
||||
|
||||
static std::unique_ptr<CountDownLatch> CreateCountDownLatch(
|
||||
std::int32_t count);
|
||||
static std::unique_ptr<Mutex> CreateMutex(Mutex::Mode mode);
|
||||
static std::unique_ptr<ConditionVariable> CreateConditionVariable(
|
||||
Mutex* mutex);
|
||||
static std::unique_ptr<InputFile> CreateInputFile(std::int64_t payload_id,
|
||||
static std::unique_ptr<InputFile> CreateInputFile(PayloadId payload_id,
|
||||
std::int64_t total_size);
|
||||
static std::unique_ptr<OutputFile> CreateOutputFile(std::int64_t payload_id);
|
||||
static std::unique_ptr<OutputFile> CreateOutputFile(PayloadId payload_id);
|
||||
static std::unique_ptr<LogMessage> CreateLogMessage(
|
||||
const char* file, int line, LogMessage::Severity severity);
|
||||
|
||||
// Java-like Executors
|
||||
static std::unique_ptr<SubmittableExecutor> CreateSingleThreadExecutor();
|
||||
@@ -88,7 +103,6 @@ class ImplementationPlatform {
|
||||
static std::unique_ptr<WifiMedium> CreateWifiMedium();
|
||||
static std::unique_ptr<WifiLanMedium> CreateWifiLanMedium();
|
||||
static std::unique_ptr<WebRtcMedium> CreateWebRtcMedium();
|
||||
static std::string GetDeviceId();
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -30,8 +30,15 @@ class SettableFuture : public ListenableFuture<T> {
|
||||
public:
|
||||
~SettableFuture() override = default;
|
||||
|
||||
virtual bool Set(const T& value) = 0;
|
||||
virtual bool Set(T&& value) = 0;
|
||||
// Completes the future successfully. The value is returned to any waiters.
|
||||
// Returns true, if value was set.
|
||||
// Returns false, if Future is already in "done" state.
|
||||
virtual bool Set(T value) = 0;
|
||||
|
||||
// Completes the future unsuccessfully. The exception value is returned to any
|
||||
// waiters.
|
||||
// Returns true, if exception was set.
|
||||
// Returns false, if Future is already in "done" state.
|
||||
virtual bool SetException(Exception exception) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/listeners.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
@@ -32,25 +32,33 @@ class WifiLanService {
|
||||
public:
|
||||
virtual ~WifiLanService() = default;
|
||||
|
||||
virtual std::string GetName() = 0;
|
||||
virtual std::string GetName() const = 0;
|
||||
};
|
||||
|
||||
class WifiLanSocket {
|
||||
public:
|
||||
virtual ~WifiLanSocket() = default;
|
||||
|
||||
// Returns the InputStream of the WifiLanSocket, empty std::unique_ptr<>
|
||||
// on error.
|
||||
virtual std::unique_ptr<InputStream> GetInputStream() = 0;
|
||||
// Returns the InputStream of the WifiLanSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the WifiLanSocket object is destroyed.
|
||||
virtual InputStream& GetInputStream() = 0;
|
||||
|
||||
// Returns the OutputStream of the WifiLanSocket, empty std::unique_ptr<>
|
||||
// on error.
|
||||
virtual std::unique_ptr<OutputStream> GetOutputStream() = 0;
|
||||
// Returns the OutputStream of the WifiLanSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the WifiLanSocket object is destroyed.
|
||||
virtual OutputStream& GetOutputStream() = 0;
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
virtual Exception::Value Close() = 0;
|
||||
virtual Exception Close() = 0;
|
||||
|
||||
virtual WifiLanService& GetRemoteWifiLanService() = 0;
|
||||
// Returns valid WifiLanService pointer if there is a connection, and
|
||||
// nullptr otherwise.
|
||||
virtual WifiLanService* GetRemoteWifiLanService() = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WifiLan medium.
|
||||
@@ -59,39 +67,51 @@ class WifiLanMedium {
|
||||
virtual ~WifiLanMedium() = default;
|
||||
|
||||
virtual bool StartAdvertising(
|
||||
absl::string_view service_id,
|
||||
absl::string_view wifi_lan_service_info_name) = 0;
|
||||
virtual void StopAdvertising(absl::string_view service_id) = 0;
|
||||
const std::string& service_id,
|
||||
const std::string& wifi_lan_service_info_name) = 0;
|
||||
virtual bool StopAdvertising(const std::string& service_id) = 0;
|
||||
|
||||
// Callback for WifiLan discover results.
|
||||
class DiscoveredServiceCallback {
|
||||
public:
|
||||
virtual ~DiscoveredServiceCallback() = default;
|
||||
|
||||
virtual void OnServiceDiscovered(WifiLanService* wifi_lan_service) = 0;
|
||||
virtual void OnServiceLost(WifiLanService* wifi_lan_service) = 0;
|
||||
struct DiscoveredServiceCallback {
|
||||
// The WifiLanService* is not owned by callbacks.
|
||||
// It is passed to give access to its non-const methods.
|
||||
// It is guaranteed to be valid for the duration of call.
|
||||
std::function<void(WifiLanService& wifi_lan_service,
|
||||
const std::string& service_id)>
|
||||
service_discovered_cb =
|
||||
DefaultCallback<WifiLanService&, const std::string&>();
|
||||
std::function<void(WifiLanService& wifi_lan_service,
|
||||
const std::string& service_id)>
|
||||
service_lost_cb =
|
||||
DefaultCallback<WifiLanService&, const std::string&>();
|
||||
};
|
||||
|
||||
virtual bool StartDiscovery(
|
||||
absl::string_view service_id,
|
||||
DiscoveredServiceCallback* discovered_service_callback) = 0;
|
||||
virtual void StopDiscovery(absl::string_view service_id) = 0;
|
||||
// Returns true once the WifiLan discovery has been initiated.
|
||||
virtual bool StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback) = 0;
|
||||
|
||||
class AcceptedConnectionCallback {
|
||||
public:
|
||||
virtual ~AcceptedConnectionCallback() = default;
|
||||
// Returns true once WifiLan discovery for service_id is well and truly
|
||||
// stopped; after this returns, there must be no more invocations of the
|
||||
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
|
||||
virtual bool StopDiscovery(const std::string& service_id) = 0;
|
||||
|
||||
virtual void OnConnectionAccepted(WifiLanSocket* socket,
|
||||
absl::string_view service_id) = 0;
|
||||
// Callback that is invoked when a new connection is accepted.
|
||||
struct AcceptedConnectionCallback {
|
||||
std::function<void(WifiLanSocket& socket, const std::string& service_id)>
|
||||
accepted_cb = DefaultCallback<WifiLanSocket&, const std::string&>();
|
||||
};
|
||||
|
||||
// Returns true once WifiLan socket connection requests to service_id can be
|
||||
// accepted.
|
||||
virtual bool StartAcceptingConnections(
|
||||
absl::string_view service_id,
|
||||
AcceptedConnectionCallback* accepted_connection_callback) = 0;
|
||||
virtual void StopAcceptingConnections(absl::string_view service_id) = 0;
|
||||
const std::string& service_id,
|
||||
AcceptedConnectionCallback callback) = 0;
|
||||
virtual bool StopAcceptingConnections(const std::string& service_id) = 0;
|
||||
|
||||
virtual WifiLanSocket* Connect(WifiLanService* wifi_lan_service,
|
||||
absl::string_view service_id) = 0;
|
||||
// Connects to a WifiLan service.
|
||||
// On success, returns a new WifiLanSocket.
|
||||
// On error, returns nullptr.
|
||||
virtual std::unique_ptr<WifiLanSocket> Connect(
|
||||
WifiLanService& service, const std::string& service_id) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -28,9 +28,11 @@ cc_library(
|
||||
"input_stream.h",
|
||||
"listeners.h",
|
||||
"output_stream.h",
|
||||
"payload_id.h",
|
||||
"prng.h",
|
||||
"runnable.h",
|
||||
"socket.h",
|
||||
"types.h",
|
||||
],
|
||||
visibility = [
|
||||
"//core_v2:__subpackages__",
|
||||
@@ -56,6 +58,7 @@ cc_library(
|
||||
"base_pipe.h",
|
||||
],
|
||||
visibility = [
|
||||
"//core_v2:__subpackages__",
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
"//platform_v2/public:__pkg__",
|
||||
],
|
||||
@@ -75,7 +78,8 @@ cc_library(
|
||||
"//platform_v2:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//platform:logging",
|
||||
"//platform_v2/api:platform",
|
||||
"//platform_v2/api:types",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -99,6 +103,7 @@ cc_library(
|
||||
"//platform_v2/api:comm",
|
||||
"//platform_v2/public:types",
|
||||
"//absl/container:flat_hash_map",
|
||||
"//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -41,13 +41,12 @@ class BaseInputStream : public InputStream {
|
||||
std::uint16_t ReadUint16();
|
||||
std::uint32_t ReadUint32();
|
||||
std::uint64_t ReadUint64();
|
||||
ByteArray ReadBytes(int size);
|
||||
bool IsAvailable(int size) const {
|
||||
return buffer_.size() - position_ >= size;
|
||||
}
|
||||
|
||||
private:
|
||||
ByteArray ReadBytes(int size);
|
||||
|
||||
ByteArray &buffer_;
|
||||
int position_{0};
|
||||
};
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
#ifndef PLATFORM_V2_BASE_BYTE_ARRAY_H_
|
||||
#define PLATFORM_V2_BASE_BYTE_ARRAY_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -27,13 +28,22 @@ class ByteArray {
|
||||
public:
|
||||
// Create an empty ByteArray
|
||||
ByteArray() = default;
|
||||
template <size_t N>
|
||||
explicit ByteArray(const std::array<char, N>& data) {
|
||||
SetData(data.data(), data.size());
|
||||
}
|
||||
ByteArray(const ByteArray&) = default;
|
||||
ByteArray& operator=(const ByteArray&) = default;
|
||||
ByteArray(ByteArray&&) = default;
|
||||
ByteArray& operator=(ByteArray&&) = default;
|
||||
|
||||
// Create ByteArray from string.
|
||||
explicit ByteArray(absl::string_view source) {
|
||||
// Moves string out of temporary, allowing for a zero-copy constructions.
|
||||
// This is an optimization for very large strings.
|
||||
explicit ByteArray(std::string&& source) : data_(std::move(source)) {}
|
||||
|
||||
// Create ByteArray by copy of a std::string. This can't be a string_view,
|
||||
// because it will conflict with std::string&& version of constructor.
|
||||
explicit ByteArray(const std::string& source) {
|
||||
SetData(source.data(), source.size());
|
||||
}
|
||||
|
||||
@@ -73,7 +83,12 @@ class ByteArray {
|
||||
friend bool operator!=(const ByteArray& lhs, const ByteArray& rhs);
|
||||
friend bool operator<(const ByteArray& lhs, const ByteArray& rhs);
|
||||
|
||||
explicit operator std::string() const { return data_; }
|
||||
// Returns a copy of internal representation as std::string.
|
||||
explicit operator std::string() const& { return data_; }
|
||||
|
||||
// Moves string out of temporary ByteArray, allowing for a zero-copy
|
||||
// operation.
|
||||
explicit operator std::string() const&& { return std::move(data_); }
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
|
||||
@@ -79,4 +79,12 @@ TEST(ByteArrayTest, SetExplicitData) {
|
||||
EXPECT_EQ(0, memcmp(message, bytes.data(), kMessageSize));
|
||||
}
|
||||
|
||||
TEST(ByteArrayTest, CreateFromNonNullTerminatedStdArray) {
|
||||
constexpr static const std::array data{'a', '\x00', 'b'};
|
||||
ByteArray bytes{data};
|
||||
EXPECT_EQ(bytes.size(), 3);
|
||||
EXPECT_EQ(bytes.size(), std::string(bytes).size());
|
||||
EXPECT_EQ(std::string(bytes), std::string(data.data(), data.size()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -15,6 +15,60 @@
|
||||
#ifndef PLATFORM_V2_BASE_LOGGING_H_
|
||||
#define PLATFORM_V2_BASE_LOGGING_H_
|
||||
|
||||
#include "platform/logging.h"
|
||||
#include "platform_v2/api/log_message.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// This class is used to explicitly ignore values in the conditional
|
||||
// logging macros. This avoids compiler warnings like "value computed
|
||||
// is not used" and "statement has no effect".
|
||||
class LogMessageVoidify {
|
||||
public:
|
||||
LogMessageVoidify() = default;
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(std::ostream&) {}
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
// Severity enum conversion
|
||||
#define NEARBY_SEVERITY_INFO location::nearby::api::LogMessage::Severity::kInfo
|
||||
#define NEARBY_SEVERITY_WARNING \
|
||||
location::nearby::api::LogMessage::Severity::kWarning
|
||||
#define NEARBY_SEVERITY_ERROR \
|
||||
location::nearby::api::LogMessage::Severity::kError
|
||||
#define NEARBY_SEVERITY_FATAL \
|
||||
location::nearby::api::LogMessage::Severity::kFatal
|
||||
|
||||
#define NEARBY_SEVERITY(severity) NEARBY_SEVERITY_##severity
|
||||
|
||||
// Log enabling
|
||||
#define NEARBY_LOG_IS_ON(severity) \
|
||||
location::nearby::api::LogMessage::ShouldCreateLogMessage( \
|
||||
NEARBY_SEVERITY(severity))
|
||||
|
||||
#define NEARBY_LOG_SET_SEVERITY(severity) \
|
||||
location::nearby::api::LogMessage::SetMinLogSeverity( \
|
||||
NEARBY_SEVERITY(severity))
|
||||
|
||||
// Log message creation
|
||||
#define NEARBY_LOG_MESSAGE(severity) \
|
||||
location::nearby::api::ImplementationPlatform::CreateLogMessage( \
|
||||
__FILE__, __LINE__, NEARBY_SEVERITY(severity))
|
||||
|
||||
// Public APIs
|
||||
// The stream statement must come last or otherwise it won't compile.
|
||||
#define NEARBY_LOGS(severity) \
|
||||
!(NEARBY_LOG_IS_ON(severity)) ? (void)0 \
|
||||
: location::nearby::LogMessageVoidify() & \
|
||||
NEARBY_LOG_MESSAGE(severity)->Stream()
|
||||
|
||||
#define NEARBY_LOG(severity, ...) \
|
||||
NEARBY_LOG_IS_ON(severity) \
|
||||
? NEARBY_LOG_MESSAGE(severity)->Print(__VA_ARGS__) : (void)0
|
||||
|
||||
#endif // PLATFORM_V2_BASE_LOGGING_H_
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/logging.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
|
||||
@@ -54,6 +55,7 @@ void MediumEnvironment::Reset() {
|
||||
NEARBY_LOG(INFO, "MediumEnvironment::Reset()");
|
||||
bluetooth_adapters_.clear();
|
||||
bluetooth_mediums_.clear();
|
||||
wifi_lan_mediums_.clear();
|
||||
});
|
||||
Sync();
|
||||
}
|
||||
@@ -91,7 +93,7 @@ void MediumEnvironment::OnBluetoothAdapterChangedState(
|
||||
if (info.adapter == &adapter) continue;
|
||||
NEARBY_LOG(INFO, "[adapter=%p, device=%p] notify: adapter=%p", &adapter,
|
||||
&adapter_device, info.adapter);
|
||||
OnDeviceStateChanged(info, adapter_device, name, mode, enabled);
|
||||
OnBluetoothDeviceStateChanged(info, adapter_device, name, mode, enabled);
|
||||
}
|
||||
// We don't care if there is an adapter already since all we store is a
|
||||
// pointer. Pointer must remain valid for the duration of a Core session
|
||||
@@ -101,16 +103,17 @@ void MediumEnvironment::OnBluetoothAdapterChangedState(
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::OnDeviceStateChanged(
|
||||
void MediumEnvironment::OnBluetoothDeviceStateChanged(
|
||||
BluetoothMediumContext& info, api::BluetoothDevice& device,
|
||||
const std::string& name, api::BluetoothAdapter::ScanMode mode,
|
||||
bool enabled) {
|
||||
if (!enabled_) return;
|
||||
auto item = info.devices.find(&device);
|
||||
if (item == info.devices.end()) {
|
||||
NEARBY_LOG(
|
||||
INFO, "G3 OnDeviceStateChanged [device impl=%p]: new device; notify=%d",
|
||||
&device, enable_notifications_.load());
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 OnBluetoothDeviceStateChanged [device impl=%p]: new device; "
|
||||
"notify=%d",
|
||||
&device, enable_notifications_.load());
|
||||
if (mode == api::BluetoothAdapter::ScanMode::kConnectableDiscoverable &&
|
||||
enabled) {
|
||||
// New device is turned on, and is in discoverable state.
|
||||
@@ -122,10 +125,10 @@ void MediumEnvironment::OnDeviceStateChanged(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"G3 OnDeviceStateChanged [device impl=%p]: exisitng device; notify=%d",
|
||||
&device, enable_notifications_.load());
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 OnBluetoothDeviceStateChanged [device impl=%p]: exisitng "
|
||||
"device; notify=%d",
|
||||
&device, enable_notifications_.load());
|
||||
auto& discovered_name = item->second;
|
||||
if (mode == api::BluetoothAdapter::ScanMode::kConnectableDiscoverable &&
|
||||
enabled) {
|
||||
@@ -159,6 +162,39 @@ void MediumEnvironment::OnDeviceStateChanged(
|
||||
}
|
||||
}
|
||||
|
||||
void MediumEnvironment::OnWifiLanServiceStateChanged(
|
||||
WifiLanMediumContext& info, api::WifiLanService& service,
|
||||
const std::string& service_id, bool enabled) {
|
||||
if (!enabled_) return;
|
||||
auto item = info.services.find(&service);
|
||||
if (item == info.services.end()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 OnWifiLanServiceStateChanged [service impl=%p]: new service",
|
||||
&service);
|
||||
info.services.emplace(&service, service.GetName());
|
||||
if (enabled) {
|
||||
RunOnMediumEnvironmentThread([&info, &service, service_id]() {
|
||||
info.discovery_callback.service_discovered_cb(service, service_id);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 OnWifiLanServiceStateChanged [service impl=%p]: exisitng "
|
||||
"service",
|
||||
&service);
|
||||
if (enabled) {
|
||||
RunOnMediumEnvironmentThread([&info, &service, service_id]() {
|
||||
info.discovery_callback.service_discovered_cb(service, service_id);
|
||||
});
|
||||
} else {
|
||||
RunOnMediumEnvironmentThread([&info, &service, service_id]() {
|
||||
info.discovery_callback.service_lost_cb(service, service_id);
|
||||
});
|
||||
info.services.erase(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediumEnvironment::RunOnMediumEnvironmentThread(
|
||||
std::function<void()> runnable) {
|
||||
job_count_++;
|
||||
@@ -181,8 +217,9 @@ void MediumEnvironment::RegisterBluetoothMedium(
|
||||
owned_adapter);
|
||||
for (auto& [adapter, device] : bluetooth_adapters_) {
|
||||
if (adapter == nullptr) continue;
|
||||
OnDeviceStateChanged(context, *device, adapter->GetName(),
|
||||
adapter->GetScanMode(), adapter->IsEnabled());
|
||||
OnBluetoothDeviceStateChanged(context, *device, adapter->GetName(),
|
||||
adapter->GetScanMode(),
|
||||
adapter->IsEnabled());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -204,8 +241,9 @@ void MediumEnvironment::UpdateBluetoothMedium(
|
||||
owned_adapter->IsEnabled(), owned_adapter->GetScanMode());
|
||||
for (auto& [adapter, device] : bluetooth_adapters_) {
|
||||
if (adapter == nullptr) continue;
|
||||
OnDeviceStateChanged(context, *device, adapter->GetName(),
|
||||
adapter->GetScanMode(), adapter->IsEnabled());
|
||||
OnBluetoothDeviceStateChanged(context, *device, adapter->GetName(),
|
||||
adapter->GetScanMode(),
|
||||
adapter->IsEnabled());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -222,5 +260,100 @@ void MediumEnvironment::UnregisterBluetoothMedium(
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::RegisterWebRtcSignalingMessenger(
|
||||
absl::string_view self_id, OnSignalingMessageCallback callback) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread(
|
||||
[this, self_id{std::string(self_id)}, callback{std::move(callback)}]() {
|
||||
webrtc_signaling_callback_[self_id] = std::move(callback);
|
||||
NEARBY_LOG(INFO, "Registered signaling message callback for id = %s",
|
||||
self_id.c_str());
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UnregisterWebRtcSignalingMessenger(
|
||||
absl::string_view self_id) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, self_id{std::string(self_id)}]() {
|
||||
auto item = webrtc_signaling_callback_.extract(self_id);
|
||||
if (item.empty()) return;
|
||||
NEARBY_LOG(INFO, "Unregistered signaling message callback for id = %s",
|
||||
self_id.c_str());
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::SendWebRtcSignalingMessage(absl::string_view peer_id,
|
||||
const ByteArray& message) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread(
|
||||
[this, peer_id{std::string(peer_id)}, message]() {
|
||||
auto item = webrtc_signaling_callback_.find(peer_id);
|
||||
if (item == webrtc_signaling_callback_.end()) {
|
||||
NEARBY_LOG(WARNING, "No callback registered for peer id = %s",
|
||||
peer_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
item->second(message);
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::RegisterWifiLanMedium(api::WifiLanMedium& medium) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium]() {
|
||||
wifi_lan_mediums_.insert({&medium, WifiLanMediumContext{}});
|
||||
NEARBY_LOG(INFO, "Registered: medium=%p", &medium);
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UpdateWifiLanMediumForDiscovery(
|
||||
api::WifiLanMedium& medium, api::WifiLanService& service,
|
||||
const std::string& service_id, WifiLanDiscoveredServiceCallback callback,
|
||||
bool enabled) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium, &service, service_id,
|
||||
callback = std::move(callback), enabled]() {
|
||||
auto item = wifi_lan_mediums_.find(&medium);
|
||||
if (item == wifi_lan_mediums_.end()) {
|
||||
NEARBY_LOG(
|
||||
INFO, "Update WifiLan medium failed. There is no medium registered.");
|
||||
return;
|
||||
}
|
||||
auto& context = item->second;
|
||||
context.discovery_callback = std::move(callback);
|
||||
NEARBY_LOG(INFO, "Updated: this=%p; medium=%p", this, &medium);
|
||||
OnWifiLanServiceStateChanged(context, service, service_id, enabled);
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UpdateWifiLanMediumForAcceptedConnection(
|
||||
api::WifiLanMedium& medium, const std::string& service_id,
|
||||
WifiLanAcceptedConnectionCallback accepted_connection_callback) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium,
|
||||
accepted_connection_callback =
|
||||
std::move(accepted_connection_callback)]() {
|
||||
auto item = wifi_lan_mediums_.find(&medium);
|
||||
if (item == wifi_lan_mediums_.end()) {
|
||||
NEARBY_LOG(
|
||||
INFO, "Update WifiLan medium failed. There is no medium registered.");
|
||||
return;
|
||||
}
|
||||
auto& context = item->second;
|
||||
context.accepted_connection_callback =
|
||||
std::move(accepted_connection_callback);
|
||||
NEARBY_LOG(INFO, "Updated: this=%p; medium=%p", this, &medium);
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UnregisterWifiLanMedium(api::WifiLanMedium& medium) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium]() {
|
||||
auto item = wifi_lan_mediums_.extract(&medium);
|
||||
if (item.empty()) return;
|
||||
NEARBY_LOG(INFO, "Unregistered WifiLan medium");
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -19,9 +19,12 @@
|
||||
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/api/webrtc.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/listeners.h"
|
||||
#include "platform_v2/public/single_thread_executor.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -35,6 +38,12 @@ class MediumEnvironment {
|
||||
public:
|
||||
using BluetoothDiscoveryCallback =
|
||||
api::BluetoothClassicMedium::DiscoveryCallback;
|
||||
using OnSignalingMessageCallback =
|
||||
api::WebRtcSignalingMessenger::OnSignalingMessageCallback;
|
||||
using WifiLanDiscoveredServiceCallback =
|
||||
api::WifiLanMedium::DiscoveredServiceCallback;
|
||||
using WifiLanAcceptedConnectionCallback =
|
||||
api::WifiLanMedium::AcceptedConnectionCallback;
|
||||
MediumEnvironment(const MediumEnvironment&) = delete;
|
||||
MediumEnvironment& operator=(const MediumEnvironment&) = delete;
|
||||
|
||||
@@ -98,6 +107,28 @@ class MediumEnvironment {
|
||||
// Removes medium-related info. This should correspond to device power off.
|
||||
void UnregisterBluetoothMedium(api::BluetoothClassicMedium& medium);
|
||||
|
||||
// Registers |callback| to receive messages sent to device with id |self_id|.
|
||||
void RegisterWebRtcSignalingMessenger(absl::string_view self_id,
|
||||
OnSignalingMessageCallback callback);
|
||||
|
||||
// Unregisters the callback listening to incoming messages for |self_id|.
|
||||
void UnregisterWebRtcSignalingMessenger(absl::string_view self_id);
|
||||
|
||||
// Simulates sending a signaling message |message| to device with id
|
||||
// |peer_id|.
|
||||
void SendWebRtcSignalingMessage(absl::string_view peer_id,
|
||||
const ByteArray& message);
|
||||
// Wifi-Lan medium registration/update calls.
|
||||
void RegisterWifiLanMedium(api::WifiLanMedium& medium);
|
||||
void UpdateWifiLanMediumForDiscovery(
|
||||
api::WifiLanMedium& medium, api::WifiLanService& service,
|
||||
const std::string& service_id,
|
||||
WifiLanDiscoveredServiceCallback discovery_callback, bool enabled);
|
||||
void UpdateWifiLanMediumForAcceptedConnection(
|
||||
api::WifiLanMedium& medium, const std::string& service_id,
|
||||
WifiLanAcceptedConnectionCallback accepted_connection_callback);
|
||||
void UnregisterWifiLanMedium(api::WifiLanMedium& medium);
|
||||
|
||||
private:
|
||||
struct BluetoothMediumContext {
|
||||
BluetoothDiscoveryCallback callback;
|
||||
@@ -106,6 +137,13 @@ class MediumEnvironment {
|
||||
absl::flat_hash_map<api::BluetoothDevice*, std::string> devices;
|
||||
};
|
||||
|
||||
struct WifiLanMediumContext {
|
||||
WifiLanDiscoveredServiceCallback discovery_callback;
|
||||
WifiLanAcceptedConnectionCallback accepted_connection_callback;
|
||||
// discovered service vs service name map.
|
||||
absl::flat_hash_map<api::WifiLanService*, std::string> services;
|
||||
};
|
||||
|
||||
// This is a singleton object, for which destructor will never be called.
|
||||
// Constructor will be invoked once from Instance() static method.
|
||||
// Object is create in-place (with a placement new) to guarantee that
|
||||
@@ -113,10 +151,17 @@ class MediumEnvironment {
|
||||
MediumEnvironment() = default;
|
||||
~MediumEnvironment() = default;
|
||||
|
||||
void OnDeviceStateChanged(BluetoothMediumContext& info,
|
||||
api::BluetoothDevice& device,
|
||||
const std::string& name,
|
||||
api::BluetoothAdapter::ScanMode mode, bool enabled);
|
||||
void OnBluetoothDeviceStateChanged(BluetoothMediumContext& info,
|
||||
api::BluetoothDevice& device,
|
||||
const std::string& name,
|
||||
api::BluetoothAdapter::ScanMode mode,
|
||||
bool enabled);
|
||||
|
||||
void OnWifiLanServiceStateChanged(WifiLanMediumContext& info,
|
||||
api::WifiLanService& service,
|
||||
const std::string& service_id,
|
||||
bool enabled);
|
||||
|
||||
void RunOnMediumEnvironmentThread(std::function<void()> runnable);
|
||||
|
||||
std::atomic_bool enabled_ = true;
|
||||
@@ -130,6 +175,13 @@ class MediumEnvironment {
|
||||
bluetooth_adapters_;
|
||||
absl::flat_hash_map<api::BluetoothClassicMedium*, BluetoothMediumContext>
|
||||
bluetooth_mediums_;
|
||||
|
||||
// Maps peer id to callback for receiving signaling messages.
|
||||
absl::flat_hash_map<std::string, OnSignalingMessageCallback>
|
||||
webrtc_signaling_callback_;
|
||||
|
||||
absl::flat_hash_map<api::WifiLanMedium*, WifiLanMediumContext>
|
||||
wifi_lan_mediums_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef PLATFORM_V2_BASE_PAYLOAD_ID_H_
|
||||
#define PLATFORM_V2_BASE_PAYLOAD_ID_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
using PayloadId = std::int64_t;
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_PAYLOAD_ID_H_
|
||||
@@ -52,7 +52,7 @@ std::uint32_t Prng::NextUint32() {
|
||||
|
||||
std::int64_t Prng::NextInt64() {
|
||||
return (static_cast<std::int64_t>(NextInt32()) << 32) |
|
||||
(static_cast<std::int64_t>(NextInt32()));
|
||||
(static_cast<std::int64_t>(NextUint32()));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
enum class TestMode {
|
||||
kUpperHalfOfInt64,
|
||||
kLowerHalfOfInt64,
|
||||
kInt32,
|
||||
kUint32,
|
||||
};
|
||||
|
||||
TEST(PrngTest, NextInt32) {
|
||||
std::int32_t i = Prng().NextInt32();
|
||||
EXPECT_LE(i, std::numeric_limits<std::int32_t>::max());
|
||||
@@ -37,5 +44,48 @@ TEST(PrngTest, NextInt64) {
|
||||
EXPECT_GE(i, std::numeric_limits<std::int64_t>::min());
|
||||
}
|
||||
|
||||
void ValidateRandom(TestMode mode) {
|
||||
int count_all_zeros = 0;
|
||||
int count_all_ones = 0;
|
||||
std::uint32_t i;
|
||||
Prng prng;
|
||||
for (int count = 0; count < 100; ++count) {
|
||||
switch (mode) {
|
||||
case TestMode::kUpperHalfOfInt64:
|
||||
i = static_cast<std::uint32_t>(prng.NextInt64() >> 32);
|
||||
break;
|
||||
case TestMode::kLowerHalfOfInt64:
|
||||
i = static_cast<std::uint32_t>(prng.NextInt64());
|
||||
break;
|
||||
case TestMode::kInt32:
|
||||
i = static_cast<std::uint32_t>(prng.NextInt32());
|
||||
break;
|
||||
case TestMode::kUint32:
|
||||
i = static_cast<std::uint32_t>(prng.NextUint32());
|
||||
break;
|
||||
}
|
||||
if (!i) count_all_zeros++;
|
||||
if (i == 0xFFFFFFFF) count_all_ones++;
|
||||
}
|
||||
EXPECT_LE(count_all_zeros, 1);
|
||||
EXPECT_LE(count_all_ones, 1);
|
||||
}
|
||||
|
||||
TEST(PrngTest, ValidateUpperHalfOfInt64) {
|
||||
ValidateRandom(TestMode::kUpperHalfOfInt64);
|
||||
}
|
||||
|
||||
TEST(PrngTest, ValidateLowerHalfOfInt64) {
|
||||
ValidateRandom(TestMode::kLowerHalfOfInt64);
|
||||
}
|
||||
|
||||
TEST(PrngTest, ValidateInt32) {
|
||||
ValidateRandom(TestMode::kInt32);
|
||||
}
|
||||
|
||||
TEST(PrngTest, ValidateUint32) {
|
||||
ValidateRandom(TestMode::kUint32);
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef PLATFORM_V2_BASE_TYPES_H_
|
||||
#define PLATFORM_V2_BASE_TYPES_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// Similar to static_cast, but will assert that Derived is a derived type of
|
||||
// Base.
|
||||
// Usage:
|
||||
// class A {};
|
||||
// class B : public A {};
|
||||
// class C {};
|
||||
// B b;
|
||||
// A* a = &b;
|
||||
// B* b2 = down_cast<B*>(a); // This is OK.
|
||||
// C* c = down_cast<C*>(a); // This will fail to compile.
|
||||
template <typename Derived, typename Base>
|
||||
inline Derived down_cast(Base* value) {
|
||||
using DerivedType = typename std::remove_pointer<Derived>::type;
|
||||
static_assert(std::is_base_of<Base, DerivedType>::value);
|
||||
return static_cast<Derived>(value);
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_TYPES_H_
|
||||
@@ -16,25 +16,27 @@ cc_library(
|
||||
name = "types",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"log_message.cc",
|
||||
"scheduled_executor.cc",
|
||||
"system_clock.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"atomic_boolean.h",
|
||||
"atomic_reference_any.h",
|
||||
"atomic_reference.h",
|
||||
"condition_variable.h",
|
||||
"count_down_latch.h",
|
||||
"log_message.h",
|
||||
"multi_thread_executor.h",
|
||||
"mutex.h",
|
||||
"pipe.h",
|
||||
"scheduled_executor.h",
|
||||
"settable_future_any.h",
|
||||
"single_thread_executor.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/impl/g3:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//base",
|
||||
"//platform_v2/api:platform",
|
||||
"//platform_v2/api:types",
|
||||
"//platform_v2/base",
|
||||
@@ -55,11 +57,13 @@ cc_library(
|
||||
"bluetooth_adapter.cc",
|
||||
"bluetooth_classic.cc",
|
||||
"webrtc.cc",
|
||||
"wifi_lan.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"bluetooth_adapter.h",
|
||||
"bluetooth_classic.h",
|
||||
"webrtc.h",
|
||||
"wifi_lan.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/impl/g3:__pkg__",
|
||||
@@ -119,6 +123,7 @@ cc_library(
|
||||
"//platform_v2/impl/shared:file",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/memory",
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_H_
|
||||
#define PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class AtomicUint32 : public api::AtomicUint32 {
|
||||
public:
|
||||
explicit AtomicUint32(std::int32_t value) : value_(value) {}
|
||||
~AtomicUint32() override = default;
|
||||
|
||||
std::uint32_t Get() const override {
|
||||
return value_;
|
||||
}
|
||||
void Set(std::uint32_t value) override {
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<std::uint32_t> value_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_H_
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright 2020 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 PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_ANY_H_
|
||||
#define PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_ANY_H_
|
||||
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "absl/base/integral_types.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// Provide implementation for absl::any.
|
||||
class AtomicReferenceAny : public api::AtomicReference<absl::any> {
|
||||
public:
|
||||
explicit AtomicReferenceAny(absl::any initial_value)
|
||||
: value_(std::move(initial_value)) {}
|
||||
~AtomicReferenceAny() override = default;
|
||||
|
||||
absl::any Get() const & override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return value_;
|
||||
}
|
||||
absl::any Get() && override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return std::move(value_);
|
||||
}
|
||||
void Set(const absl::any& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
value_ = value;
|
||||
}
|
||||
void Set(absl::any&& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
value_ = std::move(value);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable absl::Mutex mutex_;
|
||||
absl::any value_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_ATOMIC_REFERENCE_ANY_H_
|
||||
@@ -27,9 +27,15 @@ namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
BluetoothSocket::~BluetoothSocket() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
DoClose();
|
||||
}
|
||||
|
||||
void BluetoothSocket::Connect(BluetoothSocket& other) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
remote_socket_ = &other;
|
||||
input_ = other.output_;
|
||||
}
|
||||
|
||||
bool BluetoothSocket::IsConnected() const {
|
||||
@@ -43,7 +49,7 @@ bool BluetoothSocket::IsClosed() const {
|
||||
}
|
||||
|
||||
bool BluetoothSocket::IsConnectedLocked() const {
|
||||
return remote_socket_ != nullptr;
|
||||
return input_ != nullptr;
|
||||
}
|
||||
|
||||
InputStream& BluetoothSocket::GetInputStream() {
|
||||
@@ -58,31 +64,31 @@ OutputStream& BluetoothSocket::GetOutputStream() {
|
||||
|
||||
InputStream& BluetoothSocket::GetLocalInputStream() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return output_.GetInputStream();
|
||||
return output_->GetInputStream();
|
||||
}
|
||||
|
||||
OutputStream& BluetoothSocket::GetLocalOutputStream() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return output_.GetOutputStream();
|
||||
return output_->GetOutputStream();
|
||||
}
|
||||
|
||||
Exception BluetoothSocket::Close() {
|
||||
BluetoothSocket* remote_socket = nullptr;
|
||||
{
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!closed_) {
|
||||
remote_socket = remote_socket_;
|
||||
output_.GetOutputStream().Close();
|
||||
output_.GetInputStream().Close();
|
||||
closed_ = true;
|
||||
}
|
||||
}
|
||||
if (remote_socket != nullptr) {
|
||||
remote_socket->Close();
|
||||
}
|
||||
absl::MutexLock lock(&mutex_);
|
||||
DoClose();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
void BluetoothSocket::DoClose() {
|
||||
if (!closed_) {
|
||||
remote_socket_ = nullptr;
|
||||
output_->GetOutputStream().Close();
|
||||
output_->GetInputStream().Close();
|
||||
input_->GetOutputStream().Close();
|
||||
input_->GetInputStream().Close();
|
||||
closed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothSocket* BluetoothSocket::GetRemoteSocket() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return remote_socket_;
|
||||
|
||||
@@ -39,7 +39,7 @@ class BluetoothSocket : public api::BluetoothSocket {
|
||||
public:
|
||||
BluetoothSocket() = default;
|
||||
explicit BluetoothSocket(BluetoothAdapter* adapter) : adapter_(adapter) {}
|
||||
~BluetoothSocket() override = default;
|
||||
~BluetoothSocket() override;
|
||||
|
||||
// Connects to another BluetoothSocket, to form a functional low-level
|
||||
// channel. From this point on, and until Close is called, connection exists.
|
||||
@@ -78,6 +78,8 @@ class BluetoothSocket : public api::BluetoothSocket {
|
||||
BluetoothDevice* GetRemoteDevice() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Returns true if connection exists to the (possibly closed) remote socket.
|
||||
bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
@@ -94,7 +96,8 @@ class BluetoothSocket : public api::BluetoothSocket {
|
||||
// Output pipe is initialized by constructor, it remains always valid, until
|
||||
// it is closed. it represents output part of a local socket. Input part of a
|
||||
// local socket comes from the peer socket, after connection.
|
||||
Pipe output_;
|
||||
std::shared_ptr<Pipe> output_ {new Pipe};
|
||||
std::shared_ptr<Pipe> input_;
|
||||
mutable absl::Mutex mutex_;
|
||||
BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only.
|
||||
BluetoothSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
|
||||
|
||||
@@ -33,6 +33,11 @@ class ConditionVariable : public api::ConditionVariable {
|
||||
cond_var_.Wait(mutex_);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
Exception Wait(absl::Duration timeout) override {
|
||||
return cond_var_.WaitWithTimeout(mutex_, timeout)
|
||||
? Exception{Exception::kTimeout}
|
||||
: Exception{Exception::kSuccess};
|
||||
}
|
||||
void Notify() override { cond_var_.SignalAll(); }
|
||||
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "platform_v2/impl/g3/log_message.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/stringprintf.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
api::LogMessage::Severity g_min_log_severity = api::LogMessage::Severity::kInfo;
|
||||
|
||||
inline absl::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) {
|
||||
switch (severity) {
|
||||
case api::LogMessage::Severity::kInfo:
|
||||
return absl::LogSeverity::kInfo;
|
||||
case api::LogMessage::Severity::kWarning:
|
||||
return absl::LogSeverity::kWarning;
|
||||
case api::LogMessage::Severity::kError:
|
||||
return absl::LogSeverity::kError;
|
||||
case api::LogMessage::Severity::kFatal:
|
||||
return absl::LogSeverity::kFatal;
|
||||
}
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, Severity severity)
|
||||
: log_streamer_(ConvertSeverity(severity), file, line) {}
|
||||
|
||||
LogMessage::~LogMessage() = default;
|
||||
|
||||
void LogMessage::Print(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string result;
|
||||
StringAppendV(&result, format, ap);
|
||||
log_streamer_.stream() << result;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
|
||||
|
||||
} // namespace g3
|
||||
|
||||
namespace api {
|
||||
|
||||
void LogMessage::SetMinLogSeverity(Severity severity) {
|
||||
g3::g_min_log_severity = severity;
|
||||
}
|
||||
|
||||
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
|
||||
return severity >= g3::g_min_log_severity;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_LOG_MESSAGE_H_
|
||||
#define PLATFORM_V2_IMPL_G3_LOG_MESSAGE_H_
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "platform_v2/api/log_message.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// See documentation in cpp/platform_v2/api/log_message.h
|
||||
class LogMessage : public api::LogMessage {
|
||||
public:
|
||||
LogMessage(const char* file, int line, Severity severity);
|
||||
~LogMessage() override;
|
||||
|
||||
void Print(const char* format, ...) override;
|
||||
|
||||
std::ostream& Stream() override;
|
||||
|
||||
private:
|
||||
absl::LogStreamer log_streamer_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_LOG_MESSAGE_H_
|
||||
@@ -25,28 +25,30 @@
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/api/condition_variable.h"
|
||||
#include "platform_v2/api/count_down_latch.h"
|
||||
#include "platform_v2/api/log_message.h"
|
||||
#include "platform_v2/api/mutex.h"
|
||||
#include "platform_v2/api/scheduled_executor.h"
|
||||
#include "platform_v2/api/server_sync.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "platform_v2/api/submittable_executor.h"
|
||||
#include "platform_v2/api/webrtc.h"
|
||||
#include "platform_v2/api/wifi.h"
|
||||
#include "platform_v2/impl/g3/atomic_boolean.h"
|
||||
#include "platform_v2/impl/g3/atomic_reference_any.h"
|
||||
#include "platform_v2/impl/g3/atomic_reference.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_adapter.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_classic.h"
|
||||
#include "platform_v2/impl/g3/condition_variable.h"
|
||||
#include "platform_v2/impl/g3/count_down_latch.h"
|
||||
#include "platform_v2/impl/g3/log_message.h"
|
||||
#include "platform_v2/impl/g3/multi_thread_executor.h"
|
||||
#include "platform_v2/impl/g3/mutex.h"
|
||||
#include "platform_v2/impl/g3/scheduled_executor.h"
|
||||
#include "platform_v2/impl/g3/settable_future_any.h"
|
||||
#include "platform_v2/impl/g3/single_thread_executor.h"
|
||||
#include "platform_v2/impl/g3/webrtc.h"
|
||||
#include "platform_v2/impl/g3/wifi_lan.h"
|
||||
#include "platform_v2/impl/shared/file.h"
|
||||
#include "absl/base/integral_types.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
@@ -54,8 +56,8 @@ namespace nearby {
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
std::string GetPayloadPath(std::int64_t payload_id) {
|
||||
return "/tmp/" + std::to_string(payload_id);
|
||||
std::string GetPayloadPath(PayloadId payload_id) {
|
||||
return absl::StrCat("/tmp/", payload_id);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -74,14 +76,9 @@ ImplementationPlatform::CreateScheduledExecutor() {
|
||||
return absl::make_unique<g3::ScheduledExecutor>();
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicReference<absl::any>>
|
||||
ImplementationPlatform::CreateAtomicReferenceAny(absl::any initial_value) {
|
||||
return absl::make_unique<g3::AtomicReferenceAny>(initial_value);
|
||||
}
|
||||
|
||||
std::unique_ptr<SettableFuture<absl::any>>
|
||||
ImplementationPlatform::CreateSettableFutureAny() {
|
||||
return absl::make_unique<g3::SettableFutureAny>();
|
||||
std::unique_ptr<AtomicUint32>
|
||||
ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) {
|
||||
return absl::make_unique<g3::AtomicUint32>(value);
|
||||
}
|
||||
|
||||
std::unique_ptr<BluetoothAdapter>
|
||||
@@ -100,16 +97,21 @@ std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
|
||||
}
|
||||
|
||||
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
|
||||
std::int64_t payload_id, std::int64_t total_size) {
|
||||
PayloadId payload_id, std::int64_t total_size) {
|
||||
return absl::make_unique<shared::InputFile>(GetPayloadPath(payload_id),
|
||||
total_size);
|
||||
}
|
||||
|
||||
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
|
||||
std::int64_t payload_id) {
|
||||
PayloadId payload_id) {
|
||||
return absl::make_unique<shared::OutputFile>(GetPayloadPath(payload_id));
|
||||
}
|
||||
|
||||
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
|
||||
const char* file, int line, LogMessage::Severity severity) {
|
||||
return absl::make_unique<g3::LogMessage>(file, line, severity);
|
||||
}
|
||||
|
||||
std::unique_ptr<BluetoothClassicMedium>
|
||||
ImplementationPlatform::CreateBluetoothClassicMedium(
|
||||
api::BluetoothAdapter& adapter) {
|
||||
@@ -136,7 +138,7 @@ std::unique_ptr<WifiMedium> ImplementationPlatform::CreateWifiMedium() {
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiLanMedium> ImplementationPlatform::CreateWifiLanMedium() {
|
||||
return std::unique_ptr<WifiLanMedium>();
|
||||
return absl::make_unique<g3::WifiLanMedium>();
|
||||
}
|
||||
|
||||
std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() {
|
||||
@@ -156,11 +158,6 @@ ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
|
||||
new g3::ConditionVariable(static_cast<g3::Mutex*>(mutex)));
|
||||
}
|
||||
|
||||
std::string ImplementationPlatform::GetDeviceId() {
|
||||
// TODO(alexchau): Get deviceId from base
|
||||
return "google3";
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
// Copyright 2020 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 PLATFORM_V2_IMPL_G3_SETTABLE_FUTURE_ANY_H_
|
||||
#define PLATFORM_V2_IMPL_G3_SETTABLE_FUTURE_ANY_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class SettableFutureAny : public api::SettableFuture<absl::any> {
|
||||
public:
|
||||
SettableFutureAny() = default;
|
||||
~SettableFutureAny() override = default;
|
||||
|
||||
bool Set(const absl::any& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!done_) {
|
||||
value_ = value;
|
||||
done_ = true;
|
||||
exception_ = {Exception::kSuccess};
|
||||
completed_.SignalAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Set(absl::any&& value) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (!done_) {
|
||||
value_ = std::move(value);
|
||||
done_ = true;
|
||||
exception_ = {Exception::kSuccess};
|
||||
completed_.SignalAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetException(Exception exception) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return SetExceptionLocked(exception);
|
||||
}
|
||||
|
||||
void AddListener(Runnable runnable, api::Executor* executor) override {}
|
||||
|
||||
ExceptionOr<std::any> Get() override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
while (!done_) {
|
||||
completed_.Wait(&mutex_);
|
||||
}
|
||||
return exception_.value != Exception::kSuccess
|
||||
? ExceptionOr<std::any>{exception_.value}
|
||||
: ExceptionOr<std::any>{value_};
|
||||
}
|
||||
|
||||
ExceptionOr<std::any> Get(absl::Duration timeout) override {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
while (!done_) {
|
||||
absl::Time start_time = absl::Now();
|
||||
if (completed_.WaitWithTimeout(&mutex_, timeout)) {
|
||||
SetExceptionLocked({Exception::kTimeout});
|
||||
break;
|
||||
}
|
||||
absl::Duration spent = absl::Now() - start_time;
|
||||
if (spent < timeout) {
|
||||
timeout -= spent;
|
||||
} else if (!done_) {
|
||||
SetExceptionLocked({Exception::kTimeout});
|
||||
break;
|
||||
}
|
||||
}
|
||||
return exception_.value != Exception::kSuccess
|
||||
? ExceptionOr<std::any>{exception_.value}
|
||||
: ExceptionOr<std::any>{value_};
|
||||
}
|
||||
|
||||
private:
|
||||
bool SetExceptionLocked(Exception exception) {
|
||||
if (!done_) {
|
||||
exception_ = exception.value != Exception::kSuccess
|
||||
? exception
|
||||
: Exception{Exception::kFailed};
|
||||
done_ = true;
|
||||
completed_.SignalAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::Mutex mutex_;
|
||||
absl::CondVar completed_;
|
||||
bool done_{false};
|
||||
absl::any value_;
|
||||
Exception exception_{Exception::kFailed};
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_SETTABLE_FUTURE_ANY_H_
|
||||
@@ -14,25 +14,50 @@
|
||||
|
||||
#include "platform_v2/impl/g3/webrtc.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "webrtc/api/task_queue/default_task_queue_factory.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
WebRtcSignalingMessenger::WebRtcSignalingMessenger(absl::string_view self_id)
|
||||
: self_id_(self_id) {}
|
||||
|
||||
bool WebRtcSignalingMessenger::SendMessage(absl::string_view peer_id,
|
||||
const ByteArray& message) {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.SendWebRtcSignalingMessage(peer_id, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcSignalingMessenger::StartReceivingMessages(
|
||||
OnSignalingMessageCallback listener) {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.RegisterWebRtcSignalingMessenger(self_id_, listener);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebRtcSignalingMessenger::StopReceivingMessages() {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UnregisterWebRtcSignalingMessenger(self_id_);
|
||||
}
|
||||
|
||||
void WebRtcMedium::CreatePeerConnection(
|
||||
webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) {
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
|
||||
webrtc::PeerConnectionDependencies dependencies(observer);
|
||||
|
||||
std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
|
||||
signaling_thread->SetName("signaling_thread", nullptr);
|
||||
RTC_CHECK(signaling_thread->Start()) << "Failed to start thread";
|
||||
signaling_thread_ = rtc::Thread::Create();
|
||||
signaling_thread_->SetName("signaling_thread", nullptr);
|
||||
RTC_CHECK(signaling_thread_->Start()) << "Failed to start thread";
|
||||
|
||||
webrtc::PeerConnectionFactoryDependencies factory_dependencies;
|
||||
factory_dependencies.task_queue_factory =
|
||||
webrtc::CreateDefaultTaskQueueFactory();
|
||||
factory_dependencies.signaling_thread = signaling_thread.release();
|
||||
factory_dependencies.signaling_thread = signaling_thread_.get();
|
||||
|
||||
callback(webrtc::CreateModularPeerConnectionFactory(
|
||||
std::move(factory_dependencies))
|
||||
@@ -41,8 +66,7 @@ void WebRtcMedium::CreatePeerConnection(
|
||||
|
||||
std::unique_ptr<api::WebRtcSignalingMessenger>
|
||||
WebRtcMedium::GetSignalingMessenger(absl::string_view self_id) {
|
||||
// TODO(bfranz): Implement
|
||||
return nullptr;
|
||||
return std::make_unique<WebRtcSignalingMessenger>(self_id);
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
|
||||
@@ -25,6 +25,23 @@ namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class WebRtcSignalingMessenger : public api::WebRtcSignalingMessenger {
|
||||
public:
|
||||
using OnSignalingMessageCallback =
|
||||
api::WebRtcSignalingMessenger::OnSignalingMessageCallback;
|
||||
|
||||
explicit WebRtcSignalingMessenger(absl::string_view self_id);
|
||||
~WebRtcSignalingMessenger() override = default;
|
||||
|
||||
bool SendMessage(absl::string_view peer_id,
|
||||
const ByteArray& message) override;
|
||||
bool StartReceivingMessages(OnSignalingMessageCallback listener) override;
|
||||
void StopReceivingMessages() override;
|
||||
|
||||
private:
|
||||
absl::string_view self_id_;
|
||||
};
|
||||
|
||||
class WebRtcMedium : public api::WebRtcMedium {
|
||||
public:
|
||||
using PeerConnectionCallback = api::WebRtcMedium::PeerConnectionCallback;
|
||||
@@ -40,6 +57,8 @@ class WebRtcMedium : public api::WebRtcMedium {
|
||||
// Returns a signaling messenger for sending WebRTC signaling messages.
|
||||
std::unique_ptr<api::WebRtcSignalingMessenger> GetSignalingMessenger(
|
||||
absl::string_view self_id) override;
|
||||
private:
|
||||
std::unique_ptr<rtc::Thread> signaling_thread_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "platform_v2/impl/g3/wifi_lan.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/logging.h"
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
InputStream& WifiLanSocket::GetInputStream() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return pipe_.GetInputStream();
|
||||
}
|
||||
|
||||
OutputStream& WifiLanSocket::GetOutputStream() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return pipe_.GetOutputStream();
|
||||
}
|
||||
|
||||
Exception WifiLanSocket::Close() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
pipe_.GetOutputStream().Close();
|
||||
pipe_.GetInputStream().Close();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
WifiLanService* WifiLanSocket::GetRemoteWifiLanService() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return service_;
|
||||
}
|
||||
|
||||
WifiLanMedium::WifiLanMedium() {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.RegisterWifiLanMedium(*this);
|
||||
}
|
||||
|
||||
WifiLanMedium::~WifiLanMedium() {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UnregisterWifiLanMedium(*this);
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartAdvertising(
|
||||
const std::string& service_id,
|
||||
const std::string& wifi_lan_service_info_name) {
|
||||
// TODO(edwinwu): Integrate medium_environment.
|
||||
// steps:
|
||||
// 1. create wifi_lan_service as the parameter to create wifi_lan_socket
|
||||
// auto service = std::make_unique<WifiLanService>();
|
||||
// auto socket = std::make_unique<WifiLanSocket>(service);
|
||||
// 2. callback for accepting connection; otherwise don't callback if not
|
||||
// accepted connection.
|
||||
// accepted_connection_callback_.accepted_cb(socket, service_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAdvertising(const std::string& service_id) {
|
||||
// TODO(edwinwu): Integrate medium_environment.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback) {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
NEARBY_LOG(INFO, "G3 StartDiscovery: service_id=%s", service_id.c_str());
|
||||
env.UpdateWifiLanMediumForDiscovery(*this, service_, service_id,
|
||||
std::move(callback), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopDiscovery(const std::string& service_id) {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UpdateWifiLanMediumForDiscovery(*this, service_, service_id, {}, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartAcceptingConnections(
|
||||
const std::string& service_id, AcceptedConnectionCallback callback) {
|
||||
// TODO(edwinwu): Integrate medium_environment.
|
||||
// steps:
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UpdateWifiLanMediumForAcceptedConnection(*this, service_id, callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAcceptingConnections(const std::string& service_id) {
|
||||
// TODO(edwinwu): Integrate medium_environment.
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UpdateWifiLanMediumForAcceptedConnection(*this, service_id, {});
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::Connect(
|
||||
api::WifiLanService& service, const std::string& service_id) {
|
||||
auto socket = std::make_unique<WifiLanSocket>();
|
||||
NEARBY_LOG(INFO, "G3 Connect: medium=%p, service_id=%s", this,
|
||||
service_id.c_str());
|
||||
return socket;
|
||||
// TODO(edwinwu): Integrate medium_environment.
|
||||
// steps:
|
||||
// Request a connection, and block until the socket is provided via the
|
||||
// callback.
|
||||
// 1. connection = wifi_lan_service.requestConnection_();
|
||||
// 2. create wifi_lan_socket with wifi_lan_service and connection
|
||||
// return wifi_lan_socket;
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,109 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_WIFI_LAN_H_
|
||||
#define PLATFORM_V2_IMPL_G3_WIFI_LAN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "platform_v2/impl/g3/pipe.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
// Opaque wrapper over a WifiLan service which contains encoded WifiLan service
|
||||
// info name.
|
||||
class WifiLanService : public api::WifiLanService {
|
||||
public:
|
||||
explicit WifiLanService(std::string name) : name_(std::move(name)) {}
|
||||
~WifiLanService() override = default;
|
||||
|
||||
void SetName(std::string name) { name_ = std::move(name); }
|
||||
std::string GetName() const override { return name_; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
class WifiLanSocket : public api::WifiLanSocket {
|
||||
public:
|
||||
WifiLanSocket() = default;
|
||||
explicit WifiLanSocket(WifiLanService* service) : service_(service) {}
|
||||
~WifiLanSocket() override = default;
|
||||
|
||||
// Connect to another WifiLanSocket, to form a functional low-level channel.
|
||||
// from this point on, and until Close is called, connection exists.
|
||||
void ConnectTo(WifiLanSocket* other) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns the InputStream of this connected WifiLanSocket.
|
||||
InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns the OutputStream of this connected WifiLanSocket.
|
||||
// This stream is for local side to write.
|
||||
OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns valid WifiLanService pointer if there is a connection, and
|
||||
// nullptr otherwise.
|
||||
WifiLanService* GetRemoteWifiLanService() override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
Pipe pipe_;
|
||||
WifiLanService* service_;
|
||||
mutable absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WifiLan medium.
|
||||
class WifiLanMedium : public api::WifiLanMedium {
|
||||
public:
|
||||
WifiLanMedium();
|
||||
~WifiLanMedium() override;
|
||||
|
||||
bool StartAdvertising(const std::string& service_id,
|
||||
const std::string& wifi_lan_service_info_name) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool StopAdvertising(const std::string& service_id) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns true once the WifiLan discovery has been initiated.
|
||||
bool StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns true once WifiLan discovery for service_id is well and truly
|
||||
// stopped; after this returns, there must be no more invocations of the
|
||||
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
|
||||
bool StopDiscovery(const std::string& service_id) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns true once WifiLan socket connection requests to service_id can be
|
||||
// accepted.
|
||||
bool StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
bool StopAcceptingConnections(const std::string& service_id) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns a new WifiLanSocket. On Success, WifiLanSocket::IsValid()
|
||||
// returns true.
|
||||
std::unique_ptr<api::WifiLanSocket> Connect(
|
||||
api::WifiLanService& service, const std::string& service_id) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
WifiLanService service_{"wifi_lan_service_info_name"};
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_IMPL_G3_WIFI_LAN_H_
|
||||
@@ -27,11 +27,13 @@ cc_library(
|
||||
"crypto.h",
|
||||
"file.h",
|
||||
"future.h",
|
||||
"logging.h",
|
||||
"multi_thread_executor.h",
|
||||
"mutex.h",
|
||||
"mutex_lock.h",
|
||||
"pipe.h",
|
||||
"scheduled_executor.h",
|
||||
"settable_future.h",
|
||||
"single_thread_executor.h",
|
||||
"submittable_executor.h",
|
||||
"system_clock.h",
|
||||
@@ -46,6 +48,7 @@ cc_library(
|
||||
"//platform_v2/api:platform",
|
||||
"//platform_v2/api:types",
|
||||
"//platform_v2/base",
|
||||
"//platform_v2/base:logging",
|
||||
"//platform_v2/base:util",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/container:flat_hash_map",
|
||||
@@ -58,11 +61,13 @@ cc_library(
|
||||
name = "comm",
|
||||
srcs = [
|
||||
"bluetooth_classic.cc",
|
||||
"wifi_lan.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"bluetooth_adapter.h",
|
||||
"bluetooth_classic.h",
|
||||
"webrtc.h",
|
||||
"wifi_lan.h",
|
||||
],
|
||||
visibility = [
|
||||
"//core_v2:__subpackages__",
|
||||
@@ -103,6 +108,7 @@ cc_test(
|
||||
"atomic_reference_test.cc",
|
||||
"bluetooth_adapter_test.cc",
|
||||
"bluetooth_classic_test.cc",
|
||||
"condition_variable_test.cc",
|
||||
"count_down_latch_test.cc",
|
||||
"crypto_test.cc",
|
||||
"future_test.cc",
|
||||
@@ -112,6 +118,7 @@ cc_test(
|
||||
"pipe_test.cc",
|
||||
"scheduled_executor_test.cc",
|
||||
"single_thread_executor_test.cc",
|
||||
"wifi_lan_test.cc",
|
||||
],
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
|
||||
@@ -16,36 +16,71 @@
|
||||
#define PLATFORM_V2_PUBLIC_ATOMIC_REFERENCE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "platform_v2/public/mutex_lock.h"
|
||||
#include "absl/types/any.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// An object reference that may be updated atomically.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
|
||||
template <typename, typename = void>
|
||||
class AtomicReference;
|
||||
|
||||
// Platform-based atomic type, for something convertible to std::uint32_t.
|
||||
template <typename T>
|
||||
class AtomicReference final : public api::AtomicReference<T> {
|
||||
class AtomicReference<T, std::enable_if_t<sizeof(T) <= sizeof(std::uint32_t) &&
|
||||
std::is_trivially_copyable_v<T>,
|
||||
void>>
|
||||
final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit AtomicReference(const T& value)
|
||||
: impl_(Platform::CreateAtomicReferenceAny(value)) {}
|
||||
explicit AtomicReference(T&& value)
|
||||
: impl_(Platform::CreateAtomicReferenceAny(std::move(value))) {}
|
||||
~AtomicReference() override = default;
|
||||
explicit AtomicReference(T value)
|
||||
: impl_(Platform::CreateAtomicUint32(static_cast<std::uint32_t>(value))) {
|
||||
}
|
||||
~AtomicReference() = default;
|
||||
AtomicReference(AtomicReference&&) = default;
|
||||
AtomicReference& operator=(AtomicReference&&) = default;
|
||||
|
||||
T Get() const& override { return absl::any_cast<T>(impl_->Get()); }
|
||||
T Get() && override { return absl::any_cast<T>(std::move(impl_->Get())); }
|
||||
void Set(const T& value) override { impl_->Set(absl::any(value)); }
|
||||
void Set(T&& value) override { impl_->Set(absl::any(value)); }
|
||||
T Get() const { return static_cast<T>(impl_->Get()); }
|
||||
void Set(T value) { impl_->Set(static_cast<std::uint32_t>(value)); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::AtomicReference<absl::any>> impl_;
|
||||
std::unique_ptr<api::AtomicUint32> impl_;
|
||||
};
|
||||
|
||||
// Atomic type that is using Platform mutex to provide atomicity.
|
||||
// Supports any copyable type.
|
||||
template <typename T>
|
||||
class AtomicReference<T, std::enable_if_t<(sizeof(T) > sizeof(std::uint32_t) ||
|
||||
!std::is_trivially_copyable_v<T>),
|
||||
void>>
|
||||
final {
|
||||
public:
|
||||
explicit AtomicReference(T value) {
|
||||
MutexLock lock(&mutex_);
|
||||
value_ = std::move(value);
|
||||
}
|
||||
void Set(T value) {
|
||||
MutexLock lock(&mutex_);
|
||||
value_ = std::move(value);
|
||||
}
|
||||
T Get() const& {
|
||||
MutexLock lock(&mutex_);
|
||||
return value_;
|
||||
}
|
||||
T&& Get() const&& {
|
||||
MutexLock lock(&mutex_);
|
||||
return std::move(value_);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable Mutex mutex_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -33,6 +33,7 @@ class BluetoothClassicMediumTest : public ::testing::Test {
|
||||
protected:
|
||||
using DiscoveryCallback = BluetoothClassicMedium::DiscoveryCallback;
|
||||
BluetoothClassicMediumTest() {
|
||||
env_.Start();
|
||||
env_.Reset();
|
||||
adapter_a_ = std::make_unique<BluetoothAdapter>();
|
||||
adapter_b_ = std::make_unique<BluetoothAdapter>();
|
||||
@@ -54,6 +55,7 @@ class BluetoothClassicMediumTest : public ::testing::Test {
|
||||
adapter_a_.reset();
|
||||
adapter_b_.reset();
|
||||
env_.Reset();
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
|
||||
@@ -35,10 +35,9 @@ class ConditionVariable final {
|
||||
ConditionVariable(ConditionVariable&&) = default;
|
||||
ConditionVariable& operator=(ConditionVariable&&) = default;
|
||||
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify--
|
||||
void Notify() { impl_->Notify(); }
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--
|
||||
Exception Wait() { return impl_->Wait(); }
|
||||
Exception Wait(absl::Duration timeout) { return impl_->Wait(timeout); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::ConditionVariable> impl_;
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "platform_v2/public/condition_variable.h"
|
||||
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "platform_v2/public/single_thread_executor.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
TEST(ConditionVariableTest, CanCreate) {
|
||||
Mutex mutex;
|
||||
ConditionVariable cond{&mutex};
|
||||
}
|
||||
|
||||
TEST(ConditionVariableTest, CanWakeupWaiter) {
|
||||
Mutex mutex;
|
||||
ConditionVariable cond{&mutex};
|
||||
bool done = false;
|
||||
bool waiting = false;
|
||||
NEARBY_LOG(INFO, "At start; done=%d", done);
|
||||
{
|
||||
SingleThreadExecutor executor;
|
||||
executor.Execute([&cond, &mutex, &done, &waiting]() {
|
||||
MutexLock lock(&mutex);
|
||||
NEARBY_LOG(INFO, "Before cond.Wait(); done=%d", done);
|
||||
waiting = true;
|
||||
cond.Wait();
|
||||
waiting = false;
|
||||
done = true;
|
||||
NEARBY_LOG(INFO, "After cond.Wait(); done=%d", done);
|
||||
});
|
||||
while (true) {
|
||||
{
|
||||
MutexLock lock(&mutex);
|
||||
if (waiting) break;
|
||||
}
|
||||
SystemClock::Sleep(absl::Milliseconds(100));
|
||||
}
|
||||
{
|
||||
MutexLock lock(&mutex);
|
||||
cond.Notify();
|
||||
EXPECT_FALSE(done);
|
||||
}
|
||||
}
|
||||
NEARBY_LOG(INFO, "After executor shutdown: done=%d", done);
|
||||
EXPECT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(ConditionVariableTest, WaitTerminatesOnTimeoutWithoutNotify) {
|
||||
Mutex mutex;
|
||||
ConditionVariable cond{&mutex};
|
||||
MutexLock lock(&mutex);
|
||||
EXPECT_EQ(cond.Wait(absl::Milliseconds(100)), Exception{Exception::kTimeout});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -24,45 +24,89 @@
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class InputFile final : public api::InputFile {
|
||||
class InputFile final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
InputFile(std::int64_t payload_id, std::int64_t size)
|
||||
: impl_(Platform::CreateInputFile(payload_id, size)) {}
|
||||
~InputFile() override = default;
|
||||
InputFile(PayloadId payload_id, std::int64_t size)
|
||||
: impl_(Platform::CreateInputFile(payload_id, size)), id_(payload_id) {}
|
||||
~InputFile() = default;
|
||||
InputFile(InputFile&&) = default;
|
||||
InputFile& operator=(InputFile&&) = default;
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override {
|
||||
return impl_->Read(size);
|
||||
}
|
||||
std::string GetFilePath() const override { return impl_->GetFilePath(); }
|
||||
std::int64_t GetTotalSize() const override { return impl_->GetTotalSize(); }
|
||||
Exception Close() override { return impl_->Close(); }
|
||||
// Reads up to size bytes and returns as a ByteArray object wrapped by
|
||||
// ExceptionOr.
|
||||
// Returns Exception::kIo on error, or end of file.
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) { return impl_->Read(size); }
|
||||
|
||||
// Returns a string that uniqely identifies this file.
|
||||
std::string GetFilePath() const { return impl_->GetFilePath(); }
|
||||
|
||||
// Returns total size of this file in bytes.
|
||||
std::int64_t GetTotalSize() const { return impl_->GetTotalSize(); }
|
||||
|
||||
// Disallows further reads from the file and frees system resources,
|
||||
// associated with it.
|
||||
Exception Close() { return impl_->Close(); }
|
||||
|
||||
// Returns a handle to the underlying input stream.
|
||||
//
|
||||
// Returned handle will remain valid even if InputFile is moved, for as long
|
||||
// as original InputFile lifetime continues.
|
||||
// Side effects of any non-const operation invoked for InputFile (such as
|
||||
// Read, or Close will be observable through InputStream& handle, and vice
|
||||
// versa.
|
||||
InputStream& GetInputStream() { return *impl_; }
|
||||
|
||||
// Returns payload id of this file. The closest "file" equivalent is inode.
|
||||
PayloadId GetPayloadId() const { return id_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::InputFile> impl_;
|
||||
PayloadId id_;
|
||||
};
|
||||
|
||||
class OutputFile final : public api::OutputFile {
|
||||
class OutputFile final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
explicit OutputFile(std::int64_t payload_id)
|
||||
: impl_(Platform::CreateOutputFile(payload_id)) {}
|
||||
~OutputFile() override = default;
|
||||
explicit OutputFile(PayloadId payload_id)
|
||||
: impl_(Platform::CreateOutputFile(payload_id)), id_(payload_id) {}
|
||||
~OutputFile() = default;
|
||||
OutputFile(OutputFile&&) = default;
|
||||
OutputFile& operator=(OutputFile&&) = default;
|
||||
|
||||
Exception Write(const ByteArray& data) override { return impl_->Write(data); }
|
||||
Exception Flush() override { return impl_->Flush(); }
|
||||
Exception Close() override { return impl_->Close(); }
|
||||
// Writes all data from ByteArray object to the underlying stream.
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Write(const ByteArray& data) { return impl_->Write(data); }
|
||||
|
||||
// Ensures that all data written by previous calls to Write() is passed
|
||||
// down to the applicable transport layer.
|
||||
Exception Flush() { return impl_->Flush(); }
|
||||
|
||||
// Disallows further writes to the file and frees system resources,
|
||||
// associated with it.
|
||||
Exception Close() { return impl_->Close(); }
|
||||
|
||||
// Returns a handle to the underlying output stream.
|
||||
//
|
||||
// Returned handle will remain valid even if OutputFile is moved, for as long
|
||||
// as original OutputFile lifetime continues.
|
||||
// Side effects of any non-const operation invoked for OutputFile (such as
|
||||
// Write, or Close will be observable through OutputStream& handle, and vice
|
||||
// versa.
|
||||
OutputStream& GetOutputStream() { return *impl_; }
|
||||
|
||||
// Returns payload id of this file. The closest "file" equivalent is inode.
|
||||
PayloadId GetPayloadId() const { return id_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::OutputFile> impl_;
|
||||
PayloadId id_;
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -15,60 +15,38 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_FUTURE_H_
|
||||
#define PLATFORM_V2_PUBLIC_FUTURE_H_
|
||||
|
||||
#include "platform_v2/api/executor.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/api/settable_future.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/base/runnable.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "absl/types/any.h"
|
||||
#include "platform_v2/public/settable_future.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
template <typename T>
|
||||
class Future final : public api::SettableFuture<T> {
|
||||
class Future final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
~Future() override = default;
|
||||
Future() : impl_(Platform::CreateSettableFutureAny().release()) {}
|
||||
Future(Future&& other) = default;
|
||||
Future& operator=(Future&& other) = default;
|
||||
|
||||
void AddListener(Runnable runnable, api::Executor* executor) override {
|
||||
impl_->AddListener(runnable, executor);
|
||||
}
|
||||
bool Set(const T& value) override { return impl_->Set(absl::any(value)); }
|
||||
bool Set(T&& value) override { return impl_->Set(absl::any(value)); }
|
||||
bool SetException(Exception exception) override {
|
||||
virtual bool Set(T value) { return impl_->Set(std::move(value)); }
|
||||
virtual bool SetException(Exception exception) {
|
||||
return impl_->SetException(exception);
|
||||
}
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
ExceptionOr<T> Get() override {
|
||||
auto ret_val = impl_->Get();
|
||||
if (ret_val.ok()) {
|
||||
T result = absl::any_cast<T>(ret_val.result());
|
||||
return ExceptionOr<T>{result};
|
||||
} else {
|
||||
return ExceptionOr<T>{ret_val.exception()};
|
||||
}
|
||||
virtual ExceptionOr<T> Get() { return impl_->Get(); }
|
||||
virtual ExceptionOr<T> Get(absl::Duration timeout) {
|
||||
return impl_->Get(timeout);
|
||||
}
|
||||
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
// throws Exception::kTimeout if timeout is exceeded while waiting for
|
||||
// result.
|
||||
ExceptionOr<T> Get(absl::Duration timeout) override {
|
||||
auto ret_val = impl_->Get(timeout);
|
||||
if (ret_val.ok()) {
|
||||
T result = absl::any_cast<T>(ret_val.result());
|
||||
return ExceptionOr<T>{result};
|
||||
} else {
|
||||
return ExceptionOr<T>{ret_val.exception()};
|
||||
}
|
||||
void AddListener(Runnable runnable, api::Executor* executor) {
|
||||
impl_->AddListener(std::move(runnable), executor);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::SettableFuture<absl::any>> impl_;
|
||||
// Instance of future implementation is wrapped in shared_ptr<> to make
|
||||
// it possible to pass Future by value and share the implementation.
|
||||
// This allows for the following constructions:
|
||||
// 1)
|
||||
// Future<bool> future;
|
||||
// RunOnXyzThread([future]() { future.Set(DoTheJobAndReport()); });
|
||||
// if (future.Get().Ok()) { /*...*/ }
|
||||
// 2)
|
||||
// Future<bool> future = DoSomeAsyncWork(); // Returns future, but keeps copy.
|
||||
// if (future.Get().Ok()) { /*...*/ }
|
||||
std::shared_ptr<SettableFuture<T>> impl_{new SettableFuture<T>()};
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
|
||||
@@ -20,7 +20,33 @@
|
||||
namespace {
|
||||
|
||||
TEST(LoggingTest, CanLog) {
|
||||
NEARBY_LOG(INFO, "message");
|
||||
NEARBY_LOG_SET_SEVERITY(INFO);
|
||||
int num = 42;
|
||||
NEARBY_LOG(INFO, "The answer to everything: %d", num++);
|
||||
EXPECT_EQ(num, 43);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, CanLog_LoggingDisabled) {
|
||||
NEARBY_LOG_SET_SEVERITY(ERROR);
|
||||
int num = 42;
|
||||
NEARBY_LOG(INFO, "The answer to everything: %d", num++);
|
||||
// num++ should not be evaluated
|
||||
EXPECT_EQ(num, 42);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, CanStream) {
|
||||
NEARBY_LOG_SET_SEVERITY(INFO);
|
||||
int num = 42;
|
||||
NEARBY_LOGS(INFO) << "The answer to everything: " << num++;
|
||||
EXPECT_EQ(num, 43);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, CanStream_LoggingDisabled) {
|
||||
NEARBY_LOG_SET_SEVERITY(ERROR);
|
||||
int num = 42;
|
||||
NEARBY_LOGS(INFO) << "The answer to everything: " << num++;
|
||||
// num++ should not be evaluated
|
||||
EXPECT_EQ(num, 42);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -41,7 +41,7 @@ class MutexTest : public testing::Test {
|
||||
|
||||
protected:
|
||||
SingleThreadExecutor executor_;
|
||||
const absl::Duration kTimeToWait = absl::Milliseconds(200);
|
||||
const absl::Duration kTimeToWait = absl::Milliseconds(500);
|
||||
std::atomic_int step_ = 0;
|
||||
absl::Mutex step_mutex_;
|
||||
absl::CondVar step_cond_;
|
||||
|
||||
@@ -26,6 +26,14 @@
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// kShortDelay must be significant enough to guarantee that OS under heavy load
|
||||
// should be able to execute the non-blocking test paths within this time.
|
||||
absl::Duration kShortDelay = absl::Milliseconds(100);
|
||||
|
||||
// kLongDelay must be long enough to make sure that under OS under heavy load
|
||||
// will let kShortDelay fire and jobs scheduled before the kLongDelay fires.
|
||||
absl::Duration kLongDelay = 10 * kShortDelay;
|
||||
|
||||
TEST(ScheduledExecutorTest, ConsructorDestructorWorks) {
|
||||
ScheduledExecutor executor;
|
||||
}
|
||||
@@ -42,7 +50,7 @@ TEST(ScheduledExecutorTest, CanExecute) {
|
||||
{
|
||||
absl::MutexLock lock(&mutex);
|
||||
if (!done) {
|
||||
cond.WaitWithTimeout(&mutex, absl::Seconds(1));
|
||||
cond.WaitWithTimeout(&mutex, kLongDelay);
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(done);
|
||||
@@ -53,25 +61,25 @@ TEST(ScheduledExecutorTest, CanSchedule) {
|
||||
std::atomic_int value = 0;
|
||||
absl::Mutex mutex;
|
||||
absl::CondVar cond;
|
||||
// schedule job due in 100 ms.
|
||||
// schedule job due in kLongDelay.
|
||||
executor.Schedule(
|
||||
[&value, &cond]() {
|
||||
EXPECT_EQ(value, 1);
|
||||
value = 5;
|
||||
cond.Signal();
|
||||
},
|
||||
absl::Milliseconds(100));
|
||||
// schedule job due in 10 ms; must fire before the first one.
|
||||
kLongDelay);
|
||||
// schedule job due in kShortDelay; must fire before the first one.
|
||||
executor.Schedule(
|
||||
[&value]() {
|
||||
EXPECT_EQ(value, 0);
|
||||
value = 1;
|
||||
},
|
||||
absl::Milliseconds(10));
|
||||
kShortDelay);
|
||||
{
|
||||
// wait for the final job to unblock us.
|
||||
// wait for the final job to unblock us; wait longer than kLongDelay.
|
||||
absl::MutexLock lock(&mutex);
|
||||
cond.WaitWithTimeout(&mutex, absl::Milliseconds(1000));
|
||||
cond.WaitWithTimeout(&mutex, 2 * kLongDelay);
|
||||
}
|
||||
EXPECT_EQ(value, 5);
|
||||
}
|
||||
@@ -80,10 +88,10 @@ TEST(ScheduledExecutorTest, CanCancel) {
|
||||
ScheduledExecutor executor;
|
||||
std::atomic_int value = 0;
|
||||
Cancelable cancelable =
|
||||
executor.Schedule([&value]() { value += 1; }, absl::Milliseconds(10));
|
||||
executor.Schedule([&value]() { value += 1; }, kShortDelay);
|
||||
EXPECT_EQ(value, 0);
|
||||
EXPECT_TRUE(cancelable.Cancel());
|
||||
absl::SleepFor(absl::Milliseconds(500));
|
||||
absl::SleepFor(kLongDelay);
|
||||
EXPECT_EQ(value, 0);
|
||||
}
|
||||
|
||||
@@ -92,17 +100,17 @@ TEST(ScheduledExecutorTest, FailToCancel) {
|
||||
absl::CondVar cond;
|
||||
ScheduledExecutor executor;
|
||||
std::atomic_int value = 0;
|
||||
// Schedule job in 10ms, which will we will attempt to cancel later.
|
||||
// Schedule job in kShortDelay, which will we will attempt to cancel later.
|
||||
Cancelable cancelable =
|
||||
executor.Schedule([&value]() { value += 1; }, absl::Milliseconds(10));
|
||||
// schedule another job to test results of the first one, in 50ms from now.
|
||||
executor.Schedule([&value]() { value += 1; }, kShortDelay);
|
||||
// schedule another job to test results of the first one, in kLongDelay.
|
||||
executor.Schedule(
|
||||
[&cancelable, &cond]() {
|
||||
EXPECT_FALSE(cancelable.Cancel());
|
||||
// Wake up main thread.
|
||||
cond.Signal();
|
||||
},
|
||||
absl::Milliseconds(50));
|
||||
kLongDelay);
|
||||
{
|
||||
absl::MutexLock lock(&mutex);
|
||||
cond.Wait(&mutex);
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_SETTABLE_FUTURE_H_
|
||||
#define PLATFORM_V2_PUBLIC_SETTABLE_FUTURE_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "platform_v2/public/condition_variable.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "platform_v2/public/mutex_lock.h"
|
||||
#include "platform_v2/public/system_clock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
template <typename T>
|
||||
class SettableFuture : public api::SettableFuture<T> {
|
||||
public:
|
||||
SettableFuture() = default;
|
||||
~SettableFuture() override = default;
|
||||
|
||||
bool Set(T value) override {
|
||||
MutexLock lock(&mutex_);
|
||||
if (!done_) {
|
||||
value_ = std::move(value);
|
||||
done_ = true;
|
||||
exception_ = {Exception::kSuccess};
|
||||
completed_.Notify();
|
||||
InvokeAllLocked();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddListener(Runnable runnable, api::Executor* executor) override {
|
||||
MutexLock lock(&mutex_);
|
||||
if (done_) {
|
||||
executor->Execute(std::move(runnable));
|
||||
} else {
|
||||
listeners_.emplace_back(std::make_pair(executor, std::move(runnable)));
|
||||
}
|
||||
}
|
||||
|
||||
bool SetException(Exception exception) override {
|
||||
MutexLock lock(&mutex_);
|
||||
return SetExceptionLocked(exception);
|
||||
}
|
||||
|
||||
ExceptionOr<T> Get() override {
|
||||
MutexLock lock(&mutex_);
|
||||
while (!done_) {
|
||||
completed_.Wait();
|
||||
}
|
||||
return exception_.value != Exception::kSuccess
|
||||
? ExceptionOr<T>{exception_.value}
|
||||
: ExceptionOr<T>{value_};
|
||||
}
|
||||
|
||||
ExceptionOr<T> Get(absl::Duration timeout) override {
|
||||
MutexLock lock(&mutex_);
|
||||
while (!done_) {
|
||||
absl::Time start_time = SystemClock::ElapsedRealtime();
|
||||
if (completed_.Wait(timeout).Raised(Exception::kTimeout)) {
|
||||
SetExceptionLocked({Exception::kTimeout});
|
||||
break;
|
||||
}
|
||||
absl::Duration spent = SystemClock::ElapsedRealtime() - start_time;
|
||||
if (spent < timeout) {
|
||||
timeout -= spent;
|
||||
} else if (!done_) {
|
||||
SetExceptionLocked({Exception::kTimeout});
|
||||
break;
|
||||
}
|
||||
}
|
||||
return exception_.value != Exception::kSuccess
|
||||
? ExceptionOr<T>{exception_.value}
|
||||
: ExceptionOr<T>{value_};
|
||||
}
|
||||
|
||||
private:
|
||||
bool SetExceptionLocked(Exception exception) {
|
||||
if (!done_) {
|
||||
exception_ = exception.value != Exception::kSuccess
|
||||
? exception
|
||||
: Exception{Exception::kFailed};
|
||||
done_ = true;
|
||||
completed_.Notify();
|
||||
InvokeAllLocked();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InvokeAllLocked() {
|
||||
for (auto& item : listeners_) {
|
||||
item.first->Execute(std::move(item.second));
|
||||
}
|
||||
listeners_.clear();
|
||||
}
|
||||
|
||||
Mutex mutex_;
|
||||
ConditionVariable completed_{&mutex_};
|
||||
std::vector<std::pair<api::Executor*, std::function<void()>>> listeners_;
|
||||
bool done_{false};
|
||||
T value_;
|
||||
Exception exception_{Exception::kFailed};
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_SETTABLE_FUTURE_H_
|
||||
@@ -24,6 +24,34 @@
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class WebRtcSignalingMessenger final {
|
||||
public:
|
||||
using OnSignalingMessageCallback =
|
||||
api::WebRtcSignalingMessenger::OnSignalingMessageCallback;
|
||||
|
||||
explicit WebRtcSignalingMessenger(
|
||||
std::unique_ptr<api::WebRtcSignalingMessenger> messenger)
|
||||
: impl_(std::move(messenger)) {}
|
||||
~WebRtcSignalingMessenger() = default;
|
||||
WebRtcSignalingMessenger(WebRtcSignalingMessenger&&) = default;
|
||||
WebRtcSignalingMessenger operator=(WebRtcSignalingMessenger&&) = delete;
|
||||
|
||||
bool SendMessage(absl::string_view peer_id, const ByteArray& message) {
|
||||
return impl_->SendMessage(peer_id, message);
|
||||
}
|
||||
|
||||
bool StartReceivingMessages(OnSignalingMessageCallback listener) {
|
||||
return impl_->StartReceivingMessages(listener);
|
||||
}
|
||||
|
||||
void StopReceivingMessages() { impl_->StopReceivingMessages(); }
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<api::WebRtcSignalingMessenger> impl_;
|
||||
};
|
||||
|
||||
class WebRtcMedium final {
|
||||
public:
|
||||
using PeerConnectionCallback = api::WebRtcMedium::PeerConnectionCallback;
|
||||
@@ -41,9 +69,10 @@ class WebRtcMedium final {
|
||||
}
|
||||
|
||||
// Returns a signaling messenger for sending WebRTC signaling messages.
|
||||
std::unique_ptr<api::WebRtcSignalingMessenger> GetSignalingMessenger(
|
||||
std::unique_ptr<WebRtcSignalingMessenger> GetSignalingMessenger(
|
||||
absl::string_view self_id) {
|
||||
return impl_->GetSignalingMessenger(self_id);
|
||||
return std::make_unique<WebRtcSignalingMessenger>(
|
||||
impl_->GetSignalingMessenger(self_id));
|
||||
}
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "platform_v2/public/wifi_lan.h"
|
||||
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "platform_v2/public/mutex_lock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
bool WifiLanMedium::StartAdvertising(
|
||||
const std::string& service_id,
|
||||
const std::string& wifi_lan_service_info_name) {
|
||||
return impl_->StartAdvertising(service_id, wifi_lan_service_info_name);
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAdvertising(const std::string& service_id) {
|
||||
return impl_->StopAdvertising(service_id);
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
discovered_service_callback_ = std::move(callback);
|
||||
services_.clear();
|
||||
}
|
||||
return impl_->StartDiscovery(
|
||||
service_id,
|
||||
{
|
||||
.service_discovered_cb =
|
||||
[this](api::WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
auto pair = services_.emplace(
|
||||
&service, absl::make_unique<ServiceDiscoveryInfo>());
|
||||
auto& context = *pair.first->second;
|
||||
if (!pair.second) {
|
||||
NEARBY_LOG(INFO, "Adding (again) service=%p, impl=%p",
|
||||
&context.service, &service);
|
||||
return;
|
||||
}
|
||||
context.service = WifiLanService(&service);
|
||||
NEARBY_LOG(INFO, "Adding service=%p, impl=%p", &context.service,
|
||||
&service);
|
||||
discovered_service_callback_.service_discovered_cb(
|
||||
context.service, service_id);
|
||||
},
|
||||
.service_lost_cb =
|
||||
[this](api::WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
auto item = services_.extract(&service);
|
||||
auto& context = *item.mapped();
|
||||
NEARBY_LOG(INFO, "Removing service=%p, impl=%p",
|
||||
&context.service, &service);
|
||||
discovered_service_callback_.service_lost_cb(context.service,
|
||||
service_id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopDiscovery(const std::string& service_id) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
discovered_service_callback_ = {};
|
||||
services_.clear();
|
||||
NEARBY_LOG(INFO, "WifiLan Discovery disabled: impl=%p", &GetImpl());
|
||||
}
|
||||
return impl_->StopDiscovery(service_id);
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartAcceptingConnections(
|
||||
const std::string& service_id, AcceptedConnectionCallback callback) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
accepted_connection_callback_ = std::move(callback);
|
||||
}
|
||||
return impl_->StartAcceptingConnections(
|
||||
service_id,
|
||||
{
|
||||
.accepted_cb =
|
||||
[this](api::WifiLanSocket& socket,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
auto pair = sockets_.emplace(
|
||||
&socket, absl::make_unique<AcceptedConnectionInfo>());
|
||||
auto& context = *pair.first->second;
|
||||
if (!pair.second) {
|
||||
NEARBY_LOG(INFO, "Adding (again) socket=%p, impl=%p",
|
||||
&context.socket, &socket);
|
||||
return;
|
||||
}
|
||||
context.socket = WifiLanSocket(&socket);
|
||||
NEARBY_LOG(INFO, "Adding socket=%p, impl=%p", &context.socket,
|
||||
&socket);
|
||||
accepted_connection_callback_.accepted_cb(context.socket,
|
||||
service_id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAcceptingConnections(const std::string& service_id) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
accepted_connection_callback_ = {};
|
||||
sockets_.clear();
|
||||
NEARBY_LOG(INFO, "WifiLan accepted connection disabled: impl=%p",
|
||||
&GetImpl());
|
||||
}
|
||||
return impl_->StopDiscovery(service_id);
|
||||
}
|
||||
|
||||
WifiLanSocket WifiLanMedium::Connect(WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "WifiLanMedium::Connect: service=%p [impl=%p]", &service,
|
||||
&service.GetImpl());
|
||||
return WifiLanSocket(impl_->Connect(service.GetImpl(), service_id));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,160 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_WIFI_LAN_H_
|
||||
#define PLATFORM_V2_PUBLIC_WIFI_LAN_H_
|
||||
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
// Opaque wrapper over a WifiLan service which contains encoded service name.
|
||||
class WifiLanService final {
|
||||
public:
|
||||
WifiLanService() = default;
|
||||
WifiLanService(const WifiLanService&) = default;
|
||||
WifiLanService& operator=(const WifiLanService&) = default;
|
||||
explicit WifiLanService(api::WifiLanService* service) : impl_(service) {}
|
||||
~WifiLanService() = default;
|
||||
|
||||
std::string GetName() const { return impl_->GetName(); }
|
||||
|
||||
api::WifiLanService& GetImpl() { return *impl_; }
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
private:
|
||||
api::WifiLanService* impl_;
|
||||
};
|
||||
|
||||
class WifiLanSocket final {
|
||||
public:
|
||||
WifiLanSocket() = default;
|
||||
WifiLanSocket(const WifiLanSocket&) = default;
|
||||
WifiLanSocket& operator=(const WifiLanSocket&) = default;
|
||||
explicit WifiLanSocket(api::WifiLanSocket* socket) : impl_(socket) {}
|
||||
explicit WifiLanSocket(std::unique_ptr<api::WifiLanSocket> socket)
|
||||
: impl_(socket.release()) {}
|
||||
~WifiLanSocket() = default;
|
||||
|
||||
// Returns the InputStream of the WifiLanSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the WifiLanSocket object is destroyed.
|
||||
InputStream& GetInputStream() { return impl_->GetInputStream(); }
|
||||
|
||||
// Returns the OutputStream of the WifiLanSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the WifiLanSocket object is destroyed.
|
||||
OutputStream& GetOutputStream() { return impl_->GetOutputStream(); }
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() { return impl_->Close(); }
|
||||
|
||||
WifiLanService GetRemoteWifiLanService() {
|
||||
return WifiLanService(impl_->GetRemoteWifiLanService());
|
||||
}
|
||||
|
||||
// Returns true if a socket is usable. If this method returns false,
|
||||
// it is not safe to call any other method.
|
||||
// NOTE(socket validity):
|
||||
// Socket created by a default public constructor is not valid, because
|
||||
// it is missing platform implementation.
|
||||
// The only way to obtain a valid socket is through connection, such as
|
||||
// an object returned by WifiLanMedium::Connect
|
||||
// These methods may also return an invalid socket if connection failed for
|
||||
// any reason.
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
// Returns reference to platform implementation.
|
||||
// This is used to communicate with platform code, and for debugging purposes.
|
||||
// Returned reference will remain valid for while WifiLanSocket object is
|
||||
// itself valid. Typically WifiLanSocket lifetime matches duration of the
|
||||
// connection, and is controlled by end user, since they hold the instance.
|
||||
api::WifiLanSocket& GetImpl() { return *impl_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<api::WifiLanSocket> impl_;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WifiLan medium.
|
||||
class WifiLanMedium final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
struct DiscoveredServiceCallback {
|
||||
std::function<void(WifiLanService& wifi_lan_service,
|
||||
const std::string& service_id)>
|
||||
service_discovered_cb =
|
||||
DefaultCallback<WifiLanService&, const std::string&>();
|
||||
std::function<void(WifiLanService& wifi_lan_service,
|
||||
const std::string& service_id)>
|
||||
service_lost_cb =
|
||||
DefaultCallback<WifiLanService&, const std::string&>();
|
||||
};
|
||||
struct ServiceDiscoveryInfo {
|
||||
WifiLanService service;
|
||||
};
|
||||
|
||||
struct AcceptedConnectionCallback {
|
||||
std::function<void(WifiLanSocket& socket, const std::string& service_id)>
|
||||
accepted_cb = DefaultCallback<WifiLanSocket&, const std::string&>();
|
||||
};
|
||||
struct AcceptedConnectionInfo {
|
||||
WifiLanSocket socket;
|
||||
};
|
||||
|
||||
WifiLanMedium() : impl_(Platform::CreateWifiLanMedium()) {}
|
||||
~WifiLanMedium() = default;
|
||||
|
||||
bool StartAdvertising(const std::string& service_id,
|
||||
const std::string& wifi_lan_service_info_name);
|
||||
bool StopAdvertising(const std::string& service_id);
|
||||
|
||||
// Returns true once the WifiLan discovery has been initiated.
|
||||
bool StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback);
|
||||
|
||||
// Returns true once WifiLan discovery for service_id is well and truly
|
||||
// stopped; after this returns, there must be no more invocations of the
|
||||
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
|
||||
bool StopDiscovery(const std::string& service_id);
|
||||
|
||||
// Returns true once WifiLan socket connection requests to service_id can be
|
||||
// accepted.
|
||||
bool StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback);
|
||||
bool StopAcceptingConnections(const std::string& service_id);
|
||||
|
||||
// Returns a new WifiLanSocket. On Success, WifiLanSocket::IsValid()
|
||||
// returns true.
|
||||
WifiLanSocket Connect(WifiLanService& service, const std::string& service_id);
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
api::WifiLanMedium& GetImpl() { return *impl_; }
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
std::unique_ptr<api::WifiLanMedium> impl_;
|
||||
absl::flat_hash_map<api::WifiLanService*,
|
||||
std::unique_ptr<ServiceDiscoveryInfo>>
|
||||
services_ ABSL_GUARDED_BY(mutex_);
|
||||
absl::flat_hash_map<api::WifiLanSocket*,
|
||||
std::unique_ptr<AcceptedConnectionInfo>>
|
||||
sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
DiscoveredServiceCallback discovered_service_callback_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
AcceptedConnectionCallback accepted_connection_callback_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_WIFI_LAN_H_
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "platform_v2/public/wifi_lan.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"};
|
||||
|
||||
class WifiLanMediumTest : public ::testing::Test {
|
||||
protected:
|
||||
using DiscoveredServiceCallback = WifiLanMedium::DiscoveredServiceCallback;
|
||||
|
||||
WifiLanMediumTest() { env_.Stop(); }
|
||||
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
};
|
||||
|
||||
TEST_F(WifiLanMediumTest, ConstructorDestructorWorks) {
|
||||
env_.Start();
|
||||
WifiLanMedium medium_a;
|
||||
WifiLanMedium medium_b;
|
||||
|
||||
// Make sure we can create functional mediums.
|
||||
ASSERT_TRUE(medium_a.IsValid());
|
||||
ASSERT_TRUE(medium_b.IsValid());
|
||||
|
||||
// Make sure we can create 2 distinct mediums.
|
||||
EXPECT_NE(&medium_a.GetImpl(), &medium_b.GetImpl());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(WifiLanMediumTest, CanStartDiscoveryAndServiceIndeedDiscovered) {
|
||||
env_.Start();
|
||||
WifiLanMedium medium;
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
medium.StartDiscovery(std::string(kServiceID),
|
||||
DiscoveredServiceCallback{
|
||||
.service_discovered_cb =
|
||||
[&found_latch](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Service discovered: %s",
|
||||
service.GetName().c_str());
|
||||
EXPECT_EQ(kServiceID, service_id);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.service_lost_cb =
|
||||
[&lost_latch](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Service lost: %s",
|
||||
service.GetName().c_str());
|
||||
EXPECT_EQ(kServiceID, service_id);
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
});
|
||||
EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(WifiLanMediumTest, CanStopDiscovery) {
|
||||
env_.Start();
|
||||
WifiLanMedium medium;
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
medium.StartDiscovery(std::string(kServiceID),
|
||||
DiscoveredServiceCallback{
|
||||
.service_discovered_cb =
|
||||
[&found_latch](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Service discovered: %s",
|
||||
service.GetName().c_str());
|
||||
EXPECT_EQ(kServiceID, service_id);
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.service_lost_cb =
|
||||
[&lost_latch](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Service lost: %s",
|
||||
service.GetName().c_str());
|
||||
EXPECT_EQ(kServiceID, service_id);
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
});
|
||||
EXPECT_TRUE(found_latch.Await(absl::Milliseconds(1000)).result());
|
||||
bool stop = medium.StopDiscovery(std::string(kServiceID));
|
||||
EXPECT_TRUE(stop);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
Reference in New Issue
Block a user