Set up Heroku deployment.

This commit is contained in:
Gareth Latty
2019-06-23 01:02:52 +01:00
parent 8f75e837cc
commit 7d88752bd1
15 changed files with 13767 additions and 80 deletions
+7 -1
View File
@@ -9,10 +9,12 @@
listenOn: 8081,
// It is also possible to listen on a unix socket.
// listenOn: "/tmp/sock",
// This will be overwritten by the environment variable MD_LISTEN_ON, if set.
// The path this is hosted behind - only relevant when behind a reverse proxy, this won't actually host on a different
// path. This should always have a trailing slash if it isn't empty, and never one at the start.
basePath: "",
// This will be overwritten by the environment variable MD_BASE_PATH, if set.
// Timeouts determine how long the server waits before taking certain actions.
// These values are all ISO 8601 durations.
@@ -87,7 +89,11 @@
checkAfter: "PT5M"
},
// A file to touch when the server is started. If null, we won't touch any files.
touchOnStart: null,
// This will be overwritten by the environment variable MD_TOUCH_ON_START, if set.
// The version of Massive Decks.
// This will be overwritten by the environment variable MD_VERSION, if set.
version: "dev"
// This will be overwritten by the environment variable MD_VERSION, if set.
}
+14 -14
View File
@@ -1151,13 +1151,13 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.0.tgz",
"integrity": "sha512-SrrIfcd4tOgsspOKTSwamuTOAMZOUigHQhVMrzNjz4/B9Za6SHQDIocMIyIDfwDgx6MhS15nS6HC8kumCV2qBQ==",
"version": "5.16.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz",
"integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"ajv": "^6.10.0",
"ajv": "^6.9.1",
"chalk": "^2.1.0",
"cross-spawn": "^6.0.5",
"debug": "^4.0.1",
@@ -1165,19 +1165,18 @@
"eslint-scope": "^4.0.3",
"eslint-utils": "^1.3.1",
"eslint-visitor-keys": "^1.0.0",
"espree": "^6.0.0",
"espree": "^5.0.1",
"esquery": "^1.0.1",
"esutils": "^2.0.2",
"file-entry-cache": "^5.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^3.1.0",
"glob": "^7.1.2",
"globals": "^11.7.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"inquirer": "^6.2.2",
"is-glob": "^4.0.0",
"js-yaml": "^3.13.1",
"js-yaml": "^3.13.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.11",
@@ -1185,6 +1184,7 @@
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.2",
"progress": "^2.0.0",
"regexpp": "^2.0.1",
"semver": "^5.5.1",
@@ -1265,9 +1265,9 @@
"dev": true
},
"espree": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz",
"integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
"integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
"dev": true,
"requires": {
"acorn": "^6.0.7",
@@ -4430,9 +4430,9 @@
}
},
"tslib": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
"dev": true
},
"tsutils": {
+19 -12
View File
@@ -1,22 +1,29 @@
{
"name": "server",
"description": "The game server for Massive Decks, a comedy party game.",
"version": "2.0.0",
"description": "Massive Decks server.",
"main": "dist/index.js",
"scripts": {
"generate-json-validators": "npx typescript-json-validator src/ts/action/validation.ts --collection --noExtraProps--format=full --aliasRefs --ignoreErrors && sed -i '1s;^;/* eslint-disable */\\n;' src/ts/action/validation.validator.ts",
"build": "tsc",
"prestart": "npm run build",
"dev": "nodemon .",
"debug": "nodemon --inspect .",
"generate-secret": "npm run prestart && node dist/secret.js"
},
"author": "Reread Games <team@rereadgames.com>",
"license": "AGPL-3.0-or-later",
"private": true,
"repository": "github:Lattyware/massivedecks",
"engines": {
"node": ">=0.12"
"node": ">=11 <12"
},
"main": "dist/index.js",
"scripts": {
"prepublishOnly": "npm run build",
"build": "tsc",
"prestart": "npm run build",
"start": "node dist/index.js",
"dev": "nodemon .",
"debug": "nodemon --inspect .",
"generate-json-validators": "npx typescript-json-validator src/ts/action/validation.ts --collection --noExtraProps--format=full --aliasRefs --ignoreErrors && sed -i '1s;^;/* eslint-disable */\\n;' src/ts/action/validation.validator.ts",
"generate-secret": "npm run prestart && node dist/secret.js"
},
"files": [
"dist/*",
"config.json5"
],
"dependencies": {
"ajv": "^6.10.0",
"axios": "^0.19.0",
@@ -52,7 +59,7 @@
"@types/wu": "^2.1.39",
"@typescript-eslint/eslint-plugin": "^1.10.2",
"@typescript-eslint/parser": "^1.10.2",
"eslint": "^6.0.0",
"eslint": "^5.12.1",
"eslint-config-prettier": "^5.0.0",
"eslint-plugin-prettier": "^3.1.0",
"nodemon": "^1.19.1",
+9 -9
View File
@@ -21,15 +21,15 @@ export const Schema = {
definitions: {
Action: {
anyOf: [
{
$ref: "#/definitions/Authenticate"
},
{
$ref: "#/definitions/Judge"
},
{
$ref: "#/definitions/Reveal"
},
{
$ref: "#/definitions/Authenticate"
},
{
$ref: "#/definitions/Submit"
},
@@ -64,7 +64,7 @@ export const Schema = {
description: "Authenticate with the game.",
properties: {
action: {
$ref: "#/definitions/NameType_2"
$ref: "#/definitions/NameType"
},
token: {
$ref: "#/definitions/Token"
@@ -247,7 +247,7 @@ export const Schema = {
description: "A user declares the winning play for a round.",
properties: {
action: {
$ref: "#/definitions/NameType"
$ref: "#/definitions/NameType_1"
},
winner: {
$ref: "#/definitions/Id"
@@ -263,15 +263,15 @@ export const Schema = {
type: "string"
},
NameType: {
enum: ["Judge"],
enum: ["Authenticate"],
type: "string"
},
NameType_1: {
enum: ["Reveal"],
enum: ["Judge"],
type: "string"
},
NameType_2: {
enum: ["Authenticate"],
enum: ["Reveal"],
type: "string"
},
NameType_3: {
@@ -373,7 +373,7 @@ export const Schema = {
description: "A user judges the winning play for a round.",
properties: {
action: {
$ref: "#/definitions/NameType_1"
$ref: "#/definitions/NameType_2"
},
play: {
$ref: "#/definitions/Id"
+34 -7
View File
@@ -5,11 +5,23 @@ type Duration = UnparsedDuration | ParsedDuration;
type UnparsedDuration = string;
type ParsedDuration = number;
export interface Config<D extends Duration> {
const environmental: (keyof EnvironmentalConfig)[] = [
"secret",
"listenOn",
"basePath",
"version",
"touchOnStart"
];
export interface EnvironmentalConfig {
secret: string;
listenOn: number | string; // Port or unix socket path.
basePath: string;
version: string;
touchOnStart: string;
}
export interface Config<D extends Duration> extends EnvironmentalConfig {
timeouts: Timeouts<D>;
storage: BaseStorage<D>;
cache: BaseCache<D>;
@@ -98,9 +110,24 @@ export const parseTimeouts = (
parseDuration(value)
);
export const parse = (config: Unparsed): Parsed => ({
...config,
timeouts: parseTimeouts(config.timeouts),
storage: parseStorage(config.storage),
cache: parseCache(config.cache)
});
export const parse = (config: Unparsed): Parsed =>
pullFromEnvironment({
...config,
timeouts: parseTimeouts(config.timeouts),
storage: parseStorage(config.storage),
cache: parseCache(config.cache)
});
export const pullFromEnvironment = (config: Parsed): Parsed => {
for (const name of environmental) {
const envName = `MD_${name
.split(/(?=[A-Z])/)
.join("_")
.toUpperCase()}`;
const value = process.env[envName];
if (value !== undefined) {
config[name] = value;
}
}
return config;
};
+14 -15
View File
@@ -37,25 +37,20 @@ process.on("unhandledRejection", function(reason, promise) {
process.exit(1);
});
function getConfigFilePath(): string {
const configPath = process.env["MD_CONFIG_PATH"];
return configPath === undefined ? "config.json5" : configPath;
}
async function main(): Promise<void> {
const config = serverConfig.parse(JSON5.parse(
(await promisify(fs.readFile)("config.json5")).toString()
(await promisify(fs.readFile)(getConfigFilePath())).toString()
) as serverConfig.Unparsed);
const envSecret = process.env.MD_SECRET;
if (envSecret !== undefined) {
config.secret = envSecret;
}
const envVersion = process.env.MD_VERSION;
if (envVersion !== undefined) {
config.version = envVersion;
}
const { app } = ws(express());
app.use(helmet());
app.set('trust proxy', true);
app.set("trust proxy", true);
const environment = app.get("env");
@@ -199,9 +194,13 @@ async function main(): Promise<void> {
.loadFromStore(state)
.catch(error => logging.logException("Error running store tasks:", error));
app.listen(config.listenOn, () =>
logging.logger.info(`Listening on ${config.listenOn}.`)
);
app.listen(config.listenOn, async () => {
logging.logger.info(`Listening on ${config.listenOn}.`);
if (config.touchOnStart !== null) {
const f = await promisify(fs.open)(config.touchOnStart, "w");
await promisify(fs.close)(f);
}
});
}
main().catch(error => {