blob: 8aca52efb5b14381215b3b9e844913c92bb47e59 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/bluetooth/BluetoothRemoteGATTServer.h"
#include "bindings/core/v8/CallbackPromiseAdapter.h"
#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "core/events/Event.h"
#include "modules/bluetooth/Bluetooth.h"
#include "modules/bluetooth/BluetoothDevice.h"
#include "modules/bluetooth/BluetoothError.h"
#include "modules/bluetooth/BluetoothRemoteGATTService.h"
#include "modules/bluetooth/BluetoothUUID.h"
#include <utility>
namespace blink {
BluetoothRemoteGATTServer::BluetoothRemoteGATTServer(BluetoothDevice* device)
: m_device(device), m_connected(false) {}
BluetoothRemoteGATTServer* BluetoothRemoteGATTServer::Create(
BluetoothDevice* device) {
return new BluetoothRemoteGATTServer(device);
}
void BluetoothRemoteGATTServer::AddToActiveAlgorithms(
ScriptPromiseResolver* resolver) {
auto result = m_activeAlgorithms.insert(resolver);
CHECK(result.isNewEntry);
}
bool BluetoothRemoteGATTServer::RemoveFromActiveAlgorithms(
ScriptPromiseResolver* resolver) {
if (!m_activeAlgorithms.contains(resolver)) {
return false;
}
m_activeAlgorithms.erase(resolver);
return true;
}
DEFINE_TRACE(BluetoothRemoteGATTServer) {
visitor->trace(m_activeAlgorithms);
visitor->trace(m_device);
}
void BluetoothRemoteGATTServer::ConnectCallback(
ScriptPromiseResolver* resolver,
mojom::blink::WebBluetoothResult result) {
if (!resolver->getExecutionContext() ||
resolver->getExecutionContext()->isContextDestroyed())
return;
if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
m_device->bluetooth()->AddToConnectedDevicesMap(m_device->id(), m_device);
SetConnected(true);
resolver->resolve(this);
} else {
resolver->reject(BluetoothError::CreateDOMException(result));
}
}
ScriptPromise BluetoothRemoteGATTServer::connect(ScriptState* scriptState) {
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
mojom::blink::WebBluetoothService* service = m_device->bluetooth()->Service();
service->RemoteServerConnect(
m_device->id(), convertToBaseCallback(WTF::bind(
&BluetoothRemoteGATTServer::ConnectCallback,
wrapPersistent(this), wrapPersistent(resolver))));
return promise;
}
void BluetoothRemoteGATTServer::disconnect(ScriptState* scriptState) {
if (!m_connected)
return;
m_device->CleanupDisconnectedDeviceAndFireEvent();
m_device->bluetooth()->RemoveFromConnectedDevicesMap(m_device->id());
mojom::blink::WebBluetoothService* service = m_device->bluetooth()->Service();
service->RemoteServerDisconnect(m_device->id());
}
// Callback that allows us to resolve the promise with a single service or
// with a vector owning the services.
void BluetoothRemoteGATTServer::GetPrimaryServicesCallback(
const String& requestedServiceUUID,
mojom::blink::WebBluetoothGATTQueryQuantity quantity,
ScriptPromiseResolver* resolver,
mojom::blink::WebBluetoothResult result,
Optional<Vector<mojom::blink::WebBluetoothRemoteGATTServicePtr>> services) {
if (!resolver->getExecutionContext() ||
resolver->getExecutionContext()->isContextDestroyed())
return;
// If the device is disconnected, reject.
if (!RemoveFromActiveAlgorithms(resolver)) {
resolver->reject(BluetoothError::CreateNotConnectedException(
BluetoothOperation::ServicesRetrieval));
return;
}
if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
DCHECK(services);
if (quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) {
DCHECK_EQ(1u, services->size());
resolver->resolve(m_device->GetOrCreateRemoteGATTService(
std::move(services.value()[0]), true /* isPrimary */,
m_device->id()));
return;
}
HeapVector<Member<BluetoothRemoteGATTService>> gattServices;
gattServices.reserveInitialCapacity(services->size());
for (auto& service : services.value()) {
gattServices.push_back(m_device->GetOrCreateRemoteGATTService(
std::move(service), true /* isPrimary */, m_device->id()));
}
resolver->resolve(gattServices);
} else {
if (result == mojom::blink::WebBluetoothResult::SERVICE_NOT_FOUND) {
resolver->reject(BluetoothError::CreateDOMException(
BluetoothErrorCode::ServiceNotFound, "No Services matching UUID " +
requestedServiceUUID +
" found in Device."));
} else {
resolver->reject(BluetoothError::CreateDOMException(result));
}
}
}
ScriptPromise BluetoothRemoteGATTServer::getPrimaryService(
ScriptState* scriptState,
const StringOrUnsignedLong& service,
ExceptionState& exceptionState) {
String serviceUUID = BluetoothUUID::getService(service, exceptionState);
if (exceptionState.hadException())
return exceptionState.reject(scriptState);
return GetPrimaryServicesImpl(
scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE,
serviceUUID);
}
ScriptPromise BluetoothRemoteGATTServer::getPrimaryServices(
ScriptState* scriptState,
const StringOrUnsignedLong& service,
ExceptionState& exceptionState) {
String serviceUUID = BluetoothUUID::getService(service, exceptionState);
if (exceptionState.hadException())
return exceptionState.reject(scriptState);
return GetPrimaryServicesImpl(
scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE,
serviceUUID);
}
ScriptPromise BluetoothRemoteGATTServer::getPrimaryServices(
ScriptState* scriptState,
ExceptionState&) {
return GetPrimaryServicesImpl(
scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE);
}
ScriptPromise BluetoothRemoteGATTServer::GetPrimaryServicesImpl(
ScriptState* scriptState,
mojom::blink::WebBluetoothGATTQueryQuantity quantity,
String servicesUUID) {
if (!m_connected) {
return ScriptPromise::rejectWithDOMException(
scriptState, BluetoothError::CreateNotConnectedException(
BluetoothOperation::ServicesRetrieval));
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
AddToActiveAlgorithms(resolver);
mojom::blink::WebBluetoothService* service = m_device->bluetooth()->Service();
service->RemoteServerGetPrimaryServices(
m_device->id(), quantity, servicesUUID,
convertToBaseCallback(
WTF::bind(&BluetoothRemoteGATTServer::GetPrimaryServicesCallback,
wrapPersistent(this), servicesUUID, quantity,
wrapPersistent(resolver))));
return promise;
}
} // namespace blink