source: Klonkt/scripts/instance-env.mjs@ 6248497

main
Last change on this file since 6248497 was 6248497, checked in by roboburr <roboburr@…>, 5 weeks ago

Export en import kiezen de juiste instance, en tijdstempels zijn echt UTC

Twee fouten, allebei op productie gevonden en allebei van het soort dat SUCCES
meldt.

## 1. Het script opende de verkeerde database

Op een split install deelt elke Klonkt de code in /opt/klonkt maar staat zijn data
onder /var/lib/klonkt/<slug>/ met een eigen .env. De scripts lazen die .env niet,
dus database.js viel terug op storage/database.sqlite IN DE CODE-MAP. Op een
server die ooit de enkelvoudige opzet draaide ligt daar een achtergebleven oude
database.

Waargenomen: export-archive.mjs boiert schreef een archief van 444 bytes met
"posts: 0" en meldde dat het gelukt was, terwijl het in een oude lege database
keek. liz en sood gaven "onbekende site". Het script raakte die oude database
ook nog aan (boot-migraties), terwijl het alleen hoort te lezen.

Nu leest scripts/instance-env.mjs de .env van de instance (standaard
/var/lib/klonkt/<slug>/.env, of --data-root / --env) VOORDAT de service geladen
wordt -- database.js opent de database namelijk bij import. De uitvoer noemt
voortaan welke .env en welke database gebruikt zijn.

En zonder PUBLIC_BASE_URL stopt hij nu HARD in plaats van het als bijzin te
melden: zonder origin krijgt het archief een lege origin, en dan maakt een import
nieuwe AP-ids. Dan is het een kopie van de tekst en geen herstel -- precies de
belofte waar het formaat om draait.

Voor de importer weegt dit zwaarder dan voor de exporter: in de verkeerde
database schrijven draai je niet terug.

## 2. Tijdstempels schoven met de tijdzone van de machine

Vraag van Bart: normaliseert de export wel naar UTC? Nee.

SQLite schrijft CURRENT_TIMESTAMP als "2026-07-01 12:56:10" -- in UTC, maar zonder
zone. Date.parse leest die vorm als LOKALE tijd. Op een machine in Amsterdam komt
daar 10:56:10Z uit: twee uur verschoven, in elk archief.

Geen enkele test kon dat zien, want de testmachine draait op UTC. En mijn eigen
rondgang-vergelijking plakte er zelf een Z achter, waarmee ik er precies overheen
keek.

toISO leest een zoneloze vorm nu expliciet als UTC. Nieuwe test die alleen onder
een niet-UTC zone iets bewijst; gecontroleerd dat hij onder Europe/Amsterdam
omvalt zonder de fix. Hele suite 577/577 onder zowel UTC als Europe/Amsterdam.

  • Property mode set to 100644
