store games in db
This commit is contained in:
parent
126384e5bd
commit
4e528cc83d
14 changed files with 371 additions and 133 deletions
1
build/public/assets/index.63ff8630.js
Normal file
1
build/public/assets/index.63ff8630.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<title>🧩 jigsaw.hyottoko.club</title>
|
<title>🧩 jigsaw.hyottoko.club</title>
|
||||||
<script type="module" crossorigin src="/assets/index.97691b3e.js"></script>
|
<script type="module" crossorigin src="/assets/index.63ff8630.js"></script>
|
||||||
<link rel="modulepreload" href="/assets/vendor.684f7bc8.js">
|
<link rel="modulepreload" href="/assets/vendor.684f7bc8.js">
|
||||||
<link rel="stylesheet" href="/assets/index.22dc307c.css">
|
<link rel="stylesheet" href="/assets/index.22dc307c.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ function encodeGame(data) {
|
||||||
data.scoreMode,
|
data.scoreMode,
|
||||||
data.shapeMode,
|
data.shapeMode,
|
||||||
data.snapMode,
|
data.snapMode,
|
||||||
|
data.creatorUserId,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
function decodeGame(data) {
|
function decodeGame(data) {
|
||||||
|
|
@ -170,6 +171,7 @@ function decodeGame(data) {
|
||||||
scoreMode: data[6],
|
scoreMode: data[6],
|
||||||
shapeMode: data[7],
|
shapeMode: data[7],
|
||||||
snapMode: data[8],
|
snapMode: data[8],
|
||||||
|
creatorUserId: data[9],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function coordByPieceIdx(info, pieceIdx) {
|
function coordByPieceIdx(info, pieceIdx) {
|
||||||
|
|
@ -1358,6 +1360,7 @@ const get = (gameId, offset = 0) => {
|
||||||
log[0][5] = DefaultScoreMode(log[0][5]);
|
log[0][5] = DefaultScoreMode(log[0][5]);
|
||||||
log[0][6] = DefaultShapeMode(log[0][6]);
|
log[0][6] = DefaultShapeMode(log[0][6]);
|
||||||
log[0][7] = DefaultSnapMode(log[0][7]);
|
log[0][7] = DefaultSnapMode(log[0][7]);
|
||||||
|
log[0][8] = log[0][8] || null;
|
||||||
}
|
}
|
||||||
return log;
|
return log;
|
||||||
};
|
};
|
||||||
|
|
@ -1753,7 +1756,63 @@ function setDirty(gameId) {
|
||||||
function setClean(gameId) {
|
function setClean(gameId) {
|
||||||
delete dirtyGames[gameId];
|
delete dirtyGames[gameId];
|
||||||
}
|
}
|
||||||
function loadGames() {
|
function loadGamesFromDb(db) {
|
||||||
|
const gameRows = db.getMany('games');
|
||||||
|
for (const gameRow of gameRows) {
|
||||||
|
loadGameFromDb(db, gameRow.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function loadGameFromDb(db, gameId) {
|
||||||
|
const gameRow = db.get('games', { id: gameId });
|
||||||
|
let game;
|
||||||
|
try {
|
||||||
|
game = JSON.parse(gameRow.data);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
log$3.log(`[ERR] unable to load game from db ${gameId}`);
|
||||||
|
}
|
||||||
|
if (typeof game.puzzle.data.started === 'undefined') {
|
||||||
|
game.puzzle.data.started = gameRow.created;
|
||||||
|
}
|
||||||
|
if (typeof game.puzzle.data.finished === 'undefined') {
|
||||||
|
game.puzzle.data.finished = gameRow.finished;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(game.players)) {
|
||||||
|
game.players = Object.values(game.players);
|
||||||
|
}
|
||||||
|
const gameObject = storeDataToGame(game, game.creator_user_id);
|
||||||
|
GameCommon.setGame(gameObject.id, gameObject);
|
||||||
|
}
|
||||||
|
function persistGamesToDb(db) {
|
||||||
|
for (const gameId of Object.keys(dirtyGames)) {
|
||||||
|
persistGameToDb(db, gameId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function persistGameToDb(db, gameId) {
|
||||||
|
const game = GameCommon.get(gameId);
|
||||||
|
if (!game) {
|
||||||
|
log$3.error(`[ERROR] unable to persist non existing game ${gameId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (game.id in dirtyGames) {
|
||||||
|
setClean(game.id);
|
||||||
|
}
|
||||||
|
db.upsert('games', {
|
||||||
|
id: game.id,
|
||||||
|
creator_user_id: game.creatorUserId,
|
||||||
|
image_id: game.puzzle.info.image?.id,
|
||||||
|
created: game.puzzle.data.started,
|
||||||
|
finished: game.puzzle.data.finished,
|
||||||
|
data: gameToStoreData(game)
|
||||||
|
}, {
|
||||||
|
id: game.id,
|
||||||
|
});
|
||||||
|
log$3.info(`[INFO] persisted game ${game.id}`);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function loadGamesFromDisk() {
|
||||||
const files = fs.readdirSync(DATA_DIR);
|
const files = fs.readdirSync(DATA_DIR);
|
||||||
for (const f of files) {
|
for (const f of files) {
|
||||||
const m = f.match(/^([a-z0-9]+)\.json$/);
|
const m = f.match(/^([a-z0-9]+)\.json$/);
|
||||||
|
|
@ -1761,10 +1820,13 @@ function loadGames() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const gameId = m[1];
|
const gameId = m[1];
|
||||||
loadGame(gameId);
|
loadGameFromDisk(gameId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function loadGame(gameId) {
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function loadGameFromDisk(gameId) {
|
||||||
const file = `${DATA_DIR}/${gameId}.json`;
|
const file = `${DATA_DIR}/${gameId}.json`;
|
||||||
const contents = fs.readFileSync(file, 'utf-8');
|
const contents = fs.readFileSync(file, 'utf-8');
|
||||||
let game;
|
let game;
|
||||||
|
|
@ -1786,27 +1848,21 @@ function loadGame(gameId) {
|
||||||
if (!Array.isArray(game.players)) {
|
if (!Array.isArray(game.players)) {
|
||||||
game.players = Object.values(game.players);
|
game.players = Object.values(game.players);
|
||||||
}
|
}
|
||||||
const gameObject = {
|
const gameObject = storeDataToGame(game, null);
|
||||||
id: game.id,
|
|
||||||
rng: {
|
|
||||||
type: game.rng ? game.rng.type : '_fake_',
|
|
||||||
obj: game.rng ? Rng.unserialize(game.rng.obj) : new Rng(0),
|
|
||||||
},
|
|
||||||
puzzle: game.puzzle,
|
|
||||||
players: game.players,
|
|
||||||
evtInfos: {},
|
|
||||||
scoreMode: DefaultScoreMode(game.scoreMode),
|
|
||||||
shapeMode: DefaultShapeMode(game.shapeMode),
|
|
||||||
snapMode: DefaultSnapMode(game.snapMode),
|
|
||||||
};
|
|
||||||
GameCommon.setGame(gameObject.id, gameObject);
|
GameCommon.setGame(gameObject.id, gameObject);
|
||||||
}
|
}
|
||||||
function persistGames() {
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function persistGamesToDisk() {
|
||||||
for (const gameId of Object.keys(dirtyGames)) {
|
for (const gameId of Object.keys(dirtyGames)) {
|
||||||
persistGame(gameId);
|
persistGameToDisk(gameId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function persistGame(gameId) {
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function persistGameToDisk(gameId) {
|
||||||
const game = GameCommon.get(gameId);
|
const game = GameCommon.get(gameId);
|
||||||
if (!game) {
|
if (!game) {
|
||||||
log$3.error(`[ERROR] unable to persist non existing game ${gameId}`);
|
log$3.error(`[ERROR] unable to persist non existing game ${gameId}`);
|
||||||
|
|
@ -1815,7 +1871,27 @@ function persistGame(gameId) {
|
||||||
if (game.id in dirtyGames) {
|
if (game.id in dirtyGames) {
|
||||||
setClean(game.id);
|
setClean(game.id);
|
||||||
}
|
}
|
||||||
fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, JSON.stringify({
|
fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, gameToStoreData(game));
|
||||||
|
log$3.info(`[INFO] persisted game ${game.id}`);
|
||||||
|
}
|
||||||
|
function storeDataToGame(storeData, creatorUserId) {
|
||||||
|
return {
|
||||||
|
id: storeData.id,
|
||||||
|
creatorUserId,
|
||||||
|
rng: {
|
||||||
|
type: storeData.rng ? storeData.rng.type : '_fake_',
|
||||||
|
obj: storeData.rng ? Rng.unserialize(storeData.rng.obj) : new Rng(0),
|
||||||
|
},
|
||||||
|
puzzle: storeData.puzzle,
|
||||||
|
players: storeData.players,
|
||||||
|
evtInfos: {},
|
||||||
|
scoreMode: DefaultScoreMode(storeData.scoreMode),
|
||||||
|
shapeMode: DefaultShapeMode(storeData.shapeMode),
|
||||||
|
snapMode: DefaultSnapMode(storeData.snapMode),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function gameToStoreData(game) {
|
||||||
|
return JSON.stringify({
|
||||||
id: game.id,
|
id: game.id,
|
||||||
rng: {
|
rng: {
|
||||||
type: game.rng.type,
|
type: game.rng.type,
|
||||||
|
|
@ -1826,22 +1902,27 @@ function persistGame(gameId) {
|
||||||
scoreMode: game.scoreMode,
|
scoreMode: game.scoreMode,
|
||||||
shapeMode: game.shapeMode,
|
shapeMode: game.shapeMode,
|
||||||
snapMode: game.snapMode,
|
snapMode: game.snapMode,
|
||||||
}));
|
});
|
||||||
log$3.info(`[INFO] persisted game ${game.id}`);
|
|
||||||
}
|
}
|
||||||
var GameStorage = {
|
var GameStorage = {
|
||||||
loadGames,
|
// disk functions are deprecated
|
||||||
loadGame,
|
loadGamesFromDisk,
|
||||||
persistGames,
|
loadGameFromDisk,
|
||||||
persistGame,
|
persistGamesToDisk,
|
||||||
|
persistGameToDisk,
|
||||||
|
loadGamesFromDb,
|
||||||
|
loadGameFromDb,
|
||||||
|
persistGamesToDb,
|
||||||
|
persistGameToDb,
|
||||||
setDirty,
|
setDirty,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode) {
|
async function createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode, creatorUserId) {
|
||||||
const seed = Util.hash(gameId + ' ' + ts);
|
const seed = Util.hash(gameId + ' ' + ts);
|
||||||
const rng = new Rng(seed);
|
const rng = new Rng(seed);
|
||||||
return {
|
return {
|
||||||
id: gameId,
|
id: gameId,
|
||||||
|
creatorUserId,
|
||||||
rng: { type: 'Rng', obj: rng },
|
rng: { type: 'Rng', obj: rng },
|
||||||
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
|
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
|
||||||
players: [],
|
players: [],
|
||||||
|
|
@ -1851,10 +1932,10 @@ async function createGameObject(gameId, targetTiles, image, ts, scoreMode, shape
|
||||||
snapMode,
|
snapMode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
async function createGame(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode) {
|
async function createGame(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode, creatorUserId) {
|
||||||
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode);
|
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode, creatorUserId);
|
||||||
GameLog.create(gameId, ts);
|
GameLog.create(gameId, ts);
|
||||||
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode, shapeMode, snapMode);
|
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode, shapeMode, snapMode, gameObject.creatorUserId);
|
||||||
GameCommon.setGame(gameObject.id, gameObject);
|
GameCommon.setGame(gameObject.id, gameObject);
|
||||||
GameStorage.setDirty(gameId);
|
GameStorage.setDirty(gameId);
|
||||||
}
|
}
|
||||||
|
|
@ -2101,10 +2182,7 @@ const storage = multer.diskStorage({
|
||||||
});
|
});
|
||||||
const upload = multer({ storage }).single('file');
|
const upload = multer({ storage }).single('file');
|
||||||
app.get('/api/me', (req, res) => {
|
app.get('/api/me', (req, res) => {
|
||||||
let user = db.get('users', {
|
let user = getUser(db, req);
|
||||||
'client_id': req.headers['client-id'],
|
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
});
|
|
||||||
res.send({
|
res.send({
|
||||||
id: user ? user.id : null,
|
id: user ? user.id : null,
|
||||||
created: user ? user.created : null,
|
created: user ? user.created : null,
|
||||||
|
|
@ -2137,7 +2215,7 @@ app.get('/api/replay-data', async (req, res) => {
|
||||||
if (offset === 0) {
|
if (offset === 0) {
|
||||||
// also need the game
|
// also need the game
|
||||||
game = await Game.createGameObject(gameId, log[0][2], log[0][3], // must be ImageInfo
|
game = await Game.createGameObject(gameId, log[0][2], log[0][3], // must be ImageInfo
|
||||||
log[0][4], log[0][5], log[0][6], log[0][7]);
|
log[0][4], log[0][5], log[0][6], log[0][7], log[0][8]);
|
||||||
}
|
}
|
||||||
res.send({ log, game: game ? Util.encodeGame(game) : null });
|
res.send({ log, game: game ? Util.encodeGame(game) : null });
|
||||||
});
|
});
|
||||||
|
|
@ -2168,6 +2246,28 @@ app.get('/api/index-data', (req, res) => {
|
||||||
gamesFinished: games.filter(g => !!g.finished),
|
gamesFinished: games.filter(g => !!g.finished),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const getOrCreateUser = (db, req) => {
|
||||||
|
let user = getUser(db, req);
|
||||||
|
if (!user) {
|
||||||
|
db.insert('users', {
|
||||||
|
'client_id': req.headers['client-id'],
|
||||||
|
'client_secret': req.headers['client-secret'],
|
||||||
|
'created': Time.timestamp(),
|
||||||
|
});
|
||||||
|
user = getUser(db, req);
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
const getUser = (db, req) => {
|
||||||
|
let user = db.get('users', {
|
||||||
|
'client_id': req.headers['client-id'],
|
||||||
|
'client_secret': req.headers['client-secret'],
|
||||||
|
});
|
||||||
|
if (user) {
|
||||||
|
user.id = parseInt(user.id, 10);
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
};
|
||||||
const setImageTags = (db, imageId, tags) => {
|
const setImageTags = (db, imageId, tags) => {
|
||||||
tags.forEach((tag) => {
|
tags.forEach((tag) => {
|
||||||
const slug = Util.slug(tag);
|
const slug = Util.slug(tag);
|
||||||
|
|
@ -2181,21 +2281,14 @@ const setImageTags = (db, imageId, tags) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
app.post('/api/save-image', express.json(), (req, res) => {
|
app.post('/api/save-image', express.json(), (req, res) => {
|
||||||
let user = db.get('users', {
|
let user = getUser(db, req);
|
||||||
'client_id': req.headers['client-id'],
|
if (!user || !user.id) {
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
});
|
|
||||||
let userId = null;
|
|
||||||
if (user) {
|
|
||||||
userId = parseInt(user.id, 10);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(403).send({ ok: false, error: 'forbidden' });
|
res.status(403).send({ ok: false, error: 'forbidden' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = req.body;
|
const data = req.body;
|
||||||
let image = db.get('images', { id: data.id });
|
let image = db.get('images', { id: data.id });
|
||||||
if (parseInt(image.uploader_user_id, 10) !== userId) {
|
if (parseInt(image.uploader_user_id, 10) !== user.id) {
|
||||||
res.status(403).send({ ok: false, error: 'forbidden' });
|
res.status(403).send({ ok: false, error: 'forbidden' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2223,24 +2316,10 @@ app.post('/api/upload', (req, res) => {
|
||||||
log.log(err);
|
log.log(err);
|
||||||
res.status(400).send("Something went wrong!");
|
res.status(400).send("Something went wrong!");
|
||||||
}
|
}
|
||||||
let user = db.get('users', {
|
const user = getOrCreateUser(db, req);
|
||||||
'client_id': req.headers['client-id'],
|
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
});
|
|
||||||
let userId = null;
|
|
||||||
if (user) {
|
|
||||||
userId = user.id;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
userId = db.insert('users', {
|
|
||||||
'client_id': req.headers['client-id'],
|
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
'created': Time.timestamp(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const dim = await Images.getDimensions(`${UPLOAD_DIR}/${req.file.filename}`);
|
const dim = await Images.getDimensions(`${UPLOAD_DIR}/${req.file.filename}`);
|
||||||
const imageId = db.insert('images', {
|
const imageId = db.insert('images', {
|
||||||
uploader_user_id: userId,
|
uploader_user_id: user.id,
|
||||||
filename: req.file.filename,
|
filename: req.file.filename,
|
||||||
filename_original: req.file.originalname,
|
filename_original: req.file.originalname,
|
||||||
title: req.body.title || '',
|
title: req.body.title || '',
|
||||||
|
|
@ -2256,12 +2335,17 @@ app.post('/api/upload', (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.post('/api/newgame', express.json(), async (req, res) => {
|
app.post('/api/newgame', express.json(), async (req, res) => {
|
||||||
|
let user = getOrCreateUser(db, req);
|
||||||
|
if (!user || !user.id) {
|
||||||
|
res.status(403).send({ ok: false, error: 'forbidden' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
const gameSettings = req.body;
|
const gameSettings = req.body;
|
||||||
log.log(gameSettings);
|
log.log(gameSettings);
|
||||||
const gameId = Util.uniqId();
|
const gameId = Util.uniqId();
|
||||||
if (!GameCommon.exists(gameId)) {
|
if (!GameCommon.exists(gameId)) {
|
||||||
const ts = Time.timestamp();
|
const ts = Time.timestamp();
|
||||||
await Game.createGame(gameId, gameSettings.tiles, gameSettings.image, ts, gameSettings.scoreMode, gameSettings.shapeMode, gameSettings.snapMode);
|
await Game.createGame(gameId, gameSettings.tiles, gameSettings.image, ts, gameSettings.scoreMode, gameSettings.shapeMode, gameSettings.snapMode, user.id);
|
||||||
}
|
}
|
||||||
res.send({ id: gameId });
|
res.send({ id: gameId });
|
||||||
});
|
});
|
||||||
|
|
@ -2343,7 +2427,7 @@ wss.on('message', async ({ socket, data }) => {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
GameStorage.loadGames();
|
GameStorage.loadGamesFromDb(db);
|
||||||
const server = app.listen(port, hostname, () => log.log(`server running on http://${hostname}:${port}`));
|
const server = app.listen(port, hostname, () => log.log(`server running on http://${hostname}:${port}`));
|
||||||
wss.listen();
|
wss.listen();
|
||||||
const memoryUsageHuman = () => {
|
const memoryUsageHuman = () => {
|
||||||
|
|
@ -2357,7 +2441,7 @@ memoryUsageHuman();
|
||||||
// persist games in fixed interval
|
// persist games in fixed interval
|
||||||
const persistInterval = setInterval(() => {
|
const persistInterval = setInterval(() => {
|
||||||
log.log('Persisting games...');
|
log.log('Persisting games...');
|
||||||
GameStorage.persistGames();
|
GameStorage.persistGamesToDb(db);
|
||||||
memoryUsageHuman();
|
memoryUsageHuman();
|
||||||
}, config.persistence.interval);
|
}, config.persistence.interval);
|
||||||
const gracefulShutdown = (signal) => {
|
const gracefulShutdown = (signal) => {
|
||||||
|
|
@ -2365,7 +2449,7 @@ const gracefulShutdown = (signal) => {
|
||||||
log.log('clearing persist interval...');
|
log.log('clearing persist interval...');
|
||||||
clearInterval(persistInterval);
|
clearInterval(persistInterval);
|
||||||
log.log('persisting games...');
|
log.log('persisting games...');
|
||||||
GameStorage.persistGames();
|
GameStorage.persistGamesToDb(db);
|
||||||
log.log('shutting down webserver...');
|
log.log('shutting down webserver...');
|
||||||
server.close();
|
server.close();
|
||||||
log.log('shutting down websocketserver...');
|
log.log('shutting down websocketserver...');
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ function fixOne(gameId: string) {
|
||||||
|
|
||||||
log.log(g.puzzle.info.image.title, imageRow.id)
|
log.log(g.puzzle.info.image.title, imageRow.id)
|
||||||
|
|
||||||
GameStorage.persistGame(gameId)
|
GameStorage.persistGameToDb(db, gameId)
|
||||||
} else if (g.puzzle.info.image?.id) {
|
} else if (g.puzzle.info.image?.id) {
|
||||||
const imageId = g.puzzle.info.image.id
|
const imageId = g.puzzle.info.image.id
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ function fixOne(gameId: string) {
|
||||||
|
|
||||||
log.log(g.puzzle.info.image.title, imageId)
|
log.log(g.puzzle.info.image.title, imageId)
|
||||||
|
|
||||||
GameStorage.persistGame(gameId)
|
GameStorage.persistGameToDb(db, gameId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix log
|
// fix log
|
||||||
|
|
@ -81,7 +81,7 @@ function fixOne(gameId: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fix() {
|
function fix() {
|
||||||
GameStorage.loadGames()
|
GameStorage.loadGamesFromDisk()
|
||||||
GameCommon.getAllGames().forEach((game: Game) => {
|
GameCommon.getAllGames().forEach((game: Game) => {
|
||||||
fixOne(game.id)
|
fixOne(game.id)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
import GameCommon from '../src/common/GameCommon'
|
import GameCommon from '../src/common/GameCommon'
|
||||||
import { logger } from '../src/common/Util'
|
import { logger } from '../src/common/Util'
|
||||||
|
import Db from '../src/server/Db'
|
||||||
|
import { DB_FILE, DB_PATCHES_DIR } from '../src/server/Dirs'
|
||||||
import GameStorage from '../src/server/GameStorage'
|
import GameStorage from '../src/server/GameStorage'
|
||||||
|
|
||||||
const log = logger('fix_tiles.js')
|
const log = logger('fix_tiles.js')
|
||||||
|
|
||||||
|
const db = new Db(DB_FILE, DB_PATCHES_DIR)
|
||||||
|
db.patch(true)
|
||||||
|
|
||||||
function fix_tiles(gameId) {
|
function fix_tiles(gameId) {
|
||||||
GameStorage.loadGame(gameId)
|
GameStorage.loadGameFromDb(db, gameId)
|
||||||
let changed = false
|
let changed = false
|
||||||
const tiles = GameCommon.getPiecesSortedByZIndex(gameId)
|
const tiles = GameCommon.getPiecesSortedByZIndex(gameId)
|
||||||
for (let tile of tiles) {
|
for (let tile of tiles) {
|
||||||
|
|
@ -27,7 +32,7 @@ function fix_tiles(gameId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
GameStorage.persistGame(gameId)
|
GameStorage.persistGameToDb(db, gameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
27
scripts/import_games.ts
Normal file
27
scripts/import_games.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import GameCommon from '../src/common/GameCommon'
|
||||||
|
import { Game } from '../src/common/Types'
|
||||||
|
import { logger } from '../src/common/Util'
|
||||||
|
import { DB_FILE, DB_PATCHES_DIR } from '../src/server/Dirs'
|
||||||
|
import Db from '../src/server/Db'
|
||||||
|
import GameStorage from '../src/server/GameStorage'
|
||||||
|
|
||||||
|
const log = logger('import_games.ts')
|
||||||
|
|
||||||
|
console.log(DB_FILE)
|
||||||
|
|
||||||
|
const db = new Db(DB_FILE, DB_PATCHES_DIR)
|
||||||
|
db.patch(true)
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
GameStorage.loadGamesFromDisk()
|
||||||
|
GameCommon.getAllGames().forEach((game: Game) => {
|
||||||
|
if (!game.puzzle.info.image?.id) {
|
||||||
|
log.error(game.id + " has no image")
|
||||||
|
log.error(game.puzzle.info.image)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
GameStorage.persistGameToDb(db, game.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
run()
|
||||||
|
|
@ -51,6 +51,7 @@ export type EncodedGame = FixedLengthArray<[
|
||||||
ScoreMode,
|
ScoreMode,
|
||||||
ShapeMode,
|
ShapeMode,
|
||||||
SnapMode,
|
SnapMode,
|
||||||
|
number|null,
|
||||||
]>
|
]>
|
||||||
|
|
||||||
export interface ReplayData {
|
export interface ReplayData {
|
||||||
|
|
@ -72,6 +73,7 @@ interface GameRng {
|
||||||
|
|
||||||
export interface Game {
|
export interface Game {
|
||||||
id: string
|
id: string
|
||||||
|
creatorUserId: number|null
|
||||||
players: Array<EncodedPlayer>
|
players: Array<EncodedPlayer>
|
||||||
puzzle: Puzzle
|
puzzle: Puzzle
|
||||||
evtInfos: Record<string, EvtInfo>
|
evtInfos: Record<string, EvtInfo>
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ function encodeGame(data: Game): EncodedGame {
|
||||||
data.scoreMode,
|
data.scoreMode,
|
||||||
data.shapeMode,
|
data.shapeMode,
|
||||||
data.snapMode,
|
data.snapMode,
|
||||||
|
data.creatorUserId,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,6 +150,7 @@ function decodeGame(data: EncodedGame): Game {
|
||||||
scoreMode: data[6],
|
scoreMode: data[6],
|
||||||
shapeMode: data[7],
|
shapeMode: data[7],
|
||||||
snapMode: data[8],
|
snapMode: data[8],
|
||||||
|
creatorUserId: data[9],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
11
src/dbpatches/04_games.sqlite
Normal file
11
src/dbpatches/04_games.sqlite
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
CREATE TABLE games (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
|
||||||
|
creator_user_id INTEGER,
|
||||||
|
image_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
created TIMESTAMP NOT NULL,
|
||||||
|
finished TIMESTAMP NOT NULL,
|
||||||
|
|
||||||
|
data TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
@ -16,12 +16,14 @@ async function createGameObject(
|
||||||
ts: Timestamp,
|
ts: Timestamp,
|
||||||
scoreMode: ScoreMode,
|
scoreMode: ScoreMode,
|
||||||
shapeMode: ShapeMode,
|
shapeMode: ShapeMode,
|
||||||
snapMode: SnapMode
|
snapMode: SnapMode,
|
||||||
|
creatorUserId: number|null
|
||||||
): Promise<Game> {
|
): Promise<Game> {
|
||||||
const seed = Util.hash(gameId + ' ' + ts)
|
const seed = Util.hash(gameId + ' ' + ts)
|
||||||
const rng = new Rng(seed)
|
const rng = new Rng(seed)
|
||||||
return {
|
return {
|
||||||
id: gameId,
|
id: gameId,
|
||||||
|
creatorUserId,
|
||||||
rng: { type: 'Rng', obj: rng },
|
rng: { type: 'Rng', obj: rng },
|
||||||
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
|
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
|
||||||
players: [],
|
players: [],
|
||||||
|
|
@ -39,7 +41,8 @@ async function createGame(
|
||||||
ts: Timestamp,
|
ts: Timestamp,
|
||||||
scoreMode: ScoreMode,
|
scoreMode: ScoreMode,
|
||||||
shapeMode: ShapeMode,
|
shapeMode: ShapeMode,
|
||||||
snapMode: SnapMode
|
snapMode: SnapMode,
|
||||||
|
creatorUserId: number
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const gameObject = await createGameObject(
|
const gameObject = await createGameObject(
|
||||||
gameId,
|
gameId,
|
||||||
|
|
@ -48,7 +51,8 @@ async function createGame(
|
||||||
ts,
|
ts,
|
||||||
scoreMode,
|
scoreMode,
|
||||||
shapeMode,
|
shapeMode,
|
||||||
snapMode
|
snapMode,
|
||||||
|
creatorUserId
|
||||||
)
|
)
|
||||||
|
|
||||||
GameLog.create(gameId, ts)
|
GameLog.create(gameId, ts)
|
||||||
|
|
@ -61,7 +65,8 @@ async function createGame(
|
||||||
ts,
|
ts,
|
||||||
scoreMode,
|
scoreMode,
|
||||||
shapeMode,
|
shapeMode,
|
||||||
snapMode
|
snapMode,
|
||||||
|
gameObject.creatorUserId
|
||||||
)
|
)
|
||||||
|
|
||||||
GameCommon.setGame(gameObject.id, gameObject)
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ const get = (
|
||||||
log[0][5] = DefaultScoreMode(log[0][5])
|
log[0][5] = DefaultScoreMode(log[0][5])
|
||||||
log[0][6] = DefaultShapeMode(log[0][6])
|
log[0][6] = DefaultShapeMode(log[0][6])
|
||||||
log[0][7] = DefaultSnapMode(log[0][7])
|
log[0][7] = DefaultSnapMode(log[0][7])
|
||||||
|
log[0][8] = log[0][8] || null
|
||||||
}
|
}
|
||||||
return log
|
return log
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import Util, { logger } from './../common/Util'
|
||||||
import { Rng } from './../common/Rng'
|
import { Rng } from './../common/Rng'
|
||||||
import { DATA_DIR } from './Dirs'
|
import { DATA_DIR } from './Dirs'
|
||||||
import Time from './../common/Time'
|
import Time from './../common/Time'
|
||||||
|
import Db from './Db'
|
||||||
|
|
||||||
const log = logger('GameStorage.js')
|
const log = logger('GameStorage.js')
|
||||||
|
|
||||||
|
|
@ -15,8 +16,73 @@ function setDirty(gameId: string): void {
|
||||||
function setClean(gameId: string): void {
|
function setClean(gameId: string): void {
|
||||||
delete dirtyGames[gameId]
|
delete dirtyGames[gameId]
|
||||||
}
|
}
|
||||||
|
function loadGamesFromDb(db: Db): void {
|
||||||
|
const gameRows = db.getMany('games')
|
||||||
|
for (const gameRow of gameRows) {
|
||||||
|
loadGameFromDb(db, gameRow.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadGames(): void {
|
function loadGameFromDb(db: Db, gameId: string): void {
|
||||||
|
const gameRow = db.get('games', {id: gameId})
|
||||||
|
|
||||||
|
let game
|
||||||
|
try {
|
||||||
|
game = JSON.parse(gameRow.data)
|
||||||
|
} catch {
|
||||||
|
log.log(`[ERR] unable to load game from db ${gameId}`);
|
||||||
|
}
|
||||||
|
if (typeof game.puzzle.data.started === 'undefined') {
|
||||||
|
game.puzzle.data.started = gameRow.created
|
||||||
|
}
|
||||||
|
if (typeof game.puzzle.data.finished === 'undefined') {
|
||||||
|
game.puzzle.data.finished = gameRow.finished
|
||||||
|
}
|
||||||
|
if (!Array.isArray(game.players)) {
|
||||||
|
game.players = Object.values(game.players)
|
||||||
|
}
|
||||||
|
|
||||||
|
const gameObject: Game = storeDataToGame(game, game.creator_user_id)
|
||||||
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistGamesToDb(db: Db): void {
|
||||||
|
for (const gameId of Object.keys(dirtyGames)) {
|
||||||
|
persistGameToDb(db, gameId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistGameToDb(db: Db, gameId: string): void {
|
||||||
|
const game: Game|null = GameCommon.get(gameId)
|
||||||
|
if (!game) {
|
||||||
|
log.error(`[ERROR] unable to persist non existing game ${gameId}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game.id in dirtyGames) {
|
||||||
|
setClean(game.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.upsert('games', {
|
||||||
|
id: game.id,
|
||||||
|
|
||||||
|
creator_user_id: game.creatorUserId,
|
||||||
|
image_id: game.puzzle.info.image?.id,
|
||||||
|
|
||||||
|
created: game.puzzle.data.started,
|
||||||
|
finished: game.puzzle.data.finished,
|
||||||
|
|
||||||
|
data: gameToStoreData(game)
|
||||||
|
}, {
|
||||||
|
id: game.id,
|
||||||
|
})
|
||||||
|
log.info(`[INFO] persisted game ${game.id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function loadGamesFromDisk(): void {
|
||||||
const files = fs.readdirSync(DATA_DIR)
|
const files = fs.readdirSync(DATA_DIR)
|
||||||
for (const f of files) {
|
for (const f of files) {
|
||||||
const m = f.match(/^([a-z0-9]+)\.json$/)
|
const m = f.match(/^([a-z0-9]+)\.json$/)
|
||||||
|
|
@ -24,11 +90,14 @@ function loadGames(): void {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const gameId = m[1]
|
const gameId = m[1]
|
||||||
loadGame(gameId)
|
loadGameFromDisk(gameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadGame(gameId: string): void {
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function loadGameFromDisk(gameId: string): void {
|
||||||
const file = `${DATA_DIR}/${gameId}.json`
|
const file = `${DATA_DIR}/${gameId}.json`
|
||||||
const contents = fs.readFileSync(file, 'utf-8')
|
const contents = fs.readFileSync(file, 'utf-8')
|
||||||
let game
|
let game
|
||||||
|
|
@ -49,29 +118,23 @@ function loadGame(gameId: string): void {
|
||||||
if (!Array.isArray(game.players)) {
|
if (!Array.isArray(game.players)) {
|
||||||
game.players = Object.values(game.players)
|
game.players = Object.values(game.players)
|
||||||
}
|
}
|
||||||
const gameObject: Game = {
|
const gameObject: Game = storeDataToGame(game, null)
|
||||||
id: game.id,
|
|
||||||
rng: {
|
|
||||||
type: game.rng ? game.rng.type : '_fake_',
|
|
||||||
obj: game.rng ? Rng.unserialize(game.rng.obj) : new Rng(0),
|
|
||||||
},
|
|
||||||
puzzle: game.puzzle,
|
|
||||||
players: game.players,
|
|
||||||
evtInfos: {},
|
|
||||||
scoreMode: DefaultScoreMode(game.scoreMode),
|
|
||||||
shapeMode: DefaultShapeMode(game.shapeMode),
|
|
||||||
snapMode: DefaultSnapMode(game.snapMode),
|
|
||||||
}
|
|
||||||
GameCommon.setGame(gameObject.id, gameObject)
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
function persistGames(): void {
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function persistGamesToDisk(): void {
|
||||||
for (const gameId of Object.keys(dirtyGames)) {
|
for (const gameId of Object.keys(dirtyGames)) {
|
||||||
persistGame(gameId)
|
persistGameToDisk(gameId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function persistGame(gameId: string): void {
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
function persistGameToDisk(gameId: string): void {
|
||||||
const game = GameCommon.get(gameId)
|
const game = GameCommon.get(gameId)
|
||||||
if (!game) {
|
if (!game) {
|
||||||
log.error(`[ERROR] unable to persist non existing game ${gameId}`)
|
log.error(`[ERROR] unable to persist non existing game ${gameId}`)
|
||||||
|
|
@ -81,7 +144,29 @@ function persistGame(gameId: string): void {
|
||||||
if (game.id in dirtyGames) {
|
if (game.id in dirtyGames) {
|
||||||
setClean(game.id)
|
setClean(game.id)
|
||||||
}
|
}
|
||||||
fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, JSON.stringify({
|
fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, gameToStoreData(game))
|
||||||
|
log.info(`[INFO] persisted game ${game.id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeDataToGame(storeData: any, creatorUserId: number|null): Game {
|
||||||
|
return {
|
||||||
|
id: storeData.id,
|
||||||
|
creatorUserId,
|
||||||
|
rng: {
|
||||||
|
type: storeData.rng ? storeData.rng.type : '_fake_',
|
||||||
|
obj: storeData.rng ? Rng.unserialize(storeData.rng.obj) : new Rng(0),
|
||||||
|
},
|
||||||
|
puzzle: storeData.puzzle,
|
||||||
|
players: storeData.players,
|
||||||
|
evtInfos: {},
|
||||||
|
scoreMode: DefaultScoreMode(storeData.scoreMode),
|
||||||
|
shapeMode: DefaultShapeMode(storeData.shapeMode),
|
||||||
|
snapMode: DefaultSnapMode(storeData.snapMode),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gameToStoreData(game: Game): string {
|
||||||
|
return JSON.stringify({
|
||||||
id: game.id,
|
id: game.id,
|
||||||
rng: {
|
rng: {
|
||||||
type: game.rng.type,
|
type: game.rng.type,
|
||||||
|
|
@ -92,14 +177,20 @@ function persistGame(gameId: string): void {
|
||||||
scoreMode: game.scoreMode,
|
scoreMode: game.scoreMode,
|
||||||
shapeMode: game.shapeMode,
|
shapeMode: game.shapeMode,
|
||||||
snapMode: game.snapMode,
|
snapMode: game.snapMode,
|
||||||
}))
|
});
|
||||||
log.info(`[INFO] persisted game ${game.id}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
loadGames,
|
// disk functions are deprecated
|
||||||
loadGame,
|
loadGamesFromDisk,
|
||||||
persistGames,
|
loadGameFromDisk,
|
||||||
persistGame,
|
persistGamesToDisk,
|
||||||
|
persistGameToDisk,
|
||||||
|
|
||||||
|
loadGamesFromDb,
|
||||||
|
loadGameFromDb,
|
||||||
|
persistGamesToDb,
|
||||||
|
persistGameToDb,
|
||||||
|
|
||||||
setDirty,
|
setDirty,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,7 @@ const storage = multer.diskStorage({
|
||||||
const upload = multer({storage}).single('file');
|
const upload = multer({storage}).single('file');
|
||||||
|
|
||||||
app.get('/api/me', (req, res): void => {
|
app.get('/api/me', (req, res): void => {
|
||||||
let user = db.get('users', {
|
let user = getUser(db, req)
|
||||||
'client_id': req.headers['client-id'],
|
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
})
|
|
||||||
res.send({
|
res.send({
|
||||||
id: user ? user.id : null,
|
id: user ? user.id : null,
|
||||||
created: user ? user.created : null,
|
created: user ? user.created : null,
|
||||||
|
|
@ -103,6 +100,7 @@ app.get('/api/replay-data', async (req, res): Promise<void> => {
|
||||||
log[0][5],
|
log[0][5],
|
||||||
log[0][6],
|
log[0][6],
|
||||||
log[0][7],
|
log[0][7],
|
||||||
|
log[0][8], // creatorUserId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
res.send({ log, game: game ? Util.encodeGame(game) : null })
|
res.send({ log, game: game ? Util.encodeGame(game) : null })
|
||||||
|
|
@ -144,6 +142,30 @@ interface SaveImageRequestData {
|
||||||
tags: string[]
|
tags: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getOrCreateUser = (db: Db, req: any): any => {
|
||||||
|
let user = getUser(db, req)
|
||||||
|
if (!user) {
|
||||||
|
db.insert('users', {
|
||||||
|
'client_id': req.headers['client-id'],
|
||||||
|
'client_secret': req.headers['client-secret'],
|
||||||
|
'created': Time.timestamp(),
|
||||||
|
})
|
||||||
|
user = getUser(db, req)
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUser = (db: Db, req: any): any => {
|
||||||
|
let user = db.get('users', {
|
||||||
|
'client_id': req.headers['client-id'],
|
||||||
|
'client_secret': req.headers['client-secret'],
|
||||||
|
})
|
||||||
|
if (user) {
|
||||||
|
user.id = parseInt(user.id, 10)
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
const setImageTags = (db: Db, imageId: number, tags: string[]): void => {
|
const setImageTags = (db: Db, imageId: number, tags: string[]): void => {
|
||||||
tags.forEach((tag: string) => {
|
tags.forEach((tag: string) => {
|
||||||
const slug = Util.slug(tag)
|
const slug = Util.slug(tag)
|
||||||
|
|
@ -158,21 +180,15 @@ const setImageTags = (db: Db, imageId: number, tags: string[]): void => {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.post('/api/save-image', express.json(), (req, res): void => {
|
app.post('/api/save-image', express.json(), (req, res): void => {
|
||||||
let user = db.get('users', {
|
let user = getUser(db, req)
|
||||||
'client_id': req.headers['client-id'],
|
if (!user || !user.id) {
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
})
|
|
||||||
let userId: number|null = null
|
|
||||||
if (user) {
|
|
||||||
userId = parseInt(user.id, 10)
|
|
||||||
} else {
|
|
||||||
res.status(403).send({ ok: false, error: 'forbidden' })
|
res.status(403).send({ ok: false, error: 'forbidden' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = req.body as SaveImageRequestData
|
const data = req.body as SaveImageRequestData
|
||||||
let image = db.get('images', {id: data.id})
|
let image = db.get('images', {id: data.id})
|
||||||
if (parseInt(image.uploader_user_id, 10) !== userId) {
|
if (parseInt(image.uploader_user_id, 10) !== user.id) {
|
||||||
res.status(403).send({ ok: false, error: 'forbidden' })
|
res.status(403).send({ ok: false, error: 'forbidden' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -205,26 +221,13 @@ app.post('/api/upload', (req, res): void => {
|
||||||
res.status(400).send("Something went wrong!");
|
res.status(400).send("Something went wrong!");
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = db.get('users', {
|
const user = getOrCreateUser(db, req)
|
||||||
'client_id': req.headers['client-id'],
|
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
})
|
|
||||||
let userId: number|null = null
|
|
||||||
if (user) {
|
|
||||||
userId = user.id
|
|
||||||
} else {
|
|
||||||
userId = db.insert('users', {
|
|
||||||
'client_id': req.headers['client-id'],
|
|
||||||
'client_secret': req.headers['client-secret'],
|
|
||||||
'created': Time.timestamp(),
|
|
||||||
}) as number
|
|
||||||
}
|
|
||||||
|
|
||||||
const dim = await Images.getDimensions(
|
const dim = await Images.getDimensions(
|
||||||
`${UPLOAD_DIR}/${req.file.filename}`
|
`${UPLOAD_DIR}/${req.file.filename}`
|
||||||
)
|
)
|
||||||
const imageId = db.insert('images', {
|
const imageId = db.insert('images', {
|
||||||
uploader_user_id: userId,
|
uploader_user_id: user.id,
|
||||||
filename: req.file.filename,
|
filename: req.file.filename,
|
||||||
filename_original: req.file.originalname,
|
filename_original: req.file.originalname,
|
||||||
title: req.body.title || '',
|
title: req.body.title || '',
|
||||||
|
|
@ -243,6 +246,12 @@ app.post('/api/upload', (req, res): void => {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/api/newgame', express.json(), async (req, res): Promise<void> => {
|
app.post('/api/newgame', express.json(), async (req, res): Promise<void> => {
|
||||||
|
let user = getOrCreateUser(db, req)
|
||||||
|
if (!user || !user.id) {
|
||||||
|
res.status(403).send({ ok: false, error: 'forbidden' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const gameSettings = req.body as GameSettings
|
const gameSettings = req.body as GameSettings
|
||||||
log.log(gameSettings)
|
log.log(gameSettings)
|
||||||
const gameId = Util.uniqId()
|
const gameId = Util.uniqId()
|
||||||
|
|
@ -256,6 +265,7 @@ app.post('/api/newgame', express.json(), async (req, res): Promise<void> => {
|
||||||
gameSettings.scoreMode,
|
gameSettings.scoreMode,
|
||||||
gameSettings.shapeMode,
|
gameSettings.shapeMode,
|
||||||
gameSettings.snapMode,
|
gameSettings.snapMode,
|
||||||
|
user.id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
res.send({ id: gameId })
|
res.send({ id: gameId })
|
||||||
|
|
@ -355,7 +365,7 @@ wss.on('message', async (
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
GameStorage.loadGames()
|
GameStorage.loadGamesFromDb(db)
|
||||||
const server = app.listen(
|
const server = app.listen(
|
||||||
port,
|
port,
|
||||||
hostname,
|
hostname,
|
||||||
|
|
@ -378,7 +388,7 @@ memoryUsageHuman()
|
||||||
// persist games in fixed interval
|
// persist games in fixed interval
|
||||||
const persistInterval = setInterval(() => {
|
const persistInterval = setInterval(() => {
|
||||||
log.log('Persisting games...')
|
log.log('Persisting games...')
|
||||||
GameStorage.persistGames()
|
GameStorage.persistGamesToDb(db)
|
||||||
|
|
||||||
memoryUsageHuman()
|
memoryUsageHuman()
|
||||||
}, config.persistence.interval)
|
}, config.persistence.interval)
|
||||||
|
|
@ -390,7 +400,7 @@ const gracefulShutdown = (signal: string): void => {
|
||||||
clearInterval(persistInterval)
|
clearInterval(persistInterval)
|
||||||
|
|
||||||
log.log('persisting games...')
|
log.log('persisting games...')
|
||||||
GameStorage.persistGames()
|
GameStorage.persistGamesToDb(db)
|
||||||
|
|
||||||
log.log('shutting down webserver...')
|
log.log('shutting down webserver...')
|
||||||
server.close()
|
server.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue