agents/blobs/BlobsAgent.tsView |
---|
30 | 30 … | } |
31 | 31 … | |
32 | 32 … | class PendingWant { |
33 | 33 … | readonly created: number; |
| 34 … | + readonly interestedPeers: Set<string> = new Set<string>(); |
34 | 35 … | |
35 | 36 … | constructor( |
36 | 37 … | public want: BlobWant, |
37 | | - public alreadyAsked: Set<FeedId> = new Set<FeedId>(), |
| 38 … | + onBehalfOf?: FeedId, |
| 39 … | + public alreadyAsked: Set<string> = new Set<string>(), |
38 | 40 … | ) { |
39 | 41 … | this.created = Date.now(); |
| 42 … | + if (onBehalfOf) { |
| 43 … | + this.interestedPeers.add(onBehalfOf.base64Key); |
| 44 … | + } |
40 | 45 … | } |
41 | 46 … | |
42 | 47 … | [x: string]: unknown |
43 | 48 … | } |
55 | 60 … | want(blobId: BlobId) { |
56 | 61 … | this.processWant(new BlobWant(blobId)); |
57 | 62 … | } |
58 | 63 … | |
59 | | - private processWant(want: BlobWant) { |
60 | | - |
61 | | - this.wantFeeds.forEach((f) => f(want)); |
62 | | - |
63 | | - this.pendingWants.set(want.blobId.base64Key, new PendingWant(want)); |
| 64 … | + private processWant(want: BlobWant, onBehalfOf?: FeedId) { |
| 65 … | + const alreadyPendingWant = this.pendingWants.get( |
| 66 … | + want.blobId.base64FilenameSafe, |
| 67 … | + ); |
| 68 … | + if (alreadyPendingWant) { |
| 69 … | + if (onBehalfOf) { |
| 70 … | + alreadyPendingWant.interestedPeers.add(onBehalfOf.base64Key); |
| 71 … | + } |
| 72 … | + } else { |
| 73 … | + |
| 74 … | + for (const f of this.wantFeeds.entries()) { |
| 75 … | + if (f[0] !== onBehalfOf?.base64Key) { |
| 76 … | + f[1](want); |
| 77 … | + } |
| 78 … | + } |
| 79 … | + |
| 80 … | + this.pendingWants.set( |
| 81 … | + want.blobId.base64Key, |
| 82 … | + new PendingWant(want, onBehalfOf), |
| 83 … | + ); |
| 84 … | + } |
64 | 85 … | } |
65 | 86 … | |
66 | | - private wantFeeds = new Set<(_: BlobWant) => void>(); |
| 87 … | + |
| 88 … | + private wantFeeds = new Map<string, (_: BlobWant) => void>(); |
67 | 89 … | |
68 | 90 … | |
69 | 91 … | private pendingWants = new Map<string, PendingWant>(); |
70 | 92 … | |
89 | 111 … | args: Record<string, string>[], |
90 | 112 … | ): AsyncIterable<Record<string, unknown>> { |
91 | 113 … | log.info(`${feedId} invoked blobs.createWants with ${args}`); |
92 | 114 … | for (const p of pendingWants.values()) { |
93 | | - if (!p.alreadyAsked.has(feedId)) { |
| 115 … | + if ( |
| 116 … | + !p.alreadyAsked.has(feedId.base64Key) && |
| 117 … | + !p.interestedPeers.has(feedId.base64Key) |
| 118 … | + ) { |
94 | 119 … | yield p.want.shortWant; |
95 | | - p.alreadyAsked.add(feedId); |
| 120 … | + p.alreadyAsked.add(feedId.base64Key); |
96 | 121 … | } |
97 | 122 … | } |
98 | 123 … | while (true) { |
99 | 124 … | yield await new Promise((resolve) => { |
100 | 125 … | |
101 | 126 … | value: new BlobWant(new BlobId(new Uint8Array())), |
102 | 127 … | });*/ |
103 | 128 … | const wanter = ((want: BlobWant) => { |
104 | | - wantFeeds.delete(wanter); |
| 129 … | + wantFeeds.delete(feedId.base64Key); |
105 | 130 … | resolve({ value: want.shortWant }); |
106 | 131 … | }); |
107 | | - wantFeeds.add(wanter); |
| 132 … | + wantFeeds.set(feedId.base64Key, wanter); |
108 | 133 … | }); |
109 | 134 … | } |
110 | 135 … | }, |
111 | 136 … | }, |
132 | 157 … | `Got has/want from ${rpcConnection.boxConnection.peer}: ${ |
133 | 158 … | JSON.stringify(hasOrWant) |
134 | 159 … | }`, |
135 | 160 … | ); |
136 | | - if (hasOrWant.level > 0) { |
| 161 … | + if (hasOrWant.level >= 0) { |
137 | 162 … | |
138 | 163 … | if (this.pendingWants.has(hasOrWant.blobId.base64Key)) { |
139 | 164 … | const pendingWant = this.pendingWants.get( |
140 | 165 … | hasOrWant.blobId.base64Key, |
141 | | - ); |
| 166 … | + )!; |
142 | 167 … | await this.retrieveBlobFromPeer( |
143 | | - pendingWant!.want.blobId, |
| 168 … | + pendingWant.want.blobId, |
144 | 169 … | rpcConnection.boxConnection.peer, |
145 | 170 … | ); |
| 171 … | + |
| 172 … | + await Promise.all( |
| 173 … | + [...pendingWant.interestedPeers].map(async (feedKey) => { |
| 174 … | + const wantFeed = this.wantFeeds.get(feedKey); |
| 175 … | + if (wantFeed) { |
| 176 … | + wantFeed( |
| 177 … | + new BlobWant( |
| 178 … | + hasOrWant.blobId, |
| 179 … | + (await FsStorage.getBlob(hasOrWant.blobId)).length, |
| 180 … | + ), |
| 181 … | + ); |
| 182 … | + } |
| 183 … | + }), |
| 184 … | + ); |
146 | 185 … | } |
| 186 … | + } else { |
| 187 … | + |
| 188 … | + if (await FsStorage.hasBlob(hasOrWant.blobId)) { |
| 189 … | + const wantFeed = this.wantFeeds.get( |
| 190 … | + rpcConnection.boxConnection.peer.base64Key, |
| 191 … | + ); |
| 192 … | + if (wantFeed) { |
| 193 … | + const blob = await FsStorage.getBlob(hasOrWant.blobId); |
| 194 … | + wantFeed(new BlobWant(hasOrWant.blobId, blob.length)); |
| 195 … | + } else { |
| 196 … | + |
| 197 … | + log.warning( |
| 198 … | + `${rpcConnection.boxConnection.peer} asked for a blob we have, but we can't tell them`, |
| 199 … | + ); |
| 200 … | + } |
| 201 … | + } else { |
| 202 … | + this.processWant( |
| 203 … | + new BlobWant(hasOrWant.blobId, hasOrWant.level - 1), |
| 204 … | + rpcConnection.boxConnection.peer, |
| 205 … | + ); |
| 206 … | + } |
147 | 207 … | } |
148 | 208 … | } |
149 | 209 … | } |
150 | 210 … | } |