ableton-js 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,8 +4,23 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [v3.1.2](https://github.com/leolabs/ableton.js/compare/v3.1.1...v3.1.2)
8
+
9
+ - :sparkles: Keep a handle to the client port file open for faster read performance [`2a0295d`](https://github.com/leolabs/ableton.js/commit/2a0295dff3022e3812c2a0f6077ffb7bdcd00bf0)
10
+ - :sparkles: Try re-using the previous port for a quicker reconnect [`5c77760`](https://github.com/leolabs/ableton.js/commit/5c777606ce97295429dcac1a5685a34c8aa5abe3)
11
+ - :bug: Fix double disconnect/connect event [`2f960be`](https://github.com/leolabs/ableton.js/commit/2f960be4c6d18b2668d15258914cd3b763be0f4a)
12
+
13
+ #### [v3.1.1](https://github.com/leolabs/ableton.js/compare/v3.1.0...v3.1.1)
14
+
15
+ > 25 February 2023
16
+
17
+ - :loud_sound: Log connect and disconnect events [`e69f610`](https://github.com/leolabs/ableton.js/commit/e69f61098d61fd4027db4e94aad8155db5dbb504)
18
+ - :bug: Don't count a failed ping as a successful connection event [`217e91e`](https://github.com/leolabs/ableton.js/commit/217e91ed936326c29a391ace9dcbe831125f4fa2)
19
+
7
20
  #### [v3.1.0](https://github.com/leolabs/ableton.js/compare/v3.0.1...v3.1.0)
8
21
 
22
+ > 25 February 2023
23
+
9
24
  - :art: Extract connect and disconnect handlers into separate functions [`955a6cb`](https://github.com/leolabs/ableton.js/commit/955a6cbf132a38c6616e5e61cb8304507557d32f)
10
25
  - :sparkles: Add a `waitForConnection` function that returns a Promise that resolves when Live is connected [`3323d3d`](https://github.com/leolabs/ableton.js/commit/3323d3dba256fe86eeb85c0c6931de73337f4369)
11
26
  - :sparkles: Try a ping request in addition to waiting for the connection event [`c019e68`](https://github.com/leolabs/ableton.js/commit/c019e68b7e9744698e331b9d1fcad92b520d1a95)
package/index.d.ts CHANGED
@@ -63,6 +63,7 @@ export declare class Ableton extends EventEmitter implements ConnectionEventEmit
63
63
  private serverPortFile;
64
64
  private logger;
65
65
  private clientState;
66
+ private cancelDisconnectEvent;
66
67
  constructor(options?: AbletonOptions | undefined);
67
68
  private handleConnect;
68
69
  private handleDisconnect;
package/index.js CHANGED
@@ -132,6 +132,7 @@ var Ableton = /** @class */ (function (_super) {
132
132
  _this.internal = new internal_1.Internal(_this);
133
133
  _this.midi = new midi_1.Midi(_this);
134
134
  _this.clientState = "closed";
135
+ _this.cancelDisconnectEvent = false;
135
136
  _this.logger = options === null || options === void 0 ? void 0 : options.logger;
136
137
  _this.cache = new lru_cache_1.default(__assign({ max: 500, ttl: 1000 * 60 * 10 }, options === null || options === void 0 ? void 0 : options.cacheOptions));
137
138
  _this.clientPortFile = path_1.default.join(os_1.default.tmpdir(), (_b = (_a = _this.options) === null || _a === void 0 ? void 0 : _a.clientPortFile) !== null && _b !== void 0 ? _b : CLIENT_PORT_FILE);
@@ -139,17 +140,21 @@ var Ableton = /** @class */ (function (_super) {
139
140
  return _this;
140
141
  }
141
142
  Ableton.prototype.handleConnect = function (type) {
143
+ var _a;
142
144
  if (!this._isConnected) {
143
145
  this._isConnected = true;
146
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info("Live connected", { type: type });
144
147
  this.emit("connect", type);
145
148
  }
146
149
  };
147
150
  Ableton.prototype.handleDisconnect = function (type) {
151
+ var _a;
148
152
  if (this._isConnected) {
149
153
  this._isConnected = false;
150
154
  this.eventListeners.clear();
151
155
  this.msgMap.forEach(function (msg) { return msg.clearTimeout(); });
152
156
  this.msgMap.clear();
157
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info("Live disconnected", { type: type });
153
158
  this.emit("disconnect", type);
154
159
  }
155
160
  };
@@ -167,7 +172,7 @@ var Ableton = /** @class */ (function (_super) {
167
172
  else {
168
173
  return [2 /*return*/, Promise.race([
169
174
  new Promise(function (res) { return _this.once("connect", res); }),
170
- this.internal.get("ping").catch(function () { }),
175
+ this.internal.get("ping").catch(function () { return new Promise(function () { }); }),
171
176
  ])];
172
177
  }
173
178
  return [2 /*return*/];
@@ -286,17 +291,22 @@ var Ableton = /** @class */ (function (_super) {
286
291
  return __generator(this, function (_a) {
287
292
  switch (_a.label) {
288
293
  case 0:
289
- _a.trys.push([0, 2, , 3]);
294
+ _a.trys.push([0, 2, 3, 4]);
290
295
  return [4 /*yield*/, this.internal.get("ping")];
291
296
  case 1:
292
297
  _a.sent();
293
298
  this.handleConnect("heartbeat");
294
- return [3 /*break*/, 3];
299
+ return [3 /*break*/, 4];
295
300
  case 2:
296
301
  e_2 = _a.sent();
297
- this.handleDisconnect("heartbeat");
298
- return [3 /*break*/, 3];
299
- case 3: return [2 /*return*/];
302
+ if (!this.cancelDisconnectEvent) {
303
+ this.handleDisconnect("heartbeat");
304
+ }
305
+ return [3 /*break*/, 4];
306
+ case 3:
307
+ this.cancelDisconnectEvent = false;
308
+ return [7 /*endfinally*/];
309
+ case 4: return [2 /*return*/];
300
310
  }
301
311
  });
302
312
  }); };
@@ -391,6 +401,9 @@ var Ableton = /** @class */ (function (_super) {
391
401
  return this.handleDisconnect("realtime");
392
402
  }
393
403
  if (data.event === "connect") {
404
+ // If some heartbeat ping from the old connection is still pending,
405
+ // cancel it to prevent a double disconnect/connect event.
406
+ this.cancelDisconnectEvent = true;
394
407
  if (data.data.port && data.data.port !== this.serverPort) {
395
408
  (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info("Got new server port via connect:", {
396
409
  port: data.data.port,
@@ -13,4 +13,4 @@ class Internal(Interface):
13
13
  return True
14
14
 
15
15
  def get_version(self, ns):
16
- return "3.1.0"
16
+ return "3.1.2"
@@ -37,48 +37,79 @@ class Socket(object):
37
37
  self.input_handler = handler
38
38
  self._server_addr = ('127.0.0.1', 0)
39
39
  self._client_addr = ('127.0.0.1', 39031)
40
+ self.remote_port_file = None
40
41
  self.read_remote_port()
41
42
  self.init_socket()
42
43
 
44
+ def read_last_server_port(self):
45
+ try:
46
+ with open(server_port_path) as file:
47
+ port = int(file.read())
48
+
49
+ self.log_message("Stored server port: " + str(port))
50
+ return port
51
+ except Exception as e:
52
+ self.log_message(
53
+ "Couldn't read stored server port: " + str(e.args))
54
+ return None
55
+
43
56
  def read_remote_port(self):
44
57
  '''Reads the port our client is listening on'''
45
58
  try:
46
- with open(client_port_path) as file:
47
- port = int(file.read())
48
- if port != self._client_addr[1]:
49
- self.log_message("Client port changed: " + str(port))
50
- self._client_addr = ('127.0.0.1', port)
59
+ if self.remote_port_file == None or self.remote_port_file.closed:
60
+ self.log_message("Opening remote port file...")
61
+ self.remote_port_file = open(client_port_path)
62
+
63
+ self.remote_port_file.seek(0)
64
+ port = int(self.remote_port_file.read())
65
+
66
+ if port != self._client_addr[1]:
67
+ self.log_message("Client port changed: " + str(port))
68
+ self._client_addr = ('127.0.0.1', port)
51
69
 
52
- if hasattr(self, "_socket"):
53
- self.send("connect", {"port": self._server_addr[1]})
70
+ if hasattr(self, "_socket"):
71
+ self.send("connect", {"port": self._server_addr[1]})
54
72
  except Exception as e:
55
73
  self.log_message("Couldn't read remote port:", str(e.args))
74
+ if self.remote_port_file:
75
+ self.remote_port_file.close()
56
76
 
57
- t = Timer(1, self.read_remote_port)
58
- t.start()
77
+ Timer(1, self.read_remote_port).start()
59
78
 
60
79
  def init_socket(self):
61
80
  self._socket = socket.socket(
62
81
  socket.AF_INET, socket.SOCK_DGRAM)
63
82
  self._socket.setblocking(0)
64
83
 
65
- self.bind()
84
+ self.bind(True)
66
85
 
67
86
  def shutdown(self):
68
87
  self._socket.close()
88
+ if self.remote_port_file:
89
+ self.remote_port_file.close()
69
90
 
70
- def bind(self):
91
+ def bind(self, try_stored=False):
71
92
  try:
93
+ stored_port = self.read_last_server_port()
94
+
95
+ # Try the port we used last time first
96
+ if try_stored and stored_port:
97
+ self._server_addr = ("127.0.0.1", stored_port)
98
+ else:
99
+ self._server_addr = ("127.0.0.1", 0)
100
+
72
101
  self._socket.bind(self._server_addr)
73
102
  port = self._socket.getsockname()[1]
74
103
 
75
104
  # Write the chosen port to a file
76
- with open(server_port_path, "w") as file:
77
- file.write(str(port))
105
+ if stored_port != port:
106
+ with open(server_port_path, "w") as file:
107
+ file.write(str(port))
78
108
 
79
109
  self.send("connect", {"port": port})
110
+ self.show_message("Started server on port " + str(port))
80
111
 
81
- self.log_message('Starting on: ' + str(self._socket.getsockname()) +
112
+ self.log_message('Started on: ' + str(self._socket.getsockname()) +
82
113
  ', remote addr: ' + str(self._client_addr))
83
114
  except Exception as e:
84
115
  msg = 'ERROR: Cannot bind to ' + \
@@ -117,8 +148,10 @@ class Socket(object):
117
148
  {"event": name, "data": obj, "uuid": uuid}, default=jsonReplace, ensure_ascii=False))
118
149
  except socket.error as e:
119
150
  self.log_message("Socket error: " + str(e.args))
151
+ self.log_message("Server: " + str(self._server_addr) +
152
+ ", client: " + str(self._client_addr))
120
153
  self.log_message("Restarting socket...")
121
- self.shutdown()
154
+ self._socket.close()
122
155
  self.init_socket()
123
156
  except Exception as e:
124
157
  error = str(type(e).__name__) + ': ' + str(e.args)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ableton-js",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Control Ableton Live from Node",
5
5
  "main": "index.js",
6
6
  "author": "Leo Bernard <admin@leolabs.org>",