214 lines
5.7 KiB
JavaScript
214 lines
5.7 KiB
JavaScript
var config = { port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765 };
|
|
|
|
var fs = require('fs');
|
|
var Gun = require('gun');
|
|
var SEA = require('gun/sea');
|
|
var NTS = require('gun/nts');
|
|
var rtc = require('gun/lib/webrtc');
|
|
|
|
var sqlite3 = require('./sqlite3-promises');
|
|
|
|
if(process.env.HTTPS_KEY){
|
|
config.key = fs.readFileSync(process.env.HTTPS_KEY);
|
|
config.cert = fs.readFileSync(process.env.HTTPS_CERT);
|
|
config.server = require('https').createServer(config, Gun.serve(__dirname));
|
|
} else {
|
|
config.server = require('http').createServer(Gun.serve(__dirname));
|
|
}
|
|
|
|
Gun.chain.onWithCancel = (function() {
|
|
function cancelCallback(data,key,msg,ev) {
|
|
if (ev && typeof ev.off === 'function') {
|
|
ev.off();
|
|
}
|
|
}
|
|
|
|
return function(tag, arg, eas, as) {
|
|
if (typeof tag === 'function') {
|
|
let callback = tag;
|
|
const cancelEv = function() {
|
|
callback = cancelCallback;
|
|
};
|
|
const wrapper = function() {
|
|
return callback.apply(this, arguments);
|
|
};
|
|
this.on(wrapper, arg, eas, as);
|
|
return cancelEv;
|
|
} else {
|
|
this.on(tag, arg, eas, as);
|
|
return null;
|
|
}
|
|
};
|
|
})();
|
|
|
|
var appendJournal = (function() {
|
|
let lastJournalText = null;
|
|
return function appendJournal(text) {
|
|
if (text !== lastJournalText) {
|
|
fs.appendFileSync('journal/journal.txt', text + '\n');
|
|
lastJournalText = text;
|
|
}
|
|
};
|
|
})();
|
|
|
|
var gun = Gun({
|
|
web: config.server.listen(config.port),
|
|
peers: ['https://jessemcdonald.info/gun'],
|
|
});
|
|
console.log('Relay peer started on port ' + config.port + ' with /gun');
|
|
|
|
function logIn(msg){
|
|
console.log(`in msg:${JSON.stringify(msg)}.........`);
|
|
}
|
|
|
|
function logOut(msg){
|
|
console.log(`out msg:${JSON.stringify(msg)}.........`);
|
|
}
|
|
|
|
function logPeers() {
|
|
console.log(`Peers: ${Object.keys(gun._.opt.peers).join(', ')}`);
|
|
}
|
|
|
|
function logData() {
|
|
console.log(`In Memory: ${JSON.stringify(gun._.graph)}`);
|
|
}
|
|
|
|
//gun._.on('in', logIn);
|
|
//gun._.on('out', logOut);
|
|
|
|
//setInterval(logPeers, 5000); //Log peer list every 5 secs
|
|
//setInterval(logData, 20000); //Log gun graph every 20 secs
|
|
|
|
function logDbError(label) {
|
|
return function(err) {
|
|
console.error(label + ':', ((err && err.message) || err));
|
|
};
|
|
}
|
|
|
|
const dbInit = (async function dbInit() {
|
|
const db = await sqlite3.openAsync('./pacosako.db');
|
|
|
|
await db.runAsync(`
|
|
CREATE TABLE IF NOT EXISTS games (
|
|
gameId TEXT PRIMARY KEY,
|
|
board TEXT
|
|
)
|
|
`);
|
|
|
|
await db.runAsync(`
|
|
CREATE TABLE IF NOT EXISTS meta (
|
|
gameId TEXT PRIMARY KEY,
|
|
lightName TEXT NOT NULL,
|
|
darkName TEXT NOT NULL,
|
|
moves INTEGER NOT NULL,
|
|
status TEXT,
|
|
timestamp INTEGER NOT NULL
|
|
)
|
|
`);
|
|
|
|
console.log('Connected to the SQLite database.');
|
|
|
|
return db;
|
|
})().catch(logDbError('dbInit'));
|
|
|
|
async function logAllMeta() {
|
|
const db = await dbInit;
|
|
try {
|
|
for await (const row of db.eachAsync(`SELECT * FROM meta ORDER BY timestamp DESC`)) {
|
|
console.log(JSON.stringify(row));
|
|
}
|
|
} catch(err) {
|
|
logDbError('logAllMeta')(err);
|
|
}
|
|
}
|
|
|
|
//logAllMeta();
|
|
|
|
async function updateMeta(gameId, meta) {
|
|
const db = await dbInit;
|
|
|
|
const insertSql =
|
|
`INSERT OR REPLACE INTO meta
|
|
( gameId, lightName, darkName, moves, status, timestamp)
|
|
VALUES
|
|
($gameId, $lightName, $darkName, $moves, $status, $timestamp)`;
|
|
await db.runAsync(insertSql, {
|
|
$gameId: gameId,
|
|
$lightName: String(meta.lightName || ''),
|
|
$darkName: String(meta.darkName || ''),
|
|
$moves: Number(meta.moves) || 0,
|
|
$status: (meta.status ? String(meta.status) : null),
|
|
$timestamp: Number(meta.timestamp) || 0,
|
|
});
|
|
|
|
return db;
|
|
}
|
|
|
|
async function updateGame(gameId, moves) {
|
|
const db = await dbInit;
|
|
|
|
const insertSql =
|
|
`INSERT OR REPLACE INTO games (gameId, board) VALUES ($gameId, $board)`;
|
|
await db.runAsync(insertSql, {
|
|
$gameId: gameId,
|
|
$board: JSON.stringify(moves),
|
|
});
|
|
|
|
return db;
|
|
}
|
|
|
|
const PacoSakoUUID = 'b425b812-6bdb-11ea-9414-6f946662bac3';
|
|
|
|
let cancellers = {};
|
|
|
|
gun.get(PacoSakoUUID + '/meta').on(function(meta) {
|
|
for (const gameId in meta) { /* use of 'in' here is deliberate */
|
|
/* 'gameId' may include extra GUN fields like '_' */
|
|
if (gameId.match(/^[0-9a-f]{16}$/)) {
|
|
if (!Gun.obj.is(meta[gameId])) {
|
|
appendJournal(JSON.stringify({ meta: { [gameId]: null } }));
|
|
if (gameId in cancellers) {
|
|
cancellers[gameId]();
|
|
delete cancellers[gameId];
|
|
}
|
|
} else if (!(gameId in cancellers)) {
|
|
let cancelMeta = gun.get(meta[gameId]).onWithCancel(function(data) {
|
|
updateMeta(gameId, data).catch(logDbError('updateMeta'));
|
|
let text;
|
|
try {
|
|
let clean = null;
|
|
if (data !== null) {
|
|
clean = {};
|
|
for (const k of Object.keys(data).sort()) {
|
|
if (k !== '_') {
|
|
clean[k] = data[k];
|
|
}
|
|
}
|
|
}
|
|
text = JSON.stringify({ meta: { [gameId]: clean } });
|
|
} catch(err) {}
|
|
if (text) {
|
|
appendJournal(text);
|
|
}
|
|
});
|
|
|
|
let cancelGame = gun.get(PacoSakoUUID + '/game/' + gameId).onWithCancel(function(data) {
|
|
if (data && typeof data.board === 'string') {
|
|
let text;
|
|
try {
|
|
const parsed = JSON.parse(data.board);
|
|
updateGame(gameId, parsed).catch(logDbError('updateGame'));
|
|
text = JSON.stringify({ game: { [gameId]: { board: parsed } } });
|
|
} catch(err) {}
|
|
if (text) {
|
|
appendJournal(text);
|
|
}
|
|
}
|
|
});
|
|
|
|
cancellers[gameId] = function() { cancelMeta(); cancelGame(); };
|
|
}
|
|
}
|
|
}
|
|
}, { change: true });
|