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 +15 -0
- package/index.d.ts +1 -0
- package/index.js +19 -6
- package/midi-script/Internal.py +1 -1
- package/midi-script/Socket.py +48 -15
- package/package.json +1 -1
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, ,
|
|
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*/,
|
|
299
|
+
return [3 /*break*/, 4];
|
|
295
300
|
case 2:
|
|
296
301
|
e_2 = _a.sent();
|
|
297
|
-
this.
|
|
298
|
-
|
|
299
|
-
|
|
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,
|
package/midi-script/Internal.py
CHANGED
package/midi-script/Socket.py
CHANGED
|
@@ -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
|
-
|
|
47
|
-
port
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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('
|
|
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.
|
|
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)
|