michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: let {Cu} = require("chrome"); michael@0: let {DebuggerServer} = require("devtools/server/main"); michael@0: michael@0: let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); michael@0: let {Class} = require("sdk/core/heritage"); michael@0: michael@0: let protocol = require("devtools/server/protocol"); michael@0: let {method, Arg, Option, RetVal} = protocol; michael@0: michael@0: exports.LongStringActor = protocol.ActorClass({ michael@0: typeName: "longstractor", michael@0: michael@0: initialize: function(conn, str) { michael@0: protocol.Actor.prototype.initialize.call(this, conn); michael@0: this.str = str; michael@0: this.short = (this.str.length < DebuggerServer.LONG_STRING_LENGTH); michael@0: }, michael@0: michael@0: destroy: function() { michael@0: this.str = null; michael@0: protocol.Actor.prototype.destroy.call(this); michael@0: }, michael@0: michael@0: form: function() { michael@0: if (this.short) { michael@0: return this.str; michael@0: } michael@0: return { michael@0: type: "longString", michael@0: actor: this.actorID, michael@0: length: this.str.length, michael@0: initial: this.str.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH) michael@0: } michael@0: }, michael@0: michael@0: substring: method(function(start, end) { michael@0: return promise.resolve(this.str.substring(start, end)); michael@0: }, { michael@0: request: { michael@0: start: Arg(0), michael@0: end: Arg(1) michael@0: }, michael@0: response: { substring: RetVal() }, michael@0: }), michael@0: michael@0: release: method(function() { }, { release: true }) michael@0: }); michael@0: michael@0: /** michael@0: * When a LongString on the server is short enough to be passed michael@0: * as a full string, the client will get a ShortLongString instead of michael@0: * a LongStringFront. Its API should match. michael@0: * michael@0: * I'm very proud of this name. michael@0: */ michael@0: exports.ShortLongString = Class({ michael@0: initialize: function(str) { michael@0: this.str = str; michael@0: }, michael@0: michael@0: get length() { return this.str.length; }, michael@0: get initial() { return this.str; }, michael@0: string: function() { return promise.resolve(this.str) }, michael@0: michael@0: substring: function(start, end) { michael@0: return promise.resolve(this.str.substring(start, end)); michael@0: }, michael@0: michael@0: release: function() { michael@0: this.str = null; michael@0: return promise.resolve(undefined); michael@0: } michael@0: }) michael@0: michael@0: exports.LongStringFront = protocol.FrontClass(exports.LongStringActor, { michael@0: initialize: function(client, form) { michael@0: // Don't give the form by default, because we're being tricky and it might just michael@0: // be a string. michael@0: protocol.Front.prototype.initialize.call(this, client, null); michael@0: this.form(form); michael@0: }, michael@0: michael@0: destroy: function() { michael@0: this.initial = null; michael@0: this.length = null; michael@0: this.strPromise = null; michael@0: protocol.Front.prototype.destroy.call(this); michael@0: }, michael@0: michael@0: form: function(form) { michael@0: this.actorID = form.actorID; michael@0: this.initial = form.initial; michael@0: this.length = form.length; michael@0: }, michael@0: michael@0: string: function() { michael@0: if (!this.strPromise) { michael@0: let promiseRest = (thusFar) => { michael@0: if (thusFar.length === this.length) michael@0: return promise.resolve(thusFar); michael@0: else { michael@0: return this.substring(thusFar.length, michael@0: thusFar.length + DebuggerServer.LONG_STRING_READ_LENGTH) michael@0: .then((next) => promiseRest(thusFar + next)); michael@0: } michael@0: } michael@0: michael@0: this.strPromise = promiseRest(this.initial); michael@0: } michael@0: return this.strPromise; michael@0: } michael@0: }); michael@0: michael@0: // The long string actor needs some custom marshalling, because it is sometimes michael@0: // returned as a primitive rather than a complete form. michael@0: michael@0: let stringActorType = protocol.types.getType("longstractor"); michael@0: protocol.types.addType("longstring", { michael@0: _actor: true, michael@0: write: (value, context, detail) => { michael@0: if (!(context instanceof protocol.Actor)) { michael@0: throw Error("Passing a longstring as an argument isn't supported."); michael@0: } michael@0: if (value.short) { michael@0: return value.str; michael@0: } else { michael@0: return stringActorType.write(value, context, detail); michael@0: } michael@0: }, michael@0: read: (value, context, detail) => { michael@0: if (context instanceof protocol.Actor) { michael@0: throw Error("Passing a longstring as an argument isn't supported."); michael@0: } michael@0: if (typeof(value) === "string") { michael@0: return exports.ShortLongString(value); michael@0: } michael@0: return stringActorType.read(value, context, detail); michael@0: } michael@0: });