Commit 16ba2c0a authored by Alexei Filippov's avatar Alexei Filippov Committed by Commit Bot

DevTools: Get rid of OutputStreamDelegate.

Change-Id: I1b54003924e3c35c04fb9781820dced4830afde7
Reviewed-on: https://chromium-review.googlesource.com/545238
Commit-Queue: Alexei Filippov <alph@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#485079}
parent 2d9116a4
......@@ -856,7 +856,6 @@ InspectorTest.MockSetting.prototype = {
* @constructor
* @param {!string} dirPath
* @param {!string} name
* @param {!function(?Bindings.TempFile)} callback
*/
InspectorTest.TempFileMock = function(dirPath, name)
{
......@@ -905,9 +904,10 @@ InspectorTest.TempFileMock.prototype = {
/**
* @param {!Common.OutputStream} outputStream
* @param {!Bindings.OutputStreamDelegate} delegate
* @param {function(*)=} progress
* @return {!Promise<boolean>}
*/
copyToOutputStream: function(outputStream, delegate)
copyToOutputStream: function(outputStream, progress)
{
var name = this._name;
var text = this._chunks.join("");
......@@ -929,11 +929,11 @@ InspectorTest.TempFileMock.prototype = {
cancel: function() { }
}
delegate.onTransferStarted(chunkedReaderMock);
outputStream.write(text);
delegate.onChunkTransferred(chunkedReaderMock);
if (progress)
progress(chunkedReaderMock);
outputStream.close();
delegate.onTransferFinished(chunkedReaderMock);
return Promise.resolve(true);
},
remove: function() { }
......
......@@ -69,9 +69,6 @@ InspectorTest.formatters.formatAsInvalidationCause = function(cause)
return "{reason: " + cause.reason + ", stackTrace: " + stackTrace + "}";
}
InspectorTest.preloadPanel("timeline");
Bindings.TempFile = InspectorTest.TempFileMock;
InspectorTest.createTracingModel = function(events)
{
var model = new SDK.TracingModel(new Bindings.TempFileBackingStorage("tracing"));
......@@ -302,13 +299,57 @@ InspectorTest.findChildEvent = function(events, parentIndex, name)
return null;
}
InspectorTest.FakeFileReader = function(input, delegate, callback)
{
this._delegate = delegate;
this._callback = callback;
this._input = input;
this._loadedSize = 0;
this._fileSize = input.length;
InspectorTest.FakeFileReader = class {
constructor(input, chunkSize, chunkTransferredCallback)
{
this._input = input;
this._loadedSize = 0;
this._fileSize = input.length;
this._chunkTransferredCallback = chunkTransferredCallback;
}
read(output)
{
var length = this._input.length;
var half = (length + 1) >> 1;
var chunk = this._input.substring(0, half);
this._loadedSize += chunk.length;
output.write(chunk);
if (this._chunkTransferredCallback)
this._chunkTransferredCallback(this);
chunk = this._input.substring(half);
this._loadedSize += chunk.length;
output.write(chunk);
if (this._chunkTransferredCallback)
this._chunkTransferredCallback(this);
output.close();
return Promise.resolve(true);
}
cancel() { }
loadedSize()
{
return this._loadedSize;
}
fileSize()
{
return this._fileSize;
}
fileName()
{
return "fakeFile";
}
error()
{
return null;
}
};
InspectorTest.dumpFrame = function(frame)
......@@ -372,60 +413,11 @@ InspectorTest.dumpTimelineFlameChart = function(includeGroups) {
InspectorTest.dumpFlameChartProvider(provider, includeGroups);
}
InspectorTest.FakeFileReader.prototype = {
start: function(output)
{
this._delegate.onTransferStarted(this);
var length = this._input.length;
var half = (length + 1) >> 1;
var chunk = this._input.substring(0, half);
this._loadedSize += chunk.length;
output.write(chunk);
this._delegate.onChunkTransferred(this);
chunk = this._input.substring(half);
this._loadedSize += chunk.length;
output.write(chunk);
this._delegate.onChunkTransferred(this);
output.close();
this._delegate.onTransferFinished(this);
this._callback();
},
cancel: function() { },
loadedSize: function()
{
return this._loadedSize;
},
fileSize: function()
{
return this._fileSize;
},
fileName: function()
{
return "fakeFile";
}
};
InspectorTest.loadTimeline = function(timelineData)
{
var timeline = UI.panels.timeline;
function createFileReader(file, delegate)
{
return new InspectorTest.FakeFileReader(timelineData, delegate, timeline._saveToFile.bind(timeline));
}
InspectorTest.override(Timeline.TimelineLoader, "_createFileReader", createFileReader);
Bindings.ChunkedFileReader = InspectorTest.FakeFileReader;
var promise = new Promise(fulfill => InspectorTest.runWhenTimelineIsReady(fulfill));
timeline._loadFromFile({});
UI.panels.timeline._loadFromFile(timelineData);
return promise;
}
......
This tests that ChunkedFileReader properly re-assembles chunks, especially in case these contain multibyte characters.
Bindings.OutputStreamDelegate.onTransferStarted() called
Chunks transferred: 40
Bindings.OutputStreamDelegate.onTransferFinished() called
Read result: true
Chunks transferred: 41
DONE
......@@ -4,50 +4,7 @@
<script src="../../http/tests/inspector/inspector-test.js"></script>
<script>
function initialize_ChunkedFileReaderTest()
{
InspectorTest.TestOutputStreamDelegate = function(doneCallback)
{
this._doneCallback = doneCallback;
this._chunkCount = 0;
}
InspectorTest.TestOutputStreamDelegate.prototype = {
onTransferStarted: function()
{
InspectorTest.addResult("Bindings.OutputStreamDelegate.onTransferStarted() called");
},
onTransferFinished: function()
{
InspectorTest.addResult("Chunks transferred: " + this._chunkCount);
InspectorTest.addResult("Bindings.OutputStreamDelegate.onTransferFinished() called");
this._doneCallback();
},
/**
* @param {!Bindings.ChunkedReader} reader
*/
onChunkTransferred: function(reader)
{
this._chunkCount++;
},
/**
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} event
*/
onError: function(reader, event)
{
InspectorTest.addResult("Bindings.OutputStreamDelegate.onError() called");
this._doneCallback();
}
};
}
function test()
async function test()
{
var text = ["Латынь из моды вышла ныне:\n",
"Так, если правду вам сказать,\n",
......@@ -58,15 +15,17 @@ function test()
// Most of the characters above will be encoded as 2 bytes, so make sure we use odd
// chunk size to cause chunk boundaries sometimes to happen between chaacter bytes.
var chunkSize = 5;
var reader = new Bindings.ChunkedFileReader(blob, chunkSize, new InspectorTest.TestOutputStreamDelegate(onTransferFinished));
var chunkCount = 0;
var reader = new Bindings.ChunkedFileReader(blob, chunkSize, () => ++chunkCount);
var output = new Common.StringOutputStream();
reader.start(output);
function onTransferFinished()
{
InspectorTest.assertEquals(text.join(""), output.data(), "Read text is different from written text");
InspectorTest.addResult("DONE");
InspectorTest.completeTest();
}
var error = await reader.read(output);
InspectorTest.addResult("Read result: " + error);
InspectorTest.addResult("Chunks transferred: " + chunkCount);
InspectorTest.assertEquals(text.join(""), output.data(), "Read text is different from written text");
InspectorTest.addResult("DONE");
InspectorTest.completeTest();
}
</script>
......
......@@ -108,13 +108,12 @@ function test()
var profileName = file.name.substr(0, file.name.length - ".cpuprofile".length);
InspectorTest.waitUntilProfileViewIsShown(profileName, checkLoadedContent);
profilesPanel._loadFromFile(file);
var onTransferFinished = Profiler.CPUProfileHeader.prototype.onTransferFinished;
Profiler.CPUProfileHeader.prototype.onTransferFinished = function()
{
InspectorTest.addSniffer(Profiler.CPUProfileHeader.prototype, "updateStatus", function(statusText) {
if (!statusText.startsWith("Parsing"))
return;
loadedProfileData = this._jsonifiedProfile;
onTransferFinished.call(this);
UI.panels.js_profiler.showProfile(this);
}
setTimeout(() => UI.panels.js_profiler.showProfile(this), 0);
}, true);
}
]);
......
......@@ -81,33 +81,31 @@ function test()
size: sourceStringified.length
};
InspectorTest.override(Profiler.HeapProfileHeader.prototype, '_createFileReader', function(fileMock, delegate) {
return {
start: function(receiver) {
delegate.onTransferStarted(this);
receiver.write(sourceStringified);
delegate.onChunkTransferred(this);
receiver.close();
delegate.onTransferFinished(this);
},
loadedSize: function()
{
return fileMock.size;
},
fileSize: function()
{
return fileMock.size;
},
fileName: function()
{
return fileMock.name;
}
};
});
InspectorTest.addSniffer(Profiler.HeapProfileHeader.prototype, "_snapshotReceived", function() { next(); });
Bindings.ChunkedFileReader = class {
constructor() {}
read(receiver) {
receiver.write(sourceStringified);
receiver.close();
return Promise.resolve(true);
}
loadedSize()
{
return fileMock.size;
}
fileSize()
{
return fileMock.size;
}
fileName()
{
return fileMock.name;
}
};
InspectorTest.addSniffer(Profiler.HeapProfileHeader.prototype, "_snapshotReceived", next);
panel._loadFromFile(fileMock);
},
......
......@@ -6,7 +6,7 @@
<script src="../resources/timeline-data.js"></script>
<script>
function test()
async function test()
{
var timeline = UI.panels.timeline;
timeline._onModeChanged();
......@@ -19,7 +19,8 @@ function test()
}
timeline.requestWindowTimes = requestWindowTimesHook;
InspectorTest.loadTimeline(InspectorTest.timelineData()).then(() => InspectorTest.completeTest());
await InspectorTest.loadTimeline(InspectorTest.timelineData());
InspectorTest.completeTest();
}
</script>
......
......@@ -6,9 +6,9 @@
function test()
{
InspectorTest.TestTimelineLoaderClient = function(callback)
InspectorTest.TestTimelineLoaderClient = function()
{
this._callback = callback;
this._completePromise = new Promise(resolve => this._resolve = resolve);
}
InspectorTest.TestTimelineLoaderClient.prototype = {
......@@ -29,19 +29,18 @@ function test()
loadingComplete: function(model)
{
this.model = model;
InspectorTest.addResult(`TimelineLoaderClient.loadingComplete(${!!model})`);
this._callback();
this._resolve(model);
},
}
function runTestWithDataAndCheck(input, expectedOutput, callback)
{
function createFileReader(file, delegate)
modelPromise: function()
{
return new InspectorTest.FakeFileReader(input, delegate, () => {});
return this._completePromise;
}
}
async function runTestWithDataAndCheck(input, expectedOutput, callback)
{
function checkSaveData(output)
{
var saveData = JSON.parse(output);
......@@ -49,36 +48,24 @@ function test()
callback();
}
InspectorTest.override(Timeline.TimelineLoader, "_createFileReader", createFileReader);
var delegate = new InspectorTest.TestTimelineLoaderClient(onTimelineLoaded);
Timeline.TimelineLoader.loadFromFile({}, delegate);
async function onTimelineLoaded()
{
var saver = new Timeline.TracingTimelineSaver();
var stream = new InspectorTest.StringOutputStream(InspectorTest.safeWrap(checkSaveData));
var storage = delegate.model.backingStorage();
await stream.open("");
storage.writeToStream(stream, saver);
}
Bindings.ChunkedFileReader = InspectorTest.FakeFileReader;
var client = new InspectorTest.TestTimelineLoaderClient();
var loader = Timeline.TimelineLoader.loadFromFile(input, client);
var stream = new InspectorTest.StringOutputStream(InspectorTest.safeWrap(checkSaveData));
var model = await client.modelPromise();
var storage = model.backingStorage();
await stream.open("");
storage.writeToStream(stream);
}
function runTestOnMalformedInput(input, callback)
async function runTestOnMalformedInput(input, callback)
{
function createFileReader(file, delegate)
{
return new InspectorTest.FakeFileReader(input, delegate, () => {});
}
function checkLoadedData(data)
{
var model = delegate.model;
InspectorTest.addResult("Model is empty: " + (!model || (!model.minimumRecordTime() && !model.maximumRecordTime())));
callback();
}
InspectorTest.override(Timeline.TimelineLoader, "_createFileReader", createFileReader);
var delegate = new InspectorTest.TestTimelineLoaderClient(checkLoadedData);
Timeline.TimelineLoader.loadFromFile({}, delegate);
Bindings.ChunkedFileReader = InspectorTest.FakeFileReader;
var client = new InspectorTest.TestTimelineLoaderClient();
var loader = Timeline.TimelineLoader.loadFromFile(input, client);
var model = await client.modelPromise();
InspectorTest.addResult("Model is empty: " + (!model || (!model.minimumRecordTime() && !model.maximumRecordTime())));
callback();
}
var data = [{"args":{"number":32},"cat":"__metadata","name":"num_cpus","ph":"M","pid":32127,"tid":0,"ts":0},
......
......@@ -27,27 +27,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @interface
*/
Bindings.OutputStreamDelegate = function() {};
Bindings.OutputStreamDelegate.prototype = {
onTransferStarted() {},
onTransferFinished() {},
/**
* @param {!Bindings.ChunkedReader} reader
*/
onChunkTransferred(reader) {},
/**
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} event
*/
onError(reader, event) {},
};
/**
* @interface
......@@ -70,7 +49,12 @@ Bindings.ChunkedReader.prototype = {
*/
fileName() {},
cancel() {}
cancel() {},
/**
* @return {?FileError}
*/
error() {}
};
/**
......@@ -81,29 +65,33 @@ Bindings.ChunkedFileReader = class {
/**
* @param {!File} file
* @param {number} chunkSize
* @param {!Bindings.OutputStreamDelegate} delegate
* @param {function(!Bindings.ChunkedReader)=} chunkTransferredCallback
*/
constructor(file, chunkSize, delegate) {
constructor(file, chunkSize, chunkTransferredCallback) {
this._file = file;
this._fileSize = file.size;
this._loadedSize = 0;
this._chunkSize = chunkSize;
this._delegate = delegate;
this._chunkTransferredCallback = chunkTransferredCallback;
this._decoder = new TextDecoder();
this._isCanceled = false;
/** @type {?FileError} */
this._error = null;
}
/**
* @param {!Common.OutputStream} output
* @return {!Promise<boolean>}
*/
start(output) {
read(output) {
if (this._chunkTransferredCallback)
this._chunkTransferredCallback(this);
this._output = output;
this._reader = new FileReader();
this._reader.onload = this._onChunkLoaded.bind(this);
this._reader.onerror = this._delegate.onError.bind(this._delegate, this);
this._delegate.onTransferStarted();
this._reader.onerror = this._onError.bind(this);
this._loadChunk();
return new Promise(resolve => this._transferFinished = resolve);
}
/**
......@@ -137,6 +125,14 @@ Bindings.ChunkedFileReader = class {
return this._file.name;
}
/**
* @override
* @return {?FileError}
*/
error() {
return this._error;
}
/**
* @param {!Event} event
*/
......@@ -154,13 +150,14 @@ Bindings.ChunkedFileReader = class {
this._output.write(decodedString);
if (this._isCanceled)
return;
this._delegate.onChunkTransferred(this);
if (this._chunkTransferredCallback)
this._chunkTransferredCallback(this);
if (endOfFile) {
this._file = null;
this._reader = null;
this._output.close();
this._delegate.onTransferFinished();
this._transferFinished(!this._error);
return;
}
......@@ -173,6 +170,14 @@ Bindings.ChunkedFileReader = class {
var nextPart = this._file.slice(chunkStart, chunkEnd);
this._reader.readAsArrayBuffer(nextPart);
}
/**
* @param {!Event} event
*/
_onError(event) {
this._error = event.target.error;
this._transferFinished(false);
}
};
/**
......
......@@ -143,23 +143,31 @@ Bindings.TempFile = class {
/**
* @param {!Common.OutputStream} outputStream
* @param {!Bindings.OutputStreamDelegate} delegate
* @param {function(!Bindings.ChunkedReader)=} progress
* @return {!Promise<?FileError>}
*/
copyToOutputStream(outputStream, delegate) {
/**
* @param {!File} file
*/
function didGetFile(file) {
var reader = new Bindings.ChunkedFileReader(file, 10 * 1000 * 1000, delegate);
reader.start(outputStream);
}
function didFailToGetFile(error) {
Common.console.error('Failed to load temp file: ' + error.message);
outputStream.close();
}
copyToOutputStream(outputStream, progress) {
return new Promise(resolve => {
this._fileEntry.file(didGetFile, didFailToGetFile);
/**
* @param {!File} file
*/
async function didGetFile(file) {
var reader = new Bindings.ChunkedFileReader(file, 10 * 1000 * 1000, progress);
var success = await reader.read(outputStream);
resolve(success ? null : reader.error());
}
this._fileEntry.file(didGetFile, didFailToGetFile);
/**
* @param {!FileError} error
*/
function didFailToGetFile(error) {
Common.console.error('Failed to load temp file: ' + error.message);
outputStream.close();
resolve(error);
}
});
}
remove() {
......@@ -232,12 +240,12 @@ Bindings.DeferredTempFile = class {
/**
* @param {!Common.OutputStream} outputStream
* @param {!Bindings.OutputStreamDelegate} delegate
* @param {function()=} progress
* @return {!Promise<?FileError>}
*/
async copyToOutputStream(outputStream, delegate) {
async copyToOutputStream(outputStream, progress) {
await this._writeFinishedPromise;
if (this._tempFile)
this._tempFile.copyToOutputStream(outputStream, delegate);
return this._tempFile ? await this._tempFile.copyToOutputStream(outputStream, progress) : null;
}
async remove() {
......@@ -364,11 +372,10 @@ Bindings.TempFileBackingStorage = class {
/**
* @param {!Common.OutputStream} outputStream
* @param {!Bindings.OutputStreamDelegate} delegate
* @return {!Promise<?FileError>}
*/
writeToStream(outputStream, delegate) {
if (this._file)
this._file.copyToOutputStream(outputStream, delegate);
writeToStream(outputStream) {
return this._file ? this._file.copyToOutputStream(outputStream) : Promise.resolve(null);
}
};
......
......@@ -1316,6 +1316,8 @@ Profiler.HeapProfileHeader = class extends Profiler.ProfileHeader {
this._loadPromise = new Promise(resolve => this._fulfillLoad = resolve);
this._totalNumberOfChunks = 0;
this._bufferedWriter = null;
/** @type {?Bindings.TempFile} */
this._tempFile = null;
}
/**
......@@ -1359,6 +1361,9 @@ Profiler.HeapProfileHeader = class extends Profiler.ProfileHeader {
this._didWriteToTempFile(file);
}
/**
* @param {!Bindings.TempFile} tempFile
*/
_didWriteToTempFile(tempFile) {
if (this._wasDisposed) {
if (tempFile)
......@@ -1470,145 +1475,53 @@ Profiler.HeapProfileHeader = class extends Profiler.ProfileHeader {
* @param {boolean} accepted
* @this {Profiler.HeapProfileHeader}
*/
function onOpen(accepted) {
async function onOpen(accepted) {
if (!accepted)
return;
if (this._failedToCreateTempFile) {
Common.console.error('Failed to open temp file with heap snapshot');
fileOutputStream.close();
} else if (this._tempFile) {
var delegate = new Profiler.SaveSnapshotOutputStreamDelegate(this);
this._tempFile.copyToOutputStream(fileOutputStream, delegate);
} else {
this._onTempFileReady = onOpen.bind(this, accepted);
this._updateSaveProgress(0, 1);
return;
}
}
}
_updateSaveProgress(value, total) {
var percentValue = ((total ? (value / total) : 0) * 100).toFixed(0);
this.updateStatus(Common.UIString('Saving\u2026 %d%%', percentValue));
}
/**
* @override
* @param {!File} file
*/
loadFromFile(file) {
this.updateStatus(Common.UIString('Loading\u2026'), true);
this._setupWorker();
var delegate = new Profiler.HeapSnapshotLoadFromFileDelegate(this);
var fileReader = this._createFileReader(file, delegate);
fileReader.start(/** @type {!Common.OutputStream} */ (this._receiver));
}
/**
* @param {!File} file
* @param {!Profiler.HeapSnapshotLoadFromFileDelegate} delegate
* @return {!Bindings.ChunkedFileReader}
*/
_createFileReader(file, delegate) {
return new Bindings.ChunkedFileReader(file, 10000000, delegate);
}
};
/**
* @implements {Bindings.OutputStreamDelegate}
* @unrestricted
*/
Profiler.HeapSnapshotLoadFromFileDelegate = class {
/**
* @param {!Profiler.HeapProfileHeader} snapshotHeader
*/
constructor(snapshotHeader) {
this._snapshotHeader = snapshotHeader;
}
/**
* @override
*/
onTransferStarted() {
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
*/
onChunkTransferred(reader) {
}
/**
* @override
*/
onTransferFinished() {
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} e
*/
onError(reader, e) {
var subtitle;
switch (e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
subtitle = Common.UIString('\'%s\' not found.', reader.fileName());
break;
case e.target.error.NOT_READABLE_ERR:
subtitle = Common.UIString('\'%s\' is not readable', reader.fileName());
break;
case e.target.error.ABORT_ERR:
if (this._tempFile) {
var error = await this._tempFile.copyToOutputStream(fileOutputStream, this._onChunkTransferred.bind(this));
if (error)
Common.console.error('Failed to read heap snapshot from temp file: ' + error.message);
this._didCompleteSnapshotTransfer();
return;
default:
subtitle = Common.UIString('\'%s\' error %d', reader.fileName(), e.target.error.code);
}
this._onTempFileReady = onOpen.bind(this, accepted);
this._updateSaveProgress(0, 1);
}
this._snapshotHeader.updateStatus(subtitle);
}
};
/**
* @implements {Bindings.OutputStreamDelegate}
*/
Profiler.SaveSnapshotOutputStreamDelegate = class {
/**
* @param {!Profiler.HeapProfileHeader} profileHeader
*/
constructor(profileHeader) {
this._profileHeader = profileHeader;
}
/**
* @override
*/
onTransferStarted() {
this._profileHeader._updateSaveProgress(0, 1);
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
*/
onTransferFinished() {
this._profileHeader._didCompleteSnapshotTransfer();
_onChunkTransferred(reader) {
this._updateSaveProgress(reader.loadedSize(), reader.fileSize());
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
* @param {number} value
* @param {number} total
*/
onChunkTransferred(reader) {
this._profileHeader._updateSaveProgress(reader.loadedSize(), reader.fileSize());
_updateSaveProgress(value, total) {
var percentValue = ((total && value / total) * 100).toFixed(0);
this.updateStatus(Common.UIString('Saving\u2026 %d%%', percentValue));
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} event
* @param {!File} file
*/
onError(reader, event) {
Common.console.error('Failed to read heap snapshot from temp file: ' + /** @type {!ErrorEvent} */ (event).message);
this.onTransferFinished();
async loadFromFile(file) {
this.updateStatus(Common.UIString('Loading\u2026'), true);
this._setupWorker();
var reader = new Bindings.ChunkedFileReader(file, 10000000);
var success = await reader.read(/** @type {!Common.OutputStream} */ (this._receiver));
if (!success)
this.updateStatus(reader.error().message);
}
};
......
......@@ -40,7 +40,7 @@ Profiler.ProfileHeader = class extends Common.Object {
* @return {!Profiler.ProfileSidebarTreeElement}
*/
createSidebarTreeElement(dataDisplayDelegate) {
throw new Error('Needs implemented.');
throw new Error('Not implemented.');
}
/**
......@@ -67,14 +67,14 @@ Profiler.ProfileHeader = class extends Common.Object {
}
saveToFile() {
throw new Error('Needs implemented');
throw new Error('Not implemented');
}
/**
* @param {!File} file
*/
loadFromFile(file) {
throw new Error('Needs implemented');
throw new Error('Not implemented');
}
/**
......
......@@ -383,7 +383,6 @@ Profiler.ProfileView.ViewTypes = {
/**
* @implements {Common.OutputStream}
* @implements {Bindings.OutputStreamDelegate}
* @unrestricted
*/
Profiler.WritableProfileHeader = class extends Profiler.ProfileHeader {
......@@ -399,54 +398,17 @@ Profiler.WritableProfileHeader = class extends Profiler.ProfileHeader {
}
/**
* @override
*/
onTransferStarted() {
this._jsonifiedProfile = '';
this.updateStatus(Common.UIString('Loading\u2026 %s', Number.bytesToString(this._jsonifiedProfile.length)), true);
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
*/
onChunkTransferred(reader) {
_onChunkTransferred(reader) {
this.updateStatus(Common.UIString('Loading\u2026 %d%%', Number.bytesToString(this._jsonifiedProfile.length)));
}
/**
* @override
*/
onTransferFinished() {
this.updateStatus(Common.UIString('Parsing\u2026'), true);
this._profile = JSON.parse(this._jsonifiedProfile);
this._jsonifiedProfile = null;
this.updateStatus(Common.UIString('Loaded'), false);
if (this.profileType().profileBeingRecorded() === this)
this.profileType().setProfileBeingRecorded(null);
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} e
*/
onError(reader, e) {
var subtitle;
switch (e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
subtitle = Common.UIString('\'%s\' not found.', reader.fileName());
break;
case e.target.error.NOT_READABLE_ERR:
subtitle = Common.UIString('\'%s\' is not readable', reader.fileName());
break;
case e.target.error.ABORT_ERR:
return;
default:
subtitle = Common.UIString('\'%s\' error %d', reader.fileName(), e.target.error.code);
}
this.updateStatus(subtitle);
_onError(reader) {
this.updateStatus(Common.UIString(`File '%s' read error: %s`, reader.fileName(), reader.error().message));
}
/**
......@@ -522,10 +484,24 @@ Profiler.WritableProfileHeader = class extends Profiler.ProfileHeader {
* @override
* @param {!File} file
*/
loadFromFile(file) {
async loadFromFile(file) {
this.updateStatus(Common.UIString('Loading\u2026'), true);
var fileReader = new Bindings.ChunkedFileReader(file, 10000000, this);
fileReader.start(this);
var fileReader = new Bindings.ChunkedFileReader(file, 10000000, this._onChunkTransferred.bind(this));
this._jsonifiedProfile = '';
var success = await fileReader.read(this);
if (!success) {
this._onError(fileReader);
return;
}
this.updateStatus(Common.UIString('Parsing\u2026'), true);
this._profile = JSON.parse(this._jsonifiedProfile);
this._jsonifiedProfile = null;
this.updateStatus(Common.UIString('Loaded'), false);
if (this.profileType().profileBeingRecorded() === this)
this.profileType().setProfileBeingRecorded(null);
}
/**
......
......@@ -159,13 +159,13 @@ Profiler.ProfilesPanel = class extends UI.PanelWithSidebar {
continue;
extensions.push(extension);
}
Common.console.error(Common.UIString(
'Can\'t load file. Only files with extensions \'%s\' can be loaded.', extensions.join('\', \'')));
Common.console.error(
Common.UIString(`Can't load file. Only files with extensions '%s' can be loaded.`, extensions.join(`', '`)));
return;
}
if (!!profileType.profileBeingRecorded()) {
Common.console.error(Common.UIString('Can\'t load profile while another profile is recording.'));
Common.console.error(Common.UIString(`Can't load profile while another profile is being recorded.`));
return;
}
......
......@@ -154,11 +154,11 @@ Timeline.PerformanceModel = class extends Common.Object {
/**
* @param {!Common.OutputStream} stream
* @param {!Bindings.OutputStreamDelegate} delegate
* @return {!Promise<?FileError>}
*/
save(stream, delegate) {
save(stream) {
var backingStorage = /** @type {!Bindings.TempFileBackingStorage} */ (this._tracingModel.backingStorage());
backingStorage.writeToStream(stream, delegate);
return backingStorage.writeToStream(stream);
}
};
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @implements {Common.OutputStream}
* @implements {Bindings.OutputStreamDelegate}
* @unrestricted
*/
Timeline.TimelineLoader = class {
......@@ -22,7 +22,6 @@ Timeline.TimelineLoader = class {
this._buffer = '';
this._firstRawChunk = true;
this._firstChunk = true;
this._loadedBytes = 0;
/** @type {number} */
this._totalSize;
......@@ -36,10 +35,13 @@ Timeline.TimelineLoader = class {
*/
static loadFromFile(file, client) {
var loader = new Timeline.TimelineLoader(client);
var fileReader = Timeline.TimelineLoader._createFileReader(file, loader);
var fileReader = new Bindings.ChunkedFileReader(file, Timeline.TimelineLoader.TransferChunkLengthBytes);
loader._canceledCallback = fileReader.cancel.bind(fileReader);
loader._totalSize = file.size;
fileReader.start(loader);
fileReader.read(loader).then(success => {
if (!success)
this._reportErrorAndCancelLoading(fileReader.error().message);
});
return loader;
}
......@@ -49,18 +51,9 @@ Timeline.TimelineLoader = class {
* @return {!Timeline.TimelineLoader}
*/
static loadFromURL(url, client) {
var stream = new Timeline.TimelineLoader(client);
Host.ResourceLoader.loadAsStream(url, null, stream);
return stream;
}
/**
* @param {!File} file
* @param {!Bindings.OutputStreamDelegate} delegate
* @return {!Bindings.ChunkedReader}
*/
static _createFileReader(file, delegate) {
return new Bindings.ChunkedFileReader(file, Timeline.TimelineLoader.TransferChunkLengthBytes, delegate);
var loader = new Timeline.TimelineLoader(client);
Host.ResourceLoader.loadAsStream(url, null, loader);
return loader;
}
cancel() {
......@@ -198,46 +191,6 @@ Timeline.TimelineLoader = class {
this._client.loadingComplete(this._tracingModel);
}
/**
* @override
*/
onTransferStarted() {
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
*/
onChunkTransferred(reader) {
}
/**
* @override
*/
onTransferFinished() {
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} event
*/
onError(reader, event) {
switch (event.target.error.name) {
case 'NotFoundError':
this._reportErrorAndCancelLoading(Common.UIString('File "%s" not found.', reader.fileName()));
break;
case 'NotReadableError':
this._reportErrorAndCancelLoading(Common.UIString('File "%s" is not readable', reader.fileName()));
break;
case 'AbortError':
break;
default:
this._reportErrorAndCancelLoading(
Common.UIString('An error occurred while reading the file "%s"', reader.fileName()));
}
}
/**
* @param {string} text
*/
......@@ -288,39 +241,3 @@ Timeline.TimelineLoader.State = {
SkippingTail: Symbol('SkippingTail'),
LoadingCPUProfileFormat: Symbol('LoadingCPUProfileFormat')
};
/**
* @implements {Bindings.OutputStreamDelegate}
* @unrestricted
*/
Timeline.TracingTimelineSaver = class {
/**
* @override
*/
onTransferStarted() {
}
/**
* @override
*/
onTransferFinished() {
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
*/
onChunkTransferred(reader) {
}
/**
* @override
* @param {!Bindings.ChunkedReader} reader
* @param {!Event} event
*/
onError(reader, event) {
var error = event.target.error;
Common.console.error(
Common.UIString('Failed to save timeline: %s (%s, %s)', error.message, error.name, error.code));
}
};
......@@ -365,7 +365,11 @@ Timeline.TimelinePanel = class extends UI.Panel {
if (!accepted)
return;
performanceModel.save(stream, new Timeline.TracingTimelineSaver());
var error = await performanceModel.save(stream);
if (!error)
return;
Common.console.error(
Common.UIString('Failed to save timeline: %s (%s, %s)', error.message, error.name, error.code));
}
async _showHistory() {
......@@ -387,12 +391,8 @@ Timeline.TimelinePanel = class extends UI.Panel {
return true;
}
/**
* @return {boolean}
*/
_selectFileToLoad() {
this._fileSelectorElement.click();
return true;
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment