зеркало из https://github.com/mozilla/pluotsorbet.git
267 строки
8.3 KiB
JavaScript
267 строки
8.3 KiB
JavaScript
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
|
|
|
'use strict';
|
|
|
|
function loadScript(path) {
|
|
return new Promise(function(resolve, reject) {
|
|
var element = document.createElement('script');
|
|
element.setAttribute("type", "text/javascript");
|
|
element.setAttribute("src", path);
|
|
document.getElementsByTagName("head")[0].appendChild(element);
|
|
element.onload = resolve;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Pre-load dependencies and then load the main page.
|
|
*/
|
|
(function() {
|
|
var midletClassName = urlParams.midletClassName ? urlParams.midletClassName.replace(/\//g, '.') : "RunTests";
|
|
var loadingPromises = [];
|
|
if (midletClassName == "RunTests") {
|
|
loadingPromises.push(loadScript("tests/contacts.js"),
|
|
loadScript("tests/index.js"));
|
|
}
|
|
|
|
Promise.all(loadingPromises).then(function() {
|
|
document.getElementById("mozbrowser").src = "main.html" + location.search;
|
|
});
|
|
})();
|
|
|
|
var DumbPipe = {
|
|
// Functions that handle requests to open a pipe, indexed by type.
|
|
openers: {},
|
|
|
|
// Functions that receive messages from the other side for active pipes.
|
|
recipients: {},
|
|
|
|
// Queue of messages to send to the other side. Retrieved by the other side
|
|
// via a "get" message.
|
|
outgoingMessages: [],
|
|
|
|
// Every time we want to make the other side retrieve messages, the hash
|
|
// of the other side's web page has to change, so we increment it.
|
|
nextHashID: 0,
|
|
|
|
registerOpener: function(type, opener) {
|
|
this.openers[type] = opener;
|
|
},
|
|
|
|
handleEvent: function(event) {
|
|
if (event.detail.promptType == "custom-prompt") {
|
|
console.warn("unresponsive script warning; figure out how to handle");
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* We embed messages in the mozbrowsershowmodalprompt event's detail.message
|
|
* property. The value of that property is a JSON string representing
|
|
* the message envelope, whose inner "message" property contains the actual
|
|
* message.
|
|
*
|
|
* @property command {String} the command to invoke: open|message|get|close
|
|
* @property type {String} the type of pipe to open (when command == open)
|
|
* @property pipeID {Number} unique ID (when command == open|message|close)
|
|
* @property message {String} the JSON message to forward to this side
|
|
*/
|
|
var envelope = JSON.parse(event.detail.message);
|
|
|
|
switch (envelope.command) {
|
|
case "open":
|
|
//console.log("outer recv: " + JSON.stringify(envelope));
|
|
this.openPipe(envelope.pipeID, envelope.type, envelope.message);
|
|
break;
|
|
case "message":
|
|
//console.log("outer recv: " + JSON.stringify(envelope));
|
|
this.receiveMessage(envelope.pipeID, envelope.message);
|
|
break;
|
|
case "get":
|
|
this.getMessages(event);
|
|
break;
|
|
case "close":
|
|
//console.log("outer recv: " + JSON.stringify(envelope));
|
|
this.closePipe(envelope.pipeID);
|
|
break;
|
|
}
|
|
},
|
|
|
|
openPipe: function(pipeID, type, message) {
|
|
var opener = this.openers[type];
|
|
|
|
if (!opener) {
|
|
console.error("no opener for pipe type " + type);
|
|
return;
|
|
}
|
|
|
|
// Create a function that this side of the boundary can use to send
|
|
// a message to the other side.
|
|
var sender = this.sendMessage.bind(this, pipeID);
|
|
|
|
this.recipients[pipeID] = opener(message, sender);
|
|
},
|
|
|
|
sendMessage: function(pipeID, message) {
|
|
// Sadly, we have no way to send a message to the other side directly.
|
|
// Instead, we change the hash part of the other side's URL, which triggers
|
|
// a hashchange event on the other side. A listener on the other side
|
|
// then sends us a "get" prompt, and we set its return value to the message.
|
|
// Oh my shod, that's some funky git!
|
|
var envelope = { pipeID: pipeID, message: message };
|
|
//console.log("outer send: " + JSON.stringify(envelope));
|
|
this.outgoingMessages.push(envelope);
|
|
|
|
var mozbrowser = document.getElementById("mozbrowser");
|
|
window.setZeroTimeout(function() {
|
|
mozbrowser.src = mozbrowser.src.split("#")[0] + "#" + this.nextHashID++;
|
|
}.bind(this));
|
|
},
|
|
|
|
receiveMessage: function(pipeID, message, detail) {
|
|
window.setZeroTimeout(function() {
|
|
if (!this.recipients[pipeID]) {
|
|
console.warn("nonexistent pipe " + pipeID + " received message " + JSON.stringify(message));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
this.recipients[pipeID](message);
|
|
} catch(ex) {
|
|
console.error(ex + "\n" + ex.stack);
|
|
}
|
|
}.bind(this));
|
|
},
|
|
|
|
getMessages: function(event) {
|
|
try {
|
|
event.detail.returnValue = JSON.stringify(this.outgoingMessages);
|
|
} catch(ex) {
|
|
console.error("failed to stringify outgoing messages: " + ex);
|
|
} finally {
|
|
this.outgoingMessages = [];
|
|
event.detail.unblock();
|
|
}
|
|
},
|
|
|
|
closePipe: function(pipeID) {
|
|
delete this.recipients[pipeID];
|
|
}
|
|
};
|
|
|
|
document.getElementById("mozbrowser").addEventListener("mozbrowsershowmodalprompt",
|
|
DumbPipe.handleEvent.bind(DumbPipe),
|
|
true);
|
|
|
|
DumbPipe.registerOpener("mobileInfo", function(message, sender) {
|
|
// Initialize the object with the URL params and fallback placeholders
|
|
// for testing/debugging on a desktop.
|
|
var mobileInfo = {
|
|
network: {
|
|
mcc: urlParams.network_mcc || "310", // United States
|
|
mnc: urlParams.network_mnc || "001",
|
|
},
|
|
icc: {
|
|
mcc: urlParams.icc_mcc || "310", // United States
|
|
mnc: urlParams.icc_mnc || "001",
|
|
msisdn: urlParams.icc_msisdn || "10005551212",
|
|
},
|
|
};
|
|
|
|
var mobileConnections = window.navigator.mozMobileConnections;
|
|
if (!mobileConnections && window.navigator.mozMobileConnection) {
|
|
mobileConnections = [ window.navigator.mozMobileConnection ];
|
|
}
|
|
|
|
// If we have access to the Mobile Connection API, then we use it to get
|
|
// the actual values.
|
|
if (mobileConnections) {
|
|
// Then the only part of the Mobile Connection API that is accessible
|
|
// to privileged apps is lastKnownNetwork and lastKnownHomeNetwork, which
|
|
// is fortunately all we need. lastKnownNetwork is a string of format
|
|
// "<mcc>-<mnc>", while lastKnownHomeNetwork is "<mcc>-<mnc>[-<spn>]".
|
|
// Use only the info about the first SIM for the time being.
|
|
var lastKnownNetwork = mobileConnections[0].lastKnownNetwork.split("-");
|
|
mobileInfo.network.mcc = lastKnownNetwork[0];
|
|
mobileInfo.network.mnc = lastKnownNetwork[1];
|
|
|
|
var lastKnownHomeNetwork = mobileConnections[0].lastKnownHomeNetwork.split("-");
|
|
mobileInfo.icc.mcc = lastKnownHomeNetwork[0];
|
|
mobileInfo.icc.mnc = lastKnownHomeNetwork[1];
|
|
}
|
|
|
|
sender(mobileInfo);
|
|
});
|
|
|
|
DumbPipe.registerOpener("contacts", function(message, sender) {
|
|
var req = navigator.mozContacts.getAll();
|
|
|
|
req.onsuccess = function() {
|
|
var contact = req.result;
|
|
sender(contact);
|
|
if (contact) {
|
|
req.continue();
|
|
}
|
|
}
|
|
|
|
req.onerror = function() {
|
|
console.error("Error while reading contacts");
|
|
}
|
|
});
|
|
|
|
DumbPipe.registerOpener("socket", function(message, sender) {
|
|
var socket;
|
|
try {
|
|
socket = navigator.mozTCPSocket.open(message.host, message.port, { binaryType: "arraybuffer" });
|
|
} catch(ex) {
|
|
sender({ type: "error", error: "error opening socket" });
|
|
return function() {};
|
|
}
|
|
|
|
socket.onopen = function() {
|
|
sender({ type: "open" });
|
|
}
|
|
|
|
socket.onerror = function(event) {
|
|
sender({ type: "error", error: event.data.name });
|
|
}
|
|
|
|
socket.ondata = function(event) {
|
|
// Turn the buffer into a regular Array to traverse the mozbrowser boundary.
|
|
var array = Array.prototype.slice.call(new Uint8Array(event.data));
|
|
array.constructor = Array;
|
|
|
|
sender({ type: "data", data: array });
|
|
}
|
|
|
|
socket.ondrain = function(event) {
|
|
sender({ type: "drain" });
|
|
}
|
|
|
|
socket.onclose = function(event) {
|
|
sender({ type: "close" });
|
|
}
|
|
|
|
var send = function(data) {
|
|
// Convert the data back to an Int8Array.
|
|
data = new Int8Array(data);
|
|
|
|
try {
|
|
var result = socket.send(data.buffer, 0, data.length);
|
|
sender({ type: "send", result: result });
|
|
} catch (ex) {
|
|
sender({ type: "send", error: ex.toString() });
|
|
}
|
|
};
|
|
|
|
return function(message) {
|
|
switch (message.type) {
|
|
case "send":
|
|
send(message.data);
|
|
break;
|
|
case "close":
|
|
socket.close();
|
|
break;
|
|
}
|
|
};
|
|
});
|