@peerbit/pubsub 1.1.13 → 2.0.1

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/esm/index.js CHANGED
@@ -1,13 +1,12 @@
1
1
  import { logger as logFn } from "@peerbit/logger";
2
- import { DataMessage } from "@peerbit/stream-interface";
2
+ import { AcknowledgeDelivery, AnyWhere, DataMessage, MessageHeader, SeekDelivery, SilentDelivery } from "@peerbit/stream-interface";
3
3
  import { DirectStream } from "@peerbit/stream";
4
- import { CodeError } from "@libp2p/interface/errors";
5
- import { PubSubMessage, Subscribe, PubSubData, toUint8Array, Unsubscribe, GetSubscribers, Subscription, UnsubcriptionEvent, SubscriptionEvent, DataEvent, SubscriptionData } from "@peerbit/pubsub-interface";
4
+ import { CodeError } from "@libp2p/interface";
5
+ import { PubSubMessage, Subscribe, PubSubData, toUint8Array, Unsubscribe, GetSubscribers, UnsubcriptionEvent, SubscriptionEvent, DataEvent, SubscriptionData, PublishEvent } from "@peerbit/pubsub-interface";
6
6
  import { getPublicKeyFromPeerId, PublicSignKey } from "@peerbit/crypto";
7
- import { CustomEvent } from "@libp2p/interface/events";
8
- import { waitFor } from "@peerbit/time";
9
- import { equals, startsWith } from "@peerbit/uint8arrays";
10
- export const logger = logFn({ module: "direct-sub", level: "warn" });
7
+ import { CustomEvent } from "@libp2p/interface";
8
+ export const logger = logFn({ module: "lazysub", level: "warn" });
9
+ const logError = (e) => logger.error(e?.message);
11
10
  export class DirectSub extends DirectStream {
12
11
  topics; // topic -> peers --> Uint8Array subscription metadata (the latest received)
13
12
  peerToTopic; // peer -> topics
@@ -15,7 +14,7 @@ export class DirectSub extends DirectStream {
15
14
  subscriptions; // topic -> subscription ids
16
15
  lastSubscriptionMessages = new Map();
17
16
  constructor(components, props) {
18
- super(components, ["pubsub/0.0.0"], props);
17
+ super(components, ["/lazysub/0.0.0"], props);
19
18
  this.subscriptions = new Map();
20
19
  this.topics = new Map();
21
20
  this.topicsToPeers = new Map();
@@ -28,15 +27,6 @@ export class DirectSub extends DirectStream {
28
27
  this.topicsToPeers.clear();
29
28
  return super.stop();
30
29
  }
31
- async onPeerReachable(publicKey) {
32
- // Aggregate subscribers for my topics through this new peer because if we don't do this we might end up with a situtation where
33
- // we act as a relay and relay messages for a topic, but don't forward it to this new peer because we never learned about their subscriptions
34
- await this.requestSubscribers([...this.topics.keys()], publicKey);
35
- return super.onPeerReachable(publicKey);
36
- }
37
- async onPeerDisconnected(peerId, conn) {
38
- return super.onPeerDisconnected(peerId, conn);
39
- }
40
30
  initializeTopic(topic) {
41
31
  this.topics.get(topic) || this.topics.set(topic, new Map());
42
32
  this.topicsToPeers.get(topic) || this.topicsToPeers.set(topic, new Set());
@@ -48,43 +38,30 @@ export class DirectSub extends DirectStream {
48
38
  /**
49
39
  * Subscribes to a given topic.
50
40
  */
51
- /**
52
- * @param topic,
53
- * @param data, metadata associated with the subscription, shared with peers
54
- */
55
- async subscribe(topic, options) {
41
+ async subscribe(topic) {
56
42
  if (!this.started) {
57
43
  throw new Error("Pubsub has not started");
58
44
  }
59
- topic = typeof topic === "string" ? [topic] : topic;
60
45
  const newTopicsForTopicData = [];
61
- for (const t of topic) {
62
- const prev = this.subscriptions.get(t);
63
- if (prev) {
64
- const difference = !!prev.data != !!options?.data ||
65
- (prev.data && options?.data && !equals(prev.data, options?.data));
66
- prev.counter += 1;
67
- if (difference) {
68
- prev.data = options?.data;
69
- newTopicsForTopicData.push(t);
70
- }
71
- }
72
- else {
73
- this.subscriptions.set(t, {
74
- counter: 1,
75
- data: options?.data
76
- });
77
- newTopicsForTopicData.push(t);
78
- this.listenForSubscribers(t);
79
- }
46
+ const prev = this.subscriptions.get(topic);
47
+ if (prev) {
48
+ prev.counter += 1;
49
+ }
50
+ else {
51
+ this.subscriptions.set(topic, {
52
+ counter: 1
53
+ });
54
+ newTopicsForTopicData.push(topic);
55
+ this.listenForSubscribers(topic);
80
56
  }
81
57
  if (newTopicsForTopicData.length > 0) {
82
58
  const message = new DataMessage({
83
59
  data: toUint8Array(new Subscribe({
84
- subscriptions: newTopicsForTopicData.map((x) => new Subscription(x, options?.data))
85
- }).bytes())
60
+ topics: newTopicsForTopicData
61
+ }).bytes()),
62
+ header: new MessageHeader({ mode: new SeekDelivery({ redundancy: 2 }) })
86
63
  });
87
- await this.publishMessage(this.components.peerId, await message.sign(this.sign));
64
+ await this.publishMessage(this.publicKey, await message.sign(this.sign));
88
65
  }
89
66
  }
90
67
  /**
@@ -109,53 +86,40 @@ export class DirectSub extends DirectStream {
109
86
  }
110
87
  }
111
88
  if (!subscriptions?.counter || options?.force) {
89
+ await this.publishMessage(this.publicKey, await new DataMessage({
90
+ header: new MessageHeader({
91
+ mode: new AnyWhere( /* {
92
+ redundancy: 2,
93
+ to: [...this.getPeersOnTopics([topic])]
94
+ } */)
95
+ }),
96
+ data: toUint8Array(new Unsubscribe({ topics: [topic] }).bytes())
97
+ }).sign(this.sign));
112
98
  this.subscriptions.delete(topic);
