homegames-core
Version:
Play games at home
142 lines (112 loc) • 4.72 kB
JavaScript
const https = require('https');
const GameSession = require('./GameSession');
const crypto = require('crypto');
const fs = require('fs');
const { socketServer } = require('./util/socket');
const { reportBug } = require('./common/util');
const { getService } = require('./services/index');
const process = require('process');
let lastMessage;
let gameSession;
const path = require('path');
const { log, getConfigValue, getAppDataPath } = require('homegames-common');
const ERROR_REPORTING_ENABLED = getConfigValue('ERROR_REPORTING', false);
const HTTPS_ENABLED = getConfigValue('HTTPS_ENABLED', false);
const sendProcessMessage = (msg) => {
process.send(JSON.stringify(msg));
};
const startServer = (sessionInfo) => {
let gameInstance;
log.info('Starting server with this info', sessionInfo);
const addAsset = (key, asset) => new Promise((resolve, reject) => {
gameSession.handleNewAsset(key, asset).then(resolve).catch(reject);
});
const appDataPath = getAppDataPath();
process.env.SQUISH_PATH = require.resolve(`squish-${sessionInfo.squishVersion}`);
try {
log.info("THIS IS SESSION INFO");
log.info(sessionInfo);
let services = {};
if (sessionInfo.gamePath) {
const _gameClass = require(sessionInfo.gamePath);
if (_gameClass.metadata) {
const requestedServices = _gameClass.metadata().services || [];
requestedServices.forEach(s => services[s] = getService(s));
}
let saveData;
const savePath = crypto.createHash('md5').update(sessionInfo.gamePath).digest('hex');
const saveDataRoot = path.join(appDataPath, '.save-data');
const existingGameSaveDataPath = path.join(saveDataRoot, savePath);
if (!fs.existsSync(saveDataRoot)) {
fs.mkdirSync(saveDataRoot);
}
const saveGame = (data) => new Promise((resolve, reject) => {
// lol. read parsed json to validate json
const jsonData = JSON.stringify(JSON.parse(JSON.stringify(data)));
fs.writeFileSync(existingGameSaveDataPath, jsonData);
});
if (fs.existsSync(existingGameSaveDataPath)) {
try {
const stuff = fs.readFileSync(existingGameSaveDataPath);
saveData = JSON.parse(stuff);
} catch (err) {
console.log("Error reading save data");
console.log(err);
}
}
gameInstance = new _gameClass({ addAsset, saveGame, saveData, services });
} else {
const _gameClass = games[sessionInfo.key];
if (_gameClass.metadata) {
const requestedServices = _gameClass.metadata().services || [];
requestedServices.forEach(s => services[s] = getService(s));
}
gameInstance = new _gameClass({ addAsset, services });
}
gameSession = new GameSession(gameInstance, sessionInfo.port, sessionInfo.username);
} catch (err) {
log.error('Error instantiating game session');
log.error(err);
if (ERROR_REPORTING_ENABLED) {
reportBug(`Exception: ${err.message} Stack: ${err.stack}`);
}
}
if (gameSession) {
gameSession.initialize(() => {
socketServer(gameSession, sessionInfo.port, () => {
sendProcessMessage({
'success': true
});
}, HTTPS_ENABLED ? sessionInfo.certPath : null, sessionInfo.username);
});
}
};
process.on('message', (msg) => {
lastMessage = new Date();
const message = JSON.parse(msg);
if (message.key) {
startServer(message);
} else {
if (message.api) {
if (message.api === 'getPlayers') {
process.send(JSON.stringify({
'payload': Object.values(gameSession.players).map(p => { return {'id': p.id, 'name': p.info.name}; }),
'requestId': message.requestId
}));
}
}
}
});
process.on('error', (err) => {
log.error('error happened', err);
});
const checkPulse = () => {
if (!gameSession || (Object.values(gameSession.players).length == 0 && Object.values(gameSession.spectators).length == 0) || !lastMessage || new Date() - lastMessage > 5000) {
log.info('discontinuing myself');
process.exit(0);
}
};
// short grace period of ten seconds to allow the first client to connect before checking heartbeat
setTimeout(() => {
setInterval(checkPulse, 10 * 1000);
}, 2000);