Files: d2f2697f296dd39aed6a8b63c6d04a736a7db5b3 / node_modules / pull-file / index.js
3715 bytesRaw
1 | |
2 | /* jshint node: true */ |
3 | ; |
4 | |
5 | var fs = require('fs'); |
6 | var Decoder = require('pull-utf8-decoder') |
7 | /** |
8 | # pull-file |
9 | |
10 | This is a simple module which uses raw file reading methods available in |
11 | the node `fs` module to read files on-demand. It's a work in progress |
12 | and feedback is welcome :) |
13 | |
14 | ## Example Usage |
15 | |
16 | <<< examples/ipsum-chunks.js |
17 | |
18 | **/ |
19 | module.exports = function(filename, opts) { |
20 | var mode = opts && opts.mode || 0x1B6; // 0666 |
21 | var bufferSize = opts && (opts.bufferSize || (opts.buffer && opts.buffer.length)) || 1024*64; |
22 | var start = opts && opts.start || 0 |
23 | var end = opts && opts.end || Number.MAX_SAFE_INTEGER |
24 | var fd = opts && opts.fd |
25 | |
26 | var ended, closeNext, busy; |
27 | var _buffer = opts && opts.buffer || new Buffer(bufferSize) |
28 | var live = opts && !!opts.live |
29 | var liveCb, closeCb |
30 | var watcher |
31 | if(live) { |
32 | watcher = fs.watch(filename, { |
33 | persistent: opts.persistent !== false, |
34 | }, |
35 | function (event) { |
36 | if(liveCb && event === 'change') { |
37 | var cb = liveCb |
38 | liveCb = null |
39 | closeNext = false |
40 | readNext(cb) |
41 | } |
42 | }) |
43 | |
44 | } |
45 | |
46 | var flags = opts && opts.flags || 'r' |
47 | |
48 | function readNext(cb) { |
49 | if(closeNext) { |
50 | if(!live) close(cb); |
51 | else liveCb = cb; |
52 | return |
53 | } |
54 | var toRead = Math.min(end - start, bufferSize); |
55 | busy = true; |
56 | |
57 | fs.read( |
58 | fd, |
59 | _buffer, |
60 | 0, |
61 | toRead, |
62 | start, |
63 | function(err, count, buffer) { |
64 | busy = false; |
65 | start += count; |
66 | // if we have received an end noticiation, just discard this data |
67 | if(closeNext && !live) { |
68 | close(closeCb); |
69 | return cb(closeNext); |
70 | } |
71 | |
72 | if (ended) { |
73 | return cb(err || ended); |
74 | } |
75 | |
76 | // if we encountered a read error pass it on |
77 | if (err) { |
78 | return cb(err); |
79 | } |
80 | |
81 | if(count === buffer.length) { |
82 | cb(null, buffer); |
83 | } else if(count === 0 && live) { |
84 | liveCb = cb; closeNext = true |
85 | } else { |
86 | closeNext = true; |
87 | cb(null, buffer.slice(0, count)); |
88 | } |
89 | } |
90 | ); |
91 | _buffer = opts && opts.buffer || new Buffer(Math.min(end - start, bufferSize)) |
92 | } |
93 | |
94 | function open(cb) { |
95 | busy = true; |
96 | fs.open(filename, flags, mode, function(err, descriptor) { |
97 | // save the file descriptor |
98 | fd = descriptor; |
99 | |
100 | busy = false |
101 | if(closeNext) { |
102 | close(closeCb); |
103 | return cb(closeNext); |
104 | } |
105 | |
106 | if (err) { |
107 | return cb(err); |
108 | } |
109 | |
110 | // read the next bytes |
111 | return readNext(cb); |
112 | }); |
113 | } |
114 | |
115 | function close (cb) { |
116 | if(!cb) throw new Error('close must have cb') |
117 | if(watcher) watcher.close() |
118 | //if auto close is disabled, then user manages fd. |
119 | if(opts && opts.autoClose === false) return cb(true) |
120 | |
121 | //wait until we have got out of bed, then go back to bed. |
122 | //or if we are reading, wait till we read, then go back to bed. |
123 | else if(busy) { |
124 | closeCb = cb |
125 | return closeNext = true |
126 | } |
127 | |
128 | //first read was close, don't even get out of bed. |
129 | else if(!fd) { |
130 | return cb(true) |
131 | } |
132 | |
133 | //go back to bed |
134 | else { |
135 | fs.close(fd, function(err) { |
136 | fd = null; |
137 | cb(err || true); |
138 | }); |
139 | } |
140 | } |
141 | |
142 | function source (end, cb) { |
143 | if (end) { |
144 | ended = end; |
145 | live = false; |
146 | if(liveCb) { |
147 | liveCb(end || true); |
148 | } |
149 | close(cb); |
150 | } |
151 | // if we have already received the end notification, abort further |
152 | else if (ended) { |
153 | cb(ended); |
154 | } |
155 | |
156 | else if (! fd) { |
157 | open(cb); |
158 | } |
159 | |
160 | else |
161 | readNext(cb); |
162 | }; |
163 | |
164 | //read directly to text |
165 | if(opts && opts.encoding) |
166 | return Decoder(opts.encoding)(source) |
167 | |
168 | return source |
169 | |
170 | }; |
171 |
Built with git-ssb-web