-
Notifications
You must be signed in to change notification settings - Fork 8
/
index.js
125 lines (90 loc) · 2.62 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
var EventEmitter = require('eventemitter3');
var util =require('util');
var path =require('path');
var fs =require('fs');
// simple FIFO Queue for avoiding memory leak
function getCache (max) {
max = max || 1000;
var cache = {}, keys = [];
return {
set: function( key, value ) {
if ( keys.length > max ) delete cache[ keys.shift() ];
keys.push(key);
return (cache[key] = value);
},
get: function(key) {
return cache[key];
},
del: function(key){
var index = keys.indexOf( key );
if(~index){ keys.splice(index, 1) }
delete cache[key]
}
};
}
var FileStorm = function( filename ){
EventEmitter.call(this);
this.filename = path.resolve( filename );
this.status = FileStorm.IDLE;
this.pending = {
content: null,
callback: null,
options: null
}
}
util.inherits(FileStorm, EventEmitter);
var IDLE = 1;
var PENDING = 2;
var WRITING = 3;
var fo = FileStorm.prototype;
fo.write = function( content, options, callback ){
var filename = this.filename;
if( typeof options === 'function' ) {
callback = options;
options = 'utf8';
}
if( !options ) options = 'utf8';
var status = this.status;
var pending = this.pending;
var self = this;
if( status === PENDING || status === WRITING ){
if( pending.callback ) pending.callback(null, 0)
pending.content = content;
pending.callback = callback;
pending.options = options;
return this;
}
this.status = PENDING;
pending.content = content;
pending.callback = callback;
pending.options = options;
process.nextTick( function(){
var callback = pending.callback;
var content = pending.content;
// avoid call twice
pending.callback = null;
self.status = WRITING;
fs.writeFile( filename, typeof content === 'function'? content(): content, pending.options , function(err){
self.status = IDLE;
callback && callback(err, 1);
if(err) self.emit('error', err)
// after writeFile, you find the result is not the lastContent
if( content !== pending.content ){
self.write( pending.content, pending.options, pending.callback);
}else{
// TODO: we may need to notify developer when filewriter is over.
self.emit('end', content);
}
})
});
}
fo.destroy = function(){
cache.del(this.filename);
}
var cache = FileStorm.cache = getCache(1000);
module.exports = function (filename){
// make sure one file touch same pending
filename = path.resolve(filename);
return cache.get(filename) || cache.set(filename, new FileStorm(filename))
}
module.exports.FileStorm = FileStorm;