root / HServer / 00.Server / 00.Program / node_modules / fd-slicer / index.js
이력 | 보기 | 이력해설 | 다운로드 (6.97 KB)
1 | 39 | HKM | var fs = require('fs'); |
---|---|---|---|
2 | var util = require('util'); |
||
3 | var stream = require('stream'); |
||
4 | var Readable = stream.Readable;
|
||
5 | var Writable = stream.Writable;
|
||
6 | var PassThrough = stream.PassThrough;
|
||
7 | var Pend = require('pend'); |
||
8 | var EventEmitter = require('events').EventEmitter; |
||
9 | |||
10 | exports.createFromBuffer = createFromBuffer; |
||
11 | exports.createFromFd = createFromFd; |
||
12 | exports.BufferSlicer = BufferSlicer; |
||
13 | exports.FdSlicer = FdSlicer; |
||
14 | |||
15 | util.inherits(FdSlicer, EventEmitter); |
||
16 | function FdSlicer(fd, options) { |
||
17 | options = options || {}; |
||
18 | EventEmitter.call(this);
|
||
19 | |||
20 | this.fd = fd;
|
||
21 | this.pend = new Pend(); |
||
22 | this.pend.max = 1; |
||
23 | this.refCount = 0; |
||
24 | this.autoClose = !!options.autoClose;
|
||
25 | } |
||
26 | |||
27 | FdSlicer.prototype.read = function(buffer, offset, length, position, callback) { |
||
28 | var self = this; |
||
29 | self.pend.go(function(cb) {
|
||
30 | fs.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer) {
|
||
31 | cb(); |
||
32 | callback(err, bytesRead, buffer); |
||
33 | }); |
||
34 | }); |
||
35 | }; |
||
36 | |||
37 | FdSlicer.prototype.write = function(buffer, offset, length, position, callback) { |
||
38 | var self = this; |
||
39 | self.pend.go(function(cb) {
|
||
40 | fs.write(self.fd, buffer, offset, length, position, function(err, written, buffer) {
|
||
41 | cb(); |
||
42 | callback(err, written, buffer); |
||
43 | }); |
||
44 | }); |
||
45 | }; |
||
46 | |||
47 | FdSlicer.prototype.createReadStream = function(options) { |
||
48 | return new ReadStream(this, options); |
||
49 | }; |
||
50 | |||
51 | FdSlicer.prototype.createWriteStream = function(options) { |
||
52 | return new WriteStream(this, options); |
||
53 | }; |
||
54 | |||
55 | FdSlicer.prototype.ref = function() { |
||
56 | this.refCount += 1; |
||
57 | }; |
||
58 | |||
59 | FdSlicer.prototype.unref = function() { |
||
60 | var self = this; |
||
61 | self.refCount -= 1;
|
||
62 | |||
63 | if (self.refCount > 0) return; |
||
64 | if (self.refCount < 0) throw new Error("invalid unref"); |
||
65 | |||
66 | if (self.autoClose) {
|
||
67 | fs.close(self.fd, onCloseDone); |
||
68 | } |
||
69 | |||
70 | function onCloseDone(err) { |
||
71 | if (err) {
|
||
72 | self.emit('error', err);
|
||
73 | } else {
|
||
74 | self.emit('close');
|
||
75 | } |
||
76 | } |
||
77 | }; |
||
78 | |||
79 | util.inherits(ReadStream, Readable); |
||
80 | function ReadStream(context, options) { |
||
81 | options = options || {}; |
||
82 | Readable.call(this, options);
|
||
83 | |||
84 | this.context = context;
|
||
85 | this.context.ref();
|
||
86 | |||
87 | this.start = options.start || 0; |
||
88 | this.endOffset = options.end;
|
||
89 | this.pos = this.start; |
||
90 | this.destroyed = false; |
||
91 | } |
||
92 | |||
93 | ReadStream.prototype._read = function(n) { |
||
94 | var self = this; |
||
95 | if (self.destroyed) return; |
||
96 | |||
97 | var toRead = Math.min(self._readableState.highWaterMark, n);
|
||
98 | if (self.endOffset != null) { |
||
99 | toRead = Math.min(toRead, self.endOffset - self.pos); |
||
100 | } |
||
101 | if (toRead <= 0) { |
||
102 | self.destroyed = true;
|
||
103 | self.push(null);
|
||
104 | self.context.unref(); |
||
105 | return;
|
||
106 | } |
||
107 | self.context.pend.go(function(cb) {
|
||
108 | if (self.destroyed) return cb(); |
||
109 | var buffer = new Buffer(toRead); |
||
110 | fs.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) { |
||
111 | if (err) {
|
||
112 | self.destroy(err); |
||
113 | } else if (bytesRead === 0) { |
||
114 | self.destroyed = true;
|
||
115 | self.push(null);
|
||
116 | self.context.unref(); |
||
117 | } else {
|
||
118 | self.pos += bytesRead; |
||
119 | self.push(buffer.slice(0, bytesRead));
|
||
120 | } |
||
121 | cb(); |
||
122 | }); |
||
123 | }); |
||
124 | }; |
||
125 | |||
126 | ReadStream.prototype.destroy = function(err) { |
||
127 | if (this.destroyed) return; |
||
128 | err = err || new Error("stream destroyed"); |
||
129 | this.destroyed = true; |
||
130 | this.emit('error', err); |
||
131 | this.context.unref();
|
||
132 | }; |
||
133 | |||
134 | util.inherits(WriteStream, Writable); |
||
135 | function WriteStream(context, options) { |
||
136 | options = options || {}; |
||
137 | Writable.call(this, options);
|
||
138 | |||
139 | this.context = context;
|
||
140 | this.context.ref();
|
||
141 | |||
142 | this.start = options.start || 0; |
||
143 | this.endOffset = (options.end == null) ? Infinity : +options.end; |
||
144 | this.bytesWritten = 0; |
||
145 | this.pos = this.start; |
||
146 | this.destroyed = false; |
||
147 | |||
148 | this.on('finish', this.destroy.bind(this)); |
||
149 | } |
||
150 | |||
151 | WriteStream.prototype._write = function(buffer, encoding, callback) { |
||
152 | var self = this; |
||
153 | if (self.destroyed) return; |
||
154 | |||
155 | if (self.pos + buffer.length > self.endOffset) {
|
||
156 | var err = new Error("maximum file length exceeded"); |
||
157 | err.code = 'ETOOBIG';
|
||
158 | self.destroy(); |
||
159 | callback(err); |
||
160 | return;
|
||
161 | } |
||
162 | self.context.pend.go(function(cb) {
|
||
163 | if (self.destroyed) return cb(); |
||
164 | fs.write(self.context.fd, buffer, 0, buffer.length, self.pos, function(err, bytes) { |
||
165 | if (err) {
|
||
166 | self.destroy(); |
||
167 | cb(); |
||
168 | callback(err); |
||
169 | } else {
|
||
170 | self.bytesWritten += bytes; |
||
171 | self.pos += bytes; |
||
172 | self.emit('progress');
|
||
173 | cb(); |
||
174 | callback(); |
||
175 | } |
||
176 | }); |
||
177 | }); |
||
178 | }; |
||
179 | |||
180 | WriteStream.prototype.destroy = function() { |
||
181 | if (this.destroyed) return; |
||
182 | this.destroyed = true; |
||
183 | this.context.unref();
|
||
184 | }; |
||
185 | |||
186 | util.inherits(BufferSlicer, EventEmitter); |
||
187 | function BufferSlicer(buffer) { |
||
188 | EventEmitter.call(this);
|
||
189 | |||
190 | this.refCount = 0; |
||
191 | this.buffer = buffer;
|
||
192 | } |
||
193 | |||
194 | BufferSlicer.prototype.read = function(buffer, offset, length, position, callback) { |
||
195 | var end = position + length;
|
||
196 | var delta = end - this.buffer.length; |
||
197 | var written = (delta > 0) ? delta : length; |
||
198 | this.buffer.copy(buffer, offset, position, end);
|
||
199 | setImmediate(function() {
|
||
200 | callback(null, written);
|
||
201 | }); |
||
202 | }; |
||
203 | |||
204 | BufferSlicer.prototype.write = function(buffer, offset, length, position, callback) { |
||
205 | buffer.copy(this.buffer, position, offset, offset + length);
|
||
206 | setImmediate(function() {
|
||
207 | callback(null, length, buffer);
|
||
208 | }); |
||
209 | }; |
||
210 | |||
211 | BufferSlicer.prototype.createReadStream = function(options) { |
||
212 | options = options || {}; |
||
213 | var readStream = new PassThrough(options); |
||
214 | readStream.start = options.start || 0;
|
||
215 | readStream.endOffset = options.end; |
||
216 | readStream.pos = readStream.endOffset || this.buffer.length; // yep, we're already done |
||
217 | readStream.destroyed = false;
|
||
218 | readStream.write(this.buffer.slice(readStream.start, readStream.pos));
|
||
219 | readStream.end(); |
||
220 | readStream.destroy = function() { |
||
221 | readStream.destroyed = true;
|
||
222 | }; |
||
223 | return readStream;
|
||
224 | }; |
||
225 | |||
226 | BufferSlicer.prototype.createWriteStream = function(options) { |
||
227 | var bufferSlicer = this; |
||
228 | options = options || {}; |
||
229 | var writeStream = new Writable(options); |
||
230 | writeStream.start = options.start || 0;
|
||
231 | writeStream.endOffset = (options.end == null) ? this.buffer.length : +options.end; |
||
232 | writeStream.bytesWritten = 0;
|
||
233 | writeStream.pos = writeStream.start; |
||
234 | writeStream.destroyed = false;
|
||
235 | writeStream._write = function(buffer, encoding, callback) { |
||
236 | if (writeStream.destroyed) return; |
||
237 | |||
238 | var end = writeStream.pos + buffer.length;
|
||
239 | if (end > writeStream.endOffset) {
|
||
240 | var err = new Error("maximum file length exceeded"); |
||
241 | err.code = 'ETOOBIG';
|
||
242 | writeStream.destroyed = true;
|
||
243 | callback(err); |
||
244 | return;
|
||
245 | } |
||
246 | buffer.copy(bufferSlicer.buffer, writeStream.pos, 0, buffer.length);
|
||
247 | |||
248 | writeStream.bytesWritten += buffer.length; |
||
249 | writeStream.pos = end; |
||
250 | writeStream.emit('progress');
|
||
251 | callback(); |
||
252 | }; |
||
253 | writeStream.destroy = function() { |
||
254 | writeStream.destroyed = true;
|
||
255 | }; |
||
256 | return writeStream;
|
||
257 | }; |
||
258 | |||
259 | BufferSlicer.prototype.ref = function() { |
||
260 | this.refCount += 1; |
||
261 | }; |
||
262 | |||
263 | BufferSlicer.prototype.unref = function() { |
||
264 | this.refCount -= 1; |
||
265 | |||
266 | if (this.refCount < 0) { |
||
267 | throw new Error("invalid unref"); |
||
268 | } |
||
269 | }; |
||
270 | |||
271 | function createFromBuffer(buffer) { |
||
272 | return new BufferSlicer(buffer); |
||
273 | } |
||
274 | |||
275 | function createFromFd(fd, options) { |
||
276 | return new FdSlicer(fd, options); |
||
277 | } |