mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1197690 - Part2: Implement reconnect, r=smaug
--HG-- extra : rebase_source : b40f774b3af223910da37094b2f82bfc5b8b92d2
This commit is contained in:
parent
165708a330
commit
4f5b2c7d11
116
dom/presentation/ControllerConnectionCollection.cpp
Normal file
116
dom/presentation/ControllerConnectionCollection.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ControllerConnectionCollection.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsIPresentationService.h"
|
||||
#include "PresentationConnection.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */
|
||||
StaticAutoPtr<ControllerConnectionCollection>
|
||||
ControllerConnectionCollection::sSingleton;
|
||||
|
||||
/* static */ ControllerConnectionCollection*
|
||||
ControllerConnectionCollection::GetSingleton()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sSingleton) {
|
||||
sSingleton = new ControllerConnectionCollection();
|
||||
ClearOnShutdown(&sSingleton);
|
||||
}
|
||||
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
ControllerConnectionCollection::ControllerConnectionCollection()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ControllerConnectionCollection);
|
||||
}
|
||||
|
||||
ControllerConnectionCollection::~ControllerConnectionCollection()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ControllerConnectionCollection);
|
||||
}
|
||||
|
||||
void
|
||||
ControllerConnectionCollection::AddConnection(
|
||||
PresentationConnection* aConnection,
|
||||
const uint8_t aRole)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
WeakPtr<PresentationConnection> connection = aConnection;
|
||||
if (mConnections.Contains(connection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mConnections.AppendElement(connection);
|
||||
}
|
||||
|
||||
void
|
||||
ControllerConnectionCollection::RemoveConnection(
|
||||
PresentationConnection* aConnection,
|
||||
const uint8_t aRole)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
WeakPtr<PresentationConnection> connection = aConnection;
|
||||
mConnections.RemoveElement(connection);
|
||||
}
|
||||
|
||||
already_AddRefed<PresentationConnection>
|
||||
ControllerConnectionCollection::FindConnection(
|
||||
uint64_t aWindowId,
|
||||
const nsAString& aId,
|
||||
const uint8_t aRole)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "This is allowed only to be called at controller side.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Loop backwards to allow removing elements in the loop.
|
||||
for (int i = mConnections.Length() - 1; i >= 0; --i) {
|
||||
WeakPtr<PresentationConnection> connection = mConnections[i];
|
||||
if (!connection) {
|
||||
// The connection was destroyed. Remove it from the list.
|
||||
mConnections.RemoveElementAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connection->Equals(aWindowId, aId)) {
|
||||
RefPtr<PresentationConnection> matchedConnection = connection.get();
|
||||
return matchedConnection.forget();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
49
dom/presentation/ControllerConnectionCollection.h
Normal file
49
dom/presentation/ControllerConnectionCollection.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ControllerConnectionCollection_h
|
||||
#define mozilla_dom_ControllerConnectionCollection_h
|
||||
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PresentationConnection;
|
||||
|
||||
class ControllerConnectionCollection final
|
||||
{
|
||||
public:
|
||||
static ControllerConnectionCollection* GetSingleton();
|
||||
|
||||
void AddConnection(PresentationConnection* aConnection,
|
||||
const uint8_t aRole);
|
||||
|
||||
void RemoveConnection(PresentationConnection* aConnection,
|
||||
const uint8_t aRole);
|
||||
|
||||
already_AddRefed<PresentationConnection>
|
||||
FindConnection(uint64_t aWindowId,
|
||||
const nsAString& aId,
|
||||
const uint8_t aRole);
|
||||
|
||||
private:
|
||||
friend class StaticAutoPtr<ControllerConnectionCollection>;
|
||||
|
||||
ControllerConnectionCollection();
|
||||
virtual ~ControllerConnectionCollection();
|
||||
|
||||
static StaticAutoPtr<ControllerConnectionCollection> sSingleton;
|
||||
nsTArray<WeakPtr<PresentationConnection>> mConnections;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ControllerConnectionCollection_h
|
@ -13,6 +13,7 @@
|
||||
#include "PresentationCallbacks.h"
|
||||
#include "PresentationRequest.h"
|
||||
#include "PresentationConnection.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -28,6 +29,7 @@ PresentationRequesterCallback::PresentationRequesterCallback(PresentationRequest
|
||||
const nsAString& aSessionId,
|
||||
Promise* aPromise)
|
||||
: mRequest(aRequest)
|
||||
, mUrl(aUrl)
|
||||
, mSessionId(aSessionId)
|
||||
, mPromise(aPromise)
|
||||
{
|
||||
@ -46,10 +48,8 @@ PresentationRequesterCallback::NotifySuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// At the sender side, this function must get called after the transport
|
||||
// channel is ready. So we simply set the connection state as connected.
|
||||
RefPtr<PresentationConnection> connection =
|
||||
PresentationConnection::Create(mRequest->GetOwner(), mSessionId,
|
||||
PresentationConnection::Create(mRequest->GetOwner(), mSessionId, mUrl,
|
||||
nsIPresentationService::ROLE_CONTROLLER);
|
||||
if (NS_WARN_IF(!connection)) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
@ -74,6 +74,74 @@ PresentationRequesterCallback::NotifyError(nsresult aError)
|
||||
* Implementation of PresentationRequesterCallback
|
||||
*/
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(PresentationReconnectCallback,
|
||||
PresentationRequesterCallback)
|
||||
|
||||
PresentationReconnectCallback::PresentationReconnectCallback(
|
||||
PresentationRequest* aRequest,
|
||||
const nsAString& aUrl,
|
||||
const nsAString& aSessionId,
|
||||
Promise* aPromise,
|
||||
PresentationConnection* aConnection)
|
||||
: PresentationRequesterCallback(aRequest, aUrl, aSessionId, aPromise)
|
||||
, mConnection(aConnection)
|
||||
{
|
||||
}
|
||||
|
||||
PresentationReconnectCallback::~PresentationReconnectCallback()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationReconnectCallback::NotifySuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
// We found a matched connection with the same window ID, URL, and
|
||||
// the session ID. Resolve the promise with this connection and dispatch
|
||||
// the event.
|
||||
if (mConnection) {
|
||||
mPromise->MaybeResolve(mConnection);
|
||||
rv = mRequest->DispatchConnectionAvailableEvent(mConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
// Use |PresentationRequesterCallback::NotifySuccess| to create a new
|
||||
// connection since we don't find one that can be reused.
|
||||
rv = PresentationRequesterCallback::NotifySuccess();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = service->UpdateWindowIdBySessionId(mSessionId,
|
||||
mRequest->GetOwner()->WindowID());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
nsString sessionId = nsString(mSessionId);
|
||||
return NS_DispatchToMainThread(
|
||||
NS_NewRunnableFunction([sessionId, service]() -> void {
|
||||
service->BuildTransport(sessionId,
|
||||
nsIPresentationService::ROLE_CONTROLLER);
|
||||
}));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationReconnectCallback::NotifyError(nsresult aError)
|
||||
{
|
||||
return PresentationRequesterCallback::NotifyError(aError);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(PresentationResponderLoadingCallback,
|
||||
nsIWebProgressListener,
|
||||
nsISupportsWeakReference)
|
||||
|
@ -20,10 +20,11 @@ class nsIWebProgress;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PresentationConnection;
|
||||
class PresentationRequest;
|
||||
class Promise;
|
||||
|
||||
class PresentationRequesterCallback final : public nsIPresentationServiceCallback
|
||||
class PresentationRequesterCallback : public nsIPresentationServiceCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -34,14 +35,33 @@ public:
|
||||
const nsAString& aSessionId,
|
||||
Promise* aPromise);
|
||||
|
||||
private:
|
||||
~PresentationRequesterCallback();
|
||||
protected:
|
||||
virtual ~PresentationRequesterCallback();
|
||||
|
||||
RefPtr<PresentationRequest> mRequest;
|
||||
nsString mUrl;
|
||||
nsString mSessionId;
|
||||
RefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
class PresentationReconnectCallback final : public PresentationRequesterCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIPRESENTATIONSERVICECALLBACK
|
||||
|
||||
PresentationReconnectCallback(PresentationRequest* aRequest,
|
||||
const nsAString& aUrl,
|
||||
const nsAString& aSessionId,
|
||||
Promise* aPromise,
|
||||
PresentationConnection* aConnection);
|
||||
|
||||
private:
|
||||
virtual ~PresentationReconnectCallback();
|
||||
|
||||
RefPtr<PresentationConnection> mConnection;
|
||||
};
|
||||
|
||||
class PresentationResponderLoadingCallback final : public nsIWebProgressListener
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "PresentationConnection.h"
|
||||
|
||||
#include "ControllerConnectionCollection.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/MessageEvent.h"
|
||||
@ -43,10 +44,12 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aId,
|
||||
const nsAString& aUrl,
|
||||
const uint8_t aRole,
|
||||
PresentationConnectionList* aList)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mId(aId)
|
||||
, mUrl(aUrl)
|
||||
, mState(PresentationConnectionState::Connecting)
|
||||
, mOwningConnectionList(aList)
|
||||
{
|
||||
@ -62,14 +65,24 @@ PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
|
||||
/* static */ already_AddRefed<PresentationConnection>
|
||||
PresentationConnection::Create(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aId,
|
||||
const nsAString& aUrl,
|
||||
const uint8_t aRole,
|
||||
PresentationConnectionList* aList)
|
||||
{
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
RefPtr<PresentationConnection> connection =
|
||||
new PresentationConnection(aWindow, aId, aRole, aList);
|
||||
return NS_WARN_IF(!connection->Init()) ? nullptr : connection.forget();
|
||||
new PresentationConnection(aWindow, aId, aUrl, aRole, aList);
|
||||
if (NS_WARN_IF(!connection->Init())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
|
||||
ControllerConnectionCollection::GetSingleton()->AddConnection(connection,
|
||||
aRole);
|
||||
}
|
||||
|
||||
return connection.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -112,6 +125,11 @@ PresentationConnection::Shutdown()
|
||||
|
||||
rv = RemoveFromLoadGroup();
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
if (mRole == nsIPresentationService::ROLE_CONTROLLER) {
|
||||
ControllerConnectionCollection::GetSingleton()->RemoveConnection(this,
|
||||
mRole);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
@ -134,6 +152,12 @@ PresentationConnection::GetId(nsAString& aId) const
|
||||
aId = mId;
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::GetUrl(nsAString& aUrl) const
|
||||
{
|
||||
aUrl = mUrl;
|
||||
}
|
||||
|
||||
PresentationConnectionState
|
||||
PresentationConnection::State() const
|
||||
{
|
||||
@ -203,6 +227,15 @@ PresentationConnection::Terminate(ErrorResult& aRv)
|
||||
NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationConnection::Equals(uint64_t aWindowId,
|
||||
const nsAString& aId)
|
||||
{
|
||||
return GetOwner() &&
|
||||
aWindowId == GetOwner()->WindowID() &&
|
||||
mId.Equals(aId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationConnection::NotifyStateChange(const nsAString& aSessionId,
|
||||
uint16_t aState,
|
||||
@ -252,6 +285,8 @@ nsresult
|
||||
PresentationConnection::ProcessStateChanged(nsresult aReason)
|
||||
{
|
||||
switch (mState) {
|
||||
case PresentationConnectionState::Connecting:
|
||||
return NS_OK;
|
||||
case PresentationConnectionState::Connected: {
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, NS_LITERAL_STRING("connect"), false);
|
||||
@ -333,6 +368,14 @@ PresentationConnection::NotifyMessage(const nsAString& aSessionId,
|
||||
return DispatchMessageEvent(jsData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationConnection::NotifyReplaced()
|
||||
{
|
||||
return NotifyStateChange(mId,
|
||||
nsIPresentationSessionListener::STATE_CLOSED,
|
||||
NS_OK);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationConnection::DispatchConnectionClosedEvent(
|
||||
PresentationConnectionClosedReason aReason,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_PresentationConnection_h
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/dom/PresentationConnectionBinding.h"
|
||||
#include "mozilla/dom/PresentationConnectionClosedEventBinding.h"
|
||||
#include "nsIPresentationListener.h"
|
||||
@ -22,6 +23,7 @@ class PresentationConnectionList;
|
||||
class PresentationConnection final : public DOMEventTargetHelper
|
||||
, public nsIPresentationSessionListener
|
||||
, public nsIRequest
|
||||
, public SupportsWeakPtr<PresentationConnection>
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
@ -29,10 +31,12 @@ public:
|
||||
DOMEventTargetHelper)
|
||||
NS_DECL_NSIPRESENTATIONSESSIONLISTENER
|
||||
NS_DECL_NSIREQUEST
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PresentationConnection)
|
||||
|
||||
static already_AddRefed<PresentationConnection>
|
||||
Create(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aId,
|
||||
const nsAString& aUrl,
|
||||
const uint8_t aRole,
|
||||
PresentationConnectionList* aList = nullptr);
|
||||
|
||||
@ -44,6 +48,8 @@ public:
|
||||
// WebIDL (public APIs)
|
||||
void GetId(nsAString& aId) const;
|
||||
|
||||
void GetUrl(nsAString& aUrl) const;
|
||||
|
||||
PresentationConnectionState State() const;
|
||||
|
||||
void Send(const nsAString& aData,
|
||||
@ -53,6 +59,9 @@ public:
|
||||
|
||||
void Terminate(ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
Equals(uint64_t aWindowId, const nsAString& aId);
|
||||
|
||||
IMPL_EVENT_HANDLER(connect);
|
||||
IMPL_EVENT_HANDLER(close);
|
||||
IMPL_EVENT_HANDLER(terminate);
|
||||
@ -61,6 +70,7 @@ public:
|
||||
private:
|
||||
PresentationConnection(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aId,
|
||||
const nsAString& aUrl,
|
||||
const uint8_t aRole,
|
||||
PresentationConnectionList* aList);
|
||||
|
||||
@ -84,6 +94,7 @@ private:
|
||||
nsresult RemoveFromLoadGroup();
|
||||
|
||||
nsString mId;
|
||||
nsString mUrl;
|
||||
uint8_t mRole;
|
||||
PresentationConnectionState mState;
|
||||
RefPtr<PresentationConnectionList> mOwningConnectionList;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/dom/PresentationReceiverBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPresentationService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -56,7 +57,11 @@ PresentationReceiver::Init()
|
||||
}
|
||||
mWindowId = mOwner->WindowID();
|
||||
|
||||
return true;
|
||||
nsCOMPtr<nsIDocShell> docShell = mOwner->GetDocShell();
|
||||
MOZ_ASSERT(docShell);
|
||||
|
||||
nsContentUtils::GetPresentationURL(docShell, mUrl);
|
||||
return !mUrl.IsEmpty();
|
||||
}
|
||||
|
||||
void PresentationReceiver::Shutdown()
|
||||
@ -96,7 +101,7 @@ PresentationReceiver::NotifySessionConnect(uint64_t aWindowId,
|
||||
}
|
||||
|
||||
RefPtr<PresentationConnection> connection =
|
||||
PresentationConnection::Create(mOwner, aSessionId,
|
||||
PresentationConnection::Create(mOwner, aSessionId, mUrl,
|
||||
nsIPresentationService::ROLE_RECEIVER,
|
||||
mConnectionList);
|
||||
if (NS_WARN_IF(!connection)) {
|
||||
|
@ -54,6 +54,7 @@ private:
|
||||
uint64_t mWindowId;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mOwner;
|
||||
nsString mUrl;
|
||||
RefPtr<Promise> mGetConnectionListPromise;
|
||||
RefPtr<PresentationConnectionList> mConnectionList;
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "PresentationRequest.h"
|
||||
|
||||
#include "ControllerConnectionCollection.h"
|
||||
#include "mozilla/dom/PresentationRequestBinding.h"
|
||||
#include "mozilla/dom/PresentationConnectionAvailableEvent.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
@ -152,6 +153,118 @@ PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PresentationRequest::Reconnect(const nsAString& aPresentationId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// TODO: Before starting to reconnect, we have to run the prohibits
|
||||
// mixed security contexts algorithm first. This will be implemented
|
||||
// in bug 1254488.
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (doc->GetSandboxFlags() & SANDBOXED_PRESENTATION) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsString presentationId = nsString(aPresentationId);
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NewRunnableMethod<nsString, RefPtr<Promise>>(
|
||||
this,
|
||||
&PresentationRequest::FindOrCreatePresentationConnection,
|
||||
presentationId,
|
||||
promise);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
PresentationRequest::FindOrCreatePresentationConnection(
|
||||
const nsAString& aPresentationId,
|
||||
Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
if (NS_WARN_IF(!GetOwner())) {
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<PresentationConnection> connection =
|
||||
ControllerConnectionCollection::GetSingleton()->FindConnection(
|
||||
GetOwner()->WindowID(),
|
||||
aPresentationId,
|
||||
nsIPresentationService::ROLE_CONTROLLER);
|
||||
|
||||
if (connection) {
|
||||
nsAutoString url;
|
||||
connection->GetUrl(url);
|
||||
if (url.Equals(mUrl)) {
|
||||
switch (connection->State()) {
|
||||
case PresentationConnectionState::Closed:
|
||||
// We found the matched connection.
|
||||
break;
|
||||
case PresentationConnectionState::Connecting:
|
||||
case PresentationConnectionState::Connected:
|
||||
aPromise->MaybeResolve(connection);
|
||||
return;
|
||||
case PresentationConnectionState::Terminated:
|
||||
// A terminated connection cannot be reused.
|
||||
connection = nullptr;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown presentation session state.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationServiceCallback> callback =
|
||||
new PresentationReconnectCallback(this,
|
||||
mUrl,
|
||||
aPresentationId,
|
||||
aPromise,
|
||||
connection);
|
||||
|
||||
nsresult rv =
|
||||
service->ReconnectSession(mUrl,
|
||||
aPresentationId,
|
||||
nsIPresentationService::ROLE_CONTROLLER,
|
||||
callback);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PresentationRequest::GetAvailability(ErrorResult& aRv)
|
||||
{
|
||||
|
@ -36,6 +36,9 @@ public:
|
||||
already_AddRefed<Promise> StartWithDevice(const nsAString& aDeviceId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Reconnect(const nsAString& aPresentationId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetAvailability(ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(connectionavailable);
|
||||
@ -50,6 +53,9 @@ private:
|
||||
|
||||
bool Init();
|
||||
|
||||
void FindOrCreatePresentationConnection(const nsAString& aPresentationId,
|
||||
Promise* aPromise);
|
||||
|
||||
nsString mUrl;
|
||||
RefPtr<PresentationAvailability> mAvailability;
|
||||
};
|
||||
|
@ -223,6 +223,10 @@ PresentationService::Init()
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
rv = obs->AddObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
|
||||
do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
|
||||
@ -258,6 +262,13 @@ PresentationService::Observe(nsISupports* aSubject,
|
||||
}
|
||||
|
||||
return HandleTerminateRequest(request);
|
||||
} else if (!strcmp(aTopic, PRESENTATION_RECONNECT_REQUEST_TOPIC)) {
|
||||
nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
|
||||
if (NS_WARN_IF(!request)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return HandleReconnectRequest(request);
|
||||
} else if (!strcmp(aTopic, "profile-after-change")) {
|
||||
// It's expected since we add and entry to |kLayoutCategories| in
|
||||
// |nsLayoutModule.cpp| to launch this service earlier.
|
||||
@ -285,6 +296,7 @@ PresentationService::HandleShutdown()
|
||||
obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
|
||||
obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
|
||||
obs->RemoveObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC);
|
||||
obs->RemoveObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,12 +378,18 @@ PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aReques
|
||||
// Create or reuse session info.
|
||||
RefPtr<PresentationSessionInfo> info =
|
||||
GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
|
||||
if (NS_WARN_IF(info)) {
|
||||
// TODO Bug 1195605. Update here after session join/resume becomes supported.
|
||||
ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return NS_ERROR_DOM_ABORT_ERR;
|
||||
|
||||
// This is the case for reconnecting a session.
|
||||
// Update the control channel and device of the session info.
|
||||
// Call |NotifyResponderReady| to indicate the receiver page is already there.
|
||||
if (info) {
|
||||
info->SetControlChannel(ctrlChannel);
|
||||
info->SetDevice(device);
|
||||
return static_cast<PresentationPresentingInfo*>(
|
||||
info.get())->NotifyResponderReady();
|
||||
}
|
||||
|
||||
// This is the case for a new session.
|
||||
info = new PresentationPresentingInfo(url, sessionId, device);
|
||||
rv = info->Init(ctrlChannel);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -452,6 +470,53 @@ PresentationService::HandleTerminateRequest(nsIPresentationTerminateRequest* aRe
|
||||
return info->OnTerminate(ctrlChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationService::HandleReconnectRequest(nsIPresentationSessionRequest* aRequest)
|
||||
{
|
||||
nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
|
||||
nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
|
||||
if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoString sessionId;
|
||||
rv = aRequest->GetPresentationId(sessionId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ctrlChannel->Disconnect(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint64_t windowId;
|
||||
rv = GetWindowIdBySessionIdInternal(sessionId, &windowId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ctrlChannel->Disconnect(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<PresentationSessionInfo> info =
|
||||
GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
// Cannot reconnect non-existed session
|
||||
ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return NS_ERROR_DOM_ABORT_ERR;
|
||||
}
|
||||
|
||||
nsAutoString url;
|
||||
rv = aRequest->GetUrl(url);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ctrlChannel->Disconnect(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Make sure the url is the same as the previous one.
|
||||
if (NS_WARN_IF(!info->GetUrl().Equals(url))) {
|
||||
ctrlChannel->Disconnect(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return HandleSessionRequest(aRequest);
|
||||
}
|
||||
|
||||
void
|
||||
PresentationService::NotifyAvailableChange(bool aIsAvailable)
|
||||
{
|
||||
@ -642,6 +707,57 @@ PresentationService::TerminateSession(const nsAString& aSessionId,
|
||||
return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::ReconnectSession(const nsAString& aUrl,
|
||||
const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aCallback)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!info->GetUrl().Equals(aUrl))) {
|
||||
return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
}
|
||||
|
||||
return static_cast<PresentationControllingInfo*>(info.get())->Reconnect(aCallback);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::BuildTransport(const nsAString& aSessionId,
|
||||
uint8_t aRole)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "Only controller can call BuildTransport.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return static_cast<PresentationControllingInfo*>(info.get())->BuildTransport();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::RegisterAvailabilityListener(nsIPresentationAvailabilityListener* aListener)
|
||||
{
|
||||
@ -848,6 +964,13 @@ PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
|
||||
return GetWindowIdBySessionIdInternal(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
|
||||
const uint64_t aWindowId)
|
||||
{
|
||||
return UpdateWindowIdBySessionIdInternal(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationService::IsSessionAccessible(const nsAString& aSessionId,
|
||||
const uint8_t aRole,
|
||||
|
@ -68,6 +68,7 @@ private:
|
||||
nsresult HandleDeviceChange();
|
||||
nsresult HandleSessionRequest(nsIPresentationSessionRequest* aRequest);
|
||||
nsresult HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest);
|
||||
nsresult HandleReconnectRequest(nsIPresentationSessionRequest* aRequest);
|
||||
void NotifyAvailableChange(bool aIsAvailable);
|
||||
bool IsAppInstalled(nsIURI* aUri);
|
||||
|
||||
|
@ -36,6 +36,8 @@ PresentationServiceBase::GetWindowIdBySessionIdInternal(
|
||||
const nsAString& aSessionId,
|
||||
uint64_t* aWindowId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -46,6 +48,8 @@ void
|
||||
PresentationServiceBase::AddRespondingSessionId(uint64_t aWindowId,
|
||||
const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_WARN_IF(aWindowId == 0)) {
|
||||
return;
|
||||
}
|
||||
@ -63,6 +67,8 @@ PresentationServiceBase::AddRespondingSessionId(uint64_t aWindowId,
|
||||
void
|
||||
PresentationServiceBase::RemoveRespondingSessionId(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
uint64_t windowId = 0;
|
||||
if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
|
||||
mRespondingWindowIds.Remove(aSessionId);
|
||||
@ -76,5 +82,17 @@ PresentationServiceBase::RemoveRespondingSessionId(const nsAString& aSessionId)
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationServiceBase::UpdateWindowIdBySessionIdInternal(
|
||||
const nsAString& aSessionId,
|
||||
const uint64_t aWindowId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RemoveRespondingSessionId(aSessionId);
|
||||
AddRespondingSessionId(aWindowId, aSessionId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -37,6 +37,8 @@ protected:
|
||||
nsresult GetWindowIdBySessionIdInternal(const nsAString& aSessionId, uint64_t* aWindowId);
|
||||
void AddRespondingSessionId(uint64_t aWindowId, const nsAString& aSessionId);
|
||||
void RemoveRespondingSessionId(const nsAString& aSessionId);
|
||||
nsresult UpdateWindowIdBySessionIdInternal(const nsAString& aSessionId,
|
||||
const uint64_t aWindowId);
|
||||
|
||||
// Store the responding listener based on the window ID of the (in-process or
|
||||
// OOP) receiver page.
|
||||
|
@ -244,6 +244,10 @@ PresentationSessionInfo::Shutdown(nsresult aReason)
|
||||
nsresult
|
||||
PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
|
||||
{
|
||||
if (mListener && aListener) {
|
||||
NS_WARN_IF(NS_FAILED(mListener->NotifyReplaced()));
|
||||
}
|
||||
|
||||
mListener = aListener;
|
||||
|
||||
if (mListener) {
|
||||
@ -425,7 +429,8 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
|
||||
// potential subsequent |Shutdown| calls.
|
||||
mTransport = nullptr;
|
||||
|
||||
if (NS_WARN_IF(!IsSessionReady())) {
|
||||
if (NS_WARN_IF(!IsSessionReady() &&
|
||||
mState == nsIPresentationSessionListener::STATE_CONNECTING)) {
|
||||
// It happens before the session is ready. Reply the callback.
|
||||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
@ -744,6 +749,10 @@ PresentationControllingInfo::NotifyConnected()
|
||||
|
||||
switch (mState) {
|
||||
case nsIPresentationSessionListener::STATE_CONNECTING: {
|
||||
nsresult rv = mControlChannel->Launch(GetSessionId(), GetUrl());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
Unused << NS_WARN_IF(NS_FAILED(BuildTransport()));
|
||||
break;
|
||||
}
|
||||
@ -758,14 +767,27 @@ PresentationControllingInfo::NotifyConnected()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationControllingInfo::NotifyReconnected()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mReconnectCallback);
|
||||
|
||||
if (NS_WARN_IF(mState == nsIPresentationSessionListener::STATE_TERMINATED)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
SetStateWithReason(nsIPresentationSessionListener::STATE_CONNECTING, NS_OK);
|
||||
return mReconnectCallback->NotifySuccess();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationControllingInfo::BuildTransport()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv = mControlChannel->Launch(GetSessionId(), GetUrl());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
if (mState != nsIPresentationSessionListener::STATE_CONNECTING) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
|
||||
@ -807,7 +829,7 @@ PresentationControllingInfo::BuildTransport()
|
||||
if (NS_WARN_IF(!dataChannelBuilder)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
rv = dataChannelBuilder->
|
||||
nsresult rv = dataChannelBuilder->
|
||||
BuildDataChannelTransport(nsIPresentationService::ROLE_CONTROLLER,
|
||||
window,
|
||||
this);
|
||||
@ -893,6 +915,41 @@ PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationControllingInfo::Reconnect(nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
if (!aCallback) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mReconnectCallback = aCallback;
|
||||
|
||||
if (NS_WARN_IF(mState == nsIPresentationSessionListener::STATE_TERMINATED)) {
|
||||
return mReconnectCallback->NotifyError(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!mControlChannel) {
|
||||
nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
|
||||
rv = mDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return mReconnectCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
rv = Init(ctrlChannel);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return mReconnectCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
rv = mControlChannel->Reconnect(mSessionId, GetUrl());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return mReconnectCallback->NotifyError(rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of PresentationPresentingInfo
|
||||
*
|
||||
@ -1217,6 +1274,13 @@ PresentationPresentingInfo::NotifyConnected()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::NotifyReconnected()
|
||||
{
|
||||
MOZ_ASSERT(false, "NotifyReconnected should not be called at receiver side.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::NotifyDisconnected(nsresult aReason)
|
||||
{
|
||||
|
@ -186,6 +186,10 @@ public:
|
||||
|
||||
nsresult Init(nsIPresentationControlChannel* aControlChannel) override;
|
||||
|
||||
nsresult Reconnect(nsIPresentationServiceCallback* aCallback);
|
||||
|
||||
nsresult BuildTransport();
|
||||
|
||||
private:
|
||||
~PresentationControllingInfo()
|
||||
{
|
||||
@ -198,9 +202,8 @@ private:
|
||||
|
||||
nsresult OnGetAddress(const nsACString& aAddress);
|
||||
|
||||
nsresult BuildTransport();
|
||||
|
||||
nsCOMPtr<nsIServerSocket> mServerSocket;
|
||||
nsCOMPtr<nsIPresentationServiceCallback> mReconnectCallback;
|
||||
};
|
||||
|
||||
// Session info with presenting browsing context (receiver side) behaviors.
|
||||
|
@ -33,6 +33,11 @@ interface nsIPresentationSessionListener : nsISupports
|
||||
*/
|
||||
void notifyMessage(in DOMString sessionId,
|
||||
in ACString data);
|
||||
|
||||
/*
|
||||
* Called when this listener is replaced by another one.
|
||||
*/
|
||||
void notifyReplaced();
|
||||
};
|
||||
|
||||
[scriptable, uuid(27f101d7-9ed1-429e-b4f8-43b00e8e111c)]
|
||||
|
@ -98,6 +98,21 @@ interface nsIPresentationService : nsISupports
|
||||
void terminateSession(in DOMString sessionId,
|
||||
in uint8_t role);
|
||||
|
||||
/*
|
||||
* Reconnect the session.
|
||||
*
|
||||
* @param url: The url of presenting page.
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param role: Identify the function called by controller or receiver.
|
||||
* @param callback: NotifySuccess() is called when a control channel
|
||||
* is opened successfully.
|
||||
* Otherwise, NotifyError() is called with a error message.
|
||||
*/
|
||||
void reconnectSession(in DOMString url,
|
||||
in DOMString sessionId,
|
||||
in uint8_t role,
|
||||
in nsIPresentationServiceCallback callback);
|
||||
|
||||
/*
|
||||
* Register an availability listener. Must be called from the main thread.
|
||||
*
|
||||
@ -191,4 +206,23 @@ interface nsIPresentationService : nsISupports
|
||||
* The windowId for building RTCDataChannel session transport
|
||||
*/
|
||||
unsigned long long getWindowIdBySessionId(in DOMString sessionId);
|
||||
|
||||
/*
|
||||
* Update the mapping of the session ID and window ID.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param windowId: The inner window ID associated with the presentation
|
||||
* session.
|
||||
*/
|
||||
void updateWindowIdBySessionId(in DOMString sessionId,
|
||||
in unsigned long long windowId);
|
||||
|
||||
/*
|
||||
* To build the session transport.
|
||||
* NOTE: This function should be only called at controller side.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param role: Identify the function called by controller or receiver.
|
||||
*/
|
||||
void buildTransport(in DOMString sessionId, in uint8_t role);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ interface nsIPresentationControlChannel;
|
||||
|
||||
%{C++
|
||||
#define PRESENTATION_SESSION_REQUEST_TOPIC "presentation-session-request"
|
||||
#define PRESENTATION_RECONNECT_REQUEST_TOPIC "presentation-reconnect-request"
|
||||
%}
|
||||
|
||||
/*
|
||||
|
@ -42,12 +42,27 @@ struct TerminateSessionRequest
|
||||
uint8_t role;
|
||||
};
|
||||
|
||||
struct ReconnectSessionRequest
|
||||
{
|
||||
nsString url;
|
||||
nsString sessionId;
|
||||
uint8_t role;
|
||||
};
|
||||
|
||||
struct BuildTransportRequest
|
||||
{
|
||||
nsString sessionId;
|
||||
uint8_t role;
|
||||
};
|
||||
|
||||
union PresentationIPCRequest
|
||||
{
|
||||
StartSessionRequest;
|
||||
SendSessionMessageRequest;
|
||||
CloseSessionRequest;
|
||||
TerminateSessionRequest;
|
||||
ReconnectSessionRequest;
|
||||
BuildTransportRequest;
|
||||
};
|
||||
|
||||
sync protocol PPresentation
|
||||
|
@ -5,8 +5,11 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DCPresentationChannelDescription.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "PresentationBuilderChild.h"
|
||||
#include "PresentationIPCService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -28,12 +28,20 @@ PresentationContentSessionInfo::Init() {
|
||||
nsresult
|
||||
PresentationContentSessionInfo::Send(const nsAString& aData)
|
||||
{
|
||||
if (!mTransport) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->Send(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationContentSessionInfo::Close(nsresult aReason)
|
||||
{
|
||||
if (!mTransport) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->Close(aReason);
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,39 @@ PresentationIPCService::TerminateSession(const nsAString& aSessionId,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::ReconnectSession(const nsAString& aUrl,
|
||||
const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return SendRequest(aCallback, ReconnectSessionRequest(nsString(aUrl),
|
||||
nsString(aSessionId),
|
||||
aRole));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::BuildTransport(const nsAString& aSessionId,
|
||||
uint8_t aRole)
|
||||
{
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
|
||||
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId),
|
||||
aRole));
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
|
||||
const PresentationIPCRequest& aRequest)
|
||||
@ -176,6 +209,13 @@ PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aListener);
|
||||
|
||||
nsCOMPtr<nsIPresentationSessionListener> listener;
|
||||
if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) {
|
||||
NS_WARN_IF(NS_FAILED(listener->NotifyReplaced()));
|
||||
mSessionListeners.Put(aSessionId, aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mSessionListeners.Put(aSessionId, aListener);
|
||||
if (sPresentationChild) {
|
||||
NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsString(aSessionId), aRole));
|
||||
@ -245,6 +285,13 @@ PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
|
||||
return GetWindowIdBySessionIdInternal(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
|
||||
const uint64_t aWindowId)
|
||||
{
|
||||
return UpdateWindowIdBySessionIdInternal(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
|
||||
uint16_t aState,
|
||||
|
@ -62,14 +62,6 @@ private:
|
||||
nsRefPtrHashtable<nsUint64HashKey,
|
||||
nsIPresentationRespondingListener> mRespondingListeners;
|
||||
RefPtr<PresentationResponderLoadingCallback> mCallback;
|
||||
|
||||
// Store the mapping between the window ID of the OOP page (in this process)
|
||||
// and the ID of the responding session. It's used for an OOP receiver page
|
||||
// to retrieve the correspondent session ID. Besides, also keep the mapping
|
||||
// between the responding session ID and the window ID to help look up the
|
||||
// window ID.
|
||||
nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
|
||||
nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
|
||||
nsRefPtrHashtable<nsStringHashKey,
|
||||
PresentationContentSessionInfo> mSessionInfos;
|
||||
};
|
||||
|
@ -89,6 +89,12 @@ PresentationParent::RecvPPresentationRequestConstructor(
|
||||
case PresentationIPCRequest::TTerminateSessionRequest:
|
||||
rv = actor->DoRequest(aRequest.get_TerminateSessionRequest());
|
||||
break;
|
||||
case PresentationIPCRequest::TReconnectSessionRequest:
|
||||
rv = actor->DoRequest(aRequest.get_ReconnectSessionRequest());
|
||||
break;
|
||||
case PresentationIPCRequest::TBuildTransportRequest:
|
||||
rv = actor->DoRequest(aRequest.get_BuildTransportRequest());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown PresentationIPCRequest type");
|
||||
}
|
||||
@ -242,6 +248,14 @@ PresentationParent::NotifyStateChange(const nsAString& aSessionId,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationParent::NotifyReplaced()
|
||||
{
|
||||
// Do nothing here, since |PresentationIPCService::RegisterSessionListener|
|
||||
// already dealt with this in content process.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationParent::NotifyMessage(const nsAString& aSessionId,
|
||||
const nsACString& aData)
|
||||
@ -382,6 +396,48 @@ PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
|
||||
return NotifySuccess();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationRequestParent::DoRequest(const ReconnectSessionRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Validate the accessibility (primarily for receiver side) so that a
|
||||
// compromised child process can't fake the ID.
|
||||
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
|
||||
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
|
||||
|
||||
// NOTE: Return NS_ERROR_DOM_NOT_FOUND_ERR here to match the spec.
|
||||
// https://w3c.github.io/presentation-api/#reconnecting-to-a-presentation
|
||||
return NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
}
|
||||
|
||||
mNeedRegisterBuilder = true;
|
||||
mSessionId = aRequest.sessionId();
|
||||
return mService->ReconnectSession(aRequest.url(),
|
||||
aRequest.sessionId(),
|
||||
aRequest.role(),
|
||||
this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationRequestParent::DoRequest(const BuildTransportRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Validate the accessibility (primarily for receiver side) so that a
|
||||
// compromised child process can't fake the ID.
|
||||
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
|
||||
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
|
||||
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
||||
nsresult rv = mService->BuildTransport(aRequest.sessionId(), aRequest.role());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NotifyError(rv);
|
||||
}
|
||||
return NotifySuccess();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationRequestParent::NotifySuccess()
|
||||
{
|
||||
|
@ -113,6 +113,10 @@ private:
|
||||
|
||||
nsresult DoRequest(const TerminateSessionRequest& aRequest);
|
||||
|
||||
nsresult DoRequest(const ReconnectSessionRequest& aRequest);
|
||||
|
||||
nsresult DoRequest(const BuildTransportRequest& aRequest);
|
||||
|
||||
bool mActorDestroyed = false;
|
||||
bool mNeedRegisterBuilder = false;
|
||||
nsString mSessionId;
|
||||
|
@ -32,6 +32,7 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ControllerConnectionCollection.cpp',
|
||||
'DCPresentationChannelDescription.cpp',
|
||||
'ipc/PresentationBuilderChild.cpp',
|
||||
'ipc/PresentationBuilderParent.cpp',
|
||||
|
@ -29,6 +29,11 @@ interface PresentationConnection : EventTarget {
|
||||
[Constant]
|
||||
readonly attribute DOMString id;
|
||||
|
||||
/*
|
||||
* Specifies the connection's presentation URL.
|
||||
*/
|
||||
readonly attribute DOMString url;
|
||||
|
||||
/*
|
||||
* @value "connected", "closed", or "terminated".
|
||||
*/
|
||||
|
@ -24,10 +24,26 @@ interface PresentationRequest : EventTarget {
|
||||
* - "AbortError": User dismiss/cancel the device prompt box.
|
||||
* - "NetworkError": Failed to establish the control channel or data channel.
|
||||
* - "TimeoutError": Presenting page takes too long to load.
|
||||
* - "SecurityError": This operation is insecure.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<PresentationConnection> start();
|
||||
|
||||
/*
|
||||
* A requesting page can use reconnect(presentationId) to reopen a
|
||||
* non-terminated presentation connection.
|
||||
*
|
||||
* The promise is resolved when a new presentation connection is created.
|
||||
* The connection state is "connecting".
|
||||
*
|
||||
* The promise may be rejected duo to one of the following reasons:
|
||||
* - "OperationError": Unexpected error occurs.
|
||||
* - "NotFoundError": Can not find a presentation connection with the presentationId.
|
||||
* - "SecurityError": This operation is insecure.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<PresentationConnection> reconnect(DOMString presentationId);
|
||||
|
||||
/*
|
||||
* UA triggers device discovery mechanism periodically and monitor device
|
||||
* availability.
|
||||
|
Loading…
Reference in New Issue
Block a user