-
Notifications
You must be signed in to change notification settings - Fork 5
/
entry.ts
174 lines (160 loc) · 5.18 KB
/
entry.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import { Logger as MatrixLogger } from 'matrix-appservice-bridge';
import yargs from 'yargs/yargs';
import ConfigReader from './src/configuration/ConfigReader';
import DatabaseConfiguration from './src/configuration/DatabaseConfiguration';
import Database from './src/repositories/Database';
import startup from './src/startup';
import logger, { configureLogger, logExt } from './src/util/logger';
import parseBoolean from './src/util/parseBoolean';
const parseArgs = async () => {
const { argv } = await yargs(process.argv.slice(2))
.version(false)
.strict(true)
.demandCommand(0, 0)
.usage('$0 [options]')
.option('config', {
alias: 'c',
type: 'string',
nargs: 1,
describe: 'Path to the configuration file.',
default: () => process.env.WEBHOOK_CONFIG ?? './gateway-config.yaml',
defaultDescription: './gateway-config.yaml',
})
.option('appservice-config', {
alias: 'a',
type: 'string',
nargs: 1,
describe: 'Where the generated appservice.yaml should be placed.',
default: () =>
process.env.WEBHOOK_APPSERVICE_CONFIG ?? './appservice.yaml',
defaultDescription: './appservice.yaml',
})
.boolean('clear-plugin-cache')
.default('clear-plugin-cache', false)
.describe(
'clear-plugin-cache',
'Clear the plugin cache before compiling plugins.',
)
.option('migrate', {
type: 'number',
description:
'Apply the specified number of migrations. To migrate up, supply a ' +
'positive number. To migrate down, supply a negative number. ' +
'Implies --no-auto-migrate.',
nargs: 1,
})
.option('migrate-status', {
type: 'boolean',
description: 'Print the migration status, then exit.',
})
.option('auto-migrate', {
default: () => parseBoolean(process.env.WEBHOOK_AUTO_MIGRATE) ?? true,
hidden: true,
})
.describe(
'no-auto-migrate',
'Do not perform automatic migrations. This will cause the application to ' +
'exit with a non-zero exit code if there are pending migrations.',
)
.count('v')
.alias('v', 'verbose')
.describe('v', 'Log verbosity, repeat multiple times to raise.')
.help('h')
.alias('h', 'help')
.check((a) => {
if (a.migrate !== undefined && Number.isNaN(a.migrate)) {
throw new Error('Invalid number of migrations supplied.');
}
return true;
});
return argv;
};
const initialiseLogging = (verbose: number) => {
configureLogger(verbose);
MatrixLogger.configure({
console: 'error',
maxFiles: 1,
});
process.on('unhandledRejection', (error) => {
logger.error('Unhandled error:', (error as Error).message);
logger.prettyError(error as Error);
logger.fatal('Unhandled promise rejection, application will now exit');
process.exit(1);
});
};
const migrateAndQuit = async (
databaseConfig: DatabaseConfiguration,
migrations: number,
) => {
const database = new Database(databaseConfig);
try {
await database.migrateBy(migrations);
} catch (error) {
logExt.tryLogMessage(error);
logger.fatal(
'Encountered an error performing migrations, application will now exit',
);
process.exit(1);
}
logger.info('Migration successful, application will now exit');
process.exit(0);
};
const printMigrationStatus = async (databaseConfig: DatabaseConfiguration) => {
const database = new Database(databaseConfig);
const migrations = await database.getMigrationStatus();
if (migrations.completed.length === 1) {
logger.info('There is one completed migration');
} else {
logger.info(
`There are ${migrations.completed.length} completed migrations`,
);
}
for (const migration of migrations.completed) {
logger.info(` - ${migration}`);
}
if (migrations.pending.length === 1) {
logger.info('There is one pending migration');
} else {
logger.info(`There are ${migrations.pending.length} pending migrations`);
}
for (const migration of migrations.pending) {
logger.info(` - ${migration.typescriptFileName}`);
}
process.exit(1);
};
const entry = async () => {
const argv = await parseArgs();
initialiseLogging(argv.verbose);
const config = ConfigReader.loadConfig(
// This is a quirk in the type annotations for yargs, it incorrectly determines
// the type of configuration keys as functions if they have a function as
// default value generator, even though yargs has already evaluated those
// generators for us.
argv.config as unknown as string,
argv['appservice-config'] as unknown as string,
);
if (typeof config === 'undefined') {
logger.fatal(
'Could not load configuration file, application will now exit',
);
process.exit(1);
}
if (argv['migrate-status']) {
await printMigrationStatus(config.database);
} else if (argv.migrate) {
await migrateAndQuit(config.database, argv.migrate);
} else {
await startup(
argv['clear-plugin-cache'],
argv['auto-migrate'] as unknown as boolean,
config,
);
}
};
entry().catch((error) => {
logger.prettyError(error);
logger.fatal(
'Encountered an error during startup, application will now exit',
);
process.exit(1);
});