Skip to content

Commit

Permalink
Sessions: Update frontend to interface with the session-based protocol.
Browse files Browse the repository at this point in the history
  • Loading branch information
rjbailey committed Jan 6, 2014
1 parent 32bf6d1 commit b0a4c3d
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 18 deletions.
93 changes: 93 additions & 0 deletions Source/WebInspectorUI/UserInterface/CaptureSessionObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2013 University of Washington. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University of Washington nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

WebInspector.CaptureSessionObject = function(uid)
{
this.uid = uid;

this._recordings = [];
this._dataLoaded = false;
}

WebInspector.CaptureSessionObject.prototype = {
constructor: WebInspector.CaptureSessionObject,
__proto__: WebInspector.Object.prototype,

// Public

get recordings() {
return this._recordings.slice();
},

append: function(recording)
{
this._recordings.push(recording);
},

insert: function(position, recording)
{
this._recordings.splice(position, 0, recording);
},

remove: function(position)
{
this._recordings.splice(position, 1);
},

loadData: function(data)
{
console.assert(this.uid === data.sessionId, "CaptureSessionObject ID doesn't match serialized session ID.", data);

this._dateCreated = new Date(data.dateCreated);
this._dataLoaded = true;

console.assert(data.recordings, "Missing recordings list in serialized recording.", data);
this._recordings = data.recordings;
},

dataLoaded: function()
{
return this._dataLoaded;
},

get dateCreated()
{
return this._dateCreated;
},

filename: function()
{
return "CaptureSession-" + this.dateCreated.toISO8601Compact() + ".webreplay";
},

displayName: function()
{
return WebInspector.UIString("Capture Session %d", this.uid) || WebInspector.UIString("(uninitialized)");
}
};
1 change: 1 addition & 0 deletions Source/WebInspectorUI/UserInterface/Main.html
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@
<script src="RecordingCalculator.js"></script>
<script src="LiveRecordingObject.js"></script>
<script src="SerializedRecordingObject.js"></script>
<script src="CaptureSessionObject.js"></script>
<script src="ReplayInputDataProvider.js"></script>
<script src="ReplayInputGraph.js"></script>
<script src="HorizontalPointMarker.js"></script>
Expand Down
96 changes: 92 additions & 4 deletions Source/WebInspectorUI/UserInterface/RecordingsManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,24 @@ WebInspector.RecordingsManager = function()
// this manager is not reset when the main frame reloads,
// so initialization is inlined into the constructor.

this._sessions = [];
this._sessionsByUID = {};

this._recordings = [];
this._recordingsByUID = {};

// load recordings that may already be available on backend.
// load recordings and sessions that may already be available on backend.
ReplayAgent.getAvailableRecordings(this._updateAvailableRecordings.bind(this));
ReplayAgent.getAvailableSessions(this._updateAvailableSessions.bind(this));
}

WebInspector.RecordingsManager.Event = {
SessionAdded: "recordings-manager-session-added",
SessionRemoved: "recordings-manager-session-removed",
RecordingAdded: "recordings-manager-recording-added",
RecordingRemoved: "recordings-manager-recording-removed"
RecordingRemoved: "recordings-manager-recording-removed",
RecordingAddedToSession: "recordings-manager-recording-added-to-session",
RecordingRemovedFromSession: "recordings-manager-recording-removed-from-session"
};

WebInspector.RecordingsManager.prototype = {
Expand All @@ -52,6 +60,10 @@ WebInspector.RecordingsManager.prototype = {

// Public

get sessions() {
return this._sessions.slice();
},

get recordings() {
return this._recordings.slice();
},
Expand Down Expand Up @@ -81,7 +93,46 @@ WebInspector.RecordingsManager.prototype = {
});
},