File size: 4.0 KB
Line 
1//
2// Welke instance bedoel je?
3//
4// Op een split install (deploy/MULTI-INSTANCE.md) deelt elke Klonkt dezelfde code
5// in /opt/klonkt, maar staat zijn DATA onder /var/lib/klonkt/<slug>/ met een eigen
6// .env. Een script dat vanuit de code-map draait zonder die .env te lezen opent
7// dus de VERKEERDE database -- en op een machine die ooit de oude enkelvoudige
8// opzet draaide is dat een achtergebleven storage/database.sqlite in de checkout.
9//
10// Dat ging in de praktijk mis en op de ergste manier: het meldde SUCCES. Een
11// export van een site met zeven jaar aan posten schreef een archief van 444 bytes
12// met "posts: 0", omdat hij in een oude lege database keek. Een leeg archief dat
13// zegt dat het gelukt is, is erger dan een foutmelding.
14//
15// Vandaar dit: los, want de importer en het herstel hebben hem net zo hard nodig.
16
17import fs from 'fs';
18import path from 'path';
19
20/** Lees een .env zonder afhankelijkheden. Alleen KEY=value, # is commentaar. */
21export function leesEnv(pad) {
22 const uit = {};
23 for (const regel of fs.readFileSync(pad, 'utf8').split('\n')) {
24 const s = regel.trim();
25 if (!s || s.startsWith('#')) continue;
26 const i = s.indexOf('=');
27 if (i < 1) continue;
28 let v = s.slice(i + 1).trim();
29 if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1);
30 uit[s.slice(0, i).trim()] = v;
31 }
32 return uit;
33}
34
35/**
36 * Zet de omgeving voor EEN instance, en zeg hardop welke.
37 *
38 * Moet AANGEROEPEN WORDEN VOORDAT src/config/database.js geladen wordt: die leest
39 * DATABASE_PATH bij import en opent de database meteen. Vandaar dat de scripts
40 * hun service-import uitstellen tot na deze aanroep.
41 *
42 * @returns {{bron: string, env: object}} waar de instellingen vandaan kwamen
43 */
44export function kiesInstance(slug, opts = {}) {
45 const dataRoot = opts.dataRoot || process.env.KLONKT_DATA_ROOT || '/var/lib/klonkt';
46 const kandidaat = opts.envPad || path.join(dataRoot, slug, '.env');
47
48 if (fs.existsSync(kandidaat)) {
49 const env = leesEnv(kandidaat);
50 // De data-map van de instance is de wortel voor relatieve paden in zijn .env,
51 // precies zoals de unit hem draait (WorkingDirectory is de code, DATA_DIR de data).
52 const basis = env.DATA_DIR || path.dirname(kandidaat);
53 const absoluut = (p) => (p && !path.isAbsolute(p) ? path.resolve(basis, p) : p);
54 for (const k of ['DATABASE_PATH', 'MEDIA_PATH', 'AUDIO_PATH', 'AVATAR_PATH', 'COVER_PATH']) {
55 if (env[k]) process.env[k] = absoluut(env[k]);
56 }
57 if (env.PUBLIC_BASE_URL) process.env.PUBLIC_BASE_URL = env.PUBLIC_BASE_URL;
58 if (env.DATA_DIR) process.env.DATA_DIR = env.DATA_DIR;
59 return { bron: kandidaat, env };
60 }
61
62 if (opts.envPad) {
63 // Expliciet meegegeven en niet gevonden: dat is een vergissing en geen reden
64 // om stilletjes iets anders te openen.
65 throw new Error(`geen .env op ${opts.envPad}`);
66 }
67 return { bron: null, env: {} };
68}
69
70/**
71 * Weiger te beginnen als we niet kunnen weten wiens gegevens dit zijn.
72 *
73 * Zonder PUBLIC_BASE_URL komt er een archief uit met een lege `origin`, en dan
74 * weigert de importer de AP-ids te behouden -- hij maakt nieuwe. Daarmee valt
75 * precies de belofte weg waar het formaat om draait: een herstel waarna de
76 * boosts en antwoorden elders hun post terugvinden. Dat mag geen voetnoot in de
77 * uitvoer zijn.
78 */
79export function eisOrigin(bron) {
80 if (process.env.PUBLIC_BASE_URL) return;
81 console.error([
82 'GESTOPT: er is geen PUBLIC_BASE_URL.',
83 '',
84 'Zonder die waarde krijgt het archief een lege origin, en dan maakt een import',
85 'NIEUWE ActivityPub-ids in plaats van de oude te behouden. Boosts, likes en',
86 'antwoorden elders vinden hun post dan niet meer terug -- het archief is dan',
87 'een kopie van de tekst en geen herstel.',
88 '',
89 bron
90 ? `Gelezen uit ${bron}, maar PUBLIC_BASE_URL staat daar niet in.`
91 : 'Geen .env van een instance gevonden. Op een split install:\n'
92 + ' node scripts/export-archive.mjs <slug> --data-root /var/lib/klonkt',
93 ].join('\n'));
94 process.exit(1);
95}
Note: See TracBrowser for help on using the repository browser.