This commit is contained in:
team3
2026-09-22 14:02:36 +02:00
parent 139663819c
commit 24efa2f4ee
4 changed files with 17 additions and 11 deletions

View File

@@ -62,7 +62,7 @@ reload:
echo "Extension neu gestartet." echo "Extension neu gestartet."
fi fi
# Dateiabgleich (Claude-Sitzungen und Memory) sofort anstoßen, wartet bis er durch ist # Dateiabgleich (Claude-Sitzungen und Memory) sofort und ohne Ruhezeit, wartet bis er durch ist
sync-files: sync-files:
@gdbus call --session --dest org.gnome.Shell --object-path /de/marha/desktop --method de.marha.Desktop.SyncFiles --timeout 3600 \ @gdbus call --session --dest org.gnome.Shell --object-path /de/marha/desktop --method de.marha.Desktop.SyncFiles --timeout 3600 \
| sed -e "s/^('//" -e "s/',)$$//" | sed -e "s/^('//" -e "s/',)$$//"

View File

@@ -69,7 +69,7 @@ einer Stunde nicht angefasst wurde. Vom Server kommt sie, wenn sie dort neuer is
Änderungszeit. Gelöschte Dateien verschwinden auch auf dem anderen PC. Die App fragt diese Änderungszeit. Gelöschte Dateien verschwinden auch auf dem anderen PC. Die App fragt diese
Dateien nie an. Bedingung: gleicher Pfad auf beiden PCs, der Ordnername enthält ihn. Dateien nie an. Bedingung: gleicher Pfad auf beiden PCs, der Ordnername enthält ihn.
`"files": false` in `sync.json` schaltet es ab, ein Pfad statt `false` ersetzt den Ordner. `"files": false` in `sync.json` schaltet es ab, ein Pfad statt `false` ersetzt den Ordner.
`make sync-files` stößt den Abgleich sofort an und wartet, bis er durch ist. `make sync-files` stößt den Abgleich sofort an, auch für Dateien, die noch keine Stunde ruhen, und wartet, bis er durch ist.
Zugang auf jedem Gerät in `~/.local/share/desktop-app/sync.json`: Zugang auf jedem Gerät in `~/.local/share/desktop-app/sync.json`:

View File

