зеркало из https://github.com/mozilla/shumway.git
Pilot for remote debugger
This commit is contained in:
Родитель
a82ac47af3
Коммит
98f236b344
|
@ -103,6 +103,9 @@ module.exports = function(grunt) {
|
|||
(grunt.option('rebuild') ? ' -r' : ''),
|
||||
cwd: 'utils/playerglobal-builder'
|
||||
},
|
||||
debug_server: {
|
||||
cmd: 'node examples/inspector/debug/server.js'
|
||||
},
|
||||
gate: {
|
||||
cmd: '"utils/jsshell/js" build/ts/shell.js -x -g ' +
|
||||
(grunt.option('verbose') ? '-v ' : '') +
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Simple class for synchronous XHR communication.
|
||||
// See also examples/inspector/debug/server.js.
|
||||
|
||||
var PingPongConnection = (function () {
|
||||
function PingPongConnection(url, onlySend) {
|
||||
this.url = url;
|
||||
this.onData = null;
|
||||
this.onError = null;
|
||||
this.currentXhr = null;
|
||||
this.closed = false;
|
||||
|
||||
if (!onlySend) {
|
||||
this.idle();
|
||||
}
|
||||
}
|
||||
|
||||
PingPongConnection.prototype = {
|
||||
idle: function () {
|
||||
function requestIncoming(connection) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', connection.url + '?idle', true);
|
||||
xhr.onload = function () {
|
||||
if (xhr.status === 204 &&
|
||||
xhr.getResponseHeader('X-PingPong-Error') === 'timeout') {
|
||||
requestIncoming(connection);
|
||||
return;
|
||||
}
|
||||
if (xhr.status === 200) {
|
||||
var result;
|
||||
if (connection.onData) {
|
||||
var response = xhr.responseText;
|
||||
result = connection.onData(response ? JSON.parse(response) : undefined);
|
||||
}
|
||||
if (xhr.getResponseHeader('X-PingPong-Async') === '1') {
|
||||
requestIncoming(connection);
|
||||
} else {
|
||||
sendResponse(connection, result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.statusText);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.error);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
connection.currentXhr = xhr;
|
||||
}
|
||||
function sendResponse(connection, result) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', connection.url + '?response', false);
|
||||
xhr.onload = function () {
|
||||
if (xhr.status !== 204) {
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.statusText);
|
||||
}
|
||||
}
|
||||
requestIncoming(connection);
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.error);
|
||||
}
|
||||
};
|
||||
xhr.send(result === undefined ? '' : JSON.stringify(result));
|
||||
connection.currentXhr = xhr;
|
||||
}
|
||||
requestIncoming(this);
|
||||
},
|
||||
send: function (data, async, timeout) {
|
||||
if (this.closed) {
|
||||
throw new Error('connection closed');
|
||||
}
|
||||
|
||||
async = !!async;
|
||||
timeout |= 0;
|
||||
|
||||
var encoded = data === undefined ? '' : JSON.stringify(data);
|
||||
if (async) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', this.url + '?async', true);
|
||||
xhr.send(encoded);
|
||||
return;
|
||||
} else {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', this.url, false);
|
||||
if (timeout > 0) {
|
||||
xhr.setRequestHeader('X-PingPong-Timeout', timeout);
|
||||
}
|
||||
xhr.send(encoded);
|
||||
if (xhr.status === 204 &&
|
||||
xhr.getResponseHeader('X-PingPong-Error') === 'timeout') {
|
||||
throw new Error('sync request timeout');
|
||||
}
|
||||
var response = xhr.responseText;
|
||||
return response ? JSON.parse(response) : undefined;
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
if (this.currentXhr) {
|
||||
this.currentXhr.abort();
|
||||
this.currentXhr = null;
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
};
|
||||
|
||||
return PingPongConnection;
|
||||
})();
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*jslint node: true */
|
||||
|
||||
// Simple HTTP server for synchronous XHR communication.
|
||||
// See also examples/inspector/debug/pingpong.js.
|
||||
|
||||
'use strict';
|
||||
|
||||
var http = require('http');
|
||||
|
||||
var ALLOW_FROM_DOMAIN = 'http://localhost:8000';
|
||||
var DEFAULT_BIND_HOST = 'localhost';
|
||||
var DEFAULT_BIND_PORT = 8010;
|
||||
|
||||
var IDLE_TIMEOUT = 500;
|
||||
var SYNC_TIMEOUT = 120000;
|
||||
|
||||
var incomingData = {};
|
||||
var incomingResponse = {};
|
||||
var outgoingResponse = {};
|
||||
var currentReading = [];
|
||||
|
||||
var verbose = false;
|
||||
|
||||
function WebServer() {
|
||||
this.host = DEFAULT_BIND_HOST;
|
||||
this.port = DEFAULT_BIND_PORT;
|
||||
this.server = null;
|
||||
}
|
||||
WebServer.prototype = {
|
||||
start: function (callback) {
|
||||
this.server = http.createServer(this._handler.bind(this));
|
||||
this.server.listen(this.port, this.host, callback);
|
||||
console.log(
|
||||
'Server running at http://' + this.host + ':' + this.port + '/');
|
||||
console.log('Allowing requests from: ' + ALLOW_FROM_DOMAIN);
|
||||
},
|
||||
stop: function (callback) {
|
||||
this.server.close(callback);
|
||||
this.server = null;
|
||||
},
|
||||
_handler: function (request, response) {
|
||||
function setStandardHeaders(response) {
|
||||
response.setHeader('Access-Control-Allow-Origin', ALLOW_FROM_DOMAIN);
|
||||
response.setHeader('Access-Control-Allow-Headers', 'Content-Type,X-PingPong-Timeout');
|
||||
response.setHeader('Access-Control-Expose-Headers', 'Content-Type,X-PingPong-Async,X-PingPong-From,X-PingPong-Error');
|
||||
response.setHeader('Content-Type', 'text/plain');
|
||||
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||
response.setHeader('Pragma', 'no-cache');
|
||||
response.setHeader('Expires', 0);
|
||||
}
|
||||
|
||||
function sendData(response, data, isAsync, fromId) {
|
||||
setStandardHeaders(response);
|
||||
response.setHeader('Content-Type', 'text/plain');
|
||||
if (isAsync) {
|
||||
response.setHeader('X-PingPong-Async', 1);
|
||||
}
|
||||
response.setHeader('X-PingPong-From', fromId);
|
||||
response.writeHead(200);
|
||||
response.end(data);
|
||||
}
|
||||
|
||||
function sendNoData(response) {
|
||||
setStandardHeaders(response);
|
||||
response.writeHead(204);
|
||||
response.end();
|
||||
}
|
||||
|
||||
function sendTimeout(response) {
|
||||
setStandardHeaders(response);
|
||||
response.setHeader('X-PingPong-Error', 'timeout');
|
||||
response.writeHead(204);
|
||||
response.end();
|
||||
}
|
||||
|
||||
var method = request.method;
|
||||
if (request.method === 'OPTIONS') {
|
||||
setStandardHeaders(response);
|
||||
response.writeHead(200);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var url = request.url;
|
||||
var urlParts = /([^?]*)((?:\?(.*))?)/.exec(url);
|
||||
var pathParts = urlParts[1].split('/');
|
||||
var queryPart = urlParts[3];
|
||||
|
||||
var sessionId = pathParts[1], fromId = pathParts[2], toId = pathParts[3];
|
||||
var isResponse = queryPart === 'response', isAsync = queryPart === 'async';
|
||||
verbose && console.log(sessionId + ': ' + fromId + '->' + toId + ' ' +
|
||||
isResponse + ' ' + isAsync + ' ' + request.method);
|
||||
var keyId = sessionId + '_' + fromId + '_' + toId;
|
||||
var reverseKeyId = sessionId + '_' + toId + '_' + fromId;
|
||||
|
||||
if (request.method === 'POST') {
|
||||
response.on('close', function () {
|
||||
verbose && console.log('connection closed'); // TODO client closed without response.end
|
||||
});
|
||||
|
||||
var body = '';
|
||||
request.on('data', function (data) {
|
||||
body += data;
|
||||
});
|
||||
request.on('end', function () {
|
||||
verbose && console.log(' ... ' + body.substring(0, 140));
|
||||
item.isReady = true;
|
||||
while (currentReading.length > 0 && currentReading[0].isReady) {
|
||||
currentReading.shift().fn();
|
||||
}
|
||||
});
|
||||
|
||||
var item = {
|
||||
isReady: false,
|
||||
fn: function () {
|
||||
if (isResponse) {
|
||||
if (outgoingResponse[reverseKeyId]) {
|
||||
sendData(outgoingResponse[reverseKeyId].shift().response, body, true, fromId);
|
||||
if (outgoingResponse[reverseKeyId].length === 0) {
|
||||
delete outgoingResponse[reverseKeyId];
|
||||
}
|
||||
} else {
|
||||
console.error('Out of sequence response for ' + reverseKeyId);
|
||||
}
|
||||
sendNoData(response);
|
||||
} else {
|
||||
if (!isAsync) {
|
||||
if (!outgoingResponse[keyId]) {
|
||||
outgoingResponse[keyId] = [];
|
||||
}
|
||||
var requestTimeout = +request.headers['x-pingpong-timeout'];
|
||||
var syncTimeout = requestTimeout || SYNC_TIMEOUT;
|
||||
outgoingResponse[keyId].push({response: response});
|
||||
setTimeout(function () {
|
||||
var responses = outgoingResponse[keyId];
|
||||
if (!responses) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < responses.length; i++) {
|
||||
if (responses[i].response === response) {
|
||||
if (responses.length === 1) {
|
||||
delete outgoingResponse[keyId];
|
||||
} else {
|
||||
responses.splice(i, 1);
|
||||
}
|
||||
sendTimeout(response);
|
||||
if (!requestTimeout) {
|
||||
console.error('Sync request timeout: ' + keyId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, syncTimeout);
|
||||
} else {
|
||||
sendNoData(response);
|
||||
}
|
||||
if (incomingResponse[reverseKeyId]) {
|
||||
sendData(incomingResponse[reverseKeyId].response, body, isAsync, fromId);
|
||||
delete incomingResponse[reverseKeyId];
|
||||
} else {
|
||||
if (!incomingData[reverseKeyId]) {
|
||||
incomingData[reverseKeyId] = [];
|
||||
}
|
||||
incomingData[reverseKeyId].push({data: body, isAsync: isAsync});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
currentReading.push(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method == 'GET' && !isResponse) {
|
||||
if (incomingData[keyId]) {
|
||||
var data = incomingData[keyId].shift();
|
||||
sendData(response, data.data, data.isAsync, toId);
|
||||
if (incomingData[keyId].length === 0) {
|
||||
delete incomingData[keyId];
|
||||
}
|
||||
} else {
|
||||
if (incomingResponse[keyId]) {
|
||||
console.error('Double incoming response from ' + keyId);
|
||||
}
|
||||
incomingResponse[keyId] = {response: response};
|
||||
}
|
||||
setTimeout(function () {
|
||||
if (incomingResponse[keyId] && incomingResponse[keyId].response === response) {
|
||||
delete incomingResponse[keyId];
|
||||
sendTimeout(response);
|
||||
}
|
||||
}, IDLE_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
setStandardHeaders(response);
|
||||
response.writeHead(500);
|
||||
response.end('Invalid request');
|
||||
}
|
||||
};
|
||||
|
||||
var server = new WebServer();
|
||||
server.start();
|
|
@ -160,6 +160,7 @@ limitations under the License.
|
|||
<script src="js/classes/SWFController.js"></script>
|
||||
<script src="js/classes/classList.min.js"></script>
|
||||
<script src="js/classes/dat.gui.js"></script>
|
||||
<script src="debug/pingpong.js"></script>
|
||||
|
||||
<script src="js/inspectorProfiler.js"></script>
|
||||
<script src="js/inspectorSettings.js"></script>
|
||||
|
@ -168,6 +169,7 @@ limitations under the License.
|
|||
<script src="js/inspectorDisplayList.js"></script>
|
||||
<script src="js/inspectorMocks.js"></script>
|
||||
<script src="js/inspectorDebugging.js"></script> <!-- P -->
|
||||
<script src="js/remoteDebugging.js"></script>
|
||||
<script src="js/unit.js"></script>
|
||||
<script src="js/inspector.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -82,6 +82,10 @@ if (queryVariables['rfile'] && !startPromise) {
|
|||
url: queryVariables['rfile'],
|
||||
args: parseQueryString(queryVariables['flashvars'])
|
||||
});
|
||||
} else {
|
||||
if (state.remoteEnabled) {
|
||||
initRemoteDebugging();
|
||||
}
|
||||
}
|
||||
if (startPromise) {
|
||||
startPromise.then(function (config) {
|
||||
|
@ -106,6 +110,7 @@ function showOpenFileButton(show) {
|
|||
var flashOverlay;
|
||||
var currentSWFUrl;
|
||||
var currentPlayer;
|
||||
var processExternalCommand;
|
||||
|
||||
var easelHost;
|
||||
function runIFramePlayer(data) {
|
||||
|
@ -130,11 +135,14 @@ function runIFramePlayer(data) {
|
|||
playerWorker.postMessage(data, '*');
|
||||
|
||||
easelHost = new Shumway.GFX.Window.WindowEaselHost(easel, playerWorker, window);
|
||||
if (processExternalCommand) {
|
||||
easelHost.processExternalCommand = processExternalCommand;
|
||||
}
|
||||
});
|
||||
container.appendChild(playerWorkerIFrame);
|
||||
}
|
||||
|
||||
function executeFile(file, buffer, movieParams) {
|
||||
function executeFile(file, buffer, movieParams, remoteDebugging) {
|
||||
var filename = file.split('?')[0].split('#')[0];
|
||||
|
||||
if (state.useIFramePlayer && filename.endsWith(".swf")) {
|
||||
|
@ -142,7 +150,8 @@ function executeFile(file, buffer, movieParams) {
|
|||
runIFramePlayer({sysMode: sysMode, appMode: appMode,
|
||||
movieParams: movieParams, file: file, asyncLoading: asyncLoading,
|
||||
stageAlign: state.salign, stageScale: state.scale,
|
||||
fileReadChunkSize: state.fileReadChunkSize, loaderURL: state.loaderURL});
|
||||
fileReadChunkSize: state.fileReadChunkSize, loaderURL: state.loaderURL,
|
||||
remoteDebugging: !!remoteDebugging});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -189,7 +198,15 @@ function executeFile(file, buffer, movieParams) {
|
|||
player.displayParameters = easel.getDisplayParameters();
|
||||
player.loaderUrl = state.loaderURL;
|
||||
|
||||
if (remoteDebugging) {
|
||||
Shumway.ExternalInterfaceService.instance = player.createExternalInterfaceService();
|
||||
}
|
||||
|
||||
easelHost = new Shumway.GFX.Test.TestEaselHost(easel);
|
||||
if (processExternalCommand) {
|
||||
easelHost.processExternalCommand = processExternalCommand;
|
||||
}
|
||||
|
||||
player.load(file, buffer);
|
||||
|
||||
currentSWFUrl = swfURL;
|
||||
|
|
|
@ -102,6 +102,10 @@ function runSwfPlayer(data) {
|
|||
fileReadChunkSize = data.fileReadChunkSize;
|
||||
var file = data.file;
|
||||
configureExternalInterfaceMocks(file);
|
||||
if (data.remoteDebugging) {
|
||||
Shumway.ClipboardService.instance = parent.Shumway.ClipboardService.instance;
|
||||
Shumway.FileLoadingService.instance = parent.Shumway.FileLoadingService.instance;
|
||||
}
|
||||
Shumway.createAVM2(builtinPath, playerglobalInfo, sysMode, appMode, function (avm2) {
|
||||
function runSWF(file) {
|
||||
var player = new Shumway.Player.Window.WindowPlayer(window);
|
||||
|
@ -111,6 +115,10 @@ function runSwfPlayer(data) {
|
|||
player.displayParameters = displayParameters;
|
||||
player.loaderUrl = loaderURL;
|
||||
player.load(file);
|
||||
|
||||
if (data.remoteDebugging) {
|
||||
Shumway.ExternalInterfaceService.instance = player.createExternalInterfaceService();
|
||||
}
|
||||
}
|
||||
file = Shumway.FileLoadingService.instance.setBaseUrl(file);
|
||||
if (asyncLoading) {
|
||||
|
|
|
@ -35,7 +35,9 @@ var stateDefaults = {
|
|||
scale: 'noscale',
|
||||
width: -1,
|
||||
height: -1,
|
||||
loaderURL: ''
|
||||
loaderURL: '',
|
||||
remoteEnabled: false,
|
||||
remoteSWF: ''
|
||||
};
|
||||
|
||||
for (var option in stateDefaults) {
|
||||
|
@ -115,6 +117,8 @@ var GUI = (function () {
|
|||
inspectorOptions.add(state, "width", -1, 4096, 1).onChange(saveInspectorOption);
|
||||
inspectorOptions.add(state, "height", -1, 4096, 1).onChange(saveInspectorOption);
|
||||
inspectorOptions.add(state, "loaderURL").onChange(saveInspectorOption);
|
||||
inspectorOptions.add(state, "remoteEnabled").onChange(saveInspectorOption);
|
||||
inspectorOptions.add(state, "remoteSWF").onChange(saveInspectorOption);
|
||||
//inspectorOptions.add(state, "mute").onChange(saveInspectorOption);
|
||||
if (state.folderOpen) {
|
||||
inspectorOptions.open();
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var removeDebuggerBaseURL = 'http://localhost:8010';
|
||||
|
||||
var remoteDebuggerId;
|
||||
var remoteDebugger;
|
||||
var remoteDebuggerController;
|
||||
function initRemoteDebugging() {
|
||||
remoteDebuggerId = (Date.now() % 100000) + 2;
|
||||
remoteDebugger = new PingPongConnection(removeDebuggerBaseURL + '/debug/' + remoteDebuggerId + '/1');
|
||||
remoteDebugger.onData = remoteDebugger_onData;
|
||||
|
||||
remoteDebuggerController = new PingPongConnection(removeDebuggerBaseURL + '/debugController/1/2');
|
||||
remoteDebuggerController.onData = function (data) {
|
||||
switch (data.action) {
|
||||
case 'getDebugger':
|
||||
if (data.swfUrl && data.swfUrl.indexOf(state.remoteSWF) === 0) {
|
||||
return remoteDebuggerId;
|
||||
}
|
||||
return 0;
|
||||
case 'enableDebugging':
|
||||
var properties = document.getElementById('settingsContainer').querySelectorAll('.property-name');
|
||||
for (var i = 0; i < properties.length; i++) {
|
||||
if (properties[i].textContent === 'remoteSWF') {
|
||||
var input = properties[i].parentElement.getElementsByTagName('input')[0];
|
||||
input.value = data.swfUrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.remoteSWF = data.swfUrl;
|
||||
saveInspectorState();
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var externalInteraceCallback;
|
||||
function remoteDebuggerInitServices() {
|
||||
window.addEventListener('beforeunload', function(event) {
|
||||
remoteDebugger.send({action: 'reload'}, true);
|
||||
});
|
||||
processExternalCommand = function (command) {
|
||||
switch (command.action) {
|
||||
case 'isEnabled':
|
||||
command.result = true;
|
||||
break;
|
||||
case 'initJS':
|
||||
remoteDebuggerSendMessage({action: 'externalCom', data: {action: 'init'}, sync: true});
|
||||
externalInteraceCallback = function (functionName, args) {
|
||||
return easelHost.sendExernalCallback(functionName, args);
|
||||
};
|
||||
break;
|
||||
default:
|
||||
var result = remoteDebuggerSendMessage({action: 'externalCom', data: command, sync: true});
|
||||
command.result = result ? JSON.parse(result) : undefined;
|
||||
break;
|
||||
}
|
||||
};
|
||||
Shumway.ClipboardService.instance = {
|
||||
setClipboard: function (data) {
|
||||
remoteDebuggerSendMessage({action: 'setClipboard', data: data}, false);
|
||||
}
|
||||
};
|
||||
Shumway.FileLoadingService.instance = {
|
||||
baseUrl: null,
|
||||
nextSessionId: 1, // 0 - is reserved
|
||||
sessions: [],
|
||||
createSession: function () {
|
||||
var sessionId = this.nextSessionId++;
|
||||
return this.sessions[sessionId] = {
|
||||
open: function (request) {
|
||||
var self = this;
|
||||
var path = Shumway.FileLoadingService.instance.resolveUrl(request.url);
|
||||
console.log('Session #' + sessionId + ': loading ' + path);
|
||||
remoteDebuggerSendMessage({
|
||||
action: 'loadFile',
|
||||
data: {url: path, method: request.method,
|
||||
mimeType: request.mimeType, postData: request.data,
|
||||
checkPolicyFile: request.checkPolicyFile, sessionId: sessionId}
|
||||
}, true);
|
||||
},
|
||||
notify: function (args) {
|
||||
switch (args.topic) {
|
||||
case "open":
|
||||
this.onopen();
|
||||
break;
|
||||
case "close":
|
||||
this.onclose();
|
||||
Shumway.FileLoadingService.instance.sessions[sessionId] = null;
|
||||
console.log('Session #' + sessionId + ': closed');
|
||||
break;
|
||||
case "error":
|
||||
this.onerror && this.onerror(args.error);
|
||||
break;
|
||||
case "progress":
|
||||
console.log('Session #' + sessionId + ': loaded ' + args.loaded + '/' + args.total);
|
||||
this.onprogress && this.onprogress(new Uint8Array(args.array), {bytesLoaded: args.loaded, bytesTotal: args.total});
|
||||
break;
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
if (Shumway.FileLoadingService.instance.sessions[sessionId]) {
|
||||
// TODO send abort
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
setBaseUrl: function (url) {
|
||||
return Shumway.FileLoadingService.instance.baseUrl = url;
|
||||
},
|
||||
resolveUrl: function (url) {
|
||||
return new URL(url, Shumway.FileLoadingService.instance.baseUrl).href;
|
||||
},
|
||||
navigateTo: function (url, target) {
|
||||
remoteDebuggerSendMessage({
|
||||
action: 'navigateTo',
|
||||
data: {
|
||||
url: this.resolveUrl(url),
|
||||
target: target
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function remoteDebuggerSendMessage(detail, async) {
|
||||
return remoteDebugger.send({action: 'sendMessage', detail: detail}, async);
|
||||
}
|
||||
|
||||
function remoteDebugger_onData(data) {
|
||||
switch (data.action) {
|
||||
case 'runViewer':
|
||||
showOpenFileButton(false);
|
||||
remoteDebuggerInitServices();
|
||||
|
||||
var flashParams = JSON.parse(remoteDebuggerSendMessage({action: 'getPluginParams', data: null, sync: true}));
|
||||
|
||||
var movieUrl = flashParams.url;
|
||||
var movieParams = flashParams.movieParams;
|
||||
executeFile(movieUrl, undefined, movieParams, true);
|
||||
|
||||
remoteDebuggerSendMessage({action: 'endActivation', data: null}, true);
|
||||
return;
|
||||
case 'onExternalCallback':
|
||||
var call = data.detail;
|
||||
externalInteraceCallback(call.functionName, call.args);
|
||||
return;
|
||||
case 'onLoadFileCallback':
|
||||
var args = data.detail;
|
||||
var session = Shumway.FileLoadingService.instance.sessions[args.sessionId];
|
||||
if (session) {
|
||||
session.notify(args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ build: ensureoutputdir
|
|||
cp -R ../../LICENSE content chrome bootstrap.js chrome.manifest icon.png icon64.png $(BUILD_DIR)/
|
||||
sed s/\(SHUMWAY_VERSION\)/$(VERSION)/ install.rdf > $(BUILD_DIR)/install.rdf
|
||||
sed s/\(SHUMWAY_VERSION\)/$(VERSION)/ update.rdf > $(BUILD_DIR)/update.rdf
|
||||
cp ../../examples/inspector/debug/pingpong.js $(BUILD_DIR)/chrome/
|
||||
# Copying WebGL shaders
|
||||
mkdir -p $(BUILD_DIR)/content/gfx/gl/shaders
|
||||
cp ../../src/gfx/gl/shaders/combined.frag $(BUILD_DIR)/content/gfx/gl/shaders/
|
||||
|
|
|
@ -46,6 +46,10 @@ function sendMessage(action, data, sync, callbackCookie) {
|
|||
return Components.utils.cloneInto(result, content);
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
sendAsyncMessage('Shumway:enableDebug', null);
|
||||
}
|
||||
|
||||
addMessageListener('Shumway:init', function (message) {
|
||||
sendAsyncMessage('Shumway:running', {}, {
|
||||
externalInterface: externalInterfaceWrapper
|
||||
|
@ -55,6 +59,7 @@ addMessageListener('Shumway:init', function (message) {
|
|||
// up Xray wrappers.
|
||||
shumwayComAdapter = Components.utils.createObjectIn(content, {defineAs: 'ShumwayCom'});
|
||||
Components.utils.exportFunction(sendMessage, shumwayComAdapter, {defineAs: 'sendMessage'});
|
||||
Components.utils.exportFunction(enableDebug, shumwayComAdapter, {defineAs: 'enableDebug'});
|
||||
Object.defineProperties(shumwayComAdapter, {
|
||||
onLoadFileCallback: { value: null, writable: true },
|
||||
onExternalCallback: { value: null, writable: true },
|
||||
|
|
|
@ -36,11 +36,23 @@ limitations under the License.
|
|||
line-height: 0;
|
||||
border: 0px none;
|
||||
}
|
||||
|
||||
body.remoteStopped {
|
||||
background-color: red;
|
||||
}
|
||||
body.remoteDebug {
|
||||
background-color: green;
|
||||
}
|
||||
body.remoteReload {
|
||||
background-color: yellow;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<iframe id="viewer" src="resource://shumway/web/viewer.html" width="100%" height="100%" mozbrowser remote="true"></iframe>
|
||||
<script src="chrome://shumway/content/pingpong.js"></script>
|
||||
<script src="chrome://shumway/content/viewerDebugger.js"></script>
|
||||
<script src="chrome://shumway/content/viewerWrapper.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var DebugUtils = (function () {
|
||||
var baseUrl = null;
|
||||
|
||||
function getBaseUrl() {
|
||||
if (baseUrl === null) {
|
||||
try {
|
||||
baseUrl = Services.prefs.getCharPref('shumway.debug.url');
|
||||
} catch (e) {
|
||||
baseUrl = 'http://localhost:8010';
|
||||
}
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
function getEnabledDebuggerId(swfUrl) {
|
||||
var id = 0;
|
||||
var url = getBaseUrl() + '/debugController/2/1';
|
||||
var connection = new PingPongConnection(url, true);
|
||||
try {
|
||||
id = connection.send({action: 'getDebugger', swfUrl: swfUrl},
|
||||
false, 500);
|
||||
} catch (e) {
|
||||
// ignoring failed send request
|
||||
}
|
||||
connection.close();
|
||||
return id;
|
||||
}
|
||||
|
||||
function enableDebug(swfUrl) {
|
||||
var url = getBaseUrl() + '/debugController/2/1';
|
||||
var connection = new PingPongConnection(url, true);
|
||||
try {
|
||||
connection.send({action: 'enableDebugging', swfUrl: swfUrl}, true);
|
||||
} catch (e) {
|
||||
// ignoring failed send request
|
||||
}
|
||||
connection.close();
|
||||
}
|
||||
|
||||
function createDebuggerConnection(swfUrl) {
|
||||
var debuggerId = getEnabledDebuggerId(swfUrl);
|
||||
if (!debuggerId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var url = getBaseUrl() + '/debug/1/' + debuggerId;
|
||||
console.log('Starting remote debugger with ' + url);
|
||||
return new PingPongConnection(url);
|
||||
}
|
||||
|
||||
return {
|
||||
get isEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref('shumway.debug.enabled');
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
enableDebug: enableDebug,
|
||||
createDebuggerConnection: createDebuggerConnection
|
||||
};
|
||||
})();
|
|
@ -53,6 +53,7 @@ function runViewer() {
|
|||
// ShumwayStreamConverter.
|
||||
var shumwayComAdapter = Components.utils.createObjectIn(childWindow, {defineAs: 'ShumwayCom'});
|
||||
Components.utils.exportFunction(sendMessage, shumwayComAdapter, {defineAs: 'sendMessage'});
|
||||
Components.utils.exportFunction(enableDebug, shumwayComAdapter, {defineAs: 'enableDebug'});
|
||||
Object.defineProperties(shumwayComAdapter, {
|
||||
onLoadFileCallback: { value: null, writable: true },
|
||||
onExternalCallback: { value: null, writable: true },
|
||||
|
@ -117,6 +118,10 @@ function runViewer() {
|
|||
return window.notifyShumwayMessage(detail);
|
||||
});
|
||||
|
||||
messageManager.addMessageListener('Shumway:enableDebug', function (message) {
|
||||
enableDebug();
|
||||
});
|
||||
|
||||
window.onExternalCallback = function (call) {
|
||||
return externalInterface.callback(JSON.stringify(call));
|
||||
};
|
||||
|
@ -135,7 +140,71 @@ function runViewer() {
|
|||
messageManager.sendAsyncMessage('Shumway:init', {});
|
||||
}
|
||||
|
||||
|
||||
function handleDebug(connection) {
|
||||
viewer.parentNode.removeChild(viewer); // we don't need viewer anymore
|
||||
document.body.className = 'remoteDebug';
|
||||
|
||||
function sendMessage(data) {
|
||||
var detail = {
|
||||
action: data.action,
|
||||
data: data.data,
|
||||
sync: data.sync
|
||||
};
|
||||
if (data.callback) {
|
||||
detail.callback = true;
|
||||
detail.cookie = data.cookie;
|
||||
}
|
||||
return window.notifyShumwayMessage(detail);
|
||||
}
|
||||
|
||||
connection.onData = function (data) {
|
||||
switch (data.action) {
|
||||
case 'sendMessage':
|
||||
return sendMessage(data.detail);
|
||||
case 'reload':
|
||||
document.body.className = 'remoteReload';
|
||||
setTimeout(function () {
|
||||
window.top.location.reload();
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
window.onExternalCallback = function (call) {
|
||||
return connection.send({action: 'onExternalCallback', detail: call});
|
||||
};
|
||||
|
||||
window.onMessageCallback = function (response) {
|
||||
return connection.send({action: 'onMessageCallback', detail: response});
|
||||
};
|
||||
|
||||
window.onLoadFileCallback = function (args) {
|
||||
if (args.array) {
|
||||
args.array = Array.prototype.slice.call(args.array, 0);
|
||||
}
|
||||
return connection.send({action: 'onLoadFileCallback', detail: args}, true);
|
||||
};
|
||||
|
||||
connection.send({action: 'runViewer'}, true);
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
DebugUtils.enableDebug(window.swfUrlLoading);
|
||||
setTimeout(function () {
|
||||
window.top.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
promise.then(function (oop) {
|
||||
if (DebugUtils.isEnabled) {
|
||||
var debuggerConnection = DebugUtils.createDebuggerConnection(window.swfUrlLoading);
|
||||
if (debuggerConnection) {
|
||||
handleDebug(debuggerConnection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (oop) {
|
||||
handlerOOP();
|
||||
} else {
|
||||
|
|
|
@ -411,7 +411,7 @@ ChromeActions.prototype = {
|
|||
var position = e.loaded;
|
||||
var data = new Uint8Array(xhr.response);
|
||||
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId,
|
||||
topic: "progress", array: data, loaded: e.loaded, total: e.total});
|
||||
topic: "progress", array: data, loaded: position, total: e.total});
|
||||
lastPosition = position;
|
||||
if (limit && e.total >= limit) {
|
||||
xhr.abort();
|
||||
|
@ -1034,6 +1034,8 @@ ShumwayStreamConverterBase.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
domWindow.swfUrlLoading = actions.url;
|
||||
|
||||
// Report telemetry on amount of swfs on the page
|
||||
if (actions.isOverlay) {
|
||||
// Looking for last actions with same baseUrl
|
||||
|
|
|
@ -111,6 +111,7 @@ limitations under the License.
|
|||
<menuitem label="Open in Inspector" id="inspectorMenu"></menuitem>
|
||||
<menuitem label="Report Problems" id="reportMenu"></menuitem>
|
||||
<menuitem label="Reload in Adobe Flash Player" id="fallbackMenu" hidden></menuitem>
|
||||
<menuitem label="Debug this SWF" id="debugMenu"></menuitem>
|
||||
<menuitem label="About Shumway %version%..." id="aboutMenu"></menuitem>
|
||||
</menu>
|
||||
</section>
|
||||
|
|
|
@ -165,6 +165,13 @@ function runViewer() {
|
|||
var version = Shumway.version || '';
|
||||
document.getElementById('aboutMenu').label =
|
||||
document.getElementById('aboutMenu').label.replace('%version%', version);
|
||||
|
||||
var debugMenuEnabled = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.debug.enabled', def: false});
|
||||
if (debugMenuEnabled) {
|
||||
document.getElementById('debugMenu').addEventListener('click', enableDebug);
|
||||
} else {
|
||||
document.getElementById('debugMenu').remove();
|
||||
}
|
||||
}
|
||||
|
||||
function showURL() {
|
||||
|
@ -205,6 +212,10 @@ function showAbout() {
|
|||
window.open('http://areweflashyet.com/');
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
ShumwayCom.enableDebug();
|
||||
}
|
||||
|
||||
var movieUrl, movieParams, objectParams;
|
||||
|
||||
window.addEventListener("message", function handlerMessage(e) {
|
||||
|
|
|
@ -26,6 +26,7 @@ build: ensureoutputdir
|
|||
echo "Creating mozcentral package"
|
||||
mkdir -p $(BUILD_EXTENSION_DIR)
|
||||
cp -R ../../LICENSE $(EXTENSION_SRC)/chrome $(EXTENSION_SRC)/content $(BUILD_EXTENSION_DIR)/
|
||||
cp ../../examples/inspector/debug/pingpong.js $(BUILD_DIR)/chrome/
|
||||
cp -R browser $(BUILD_DIR)/
|
||||
mkdir -p $(BUILD_EXTENSION_DIR)/content/gfx/gl/shaders
|
||||
cp ../../src/gfx/gl/shaders/combined.frag $(BUILD_EXTENSION_DIR)/content/gfx/gl/shaders/
|
||||
|
|
|
@ -113,7 +113,7 @@ module Shumway.AVM2.AS {
|
|||
buffer = new Uint8Array(source).buffer;
|
||||
} else if ('buffer' in source) {
|
||||
if (source.buffer instanceof ArrayBuffer) {
|
||||
buffer = new Uint8Array(source).buffer;
|
||||
buffer = new Uint8Array(source.buffer).buffer;
|
||||
} else if (source.buffer instanceof Uint8Array) {
|
||||
var begin = source.buffer.byteOffset;
|
||||
buffer = source.buffer.buffer.slice(begin, begin + source.buffer.length);
|
||||
|
|
Загрузка…
Ссылка в новой задаче