1<!DOCTYPE html>
2<!--
3Copyright (c) 2013 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import"
9      href="/tracing/ui/extras/about_tracing/tracing_controller_client.html">
10<link rel="import" href="/tracing/ui/extras/about_tracing/inspector_connection.html">
11
12<script>
13'use strict';
14
15tr.exportTo('tr.ui.e.about_tracing', function() {
16  function createResolvedPromise(data) {
17    var promise = new Promise(function(resolve, reject) {
18      if (data)
19        resolve(data);
20      else
21        resolve();
22    });
23    return promise;
24  }
25
26  function appendTraceChunksTo(chunks, messageString) {
27    if (typeof messageString !== 'string')
28      throw new Error('Invalid data');
29    var re = /"params":\s*\{\s*"value":\s*\[([^]+)\]\s*\}\s*\}/;
30    var m = re.exec(messageString);
31    if (!m)
32      throw new Error('Malformed response');
33
34    if (chunks.length > 1)
35      chunks.push(',');
36    chunks.push(m[1]);
37  }
38
39  /**
40   * Controls tracing using the inspector's FrontendAgentHost APIs.
41   *
42   * @constructor
43   */
44  function InspectorTracingControllerClient() {
45    this.recording_ = false;
46    this.bufferUsage_ = 0;
47    this.conn_ = tr.ui.e.about_tracing.InspectorConnection.instance;
48    this.currentTraceTextChunks_ = undefined;
49  }
50
51  InspectorTracingControllerClient.prototype = {
52    __proto__: tr.ui.e.about_tracing.TracingControllerClient.prototype,
53
54    beginMonitoring: function(monitoringOptions) {
55      throw new Error('Not implemented');
56    },
57
58    endMonitoring: function() {
59      throw new Error('Not implemented');
60    },
61
62    captureMonitoring: function() {
63      throw new Error('Not implemented');
64    },
65
66    getMonitoringStatus: function() {
67      return createResolvedPromise({
68        isMonitoring: false,
69        categoryFilter: '',
70        useSystemTracing: false,
71        useContinuousTracing: false,
72        useSampling: false
73      });
74    },
75
76    getCategories: function() {
77      var res = this.conn_.req('Tracing.getCategories', {});
78      return res.then(function(result) {
79        return result.categories;
80      }, function(err) {
81        return [];
82      });
83    },
84
85    beginRecording: function(recordingOptions) {
86      if (this.recording_)
87        throw new Error('Already recording');
88      this.recording_ = 'starting';
89      var res = this.conn_.req(
90          'Tracing.start',
91          {
92            categories: recordingOptions.categoryFilter,
93            options:
94                [recordingOptions.tracingRecordMode,
95                  (recordingOptions.useSampling ? 'enable-sampling' : '')
96                ].join(','),
97            bufferUsageReportingInterval: 1000
98          });
99      res = res.then(
100          function ok() {
101            this.conn_.setNotificationListener(
102                'Tracing.bufferUsage',
103                this.onBufferUsageUpdateFromInspector_.bind(this));
104            this.recording_ = true;
105          }.bind(this),
106          function error() {
107            this.recording_ = false;
108          }.bind(this));
109      return res;
110    },
111
112    onBufferUsageUpdateFromInspector_: function(params) {
113      this.bufferUsage_ = params.value || params.percentFull;
114    },
115
116    beginGetBufferPercentFull: function() {
117      var that = this;
118      return new Promise(function(resolve, reject) {
119        setTimeout(function() {
120          resolve(that.bufferUsage_);
121        }, 100);
122      });
123    },
124
125    onDataCollected_: function(messageString) {
126      appendTraceChunksTo(this.currentTraceTextChunks_, messageString);
127    },
128
129    endRecording: function() {
130      if (this.recording_ === false)
131        return createResolvedPromise();
132
133      if (this.recording_ !== true)
134        throw new Error('Cannot end');
135
136      this.currentTraceTextChunks_ = ['['];
137      this.conn_.setNotificationListener(
138          'Tracing.dataCollected', this.onDataCollected_.bind(this));
139
140      var clearListeners = function() {
141        this.conn_.setNotificationListener(
142            'Tracing.bufferUsage', undefined);
143        this.conn_.setNotificationListener(
144            'Tracing.tracingComplete', undefined);
145        this.conn_.setNotificationListener(
146            'Tracing.dataCollected', undefined);
147      }.bind(this);
148
149      this.recording_ = 'stopping';
150      return new Promise(function(resolve, reject) {
151        function tracingComplete() {
152          clearListeners();
153          this.recording_ = false;
154          this.currentTraceTextChunks_.push(']');
155          var traceText = this.currentTraceTextChunks_.join('');
156          this.currentTraceTextChunks_ = undefined;
157          resolve(traceText);
158        }
159
160        function tracingFailed(err) {
161          clearListeners();
162          this.recording_ = false;
163          reject(err);
164        }
165
166        this.conn_.setNotificationListener(
167            'Tracing.tracingComplete', tracingComplete.bind(this));
168        this.conn_.req('Tracing.end', {}).then(
169            function end() {
170              // Nothing happens here. We're really waiting for
171              // Tracing.tracingComplete.
172            }.bind(this),
173            tracingFailed.bind(this));
174      }.bind(this));
175    },
176
177    defaultTraceName: function() {
178      return 'trace.json';
179    }
180  };
181
182  return {
183    InspectorTracingControllerClient: InspectorTracingControllerClient,
184    appendTraceChunksTo: appendTraceChunksTo
185  };
186});
187</script>
188