"sync now" button

This commit is contained in:
azivner 2017-10-29 11:22:41 -04:00
parent c28b7775a5
commit d613200925
5 changed files with 79 additions and 25 deletions

View File

@ -0,0 +1,20 @@
function syncNow() {
$.ajax({
url: baseApiUrl + 'sync/now',
type: 'POST',
success: result => {
if (result.success) {
alert("Sync finished successfully");
for (const l of result.log)
{
console.log(l);
}
}
else {
alert("Sync failed");
}
},
error: () => alert("Sync failed")
});
}

View File

@ -5,6 +5,15 @@ const router = express.Router();
const auth = require('../../services/auth'); const auth = require('../../services/auth');
const sync = require('../../services/sync'); const sync = require('../../services/sync');
router.post('/now', auth.checkApiAuth, async (req, res, next) => {
const log = await sync.sync();
res.send({
success: true,
log: log
});
});
router.get('/changed/:since', auth.checkApiAuth, async (req, res, next) => { router.get('/changed/:since', auth.checkApiAuth, async (req, res, next) => {
const since = parseInt(req.params.since); const since = parseInt(req.params.since);

View File

@ -14,7 +14,7 @@ const SYNC_SERVER = config['Sync']['syncServerHost'];
let syncInProgress = false; let syncInProgress = false;
async function pullSync(cookieJar) { async function pullSync(cookieJar, syncLog) {
const lastSyncedPull = parseInt(await sql.getOption('last_synced_pull')); const lastSyncedPull = parseInt(await sql.getOption('last_synced_pull'));
const resp = await rp({ const resp = await rp({
@ -28,7 +28,7 @@ async function pullSync(cookieJar) {
try { try {
await sql.beginTransaction(); await sql.beginTransaction();
await putChanged(resp); await putChanged(resp, syncLog);
for (const noteId of resp.notes) { for (const noteId of resp.notes) {
const note = await rp({ const note = await rp({
@ -41,7 +41,7 @@ async function pullSync(cookieJar) {
}); });
await putNote(note); await putNote(note, syncLog);
} }
await sql.setOption('last_synced_pull', resp.syncTimestamp); await sql.setOption('last_synced_pull', resp.syncTimestamp);
@ -55,24 +55,30 @@ async function pullSync(cookieJar) {
} }
} }
async function pushSync(cookieJar) { async function pushSync(cookieJar, syncLog) {
const lastSyncedPush = parseInt(await sql.getOption('last_synced_push')); const lastSyncedPush = parseInt(await sql.getOption('last_synced_push'));
const syncStarted = utils.nowTimestamp(); const syncStarted = utils.nowTimestamp();
const changed = await getChangedSince(lastSyncedPush); const changed = await getChangedSince(lastSyncedPush);
await rp({ if (changed.tree.length > 0 || changed.audit_log.length > 0) {
method: 'PUT', logSync("Sending " + changed.tree.length + " tree changes and " + changed.audit_log.length + " audit changes", syncLog);
uri: SYNC_SERVER + '/api/sync/changed',
headers: { await rp({
auth: 'sync' method: 'PUT',
}, uri: SYNC_SERVER + '/api/sync/changed',
body: changed, headers: {
json: true, auth: 'sync'
jar: cookieJar },
}); body: changed,
json: true,
jar: cookieJar
});
}
for (const noteId of changed.notes) { for (const noteId of changed.notes) {
logSync("Sending note " + noteId, syncLog);
const note = await getNoteSince(noteId); const note = await getNoteSince(noteId);
await rp({ await rp({
@ -93,8 +99,10 @@ async function pushSync(cookieJar) {
async function login() { async function login() {
const timestamp = utils.nowTimestamp(); const timestamp = utils.nowTimestamp();
const hmac = crypto.createHmac('sha256', documentSecret); const documentSecret = await sql.getOption('document_secret');
hmac.update(timestamp);
const hmac = crypto.createHmac('sha256', Buffer.from(documentSecret.toString(), 'ASCII'));
hmac.update(timestamp.toString());
const hash = hmac.digest('base64'); const hash = hmac.digest('base64');
const cookieJar = rp.jar(); const cookieJar = rp.jar();
@ -120,6 +128,7 @@ async function sync() {
} }
syncInProgress = true; syncInProgress = true;
const syncLog = [];
try { try {
if (!await migration.isDbUpToDate()) { if (!await migration.isDbUpToDate()) {
@ -128,16 +137,26 @@ async function sync() {
const cookieJar = await login(); const cookieJar = await login();
await pushSync(cookieJar); await pushSync(cookieJar, syncLog);
await pullSync(cookieJar); await pullSync(cookieJar, syncLog);
} }
catch (e) { catch (e) {
log.error("sync failed: " + e.stack); logSync("sync failed: " + e.stack, syncLog);
} }
finally { finally {
syncInProgress = false; syncInProgress = false;
} }
return syncLog;
}
function logSync(message, syncLog) {
log.info(message);
if (syncLog !== null) {
syncLog.push(message);
}
} }
async function getChangedSince(since) { async function getChangedSince(since) {
@ -158,27 +177,29 @@ async function getNoteSince(noteId, since) {
}; };
} }
async function putChanged(changed) { async function putChanged(changed, syncLog) {
for (const treeItem of changed.tree) { for (const treeItem of changed.tree) {
delete treeItem['id']; delete treeItem['id'];
await sql.insert("notes_tree", treeItem, true); await sql.insert("notes_tree", treeItem, true);
log.info("Update/sync notes_tree " + treeItem.note_id); logSync("Update/sync notes_tree " + treeItem.note_id, syncLog);
} }
for (const audit of changed.audit_log) { for (const audit of changed.audit_log) {
await sql.insert("audit_log", audit, true); await sql.insert("audit_log", audit, true);
log.info("Update/sync audit_log for noteId=" + audit.note_id); logSync("Update/sync audit_log for noteId=" + audit.note_id, syncLog);
} }
if (changed.tree.length > 0 || changed.audit_log.length > 0) { if (changed.tree.length > 0 || changed.audit_log.length > 0) {
logSync("Added final audit", syncLog);
await sql.addAudit(audit_category.SYNC); await sql.addAudit(audit_category.SYNC);
} }
} }
async function putNote(note) { async function putNote(note, syncLog) {
const origNote = await sql.getSingleResult(); const origNote = await sql.getSingleResult();
if (origNote !== null && origNote.date_modified >= note.detail.date_modified) { if (origNote !== null && origNote.date_modified >= note.detail.date_modified) {
@ -203,7 +224,7 @@ async function putNote(note) {
await sql.addAudit(audit_category.SYNC); await sql.addAudit(audit_category.SYNC);
log.info("Update/sync note " + note.detail.note_id); logSync("Update/sync note " + note.detail.note_id, syncLog);
} }
if (SYNC_SERVER) { if (SYNC_SERVER) {
@ -219,6 +240,7 @@ else {
} }
module.exports = { module.exports = {
sync,
getChangedSince, getChangedSince,
getNoteSince, getNoteSince,
putChanged, putChanged,

View File

@ -19,7 +19,7 @@ function randomString(length) {
} }
function randomSecureToken(bytes = 32) { function randomSecureToken(bytes = 32) {
crypto.randomBytes(bytes).toString('base64'); return crypto.randomBytes(bytes).toString('base64');
} }
function nowTimestamp() { function nowTimestamp() {

View File

@ -21,6 +21,8 @@
<span id="top-message"></span> <span id="top-message"></span>
<span id="error-message"></span> <span id="error-message"></span>
<button class="btn btn-xs" onclick="syncNow();">Sync now</button>
<button class="btn btn-xs" onclick="displaySettings();">Settings</button> <button class="btn btn-xs" onclick="displaySettings();">Settings</button>
<form action="logout" method="POST" style="display: inline;"> <form action="logout" method="POST" style="display: inline;">
@ -274,6 +276,7 @@
<script src="javascripts/note_history.js"></script> <script src="javascripts/note_history.js"></script>
<script src="javascripts/recent_changes.js"></script> <script src="javascripts/recent_changes.js"></script>
<script src="javascripts/sync.js"></script>
<script src="javascripts/utils.js"></script> <script src="javascripts/utils.js"></script>
</body> </body>
</html> </html>