openvibers/openvibe.shared Commits

Profile panel and user card: an 8 s limit, and a failed lookup is not kept (#280)

OP OpenVibers committed 10 days ago · 035aff92c0 · 3 files, +26 −3

A request held while Network restarted in a deploy round kept the user card from
opening and stayed in the profile panel's map for the page's life, so that person's
panel never opened again. Rides the next release.

Changes

ddiff --git a/profile-panel.js b/profile-panel.js
iindex 8fabd32..e602f45 100644
---- a/profile-panel.js
++++ b/profile-panel.js
@@@ -29,8 +29,12 @@
function load(username) {
if (!seen.has(username)) {
-- seen.set(username, fetch(`${api()}/api/v1/profiles/${encodeURIComponent(username)}`, { credentials: 'omit', headers: { Accept: 'application/json' } })
-- .then((r) => (r.ok ? r.json() : null)).then((b) => (b && b.profile) || null).catch(() => null));
++ // At most eight seconds, and a failure is not kept: a request held while Network restarted used to stay in
++ // this map for the page's life, so that person's panel never opened again (11-03, the Live name card).
++ const signal = typeof AbortSignal !== 'undefined' && AbortSignal.timeout ? AbortSignal.timeout(8000) : undefined;
++ seen.set(username, fetch(`${api()}/api/v1/profiles/${encodeURIComponent(username)}`, { credentials: 'omit', headers: { Accept: 'application/json' }, signal })
++ .then((r) => (r.ok ? r.json() : null)).then((b) => (b && b.profile) || null)
++ .catch(() => { seen.delete(username); return null; }));
}
return seen.get(username);
}
ddiff --git a/test/card-fetch-limits.test.js b/test/card-fetch-limits.test.js
nnew file mode 100644
iindex 0000000..c1dd780
---- /dev/null
++++ b/test/card-fetch-limits.test.js
@@@ -0,0 +1,17 @@
++'use strict';
++// A name card never waits on a restarting service (11-03: Maticus's Live name card sat on "Loading..." for minutes
++// while a deploy round restarted Chat). The shared profile panel and user card give a lookup eight seconds, and the
++// panel does not keep a failed lookup, so a later click on the same name asks again.
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++const read = (f) => fs.readFileSync(path.join(__dirname, '..', f), 'utf8');
++
++const panel = read('profile-panel.js');
++assert.match(panel, /AbortSignal\.timeout\(8000\)/);
++assert.match(panel, /headers: \{ Accept: 'application\/json' \}, signal \}\)/, 'the panel\'s lookup carries the limit');
++assert.match(panel, /\.catch\(\(\) => \{ seen\.delete\(username\); return null; \}\)/, 'a failed lookup is not kept');
++const card = read('user-card.js');
++assert.match(card, /AbortSignal\.timeout\(8000\)/);
++assert.match(card, /credentials: 'include', signal \}\)/, 'the card\'s lookup carries the limit');
++console.log('card fetch limits: ok');
ddiff --git a/user-card.js b/user-card.js
iindex d26e798..143d5b5 100644
---- a/user-card.js
++++ b/user-card.js
@@@ -94,7 +94,9 @@
try {
const headers = {};
if (_config.token) headers['Authorization'] = `Bearer ${_config.token}`;
-- const res = await fetch(`${_config.apiBase}/api/users/${userId}/card`, { headers, credentials: 'include' });
++ // At most eight seconds: a click never waits on a service that is restarting (11-03).
++ const signal = typeof AbortSignal !== 'undefined' && AbortSignal.timeout ? AbortSignal.timeout(8000) : undefined;
++ const res = await fetch(`${_config.apiBase}/api/users/${userId}/card`, { headers, credentials: 'include', signal });
if (!res.ok) return null;
const data = await res.json();
_cache.set(userId, data);