113
99
  this.topics.delete(topic);
114
100
  this.topicsToPeers.delete(topic);
115
- await this.publishMessage(this.components.peerId, await new DataMessage({
116
- data: toUint8Array(new Unsubscribe({ topics: [topic] }).bytes())
117
- }).sign(this.sign));
118
101
  return true;
119
102
  }
120
103
  return false;
121
104
  }
122
105
  getSubscribers(topic) {
123
- if (!this.started) {
124
- throw new CodeError("not started yet", "ERR_NOT_STARTED_YET");
106
+ const remote = this.topics.get(topic.toString());
107
+ if (!remote) {
108
+ return undefined;
125
109
  }
126
- if (topic == null) {
127
- throw new CodeError("topic is required", "ERR_NOT_VALID_TOPIC");
110
+ const ret = [];
111
+ for (const v of remote.values()) {
112
+ ret.push(v.publicKey);
128
113
  }
129
- return this.topics.get(topic.toString());
130
- }
131
- getSubscribersWithData(topic, data, options) {
132
- const map = this.topics.get(topic);
133
- if (map) {
134
- const results = [];
135
- for (const [peer, info] of map.entries()) {
136
- if (!info.data) {
137
- continue;
138
- }
139
- if (options?.prefix) {
140
- if (!startsWith(info.data, data)) {
141
- continue;
142
- }
143
- }
144
- else {
145
- if (!equals(info.data, data)) {
146
- continue;
147
- }
148
- }
149
- results.push(peer);
150
- }
151
- return results;
114
+ if (this.subscriptions.get(topic)) {
115
+ ret.push(this.publicKey);
152
116
  }
153
- return;
117
+ return ret;
154
118
  }
155
119
  listenForSubscribers(topic) {
156
120
  this.initializeTopic(topic);
157
121
  }
158
- async requestSubscribers(topic, from) {
122
+ async requestSubscribers(topic, to) {
159
123
  if (!this.started) {
160
124
  throw new CodeError("not started yet", "ERR_NOT_STARTED_YET");
161
125
  }
@@ -169,24 +133,29 @@ export class DirectSub extends DirectStream {
169
133
  for (const topic of topics) {
170
134
  this.listenForSubscribers(topic);
171
135
  }
172
- return this.publishMessage(this.components.peerId, await new DataMessage({
173
- to: from ? [from.hashcode()] : [],
174
- data: toUint8Array(new GetSubscribers({ topics }).bytes())
136
+ return this.publishMessage(this.publicKey, await new DataMessage({
137
+ data: toUint8Array(new GetSubscribers({ topics }).bytes()),
138
+ header: new MessageHeader({
139
+ mode: new SeekDelivery({
140
+ to: to ? [to.hashcode()] : [],
141
+ redundancy: 2
142
+ })
143
+ })
175
144
  }).sign(this.sign));
176
145
  }
177
- getPeersWithTopics(topics, otherPeers) {
178
- const peers = otherPeers ? new Set(otherPeers) : new Set();
146
+ getPeersOnTopics(topics) {
147
+ const newPeers = new Set();
179
148
  if (topics?.length) {
180
149
  for (const topic of topics) {
181
150
  const peersOnTopic = this.topicsToPeers.get(topic.toString());
182
151
  if (peersOnTopic) {
183
152
  peersOnTopic.forEach((peer) => {
184
- peers.add(peer);
153
+ newPeers.add(peer);
185
154
  });
186
155
  }
187
156
  }
188
157
  }
189
- return peers;
158
+ return newPeers;
190
159
  }
191
160
  /* getStreamsWithTopics(topics: string[], otherPeers?: string[]): PeerStreams[] {
192
161
  const peers = this.getNeighboursWithTopics(topics, otherPeers);
@@ -203,22 +172,28 @@ export class DirectSub extends DirectStream {
203
172
  ? x.hashcode()
204
173
  : typeof x === "string"
205
174
  ? x
206
- : getPublicKeyFromPeerId(x).hashcode()) || this.getPeersWithTopics(topics);
175
+ : getPublicKeyFromPeerId(x).hashcode()) || this.getPeersOnTopics(topics);
207
176
  // Embedd topic info before the data so that peers/relays can also use topic info to route messages efficiently
208
- const dataMessage = new PubSubData({
209
- topics: topics.map((x) => x.toString()),
210
- data,
211
- strict: options.strict
212
- });
213
- const bytes = dataMessage.bytes();
177
+ const dataMessage = data
178
+ ? new PubSubData({
179
+ topics: topics.map((x) => x.toString()),
180
+ data,
181
+ strict: !!options?.to
182
+ })
183
+ : undefined;
184
+ const bytes = dataMessage?.bytes();
214
185
  const message = await this.createMessage(bytes, { ...options, to: tos });
215
- if (this.emitSelf) {
216
- super.dispatchEvent(new CustomEvent("data", {
217
- detail: new DataEvent(dataMessage, message)
186
+ if (dataMessage) {
187
+ this.dispatchEvent(new CustomEvent("publish", {
188
+ detail: new PublishEvent({
189
+ client: options?.client,
190
+ data: dataMessage,
191
+ message
192
+ })
218
193
  }));
219
194
  }
220
195
  // send to all the other peers
221
- await this.publishMessage(this.components.peerId, message, undefined);
196
+ await this.publishMessage(this.publicKey, message, undefined);
222
197
  return message.id;
223
198
  }
224
199
  deletePeerFromTopic(topic, publicKeyHash) {
@@ -235,28 +210,48 @@ export class DirectSub extends DirectStream {
235
210
  this.topicsToPeers.get(topic)?.delete(publicKeyHash);
236
211
  return change;
237
212
  }
238
- onPeerUnreachable(publicKey) {
239
- super.onPeerUnreachable(publicKey);
240
- const publicKeyHash = publicKey.hashcode();
213
+ async onPeerReachable(publicKey) {
214
+ // Aggregate subscribers for my topics through this new peer because if we don't do this we might end up with a situtation where
215
+ // we act as a relay and relay messages for a topic, but don't forward it to this new peer because we never learned about their subscriptions
216
+ /* await this.requestSubscribers([...this.topics.keys()], publicKey); */
217
+ const resp = super.onPeerReachable(publicKey);
218
+ const stream = this.peers.get(publicKey.hashcode());
219
+ if (stream && this.subscriptions.size > 0) {
220
+ // is new neighbour
221
+ // tell the peer about all topics we subscribe to
222
+ this.publishMessage(this.publicKey, await new DataMessage({
223
+ data: toUint8Array(new Subscribe({
224
+ topics: [...this.subscriptions.keys()]
225
+ }).bytes()),
226
+ header: new MessageHeader({
227
+ mode: new SeekDelivery({ redundancy: 2 })
228
+ })
229
+ }).sign(this.sign)),
230
+ [stream];
231
+ }
232
+ return resp;
233
+ }
234
+ onPeerUnreachable(publicKeyHash) {
235
+ super.onPeerUnreachable(publicKeyHash);
241
236
  const peerTopics = this.peerToTopic.get(publicKeyHash);
242
237
  const changed = [];
243
238
  if (peerTopics) {
244
239
  for (const topic of peerTopics) {
245
240
  const change = this.deletePeerFromTopic(topic, publicKeyHash);
246
241
  if (change) {
247
- changed.push(new Subscription(topic, change.data));
242
+ changed.push(topic);
248
243
  }
249
244
  }
250
245
  }
251
246
  this.lastSubscriptionMessages.delete(publicKeyHash);
252
247
  if (changed.length > 0) {
253
248
  this.dispatchEvent(new CustomEvent("unsubscribe", {
254
- detail: new UnsubcriptionEvent(publicKey, changed)
249
+ detail: new UnsubcriptionEvent(this.peerKeyHashToPublicKey.get(publicKeyHash), changed)
255
250
  }));
256
251
  }
257
252
  }
258
253
  subscriptionMessageIsLatest(message, pubsubMessage) {
259
- const subscriber = message.signatures.signatures[0].publicKey;
254
+ const subscriber = message.header.signatures.signatures[0].publicKey;
260
255
  const subscriberKey = subscriber.hashcode(); // Assume first signature is the one who is signing
261
256
  for (const topic of pubsubMessage.topics) {
262
257
  const lastTimestamp = this.lastSubscriptionMessages
@@ -274,167 +269,204 @@ export class DirectSub extends DirectStream {
274
269
  }
275
270
  return true;
276
271
  }
277
- async onDataMessage(from, stream, message) {
272
+ addPeersOnTopic(message, topics) {
273
+ const existingPeers = new Set(message.header.mode.to);
274
+ const allPeersOnTopic = this.getPeersOnTopics(topics);
275
+ for (const existing of existingPeers) {
276
+ allPeersOnTopic.add(existing);
277
+ }
278
+ allPeersOnTopic.delete(this.publicKeyHash);
279
+ message.header.mode.to = [...allPeersOnTopic];
280
+ }
281
+ async onDataMessage(from, stream, message, seenBefore) {
282
+ if (!message.data || message.data.length === 0) {
283
+ return super.onDataMessage(from, stream, message, seenBefore);
284
+ }
285
+ if (this.shouldIgnore(message, seenBefore)) {
286
+ return false;
287
+ }
278
288
  const pubsubMessage = PubSubMessage.from(message.data);
279
289
  if (pubsubMessage instanceof PubSubData) {
290
+ if (message.header.mode instanceof AnyWhere) {
291
+ throw new Error("Unexpected mode for PubSubData messages");
292
+ }
280
293
  /**
281
294
  * See if we know more subscribers of the message topics. If so, add aditional end receivers of the message
282
295
  */
283
- let verified = undefined;
284
- const isFromSelf = this.components.peerId.equals(from);
285
- if (!isFromSelf || this.emitSelf) {
286
- let isForMe;
287
- if (pubsubMessage.strict) {
288
- isForMe =
289
- !!pubsubMessage.topics.find((topic) => this.subscriptions.has(topic)) && !!message.to.find((x) => this.publicKeyHash === x);
290
- }
291
- else {
292
- isForMe =
293
- !!pubsubMessage.topics.find((topic) => this.subscriptions.has(topic)) ||
294
- (pubsubMessage.topics.length === 0 &&
295
- !!message.to.find((x) => this.publicKeyHash === x));
296
+ let isForMe;
297
+ if (pubsubMessage.strict) {
298
+ isForMe =
299
+ !!pubsubMessage.topics.find((topic) => this.subscriptions.has(topic)) && !!message.header.mode.to?.find((x) => this.publicKeyHash === x);
300
+ }
301
+ else {
302
+ isForMe =
303
+ !!pubsubMessage.topics.find((topic) => this.subscriptions.has(topic)) ||
304
+ (pubsubMessage.topics.length === 0 &&
305
+ !!message.header.mode.to?.find((x) => this.publicKeyHash === x));
306
+ }
307
+ if (isForMe) {
308
+ if ((await this.maybeVerifyMessage(message)) === false) {
309
+ logger.warn("Recieved message that did not verify PubSubData");
310
+ return false;
296
311
  }
297
- if (isForMe) {
298
- if (verified === undefined) {
299
- verified = await message.verify(this.signaturePolicy === "StictSign" ? true : false);
300
- }
301
- if (!verified) {
302
- logger.warn("Recieved message that did not verify PubSubData");
303
- return false;
304
- }
312
+ await this.acknowledgeMessage(stream, message, seenBefore);
313
+ if (seenBefore === 0) {
305
314
  this.dispatchEvent(new CustomEvent("data", {
306
- detail: new DataEvent(pubsubMessage, message)
315
+ detail: new DataEvent({
316
+ data: pubsubMessage,
317
+ message
318
+ })
307
319
  }));
308
320
  }
309
321
  }
322
+ if (message.header.mode.to) {
323
+ message.header.mode.to = message.header.mode.to.filter((x) => x !== this.publicKeyHash);
324
+ }
310
325
  // Forward
311
326
  if (!pubsubMessage.strict) {
312
- const newTos = this.getPeersWithTopics(pubsubMessage.topics, message.to);
313
- newTos.delete(this.publicKeyHash);
314
- message.to = [...newTos];
327
+ this.addPeersOnTopic(message, pubsubMessage.topics);
315
328
  }
316
329
  // Only relay if we got additional receivers
317
330
  // or we are NOT subscribing ourselves (if we are not subscribing ourselves we are)
318
331
  // If we are not subscribing ourselves, then we don't have enough information to "stop" message propagation here
319
- if (message.to.length > 0 ||
320
- !pubsubMessage.topics.find((topic) => this.topics.has(topic))) {
321
- await this.relayMessage(from, message);
332
+ if (message.header.mode.to?.length ||
333
+ 0 > 0 ||
334
+ !pubsubMessage.topics.find((topic) => this.topics.has(topic)) ||
335
+ message.header.mode instanceof SeekDelivery) {
336
+ // DONT await this since it might introduce a dead-lock
337
+ this.relayMessage(from, message).catch(logError);
322
338
  }
323
339
  }
324
- else if (pubsubMessage instanceof Subscribe) {
340
+ else {
325
341
  if (!(await message.verify(true))) {
326
- logger.warn("Recieved message that did not verify Subscribe");
342
+ logger.warn("Recieved message that did not verify Unsubscribe");
327
343
  return false;
328
344
  }
329
- if (message.signatures.signatures.length === 0) {
345
+ if (message.header.signatures.signatures.length === 0) {
330
346
  logger.warn("Recieved subscription message with no signers");
331
347
  return false;
332
348
  }
333
- if (pubsubMessage.subscriptions.length === 0) {
334
- logger.info("Recieved subscription message with no topics");
335
- return false;
336
- }
337
- if (!this.subscriptionMessageIsLatest(message, pubsubMessage)) {
338
- logger.trace("Recieved old subscription message");
339
- return false;
340
- }
341
- const subscriber = message.signatures.signatures[0].publicKey;
342
- const subscriberKey = subscriber.hashcode(); // Assume first signature is the one who is signing
343
- this.initializePeer(subscriber);
344
- const changed = [];
345
- pubsubMessage.subscriptions.forEach((subscription) => {
346
- const peers = this.topics.get(subscription.topic);
347
- if (peers == null) {
348
- return;
349
+ await this.acknowledgeMessage(stream, message, seenBefore);
350
+ const sender = message.header.signatures.signatures[0].publicKey;
351
+ const senderKey = sender.hashcode(); // Assume first signature is the one who is signing
352
+ if (pubsubMessage instanceof Subscribe) {
353
+ if (pubsubMessage.topics.length === 0) {
354
+ logger.info("Recieved subscription message with no topics");
355
+ return false;
349
356
  }
350
- // if no subscription data, or new subscription has data (and is newer) then overwrite it.
351
- // subscription where data is undefined is not intended to replace existing data
352
- const existingSubscription = peers.get(subscriberKey);
353
- if (!existingSubscription ||
354
- (existingSubscription.timestamp < message.header.timetamp &&
355
- subscription.data)) {
356
- peers.set(subscriberKey, new SubscriptionData({
357
- timestamp: message.header.timetamp,
358
- data: subscription.data,
359
- publicKey: subscriber
357
+ if (!this.subscriptionMessageIsLatest(message, pubsubMessage)) {
358
+ logger.trace("Recieved old subscription message");
359
+ return false;
360
+ }
361
+ this.initializePeer(sender);
362
+ const changed = [];
363
+ pubsubMessage.topics.forEach((topic) => {
364
+ const peers = this.topics.get(topic);
365
+ if (peers == null) {
366
+ return;
367
+ }
368
+ // if no subscription data, or new subscription has data (and is newer) then overwrite it.
369
+ // subscription where data is undefined is not intended to replace existing data
370
+ const existingSubscription = peers.get(senderKey);
371
+ if (!existingSubscription ||
372
+ existingSubscription.timestamp < message.header.timetamp) {
373
+ peers.set(senderKey, new SubscriptionData({
374
+ timestamp: message.header.timetamp, // TODO update timestamps on all messages?
375
+ publicKey: sender
376
+ }));
377
+ if (!existingSubscription) {
378
+ changed.push(topic);
379
+ }
380
+ }
381
+ this.topicsToPeers.get(topic)?.add(senderKey);
382
+ this.peerToTopic.get(senderKey)?.add(topic);
383
+ });
384
+ if (changed.length > 0) {
385
+ this.dispatchEvent(new CustomEvent("subscribe", {
386
+ detail: new SubscriptionEvent(sender, changed)
360
387
  }));
361
- if (!existingSubscription?.data ||
362
- !equals(existingSubscription.data, subscription.data)) {
363
- changed.push(subscription);
388
+ // also send back a message telling the remote whether we are subsbscring
389
+ if (message.header.mode instanceof SeekDelivery) {
390
+ // only if Subscribe message is of 'seek' type we will respond with our subscriptions
391
+ const mySubscriptions = changed
392
+ .map((x) => {
393
+ const subscription = this.subscriptions.get(x);
394
+ return subscription ? x : undefined;
395
+ })
396
+ .filter((x) => !!x);
397
+ if (mySubscriptions.length > 0) {
398
+ const response = new DataMessage({
399
+ data: toUint8Array(new Subscribe({
400
+ topics: mySubscriptions
401
+ }).bytes()),
402
+ // needs to be Ack or Silent else we will run into a infite message loop
403
+ header: new MessageHeader({
404
+ mode: new AcknowledgeDelivery({
405
+ redundancy: 2,
406
+ to: [sender.hashcode()]
407
+ })
408
+ })
409
+ });
410
+ await this.publishMessage(this.publicKey, await response.sign(this.sign));
411
+ }
364
412
  }
365
413
  }
366
- this.topicsToPeers.get(subscription.topic)?.add(subscriberKey);
367
- this.peerToTopic.get(subscriberKey)?.add(subscription.topic);
368
- });
369
- if (changed.length > 0) {
370
- this.dispatchEvent(new CustomEvent("subscribe", {
371
- detail: new SubscriptionEvent(subscriber, changed)
372
- }));
373
- }
374
- // Forward
375
- await this.relayMessage(from, message);
376
- }
377
- else if (pubsubMessage instanceof Unsubscribe) {
378
- if (!(await message.verify(true))) {
379
- logger.warn("Recieved message that did not verify Unsubscribe");
380
- return false;
381
- }
382
- if (message.signatures.signatures.length === 0) {
383
- logger.warn("Recieved subscription message with no signers");
384
- return false;
385
- }
386
- if (!this.subscriptionMessageIsLatest(message, pubsubMessage)) {
387
- logger.trace("Recieved old subscription message");
388
- return false;
414
+ // Forward
415
+ // DONT await this since it might introduce a dead-lock
416
+ this.relayMessage(from, message).catch(logError);
389
417
  }
390
- const changed = [];
391
- const subscriber = message.signatures.signatures[0].publicKey;
392
- const subscriberKey = subscriber.hashcode(); // Assume first signature is the one who is signing
393
- for (const unsubscription of pubsubMessage.unsubscriptions) {
394
- const change = this.deletePeerFromTopic(unsubscription.topic, subscriberKey);
395
- if (change) {
396
- changed.push(new Subscription(unsubscription.topic, change.data));
418
+ else if (pubsubMessage instanceof Unsubscribe) {
419
+ if (!this.subscriptionMessageIsLatest(message, pubsubMessage)) {
420
+ logger.trace("Recieved old subscription message");
421
+ return false;
397
422
  }
398
- }
399
- if (changed.length > 0) {
400
- this.dispatchEvent(new CustomEvent("unsubscribe", {
401
- detail: new UnsubcriptionEvent(subscriber, changed)
402
- }));
403
- }
404
- // Forward
405
- await this.relayMessage(from, message);
406
- }
407
- else if (pubsubMessage instanceof GetSubscribers) {
408
- if (!(await message.verify(true))) {
409
- logger.warn("Recieved message that did not verify GetSubscribers");
410
- return false;
411
- }
412
- const subscriptionsToSend = [];
413
- for (const topic of pubsubMessage.topics) {
414
- const subscription = this.subscriptions.get(topic);
415
- if (subscription) {
416
- subscriptionsToSend.push(new Subscription(topic, subscription.data));
423
+ const changed = [];
424
+ for (const unsubscription of pubsubMessage.topics) {
425
+ const change = this.deletePeerFromTopic(unsubscription, senderKey);
426
+ if (change) {
427
+ changed.push(unsubscription);
428
+ }
429
+ }
430
+ if (changed.length > 0) {
431
+ this.dispatchEvent(new CustomEvent("unsubscribe", {
432
+ detail: new UnsubcriptionEvent(sender, changed)
433
+ }));
434
+ }
435
+ // Forward
436
+ if (message.header.mode instanceof SeekDelivery ||
437
+ message.header.mode instanceof SilentDelivery ||
438
+ message.header.mode instanceof AcknowledgeDelivery) {
439
+ this.addPeersOnTopic(message, pubsubMessage.topics);
417
440
  }
441
+ // DONT await this since it might introduce a dead-lock
442
+ this.relayMessage(from, message).catch(logError);
418
443
  }
419
- if (subscriptionsToSend.length > 0) {
420
- // respond
421
- if (!stream.isWritable) {
422
- try {
423
- await waitFor(() => stream.isWritable);
424
- }
425
- catch (error) {
426
- logger.warn(`Failed to respond to GetSubscribers request to ${from.toString()} stream is not writable`);
427
- return false;
444
+ else if (pubsubMessage instanceof GetSubscribers) {
445
+ const subscriptionsToSend = [];
446
+ for (const topic of pubsubMessage.topics) {
447
+ const subscription = this.subscriptions.get(topic);
448
+ if (subscription) {
449
+ subscriptionsToSend.push(topic);
428
450
  }
429
451
  }
430
- this.publishMessage(this.components.peerId, await new DataMessage({
431
- data: toUint8Array(new Subscribe({
432
- subscriptions: subscriptionsToSend
433
- }).bytes())
434
- }).sign(this.sign), [stream]); // send back to same stream
452
+ if (subscriptionsToSend.length > 0) {
453
+ // respond
454
+ this.publishMessage(this.publicKey, await new DataMessage({
455
+ data: toUint8Array(new Subscribe({
456
+ topics: subscriptionsToSend
457
+ }).bytes()),
458
+ header: new MessageHeader({
459
+ mode: new SilentDelivery({
460
+ redundancy: 2,
461
+ to: [sender.hashcode()]
462
+ })
463
+ })
464
+ }).sign(this.sign), [stream]); // send back to same stream
465
+ }
466
+ // Forward
467
+ // DONT await this since it might introduce a dead-lock
468
+ this.relayMessage(from, message).catch(logError);
435
469
  }
436
- // Forward
437
- await this.relayMessage(from, message);
438
470
  }
439
471
  return true;
440
472
  }
@@ -455,7 +487,7 @@ export const waitForSubscribers = async (libp2p, peersToWait, topic) => {
455
487
  ? id.hashcode()
456
488
  : getPublicKeyFromPeerId(id).hashcode();
457
489
  });
458
- await libp2p.services.pubsub.requestSubscribers(topic);
490
+ // await libp2p.services.pubsub.requestSubscribers(topic);
459
491
  return new Promise((resolve, reject) => {
460
492
  let counter = 0;
461
493
  const interval = setInterval(async () => {
@@ -465,7 +497,7 @@ export const waitForSubscribers = async (libp2p, peersToWait, topic) => {
465
497
  reject(new Error("Failed to find expected subscribers for topic: " + topic));
466
498
  }
467
499
  try {
468
- const peers = await libp2p.services.pubsub.getSubscribers(topic);
500
+ const peers = await libp2p.services.pubsub.topics.get(topic);
469
501
  const hasAllPeers = peerIdsToWait
470
502
  .map((e) => peers && peers.has(e))
471
503
  .filter((e) => e === false).length === 0;