Files
pixel.horse/src/ts/server/routes/index.ts
T
Chris Multhaupt c61174f32f Update team and add discord contact config (#143)
Update team and add Discord contact config
2019-10-04 15:30:43 -05:00

169 lines
5.3 KiB
TypeScript

import * as fs from 'fs';
import * as path from 'path';
import { compileFile } from 'pug';
import { RequestHandler } from 'express';
import { ClientOptions, Server, writeObject } from 'ag-sockets';
import { OAuthProvider } from '../../common/interfaces';
import { providers, OAuthProviderInfo } from '../oauth';
import { config, version, description } from '../config';
import { TokenData } from '../serverInterfaces';
import { logger } from '../logger';
import { pathTo } from '../paths';
import { writeBinary } from '../../common/binaryUtils';
interface RevFile {
name: string;
path: string;
url: string;
}
interface PageOptions {
isPublic?: boolean;
production: boolean;
base: string;
assets?: string;
style: string;
script: string;
scriptES: string;
token?: string;
noindex?: boolean;
socketOptions?: ClientOptions;
webpack?: boolean;
local?: boolean;
}
function getFiles(urlBase: string, dir: string, sub: string): RevFile[] {
try {
return fs.readdirSync(path.join(dir, sub))
.filter(file => /\.(js|css|png)$/.test(file))
.map(file => ({
name: file.replace(/-[a-f0-9]{10}\.(js|css|png)$/, '.$1'),
path: path.join(dir, sub, file),
url: `${urlBase}/${sub}/${file}`,
}));
} catch {
return [];
}
}
export function createIndex(assetsPath: string, adminAssetsPath: string) {
function toOAuthProvider({ id, name, color, auth, connectOnly }: OAuthProviderInfo): OAuthProvider {
return { id, name, color, disabled: auth ? undefined : true, connectOnly };
}
const revServer = new Map<string, RevFile>();
[
...getFiles('assets', assetsPath, 'styles'),
...getFiles('assets', assetsPath, 'scripts'),
...getFiles('assets', assetsPath, 'images'),
...getFiles('assets-admin', adminAssetsPath, 'styles'),
...getFiles('assets-admin', adminAssetsPath, 'scripts'),
].forEach(file => revServer.set(file.name, file));
function revUrlGetter(dir: string) {
return (name: string) => {
const file = revServer.get(name);
return file && file.url || `assets/${dir}/${name}`;
};
}
function getRevPath(name: string) {
return (revServer.get(name) && revServer.get(name)!.path) || path.join(assetsPath, name);
}
const getRevScriptURL = revUrlGetter('scripts');
const getRevStyleURL = revUrlGetter('styles');
const getRevImageURL = revUrlGetter('images');
const template = compileFile(pathTo('views', 'index.pug'));
const inlineStyle = fs.readFileSync(getRevPath('style-inline.css'), 'utf8');
const loadingImage = fs.readFileSync(getRevPath('logo-gray.png'));
const oauthProviders = providers.map(toOAuthProvider);
function encodeSocketOptions(options: ClientOptions | undefined): string {
if (options) {
const data = writeBinary(writer => writeObject(writer, options));
const buffer = Buffer.from(data);
return buffer.toString('base64');
} else {
return '';
}
}
function renderPage(
{ isPublic, style, script, scriptES, production, noindex, base, socketOptions, token, local }: PageOptions
) {
return template({
doctype: 'html',
host: config.host,
title: config.title,
twitterLink: config.twitterLink,
discordLink: config.discordLink,
email: config.contactEmail,
contactDiscord: config.contactDiscord,
logo: `${config.host}${getRevImageURL('logo-120.png')}`,
loadingImage: `data:image/png;base64,${loadingImage.toString('base64')}`,
version,
description,
base,
token,
sw: config.sw ? 'true' : undefined,
noindex: noindex || config.noindex,
production,
local: local ? 'true' : undefined,
socketOptions: encodeSocketOptions(socketOptions),
inlineStyle,
style,
script,
scriptES,
oauthProviders,
facebookAppId: config.facebookAppId,
isPublic: isPublic ? 'true' : undefined,
});
}
function admin(
production: boolean, base: string, assetsBase: string, scriptName: string, socket: Server
): RequestHandler {
const socketOptions = socket.options();
const style = `${assetsBase}/${getRevStyleURL('style-admin.css')}`;
const script = `${assetsBase}/${getRevScriptURL(scriptName)}`;
const scriptES = script;
return (req, res) => {
try {
const token = socket.token({ account: req.user } as TokenData);
res.send(renderPage({ production, base, style, script, scriptES, noindex: true, socketOptions, token }));
} catch (e) {
logger.error(e);
res.sendStatus(500);
}
};
}
function user(
production: boolean, base: string, styleName: string, scriptName: string, scriptESName: string,
socketOptions: ClientOptions | undefined, noindex: boolean, local: boolean, isPublic: boolean,
) {
const style = `/${getRevStyleURL(styleName)}`;
const script = `/${getRevScriptURL(scriptName)}`;
const scriptES = `/${getRevScriptURL(scriptESName)}`;
const sprites1 = DEVELOPMENT ? `/assets/images/pony.png` : `/${getRevImageURL('pony.png')}`;
const sprites2 = DEVELOPMENT ? `/assets/images/pony2.png` : `/${getRevImageURL('pony2.png')}`;
const page = renderPage({ isPublic, production, base, style, script, scriptES, socketOptions, noindex, local });
const preload = [
`<${script}>; rel=preload; as=script`,
`<${style}>; rel=preload; as=style`,
`<${sprites1}>; rel=preload; as=fetch; crossorigin`,
`<${sprites2}>; rel=preload; as=fetch; crossorigin`,
];
return { page, preload };
}
return { admin, user, getRevScript: getRevScriptURL, getRevStyle: getRevStyleURL };
}