import { isTestInstance } from './server/helpers/core-utils' if (isTestInstance()) { require('source-map-support').install() } import bodyParser from 'body-parser' import express from 'express' import cors from 'cors' import morgan from 'morgan' import { apiRouter } from './server/controllers/api' import { logger } from './server/helpers/logger' import { API_VERSION, CONFIG, getWebserverUrl } from './server/initializers/constants' import { IndexationScheduler } from './server/lib/schedulers/indexation-scheduler' import { join } from 'path' import { readFile } from 'fs-extra' import { getConfig } from './server/controllers/api/config' const app = express() const url = getWebserverUrl() app.use(morgan('combined', { stream: { write: logger.info.bind(logger) } })) app.use(bodyParser.json({ type: [ 'application/json', 'application/*+json' ], limit: '5mb' })) app.use(bodyParser.urlencoded({ extended: false })) // ----------- Views, routes and static files ----------- app.use(cors()) const apiRoute = '/api/' + API_VERSION app.use(apiRoute, apiRouter) // Static client files app.use('/img/', express.static(join(__dirname, '../client/dist/img'), { maxAge: '30d' })) app.use('/assets/', express.static(join(__dirname, '../client/dist/assets'), { maxAge: '30d' })) app.use('/theme/', express.static(join(__dirname, './themes'), { maxAge: '30d' })) app.use('/opensearch.xml', async function (req, res) { const data = ` ${CONFIG.SEARCH_INSTANCE.NAME} ${CONFIG.SEARCH_INSTANCE.DESCRIPTION} ${url}/img/favicon.png * peertube video open true UTF-8 UTF-8 Framasoft: contact.framasoft.org ` return res.type('application/xml').send(data).end() }) let indexHTML: string app.use('/*', async function (req, res) { res.set('Content-Type', 'text/html; charset=UTF-8') if (indexHTML) return res.send(indexHTML) let bufferCSS: Buffer if (CONFIG.SEARCH_INSTANCE.THEME !== 'default') { try { bufferCSS = await readFile(join(__dirname, 'themes', CONFIG.SEARCH_INSTANCE.THEME, 'index.css')) } catch (err) { logger.error({ err }, 'Cannot fetch CSS theme.') } } const title = CONFIG.SEARCH_INSTANCE.NAME const description = CONFIG.SEARCH_INSTANCE.DESCRIPTION const styleCSS = bufferCSS ? `` : '' // Stringify the JSON object, and then stringify the string object so we can inject it into the HTML const config = getConfig() const serverConfigString = JSON.stringify(JSON.stringify(config)) const configJS = `` const tags = ` ${title} ${styleCSS} ${configJS}` const buffer = await readFile(join(__dirname, '../client/dist/index.html')) let html = buffer.toString() html = html.replace('', tags + '') // Prevent caching a not ready yet configuration (because the indexer did not have time to run) if (config.indexedHostsCount !== 0) { indexHTML = html } return res.send(html) }) // ----------- Errors ----------- // Catch 404 and forward to error handler app.use(function (req, res, next) { const err = new Error('Not Found') as any err.status = 404 next(err) }) app.use(function (err, req, res, next) { let error = 'Unknown error.' if (err) { error = err.stack || err.message || err } logger.error({ err: error }, 'Error in controller.') return res.status(err.status || 500).end() }) // ----------- Run ----------- app.listen(CONFIG.LISTEN.PORT, async () => { logger.info('Server listening on port %d', CONFIG.LISTEN.PORT) IndexationScheduler.Instance.enable() try { await IndexationScheduler.Instance.initIndexes() } catch (err) { logger.error(err, 'Cannot init videos index.') process.exit(-1) } IndexationScheduler.Instance.execute() .catch(err => logger.error(err, 'Cannot run video indexer')) })