1 |
|
2 | "use strict";
|
3 |
|
4 | const assert = require('assert');
|
5 | const Mime = require('mime');
|
6 | const fs = require('fs');
|
7 | const Path = require('path');
|
8 | const Async = require('async');
|
9 | const debug = require('debug')('upnpserver:contentProviders:File');
|
10 | const crypto = require('crypto');
|
11 |
|
12 | const logger = require('../logger');
|
13 |
|
14 | const ContentProvider = require('./contentProvider');
|
15 |
|
16 | const DIRECTORY_MIME_TYPE = "inode/directory";
|
17 |
|
18 | const CHANGE_PATH_SEPARATOR = (Path.sep !== '/');
|
19 |
|
20 | const COMPUTE_HASH = false;
|
21 |
|
22 | class FileContentProvider extends ContentProvider {
|
23 |
|
24 | |
25 |
|
26 |
|
27 | get isLocalFilesystem() {
|
28 | return true;
|
29 | }
|
30 |
|
31 | |
32 |
|
33 |
|
34 | readdir(basePath, callback) {
|
35 |
|
36 | assert(typeof (basePath) === "string", "Base path is not a string (" +
|
37 | basePath + ")");
|
38 |
|
39 | var osPath = basePath;
|
40 | if (CHANGE_PATH_SEPARATOR) {
|
41 | osPath = osPath.replace(/\//g, Path.sep);
|
42 | }
|
43 |
|
44 | fs.readdir(osPath, (error, files) => {
|
45 | if (error) {
|
46 | return callback(error);
|
47 | }
|
48 |
|
49 | for (var i = 0; i < files.length; i++) {
|
50 | files[i] = this.newURL(basePath + '/' + files[i]);
|
51 | }
|
52 |
|
53 | debug("readdir", "returns basePath=", basePath, "=>", files);
|
54 |
|
55 | callback(null, files);
|
56 | });
|
57 | }
|
58 |
|
59 | |
60 |
|
61 |
|
62 | stat(path, callback) {
|
63 | var osPath = path;
|
64 | if (CHANGE_PATH_SEPARATOR) {
|
65 | osPath = osPath.replace(/\//g, Path.sep);
|
66 | }
|
67 |
|
68 | fs.stat(osPath, (error, stats) => {
|
69 | if (error) {
|
70 | return callback(error);
|
71 | }
|
72 |
|
73 | var reg=/\/([^\/]+)$/.exec(path);
|
74 | if (reg) {
|
75 | stats.name=reg[1];
|
76 | }
|
77 |
|
78 | if (stats.isDirectory()) {
|
79 | stats.mimeType = DIRECTORY_MIME_TYPE;
|
80 |
|
81 | return callback(null, stats);
|
82 | }
|
83 |
|
84 | var mimeType = Mime.lookup(path, "");
|
85 | stats.mimeType = mimeType;
|
86 |
|
87 | if (!COMPUTE_HASH) {
|
88 | return callback(null, stats);
|
89 | }
|
90 |
|
91 | this.computeHash(path, stats, (error, hash) => {
|
92 |
|
93 | stats.sha256 = hash;
|
94 |
|
95 | callback(null, stats);
|
96 | });
|
97 | });
|
98 | }
|
99 |
|
100 | _mkdir(osPath, callback) {
|
101 | debug("_mkdir", "path=",osPath);
|
102 |
|
103 | fs.access(osPath, fs.R_OK | fs.W_OK, (error) => {
|
104 | if (error) {
|
105 | console.log("_mkdir", "parent=",osPath,"access problem=",error);
|
106 |
|
107 | if (error.code==='ENOENT') {
|
108 | var parent=Path.dirname(osPath);
|
109 |
|
110 | this._mkdir(parent, (error) => {
|
111 | if (error) {
|
112 | return callback(error);
|
113 | }
|
114 |
|
115 | fs.mkdir(osPath, callback);
|
116 | });
|
117 | return;
|
118 | }
|
119 |
|
120 | return callback(error);
|
121 | }
|
122 |
|
123 | callback();
|
124 | });
|
125 | }
|
126 |
|
127 | |
128 |
|
129 |
|
130 | createWriteStream(url, options, callback) {
|
131 | debug("createWriteStream", "Url=",url,"options=",options);
|
132 |
|
133 | var osPath = url;
|
134 | if (CHANGE_PATH_SEPARATOR) {
|
135 | osPath = osPath.replace(/\//g, Path.sep);
|
136 | }
|
137 |
|
138 | var parent=Path.dirname(osPath);
|
139 |
|
140 | this._mkdir(parent, (error) => {
|
141 | if (error) {
|
142 | console.log("createWriteStream", "parent=",parent,"access problem=",error);
|
143 | return callback(error);
|
144 | }
|
145 |
|
146 | var stream = fs.createWriteStream(url, options);
|
147 |
|
148 | callback(null, stream);
|
149 | });
|
150 | }
|
151 |
|
152 | |
153 |
|
154 |
|
155 | createReadStream(session, path, options, callback) {
|
156 | debug("createReadStream", "path=",path,"options=",options);
|
157 | assert(path, "Path parameter is null");
|
158 |
|
159 | var osPath = path;
|
160 | if (CHANGE_PATH_SEPARATOR) {
|
161 | osPath = osPath.replace(/\//g, Path.sep);
|
162 | }
|
163 |
|
164 | options = options || {};
|
165 |
|
166 | var openStream = () => {
|
167 | if (debug.enabled) {
|
168 | debug("createReadStream", "osPath=", osPath, "options=", options);
|
169 | }
|
170 |
|
171 | try {
|
172 | var stream = fs.createReadStream(osPath, options);
|
173 |
|
174 | if (options && options.fd) {
|
175 |
|
176 | stream.destroy = () => {
|
177 | };
|
178 | }
|
179 |
|
180 | return callback(null, stream);
|
181 |
|
182 | } catch (x) {
|
183 | logger.error("Can not access to " + path, x);
|
184 |
|
185 | return callback(x);
|
186 | }
|
187 | };
|
188 |
|
189 | if (session) {
|
190 | options = options || {};
|
191 | options.flags = 'r';
|
192 | options.autoClose = false;
|
193 |
|
194 | if (debug.enabled) {
|
195 | debug("createReadStream", "Has session: path=", osPath, "session.fd=" + session.fd);
|
196 | }
|
197 |
|
198 | if (!session.fd) {
|
199 | fs.open(osPath, 'r', (error, fd) => {
|
200 | if (error) {
|
201 | return callback(error);
|
202 | }
|
203 | session.fd = fd;
|
204 | options.fd = fd;
|
205 |
|
206 | if (debug.enabled) {
|
207 | debug("createReadStream", "Has session open '" + osPath + "' => session.fd=" +
|
208 | session.fd);
|
209 | }
|
210 |
|
211 | openStream();
|
212 | });
|
213 |
|
214 | return;
|
215 | }
|
216 |
|
217 | options.fd = session.fd;
|
218 | }
|
219 |
|
220 | openStream();
|
221 | }
|
222 |
|
223 | |
224 |
|
225 |
|
226 | end(session, callback) {
|
227 | if (session && session.fd) {
|
228 |
|
229 | if (debug.enabled) {
|
230 | debug("Close fd " + session.fd);
|
231 | }
|
232 |
|
233 | fs.close(session.fd, (error) => {
|
234 | delete session.fd;
|
235 |
|
236 | callback(error);
|
237 | });
|
238 | return;
|
239 | }
|
240 | callback();
|
241 | }
|
242 | }
|
243 |
|
244 | module.exports = FileContentProvider;
|