summaryrefslogtreecommitdiffstats
path: root/extensions/renderer/resources/serial_custom_bindings.js
blob: d77631cf645349fbdf27e04bb95c235d56fb67cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright 2014 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.

/**
 * Custom bindings for the Serial API.
 *
 * The bindings are implemented by asynchronously delegating to the
 * serial_service module. The functions that apply to a particular connection
 * are delegated to the appropriate method on the Connection object specified by
 * the ID parameter.
 */

var binding = require('binding').Binding.create('serial');
var context = requireNative('v8_context');
var eventBindings = require('event_bindings');
var utils = require('utils');

var serialServicePromise = function() {
  // getBackgroundPage is not available in unit tests so fall back to the
  // current page's serial_service module.
  if (!chrome.runtime.getBackgroundPage)
    return requireAsync('serial_service');

  // Load the serial_service module from the background page if one exists. This
  // is necessary for serial connections created in one window to be usable
  // after that window is closed. This is necessary because the Mojo async
  // waiter only functions while the v8 context remains.
  return utils.promise(chrome.runtime.getBackgroundPage).then(function(bgPage) {
    return context.GetModuleSystem(bgPage).requireAsync('serial_service');
  }).catch(function() {
    return requireAsync('serial_service');
  });
}();

function forwardToConnection(methodName) {
  return function(connectionId) {
    var args = $Array.slice(arguments, 1);
    return serialServicePromise.then(function(serialService) {
      return serialService.getConnection(connectionId);
    }).then(function(connection) {
      return $Function.apply(connection[methodName], connection, args);
    });
  };
}

function addEventListeners(connection, id) {
  connection.onData = function(data) {
    eventBindings.dispatchEvent(
        'serial.onReceive', [{connectionId: id, data: data}]);
  };
  connection.onError = function(error) {
    eventBindings.dispatchEvent(
        'serial.onReceiveError', [{connectionId: id, error: error}]);
  };
}

serialServicePromise.then(function(serialService) {
  return serialService.getConnections().then(function(connections) {
    for (var entry of connections) {
      var connection = entry[1];
      addEventListeners(connection, entry[0]);
      connection.resumeReceives();
    };
  });
});

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;
  apiFunctions.setHandleRequestWithPromise('getDevices', function() {
    return serialServicePromise.then(function(serialService) {
      return serialService.getDevices();
    });
  });

  apiFunctions.setHandleRequestWithPromise('connect', function(path, options) {
    return serialServicePromise.then(function(serialService) {
      return serialService.createConnection(path, options);
    }).then(function(result) {
      addEventListeners(result.connection, result.info.connectionId);
      return result.info;
    }).catch (function(e) {
      throw new Error('Failed to connect to the port.');
    });
  });

  apiFunctions.setHandleRequestWithPromise(
      'disconnect', forwardToConnection('close'));
  apiFunctions.setHandleRequestWithPromise(
      'getInfo', forwardToConnection('getInfo'));
  apiFunctions.setHandleRequestWithPromise(
      'update', forwardToConnection('setOptions'));
  apiFunctions.setHandleRequestWithPromise(
      'getControlSignals', forwardToConnection('getControlSignals'));
  apiFunctions.setHandleRequestWithPromise(
      'setControlSignals', forwardToConnection('setControlSignals'));
  apiFunctions.setHandleRequestWithPromise(
      'flush', forwardToConnection('flush'));
  apiFunctions.setHandleRequestWithPromise(
      'setPaused', forwardToConnection('setPaused'));
  apiFunctions.setHandleRequestWithPromise(
      'send', forwardToConnection('send'));

  apiFunctions.setHandleRequestWithPromise('getConnections', function() {
    return serialServicePromise.then(function(serialService) {
      return serialService.getConnections();
    }).then(function(connections) {
      var promises = [];
      for (var connection of connections.values()) {
        promises.push(connection.getInfo());
      }
      return Promise.all(promises);
    });
  });
});

exports.$set('binding', binding.generate());