Testclient: Aankloppen heet Testen, en een weigering stopt de herhaallus
Voorstel van de gebruiker, en het tweede deel loste meer op dan een knop. Een verbinding die geweigerd wordt bleef eindeloos opnieuw proberen, en elke poging is een regel in de weigerlijst van de relay; zo liep die lijst tijdens deze sessie ook vol. - klop heet test op de opdrachtregel en Testen op de pagina. - Verbinden gaat uit zodra een test zegt dat de eigenaar geweigerd wordt, met de uitkomst in het rood naast de naam. Onbekend telt als toegestaan, want anders moet je eerst testen om iets te mogen en is dat zelf ook een poging. Blob schrijven gaat door dezelfde poort en schrijft dan lokaal verder. - Een lopende verbinding stopt zichzelf: na drie mislukte sockets wordt er precies een keer getest, en bij een weigering gaat de verbinding eruit. Is het geen weigering, dan blijft hij staan, want dan is opnieuw proberen juist goed. De melding in een dialoogvenster is eruit; de uitkomst staat naast de naam en in het log en die blijven staan. In de browser nagekeken: testen geeft 401, de regel verschijnt rood, en Verbinden is uitgegrijsd voor de geteste eigenaar terwijl de ongeteste hem houdt. Suite: 478 goed, 0 fout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ export const OPDRACHTEN = {
|
||||
lijst: { argumenten: [], uitleg: 'Toont de eigenaars in het register' },
|
||||
schrijf: { argumenten: ['naam', 'label'], uitleg: 'Schrijft een blob weg voor deze eigenaar' },
|
||||
lees: { argumenten: ['naam'], uitleg: 'Toont de blobs van deze eigenaar' },
|
||||
klop: { argumenten: ['naam'], uitleg: 'Klopt aan bij de relay en toont de HTTP-status' },
|
||||
test: { argumenten: ['naam'], uitleg: 'Test of de relay deze eigenaar toelaat, zonder te verbinden' },
|
||||
spiegel: { argumenten: ['naam'], uitleg: 'Haalt deze eigenaar op in een lege database, via de relay' },
|
||||
sync: { argumenten: ['naam'], uitleg: 'Verbindt en blijft draaien tot Ctrl-C' },
|
||||
vergeet: { argumenten: ['naam'], uitleg: 'Haalt een eigenaar uit het register' },
|
||||
|
||||
@@ -146,10 +146,10 @@ const opdrachten = {
|
||||
}
|
||||
},
|
||||
|
||||
klop: async ({ naam }) => {
|
||||
test: async ({ naam }) => {
|
||||
eisRelay();
|
||||
const { regel } = haalEigenaarOp(naam);
|
||||
console.log(`Aankloppen bij ${config.relayUrl} als ${regel.ownerId}`);
|
||||
console.log(`Testen bij ${config.relayUrl} als ${regel.ownerId}`);
|
||||
const uitkomst = await klopAan(config.relayUrl, regel.ownerId);
|
||||
console.log(` status ${uitkomst.status ?? '-'}`);
|
||||
console.log(` uitkomst ${uitkomst.uitleg}`);
|
||||
|
||||
@@ -175,6 +175,13 @@
|
||||
: 'niet verbonden';
|
||||
rij.append(toestand);
|
||||
|
||||
if (eigenaar.test) {
|
||||
const test = document.createElement('span');
|
||||
test.className = eigenaar.test.geaccepteerd ? 'melding' : 'melding fout';
|
||||
test.textContent = `getest ${tijd(eigenaar.test.tijd)}: ${eigenaar.test.status ?? '-'} ${eigenaar.test.uitleg}`;
|
||||
rij.append(test);
|
||||
}
|
||||
|
||||
const duw = document.createElement('div');
|
||||
duw.className = 'duw';
|
||||
|
||||
@@ -184,14 +191,26 @@
|
||||
omvang.style.width = '6em';
|
||||
omvang.addEventListener('input', () => omvangPer.set(eigenaar.naam, omvang.value));
|
||||
|
||||
// Verbinden gaat uit zodra een test zegt dat deze eigenaar geweigerd
|
||||
// wordt. Niet uit netheid: Evolu blijft bij een weigering eindeloos
|
||||
// opnieuw proberen, en élke poging is een regel in de weigerlijst van de
|
||||
// relay. Onbekend telt als toegestaan, want anders moet je eerst testen
|
||||
// om iets te mogen, en dat is zelf ook een poging.
|
||||
const verbindKnop = eigenaar.verbonden
|
||||
? knop('Verbreken', () => roep('verbreek', { naam: eigenaar.naam }))
|
||||
: knop('Verbinden', () => roep('verbind', { naam: eigenaar.naam }));
|
||||
|
||||
if (!eigenaar.verbonden && !eigenaar.magVerbinden) {
|
||||
verbindKnop.disabled = true;
|
||||
verbindKnop.title = 'De relay weigert deze eigenaar. Laat hem toe op de statuspagina van de app en test opnieuw.';
|
||||
}
|
||||
|
||||
duw.append(
|
||||
knop('Aankloppen', async () => {
|
||||
const uit = await roep('klop', { naam: eigenaar.naam });
|
||||
alert(`status ${uit.status ?? '-'}: ${uit.uitleg}`);
|
||||
}),
|
||||
eigenaar.verbonden
|
||||
? knop('Verbreken', () => roep('verbreek', { naam: eigenaar.naam }))
|
||||
: knop('Verbinden', () => roep('verbind', { naam: eigenaar.naam })),
|
||||
// Geen melding in een dialoogvenster: de uitkomst komt naast de naam te
|
||||
// staan en in het log, en die blijven staan. Een dialoog moet je
|
||||
// wegklikken en is daarna weg.
|
||||
knop('Testen', () => roep('test', { naam: eigenaar.naam })),
|
||||
verbindKnop,
|
||||
omvang,
|
||||
knop('Blob schrijven', () =>
|
||||
roep('schrijf', { naam: eigenaar.naam, label: `blob ${tijd(new Date().toISOString())}`, bytes: omvang.value }),
|
||||
|
||||
@@ -28,6 +28,27 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
const open = new Map();
|
||||
const log = [];
|
||||
|
||||
/**
|
||||
* De laatste uitkomst van "Testen", per eigenaar.
|
||||
*
|
||||
* Hierop wordt de knop "Verbinden" uitgezet. Onbekend telt als toegestaan, en
|
||||
* dat is met opzet: anders moet je eerst testen voordat je iets mag, en een
|
||||
* test is zelf een poging die in de weigerlijst van de relay belandt.
|
||||
*/
|
||||
const laatsteTest = new Map();
|
||||
|
||||
/**
|
||||
* Hoeveel sockets er achter elkaar mislukt zijn, per eigenaar.
|
||||
*
|
||||
* Evolu is local-first en blijft eindeloos opnieuw proberen. Dat is bij een
|
||||
* relay die even weg is precies goed, maar bij een eigenaar die geweigerd
|
||||
* wordt is elke poging een regel in de weigerlijst van de relay. Vandaar de
|
||||
* teller: na een paar mislukkingen wordt er één keer getest, en bij een
|
||||
* weigering gaat de verbinding eruit in plaats van door te blijven kloppen.
|
||||
*/
|
||||
const socketFouten = new Map();
|
||||
const FOUTEN_VOOR_TEST = 3;
|
||||
|
||||
const meld = (tekst) => {
|
||||
log.unshift({ tijd: new Date().toISOString(), tekst });
|
||||
if (log.length > MAX_LOG) log.length = MAX_LOG;
|
||||
@@ -48,6 +69,33 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
meld(`${naam}: defect uit een worker, zie de terminal`);
|
||||
console.error(defect);
|
||||
},
|
||||
onWebSocket: (bericht) => {
|
||||
if (bericht.wat === 'open') {
|
||||
socketFouten.set(naam, 0);
|
||||
meld(`${naam}: socket open`);
|
||||
return;
|
||||
}
|
||||
if (bericht.wat !== 'dicht') return;
|
||||
|
||||
const aantal = (socketFouten.get(naam) ?? 0) + 1;
|
||||
socketFouten.set(naam, aantal);
|
||||
if (aantal !== FOUTEN_VOOR_TEST) return;
|
||||
|
||||
// Precies één keer testen, bij de derde mislukking. Daarna weten we of
|
||||
// dit een weigering is of een relay die even weg is, en dat scheelt de
|
||||
// relay een weigerlijst vol pogingen.
|
||||
meld(`${naam}: ${aantal} sockets mislukt (${bericht.detail}), wordt getest`);
|
||||
void (async () => {
|
||||
const uitkomst = await klopAan(config.relayUrl, regel.ownerId);
|
||||
laatsteTest.set(naam, { ...uitkomst, tijd: new Date().toISOString() });
|
||||
if (uitkomst.geaccepteerd) {
|
||||
meld(`${naam}: de relay laat hem toe, dus dit is iets anders dan een weigering`);
|
||||
return;
|
||||
}
|
||||
meld(`${naam}: geweigerd (${uitkomst.uitleg}), verbinding wordt verbroken`);
|
||||
await verbreek(naam);
|
||||
})();
|
||||
},
|
||||
});
|
||||
|
||||
const ingang = { store, sinds: new Date().toISOString(), metRelay };
|
||||
@@ -60,6 +108,7 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
const ingang = open.get(naam);
|
||||
if (!ingang) return;
|
||||
open.delete(naam);
|
||||
socketFouten.delete(naam);
|
||||
await ingang.store.sluit();
|
||||
meld(`${naam} losgekoppeld`);
|
||||
};
|
||||
@@ -76,6 +125,7 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
blobs = null;
|
||||
}
|
||||
}
|
||||
const test = laatsteTest.get(regel.naam) ?? null;
|
||||
eigenaars.push({
|
||||
naam: regel.naam,
|
||||
ownerId: regel.ownerId,
|
||||
@@ -85,6 +135,11 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
sinds: ingang?.sinds ?? null,
|
||||
transportUrl: ingang?.store.transportUrl ?? null,
|
||||
blobs,
|
||||
test,
|
||||
// Onbekend telt als toegestaan: eerst moeten testen om te mogen
|
||||
// verbinden zou betekenen dat je altijd een poging in de weigerlijst
|
||||
// van de relay zet voordat je iets kunt doen.
|
||||
magVerbinden: test === null || test.geaccepteerd === true,
|
||||
});
|
||||
}
|
||||
return { relayUrl: config.relayUrl, eigenaars, log };
|
||||
@@ -115,7 +170,12 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
if (!Number.isInteger(omvang) || omvang < 1 || omvang > 8 * 1024 * 1024) {
|
||||
throw new Error('bytes moet tussen 1 en 8388608 liggen.');
|
||||
}
|
||||
const ingang = open.get(naam) ?? (await verbind(naam, Boolean(config.relayUrl)));
|
||||
// Schrijven opent zo nodig zelf een verbinding, dus dezelfde poort als bij
|
||||
// de knop "Verbinden": een geweigerde eigenaar gaat lokaal verder in
|
||||
// plaats van de weigerlijst van de relay te vullen.
|
||||
const test = laatsteTest.get(naam);
|
||||
const geweigerd = test != null && test.geaccepteerd === false;
|
||||
const ingang = open.get(naam) ?? (await verbind(naam, Boolean(config.relayUrl) && !geweigerd));
|
||||
const body = new Uint8Array(omvang);
|
||||
for (let i = 0; i < omvang; i += 1) body[i] = i % 256;
|
||||
const geschreven = await ingang.store.schrijf(label || 'blob', body);
|
||||
@@ -135,17 +195,19 @@ export const startUi = async ({ config, register, databasesIn }) => {
|
||||
};
|
||||
},
|
||||
|
||||
klop: async ({ naam }) => {
|
||||
test: async ({ naam }) => {
|
||||
const regel = register.zoek(naam);
|
||||
if (!regel) throw new Error(`Geen eigenaar "${naam}".`);
|
||||
if (!config.relayUrl) throw new Error('Geen relay-adres. Zet RELAY_URL in .env.');
|
||||
const uitkomst = await klopAan(config.relayUrl, regel.ownerId);
|
||||
meld(`${naam}: aankloppen gaf ${uitkomst.status ?? '-'}, ${uitkomst.uitleg}`);
|
||||
laatsteTest.set(naam, { ...uitkomst, tijd: new Date().toISOString() });
|
||||
meld(`${naam}: testen gaf ${uitkomst.status ?? '-'}, ${uitkomst.uitleg}`);
|
||||
return uitkomst;
|
||||
},
|
||||
|
||||
vergeet: async ({ naam }) => {
|
||||
await verbreek(naam);
|
||||
laatsteTest.delete(naam);
|
||||
const weg = register.vergeet(naam);
|
||||
meld(`${weg.naam} uit het register gehaald`);
|
||||
return { naam: weg.naam };
|
||||
|
||||
Reference in New Issue
Block a user