Socket
Socket
Sign inDemoInstall

file-timestamp-stream

Package Overview
Dependencies
16
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0 to 2.1.0

5

CHANGELOG.md
# Changelog
## v2.1.0 2018-09-17
* Close file if its file name is already changed even if there is no new data
written: this check is made by interval timer.
## v2.0.0 2018-09-14

@@ -4,0 +9,0 @@

15

lib/file-timestamp-stream.d.ts

@@ -5,11 +5,17 @@ /// <reference types="node" />

export interface FileTimestampStreamOptions extends WritableOptions {
/** a string with [flags](https://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback) for opened stream (default: `'a'`) */
flags?: string | null;
/** a custom [fs](https://nodejs.org/api/fs.html) module (optional) */
fs?: typeof fs;
/** a template for new filenames (default: `'out.log'`) */
path?: string;
}
export declare class FileTimestampStream extends Writable {
static readonly CLOSE_UNUSED_FILE_AFTER: number;
readonly flags: string;
readonly fs: typeof fs;
readonly path: string;
/** contains last opened filename */
protected currentFilename?: string;
/** contains current [fs.WriteStream](https://nodejs.org/api/fs.html#fs_class_fs_writestream) object */
protected stream?: WriteStream;

@@ -20,2 +26,4 @@ private destroyed;

private streamErrorHandlers;
private closer?;
private closers;
constructor(options?: FileTimestampStreamOptions);

@@ -29,3 +37,8 @@ _write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;

_destroy(error: Error | null, callback: (error: Error | null) => void): void;
/** Override this */
/**
* This method can be overriden in subclass
*
* The method generates a filename for new files. By default it returns new
* filename based on path and current time.
*/
protected newFilename(): string;

@@ -32,0 +45,0 @@ private rotate;

85

lib/file-timestamp-stream.js

@@ -7,7 +7,6 @@ "use strict";

const stream_1 = require("stream");
const timers_obj_1 = require("timers-obj");
const ultra_strftime_1 = tslib_1.__importDefault(require("ultra-strftime"));
// tslint:disable-next-line:no-var-requires
const finished = require('stream.finished'); // TODO: wait for new typings for node
// tslint:disable-next-line:strict-type-predicates
const HAS_DESTROY = typeof stream_1.Writable.prototype.destroy === 'function';
class FileTimestampStream extends stream_1.Writable {

@@ -20,2 +19,3 @@ constructor(options = {}) {

this.streamErrorHandlers = new Map();
this.closers = new Map();
this.flags = options.flags || 'a';

@@ -69,3 +69,3 @@ this.fs = options.fs || fs_1.default;

if (this.streamErrorHandlers.size > 0) {
this.streamErrorHandlers.forEach((handler, filename) => {
for (const [filename, handler] of this.streamErrorHandlers) {
const stream = this.streams.get(filename);

@@ -75,27 +75,38 @@ if (stream) {

}
});
}
this.streamErrorHandlers.clear();
}
if (HAS_DESTROY) {
if (this.streamCancelFinishers.size > 0) {
this.streamCancelFinishers.forEach((cancel, filename) => {
cancel();
this.streamCancelFinishers.delete(filename);
});
this.streamCancelFinishers.clear();
if (this.streamCancelFinishers.size > 0) {
for (const [filename, cancel] of this.streamCancelFinishers) {
cancel();
this.streamCancelFinishers.delete(filename);
}
this.streamCancelFinishers.clear();
}
if (this.streams.size > 0) {
if (HAS_DESTROY) {
this.streams.forEach((stream) => {
for (const stream of this.streams.values()) {
// tslint:disable-next-line:strict-type-predicates
if (typeof stream.destroy === 'function') {
stream.destroy();
});
}
}
this.streams.clear();
}
if (this.closers.size > 0) {
for (const timer of this.closers.values()) {
timer.remove();
}
this.streams.clear();
}
this.destroyed = true;
this.stream = undefined;
this.closer = undefined;
callback(error);
}
/** Override this */
/**
* This method can be overriden in subclass
*
* The method generates a filename for new files. By default it returns new
* filename based on path and current time.
*/
newFilename() {

@@ -106,13 +117,12 @@ return ultra_strftime_1.default(this.path, new Date());

const newFilename = this.newFilename();
if (newFilename !== this.currentFilename) {
if (this.currentFilename && this.stream) {
this.stream.close();
const streamErrorHandler = this.streamErrorHandlers.get(this.currentFilename);
const { currentFilename, stream, closer } = this;
if (newFilename !== currentFilename) {
if (currentFilename && stream && closer) {
closer.remove();
stream.end();
const streamErrorHandler = this.streamErrorHandlers.get(currentFilename);
if (streamErrorHandler) {
this.stream.removeListener('error', streamErrorHandler);
this.streamErrorHandlers.delete(this.currentFilename);
stream.removeListener('error', streamErrorHandler);
this.streamErrorHandlers.delete(currentFilename);
}
if (!HAS_DESTROY) {
this.streams.delete(this.currentFilename);
}
}

@@ -129,10 +139,22 @@ const newStream = this.fs.createWriteStream(newFilename, {

this.streamErrorHandlers.set(newFilename, newStreamErrorHandler);
if (HAS_DESTROY) {
const newStreamCancelFinisher = finished(newStream, () => {
const newTimer = timers_obj_1.interval(FileTimestampStream.CLOSE_UNUSED_FILE_AFTER, () => {
if (newFilename !== this.newFilename()) {
newTimer.remove();
this.closers.delete(newFilename);
newStream.end();
}
});
this.closer = closer;
this.closers.set(newFilename, newTimer);
const newStreamCancelFinisher = finished(newStream, () => {
newTimer.remove();
this.closers.delete(newFilename);
// tslint:disable-next-line:strict-type-predicates
if (typeof newStream.destroy === 'function') {
newStream.destroy();
this.streamCancelFinishers.delete(newFilename);
this.streams.delete(newFilename);
});
this.streamCancelFinishers.set(newFilename, newStreamCancelFinisher);
}
}
this.streamCancelFinishers.delete(newFilename);
this.streams.delete(newFilename);
});
this.streamCancelFinishers.set(newFilename, newStreamCancelFinisher);
this.currentFilename = newFilename;

@@ -142,3 +164,4 @@ }

}
FileTimestampStream.CLOSE_UNUSED_FILE_AFTER = 1000;
exports.FileTimestampStream = FileTimestampStream;
exports.default = FileTimestampStream;
{
"name": "file-timestamp-stream",
"version": "2.0.0",
"version": "2.1.0",
"description": "Writing stream with file rotating based on timestamp",

@@ -27,2 +27,3 @@ "main": "lib/file-timestamp-stream.js",

"stream.finished": "^1.0.1",
"timers-obj": "^0.2.1",
"tslib": "^1.9.3",

@@ -29,0 +30,0 @@ "ultra-strftime": "^1.0.2"

@@ -9,3 +9,4 @@ # file-timestamp-stream

[stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable)
to a file which is automatically rotated based on current time.
to a file which is automatically rotated based on current time and uses
[strftime](https://www.npmjs.com/package/strftime) template for file names.

@@ -115,3 +116,3 @@ ## Requirements

* `currentFilename` contains last opened filename
* `stream` contains
* `stream` contains current
[fs.WriteStream](https://nodejs.org/api/fs.html#fs_class_fs_writestream)

@@ -118,0 +119,0 @@ object

@@ -5,2 +5,3 @@ /// <reference types="node" />

import { Writable, WritableOptions } from 'stream'
import { interval, Interval } from 'timers-obj'
import strftime from 'ultra-strftime'

@@ -11,8 +12,8 @@

// tslint:disable-next-line:strict-type-predicates
const HAS_DESTROY = typeof Writable.prototype.destroy === 'function'
export interface FileTimestampStreamOptions extends WritableOptions {
/** a string with [flags](https://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback) for opened stream (default: `'a'`) */
flags?: string | null
/** a custom [fs](https://nodejs.org/api/fs.html) module (optional) */
fs?: typeof fs
/** a template for new filenames (default: `'out.log'`) */
path?: string

@@ -22,2 +23,4 @@ }

export class FileTimestampStream extends Writable {
static readonly CLOSE_UNUSED_FILE_AFTER = 1000
readonly flags: string

@@ -27,3 +30,5 @@ readonly fs: typeof fs

/** contains last opened filename */
protected currentFilename?: string
/** contains current [fs.WriteStream](https://nodejs.org/api/fs.html#fs_class_fs_writestream) object */
protected stream?: WriteStream

@@ -35,2 +40,4 @@

private streamErrorHandlers: Map<string, (err: Error) => void> = new Map()
private closer?: Interval
private closers: Map<string, Interval> = new Map()

@@ -91,3 +98,3 @@ constructor (options: FileTimestampStreamOptions = {}) {

if (this.streamErrorHandlers.size > 0) {
this.streamErrorHandlers.forEach((handler, filename) => {
for (const [filename, handler] of this.streamErrorHandlers) {
const stream = this.streams.get(filename)

@@ -97,25 +104,31 @@ if (stream) {

}
})
}
this.streamErrorHandlers.clear()
}
if (HAS_DESTROY) {
if (this.streamCancelFinishers.size > 0) {
this.streamCancelFinishers.forEach((cancel, filename) => {
cancel()
this.streamCancelFinishers.delete(filename)
})
this.streamCancelFinishers.clear()
if (this.streamCancelFinishers.size > 0) {
for (const [filename, cancel] of this.streamCancelFinishers) {
cancel()
this.streamCancelFinishers.delete(filename)
}
this.streamCancelFinishers.clear()
}
if (this.streams.size > 0) {
if (HAS_DESTROY) {
this.streams.forEach((stream) => {
for (const stream of this.streams.values()) {
// tslint:disable-next-line:strict-type-predicates
if (typeof stream.destroy === 'function') {
stream.destroy()
})
}
}
this.streams.clear()
}
if (this.closers.size > 0) {
for (const timer of this.closers.values()) {
timer.remove()
}
this.streams.clear()
}
this.destroyed = true
this.stream = undefined
this.closer = undefined

@@ -125,3 +138,8 @@ callback(error)

/** Override this */
/**
* This method can be overriden in subclass
*
* The method generates a filename for new files. By default it returns new
* filename based on path and current time.
*/
protected newFilename (): string {

@@ -133,14 +151,15 @@ return strftime(this.path, new Date())

const newFilename = this.newFilename()
const { currentFilename, stream, closer } = this
if (newFilename !== this.currentFilename) {
if (this.currentFilename && this.stream) {
this.stream.close()
const streamErrorHandler = this.streamErrorHandlers.get(this.currentFilename)
if (newFilename !== currentFilename) {
if (currentFilename && stream && closer) {
closer.remove()
stream.end()
const streamErrorHandler = this.streamErrorHandlers.get(currentFilename)
if (streamErrorHandler) {
this.stream.removeListener('error', streamErrorHandler)
this.streamErrorHandlers.delete(this.currentFilename)
stream.removeListener('error', streamErrorHandler)
this.streamErrorHandlers.delete(currentFilename)
}
if (!HAS_DESTROY) {
this.streams.delete(this.currentFilename)
}
}

@@ -160,10 +179,25 @@

if (HAS_DESTROY) {
const newStreamCancelFinisher = finished(newStream, () => {
const newTimer = interval(FileTimestampStream.CLOSE_UNUSED_FILE_AFTER, () => {
if (newFilename !== this.newFilename()) {
newTimer.remove()
this.closers.delete(newFilename)
newStream.end()
}
})
this.closer = closer
this.closers.set(newFilename, newTimer)
const newStreamCancelFinisher = finished(newStream, () => {
newTimer.remove()
this.closers.delete(newFilename)
// tslint:disable-next-line:strict-type-predicates
if (typeof newStream.destroy === 'function') {
newStream.destroy()
this.streamCancelFinishers.delete(newFilename)
this.streams.delete(newFilename)
})
this.streamCancelFinishers.set(newFilename, newStreamCancelFinisher)
}
}
this.streamCancelFinishers.delete(newFilename)
this.streams.delete(newFilename)
})
this.streamCancelFinishers.set(newFilename, newStreamCancelFinisher)

@@ -170,0 +204,0 @@ this.currentFilename = newFilename

@@ -10,3 +10,2 @@ {

"module": "commonjs",
"noImplicitAny": true,
"noImplicitReturns": true,

@@ -13,0 +12,0 @@ "noUnusedLocals": true,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc