@leofcoin/peernet 1.0.8 → 1.0.10

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.
@@ -1,4 +1,4 @@
1
- import { L as LittlePubSub } from './peernet-749c4cfa.js';
1
+ import { L as LittlePubSub } from './peernet-7ba6837f.js';
2
2
  import './value-157ab062.js';
3
3
 
4
4
  var clientApi = _pubsub => {
@@ -224,422 +224,422 @@ const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry
224
224
  });
225
225
  };
226
226
 
227
- class Peer {
228
- #connection;
229
- #connected = false;
230
- #messageQue = [];
231
- #chunksQue = {};
232
- #channel;
233
- #peerId;
234
- #channelName;
235
- #chunkSize = 16 * 1024; // 16384
236
- #queRunning = false;
237
- #MAX_BUFFERED_AMOUNT = 16 * 1024 * 1024;
238
- get connection() {
239
- return this.#connection;
240
- }
241
- get connected() {
242
- return this.#connected;
243
- }
244
- get readyState() {
245
- return this.#channel?.readyState;
246
- }
247
- /**
248
- * @params {Object} options
249
- * @params {string} options.channelName - this peerid : otherpeer id
250
- */
251
- constructor(options = {}) {
252
- this._in = this._in.bind(this);
253
- this.offerOptions = options.offerOptions;
254
- this.initiator = options.initiator;
255
- this.streams = options.streams;
256
- this.socketClient = options.socketClient;
257
- this.id = options.id;
258
- this.to = options.to;
259
- this.bw = {
260
- up: 0,
261
- down: 0
262
- };
263
- this.#channelName = options.channelName;
264
- this.#peerId = options.peerId;
265
- this.options = options;
266
- return this.#init();
267
- }
268
- get peerId() {
269
- return this.#peerId;
270
- }
271
- set socketClient(value) {
272
- // this.socketClient?.pubsub.unsubscribe('signal', this._in)
273
- this._socketClient = value;
274
- this._socketClient.pubsub.subscribe('signal', this._in);
275
- }
276
- get socketClient() {
277
- return this._socketClient;
278
- }
279
- splitMessage(message) {
280
- const chunks = [];
281
- message = pako.deflate(message);
282
- const size = message.byteLength || message.length;
283
- let offset = 0;
284
- return new Promise((resolve, reject) => {
285
- const splitMessage = () => {
286
- const chunk = message.slice(offset, offset + this.#chunkSize > size ? size : offset + this.#chunkSize);
287
- offset += this.#chunkSize;
288
- chunks.push(chunk);
289
- if (offset < size)
290
- return splitMessage();
291
- else
292
- resolve({ chunks, size });
293
- };
294
- splitMessage();
295
- });
296
- }
297
- async #runQue() {
298
- this.#queRunning = true;
299
- if (this.#messageQue.length > 0 && this.#channel?.bufferedAmount + this.#messageQue[0]?.length < this.#MAX_BUFFERED_AMOUNT) {
300
- const message = this.#messageQue.shift();
301
- switch (this.#channel?.readyState) {
302
- case 'open':
303
- await this.#channel.send(message);
304
- if (this.#messageQue.length > 0)
305
- return this.#runQue();
306
- else
307
- this.#queRunning = false;
308
- break;
309
- case 'closed':
310
- case 'closing':
311
- this.#messageQue = [];
312
- this.#queRunning = false;
313
- debug('channel already closed, this usually means a bad implementation, try checking the readyState or check if the peer is connected before sending');
314
- break;
315
- case undefined:
316
- this.#messageQue = [];
317
- this.#queRunning = false;
318
- debug(`trying to send before a channel is created`);
319
- break;
320
- }
321
- }
322
- else {
323
- return setTimeout(() => this.#runQue(), 50);
324
- }
325
- }
326
- #trySend({ size, id, chunks }) {
327
- let offset = 0;
328
- for (const chunk of chunks) {
329
- const start = offset;
330
- const end = offset + chunk.length;
331
- const message = new TextEncoder().encode(JSON.stringify({ size, id, chunk, start, end }));
332
- this.#messageQue.push(message);
333
- }
334
- if (!this.queRunning)
335
- return this.#runQue();
336
- }
337
- async send(message, id) {
338
- const { chunks, size } = await this.splitMessage(message);
339
- return this.#trySend({ size, id, chunks });
340
- }
341
- request(data) {
342
- return new Promise((resolve, reject) => {
343
- const id = Math.random().toString(36).slice(-12);
344
- const _onData = message => {
345
- if (message.id === id) {
346
- resolve(message.data);
347
- pubsub.unsubscribe(`peer:data`, _onData);
348
- }
349
- };
350
- pubsub.subscribe(`peer:data`, _onData);
351
- // cleanup subscriptions
352
- // setTimeout(() => {
353
- // pubsub.unsubscribe(`peer:data-request-${id}`, _onData)
354
- // }, 5000);
355
- this.send(data, id);
356
- });
357
- }
358
- async #init() {
359
- try {
360
- if (!globalThis.pako) {
361
- const importee = await import('./pako.esm-aa674ebf.js');
362
- globalThis.pako = importee.default;
363
- }
364
- const iceServers = [{
365
- urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
366
- }, {
367
- urls: "stun:openrelay.metered.ca:80",
368
- }, {
369
- urls: "turn:openrelay.metered.ca:443",
370
- username: "openrelayproject",
371
- credential: "openrelayproject",
372
- }, {
373
- urls: "turn:openrelay.metered.ca:443?transport=tcp",
374
- username: "openrelayproject",
375
- credential: "openrelayproject",
376
- }];
377
- this.#connection = new wrtc.RTCPeerConnection({ iceServers });
378
- this.#connection.onicecandidate = ({ candidate }) => {
379
- if (candidate) {
380
- this.address = candidate.address;
381
- this.port = candidate.port;
382
- this.protocol = candidate.protocol;
383
- this.ipFamily = this.address.includes('::') ? 'ipv6' : 'ipv4';
384
- this._sendMessage({ candidate });
385
- }
386
- };
387
- // if (this.initiator) this.#connection.onnegotiationneeded = () => {
388
- // console.log('create offer');
389
- this.#connection.ondatachannel = (message) => {
390
- message.channel.onopen = () => {
391
- this.#connected = true;
392
- // debug(`peer:connected ${this}`)
393
- pubsub.publish('peer:connected', this);
394
- };
395
- message.channel.onclose = () => this.close.bind(this);
396
- message.channel.onmessage = (message) => {
397
- this._handleMessage(this.id, message);
398
- };
399
- this.#channel = message.channel;
400
- };
401
- if (this.initiator) {
402
- this.#channel = this.#connection.createDataChannel('messageChannel');
403
- this.#channel.onopen = () => {
404
- this.#connected = true;
405
- pubsub.publish('peer:connected', this);
406
- // this.#channel.send('hi')
407
- };
408
- this.#channel.onclose = () => this.close.bind(this);
409
- this.#channel.onmessage = (message) => {
410
- this._handleMessage(this.peerId, message);
411
- };
412
- const offer = await this.#connection.createOffer();
413
- await this.#connection.setLocalDescription(offer);
414
- this._sendMessage({ 'sdp': this.#connection.localDescription });
415
- }
416
- }
417
- catch (e) {
418
- console.log(e);
419
- }
420
- return this;
421
- }
422
- _handleMessage(peerId, message) {
423
- // debug(`incoming message from ${peerId}`)
424
- message = JSON.parse(new TextDecoder().decode(message.data));
425
- // allow sharding (multiple peers share data)
426
- pubsub.publish('peernet:shard', message);
427
- const { id } = message;
428
- if (!this.#chunksQue[id])
429
- this.#chunksQue[id] = [];
430
- if (message.size > this.#chunksQue[id].length || message.size === this.#chunksQue[id].length) {
431
- for (const value of Object.values(message.chunk)) {
432
- this.#chunksQue[id].push(value);
433
- }
434
- }
435
- if (message.size === this.#chunksQue[id].length) {
436
- let data = new Uint8Array(Object.values(this.#chunksQue[id]));
437
- delete this.#chunksQue[id];
438
- data = pako.inflate(data);
439
- pubsub.publish('peer:data', { id, data, from: this.peerId });
440
- }
441
- this.bw.down += message.byteLength || message.length;
442
- }
443
- _sendMessage(message) {
444
- this.socketClient.send({ url: 'signal', params: {
445
- to: this.to,
446
- from: this.id,
447
- channelName: this.options.channelName,
448
- ...message
449
- } });
450
- }
451
- async _in(message, data) {
452
- // message = JSON.parse(message);
453
- if (!this.#connection || message.to !== this.id || message.from !== this.#peerId)
454
- return;
455
- // if (data.videocall) return this._startStream(true, false); // start video and audio stream
456
- // if (data.call) return this._startStream(true, true); // start audio stream
457
- if (this.#connection?.signalinState === 'stable' && this.#connection?.remoteDescription !== null && this.#connection?.localDescription !== null)
458
- return;
459
- if (message.candidate) {
460
- // debug(`incoming candidate ${this.#channelName}`)
461
- // debug(message.candidate.candidate)
462
- this.remoteAddress = message.candidate.address;
463
- this.remotePort = message.candidate.port;
464
- this.remoteProtocol = message.candidate.protocol;
465
- this.remoteIpFamily = this.remoteAddress?.includes('::') ? 'ipv6' : 'ipv4';
466
- return this.#connection.addIceCandidate(new wrtc.RTCIceCandidate(message.candidate));
467
- }
468
- try {
469
- if (message.sdp) {
470
- if (message.sdp.type === 'offer') {
471
- // debug(`incoming offer ${this.#channelName}`)
472
- await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
473
- const answer = await this.#connection.createAnswer();
474
- await this.#connection.setLocalDescription(answer);
475
- this._sendMessage({ 'sdp': this.#connection.localDescription });
476
- }
477
- if (message.sdp.type === 'answer') {
478
- // debug(`incoming answer ${this.#channelName}`)
479
- await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
480
- }
481
- }
482
- }
483
- catch (e) {
484
- console.log(e);
485
- }
486
- }
487
- close() {
488
- // debug(`closing ${this.peerId}`)
489
- this.#connected = false;
490
- this.#channel?.close();
491
- this.#connection?.close();
492
- this.socketClient.pubsub.unsubscribe('signal', this._in);
493
- }
227
+ class Peer {
228
+ #connection;
229
+ #connected = false;
230
+ #messageQue = [];
231
+ #chunksQue = {};
232
+ #channel;
233
+ #peerId;
234
+ #channelName;
235
+ #chunkSize = 16 * 1024; // 16384
236
+ #queRunning = false;
237
+ #MAX_BUFFERED_AMOUNT = 16 * 1024 * 1024;
238
+ get connection() {
239
+ return this.#connection;
240
+ }
241
+ get connected() {
242
+ return this.#connected;
243
+ }
244
+ get readyState() {
245
+ return this.#channel?.readyState;
246
+ }
247
+ /**
248
+ * @params {Object} options
249
+ * @params {string} options.channelName - this peerid : otherpeer id
250
+ */
251
+ constructor(options = {}) {
252
+ this._in = this._in.bind(this);
253
+ this.offerOptions = options.offerOptions;
254
+ this.initiator = options.initiator;
255
+ this.streams = options.streams;
256
+ this.socketClient = options.socketClient;
257
+ this.id = options.id;
258
+ this.to = options.to;
259
+ this.bw = {
260
+ up: 0,
261
+ down: 0
262
+ };
263
+ this.#channelName = options.channelName;
264
+ this.#peerId = options.peerId;
265
+ this.options = options;
266
+ return this.#init();
267
+ }
268
+ get peerId() {
269
+ return this.#peerId;
270
+ }
271
+ set socketClient(value) {
272
+ // this.socketClient?.pubsub.unsubscribe('signal', this._in)
273
+ this._socketClient = value;
274
+ this._socketClient.pubsub.subscribe('signal', this._in);
275
+ }
276
+ get socketClient() {
277
+ return this._socketClient;
278
+ }
279
+ splitMessage(message) {
280
+ const chunks = [];
281
+ message = pako.deflate(message);
282
+ const size = message.byteLength || message.length;
283
+ let offset = 0;
284
+ return new Promise((resolve, reject) => {
285
+ const splitMessage = () => {
286
+ const chunk = message.slice(offset, offset + this.#chunkSize > size ? size : offset + this.#chunkSize);
287
+ offset += this.#chunkSize;
288
+ chunks.push(chunk);
289
+ if (offset < size)
290
+ return splitMessage();
291
+ else
292
+ resolve({ chunks, size });
293
+ };
294
+ splitMessage();
295
+ });
296
+ }
297
+ async #runQue() {
298
+ this.#queRunning = true;
299
+ if (this.#messageQue.length > 0 && this.#channel?.bufferedAmount + this.#messageQue[0]?.length < this.#MAX_BUFFERED_AMOUNT) {
300
+ const message = this.#messageQue.shift();
301
+ switch (this.#channel?.readyState) {
302
+ case 'open':
303
+ await this.#channel.send(message);
304
+ if (this.#messageQue.length > 0)
305
+ return this.#runQue();
306
+ else
307
+ this.#queRunning = false;
308
+ break;
309
+ case 'closed':
310
+ case 'closing':
311
+ this.#messageQue = [];
312
+ this.#queRunning = false;
313
+ debug('channel already closed, this usually means a bad implementation, try checking the readyState or check if the peer is connected before sending');
314
+ break;
315
+ case undefined:
316
+ this.#messageQue = [];
317
+ this.#queRunning = false;
318
+ debug(`trying to send before a channel is created`);
319
+ break;
320
+ }
321
+ }
322
+ else {
323
+ return setTimeout(() => this.#runQue(), 50);
324
+ }
325
+ }
326
+ #trySend({ size, id, chunks }) {
327
+ let offset = 0;
328
+ for (const chunk of chunks) {
329
+ const start = offset;
330
+ const end = offset + chunk.length;
331
+ const message = new TextEncoder().encode(JSON.stringify({ size, id, chunk, start, end }));
332
+ this.#messageQue.push(message);
333
+ }
334
+ if (!this.queRunning)
335
+ return this.#runQue();
336
+ }
337
+ async send(message, id) {
338
+ const { chunks, size } = await this.splitMessage(message);
339
+ return this.#trySend({ size, id, chunks });
340
+ }
341
+ request(data) {
342
+ return new Promise((resolve, reject) => {
343
+ const id = Math.random().toString(36).slice(-12);
344
+ const _onData = message => {
345
+ if (message.id === id) {
346
+ resolve(message.data);
347
+ pubsub.unsubscribe(`peer:data`, _onData);
348
+ }
349
+ };
350
+ pubsub.subscribe(`peer:data`, _onData);
351
+ // cleanup subscriptions
352
+ // setTimeout(() => {
353
+ // pubsub.unsubscribe(`peer:data-request-${id}`, _onData)
354
+ // }, 5000);
355
+ this.send(data, id);
356
+ });
357
+ }
358
+ async #init() {
359
+ try {
360
+ if (!globalThis.pako) {
361
+ const importee = await import('./pako.esm-aa674ebf.js');
362
+ globalThis.pako = importee.default;
363
+ }
364
+ const iceServers = [{
365
+ urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
366
+ }, {
367
+ urls: "stun:openrelay.metered.ca:80",
368
+ }, {
369
+ urls: "turn:openrelay.metered.ca:443",
370
+ username: "openrelayproject",
371
+ credential: "openrelayproject",
372
+ }, {
373
+ urls: "turn:openrelay.metered.ca:443?transport=tcp",
374
+ username: "openrelayproject",
375
+ credential: "openrelayproject",
376
+ }];
377
+ this.#connection = new wrtc.RTCPeerConnection({ iceServers });
378
+ this.#connection.onicecandidate = ({ candidate }) => {
379
+ if (candidate) {
380
+ this.address = candidate.address;
381
+ this.port = candidate.port;
382
+ this.protocol = candidate.protocol;
383
+ this.ipFamily = this.address.includes('::') ? 'ipv6' : 'ipv4';
384
+ this._sendMessage({ candidate });
385
+ }
386
+ };
387
+ // if (this.initiator) this.#connection.onnegotiationneeded = () => {
388
+ // console.log('create offer');
389
+ this.#connection.ondatachannel = (message) => {
390
+ message.channel.onopen = () => {
391
+ this.#connected = true;
392
+ // debug(`peer:connected ${this}`)
393
+ pubsub.publish('peer:connected', this);
394
+ };
395
+ message.channel.onclose = () => this.close.bind(this);
396
+ message.channel.onmessage = (message) => {
397
+ this._handleMessage(this.id, message);
398
+ };
399
+ this.#channel = message.channel;
400
+ };
401
+ if (this.initiator) {
402
+ this.#channel = this.#connection.createDataChannel('messageChannel');
403
+ this.#channel.onopen = () => {
404
+ this.#connected = true;
405
+ pubsub.publish('peer:connected', this);
406
+ // this.#channel.send('hi')
407
+ };
408
+ this.#channel.onclose = () => this.close.bind(this);
409
+ this.#channel.onmessage = (message) => {
410
+ this._handleMessage(this.peerId, message);
411
+ };
412
+ const offer = await this.#connection.createOffer();
413
+ await this.#connection.setLocalDescription(offer);
414
+ this._sendMessage({ 'sdp': this.#connection.localDescription });
415
+ }
416
+ }
417
+ catch (e) {
418
+ console.log(e);
419
+ }
420
+ return this;
421
+ }
422
+ _handleMessage(peerId, message) {
423
+ // debug(`incoming message from ${peerId}`)
424
+ message = JSON.parse(new TextDecoder().decode(message.data));
425
+ // allow sharding (multiple peers share data)
426
+ pubsub.publish('peernet:shard', message);
427
+ const { id } = message;
428
+ if (!this.#chunksQue[id])
429
+ this.#chunksQue[id] = [];
430
+ if (message.size > this.#chunksQue[id].length || message.size === this.#chunksQue[id].length) {
431
+ for (const value of Object.values(message.chunk)) {
432
+ this.#chunksQue[id].push(value);
433
+ }
434
+ }
435
+ if (message.size === this.#chunksQue[id].length) {
436
+ let data = new Uint8Array(Object.values(this.#chunksQue[id]));
437
+ delete this.#chunksQue[id];
438
+ data = pako.inflate(data);
439
+ pubsub.publish('peer:data', { id, data, from: this.peerId });
440
+ }
441
+ this.bw.down += message.byteLength || message.length;
442
+ }
443
+ _sendMessage(message) {
444
+ this.socketClient.send({ url: 'signal', params: {
445
+ to: this.to,
446
+ from: this.id,
447
+ channelName: this.options.channelName,
448
+ ...message
449
+ } });
450
+ }
451
+ async _in(message, data) {
452
+ // message = JSON.parse(message);
453
+ if (!this.#connection || message.to !== this.id || message.from !== this.#peerId)
454
+ return;
455
+ // if (data.videocall) return this._startStream(true, false); // start video and audio stream
456
+ // if (data.call) return this._startStream(true, true); // start audio stream
457
+ if (this.#connection?.signalingState === 'stable' && this.#connection?.remoteDescription !== null && this.#connection?.localDescription !== null)
458
+ return;
459
+ if (message.candidate) {
460
+ // debug(`incoming candidate ${this.#channelName}`)
461
+ // debug(message.candidate.candidate)
462
+ this.remoteAddress = message.candidate.address;
463
+ this.remotePort = message.candidate.port;
464
+ this.remoteProtocol = message.candidate.protocol;
465
+ this.remoteIpFamily = this.remoteAddress?.includes('::') ? 'ipv6' : 'ipv4';
466
+ return this.#connection.addIceCandidate(new wrtc.RTCIceCandidate(message.candidate));
467
+ }
468
+ try {
469
+ if (message.sdp) {
470
+ if (message.sdp.type === 'offer') {
471
+ // debug(`incoming offer ${this.#channelName}`)
472
+ await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
473
+ const answer = await this.#connection.createAnswer();
474
+ await this.#connection.setLocalDescription(answer);
475
+ this._sendMessage({ 'sdp': this.#connection.localDescription });
476
+ }
477
+ if (message.sdp.type === 'answer') {
478
+ // debug(`incoming answer ${this.#channelName}`)
479
+ await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
480
+ }
481
+ }
482
+ }
483
+ catch (e) {
484
+ console.log(e);
485
+ }
486
+ }
487
+ close() {
488
+ // debug(`closing ${this.peerId}`)
489
+ this.#connected = false;
490
+ this.#channel?.close();
491
+ this.#connection?.close();
492
+ this.socketClient.pubsub.unsubscribe('signal', this._in);
493
+ }
494
494
  }
495
495
 
496
- class Client {
497
- #peerConnection;
498
- #connections = {};
499
- #stars = {};
500
- id;
501
- networkVersion;
502
- starsConfig;
503
- socketClient;
504
- get connections() {
505
- return { ...this.#connections };
506
- }
507
- get peers() {
508
- return Object.entries(this.#connections);
509
- }
510
- constructor(id, networkVersion = 'peach', stars = ['wss://peach.leofcoin.org']) {
511
- this.id = id || Math.random().toString(36).slice(-12);
512
- this.peerJoined = this.peerJoined.bind(this);
513
- this.peerLeft = this.peerLeft.bind(this);
514
- this.starLeft = this.starLeft.bind(this);
515
- this.starJoined = this.starJoined.bind(this);
516
- this.networkVersion = networkVersion;
517
- this._init(stars);
518
- }
519
- async _init(stars = []) {
520
- this.starsConfig = stars;
521
- // reconnectJob()
522
- if (!globalThis.RTCPeerConnection)
523
- globalThis.wrtc = (await import('./browser-10ffabe1.js').then(function (n) { return n.b; })).default;
524
- else
525
- globalThis.wrtc = {
526
- RTCPeerConnection,
527
- RTCSessionDescription,
528
- RTCIceCandidate
529
- };
530
- for (const star of stars) {
531
- try {
532
- this.socketClient = await socketRequestClient(star, this.networkVersion);
533
- const id = await this.socketClient.request({ url: 'id', params: { from: this.id } });
534
- this.socketClient.peerId = id;
535
- this.#stars[id] = this.socketClient;
536
- }
537
- catch (e) {
538
- if (stars.indexOf(star) === stars.length - 1 && !this.socketClient)
539
- throw new Error(`No star available to connect`);
540
- }
541
- }
542
- const peers = await this.socketClient.peernet.join({ id: this.id });
543
- for (const id of peers) {
544
- if (id !== this.id && !this.#connections[id])
545
- this.#connections[id] = await new Peer({ channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id });
546
- }
547
- this.setupListeners();
548
- }
549
- setupListeners() {
550
- this.socketClient.subscribe('peer:joined', this.peerJoined);
551
- this.socketClient.subscribe('peer:left', this.peerLeft);
552
- this.socketClient.subscribe('star:left', this.starLeft);
553
- }
554
- starJoined(id) {
555
- if (this.#stars[id]) {
556
- this.#stars[id].close();
557
- delete this.#stars[id];
558
- }
559
- console.log(`star ${id} joined`);
560
- }
561
- async starLeft(id) {
562
- if (this.#stars[id]) {
563
- this.#stars[id].close();
564
- delete this.#stars[id];
565
- }
566
- if (this.socketClient?.peerId === id) {
567
- this.socketClient.unsubscribe('peer:joined', this.peerJoined);
568
- this.socketClient.unsubscribe('peer:left', this.peerLeft);
569
- this.socketClient.unsubscribe('star:left', this.starLeft);
570
- this.socketClient.close();
571
- this.socketClient = undefined;
572
- for (const star of this.starsConfig) {
573
- try {
574
- this.socketClient = await socketRequestClient(star, this.networkVersion);
575
- if (!this.socketClient?.client?._connection.connected)
576
- return;
577
- const id = await this.socketClient.request({ url: 'id', params: { from: this.id } });
578
- this.#stars[id] = this.socketClient;
579
- this.socketClient.peerId = id;
580
- const peers = await this.socketClient.peernet.join({ id: this.id });
581
- this.setupListeners();
582
- for (const id of peers) {
583
- if (id !== this.id) {
584
- // close connection
585
- if (this.#connections[id]) {
586
- if (this.#connections[id].connected)
587
- await this.#connections[id].close();
588
- delete this.#connections[id];
589
- }
590
- // reconnect
591
- if (id !== this.id)
592
- this.#connections[id] = await new Peer({ channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id });
593
- }
594
- }
595
- }
596
- catch (e) {
597
- console.log(e);
598
- if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1 && !this.socketClient)
599
- throw new Error(`No star available to connect`);
600
- }
601
- }
602
- }
603
- globalThis.debug(`star ${id} left`);
604
- }
605
- peerLeft(peer) {
606
- const id = peer.peerId || peer;
607
- if (this.#connections[id]) {
608
- this.#connections[id].close();
609
- delete this.#connections[id];
610
- }
611
- globalThis.debug(`peer ${id} left`);
612
- }
613
- async peerJoined(peer, signal) {
614
- const id = peer.peerId || peer;
615
- if (this.#connections[id]) {
616
- if (this.#connections[id].connected)
617
- this.#connections[id].close();
618
- delete this.#connections[id];
619
- }
620
- // RTCPeerConnection
621
- this.#connections[id] = await new Peer({ initiator: true, channelName: `${this.id}:${id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id });
622
- globalThis.debug(`peer ${id} joined`);
623
- }
624
- removePeer(peer) {
625
- const id = peer.peerId || peer;
626
- if (this.#connections[id]) {
627
- this.#connections[id].connected && this.#connections[id].close();
628
- delete this.#connections[id];
629
- }
630
- globalThis.debug(`peer ${id} removed`);
631
- }
632
- async close() {
633
- this.socketClient.unsubscribe('peer:joined', this.peerJoined);
634
- this.socketClient.unsubscribe('peer:left', this.peerLeft);
635
- this.socketClient.unsubscribe('star:left', this.starLeft);
636
- const promises = [
637
- Object.values(this.#connections).map(connection => connection.close()),
638
- Object.values(this.#stars).map(connection => connection.close()),
639
- this.socketClient.close()
640
- ];
641
- return Promise.allSettled(promises);
642
- }
496
+ class Client {
497
+ #peerConnection;
498
+ #connections = {};
499
+ #stars = {};
500
+ id;
501
+ networkVersion;
502
+ starsConfig;
503
+ socketClient;
504
+ get connections() {
505
+ return { ...this.#connections };
506
+ }
507
+ get peers() {
508
+ return Object.entries(this.#connections);
509
+ }
510
+ constructor(id, networkVersion = 'peach', stars = ['wss://peach.leofcoin.org']) {
511
+ this.id = id || Math.random().toString(36).slice(-12);
512
+ this.peerJoined = this.peerJoined.bind(this);
513
+ this.peerLeft = this.peerLeft.bind(this);
514
+ this.starLeft = this.starLeft.bind(this);
515
+ this.starJoined = this.starJoined.bind(this);
516
+ this.networkVersion = networkVersion;
517
+ this._init(stars);
518
+ }
519
+ async _init(stars = []) {
520
+ this.starsConfig = stars;
521
+ // reconnectJob()
522
+ if (!globalThis.RTCPeerConnection)
523
+ globalThis.wrtc = (await import('./browser-10ffabe1.js').then(function (n) { return n.b; })).default;
524
+ else
525
+ globalThis.wrtc = {
526
+ RTCPeerConnection,
527
+ RTCSessionDescription,
528
+ RTCIceCandidate
529
+ };
530
+ for (const star of stars) {
531
+ try {
532
+ this.socketClient = await socketRequestClient(star, this.networkVersion);
533
+ const id = await this.socketClient.request({ url: 'id', params: { from: this.id } });
534
+ this.socketClient.peerId = id;
535
+ this.#stars[id] = this.socketClient;
536
+ }
537
+ catch (e) {
538
+ if (stars.indexOf(star) === stars.length - 1 && !this.socketClient)
539
+ throw new Error(`No star available to connect`);
540
+ }
541
+ }
542
+ const peers = await this.socketClient.peernet.join({ id: this.id });
543
+ for (const id of peers) {
544
+ if (id !== this.id && !this.#connections[id])
545
+ this.#connections[id] = await new Peer({ channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id });
546
+ }
547
+ this.setupListeners();
548
+ }
549
+ setupListeners() {
550
+ this.socketClient.subscribe('peer:joined', this.peerJoined);
551
+ this.socketClient.subscribe('peer:left', this.peerLeft);
552
+ this.socketClient.subscribe('star:left', this.starLeft);
553
+ }
554
+ starJoined(id) {
555
+ if (this.#stars[id]) {
556
+ this.#stars[id].close();
557
+ delete this.#stars[id];
558
+ }
559
+ console.log(`star ${id} joined`);
560
+ }
561
+ async starLeft(id) {
562
+ if (this.#stars[id]) {
563
+ this.#stars[id].close();
564
+ delete this.#stars[id];
565
+ }
566
+ if (this.socketClient?.peerId === id) {
567
+ this.socketClient.unsubscribe('peer:joined', this.peerJoined);
568
+ this.socketClient.unsubscribe('peer:left', this.peerLeft);
569
+ this.socketClient.unsubscribe('star:left', this.starLeft);
570
+ this.socketClient.close();
571
+ this.socketClient = undefined;
572
+ for (const star of this.starsConfig) {
573
+ try {
574
+ this.socketClient = await socketRequestClient(star, this.networkVersion);
575
+ if (!this.socketClient?.client?._connection.connected)
576
+ return;
577
+ const id = await this.socketClient.request({ url: 'id', params: { from: this.id } });
578
+ this.#stars[id] = this.socketClient;
579
+ this.socketClient.peerId = id;
580
+ const peers = await this.socketClient.peernet.join({ id: this.id });
581
+ this.setupListeners();
582
+ for (const id of peers) {
583
+ if (id !== this.id) {
584
+ // close connection
585
+ if (this.#connections[id]) {
586
+ if (this.#connections[id].connected)
587
+ await this.#connections[id].close();
588
+ delete this.#connections[id];
589
+ }
590
+ // reconnect
591
+ if (id !== this.id)
592
+ this.#connections[id] = await new Peer({ channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id });
593
+ }
594
+ }
595
+ }
596
+ catch (e) {
597
+ console.log(e);
598
+ if (this.starsConfig.indexOf(star) === this.starsConfig.length - 1 && !this.socketClient)
599
+ throw new Error(`No star available to connect`);
600
+ }
601
+ }
602
+ }
603
+ globalThis.debug(`star ${id} left`);
604
+ }
605
+ peerLeft(peer) {
606
+ const id = peer.peerId || peer;
607
+ if (this.#connections[id]) {
608
+ this.#connections[id].close();
609
+ delete this.#connections[id];
610
+ }
611
+ globalThis.debug(`peer ${id} left`);
612
+ }
613
+ async peerJoined(peer, signal) {
614
+ const id = peer.peerId || peer;
615
+ if (this.#connections[id]) {
616
+ if (this.#connections[id].connected)
617
+ this.#connections[id].close();
618
+ delete this.#connections[id];
619
+ }
620
+ // RTCPeerConnection
621
+ this.#connections[id] = await new Peer({ initiator: true, channelName: `${this.id}:${id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id });
622
+ globalThis.debug(`peer ${id} joined`);
623
+ }
624
+ removePeer(peer) {
625
+ const id = peer.peerId || peer;
626
+ if (this.#connections[id]) {
627
+ this.#connections[id].connected && this.#connections[id].close();
628
+ delete this.#connections[id];
629
+ }
630
+ globalThis.debug(`peer ${id} removed`);
631
+ }
632
+ async close() {
633
+ this.socketClient.unsubscribe('peer:joined', this.peerJoined);
634
+ this.socketClient.unsubscribe('peer:left', this.peerLeft);
635
+ this.socketClient.unsubscribe('star:left', this.starLeft);
636
+ const promises = [
637
+ Object.values(this.#connections).map(connection => connection.close()),
638
+ Object.values(this.#stars).map(connection => connection.close()),
639
+ this.socketClient.close()
640
+ ];
641
+ return Promise.allSettled(promises);
642
+ }
643
643
  }
644
644
 
645
645
  export { Client as default };
@@ -1,4 +1,4 @@
1
- import { M as MultiWallet, e as encrypt, b as base58$1 } from './peernet-749c4cfa.js';
1
+ import { M as MultiWallet, e as encrypt, b as base58$1 } from './peernet-7ba6837f.js';
2
2
  import './value-157ab062.js';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as FormatInterface } from './peernet-749c4cfa.js';
1
+ import { F as FormatInterface } from './peernet-7ba6837f.js';
2
2
  import './value-157ab062.js';
3
3
 
4
4
  var proto$b = {
@@ -16082,7 +16082,7 @@ class Identity {
16082
16082
  globalThis.peernet.selectedAccount = new TextDecoder().decode(selected);
16083
16083
  }
16084
16084
  else {
16085
- const importee = await import(/* webpackChunkName: "generate-account" */ './index-03344048.js');
16085
+ const importee = await import(/* webpackChunkName: "generate-account" */ './index-84ee0e0b.js');
16086
16086
  const { identity, accounts } = await importee.default(password, this.network);
16087
16087
  await globalThis.accountStore.put('public', JSON.stringify({ walletId: identity.walletId }));
16088
16088
  await globalThis.walletStore.put('version', String(1));
@@ -16248,7 +16248,7 @@ class Peernet {
16248
16248
  this.root = options.root;
16249
16249
  const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile
16250
16250
  // FolderMessageResponse
16251
- } = await import(/* webpackChunkName: "messages" */ './messages-28ebb39b.js');
16251
+ } = await import(/* webpackChunkName: "messages" */ './messages-def41fbf.js');
16252
16252
  /**
16253
16253
  * proto Object containing protos
16254
16254
  * @type {Object}
@@ -16297,7 +16297,7 @@ class Peernet {
16297
16297
  * @see DataHandler
16298
16298
  */
16299
16299
  pubsub.subscribe('peer:data', dataHandler);
16300
- const importee = await import('./client-bf4b2f00.js');
16300
+ const importee = await import('./client-bbd6e332.js');
16301
16301
  /**
16302
16302
  * @access public
16303
16303
  * @type {PeernetClient}
@@ -1,2 +1,2 @@
1
- export { P as default } from './peernet-749c4cfa.js';
1
+ export { P as default } from './peernet-7ba6837f.js';
2
2
  import './value-157ab062.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leofcoin/peernet",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "",
5
5
  "main": "src/peernet.js",
6
6
  "exports": {