@@ -84,14 +84,15 @@ export class Sync {
this._dbus.export(Gio.DBus.session, '/de/marha/desktop'); this._dbus.export(Gio.DBus.session, '/de/marha/desktop');
} }
// Dateiabgleich sofort, die Antwort kommt erst, wenn er durch ist // Dateiabgleich sofort und erzwungen: auch Dateien, die noch keine Stunde ruhen.
// Die Antwort kommt erst, wenn er durch ist.
SyncFilesAsync(_params, invocation) { SyncFilesAsync(_params, invocation) {
const reply = text => invocation.return_value(new GLib.Variant('(s)', [text])); const reply = text => invocation.return_value(new GLib.Variant('(s)', [text]));
if (!this._filesRoot) { if (!this._filesRoot) {
reply('Dateiabgleich ist aus ("files": false in sync.json)'); reply('Dateiabgleich ist aus ("files": false in sync.json)');
return; return;
} }
this._filesCycle() this._filesCycle(true)
.then(r => reply(r ? `hoch ${r.uploaded}, gelöscht gemeldet ${r.removed}, runter ${r.written}, lokal gelöscht ${r.deleted}` : 'läuft gerade schon')) .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}`)); .catch(e => reply(`Fehler: ${e.message}`));
} }
@@ -278,7 +279,8 @@ export class Sync {
// Eigener Lauf mit eigenem Stand: die Antwort enthält nur Dateien, der Takt der Einträge bleibt unberührt. // 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. // Gibt zurück, was übertragen wurde, oder null, wenn gerade ein Lauf aktiv ist.
async _filesCycle() { // force: Ruhezeit ignorieren, alles Geänderte geht hoch.
async _filesCycle(force = false) {
if (this._filesBusy || !this._filesRoot) if (this._filesBusy || !this._filesRoot)
return null; return null;
this._filesBusy = true; this._filesBusy = true;
@@ -287,7 +289,7 @@ export class Sync {
const state = this._state.files; const state = this._state.files;
const local = scanFiles(this._filesRoot); const local = scanFiles(this._filesRoot);
const now = Math.floor(GLib.get_real_time() / 1e6); const now = Math.floor(GLib.get_real_time() / 1e6);
const {upload, remove} = planPush(local, state.pushed, now, FILES_IDLE_SECONDS); const {upload, remove} = planPush(local, state.pushed, now, force ? 0 : FILES_IDLE_SECONDS);
const items = []; const items = [];
for (const entry of upload) { for (const entry of upload) {
const content = readText(GLib.build_filenamev([this._filesRoot, entry.id])); const content = readText(GLib.build_filenamev([this._filesRoot, entry.id]));

View File

@@ -169,16 +169,20 @@ print(json.dumps(out))
PY PY
} }
files() { allfiles | python3 -c 'import json,sys; print(sorted((f["id"], bool(f.get("deleted"))) for f in json.load(sys.stdin)))'; } files() { allfiles | python3 -c 'import json,sys; print(sorted((f["id"], bool(f.get("deleted"))) for f in json.load(sys.stdin)))'; }
# Wie make sync-files, nur auf dem Bus der Test-Shell. Wartet, bis der Lauf durch ist. # Lauf wie vom Timer: Ruhezeit gilt
timercycle() { "$E" "$PRE ext._sync._filesCycle(); 'ok'" >/dev/null; sleep 3; }
# Wie make sync-files, nur auf dem Bus der Test-Shell: erzwungen, wartet, bis der Lauf durch ist.
filescycle() { DBUS_SESSION_BUS_ADDRESS=$(cat /tmp/desktop-app-nested/bus) gdbus call --session --dest org.gnome.Shell --object-path /de/marha/desktop --method de.marha.Desktop.SyncFiles | sed -e "s/^('//" -e "s/',)$//"; } filescycle() { DBUS_SESSION_BUS_ADDRESS=$(cat /tmp/desktop-app-nested/bus) gdbus call --session --dest org.gnome.Shell --object-path /de/marha/desktop --method de.marha.Desktop.SyncFiles | sed -e "s/^('//" -e "s/',)$//"; }
mkdir -p "$FILES/-home-x/memory" mkdir -p "$FILES/-home-x/memory"
echo '{"a":1}' > "$FILES/-home-x/alt.jsonl"; touch -d '2 hours ago' "$FILES/-home-x/alt.jsonl" echo '{"a":1}' > "$FILES/-home-x/alt.jsonl"; touch -d '2 hours ago' "$FILES/-home-x/alt.jsonl"
echo '# Memo' > "$FILES/-home-x/memory/MEMORY.md"; touch -d '90 minutes ago' "$FILES/-home-x/memory/MEMORY.md" echo '# Memo' > "$FILES/-home-x/memory/MEMORY.md"; touch -d '90 minutes ago' "$FILES/-home-x/memory/MEMORY.md"
echo 'läuft noch' > "$FILES/-home-x/frisch.jsonl" echo 'läuft noch' > "$FILES/-home-x/frisch.jsonl"
check "Sofort-Abgleich meldet, was übertragen wurde" "$(filescycle)" "hoch 2, gelöscht gemeldet 0, runter 0, lokal gelöscht 0" timercycle
check "Ruhende Dateien auf dem Server, frische nicht" "$(files)" "[('-home-x/alt.jsonl', False), ('-home-x/memory/MEMORY.md', False)]" check "Timer-Lauf: ruhende Dateien auf dem Server, frische nicht" "$(files)" "[('-home-x/alt.jsonl', False), ('-home-x/memory/MEMORY.md', False)]"
check "make sync-files erzwingt auch die frische Datei" "$(filescycle)" "hoch 1, gelöscht gemeldet 0, runter 0, lokal gelöscht 0"
check "Frische Datei jetzt auf dem Server" "$(files)" "[('-home-x/alt.jsonl', False), ('-home-x/frisch.jsonl', False), ('-home-x/memory/MEMORY.md', False)]"
check "Normale Anfrage bekommt keine Dateien" "$(api -X POST "$URL/api/sync" -d '{"since": 0}' | python3 -c 'import json,sys; d=json.load(sys.stdin); print("files" in d, "events" in d)')" "False True" check "Normale Anfrage bekommt keine Dateien" "$(api -X POST "$URL/api/sync" -d '{"since": 0}' | python3 -c 'import json,sys; d=json.load(sys.stdin); print("files" in d, "events" in d)')" "False True"
check "Stand der Dateien getrennt gemerkt" "$(val 'Object.keys(state().files.pushed).sort().join(",") + " " + (state().files.cursor > 0)')" "-home-x/alt.jsonl,-home-x/memory/MEMORY.md true" check "Stand der Dateien getrennt gemerkt" "$(val 'Object.keys(state().files.pushed).sort().join(",") + " " + (state().files.cursor > 0)')" "-home-x/alt.jsonl,-home-x/frisch.jsonl,-home-x/memory/MEMORY.md true"
push '{"files": [{"id": "-home-y/s2.jsonl", "updated": "2026-09-01T00:00:00.000Z", "content": "vom anderen PC"}]}' push '{"files": [{"id": "-home-y/s2.jsonl", "updated": "2026-09-01T00:00:00.000Z", "content": "vom anderen PC"}]}'
check "Abgleich holt die Datei" "$(filescycle)" "hoch 0, gelöscht gemeldet 0, runter 1, lokal gelöscht 0" check "Abgleich holt die Datei" "$(filescycle)" "hoch 0, gelöscht gemeldet 0, runter 1, lokal gelöscht 0"
check "Datei vom Server geschrieben, Änderungszeit übernommen" "$(cat "$FILES/-home-y/s2.jsonl") $(stat -c %Y "$FILES/-home-y/s2.jsonl")" "vom anderen PC $(date -u -d 2026-09-01T00:00:00Z +%s)" check "Datei vom Server geschrieben, Änderungszeit übernommen" "$(cat "$FILES/-home-y/s2.jsonl") $(stat -c %Y "$FILES/-home-y/s2.jsonl")" "vom anderen PC $(date -u -d 2026-09-01T00:00:00Z +%s)"
@@ -193,7 +197,7 @@ check "Abgleich meldet Löschungen" "$(filescycle)" "hoch 0, gelöscht gemeldet
check "Gelöscht in beide Richtungen" "$(files | python3 -c 'import sys; print("MEMORY.md\x27, True" in sys.stdin.read())') $([ -e "$FILES/-home-y/s2.jsonl" ] && echo da || echo weg)" "True weg" check "Gelöscht in beide Richtungen" "$(files | python3 -c 'import sys; print("MEMORY.md\x27, True" in sys.stdin.read())') $([ -e "$FILES/-home-y/s2.jsonl" ] && echo da || echo weg)" "True weg"
check "Gemeldete Löschung nicht nochmal" "$(val 'state().files.pushed["-home-x/memory/MEMORY.md"] === null && state().files.pushed["-home-y/s2.jsonl"] === null')" "true" check "Gemeldete Löschung nicht nochmal" "$(val 'state().files.pushed["-home-x/memory/MEMORY.md"] === null && state().files.pushed["-home-y/s2.jsonl"] === null')" "true"
check "Zweiter Lauf überträgt nichts" "$(filescycle)" "hoch 0, gelöscht gemeldet 0, runter 0, lokal gelöscht 0" check "Zweiter Lauf überträgt nichts" "$(filescycle)" "hoch 0, gelöscht gemeldet 0, runter 0, lokal gelöscht 0"
check "Zweiter Lauf schickt nichts erneut" "$(files)" "[('-home-x/alt.jsonl', False), ('-home-x/memory/MEMORY.md', True), ('-home-y/s2.jsonl', True)]" check "Zweiter Lauf schickt nichts erneut" "$(files)" "[('-home-x/alt.jsonl', False), ('-home-x/frisch.jsonl', False), ('-home-x/memory/MEMORY.md', True), ('-home-y/s2.jsonl', True)]"
echo "=== Server weg und wieder da" echo "=== Server weg und wieder da"
kill $SERVER_PID; sleep 1 kill $SERVER_PID; sleep 1