1// Copyright (C) 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {Actions} from '../common/actions';
16import {Engine, QueryError} from '../common/engine';
17import {iter, STR} from '../common/query_iterator';
18
19import {Controller} from './controller';
20import {globals} from './globals';
21
22export class MetricsController extends Controller<'main'> {
23  private engine: Engine;
24  private currentlyRunningMetric?: string;
25
26  constructor(args: {engine: Engine}) {
27    super('main');
28    this.engine = args.engine;
29    this.setup().finally(() => {
30      this.run();
31    });
32  }
33
34  private async getMetricNames() {
35    const metrics = [];
36    const it = iter(
37        {
38          name: STR,
39        },
40        await this.engine.query('select name from trace_metrics'));
41    for (; it.valid(); it.next()) {
42      metrics.push(it.row.name);
43    }
44    return metrics;
45  }
46
47  private async setup() {
48    const metrics = await this.getMetricNames();
49    globals.dispatch(Actions.setAvailableMetrics({metrics}));
50  }
51
52  private async computeMetric(name: string) {
53    if (name === this.currentlyRunningMetric) return;
54    this.currentlyRunningMetric = name;
55    try {
56      const metricResult = await this.engine.computeMetric([name]);
57      globals.publish(
58          'MetricResult',
59          {name, resultString: metricResult.metricsAsPrototext});
60    } catch (e) {
61      if (e instanceof QueryError) {
62        // Reroute error to be displated differently when metric is run through
63        // metric page.
64        globals.publish('MetricResult', {name, error: e.message});
65      } else {
66        throw e;
67      }
68    }
69    globals.dispatch(Actions.resetMetricRequest({name}));
70    this.currentlyRunningMetric = undefined;
71  }
72
73  run() {
74    const {requestedMetric} = globals.state.metrics;
75    if (!requestedMetric) return;
76    this.computeMetric(requestedMetric);
77  }
78}
79