mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-22 22:49:45 +01:00
feat: add basic syncing (untested)
This commit is contained in:
@@ -2,6 +2,7 @@ import Notes from "../collections/notes";
|
||||
import Notebooks from "../collections/notebooks";
|
||||
import Trash from "../collections/trash";
|
||||
import User from "../models/user";
|
||||
import Sync from "./sync";
|
||||
|
||||
class Database {
|
||||
constructor(context) {
|
||||
@@ -15,6 +16,11 @@ class Database {
|
||||
await this.notes.init(this.notebooks, this.trash);
|
||||
await this.notebooks.init(this.notes, this.trash);
|
||||
await this.trash.init(this.notes, this.notebooks);
|
||||
this.syncer = new Sync(this);
|
||||
}
|
||||
|
||||
sync() {
|
||||
return this.syncer.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
96
packages/core/api/sync.js
Normal file
96
packages/core/api/sync.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* GENERAL PROCESS:
|
||||
* make a get request to server with current lastSyncedTimestamp
|
||||
* parse the response. the response should contain everything that user has on the server
|
||||
* decrypt the response
|
||||
* merge everything into the database and look for conflicts
|
||||
* send the conflicts (if any) to the end-user for resolution
|
||||
* once the conflicts have been resolved, send the updated data back to the server
|
||||
*/
|
||||
|
||||
/**
|
||||
* MERGING:
|
||||
* Locally, get everything that was editted/added after the lastSyncedTimestamp
|
||||
* Run forEach loop on the server response.
|
||||
* Add items that do not exist in the local collections
|
||||
* Remove items (without asking) that need to be removed
|
||||
* Update items that were editted before the lastSyncedTimestamp
|
||||
* Try to merge items that were edited after the lastSyncedTimestamp
|
||||
* Items in which the content has changed, send them for conflict resolution
|
||||
* Otherwise, keep the most recently updated copy.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CONFLICTS:
|
||||
* Syncing should pause until all the conflicts have been resolved
|
||||
* And then it should continue.
|
||||
*/
|
||||
import Database from "./index";
|
||||
import { HOST } from "../utils/constants";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
export default class Sync {
|
||||
/**
|
||||
*
|
||||
* @param {Database} db
|
||||
*/
|
||||
constructor(db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
async _fetch(lastSyncedTimestamp) {
|
||||
let token = await this.db.user.token();
|
||||
if (!token) return;
|
||||
let response = await fetch(`${HOST}sync?lst=${lastSyncedTimestamp}`, {
|
||||
headers: { ...HEADERS, Authorization: `Bearer ${token}` }
|
||||
});
|
||||
//TODO decrypt the response.
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async start() {
|
||||
let user = await this.db.user.get();
|
||||
if (!user) return false;
|
||||
let lastSyncedTimestamp = user.lastSyncedTimestamp || 0;
|
||||
let serverResponse = await this._fetch(lastSyncedTimestamp);
|
||||
let data = this._merge(serverResponse, lastSyncedTimestamp);
|
||||
await this._send(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
_merge(serverResponse, lastSyncedTimestamp) {
|
||||
const { notes, notebooks /* tags, colors, trash */ } = serverResponse;
|
||||
notes.forEach(async note => {
|
||||
let localNote = this.db.notes.note(note.id);
|
||||
if (!localNote || note.dateEdited > localNote.data.dateEdited) {
|
||||
await this.db.notes.add({ ...note, remote: true });
|
||||
}
|
||||
});
|
||||
notebooks.forEach(async nb => {
|
||||
let localNb = this.db.notebooks.notebook(nb.id);
|
||||
if (!localNb || nb.dateEdited > localNb.data.dateEdited) {
|
||||
await this.db.notebooks.add({ ...nb, remote: true });
|
||||
}
|
||||
});
|
||||
// TODO trash, colors, tags
|
||||
return {
|
||||
notes: this.db.notes.filter(v => v.dateEdited > lastSyncedTimestamp),
|
||||
notebooks: this.db.notebooks.filter(
|
||||
v => v.dateEdited > lastSyncedTimestamp
|
||||
),
|
||||
tags: [],
|
||||
colors: [],
|
||||
tags: []
|
||||
};
|
||||
}
|
||||
|
||||
async _send(data) {
|
||||
//TODO encrypt the payload
|
||||
let response = await fetch(`${HOST}sync`, {
|
||||
method: "POST",
|
||||
headers: { ...HEADERS, Authorization: `Bearer ${token}` },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
return response.ok;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user