Files
api/app/server.js
Alexis Tyler 1da02e1610 add license header
Signed-off-by: Alexis Tyler <xo@wvvw.me>
2019-06-14 11:08:16 +09:30

110 lines
3.4 KiB
JavaScript

/*
* Copyright 2005-2019, Lime Technology
* Copyright 2018-2019, Alexis Tyler
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* The Graphql server.
*/
module.exports = function ($injector, fs, net, express, config, log, getEndpoints, stoppable) {
const app = express();
const port = config.get('graphql-api-port');
let server;
const ApolloServer = $injector.resolve('apollo-server-express').ApolloServer;
const graphql = $injector.resolvePath(__dirname + '/graphql');
// Mount graph endpoint
const graphApp = new ApolloServer(graphql);
graphApp.applyMiddleware({ app });
// List all endpoints at start of server
app.get('/', (req, res, next) => {
return res.send(getEndpoints(app));
});
// Handle errors by logging them and returning a 500.
app.use(function (err, req, res, next) {
log.error(err);
if (err.stack) {
err.stackTrace = err.stack;
}
res.status(error.status || 500).send(err);
});
// Return an object with start and stop methods.
return {
start() {
server = stoppable(app.listen(port, () => {
// Downgrade process user to owner of this file
return fs.stat(__filename, (err, stats) => {
if (err) {
throw err;
}
return process.setuid(stats.uid);
});
}));
// Port is a UNIX socket file
if (isNaN(parseInt(port, 10))) {
server.on('listening', () => {
// In production this will let pm2 know we're ready
if (process.send) {
process.send('ready');
}
// Set permissions
return fs.chmodSync(port, 777);
});
// Double-check EADDRINUSE
server.on('error', error => {
if (error.code !== 'EADDRINUSE') {
throw error;
}
net.connect({
path: port
}, () => {
// Really in use: re-throw
throw error;
}).on('error', error => {
if (error.code !== 'ECONNREFUSED') {
throw error;
}
// Not in use: delete it and re-listen
fs.unlinkSync(port);
server.listen(port);
});
});
}
return server;
},
stop() {
// Stop the server from accepting new connections and close existing connections
return server.close(err => {
if (err) {
log.error(err);
// Exit with error (code 1)
// eslint-disable-next-line
process.exit(1);
}
log.info('Server shutting down..');
// Gracefully exit
process.exitCode = 0;
});
}
};
};