import "../ignore_stylesheet_imports";
import * as express from "express";
import * as React from "react";
const fs = require("fs");
import { renderToString } from "react-dom/server";
import { match, RouterContext } from "react-router";
import { singleLibraryRoutes, multiLibraryRoutes } from "../routes";
import ContextProvider from "../components/ContextProvider";
import buildInitialState, { State } from "opds-web-client/lib/state";
import LibraryDataCache from "./LibraryDataCache";
import UrlShortener from "../UrlShortener";
import { LibraryData } from "../interfaces";
const initialize = async () => {
const app = express();
const port = process.env.PORT || 3000;
let registryBase = process.env.REGISTRY_BASE;
const circManagerBase = process.env.SIMPLIFIED_CATALOG_BASE;
let routes = circManagerBase ? singleLibraryRoutes : multiLibraryRoutes;
const config = {};
const configFile = process.env.CONFIG_FILE;
if (configFile) {
let configText;
if (configFile.startsWith("http")) {
try {
const configResponse = await fetch(configFile);
configText = await configResponse.text();
} catch (configUrlError) {
throw "Could not read config file at " + configFile;
}
} else {
configText = fs.readFileSync(configFile, "utf8");
}
for (let entry of configText.split("\n")) {
if ( entry && entry.charAt(0) !== "#" ) {
let [path, circManagerUrl] = entry.split("|");
config[path] = circManagerUrl;
}
}
}
if (registryBase && circManagerBase || registryBase && configFile || circManagerBase && configFile) {
console.warn("Only one of REGISTRY_BASE, SIMPLIFIED_CATALOG_BASE, and CONFIG_FILE should be used.");
}
if (!registryBase && !circManagerBase && !configFile) {
registryBase = "http://localhost:7000";
}
const shortenUrls: boolean = !(process.env.SHORTEN_URLS === "false");
const distDir = process.env.SIMPLIFIED_PATRON_DIST || "dist";
const cacheExpirationSeconds = parseInt(process.env.CACHE_EXPIRATION_SECONDS, 10);
const cache = new LibraryDataCache(registryBase, cacheExpirationSeconds, config);
// This is fired every time the server side receives a request
app.use("/js", express.static(distDir));
app.use("/css", express.static(distDir));
app.use(handleRender);
function handleRender(req, res) {
match({ routes, location: req.url }, async (error, redirectLocation, renderProps: any) => {
if (error) {
res.status(500).send(renderErrorPage());
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
let { library, collectionUrl, bookUrl } = renderProps.params;
let libraryData;
if (circManagerBase) {
// We're using a single circ manager library instead of a registry.
let catalog = await cache.getCatalog(circManagerBase);
let authDocument = await cache.getAuthDocument(catalog);
libraryData = {
onlyLibrary: true,
catalogUrl: circManagerBase,
...cache.getDataFromAuthDocumentAndCatalog(authDocument, catalog)
};
} else {
try {
libraryData = await cache.getLibraryData(library);
} catch (error) {
res.status(404).send(renderErrorPage(error));
return;
}
}
let catalogUrl = libraryData.catalogUrl;
if (!collectionUrl && !bookUrl) {
let urlShortener = new UrlShortener(catalogUrl, shortenUrls);
let preparedCollectionUrl = urlShortener.prepareCollectionUrl(catalogUrl);
// With short URLS, if the home URL is the library root URL, the prepared URL
// will be empty, and we don't need to redirect.
if (!shortenUrls || preparedCollectionUrl) {
if (library) {
res.redirect(302, "/" + library + "/collection/" + preparedCollectionUrl);
} else {
res.redirect(302, "/collection/" + preparedCollectionUrl);
}
return;
}
}
buildInitialState(collectionUrl, bookUrl).then((state: State) => {
const html = renderToString(