2016-03-18 00:11:22 +00:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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()).catch(Cu.reportError);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([
|
|
|
|
Ci.nsISupports,
|
|
|
|
Ci.nsIWebSocketChannel
|
|
|
|
]),
|
|
|
|
|
|
|
|
get originalURI() {
|
|
|
|
return this._originalURI;
|
|
|
|
},
|
|
|
|
|
|
|
|
asyncOpen(uri, origin, windowId, listener, context) {
|
|
|
|
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));
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
function MockNetworkInfo() {}
|
|
|
|
|
|
|
|
MockNetworkInfo.prototype = {
|
|
|
|
getNetworkInformation() {
|
|
|
|
return {mcc: '', mnc: '', ip: ''};
|
|
|
|
},
|
|
|
|
|
|
|
|
getNetworkState(callback) {
|
|
|
|
callback({mcc: '', mnc: '', ip: '', netid: ''});
|
|
|
|
},
|
|
|
|
|
|
|
|
getNetworkStateChangeEventName() {
|
|
|
|
return 'network:offline-status-changed';
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var pushService = Cc["@mozilla.org/push/Service;1"].
|
|
|
|
getService(Ci.nsIPushService).
|
|
|
|
wrappedJSObject;
|
|
|
|
|
|
|
|
var mockWebSocket;
|
|
|
|
|
2016-03-23 00:34:41 +00:00
|
|
|
addMessageListener("socket-setup", function () {
|
2016-03-18 00:11:22 +00:00
|
|
|
mockWebSocket = new Promise((resolve, reject) => {
|
2016-03-19 07:35:57 +00:00
|
|
|
var mockSocket = null;
|
2016-03-18 00:11:22 +00:00
|
|
|
pushService.replaceServiceBackend({
|
|
|
|
serverURI: "wss://push.example.org/",
|
|
|
|
networkInfo: new MockNetworkInfo(),
|
|
|
|
makeWebSocket(uri) {
|
2016-03-19 07:35:57 +00:00
|
|
|
if (!mockSocket) {
|
|
|
|
mockSocket = new MockWebSocketParent(uri);
|
|
|
|
resolve(mockSocket);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mockSocket;
|
2016-03-18 00:11:22 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-03-23 00:34:41 +00:00
|
|
|
addMessageListener("socket-teardown", function () {
|
2016-03-18 00:11:22 +00:00
|
|
|
mockWebSocket.then(socket => {
|
|
|
|
socket.close();
|
|
|
|
pushService.restoreServiceBackend();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-03-23 00:34:41 +00:00
|
|
|
addMessageListener("socket-server-msg", function (msg) {
|
2016-03-18 00:11:22 +00:00
|
|
|
mockWebSocket.then(socket => {
|
|
|
|
socket.serverSendMsg(msg);
|
|
|
|
});
|
|
|
|
});
|
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", {
|
|
|
|
name: name,
|
|
|
|
id: id,
|
|
|
|
params: params,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
handleResponse(response) {
|
|
|
|
if (!this.resolvers.has(response.id)) {
|
|
|
|
Cu.reportError(`Unexpected response for request ${response.id}`);
|
|
|
|
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", {
|
|
|
|
messageId: messageId,
|
|
|
|
reason: reason,
|
|
|
|
});
|
|
|
|
},
|
2016-03-23 00:34:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
addMessageListener("service-replace", function () {
|
|
|
|
pushService.service = MockService;
|
|
|
|
});
|
|
|
|
|
|
|
|
addMessageListener("service-restore", function () {
|
|
|
|
pushService.service = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
addMessageListener("service-response", function (response) {
|
|
|
|
MockService.handleResponse(response);
|
|
|
|
});
|