diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub')
13 files changed, 60 insertions, 4 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/connection-pool.js b/packages/meshbay-hub/src/meshbay_hub/static/connection-pool.js index 15d352a7..8a616c2a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/connection-pool.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/connection-pool.js @@ -58,6 +58,12 @@ const SEARCH_MAX_MS = 30000; * opened fine from the sidebar. A refusal naming a state of this browser (a * code, a passphrase, a device) is the same from every node and stops the * walk; `not_hosted`, a timeout or a failed connection moves on. + * + * So does a node this device refuses to reach on the local network (Android + * 17, Chrome 155: transport.js localNetworkRefused): another node of the group + * may be elsewhere. Search gives up long before connect() would name it, so it + * is read from the connection when giving up, and it is what is thrown when + * no node answered: the page says what to change rather than "unreachable". */ async function connectToGroup(hubBase, groupId, token, bundleKey, username, userId) { const nodesData = await hubFetch(`/v1/groups/${groupId}/nodes`, { token }); @@ -65,6 +71,7 @@ async function connectToGroup(hubBase, groupId, token, bundleKey, username, user const live = (await ensureFreshToken()) || token; let lastErr = null; + let lanErr = null; for (const n of nodesData.nodes) { const transport = new window.MeshBayTransport(hubBase, live); transport.onNeedToken = async () => (await ensureFreshToken()) || token; @@ -96,11 +103,16 @@ async function connectToGroup(hubBase, groupId, token, bundleKey, username, user } catch (e) { stopTimers(); lastErr = e; + if (!e.reason && await transport.localNetworkRefused()) { + lastErr = new Error('This device refused to reach the local network'); + lastErr.reason = 'local_network_blocked'; + } try { transport.close(); } catch {} + if (lastErr.reason === 'local_network_blocked') { lanErr = lastErr; continue; } if (e.reason && e.reason !== 'not_hosted') throw e; } } - throw (lastErr || new Error('no node served this group')); + throw (lanErr || lastErr || new Error('no node served this group')); } // -- Connection pool ---------------------------------------------------------- diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js index ae2dcfbf..228402c9 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -859,6 +859,7 @@ export default { 'search.hint': 'Tippen Sie einen Begriff ein, um in allen Ihren Gruppen zu suchen.', 'search.indexing': 'Indexierung von {done} / {total} Gruppen …', 'search.unreachable': { one: '{n} Gruppe nicht erreichbar', other: '{n} Gruppen nicht erreichbar' }, + 'search.lan_blocked': { one: "Dieses Gerät verweigert den Zugriff auf das lokale Netzwerk, in dem der Node dieser Gruppe ist. Öffnen Sie sie, um zu sehen, wie Sie ihn erlauben:", other: "Dieses Gerät verweigert den Zugriff auf das lokale Netzwerk, in dem die Nodes dieser {n} Gruppen sind. Öffnen Sie eine, um zu sehen, wie Sie ihn erlauben:" }, 'search.n_sources': { one: '{n} Quelle', other: '{n} Quellen' }, 'search.view_files': 'Dateien', 'search.view_videos': 'Videos', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js index e5ed9cb3..40c20244 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js @@ -976,6 +976,7 @@ export default { 'search.hint': 'Type to search file names across all your groups.', 'search.indexing': 'Indexing {done} / {total} groups...', 'search.unreachable': { one: '{n} group unreachable', other: '{n} groups unreachable' }, + 'search.lan_blocked': { one: "This device refuses to reach the local network, where this group's node is. Open it to see how to allow it:", other: "This device refuses to reach the local network, where the nodes of these {n} groups are. Open one to see how to allow it:" }, 'search.n_sources': { one: '{n} source', other: '{n} sources' }, 'search.view_files': 'Files', 'search.view_videos': 'Videos', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js index 9801f741..643fdeab 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -854,6 +854,7 @@ export default { 'search.hint': 'Escriba un término para buscar en todos sus grupos.', 'search.indexing': 'Indexando {done} / {total} grupos…', 'search.unreachable': { one: '{n} grupo inalcanzable', other: '{n} grupos inalcanzables' }, + 'search.lan_blocked': { one: "Este dispositivo se niega a acceder a la red local, donde está el node de este grupo. Ábralo para ver cómo permitirlo:", other: "Este dispositivo se niega a acceder a la red local, donde están los nodes de estos {n} grupos. Abra uno para ver cómo permitirlo:" }, 'search.n_sources': { one: '{n} fuente', other: '{n} fuentes' }, 'search.view_files': 'Archivos', 'search.view_videos': 'Vídeos', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js index b0dfd37b..8df543e4 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js @@ -857,6 +857,7 @@ export default { 'search.hint': 'Saisissez un terme pour rechercher dans tous vos groupes.', 'search.indexing': 'Indexation de {done} / {total} groupes…', 'search.unreachable': { one: '{n} groupe injoignable', other: '{n} groupes injoignables' }, + 'search.lan_blocked': { one: "Cet appareil refuse de joindre le réseau local, où se trouve le node de ce groupe. Ouvrez-le pour savoir comment l’autoriser :", other: "Cet appareil refuse de joindre le réseau local, où se trouvent les nodes de ces {n} groupes. Ouvrez-en un pour savoir comment l’autoriser :" }, 'search.n_sources': { one: '{n} source', other: '{n} sources' }, 'search.view_files': 'Fichiers', 'search.view_videos': 'Vidéos', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js index 22e09deb..8912af69 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js @@ -856,6 +856,7 @@ export default { 'search.hint': 'Digita un termine per cercare in tutti i tuoi gruppi.', 'search.indexing': 'Indicizzazione di {done} / {total} gruppi…', 'search.unreachable': { one: '{n} gruppo non raggiungibile', other: '{n} gruppi non raggiungibili' }, + 'search.lan_blocked': { one: "Questo dispositivo rifiuta di raggiungere la rete locale, dove si trova il node di questo gruppo. Aprilo per vedere come consentirlo:", other: "Questo dispositivo rifiuta di raggiungere la rete locale, dove si trovano i node di questi {n} gruppi. Aprine uno per vedere come consentirlo:" }, 'search.n_sources': { one: '{n} fonte', other: '{n} fonti' }, 'search.view_files': 'File', 'search.view_videos': 'Video', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js index a4645ac3..01a84dc9 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js @@ -844,6 +844,7 @@ export default { 'search.hint': '入力してすべてのグループを検索します。', 'search.indexing': '{done} / {total} グループをインデックス中…', 'search.unreachable': { other: '{n} グループに接続できません' }, + 'search.lan_blocked': { other: "このデバイスはローカルネットワークへの接続を拒否しています。このネットワークに {n} 件のグループの node があります。グループを開くと、許可する方法が表示されます:" }, 'search.n_sources': { other: '{n} 個のソース' }, 'search.view_files': 'ファイル', 'search.view_videos': '動画', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js index 0f31f6cb..dec9e9f5 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js @@ -858,6 +858,7 @@ export default { 'search.hint': 'Typ een zoekterm om in al uw groepen te zoeken.', 'search.indexing': '{done} / {total} groepen indexeren…', 'search.unreachable': { one: '{n} groep onbereikbaar', other: '{n} groepen onbereikbaar' }, + 'search.lan_blocked': { one: "Dit apparaat weigert het lokale netwerk te bereiken, waar de node van deze groep staat. Open hem om te zien hoe je het toestaat:", other: "Dit apparaat weigert het lokale netwerk te bereiken, waar de nodes van deze {n} groepen staan. Open er een om te zien hoe je het toestaat:" }, 'search.n_sources': { one: '{n} bron', other: '{n} bronnen' }, 'search.view_files': 'Bestanden', 'search.view_videos': 'Video\'s', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js index c89a60d3..0de71416 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js @@ -878,6 +878,7 @@ export default { 'search.hint': 'Wpisz frazę, aby wyszukać we wszystkich grupach.', 'search.indexing': 'Indeksowanie {done} / {total} grup…', 'search.unreachable': { one: '{n} grupa nieosiągalna', few: '{n} grupy nieosiągalne', many: '{n} grup nieosiągalnych', other: '{n} grupy nieosiągalnej' }, + 'search.lan_blocked': { one: "To urządzenie odmawia połączenia z siecią lokalną, w której jest node tej grupy. Otwórz ją, aby zobaczyć, jak na to zezwolić:", few: "To urządzenie odmawia połączenia z siecią lokalną, w której są node’y tych {n} grup. Otwórz jedną, aby zobaczyć, jak na to zezwolić:", many: "To urządzenie odmawia połączenia z siecią lokalną, w której są node’y tych {n} grup. Otwórz jedną, aby zobaczyć, jak na to zezwolić:", other: "To urządzenie odmawia połączenia z siecią lokalną, w której są node’y tych {n} grup. Otwórz jedną, aby zobaczyć, jak na to zezwolić:" }, 'search.n_sources': { one: '{n} źródło', few: '{n} źródła', many: '{n} źródeł', other: '{n} źródła' }, 'search.view_files': 'Pliki', 'search.view_videos': 'Filmy', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js index aa33e177..89e854c1 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js @@ -855,6 +855,7 @@ export default { 'search.hint': 'Digite um termo para pesquisar em todos os seus grupos.', 'search.indexing': 'Indexando {done} / {total} grupos…', 'search.unreachable': { one: '{n} grupo inacessível', other: '{n} grupos inacessíveis' }, + 'search.lan_blocked': { one: "Este dispositivo se recusa a acessar a rede local, onde está o node deste grupo. Abra-o para ver como permitir:", other: "Este dispositivo se recusa a acessar a rede local, onde estão os nodes destes {n} grupos. Abra um para ver como permitir:" }, 'search.n_sources': { one: '{n} fonte', other: '{n} fontes' }, 'search.view_files': 'Arquivos', 'search.view_videos': 'Vídeos', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js index 27f20dc7..08bf5593 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js @@ -832,6 +832,7 @@ export default { 'search.hint': '输入关键词搜索所有群组。', 'search.indexing': '正在索引 {done} / {total} 个群组…', 'search.unreachable': { other: '{n} 个群组无法连接' }, + 'search.lan_blocked': { other: "此设备拒绝访问本地网络,而 {n} 个群组的 node 就在该网络中。打开群组即可查看如何允许:" }, 'search.n_sources': { other: '{n} 个来源' }, 'search.view_files': '文件', 'search.view_videos': '视频', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/search-page.js b/packages/meshbay-hub/src/meshbay_hub/static/search-page.js index ae8eac75..d0150a8e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/search-page.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/search-page.js @@ -15,6 +15,7 @@ import { VideoPlayer } from './video-player.js'; import { transfers } from './transfers.js'; import { copyLink, entryPath, groupItemLink } from './copy-link.js'; import { say } from './note.js'; +import { groupLinkRoute } from './group-link.js'; import { mergeUnitEntries } from './source-merge.js'; import { useStickyBand } from './sticky.js'; import { ConnectionPool, MAX_IN_FLIGHT, MAX_POOL_SIZE } from './connection-pool.js'; @@ -139,6 +140,9 @@ async function fetchAllIndexes(pool, groups, token, username, userId, onProgress const total = groups.length; let done = 0; const unreachable = []; + // Groups whose node this device refused to reach on the local network: a + // setting to change, said apart from the groups that did not answer. + const lanBlocked = []; const downNow = new Set(); const results = new Map(); @@ -168,7 +172,8 @@ async function fetchAllIndexes(pool, groups, token, username, userId, onProgress downNow.add(g.id); } } catch (e) { - unreachable.push(g.name || g.id); + if (e && e.reason === 'local_network_blocked') lanBlocked.push(g); + else unreachable.push(g.name || g.id); // Still refused after transport.js's retries: the hub was busy, which // says nothing about this group's node, so it keeps its place next time. if (!(e && e.status === 429)) downNow.add(g.id); @@ -179,7 +184,7 @@ async function fetchAllIndexes(pool, groups, token, username, userId, onProgress // A sweep cut short by the page closing saw nothing about any node: every // group left was refused by this page, not by its node. if (!(pool && pool.closed)) rememberDown(downNow); - return { results, unreachable }; + return { results, unreachable, lanBlocked }; } // -- SearchPage --------------------------------------------------------------- @@ -263,6 +268,7 @@ function SearchPage({ token, username, userId, groups, onPlayQueue, userPrefs }) const [indexedGroups, setIndexedGroups] = useState(new Map()); const [progress, setProgress] = useState({ done: 0, total: 0, unreachable: [] }); const [fetching, setFetching] = useState(false); + const [lanBlocked, setLanBlocked] = useState([]); // Bumped by the Files breadcrumb refresh button — re-runs the all-groups // index fetch below, the only "cache" this page has. const [refreshTick, setRefreshTick] = useState(0); @@ -314,9 +320,10 @@ function SearchPage({ token, username, userId, groups, onPlayQueue, userPrefs }) (async () => { setFetching(true); setProgress({ done: 0, total: groups.length, unreachable: [] }); + setLanBlocked([]); if (!poolRef.current) return; - const { unreachable } = await fetchAllIndexes( + const { unreachable, lanBlocked: refused } = await fetchAllIndexes( poolRef.current, groups, token, username, userId, (p) => { if (!cancelled) setProgress(p); }, (results) => { if (!cancelled) setIndexedGroups(new Map(results)); }, @@ -324,6 +331,9 @@ function SearchPage({ token, username, userId, groups, onPlayQueue, userPrefs }) if (cancelled) return; setFetching(false); + // Left up, unlike the line below: there is something to do about it, + // and the group page says what (group-page.js explainLanRefusal). + setLanBlocked(refused); // Said once the pass is over, for a few seconds, rather than left above // the results: by then nothing more can be done about it here, and a // line that stays is one more thing between the reader and the results. @@ -714,6 +724,14 @@ function SearchPage({ token, username, userId, groups, onPlayQueue, userPrefs }) `} </div> + ${lanBlocked.length > 0 && html` + <p class="settings-hint"> + ${t('search.lan_blocked', { n: lanBlocked.length })}${' '} + ${lanBlocked.map((g, i) => html`${i ? ', ' : ''}<a + href=${'#' + groupLinkRoute(g)}>${g.name || g.id}</a>`)} + </p> + `} + ${fetching && html` <div class="search-progress"> <span class="spinner"></span> diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js index 11088adc..98a6ecfa 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js @@ -844,6 +844,21 @@ class MeshBayTransport { this._wakeReconnect(); } + /** + * Whether the connection being made is refused the local network, read from + * what is paired so far: the signature is there as soon as ICE checks + * begin, where connect() names it only once ICE gives up, half a minute. + * For a caller that stops waiting before that (connection-pool.js). + */ + async localNetworkRefused() { + const pc = this._pc; + if (!pc || !this._rawAnswerSdp || !pc.localDescription) return false; + if (pc.iceConnectionState === 'connected' || pc.iceConnectionState === 'completed') { + return false; + } + return _localNetworkRefusedBy(pc, pc.localDescription.sdp, this._rawAnswerSdp); + } + get connected() { return this._connected; } /** True while _reconnectLoop is running, backoff included. */ get reconnecting() { return !!this._reconnectPromise; } @@ -1015,6 +1030,7 @@ class MeshBayTransport { // the composer, exactly like one that had. this._setDevicePk('', 'new connection'); this._sessionUp = false; + this._rawAnswerSdp = null; this._pc = new RTCPeerConnection({ iceServers: await iceServers() }); this._channel = this._pc.createDataChannel('mnp', { ordered: true }); |