update
This commit is contained in:
@@ -30,6 +30,14 @@ const FILES_INTERVAL_SECONDS = 10 * 60;
|
||||
const FILES_IDLE_SECONDS = 60 * 60;
|
||||
const FILES_BATCH_BYTES = 16 * 1024 * 1024;
|
||||
|
||||
// Von außen anstoßbar: make sync-files ruft diese Methode über D-Bus auf
|
||||
const DBUS_IFACE = `
|
||||
<node>
|
||||
<interface name="de.marha.Desktop">
|
||||
<method name="SyncFiles"><arg type="s" direction="out" name="summary"/></method>
|
||||
</interface>
|
||||
</node>`;
|
||||
|
||||
export class Sync {
|
||||
constructor(store) {
|
||||
this._store = store;
|
||||
@@ -70,6 +78,20 @@ export class Sync {
|
||||
this._scheduleNext();
|
||||
if (this._filesRoot)
|
||||
this._scheduleFiles(FILES_FIRST_SECONDS);
|
||||
this._dbus = Gio.DBusExportedObject.wrapJSObject(DBUS_IFACE, this);
|
||||
this._dbus.export(Gio.DBus.session, '/de/marha/desktop');
|
||||
}
|
||||
|
||||
// Dateiabgleich sofort, die Antwort kommt erst, wenn er durch ist
|
||||
SyncFilesAsync(_params, invocation) {
|
||||
const reply = text => invocation.return_value(new GLib.Variant('(s)', [text]));
|
||||
if (!this._filesRoot) {
|
||||
reply('Dateiabgleich ist aus ("files": false in sync.json)');
|
||||
return;
|
||||
}
|
||||
this._filesCycle()
|
||||
.then(r => reply(r ? `hoch ${r.uploaded}, gelöscht gemeldet ${r.removed}, runter ${r.written}, lokal gelöscht ${r.deleted}` : 'läuft gerade schon'))
|
||||
.catch(e => reply(`Fehler: ${e.message}`));
|
||||
}
|
||||
|
||||
// Aktueller Takt in Sekunden, je nachdem wie lange die letzte Aktivität her ist.
|
||||
@@ -109,6 +131,8 @@ export class Sync {
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._dbus?.unexport();
|
||||
this._dbus = null;
|
||||
if (this._timerId) {
|
||||
GLib.source_remove(this._timerId);
|
||||
this._timerId = null;
|
||||
@@ -250,10 +274,12 @@ export class Sync {
|
||||
}
|
||||
|
||||
// Eigener Lauf mit eigenem Stand: die Antwort enthält nur Dateien, der Takt der Einträge bleibt unberührt.
|
||||
// Gibt zurück, was übertragen wurde, oder null, wenn gerade ein Lauf aktiv ist.
|
||||
async _filesCycle() {
|
||||
if (this._filesBusy || !this._filesRoot)
|
||||
return;
|
||||
return null;
|
||||
this._filesBusy = true;
|
||||
const result = {uploaded: 0, removed: 0, written: 0, deleted: 0};
|
||||
try {
|
||||
const state = this._state.files;
|
||||
const local = scanFiles(this._filesRoot);
|
||||
@@ -275,17 +301,20 @@ export class Sync {
|
||||
// Ein Server ohne Dateien-Sammlung würde alles verwerfen, der Stand bliebe sonst falsch
|
||||
if (!Array.isArray(response.files))
|
||||
throw new Error('Server kennt keine Dateien, dort erst make prod ausführen');
|
||||
for (const item of files)
|
||||
for (const item of files) {
|
||||
state.pushed[item.id] = item.deleted ? null : item.updated;
|
||||
this._applyFiles(response, local);
|
||||
result[item.deleted ? 'removed' : 'uploaded']++;
|
||||
}
|
||||
this._applyFiles(response, local, result);
|
||||
writeJson(this._statePath, this._state);
|
||||
}
|
||||
} finally {
|
||||
this._filesBusy = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
_applyFiles(response, local) {
|
||||
_applyFiles(response, local, result) {
|
||||
const state = this._state.files;
|
||||
for (const {file, action, mine} of planPull(response.files ?? [], local)) {
|
||||
const path = GLib.build_filenamev([this._filesRoot, file.id]);
|
||||
@@ -296,10 +325,12 @@ export class Sync {
|
||||
Gio.File.new_for_path(path).set_attribute_uint64('time::modified', seconds, Gio.FileQueryInfoFlags.NONE, null);
|
||||
local.set(file.id, seconds);
|
||||
state.pushed[file.id] = file.updated;
|
||||
result.written++;
|
||||
} else if (action === 'delete') {
|
||||
GLib.unlink(path);
|
||||
local.delete(file.id);
|
||||
state.pushed[file.id] = null;
|
||||
result.deleted++;
|
||||
} else if (file.deleted && mine === null) {
|
||||
state.pushed[file.id] = null;
|
||||
} else if (mine === file.updated) {
|
||||
|
||||
Reference in New Issue
Block a user