@toit/esptool.js
Version:
TypeScript port of the esptool
204 lines • 6.21 kB
JavaScript
"use strict";
// Copyright (C) 2021 Toitware ApS. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.
Object.defineProperty(exports, "__esModule", { value: true });
exports.Completer = exports.Reader = void 0;
const errors_1 = require("./errors");
const util_1 = require("./util");
class Reader {
constructor(readableOwner) {
this.running = false;
this.closing = false;
this.reader = undefined;
this.completer = undefined;
this.runPromise = undefined;
this.listenRef = 0;
this.buffer = new util_1.Uint8Buffer();
this.readableOwner = readableOwner;
}
start() {
if (this.runPromise !== undefined) {
throw errors_1.AlreadyRunningError;
}
this.buffer.reset();
this.closing = false;
this.runPromise = this.run();
}
async stop() {
if (this.runPromise === undefined) {
throw errors_1.NotRunningError;
}
this.closing = true;
if (this.reader !== undefined) {
try {
await this.reader.cancel();
}
catch (e) { }
}
try {
await this.runPromise;
return undefined;
}
catch (e) {
return e;
}
finally {
this.buffer.reset();
this.runPromise = undefined;
}
}
async run() {
try {
this.running = true;
while (!this.closing) {
if (this.reader === undefined) {
this.reader = this.readableOwner.readable.getReader();
}
const reader = this.reader;
try {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
this.reader = undefined;
await (0, util_1.sleep)(1);
continue;
}
if (!value) {
continue;
}
if (this.listenRef > 0) {
this.buffer.copy(value);
}
if (this.completer !== undefined) {
this.completer.complete();
}
}
catch (e) {
if (!(0, util_1.isTransientError)(e)) {
throw e;
}
// on a transient error, close the current reader and retry.
try {
await reader.cancel();
}
catch (e) { }
reader.releaseLock();
this.reader = undefined;
await (0, util_1.sleep)(1);
}
}
}
finally {
if (this.reader !== undefined) {
try {
await this.reader.cancel();
}
catch (e) { }
this.reader.releaseLock();
this.reader = undefined;
}
this.running = false;
}
}
listen() {
if (!this.running) {
throw errors_1.NotRunningError;
}
this.listenRef++;
return () => {
this.listenRef--;
if (this.listenRef < 0) {
throw "Listen ref count is negative";
}
if (this.listenRef == 0) {
this.buffer.reset();
}
};
}
async waitData(minLength, timeoutMs = undefined) {
if (!this.running) {
throw errors_1.NotRunningError;
}
if (this.completer !== undefined) {
throw errors_1.ReadAlreadyInProgressError;
}
while (this.buffer.length < minLength) {
this.completer = new Completer(timeoutMs);
try {
await this.completer.promise;
}
finally {
this.completer = undefined;
}
}
}
async waitSilent(retry, timeoutMs) {
while (retry--) {
this.buffer.reset();
try {
await this.waitData(1, timeoutMs);
}
catch (e) {
if (e === errors_1.TimeoutError) {
return true;
}
throw e;
}
await (0, util_1.sleep)(50);
}
return false;
}
async read(minLength, timeoutMs) {
if (this.listenRef <= 0) {
throw errors_1.NotListeningError;
}
await this.waitData(minLength, timeoutMs);
return this.buffer.view(true);
}
async packet(minLength, timeoutMs) {
if (this.listenRef <= 0) {
throw errors_1.NotListeningError;
}
let maxRetries = 1000;
while (maxRetries--) {
await this.waitData(minLength, timeoutMs);
const res = this.buffer.packet();
if (res !== undefined) {
return res;
}
// no packet was available in minLength, so we wait for another byte.
minLength++;
}
throw errors_1.TimeoutError;
}
}
exports.Reader = Reader;
class Completer {
constructor(timeoutMs = undefined) {
this.promise = new Promise((resolve, reject) => {
this._complete = resolve;
this._reject = reject;
if (timeoutMs !== undefined) {
if (timeoutMs > 0) {
setTimeout(() => reject(errors_1.TimeoutError), timeoutMs);
}
else {
reject(errors_1.TimeoutError);
}
}
});
}
complete(value) {
if (this._complete !== undefined) {
this._complete(value);
}
}
reject(reason) {
if (this._reject !== undefined) {
this._reject(reason);
}
}
}
exports.Completer = Completer;
//# sourceMappingURL=reader.js.map