addRecording: function(uid) {
addSession: function(uid)
{
console.assert(uid >= 0, "tried to add session with invalid uid: "+uid);

if (this._sessionsByUID[uid])
return;

// asynchronously load all data for each new session as it's added, and
// defer any events that cause the data to be accessed.
var newSession = new WebInspector.CaptureSessionObject(uid);
this._sessionsByUID[uid] = newSession;
this._sessions.push(newSession);

var loadDataForSession = function(session, error, data) {
if (error) {
console.error("Couldn't load data for session "+session.uid+":"+error);
return;
}

session.loadData(data);
this.dispatchEventToListeners(WebInspector.RecordingsManager.Event.SessionAdded, session);
};

ReplayAgent.getSerializedSession(uid, loadDataForSession.bind(this, newSession));
},

removeSession: function(uid)
{
// FIXME: implement this.
},

getSessionWithUID: function(uid)
{
console.assert(uid >= 0, "invalid uid in request for session.");
console.assert(this._sessionsByUID[uid], "no session exists with the requested uid: "+uid);
return this._sessionsByUID[uid];
},

addRecording: function(uid)
{
console.assert(uid > 0, "tried to add recording with invalid uid: "+uid);

if (this._recordingsByUID[uid])
Expand All @@ -108,19 +159,56 @@ WebInspector.RecordingsManager.prototype = {
ReplayAgent.getSerializedRecording(uid, loadDataForRecording.bind(this, newRecording));
},

removeRecording: function(recording) {
removeRecording: function(recording)
{
// FIXME: implement this (see old RecordingsModel.js).
// It depends on AsyncTaskScheduler to safely remove recordings that may be already loaded.
},

getRecordingWithUID: function(uid)
{
console.assert(uid > 0, "invalid uid in request for recording.");
console.assert(this._recordingsByUID[uid], "no recording exists with the requested uid: "+uid);
return this._recordingsByUID[uid];
},

addRecordingToSession: function(sessionId, recordingId, recordingIndex)
{
var session = this.getSessionWithUID(sessionId);
var recording = this.getRecordingWithUID(recordingId);
session.insert(recordingIndex, recording);
this.dispatchEventToListeners(WebInspector.RecordingsManager.Event.RecordingAddedToSession, {
session: session,
recording: recording
});
},

removeRecordingFromSession: function(sessionId, recordingIndex)
{
var session = this.getSessionWithUID(sessionId);
var recording = session.recordings[recordingIndex];
session.remove(recordingIndex);
this.dispatchEventToListeners(WebInspector.RecordingsManager.Event.RecordingRemovedFromSession, {
session: session,
recording: recording
});
},

// Private

_deleteEntryForSession: function(session)
{
this._sessions.splice(this._sessions.indexOf(session), 1);
delete this._sessionsByUID[session.uid];
},

_updateAvailableSessions: function(error, data)
{
for (var i = 0; i < data.length; ++i) {
this.addSession(data[i]);
}
},

_deleteEntryForRecording: function(recording)
{
this._recordings.splice(this._recordings.indexOf(recording), 1);
Expand Down
2 changes: 1 addition & 1 deletion Source/WebInspectorUI/UserInterface/ReplayDashboardView.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ WebInspector.ReplayDashboardView.prototype = {

_ejectButtonClicked: function(event)
{
WebInspector.replayManager.unloadRecordingSoon();
WebInspector.replayManager.ejectRecordingSoon();
},

_captureStarted: function()
Expand Down
49 changes: 36 additions & 13 deletions Source/WebInspectorUI/UserInterface/ReplayManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ WebInspector.ReplayManager.prototype = {
return this._replayState === WebInspector.ReplayManager.ReplayState.ReplayPausedAtInput;
},

get activeSession()
{
return this._activeSession;
},

get createdRecording()
{
console.assert(this.isCapturing, "ReplayManager.createdRecording only available when capturing is in progress.");
Expand All @@ -130,6 +135,11 @@ WebInspector.ReplayManager.prototype = {
this._replaySpeed = value;
},

get currentRecordingIndex()
{
return this._currentRecordingIndex;
},

get currentMarkIndex()
{
return this._currentMarkIndex;
Expand All @@ -145,9 +155,9 @@ WebInspector.ReplayManager.prototype = {
this.scheduler.enqueue(new WebInspector.ReplayManager.AsyncTasks.StopCapture());
},

unloadRecordingSoon: function()
ejectRecordingSoon: function()
{
this.scheduler.enqueue(new WebInspector.ReplayManager.AsyncTasks.UnloadRecording());
this.scheduler.enqueue(new WebInspector.ReplayManager.AsyncTasks.EjectRecording());
},

pausePlaybackSoon: function()
Expand Down Expand Up @@ -184,6 +194,9 @@ WebInspector.ReplayManager.prototype = {
delete this._activeRecording;
this.unsuppressBreakpoints();
this.dispatchEventToListeners(WebInspector.ReplayManager.Event.CaptureStopped);

this.recordingLoaded(this._activeSession.recordings[0].uid);
this._currentRecordingIndex = 0;
},

playbackStarted: function()
Expand Down Expand Up @@ -224,8 +237,9 @@ WebInspector.ReplayManager.prototype = {
this.dispatchEventToListeners(WebInspector.ReplayManager.Event.PlaybackError, data);
},

playbackHitMark: function(markIndex)
playbackHitLocation: function(recordingIndex, markIndex)
{
this._currentRecordingIndex = recordingIndex;
this._setReplayCursor(markIndex);
},

Expand All @@ -238,6 +252,15 @@ WebInspector.ReplayManager.prototype = {
this.dispatchEventToListeners(WebInspector.ReplayManager.Event.RecordingUnloaded, unloadedRecording);
},

sessionLoaded: function(sessionId)
{
var session = WebInspector.recordingsManager.getSessionWithUID(sessionId);
console.assert(session, "Unknown session loaded:", session);

this._activeSession = session;
this.dispatchEventToListeners(WebInspector.ReplayManager.Event.SessionLoaded, this.activeSession);
},

recordingLoaded: function(uid)
{
var setActiveRecording = function() {
Expand Down Expand Up @@ -291,11 +314,12 @@ WebInspector.ReplayManager.prototype = {
ReplayAgent.loadRecording(recording.uid);
},

unloadRecording: function()
ejectRecording: function()
{
console.assert(this.loadedRecording, "Can't unload recording because none is loaded");
console.assert(this.loadedRecording, "Can't eject recording because none is loaded");
// TODO: receiving !wasAllowed should trigger task error.
ReplayAgent.unloadRecording();
ReplayAgent.removeRecordingFromSession(this._activeSession.uid, this._currentRecordingIndex);
this.recordingUnloaded();
},

createRecording: function()
Expand All @@ -316,7 +340,7 @@ WebInspector.ReplayManager.prototype = {
{
// TODO: save replay start and end mark indices here
this.dispatchEventToListeners(WebInspector.ReplayManager.Event.PlaybackWillStart);
ReplayAgent.replayUpToMarkIndex(index, this.replaySpeed === WebInspector.ReplayManager.ReplaySpeed.Seeking);
ReplayAgent.replayUpToLocation(this._currentRecordingIndex, index, this.replaySpeed === WebInspector.ReplayManager.ReplaySpeed.Seeking);
},

replayToCompletion: function()
Expand Down Expand Up @@ -352,7 +376,6 @@ WebInspector.ReplayManager.AsyncTasks.StartCapture = function() {
var task = new WebInspector.AsyncTask("StartCapture")
// if replaying, stop playback as the first subtask.
.chain("stopPlaybackIfNeeded", WebInspector.ReplayManager.AsyncTaskSteps.StopPlaybackIfNeeded)
.chain("unloadRecordingIfNeeded", WebInspector.ReplayManager.AsyncTaskSteps.UnloadRecordingIfNeeded)
.chain("suppressBreakpoints", WebInspector.ReplayManager.AsyncTaskSteps.SuppressBreakpoints)
.chain("resumeDebuggerIfPaused", WebInspector.ReplayManager.AsyncTaskSteps.ResumeDebuggerIfPaused)
.chain("requestStartCapture", function(cb) {
Expand Down Expand Up @@ -383,11 +406,11 @@ WebInspector.ReplayManager.AsyncTasks.LoadRecording = function()
return new WebInspector.AsyncTask("not implemented", function(cb) { return cb(); });
};

WebInspector.ReplayManager.AsyncTasks.UnloadRecording = function()
WebInspector.ReplayManager.AsyncTasks.EjectRecording = function()
{
return new WebInspector.AsyncTask("UnloadRecording")
return new WebInspector.AsyncTask("EjectRecording")
.chain("stopPlaybackIfNeeded", WebInspector.ReplayManager.AsyncTaskSteps.StopPlaybackIfNeeded)
.chain("unloadRecordingIfNeeded", WebInspector.ReplayManager.AsyncTaskSteps.UnloadRecordingIfNeeded);
.chain("doEjectRecording", WebInspector.ReplayManager.AsyncTaskSteps.DoEjectRecording);
};

WebInspector.ReplayManager.AsyncTasks.ReplayToIndex = function()
Expand Down Expand Up @@ -490,11 +513,11 @@ WebInspector.ReplayManager.AsyncTaskSteps.UnsuppressBreakpoints = function(cb)
DebuggerAgent.causesRecompilation(cb);
};

WebInspector.ReplayManager.AsyncTaskSteps.UnloadRecordingIfNeeded = function(cb)
WebInspector.ReplayManager.AsyncTaskSteps.DoEjectRecording = function(cb)
{
if (!WebInspector.replayManager.canReplay)
return cb();

WebInspector.replayManager.addSingleFireEventListener(WebInspector.ReplayManager.Event.RecordingUnloaded, cb);
WebInspector.replayManager.unloadRecording();
WebInspector.replayManager.ejectRecording();
};

0 comments on commit b0a4c3d

Please sign in to comment.