mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
305 lines
9.1 KiB
JavaScript
305 lines
9.1 KiB
JavaScript
// ***** BEGIN LICENSE BLOCK *****
|
|
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
//
|
|
// The contents of this file are subject to the Mozilla Public License Version
|
|
// 1.1 (the "License"); you may not use this file except in compliance with
|
|
// the License. You may obtain a copy of the License at
|
|
// http://www.mozilla.org/MPL/
|
|
//
|
|
// Software distributed under the License is distributed on an "AS IS" basis,
|
|
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
// for the specific language governing rights and limitations under the
|
|
// License.
|
|
//
|
|
// The Original Code is Mozilla Corporation Code.
|
|
//
|
|
// The Initial Developer of the Original Code is
|
|
// based on the MozRepl project.
|
|
// Portions created by the Initial Developer are Copyright (C) 2008
|
|
// the Initial Developer. All Rights Reserved.
|
|
//
|
|
// Contributor(s):
|
|
// Mikeal Rogers <mikeal.rogers@gmail.com>
|
|
// Massimiliano Mirra <bard@hyperstruct.net>
|
|
//
|
|
// Alternatively, the contents of this file may be used under the terms of
|
|
// either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
// in which case the provisions of the GPL or the LGPL are applicable instead
|
|
// of those above. If you wish to allow use of your version of this file only
|
|
// under the terms of either the GPL or the LGPL, and not to allow others to
|
|
// use your version of this file under the terms of the MPL, indicate your
|
|
// decision by deleting the provisions above and replace them with the notice
|
|
// and other provisions required by the GPL or the LGPL. If you do not delete
|
|
// the provisions above, a recipient may use your version of this file under
|
|
// the terms of any one of the MPL, the GPL or the LGPL.
|
|
//
|
|
// ***** END LICENSE BLOCK *****
|
|
|
|
var EXPORTED_SYMBOLS = ["Server", "server", "AsyncRead", "Session", "sessions", "globalRegistry", "startServer"];
|
|
|
|
var events = {}; Components.utils.import("resource://jsbridge/modules/events.js", events);
|
|
|
|
const Cc = Components.classes;
|
|
const Ci = Components.interfaces;
|
|
const loader = Cc['@mozilla.org/moz/jssubscript-loader;1']
|
|
.getService(Ci.mozIJSSubScriptLoader);
|
|
|
|
var hwindow = Components.classes["@mozilla.org/appshell/appShellService;1"]
|
|
.getService(Components.interfaces.nsIAppShellService)
|
|
.hiddenDOMWindow;
|
|
|
|
var nativeJSON = Components.classes["@mozilla.org/dom/json;1"]
|
|
.createInstance(Components.interfaces.nsIJSON);
|
|
|
|
var json2 = Components.utils.import("resource://jsbridge/modules/json2.js");
|
|
|
|
var jsonEncode = json2.JSON.stringify;
|
|
|
|
var uuidgen = Components.classes["@mozilla.org/uuid-generator;1"]
|
|
.getService(Components.interfaces.nsIUUIDGenerator);
|
|
|
|
function AsyncRead (session) {
|
|
this.session = session;
|
|
}
|
|
AsyncRead.prototype.onStartRequest = function (request, context) {};
|
|
AsyncRead.prototype.onStopRequest = function (request, context, status) {
|
|
this.session.onQuit();
|
|
}
|
|
AsyncRead.prototype.onDataAvailable = function (request, context, inputStream, offset, count) {
|
|
var str = {};
|
|
this.session.instream.readString(count, str);
|
|
this.session.receive(str.value);
|
|
}
|
|
|
|
|
|
|
|
globalRegistry = {};
|
|
|
|
function Bridge (session) {
|
|
this.session = session;
|
|
this.registry = globalRegistry;
|
|
}
|
|
Bridge.prototype._register = function (_type) {
|
|
this.bridgeType = _type;
|
|
if (_type == "backchannel") {
|
|
events.addBackChannel(this);
|
|
}
|
|
}
|
|
Bridge.prototype.register = function (uuid, _type) {
|
|
try {
|
|
this._register(_type);
|
|
var passed = true;
|
|
} catch(e) {
|
|
if (typeof(e) == "string") {
|
|
var exception = e;
|
|
} else {
|
|
var exception = {'name':e.name, 'message':e.message};
|
|
}
|
|
this.session.encodeOut({'result':false, 'exception':exception, 'uuid':uuid});
|
|
}
|
|
if (passed != undefined) {
|
|
this.session.encodeOut({"result":true, 'eventType':'register', 'uuid':uuid});
|
|
}
|
|
|
|
}
|
|
Bridge.prototype._describe = function (obj) {
|
|
var response = {};
|
|
if (obj == null) {
|
|
var type = "null";
|
|
} else {
|
|
var type = typeof(obj);
|
|
}
|
|
if (type == "object") {
|
|
if (obj.length != undefined) {
|
|
var type = "array";
|
|
}
|
|
response.attributes = [];
|
|
for (i in obj) {
|
|
response.attributes = response.attributes.concat(i);
|
|
}
|
|
}
|
|
else if (type != "function"){
|
|
response.data = obj;
|
|
}
|
|
response.type = type;
|
|
return response;
|
|
}
|
|
Bridge.prototype.describe = function (uuid, obj) {
|
|
var response = this._describe(obj);
|
|
response.uuid = uuid;
|
|
response.result = true;
|
|
this.session.encodeOut(response);
|
|
}
|
|
Bridge.prototype._set = function (obj) {
|
|
var uuid = uuidgen.generateUUID().toString();
|
|
this.registry[uuid] = obj;
|
|
return uuid;
|
|
}
|
|
Bridge.prototype.set = function (uuid, obj) {
|
|
var ruuid = this._set(obj);
|
|
this.session.encodeOut({'result':true, 'data':'bridge.registry["'+ruuid+'"]', 'uuid':uuid});
|
|
}
|
|
Bridge.prototype._setAttribute = function (obj, name, value) {
|
|
obj[name] = value;
|
|
return value;
|
|
}
|
|
Bridge.prototype.setAttribute = function (uuid, obj, name, value) {
|
|
// log(uuid, String(obj), name, String(value))
|
|
try {
|
|
var result = this._setAttribute(obj, name, value);
|
|
} catch(e) {
|
|
if (typeof(e) == "string") {
|
|
var exception = e;
|
|
} else {
|
|
var exception = {'name':e.name, 'message':e.message};
|
|
}
|
|
this.session.encodeOut({'result':false, 'exception':exception, 'uuid':uuid});
|
|
}
|
|
if (result != undefined) {
|
|
this.set(uuid, obj[name]);
|
|
}
|
|
}
|
|
Bridge.prototype._execFunction = function (func, args) {
|
|
return func.apply(this.session.sandbox, args);
|
|
}
|
|
Bridge.prototype.execFunction = function (uuid, func, args) {
|
|
try {
|
|
var data = this._execFunction(func, args);
|
|
var result = true;
|
|
} catch(e) {
|
|
if (typeof(e) == "string") {
|
|
var exception = e;
|
|
} else {
|
|
var exception = {'name':e.name, 'message':e.message};
|
|
}
|
|
this.session.encodeOut({'result':false, 'exception':exception, 'uuid':uuid});
|
|
var result = true;
|
|
}
|
|
if (data != undefined) {
|
|
this.set(uuid, data);
|
|
} else if ( result == true) {
|
|
this.session.encodeOut({'result':true, 'data':null, 'uuid':uuid});
|
|
} else {
|
|
throw 'Something very bad happened.'
|
|
}
|
|
}
|
|
|
|
backstage = this;
|
|
|
|
function Session (transport) {
|
|
this.transpart = transport;
|
|
this.sandbox = Components.utils.Sandbox(backstage);
|
|
this.sandbox.bridge = new Bridge(this);
|
|
this.sandbox.openPreferences = hwindow.openPreferences;
|
|
try {
|
|
this.outstream = transport.openOutputStream(Ci.nsITransport.OPEN_BLOCKING , 0, 0);
|
|
this.stream = transport.openInputStream(0, 0, 0);
|
|
this.instream = Cc['@mozilla.org/intl/converter-input-stream;1']
|
|
.createInstance(Ci.nsIConverterInputStream);
|
|
this.instream.init(this.stream, 'UTF-8', 1024,
|
|
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
|
} catch(e) {
|
|
log('jsbridge: Error: ' + e);
|
|
}
|
|
// log('jsbridge: Accepted connection.');
|
|
|
|
this.pump = Cc['@mozilla.org/network/input-stream-pump;1']
|
|
.createInstance(Ci.nsIInputStreamPump);
|
|
this.pump.init(this.stream, -1, -1, 0, 0, false);
|
|
this.pump.asyncRead(new AsyncRead(this), null);
|
|
}
|
|
Session.prototype.onOutput = function(string) {
|
|
// log('jsbridge write: '+string)
|
|
if (typeof(string) != "string") {
|
|
throw "This is not a string"
|
|
}
|
|
try {
|
|
this.outstream.write(string, string.length);
|
|
} catch (e) {
|
|
throw "Why is this failing "+string
|
|
}
|
|
// this.outstream.write(string, string.length);
|
|
};
|
|
Session.prototype.onQuit = function() {
|
|
this.instream.close();
|
|
this.outstream.close();
|
|
sessions.remove(session);
|
|
};
|
|
Session.prototype.encodeOut = function (obj) {
|
|
try {
|
|
this.onOutput(jsonEncode(obj));
|
|
} catch(e) {
|
|
if (typeof(e) == "string") {
|
|
var exception = e;
|
|
} else {
|
|
var exception = {'name':e.name, 'message':e.message};
|
|
}
|
|
this.onOutput(jsonEncode({'result':false, 'exception':exception}));
|
|
}
|
|
|
|
}
|
|
Session.prototype.receive = function(data) {
|
|
// log('jsbrige receive: '+data);
|
|
Components.utils.evalInSandbox(data, this.sandbox);
|
|
}
|
|
|
|
var sessions = {
|
|
_list: [],
|
|
add: function(session) {
|
|
this._list.push(session);
|
|
},
|
|
remove: function(session) {
|
|
var index = this._list.indexOf(session);
|
|
if(index != -1)
|
|
this._list.splice(index, 1);
|
|
},
|
|
get: function(index) {
|
|
return this._list[index];
|
|
},
|
|
quit: function() {
|
|
this._list.forEach(
|
|
function(session) { session.quit; });
|
|
this._list.splice(0, this._list.length);
|
|
}
|
|
};
|
|
|
|
function Server (port) {
|
|
this.port = port;
|
|
}
|
|
Server.prototype.start = function () {
|
|
try {
|
|
this.serv = Cc['@mozilla.org/network/server-socket;1']
|
|
.createInstance(Ci.nsIServerSocket);
|
|
this.serv.init(this.port, true, -1);
|
|
this.serv.asyncListen(this);
|
|
// log('jsbridge: Listening...');
|
|
} catch(e) {
|
|
log('jsbridge: Exception: ' + e);
|
|
}
|
|
}
|
|
Server.prototype.stop = function () {
|
|
log('jsbridge: Closing...');
|
|
this.serv.close();
|
|
this.sessions.quit();
|
|
this.serv = undefined;
|
|
}
|
|
Server.prototype.onStopListening = function (serv, status) {
|
|
// Stub function
|
|
}
|
|
Server.prototype.onSocketAccepted = function (serv, transport) {
|
|
session = new Session(transport)
|
|
sessions.add(session);
|
|
}
|
|
|
|
function log(msg) {
|
|
dump(msg + '\n');
|
|
}
|
|
|
|
function startServer(port) {
|
|
var server = new Server(port)
|
|
server.start()
|
|
}
|
|
|
|
|