mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-01 05:18:38 +09:00
366 lines
12 KiB
JavaScript
366 lines
12 KiB
JavaScript
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
|
/* 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/. */
|
|
|
|
'use strict';
|
|
|
|
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
|
|
|
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
Cu.import('resource://gre/modules/Services.jsm');
|
|
|
|
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
|
.getService(Ci.nsIUUIDGenerator);
|
|
|
|
function debug(str) {
|
|
// dump('DEBUG -*- PresentationSessionChromeScript1UA -*-: ' + str + '\n');
|
|
}
|
|
|
|
const originalFactoryData = [];
|
|
var sessionId; // Store the uuid generated by PresentationRequest.
|
|
var triggerControlChannelError = false; // For simulating error during control channel establishment.
|
|
|
|
// control channel of sender
|
|
const mockControlChannelOfSender = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
|
|
set listener(listener) {
|
|
// PresentationControllingInfo::SetControlChannel
|
|
if (listener) {
|
|
debug('set listener for mockControlChannelOfSender without null');
|
|
} else {
|
|
debug('set listener for mockControlChannelOfSender with null');
|
|
}
|
|
this._listener = listener;
|
|
},
|
|
get listener() {
|
|
return this._listener;
|
|
},
|
|
notifyConnected: function() {
|
|
// send offer after notifyConnected immediately
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.notifyConnected();
|
|
},
|
|
notifyReconnected: function() {
|
|
// send offer after notifyOpened immediately
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.notifyReconnected();
|
|
},
|
|
sendOffer: function(offer) {
|
|
Services.tm.mainThread.dispatch(() => {
|
|
mockControlChannelOfReceiver.onOffer(offer);
|
|
}, Ci.nsIThread.DISPATCH_NORMAL);
|
|
},
|
|
onAnswer: function(answer) {
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.onAnswer(answer);
|
|
},
|
|
launch: function(presentationId, url) {
|
|
sessionId = presentationId;
|
|
sendAsyncMessage('sender-launch', url);
|
|
},
|
|
disconnect: function(reason) {
|
|
if (!this._listener) {
|
|
return;
|
|
}
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.notifyDisconnected(reason);
|
|
mockControlChannelOfReceiver.disconnect();
|
|
},
|
|
terminate: function(presentationId) {
|
|
sendAsyncMessage('sender-terminate');
|
|
},
|
|
reconnect: function(presentationId, url) {
|
|
sendAsyncMessage('start-reconnect', url);
|
|
},
|
|
sendIceCandidate: function(candidate) {
|
|
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
|
|
},
|
|
notifyIceCandidate: function(candidate) {
|
|
if (!this._listener) {
|
|
return;
|
|
}
|
|
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.onIceCandidate(candidate);
|
|
},
|
|
};
|
|
|
|
// control channel of receiver
|
|
const mockControlChannelOfReceiver = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
|
|
set listener(listener) {
|
|
// PresentationPresentingInfo::SetControlChannel
|
|
if (listener) {
|
|
debug('set listener for mockControlChannelOfReceiver without null');
|
|
} else {
|
|
debug('set listener for mockControlChannelOfReceiver with null');
|
|
}
|
|
this._listener = listener;
|
|
|
|
if (this._pendingOpened) {
|
|
this._pendingOpened = false;
|
|
this.notifyConnected();
|
|
}
|
|
},
|
|
get listener() {
|
|
return this._listener;
|
|
},
|
|
notifyConnected: function() {
|
|
// do nothing
|
|
if (!this._listener) {
|
|
this._pendingOpened = true;
|
|
return;
|
|
}
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.notifyConnected();
|
|
},
|
|
onOffer: function(offer) {
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.onOffer(offer);
|
|
},
|
|
sendAnswer: function(answer) {
|
|
Services.tm.mainThread.dispatch(() => {
|
|
mockControlChannelOfSender.onAnswer(answer);
|
|
}, Ci.nsIThread.DISPATCH_NORMAL);
|
|
},
|
|
disconnect: function(reason) {
|
|
if (!this._listener) {
|
|
return;
|
|
}
|
|
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.notifyDisconnected(reason);
|
|
sendAsyncMessage('control-channel-receiver-closed', reason);
|
|
},
|
|
terminate: function(presentaionId) {
|
|
},
|
|
sendIceCandidate: function(candidate) {
|
|
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
|
|
},
|
|
notifyIceCandidate: function(candidate) {
|
|
if (!this._listener) {
|
|
return;
|
|
}
|
|
|
|
this._listener
|
|
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
|
.onIceCandidate(candidate);
|
|
},
|
|
};
|
|
|
|
const mockDevice = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
|
|
id: 'id',
|
|
name: 'name',
|
|
type: 'type',
|
|
establishControlChannel: function(url, presentationId) {
|
|
if (triggerControlChannelError) {
|
|
throw Cr.NS_ERROR_FAILURE;
|
|
}
|
|
sendAsyncMessage('control-channel-established');
|
|
return mockControlChannelOfSender;
|
|
},
|
|
disconnect: function() {
|
|
sendAsyncMessage('device-disconnected');
|
|
},
|
|
isRequestedUrlSupported: function(requestedUrl) {
|
|
return true;
|
|
},
|
|
};
|
|
|
|
const mockDevicePrompt = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
|
|
Ci.nsIFactory]),
|
|
createInstance: function(aOuter, aIID) {
|
|
if (aOuter) {
|
|
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
|
}
|
|
return this.QueryInterface(aIID);
|
|
},
|
|
set request(request) {
|
|
this._request = request;
|
|
},
|
|
get request() {
|
|
return this._request;
|
|
},
|
|
promptDeviceSelection: function(request) {
|
|
this._request = request;
|
|
sendAsyncMessage('device-prompt');
|
|
},
|
|
simulateSelect: function() {
|
|
this._request.select(mockDevice);
|
|
},
|
|
simulateCancel: function() {
|
|
this._request.cancel();
|
|
}
|
|
};
|
|
|
|
const mockRequestUIGlue = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
|
|
Ci.nsIFactory]),
|
|
set promise(aPromise) {
|
|
this._promise = aPromise
|
|
},
|
|
get promise() {
|
|
return this._promise;
|
|
},
|
|
createInstance: function(aOuter, aIID) {
|
|
if (aOuter) {
|
|
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
|
}
|
|
return this.QueryInterface(aIID);
|
|
},
|
|
sendRequest: function(aUrl, aSessionId) {
|
|
return this.promise;
|
|
},
|
|
};
|
|
|
|
function initMockAndListener() {
|
|
|
|
function registerMockFactory(contractId, mockClassId, mockFactory) {
|
|
var originalClassId, originalFactory;
|
|
|
|
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
if (!registrar.isCIDRegistered(mockClassId)) {
|
|
try {
|
|
originalClassId = registrar.contractIDToCID(contractId);
|
|
originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
|
|
} catch (ex) {
|
|
originalClassId = "";
|
|
originalFactory = null;
|
|
}
|
|
if (originalFactory) {
|
|
registrar.unregisterFactory(originalClassId, originalFactory);
|
|
}
|
|
registrar.registerFactory(mockClassId, "", contractId, mockFactory);
|
|
}
|
|
|
|
return { contractId: contractId,
|
|
mockClassId: mockClassId,
|
|
mockFactory: mockFactory,
|
|
originalClassId: originalClassId,
|
|
originalFactory: originalFactory };
|
|
}
|
|
// Register mock factories.
|
|
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
|
.getService(Ci.nsIUUIDGenerator);
|
|
originalFactoryData.push(registerMockFactory("@mozilla.org/presentation-device/prompt;1",
|
|
uuidGenerator.generateUUID(),
|
|
mockDevicePrompt));
|
|
originalFactoryData.push(registerMockFactory("@mozilla.org/presentation/requestuiglue;1",
|
|
uuidGenerator.generateUUID(),
|
|
mockRequestUIGlue));
|
|
|
|
addMessageListener('trigger-device-add', function() {
|
|
debug('Got message: trigger-device-add');
|
|
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
|
|
.getService(Ci.nsIPresentationDeviceManager);
|
|
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
|
|
.addDevice(mockDevice);
|
|
});
|
|
|
|
addMessageListener('trigger-device-prompt-select', function() {
|
|
debug('Got message: trigger-device-prompt-select');
|
|
mockDevicePrompt.simulateSelect();
|
|
});
|
|
|
|
addMessageListener('trigger-on-session-request', function(url) {
|
|
debug('Got message: trigger-on-session-request');
|
|
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
|
|
.getService(Ci.nsIPresentationDeviceManager);
|
|
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
|
|
.onSessionRequest(mockDevice,
|
|
url,
|
|
sessionId,
|
|
mockControlChannelOfReceiver);
|
|
});
|
|
|
|
addMessageListener('trigger-on-terminate-request', function() {
|
|
debug('Got message: trigger-on-terminate-request');
|
|
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
|
|
.getService(Ci.nsIPresentationDeviceManager);
|
|
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
|
|
.onTerminateRequest(mockDevice,
|
|
sessionId,
|
|
mockControlChannelOfReceiver,
|
|
false);
|
|
});
|
|
|
|
addMessageListener('trigger-control-channel-open', function(reason) {
|
|
debug('Got message: trigger-control-channel-open');
|
|
mockControlChannelOfSender.notifyConnected();
|
|
mockControlChannelOfReceiver.notifyConnected();
|
|
});
|
|
|
|
addMessageListener('trigger-control-channel-error', function(reason) {
|
|
debug('Got message: trigger-control-channel-open');
|
|
triggerControlChannelError = true;
|
|
});
|
|
|
|
addMessageListener('trigger-reconnected-acked', function(url) {
|
|
debug('Got message: trigger-reconnected-acked');
|
|
mockControlChannelOfSender.notifyReconnected();
|
|
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
|
|
.getService(Ci.nsIPresentationDeviceManager);
|
|
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
|
|
.onReconnectRequest(mockDevice,
|
|
url,
|
|
sessionId,
|
|
mockControlChannelOfReceiver);
|
|
});
|
|
|
|
// Used to call sendAsyncMessage in chrome script from receiver.
|
|
addMessageListener('forward-command', function(command_data) {
|
|
let command = JSON.parse(command_data);
|
|
sendAsyncMessage(command.name, command.data);
|
|
});
|
|
|
|
addMessageListener('teardown', teardown);
|
|
|
|
var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
|
obs.addObserver(function setupRequestPromiseHandler(aSubject, aTopic, aData) {
|
|
debug('Got observer: setup-request-promise');
|
|
obs.removeObserver(setupRequestPromiseHandler, aTopic);
|
|
mockRequestUIGlue.promise = aSubject;
|
|
sendAsyncMessage('promise-setup-ready');
|
|
}, 'setup-request-promise', false);
|
|
}
|
|
|
|
function teardown() {
|
|
|
|
function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
|
|
if (originalFactory) {
|
|
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
registrar.unregisterFactory(mockedClassId, mockedFactory);
|
|
registrar.registerFactory(originalClassId, "", contractId, originalFactory);
|
|
}
|
|
}
|
|
|
|
mockRequestUIGlue.promise = null;
|
|
mockControlChannelOfSender.listener = null;
|
|
mockControlChannelOfReceiver.listener = null;
|
|
mockDevicePrompt.request = null;
|
|
|
|
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
|
|
.getService(Ci.nsIPresentationDeviceManager);
|
|
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
|
|
.removeDevice(mockDevice);
|
|
// Register original factories.
|
|
for (var data of originalFactoryData) {
|
|
registerOriginalFactory(data.contractId, data.mockClassId,
|
|
data.mockFactory, data.originalClassId,
|
|
data.originalFactory);
|
|
}
|
|
sendAsyncMessage('teardown-complete');
|
|
}
|
|
|
|
initMockAndListener();
|