123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.CustomStatWatcher = exports.assertStatus = exports.Status = exports.Event = void 0;
- const tslib_1 = require("tslib");
- const events_1 = require("events");
- const statUtils = tslib_1.__importStar(require("../../statUtils"));
- var Event;
- (function (Event) {
- Event["Change"] = "change";
- Event["Stop"] = "stop";
- })(Event = exports.Event || (exports.Event = {}));
- var Status;
- (function (Status) {
- Status["Ready"] = "ready";
- Status["Running"] = "running";
- Status["Stopped"] = "stopped";
- })(Status = exports.Status || (exports.Status = {}));
- function assertStatus(current, expected) {
- if (current !== expected) {
- throw new Error(`Invalid StatWatcher status: expected '${expected}', got '${current}'`);
- }
- }
- exports.assertStatus = assertStatus;
- class CustomStatWatcher extends events_1.EventEmitter {
- static create(fakeFs, path, opts) {
- const statWatcher = new CustomStatWatcher(fakeFs, path, opts);
- statWatcher.start();
- return statWatcher;
- }
- constructor(fakeFs, path, { bigint = false } = {}) {
- super();
- this.status = Status.Ready;
- this.changeListeners = new Map();
- this.startTimeout = null;
- this.fakeFs = fakeFs;
- this.path = path;
- this.bigint = bigint;
- this.lastStats = this.stat();
- }
- start() {
- assertStatus(this.status, Status.Ready);
- this.status = Status.Running;
- // Node allows other listeners to be registered up to 3 milliseconds
- // after the watcher has been started, so that's what we're doing too
- this.startTimeout = setTimeout(() => {
- this.startTimeout = null;
- // Per the Node FS docs:
- // "When an fs.watchFile operation results in an ENOENT error,
- // it will invoke the listener once, with all the fields zeroed
- // (or, for dates, the Unix Epoch)."
- if (!this.fakeFs.existsSync(this.path)) {
- this.emit(Event.Change, this.lastStats, this.lastStats);
- }
- }, 3);
- }
- stop() {
- assertStatus(this.status, Status.Running);
- this.status = Status.Stopped;
- if (this.startTimeout !== null) {
- clearTimeout(this.startTimeout);
- this.startTimeout = null;
- }
- this.emit(Event.Stop);
- }
- stat() {
- try {
- return this.fakeFs.statSync(this.path, { bigint: this.bigint });
- }
- catch (error) {
- // From observation, all errors seem to be mostly ignored by Node.
- // Checked with ENOENT, ENOTDIR, EPERM
- const statInstance = this.bigint
- ? new statUtils.BigIntStatsEntry()
- : new statUtils.StatEntry();
- return statUtils.clearStats(statInstance);
- }
- }
- /**
- * Creates an interval whose callback compares the current stats with the previous stats and notifies all listeners in case of changes.
- *
- * @param opts.persistent Decides whether the interval should be immediately unref-ed.
- */
- makeInterval(opts) {
- const interval = setInterval(() => {
- const currentStats = this.stat();
- const previousStats = this.lastStats;
- if (statUtils.areStatsEqual(currentStats, previousStats))
- return;
- this.lastStats = currentStats;
- this.emit(Event.Change, currentStats, previousStats);
- }, opts.interval);
- return opts.persistent ? interval : interval.unref();
- }
- /**
- * Registers a listener and assigns it an interval.
- */
- registerChangeListener(listener, opts) {
- this.addListener(Event.Change, listener);
- this.changeListeners.set(listener, this.makeInterval(opts));
- }
- /**
- * Unregisters the listener and clears the assigned interval.
- */
- unregisterChangeListener(listener) {
- this.removeListener(Event.Change, listener);
- const interval = this.changeListeners.get(listener);
- if (typeof interval !== `undefined`)
- clearInterval(interval);
- this.changeListeners.delete(listener);
- }
- /**
- * Unregisters all listeners and clears all assigned intervals.
- */
- unregisterAllChangeListeners() {
- for (const listener of this.changeListeners.keys()) {
- this.unregisterChangeListener(listener);
- }
- }
- hasChangeListeners() {
- return this.changeListeners.size > 0;
- }
- /**
- * Refs all stored intervals.
- */
- ref() {
- for (const interval of this.changeListeners.values())
- interval.ref();
- return this;
- }
- /**
- * Unrefs all stored intervals.
- */
- unref() {
- for (const interval of this.changeListeners.values())
- interval.unref();
- return this;
- }
- }
- exports.CustomStatWatcher = CustomStatWatcher;
|