dotrino-content 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/public.js CHANGED
@@ -106,18 +106,22 @@ export async function fetchPublic ({ client, owner, cid, head = false, full = fa
106
106
  if (!isValidCid(cid)) throw err('bad-input', 'invalid cid')
107
107
  const tokens = await findNodes({ client, owner })
108
108
  if (!tokens.length) throw err('no-node', 'no node of that owner is online')
109
- let last = null
110
- for (const token of tokens) {
111
- try {
112
- return await fetchFrom({ client, token, cid, head, full, timeoutMs })
113
- } catch (e) {
114
- last = e
115
- // Si el node CONTESTÓ que no (privado, no existe), otro node del mismo dueño
116
- // dirá lo mismo: no tiene sentido insistir. Solo se reintenta lo que fue ruido.
117
- if (e.code && e.code !== 'timeout' && e.code !== 'corrupt') throw e
109
+ // A TODOS a la vez, y se queda con el primero que conteste bien. En serie, cada
110
+ // token de un node ya apagado —el proxio los conserva un rato— costaba un timeout
111
+ // entero antes de llegar al que sí está vivo. Un `not-found` es una respuesta de
112
+ // verdad (otro node del mismo dueño diría lo mismo) y gana sobre los silencios.
113
+ return new Promise((resolve, reject) => {
114
+ let pending = tokens.length
115
+ let answered = null // el primer error "de verdad" (el node contestó que no)
116
+ let noise = null // timeout / corrupt: no dicen nada del contenido
117
+ for (const token of tokens) {
118
+ fetchFrom({ client, token, cid, head, full, timeoutMs }).then(resolve, (e) => {
119
+ if (e.code && e.code !== 'timeout' && e.code !== 'corrupt') answered = answered || e
120
+ else noise = noise || e
121
+ if (--pending === 0) reject(answered || noise || err('no-node', 'no node answered'))
122
+ })
118
123
  }
119
- }
120
- throw last || err('no-node', 'no node answered')
124
+ })
121
125
  }
122
126
 
123
127
  export default { channelFor, findNodes, fetchFrom, fetchPublic, MSG, FETCH_MAX_BYTES }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotrino-content",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Nodo de contenido del ecosistema Dotrino: guarda los bytes del usuario direccionados por su hash (cid), en su propia maquina y, si el dueno quiere, respaldados en su propio bucket (R2, Backblaze, Hetzner, Storj o S3). Lo publico sale por URL directa; lo privado, cifrado y solo por la red Dotrino.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,9 +23,9 @@
23
23
  "typescript": "5.9.3"
24
24
  },
25
25
  "dependencies": {
26
- "@dotrino/identity": "0.56.0",
27
- "@dotrino/remote-agent": "0.4.1",
28
- "@dotrino/vault": "0.28.0"
26
+ "@dotrino/identity": "0.57.0",
27
+ "@dotrino/remote-agent": "0.5.1",
28
+ "@dotrino/vault": "0.30.0"
29
29
  },
30
30
  "keywords": [
31
31
  "dotrino",
package/src/agent.js CHANGED
@@ -90,12 +90,18 @@ export async function startContentAgent ({
90
90
  const beacon = announce && agent.client
91
91
  ? startAnnounce({ client: agent.client, owner, quiet })
92
92
  : null
93
+ // LECTURA PÚBLICA por la red (§16): un tercero con el enlace pide el `cid` en un
94
+ // mensaje suelto y recibe solo lo marcado público. Sin esto, anunciarse no sirve
95
+ // de nada: el enlace nombraría a un node que no contesta a nadie.
96
+ const fetcher = agent.client ? startPublicFetch({ client: agent.client, node, quiet }) : null
93
97
 
94
98
  return {
95
99
  ...agent,
96
100
  owner,
97
101
  channels: () => beacon?.channels() || [],
102
+ served: () => fetcher?.served() || 0,
98
103
  close () {
104
+ try { fetcher?.close() } catch (_) {}
99
105
  try { beacon?.close() } catch (_) {}
100
106
  agent.close()
101
107
  }
package/src/announce.js CHANGED
@@ -78,7 +78,7 @@ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPU
78
78
  }
79
79
  const first = !current.length && done.length
80
80
  current = done
81
- if (first && !quiet) console.log(`[content] anunciado como node de ${owner.slice(0, 16)} en ${done.length} proxio(s)`)
81
+ if (first && !quiet) console.log(`[content] anunciado como node de ${owner.slice(0, 16)} en ${done.length} proxio(s) · token ${client.token}`)
82
82
  }
83
83
 
84
84
  publishAll()
package/src/fetch.js CHANGED
@@ -50,6 +50,7 @@ export function startPublicFetch ({ client, node, ratePerMin = 60, quiet = false
50
50
  const handle = async (from, p) => {
51
51
  const rid = typeof p.rid === 'string' ? p.rid : null
52
52
  if (!rid) return
53
+ if (!quiet) console.log(`[content] fetch ${String(p.cid).slice(0, 20)}… from ${String(from).slice(0, 16)}${p.head ? ' (head)' : ''}`)
53
54
  if (!allowed(from)) return fail(from, rid, 'rate-limited', 'too many requests')
54
55
  if (!isValidCid(p.cid)) return fail(from, rid, 'bad-input', 'invalid cid')
55
56
  const meta = node.stat(p.cid)