-
Notifications
You must be signed in to change notification settings - Fork 136
Expand file tree
/
Copy pathindex.ts
More file actions
199 lines (182 loc) Β· 5.88 KB
/
Copy pathindex.ts
File metadata and controls
199 lines (182 loc) Β· 5.88 KB
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//
// Copyright (c) Microsoft.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import debug from 'debug';
import express from 'express';
import fs from 'fs';
import http from 'http';
import https from 'https';
import path from 'path';
import { fileURLToPath } from 'url';
import configResolver from './lib/config/index.js';
import { installConsoleRedaction, installDebugRedaction } from './lib/utils.js';
import initialize from './middleware/initialize.js';
import { tryInitializeCompanySpecificDeployment } from './middleware/companySpecificDeployment.js';
import type { ExecutionEnvironment, IReposApplication, SiteConfiguration } from './interfaces/index.js';
installConsoleRedaction();
installDebugRedaction(debug);
const debugStartup = debug('startup');
const debugServer = debug('g:server');
export type StartupWebStackOptions = {
success?: () => Promise<void>;
skipStartup?: boolean;
};
// We are not currently exporting this module as a library - it's just a site.
// export * from './interfaces';
type InitializeCall = (
executionEnvironment: ExecutionEnvironment,
app: IReposApplication,
config: SiteConfiguration,
configurationError: Error
) => Promise<ExecutionEnvironment>;
export function startupWebStack(options?: StartupWebStackOptions) {
// essentially the standard Express ./bin/www
options = options || {};
debugStartup('starting web framework...');
const app = express() as any as IReposApplication;
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
app.initializeApplication = initializeApp.bind(undefined /*, app*/, dirname);
(app as any).expressInstance = express;
app.startupApplication = commonStartup.bind(
undefined,
app.initializeApplication,
false /* not a job */,
true /* enable all apps */,
app
);
function normalizePort(val: string) {
const port = parseInt(val, 10);
if (isNaN(port)) {
return val; // named pipe
}
if (port >= 0) {
return port; // port number
}
return false;
}
app.startServer = function startWebServer(): Promise<void> {
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
return new Promise((resolve, reject) => {
try {
const server: https.Server | http.Server =
process.env.USE_LOCAL_HTTPS === 'true'
? https.createServer(
{
key: fs.readFileSync(path.join(dirname, process.env.CERT_PATH_FROM_DIST_BIN, 'key.pem')),
cert: fs.readFileSync(path.join(dirname, process.env.CERT_PATH_FROM_DIST_BIN, 'cert.pem')),
},
app
)
: http.createServer(app);
server.on('error', (error) => {
console.error(`http.server.error: ${error}`);
if (error['syscall'] !== 'listen') {
return reject(error);
}
const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error['code']) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
return reject(error);
}
});
server.on('listening', () => {
const addr = server.address();
const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
debugServer('listening on ' + bind);
return resolve();
});
server.listen(port);
} catch (error) {
return reject(error);
}
});
};
const port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
if (options.skipStartup) {
return app;
}
app.startupApplication().then(async function ready() {
if (options?.success) {
await options?.success();
} else {
debugStartup('web stack is up.');
}
});
return app;
}
function initializeApp(
dirname: string,
executionEnvironment: ExecutionEnvironment,
app: IReposApplication,
config: SiteConfiguration,
configurationError: Error
) {
return initialize(executionEnvironment, app, dirname, config, configurationError);
}
export async function commonStartup(
call: InitializeCall,
isJob: boolean,
enableAllGitHubApps: boolean,
app?: IReposApplication,
entrypointName?: string
) {
await tryInitializeCompanySpecificDeployment();
const executionEnvironment: ExecutionEnvironment = {
isJob,
enableAllGitHubApps,
entrypointName,
//
expressApplication: app,
//
providers: undefined,
skipModules: new Set(),
//
started: new Date(),
};
let painlessConfigResolver = null;
try {
painlessConfigResolver = await configResolver();
} catch (error) {
const extra = error?.path ? ` (${error.path})` : '';
console.warn(`Painless config resolver initialization error${extra}:`);
console.error(error);
throw error;
}
let config: any = null;
let configurationError: Error = null;
try {
config = await painlessConfigResolver.resolve();
} catch (error) {
configurationError = error;
}
if (isJob && !app) {
executionEnvironment.skipModules.add('web');
}
try {
await call(executionEnvironment, app, config, configurationError);
} catch (startupError) {
console.error(`Startup error: ${startupError}`);
if (startupError.stack) {
const containsUndefined = startupError.stack.includes('undefined');
const containsInitialize = startupError.stack.includes('at initialize (');
if (containsUndefined || !containsInitialize) {
console.error(startupError.stack);
}
}
process.exit(1);
}
return executionEnvironment;
}