1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.Server = exports.MAX_PREFETCH_LINKS = void 0;
|
4 | var tslib_1 = require("tslib");
|
5 | var child_process = require("child_process");
|
6 | var debug_ = require("debug");
|
7 | var express = require("express");
|
8 | var fs = require("fs");
|
9 | var http = require("http");
|
10 | var https = require("https");
|
11 | var path = require("path");
|
12 | var tmp_1 = require("tmp");
|
13 | var serializable_1 = require("r2-lcp-js/dist/es5/src/serializable");
|
14 | var opds2_1 = require("r2-opds-js/dist/es5/src/opds/opds2/opds2");
|
15 | var publication_parser_1 = require("r2-shared-js/dist/es5/src/parser/publication-parser");
|
16 | var UrlUtils_1 = require("r2-utils-js/dist/es5/src/_utils/http/UrlUtils");
|
17 | var self_signed_1 = require("../utils/self-signed");
|
18 | var server_assets_1 = require("./server-assets");
|
19 | var server_lcp_lsd_show_1 = require("./server-lcp-lsd-show");
|
20 | var server_manifestjson_1 = require("./server-manifestjson");
|
21 | var server_mediaoverlays_1 = require("./server-mediaoverlays");
|
22 | var server_opds_browse_v1_1 = require("./server-opds-browse-v1");
|
23 | var server_opds_browse_v2_1 = require("./server-opds-browse-v2");
|
24 | var server_opds_convert_v1_to_v2_1 = require("./server-opds-convert-v1-to-v2");
|
25 | var server_opds_local_feed_1 = require("./server-opds-local-feed");
|
26 | var server_pub_1 = require("./server-pub");
|
27 | var server_root_1 = require("./server-root");
|
28 | var server_secure_1 = require("./server-secure");
|
29 | var server_url_1 = require("./server-url");
|
30 | var server_version_1 = require("./server-version");
|
31 | var debug = debug_("r2:streamer#http/server");
|
32 | exports.MAX_PREFETCH_LINKS = 10;
|
33 | var Server = (function () {
|
34 | function Server(options) {
|
35 | this.lcpBeginToken = "*-";
|
36 | this.lcpEndToken = "-*";
|
37 | this.disableReaders = options && options.disableReaders ? options.disableReaders : false;
|
38 | this.disableDecryption = options && options.disableDecryption ? options.disableDecryption : false;
|
39 | this.disableRemotePubUrl = options && options.disableRemotePubUrl ? options.disableRemotePubUrl : false;
|
40 | this.disableOPDS = options && options.disableOPDS ? options.disableOPDS : false;
|
41 | this.maxPrefetchLinks = options && options.maxPrefetchLinks ? options.maxPrefetchLinks : exports.MAX_PREFETCH_LINKS;
|
42 | this.publications = [];
|
43 | this.pathPublicationMap = {};
|
44 | this.publicationsOPDSfeed = undefined;
|
45 | this.publicationsOPDSfeedNeedsUpdate = true;
|
46 | this.creatingPublicationsOPDS = false;
|
47 | this.opdsJsonFilePath = tmp_1.tmpNameSync({ prefix: "readium2-OPDS2-", postfix: ".json" });
|
48 | this.expressApp = express();
|
49 | server_secure_1.serverSecure(this, this.expressApp);
|
50 | var staticOptions = {
|
51 | etag: false,
|
52 | };
|
53 | if (!this.disableReaders) {
|
54 | this.expressApp.use("/readerNYPL", express.static("misc/readers/reader-NYPL", staticOptions));
|
55 | this.expressApp.use("/readerHADRIEN", express.static("misc/readers/reader-HADRIEN", staticOptions));
|
56 | }
|
57 | server_root_1.serverRoot(this, this.expressApp);
|
58 | server_version_1.serverVersion(this, this.expressApp);
|
59 | if (!this.disableRemotePubUrl) {
|
60 | server_url_1.serverRemotePub(this, this.expressApp);
|
61 | server_lcp_lsd_show_1.serverLCPLSD_show(this, this.expressApp);
|
62 | }
|
63 | if (!this.disableOPDS) {
|
64 | server_opds_browse_v1_1.serverOPDS_browse_v1(this, this.expressApp);
|
65 | server_opds_browse_v2_1.serverOPDS_browse_v2(this, this.expressApp);
|
66 | server_opds_local_feed_1.serverOPDS_local_feed(this, this.expressApp);
|
67 | server_opds_convert_v1_to_v2_1.serverOPDS_convert_v1_to_v2(this, this.expressApp);
|
68 | }
|
69 | var routerPathBase64 = server_pub_1.serverPub(this, this.expressApp);
|
70 | server_manifestjson_1.serverManifestJson(this, routerPathBase64);
|
71 | server_mediaoverlays_1.serverMediaOverlays(this, routerPathBase64);
|
72 | server_assets_1.serverAssets(this, routerPathBase64);
|
73 | }
|
74 | Server.prototype.preventRobots = function () {
|
75 | this.expressApp.get("/robots.txt", function (_req, res) {
|
76 | var robotsTxt = "User-agent: *\nDisallow: /\n";
|
77 | res.header("Content-Type", "text/plain");
|
78 | res.status(200).send(robotsTxt);
|
79 | });
|
80 | };
|
81 | Server.prototype.expressUse = function (pathf, func) {
|
82 | this.expressApp.use(pathf, func);
|
83 | };
|
84 | Server.prototype.expressGet = function (paths, func) {
|
85 | this.expressApp.get(paths, func);
|
86 | };
|
87 | Server.prototype.isStarted = function () {
|
88 | return (typeof this.serverInfo() !== "undefined") &&
|
89 | (typeof this.httpServer !== "undefined") ||
|
90 | (typeof this.httpsServer !== "undefined");
|
91 | };
|
92 | Server.prototype.isSecured = function () {
|
93 | return (typeof this.serverInfo() !== "undefined") &&
|
94 | (typeof this.httpsServer !== "undefined");
|
95 | };
|
96 | Server.prototype.getSecureHTTPHeader = function (url) {
|
97 | return server_secure_1.serverSecureHTTPHeader(this, url);
|
98 | };
|
99 | Server.prototype.start = function (port, secure) {
|
100 | return tslib_1.__awaiter(this, void 0, void 0, function () {
|
101 | var envPort, p;
|
102 | var _this = this;
|
103 | return tslib_1.__generator(this, function (_a) {
|
104 | if (this.isStarted()) {
|
105 | return [2, Promise.resolve(this.serverInfo())];
|
106 | }
|
107 | envPort = 0;
|
108 | try {
|
109 | envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 0;
|
110 | }
|
111 | catch (err) {
|
112 | debug(err);
|
113 | envPort = 0;
|
114 | }
|
115 | p = port || envPort || 3000;
|
116 | debug("PORT: " + port + " || " + envPort + " || 3000 => " + p);
|
117 | if (secure) {
|
118 | this.httpServer = undefined;
|
119 | return [2, new Promise(function (resolve, reject) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
120 | var certData, err_1;
|
121 | var _this = this;
|
122 | return tslib_1.__generator(this, function (_a) {
|
123 | switch (_a.label) {
|
124 | case 0:
|
125 | _a.trys.push([0, 2, , 3]);
|
126 | return [4, self_signed_1.generateSelfSignedData()];
|
127 | case 1:
|
128 | certData = _a.sent();
|
129 | return [3, 3];
|
130 | case 2:
|
131 | err_1 = _a.sent();
|
132 | debug(err_1);
|
133 | reject("err");
|
134 | return [2];
|
135 | case 3:
|
136 | this.httpsServer = https.createServer({ key: certData.private, cert: certData.cert }, this.expressApp).listen(p, function () {
|
137 | _this.serverData = tslib_1.__assign(tslib_1.__assign({}, certData), { urlHost: "127.0.0.1", urlPort: p, urlScheme: "https" });
|
138 | resolve(_this.serverData);
|
139 | });
|
140 | return [2];
|
141 | }
|
142 | });
|
143 | }); })];
|
144 | }
|
145 | else {
|
146 | this.httpsServer = undefined;
|
147 | return [2, new Promise(function (resolve, _reject) {
|
148 | _this.httpServer = http.createServer(_this.expressApp).listen(p, function () {
|
149 | _this.serverData = {
|
150 | urlHost: "127.0.0.1",
|
151 | urlPort: p,
|
152 | urlScheme: "http",
|
153 | };
|
154 | resolve(_this.serverData);
|
155 | });
|
156 | })];
|
157 | }
|
158 | return [2];
|
159 | });
|
160 | });
|
161 | };
|
162 | Server.prototype.stop = function () {
|
163 | if (this.isStarted()) {
|
164 | if (this.httpServer) {
|
165 | this.httpServer.close();
|
166 | this.httpServer = undefined;
|
167 | }
|
168 | if (this.httpsServer) {
|
169 | this.httpsServer.close();
|
170 | this.httpsServer = undefined;
|
171 | }
|
172 | this.serverData = undefined;
|
173 | this.uncachePublications();
|
174 | }
|
175 | };
|
176 | Server.prototype.serverInfo = function () {
|
177 | return this.serverData;
|
178 | };
|
179 | Server.prototype.serverUrl = function () {
|
180 | if (!this.isStarted()) {
|
181 | return undefined;
|
182 | }
|
183 | var info = this.serverInfo();
|
184 | if (!info) {
|
185 | return undefined;
|
186 | }
|
187 | if (info.urlPort === 443 || info.urlPort === 80) {
|
188 | return info.urlScheme + "://" + info.urlHost;
|
189 | }
|
190 | return info.urlScheme + "://" + info.urlHost + ":" + info.urlPort;
|
191 | };
|
192 | Server.prototype.setResponseCacheHeaders = function (res, enableCaching) {
|
193 | if (enableCaching) {
|
194 | res.setHeader("Cache-Control", "public,max-age=86400");
|
195 | }
|
196 | else {
|
197 | res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
198 | res.setHeader("Pragma", "no-cache");
|
199 | res.setHeader("Expires", "0");
|
200 | }
|
201 | };
|
202 | Server.prototype.setResponseCORS = function (res) {
|
203 | res.setHeader("Access-Control-Allow-Origin", "*");
|
204 | res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
|
205 | res.setHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Ranges, Content-Range, Range, Link, Transfer-Encoding, X-Requested-With, Authorization, Accept, Origin, User-Agent, DNT, Cache-Control, Keep-Alive, If-Modified-Since");
|
206 | res.setHeader("Access-Control-Expose-Headers", "Content-Type, Content-Length, Accept-Ranges, Content-Range, Range, Link, Transfer-Encoding, X-Requested-With, Authorization, Accept, Origin, User-Agent, DNT, Cache-Control, Keep-Alive, If-Modified-Since");
|
207 | };
|
208 | Server.prototype.addPublications = function (pubs) {
|
209 | var _this = this;
|
210 | pubs.forEach(function (pub) {
|
211 | if (_this.publications.indexOf(pub) < 0) {
|
212 | _this.publicationsOPDSfeedNeedsUpdate = true;
|
213 | _this.publications.push(pub);
|
214 | }
|
215 | });
|
216 | return pubs.map(function (pub) {
|
217 | var pubid = UrlUtils_1.encodeURIComponent_RFC3986(Buffer.from(pub).toString("base64"));
|
218 | return "/pub/" + pubid + "/manifest.json";
|
219 | });
|
220 | };
|
221 | Server.prototype.removePublications = function (pubs) {
|
222 | var _this = this;
|
223 | pubs.forEach(function (pub) {
|
224 | _this.uncachePublication(pub);
|
225 | var i = _this.publications.indexOf(pub);
|
226 | if (i >= 0) {
|
227 | _this.publicationsOPDSfeedNeedsUpdate = true;
|
228 | _this.publications.splice(i, 1);
|
229 | }
|
230 | });
|
231 | return pubs.map(function (pub) {
|
232 | var pubid = UrlUtils_1.encodeURIComponent_RFC3986(Buffer.from(pub).toString("base64"));
|
233 | return "/pub/" + pubid + "/manifest.json";
|
234 | });
|
235 | };
|
236 | Server.prototype.getPublications = function () {
|
237 | return this.publications;
|
238 | };
|
239 | Server.prototype.loadOrGetCachedPublication = function (filePath) {
|
240 | return tslib_1.__awaiter(this, void 0, void 0, function () {
|
241 | var publication, err_2;
|
242 | return tslib_1.__generator(this, function (_a) {
|
243 | switch (_a.label) {
|
244 | case 0:
|
245 | publication = this.cachedPublication(filePath);
|
246 | if (!!publication) return [3, 5];
|
247 | _a.label = 1;
|
248 | case 1:
|
249 | _a.trys.push([1, 3, , 4]);
|
250 | return [4, publication_parser_1.PublicationParsePromise(filePath)];
|
251 | case 2:
|
252 | publication = _a.sent();
|
253 | return [3, 4];
|
254 | case 3:
|
255 | err_2 = _a.sent();
|
256 | debug(err_2);
|
257 | return [2, Promise.reject(err_2)];
|
258 | case 4:
|
259 | this.cachePublication(filePath, publication);
|
260 | _a.label = 5;
|
261 | case 5: return [2, publication];
|
262 | }
|
263 | });
|
264 | });
|
265 | };
|
266 | Server.prototype.isPublicationCached = function (filePath) {
|
267 | return typeof this.cachedPublication(filePath) !== "undefined";
|
268 | };
|
269 | Server.prototype.cachedPublication = function (filePath) {
|
270 | return this.pathPublicationMap[filePath];
|
271 | };
|
272 | Server.prototype.cachePublication = function (filePath, pub) {
|
273 | if (!this.isPublicationCached(filePath)) {
|
274 | this.pathPublicationMap[filePath] = pub;
|
275 | }
|
276 | };
|
277 | Server.prototype.uncachePublication = function (filePath) {
|
278 | if (this.isPublicationCached(filePath)) {
|
279 | var pub = this.cachedPublication(filePath);
|
280 | if (pub) {
|
281 | pub.freeDestroy();
|
282 | }
|
283 | this.pathPublicationMap[filePath] = undefined;
|
284 | delete this.pathPublicationMap[filePath];
|
285 | }
|
286 | };
|
287 | Server.prototype.uncachePublications = function () {
|
288 | var _this = this;
|
289 | Object.keys(this.pathPublicationMap).forEach(function (filePath) {
|
290 | _this.uncachePublication(filePath);
|
291 | });
|
292 | };
|
293 | Server.prototype.publicationsOPDS = function () {
|
294 | if (this.publicationsOPDSfeedNeedsUpdate) {
|
295 | this.publicationsOPDSfeed = undefined;
|
296 | if (fs.existsSync(this.opdsJsonFilePath)) {
|
297 | fs.unlinkSync(this.opdsJsonFilePath);
|
298 | }
|
299 | }
|
300 | if (this.publicationsOPDSfeed) {
|
301 | return this.publicationsOPDSfeed;
|
302 | }
|
303 | debug("OPDS2.json => " + this.opdsJsonFilePath);
|
304 | if (!fs.existsSync(this.opdsJsonFilePath)) {
|
305 | if (!this.creatingPublicationsOPDS) {
|
306 | this.creatingPublicationsOPDS = true;
|
307 | this.publicationsOPDSfeedNeedsUpdate = false;
|
308 | var jsFile = path.join(__dirname, "opds2-create-cli.js");
|
309 | var args_1 = [jsFile, this.opdsJsonFilePath];
|
310 | this.publications.forEach(function (pub) {
|
311 | var filePathBase64 = UrlUtils_1.encodeURIComponent_RFC3986(Buffer.from(pub).toString("base64"));
|
312 | args_1.push(filePathBase64);
|
313 | });
|
314 | debug("SPAWN OPDS2-create: " + args_1[0]);
|
315 | var child = child_process.spawn("node", args_1, {
|
316 | cwd: process.cwd(),
|
317 | env: process.env,
|
318 | });
|
319 | child.stdout.on("data", function (data) {
|
320 | debug(data.toString());
|
321 | });
|
322 | child.stderr.on("data", function (data) {
|
323 | debug(data.toString());
|
324 | });
|
325 | }
|
326 | return undefined;
|
327 | }
|
328 | this.creatingPublicationsOPDS = false;
|
329 | var jsonStr = fs.readFileSync(this.opdsJsonFilePath, { encoding: "utf8" });
|
330 | if (!jsonStr) {
|
331 | return undefined;
|
332 | }
|
333 | var json = global.JSON.parse(jsonStr);
|
334 | this.publicationsOPDSfeed = serializable_1.TaJsonDeserialize(json, opds2_1.OPDSFeed);
|
335 | return this.publicationsOPDSfeed;
|
336 | };
|
337 | return Server;
|
338 | }());
|
339 | exports.Server = Server;
|
340 |
|
\ | No newline at end of file |