Socket
Socket
Sign inDemoInstall

file-timestamp-stream

Package Overview
Dependencies
15
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0 to 1.1.0

4

CHANGELOG.md
# Changelog
## v1.1.0 2018-09-12
* Clean up streams more carefully after they are not needed anymore.
## v1.0.0 2018-09-07

@@ -4,0 +8,0 @@

6

lib/file-timestamp-stream.d.ts

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

newFilename: (fileTimestampStream: FileTimestampStream) => string;
private streamErrorHandler;
private streams;
private streamCancelFinishers;
private streamErrorHandlers;
constructor(options?: FileTimestampStreamOptions);
_rotate(): void;
_write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;

@@ -28,3 +29,4 @@ _writev(chunks: Array<{

_destroy(error: Error | null, callback: (error: Error | null) => void): void;
private rotate;
}
export default FileTimestampStream;

@@ -8,5 +8,12 @@ "use strict";

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 {
constructor(options = {}) {
super(options);
this.streams = new Map();
this.streamCancelFinishers = new Map();
this.streamErrorHandlers = new Map();
this.newFilename = options.newFilename || defaultNewFilename;

@@ -16,23 +23,6 @@ this.flags = options.flags || 'a';

this.path = options.path || 'out.log';
this.streamErrorHandler = (err) => {
this.emit('error', err);
};
}
_rotate() {
const newFilename = this.newFilename(this);
if (newFilename !== this.currentFilename) {
if (this.stream) {
this.stream.end();
this.stream.removeListener('error', this.streamErrorHandler);
}
this.stream = this.fs.createWriteStream(newFilename, {
flags: this.flags
});
this.stream.on('error', this.streamErrorHandler);
this.currentFilename = newFilename;
}
}
_write(chunk, encoding, callback) {
try {
this._rotate();
this.rotate();
this.stream.write(chunk, encoding, callback);

@@ -47,3 +37,3 @@ }

try {
this._rotate();
this.rotate();
corked = true;

@@ -73,8 +63,27 @@ this.stream.cork();

_destroy(error, callback) {
if (this.stream) {
this.stream.destroy();
this.stream.removeListener('error', this.streamErrorHandler);
delete this.streamErrorHandler;
delete this.stream;
if (this.streamErrorHandlers.size > 0) {
this.streamErrorHandlers.forEach((handler, filename) => {
const stream = this.streams.get(filename);
if (stream) {
stream.removeListener('error', handler);
}
});
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.streams.size > 0) {
this.streams.forEach((stream) => {
stream.destroy();
});
this.streams.clear();
}
this.stream = undefined;
this.newFilename = (_fileTimestampStream) => {

@@ -85,2 +94,37 @@ throw new Error('write after destroy');

}
rotate() {
const newFilename = this.newFilename(this);
if (newFilename !== this.currentFilename) {
if (this.currentFilename && this.stream) {
this.stream.end();
const streamErrorHandler = this.streamErrorHandlers.get(this.currentFilename);
if (streamErrorHandler) {
this.stream.removeListener('error', streamErrorHandler);
this.streamErrorHandlers.delete(this.currentFilename);
}
if (!HAS_DESTROY) {
this.streams.delete(this.currentFilename);
}
}
const newStream = this.fs.createWriteStream(newFilename, {
flags: this.flags
});
this.stream = newStream;
this.streams.set(newFilename, newStream);
const newStreamErrorHandler = (err) => {
this.emit('error', err);
};
newStream.on('error', newStreamErrorHandler);
this.streamErrorHandlers.set(newFilename, newStreamErrorHandler);
if (HAS_DESTROY) {
const newStreamCancelFinisher = finished(newStream, () => {
newStream.destroy();
this.streamCancelFinishers.delete(newFilename);
this.streams.delete(newFilename);
});
this.streamCancelFinishers.set(newFilename, newStreamCancelFinisher);
}
this.currentFilename = newFilename;
}
}
}

@@ -87,0 +131,0 @@ exports.FileTimestampStream = FileTimestampStream;

{
"name": "file-timestamp-stream",
"version": "1.0.0",
"version": "1.1.0",
"description": "Writing stream with file rotating based on timestamp",

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

"dependencies": {
"stream.finished": "^1.0.1",
"tslib": "^1.9.3",

@@ -36,2 +37,3 @@ "ultra-strftime": "^1.0.2"

"chai": "^4.1.2",
"coveralls": "^3.0.2",
"eslint": "^5.5.0",

@@ -56,3 +58,3 @@ "eslint-config-standard": "^12.0.0",

"prepublishOnly": "npm run build",
"pretest": "npm run build && eslint . && tslint -t stylish -p . && markdownlint \"*.md\"",
"pretest": "npm run build && tsc --pretty -p examples && tsc --pretty -p test && eslint . && tslint -t stylish -p . && tslint -t stylish -p examples && tslint -t stylish -p test && markdownlint \"*.md\"",
"test": "npm run test:spec",

@@ -68,2 +70,3 @@ "test:spec": "npm run ts-mocha -- \"test/*.ts\"",

"exclude": [
".*.js",
"**/*.d.ts"

@@ -70,0 +73,0 @@ ]

@@ -27,2 +27,14 @@ # file-timestamp-stream

Transpiling this module with own settings in `tsconfig.json`:
```json
{
"compilerOptions": {
"paths": {
"file-timestamp-stream": ["node_modules/file-timestamp-stream/src/file-timestamp-stream"]
}
}
}
```
## Usage

@@ -42,14 +54,2 @@

Transpiling this module with own settings in `tsconfig.json`:
```json
{
"compilerOptions": {
"paths": {
"file-timestamp-stream": ["node_modules/file-timestamp-stream/src/file-timestamp-stream"]
}
}
}
```
### Options

@@ -56,0 +56,0 @@

@@ -7,2 +7,8 @@ /// <reference types="node" />

// tslint:disable-next-line:no-var-requires
const finished = require('stream.finished') as (stream: NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream, callback?: (err: NodeJS.ErrnoException) => void) => () => void // TODO: wait for new typings for node
// tslint:disable-next-line:strict-type-predicates
const HAS_DESTROY = typeof Writable.prototype.destroy === 'function'
export interface FileTimestampStreamOptions extends WritableOptions {

@@ -24,3 +30,5 @@ flags?: string | null

private streamErrorHandler: (err: Error) => void
private streams: Map<string, Writable> = new Map()
private streamCancelFinishers: Map<string, () => void> = new Map()
private streamErrorHandlers: Map<string, (err: Error) => void> = new Map()

@@ -35,30 +43,7 @@ constructor (options: FileTimestampStreamOptions = {}) {

this.path = options.path || 'out.log'
this.streamErrorHandler = (err) => {
this.emit('error', err)
}
}
_rotate (): void {
const newFilename = this.newFilename(this)
if (newFilename !== this.currentFilename) {
if (this.stream) {
this.stream.end()
this.stream.removeListener('error', this.streamErrorHandler)
}
this.stream = this.fs.createWriteStream(newFilename, {
flags: this.flags
})
this.stream.on('error', this.streamErrorHandler)
this.currentFilename = newFilename
}
}
_write (chunk: any, encoding: string, callback: (error?: Error | null) => void): void {
try {
this._rotate()
this.rotate()
this.stream!.write(chunk, encoding, callback)

@@ -73,3 +58,3 @@ } catch (e) {

try {
this._rotate()
this.rotate()
corked = true

@@ -99,13 +84,76 @@ this.stream!.cork()

_destroy (error: Error | null, callback: (error: Error | null) => void): void {
if (this.stream) {
this.stream.destroy()
this.stream.removeListener('error', this.streamErrorHandler)
delete this.streamErrorHandler
delete this.stream
if (this.streamErrorHandlers.size > 0) {
this.streamErrorHandlers.forEach((handler, filename) => {
const stream = this.streams.get(filename)
if (stream) {
stream.removeListener('error', handler)
}
})
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.streams.size > 0) {
this.streams.forEach((stream) => {
stream.destroy()
})
this.streams.clear()
}
this.stream = undefined
this.newFilename = (_fileTimestampStream: any) => {
throw new Error('write after destroy')
}
callback(error)
}
private rotate (): void {
const newFilename = this.newFilename(this)
if (newFilename !== this.currentFilename) {
if (this.currentFilename && this.stream) {
this.stream.end()
const streamErrorHandler = this.streamErrorHandlers.get(this.currentFilename)
if (streamErrorHandler) {
this.stream.removeListener('error', streamErrorHandler)
this.streamErrorHandlers.delete(this.currentFilename)
}
if (!HAS_DESTROY) {
this.streams.delete(this.currentFilename)
}
}
const newStream = this.fs.createWriteStream(newFilename, {
flags: this.flags
})
this.stream = newStream
this.streams.set(newFilename, newStream)
const newStreamErrorHandler = (err: Error) => {
this.emit('error', err)
}
newStream.on('error', newStreamErrorHandler)
this.streamErrorHandlers.set(newFilename, newStreamErrorHandler)
if (HAS_DESTROY) {
const newStreamCancelFinisher = finished(newStream, () => {
newStream.destroy()
this.streamCancelFinishers.delete(newFilename)
this.streams.delete(newFilename)
})
this.streamCancelFinishers.set(newFilename, newStreamCancelFinisher)
}
this.currentFilename = newFilename
}
}
}

@@ -112,0 +160,0 @@

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