2022-07-26 02:46:30 +00:00
|
|
|
/* eslint-env mozilla/chrome-script */
|
2019-04-09 10:05:51 +00:00
|
|
|
|
2016-03-18 00:11:22 +00:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defers one or more callbacks until the next turn of the event loop. Multiple
|
|
|
|
* callbacks are executed in order.
|
|
|
|
*
|
|
|
|
* @param {Function[]} callbacks The callbacks to execute. One callback will be
|
|
|
|
* executed per tick.
|
|
|
|
*/
|
|
|
|
function waterfall(...callbacks) {
|
|
|
|
callbacks
|
|
|
|
.reduce(
|
|
|
|
(promise, callback) =>
|
|
|
|
promise.then(() => {
|
|
|
|
callback();
|
|
|
|
}),
|
|
|
|
Promise.resolve()
|
2019-07-05 08:44:55 +00:00
|
|
|
)
|
2022-12-20 20:52:57 +00:00
|
|
|
.catch(Cu.reportError);
|
2016-03-18 00:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Minimal implementation of a mock WebSocket connect to be used with
|
|
|
|
* PushService. Forwards and receive messages from the implementation
|
|
|
|
* that lives in the content process.
|
|
|
|
*/
|
|
|
|
function MockWebSocketParent(originalURI) {
|
|
|
|
this._originalURI = originalURI;
|
|
|
|
}
|
|
|
|
|
|
|
|
MockWebSocketParent.prototype = {
|
|
|
|
_originalURI: null,
|
|
|
|
|
|
|
|
_listener: null,
|
|
|
|
_context: null,
|
|
|
|
|
Bug 1649221: Update ChromeUtils.generateQI callers to pass strings. r=mccr8,remote-protocol-reviewers,marionette-reviewers,perftest-reviewers,webcompat-reviewers,geckoview-reviewers,preferences-reviewers,agi,whimboo,Bebe,twisniewski
Differential Revision: https://phabricator.services.mozilla.com/D81594
2020-07-10 23:58:28 +00:00
|
|
|
QueryInterface: ChromeUtils.generateQI(["nsIWebSocketChannel"]),
|
2016-03-18 00:11:22 +00:00
|
|
|
|
|
|
|
get originalURI() {
|
|
|
|
return this._originalURI;
|
|
|
|
},
|
|
|
|
|
2021-07-21 12:44:40 +00:00
|
|
|
asyncOpen(uri, origin, originAttributes, windowId, listener, context) {
|
2016-03-18 00:11:22 +00:00
|
|
|
this._listener = listener;
|
|
|
|
this._context = context;
|
|
|
|
waterfall(() => this._listener.onStart(this._context));
|
|
|
|
},
|
|
|
|
|
|
|
|
sendMsg(msg) {
|
2016-03-23 00:34:41 +00:00
|
|
|
sendAsyncMessage("socket-client-msg", msg);
|
2016-03-18 00:11:22 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
close() {
|
|
|
|
waterfall(() => this._listener.onStop(this._context, Cr.NS_OK));
|
|
|
|
},
|
|
|
|
|
|
|
|
serverSendMsg(msg) {
|
|
|
|
waterfall(
|
|
|
|
() => this._listener.onMessageAvailable(this._context, msg),
|
|
|
|
() => this._listener.onAcknowledge(this._context, 0)
|
|
|
|
);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
var pushService = Cc["@mozilla.org/push/Service;1"].getService(
|
|
|
|
Ci.nsIPushService
|
|
|
|
).wrappedJSObject;
|
|
|
|
|
2016-04-08 18:39:00 +00:00
|
|
|
var mockSocket;
|
|
|
|
var serverMsgs = [];
|
2016-03-18 00:11:22 +00:00
|
|
|
|
2023-05-20 12:26:49 +00:00
|
|
|
addMessageListener("socket-setup", function () {
|
2016-04-08 18:39:00 +00:00
|
|
|
pushService.replaceServiceBackend({
|
|
|
|
serverURI: "wss://push.example.org/",
|
|
|
|
makeWebSocket(uri) {
|
|
|
|
mockSocket = new MockWebSocketParent(uri);
|
2022-09-02 11:05:17 +00:00
|
|
|
while (serverMsgs.length) {
|
2016-04-08 18:39:00 +00:00
|
|
|
let msg = serverMsgs.shift();
|
|
|
|
mockSocket.serverSendMsg(msg);
|
2016-03-18 00:11:22 +00:00
|
|
|
}
|
2016-04-08 18:39:00 +00:00
|
|
|
return mockSocket;
|
2019-04-09 10:05:51 +00:00
|
|
|
},
|
2016-03-18 00:11:22 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-05-20 12:26:49 +00:00
|
|
|
addMessageListener("socket-teardown", function (msg) {
|
2016-04-08 18:39:00 +00:00
|
|
|
pushService
|
|
|
|
.restoreServiceBackend()
|
|
|
|
.then(_ => {
|
|
|
|
serverMsgs.length = 0;
|
|
|
|
if (mockSocket) {
|
|
|
|
mockSocket.close();
|
|
|
|
mockSocket = null;
|
|
|
|
}
|
|
|
|
sendAsyncMessage("socket-server-teardown");
|
|
|
|
})
|
|
|
|
.catch(error => {
|
2022-12-20 20:52:57 +00:00
|
|
|
Cu.reportError(`Error restoring service backend: ${error}`);
|
2019-04-09 10:05:51 +00:00
|
|
|
});
|
2016-03-18 00:11:22 +00:00
|
|
|
});
|
|
|
|
|
2023-05-20 12:26:49 +00:00
|
|
|
addMessageListener("socket-server-msg", function (msg) {
|
2016-04-08 18:39:00 +00:00
|
|
|
if (mockSocket) {
|
|
|
|
mockSocket.serverSendMsg(msg);
|
|
|
|
} else {
|
|
|
|
serverMsgs.push(msg);
|
|
|
|
}
|
2016-03-18 00:11:22 +00:00
|
|
|
});
|
2016-03-23 00:34:41 +00:00
|
|
|
|
|
|
|
var MockService = {
|
|
|
|
requestID: 1,
|
|
|
|
resolvers: new Map(),
|
|
|
|
|
|
|
|
sendRequest(name, params) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let id = this.requestID++;
|
|
|
|
this.resolvers.set(id, { resolve, reject });
|
|
|
|
sendAsyncMessage("service-request", {
|
2019-04-09 10:05:51 +00:00
|
|
|
name,
|
|
|
|
id,
|
2020-04-20 22:15:19 +00:00
|
|
|
// The request params from the real push service may contain a
|
|
|
|
// principal, which cannot be passed to the unprivileged
|
|
|
|
// mochitest scope, and will cause the message to be dropped if
|
|
|
|
// present. The mochitest scope fortunately does not need the
|
|
|
|
// principal, though, so set it to null before sending.
|
|
|
|
params: Object.assign({}, params, { principal: null }),
|
2016-03-23 00:34:41 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
handleResponse(response) {
|
|
|
|
if (!this.resolvers.has(response.id)) {
|
2022-12-20 20:52:57 +00:00
|
|
|
Cu.reportError(`Unexpected response for request ${response.id}`);
|
2016-03-23 00:34:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
let resolver = this.resolvers.get(response.id);
|
|
|
|
this.resolvers.delete(response.id);
|
|
|
|
if (response.error) {
|
|
|
|
resolver.reject(response.error);
|
|
|
|
} else {
|
|
|
|
resolver.resolve(response.result);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
init() {},
|
|
|
|
|
|
|
|
register(pageRecord) {
|
|
|
|
return this.sendRequest("register", pageRecord);
|
|
|
|
},
|
|
|
|
|
|
|
|
registration(pageRecord) {
|
|
|
|
return this.sendRequest("registration", pageRecord);
|
|
|
|
},
|
|
|
|
|
|
|
|
unregister(pageRecord) {
|
|
|
|
return this.sendRequest("unregister", pageRecord);
|
|
|
|
},
|
2016-03-28 18:40:58 +00:00
|
|
|
|
|
|
|
reportDeliveryError(messageId, reason) {
|
|
|
|
sendAsyncMessage("service-delivery-error", {
|
2019-04-09 10:05:51 +00:00
|
|
|
messageId,
|
|
|
|
reason,
|
2016-03-28 18:40:58 +00:00
|
|
|
});
|
|
|
|
},
|
2019-03-14 22:37:51 +00:00
|
|
|
|
|
|
|
uninit() {
|
|
|
|
return Promise.resolve();
|
|
|
|
},
|
2016-03-23 00:34:41 +00:00
|
|
|
};
|
|
|
|
|
2019-03-14 22:37:51 +00:00
|
|
|
async function replaceService(service) {
|
|
|
|
await pushService.service.uninit();
|
|
|
|
pushService.service = service;
|
|
|
|
await pushService.service.init();
|
|
|
|
}
|
|
|
|
|
2023-05-20 12:26:49 +00:00
|
|
|
addMessageListener("service-replace", function () {
|
2019-03-14 22:37:51 +00:00
|
|
|
replaceService(MockService)
|
|
|
|
.then(_ => {
|
|
|
|
sendAsyncMessage("service-replaced");
|
|
|
|
})
|
|
|
|
.catch(error => {
|
2022-12-20 20:52:57 +00:00
|
|
|
Cu.reportError(`Error replacing service: ${error}`);
|
2019-03-14 22:37:51 +00:00
|
|
|
});
|
2016-03-23 00:34:41 +00:00
|
|
|
});
|
|
|
|
|
2023-05-20 12:26:49 +00:00
|
|
|
addMessageListener("service-restore", function () {
|
2019-03-14 22:37:51 +00:00
|
|
|
replaceService(null)
|
|
|
|
.then(_ => {
|
|
|
|
sendAsyncMessage("service-restored");
|
|
|
|
})
|
|
|
|
.catch(error => {
|
2022-12-20 20:52:57 +00:00
|
|
|
Cu.reportError(`Error restoring service: ${error}`);
|
2019-03-14 22:37:51 +00:00
|
|
|
});
|
2016-03-23 00:34:41 +00:00
|
|
|
});
|
|
|
|
|
2023-05-20 12:26:49 +00:00
|
|
|
addMessageListener("service-response", function (response) {
|
2016-03-23 00:34:41 +00:00
|
|
|
MockService.handleResponse(response);
|
|
|
|
});
|