@leofcoin/peernet 0.11.0 → 0.11.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.
Files changed (38) hide show
  1. package/coverage/lcov-report/base.css +224 -0
  2. package/coverage/lcov-report/block-navigation.js +87 -0
  3. package/coverage/lcov-report/codec-format-interface.js.html +637 -0
  4. package/coverage/lcov-report/dht-response.js.html +193 -0
  5. package/coverage/lcov-report/favicon.png +0 -0
  6. package/coverage/lcov-report/index.html +131 -0
  7. package/coverage/lcov-report/prettify.css +1 -0
  8. package/coverage/lcov-report/prettify.js +2 -0
  9. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  10. package/coverage/lcov-report/sorter.js +196 -0
  11. package/coverage/lcov.info +199 -0
  12. package/dist/browser/peernet.js +1288 -1385
  13. package/dist/commonjs/{client-bd0caeb7.js → client-1a1f75e6.js} +41 -41
  14. package/dist/commonjs/{codec-4a768e5e.js → codec-8c8c652f.js} +118 -118
  15. package/dist/commonjs/codec-format-interface.js +167 -167
  16. package/dist/commonjs/codec.js +2 -2
  17. package/dist/commonjs/dht-response.js +11 -11
  18. package/dist/commonjs/dht.js +2 -2
  19. package/dist/commonjs/hash.js +149 -149
  20. package/dist/commonjs/{http-2b0735ef.js → http-7bbac90a.js} +1 -1
  21. package/dist/commonjs/peernet-message.js +2 -2
  22. package/dist/commonjs/peernet.js +843 -934
  23. package/dist/commonjs/request.js +2 -2
  24. package/dist/commonjs/response.js +2 -2
  25. package/dist/module/peernet.js +1357 -1448
  26. package/package.json +2 -18
  27. package/src/client.js +75 -75
  28. package/src/codec/codec-format-interface.js +172 -172
  29. package/src/codec/codec.js +124 -124
  30. package/src/dht/dht.js +121 -121
  31. package/src/discovery/peer-discovery.js +75 -75
  32. package/src/hash/hash.js +155 -155
  33. package/src/http/client/http-client.js +44 -44
  34. package/src/messages/dht-response.js +14 -14
  35. package/src/peer.js +67 -67
  36. package/src/peernet.js +612 -612
  37. package/src/proto/chat-message.proto.js +7 -7
  38. package/src/utils/utils.js +78 -78
@@ -2,7 +2,7 @@ import LeofcoinStorage from '@leofcoin/storage';
2
2
  import protons from 'protons';
3
3
  import bs32 from '@vandeurenglenn/base32';
4
4
  import bs58 from '@vandeurenglenn/base58';
5
- import isHex from 'is-hex';
5
+ import isHex from '@vandeurenglenn/is-hex';
6
6
  import varint from 'varint';
7
7
  import createKeccakHash from 'keccak';
8
8
  import fetch from 'node-fetch';
@@ -706,439 +706,439 @@ var codecs = {
706
706
  },
707
707
  };
708
708
 
709
- class PeernetCodec {
710
- get codecs() {
711
- return {...globalThis.peernet.codecs, ...codecs}
712
- }
713
- constructor(buffer) {
714
- if (buffer) {
715
- if (buffer instanceof Uint8Array) {
716
- const codec = varint.decode(buffer);
717
- const name = this.getCodecName(codec);
718
- if (name) {
719
- this.name = name;
720
- this.encoded = buffer;
721
- this.decode(buffer);
722
- } else {
723
- this.encode(buffer);
724
- }
725
- } else if (buffer instanceof ArrayBuffer) {
726
- const encoded = new Uint8Array(buffer.byteLength);
727
-
728
- for (let i = 0; i < buffer.byteLength; i++) {
729
- encoded[i] = buffer[i];
730
- }
731
- this.encoded = encoded;
732
- // this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
733
- this.decode(buffer);
734
- return
735
- }
736
- if (typeof buffer === 'string') {
737
- if (this.codecs[buffer]) this.fromName(buffer);
738
- else if (isHex(buffer)) this.fromHex(buffer);
739
- else if (bs32.isBase32(buffer)) this.fromBs32(buffer);
740
- else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
741
- else throw new Error(`unsupported string ${buffer}`)
742
- }
743
- if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer);
744
- }
745
- }
746
-
747
- fromEncoded(encoded) {
748
- const codec = varint.decode(encoded);
749
- const name = this.getCodecName(codec);
750
- this.name = name;
751
- this.encoded = encoded;
752
- this.decode(encoded);
753
- }
754
-
755
- fromHex(hex) {
756
- this.encoded = Buffer.from(hex, 'hex');
757
- this.decode();
758
- }
759
-
760
- fromBs32(input) {
761
- this.encoded = bs32.decode(input);
762
- this.decode();
763
- }
764
-
765
- fromBs58(input) {
766
- this.encoded = bs58.decode(input);
767
- this.decode();
768
- }
769
-
770
- getCodec(name) {
771
- return this.codecs[name].codec
772
- }
773
-
774
- getCodecName(codec) {
775
- return Object.keys(this.codecs).reduce((p, c) => {
776
- const item = this.codecs[c];
777
- if (item.codec === codec) return c;
778
- else return p;
779
- }, undefined)
780
- }
781
-
782
- getHashAlg(name) {
783
- return this.codecs[name].hashAlg
784
- }
785
-
786
- fromCodec(codec) {
787
- this.name = this.getCodecName(codec);
788
- this.hashAlg = this.getHashAlg(this.name);
789
-
790
- this.codec = this.getCodec(this.name);
791
- this.codecBuffer = varint.encode(codec);
792
- }
793
-
794
- fromName(name) {
795
- const codec = this.getCodec(name);
796
- this.name = name;
797
- this.codec = codec;
798
- this.hashAlg = this.getHashAlg(name);
799
- this.codecBuffer = varint.encode(codec);
800
- }
801
-
802
- toBs32() {
803
- this.encode();
804
- return bs32.encode(this.encoded)
805
- }
806
-
807
- toBs58() {
808
- this.encode();
809
- return bs58.encode(this.encoded)
810
- }
811
-
812
- toHex() {
813
- return this.encoded.toString('hex')
814
- }
815
-
816
- decode() {
817
- const codec = varint.decode(this.encoded);
818
- this.fromCodec(codec);
819
- }
820
-
821
- encode() {
822
- const codec = varint.encode(this.decoded);
823
- this.encoded = codec;
824
- return this.encoded
825
- }
709
+ class PeernetCodec {
710
+ get codecs() {
711
+ return {...globalThis.peernet.codecs, ...codecs}
712
+ }
713
+ constructor(buffer) {
714
+ if (buffer) {
715
+ if (buffer instanceof Uint8Array) {
716
+ const codec = varint.decode(buffer);
717
+ const name = this.getCodecName(codec);
718
+ if (name) {
719
+ this.name = name;
720
+ this.encoded = buffer;
721
+ this.decode(buffer);
722
+ } else {
723
+ this.encode(buffer);
724
+ }
725
+ } else if (buffer instanceof ArrayBuffer) {
726
+ const encoded = new Uint8Array(buffer.byteLength);
727
+
728
+ for (let i = 0; i < buffer.byteLength; i++) {
729
+ encoded[i] = buffer[i];
730
+ }
731
+ this.encoded = encoded;
732
+ // this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
733
+ this.decode(buffer);
734
+ return
735
+ }
736
+ if (typeof buffer === 'string') {
737
+ if (this.codecs[buffer]) this.fromName(buffer);
738
+ else if (isHex(buffer)) this.fromHex(buffer);
739
+ else if (bs32.isBase32(buffer)) this.fromBs32(buffer);
740
+ else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
741
+ else throw new Error(`unsupported string ${buffer}`)
742
+ }
743
+ if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer);
744
+ }
745
+ }
746
+
747
+ fromEncoded(encoded) {
748
+ const codec = varint.decode(encoded);
749
+ const name = this.getCodecName(codec);
750
+ this.name = name;
751
+ this.encoded = encoded;
752
+ this.decode(encoded);
753
+ }
754
+
755
+ fromHex(hex) {
756
+ this.encoded = Buffer.from(hex, 'hex');
757
+ this.decode();
758
+ }
759
+
760
+ fromBs32(input) {
761
+ this.encoded = bs32.decode(input);
762
+ this.decode();
763
+ }
764
+
765
+ fromBs58(input) {
766
+ this.encoded = bs58.decode(input);
767
+ this.decode();
768
+ }
769
+
770
+ getCodec(name) {
771
+ return this.codecs[name].codec
772
+ }
773
+
774
+ getCodecName(codec) {
775
+ return Object.keys(this.codecs).reduce((p, c) => {
776
+ const item = this.codecs[c];
777
+ if (item.codec === codec) return c;
778
+ else return p;
779
+ }, undefined)
780
+ }
781
+
782
+ getHashAlg(name) {
783
+ return this.codecs[name].hashAlg
784
+ }
785
+
786
+ fromCodec(codec) {
787
+ this.name = this.getCodecName(codec);
788
+ this.hashAlg = this.getHashAlg(this.name);
789
+
790
+ this.codec = this.getCodec(this.name);
791
+ this.codecBuffer = varint.encode(codec);
792
+ }
793
+
794
+ fromName(name) {
795
+ const codec = this.getCodec(name);
796
+ this.name = name;
797
+ this.codec = codec;
798
+ this.hashAlg = this.getHashAlg(name);
799
+ this.codecBuffer = varint.encode(codec);
800
+ }
801
+
802
+ toBs32() {
803
+ this.encode();
804
+ return bs32.encode(this.encoded)
805
+ }
806
+
807
+ toBs58() {
808
+ this.encode();
809
+ return bs58.encode(this.encoded)
810
+ }
811
+
812
+ toHex() {
813
+ return this.encoded.toString('hex')
814
+ }
815
+
816
+ decode() {
817
+ const codec = varint.decode(this.encoded);
818
+ this.fromCodec(codec);
819
+ }
820
+
821
+ encode() {
822
+ const codec = varint.encode(this.decoded);
823
+ this.encoded = codec;
824
+ return this.encoded
825
+ }
826
826
  }
827
827
 
828
- class PeernetHash {
829
- constructor(buffer, options = {}) {
830
- if (options.name) this.name = options.name;
831
- else this.name = 'disco-hash';
832
- if (options.codecs) this.codecs = options.codecs;
833
- if (buffer) {
834
- if (Buffer.isBuffer(buffer)) {
835
- this.discoCodec = new PeernetCodec(buffer, this.codecs);
836
- const name = this.discoCodec.name;
837
-
838
- if (name) {
839
- this.name = name;
840
- this.decode(buffer);
841
- } else {
842
- this.encode(buffer);
843
- }
844
- }
845
-
846
- if (typeof buffer === 'string') {
847
- if (isHex(buffer)) this.fromHex(buffer);
848
- if (bs32.isBase32(buffer)) this.fromBs32(buffer);
849
- else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
850
- else throw new Error(`unsupported string ${buffer}`)
851
- } else if (typeof buffer === 'object') this.fromJSON(buffer);
852
- }
853
- }
854
-
855
- get prefix() {
856
- const length = this.length;
857
- const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length);
858
- for (let i = 0; i < this.discoCodec.codecBuffer.length; i++) {
859
- uint8Array[i] = this.discoCodec.codecBuffer[i];
860
- }
861
-
862
- for (let i = uint8Array.length - 1; i < length.length; i++) {
863
- uint8Array[i] = length[i];
864
- }
865
- return uint8Array
866
- }
867
-
868
- get length() {
869
- return varint.encode(this.size)
870
- }
871
-
872
- get buffer() {
873
- return this.hash
874
- }
875
-
876
- toHex() {
877
- return this.hash.toString('hex')
878
- }
879
-
880
- fromHex(hex) {
881
- return this.decode(Buffer.from(hex, 'hex'))
882
- }
883
-
884
- fromJSON(json) {
885
- return this.encode(Buffer.from(JSON.stringify(json)))
886
- }
887
-
888
- toBs32() {
889
- return bs32.encode(this.hash)
890
- }
891
-
892
- fromBs32(bs) {
893
- return this.decode(bs32.decode(bs))
894
- }
895
-
896
- toBs58() {
897
- return bs58.encode(this.hash)
898
- }
899
-
900
- fromBs58(bs) {
901
- return this.decode(bs58.decode(bs))
902
- }
903
-
904
- toString(encoding = 'utf8') {
905
- return this.hash.toString(encoding)
906
- }
907
-
908
- encode(buffer, name) {
909
- if (!this.name && name) this.name = name;
910
- if (!buffer) buffer = this.buffer;
911
- this.discoCodec = new PeernetCodec(this.name, this.codecs);
912
- this.discoCodec.fromName(this.name);
913
- let hashAlg = this.discoCodec.hashAlg;
914
- if (hashAlg.includes('dbl')) {
915
- hashAlg = hashAlg.replace('dbl-', '');
916
- buffer = createKeccakHash(hashAlg.replace('-', '')).update(buffer).digest();
917
- }
918
- this.digest = createKeccakHash(hashAlg.replace('-', '')).update(buffer).digest();
919
- this.size = this.digest.length;
920
-
921
- this.codec = this.discoCodec.encode();
922
- this.codec = this.discoCodec.codecBuffer;
923
- this.hash = Buffer.concat([
924
- this.prefix,
925
- this.digest,
926
- ]);
927
-
928
- return this.hash
929
- }
930
-
931
- validate(buffer) {
932
- if (Buffer.isBuffer(buffer)) {
933
- const codec = varint.decode(buffer);
934
- if (this.codecs[codec]) {
935
- this.decode(buffer);
936
- } else {
937
- this.encode(buffer);
938
- }
939
- }
940
- if (typeof buffer === 'string') {
941
- if (isHex(buffer)) this.fromHex(buffer);
942
- if (bs32.test(buffer)) this.fromBs32(buffer);
943
- }
944
- if (typeof buffer === 'object') this.fromJSON(buffer);
945
- }
946
-
947
- decode(buffer) {
948
- this.hash = buffer;
949
- const codec = varint.decode(buffer);
950
-
951
- this.discoCodec = new PeernetCodec(codec, this.codecs);
952
- // TODO: validate codec
953
- buffer = buffer.slice(varint.decode.bytes);
954
- this.size = varint.decode(buffer);
955
- this.digest = buffer.slice(varint.decode.bytes);
956
- if (this.digest.length !== this.size) {
957
- throw new Error(`hash length inconsistent: 0x${this.hash.toString('hex')}`)
958
- }
959
-
960
- // const discoCodec = new Codec(codec, this.codecs)
961
-
962
- this.name = this.discoCodec.name;
963
-
964
-
965
- this.size = this.digest.length;
966
-
967
- return {
968
- codec: this.codec,
969
- name: this.name,
970
- size: this.size,
971
- length: this.length,
972
- digest: this.digest,
973
- }
974
- }
828
+ class PeernetHash {
829
+ constructor(buffer, options = {}) {
830
+ if (options.name) this.name = options.name;
831
+ else this.name = 'disco-hash';
832
+ if (options.codecs) this.codecs = options.codecs;
833
+ if (buffer) {
834
+ if (Buffer.isBuffer(buffer)) {
835
+ this.discoCodec = new PeernetCodec(buffer, this.codecs);
836
+ const name = this.discoCodec.name;
837
+
838
+ if (name) {
839
+ this.name = name;
840
+ this.decode(buffer);
841
+ } else {
842
+ this.encode(buffer);
843
+ }
844
+ }
845
+
846
+ if (typeof buffer === 'string') {
847
+ if (isHex(buffer)) this.fromHex(buffer);
848
+ if (bs32.isBase32(buffer)) this.fromBs32(buffer);
849
+ else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
850
+ else throw new Error(`unsupported string ${buffer}`)
851
+ } else if (typeof buffer === 'object') this.fromJSON(buffer);
852
+ }
853
+ }
854
+
855
+ get prefix() {
856
+ const length = this.length;
857
+ const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length);
858
+ for (let i = 0; i < this.discoCodec.codecBuffer.length; i++) {
859
+ uint8Array[i] = this.discoCodec.codecBuffer[i];
860
+ }
861
+
862
+ for (let i = uint8Array.length - 1; i < length.length; i++) {
863
+ uint8Array[i] = length[i];
864
+ }
865
+ return uint8Array
866
+ }
867
+
868
+ get length() {
869
+ return varint.encode(this.size)
870
+ }
871
+
872
+ get buffer() {
873
+ return this.hash
874
+ }
875
+
876
+ toHex() {
877
+ return this.hash.toString('hex')
878
+ }
879
+
880
+ fromHex(hex) {
881
+ return this.decode(Buffer.from(hex, 'hex'))
882
+ }
883
+
884
+ fromJSON(json) {
885
+ return this.encode(Buffer.from(JSON.stringify(json)))
886
+ }
887
+
888
+ toBs32() {
889
+ return bs32.encode(this.hash)
890
+ }
891
+
892
+ fromBs32(bs) {
893
+ return this.decode(bs32.decode(bs))
894
+ }
895
+
896
+ toBs58() {
897
+ return bs58.encode(this.hash)
898
+ }
899
+
900
+ fromBs58(bs) {
901
+ return this.decode(bs58.decode(bs))
902
+ }
903
+
904
+ toString(encoding = 'utf8') {
905
+ return this.hash.toString(encoding)
906
+ }
907
+
908
+ encode(buffer, name) {
909
+ if (!this.name && name) this.name = name;
910
+ if (!buffer) buffer = this.buffer;
911
+ this.discoCodec = new PeernetCodec(this.name, this.codecs);
912
+ this.discoCodec.fromName(this.name);
913
+ let hashAlg = this.discoCodec.hashAlg;
914
+ if (hashAlg.includes('dbl')) {
915
+ hashAlg = hashAlg.replace('dbl-', '');
916
+ buffer = createKeccakHash(hashAlg.replace('-', '')).update(buffer).digest();
917
+ }
918
+ this.digest = createKeccakHash(hashAlg.replace('-', '')).update(buffer).digest();
919
+ this.size = this.digest.length;
920
+
921
+ this.codec = this.discoCodec.encode();
922
+ this.codec = this.discoCodec.codecBuffer;
923
+ this.hash = Buffer.concat([
924
+ this.prefix,
925
+ this.digest,
926
+ ]);
927
+
928
+ return this.hash
929
+ }
930
+
931
+ validate(buffer) {
932
+ if (Buffer.isBuffer(buffer)) {
933
+ const codec = varint.decode(buffer);
934
+ if (this.codecs[codec]) {
935
+ this.decode(buffer);
936
+ } else {
937
+ this.encode(buffer);
938
+ }
939
+ }
940
+ if (typeof buffer === 'string') {
941
+ if (isHex(buffer)) this.fromHex(buffer);
942
+ if (bs32.test(buffer)) this.fromBs32(buffer);
943
+ }
944
+ if (typeof buffer === 'object') this.fromJSON(buffer);
945
+ }
946
+
947
+ decode(buffer) {
948
+ this.hash = buffer;
949
+ const codec = varint.decode(buffer);
950
+
951
+ this.discoCodec = new PeernetCodec(codec, this.codecs);
952
+ // TODO: validate codec
953
+ buffer = buffer.slice(varint.decode.bytes);
954
+ this.size = varint.decode(buffer);
955
+ this.digest = buffer.slice(varint.decode.bytes);
956
+ if (this.digest.length !== this.size) {
957
+ throw new Error(`hash length inconsistent: 0x${this.hash.toString('hex')}`)
958
+ }
959
+
960
+ // const discoCodec = new Codec(codec, this.codecs)
961
+
962
+ this.name = this.discoCodec.name;
963
+
964
+
965
+ this.size = this.digest.length;
966
+
967
+ return {
968
+ codec: this.codec,
969
+ name: this.name,
970
+ size: this.size,
971
+ length: this.length,
972
+ digest: this.digest,
973
+ }
974
+ }
975
975
  }
976
976
 
977
- class FormatInterface {
978
- /**
979
- * @param {Buffer|String|Object} buffer - data - The data needed to create the desired message
980
- * @param {Object} proto - {encode, decode}
981
- * @param {Object} options - {hashFormat, name}
982
- */
983
- constructor(buffer, proto, options = {}) {
984
- this.protoEncode = proto.encode;
985
- this.protoDecode = proto.decode;
986
- this.hashFormat = options.hashFormat || 'bs32';
987
- if (options.name) this.name = options.name;
988
- if (buffer instanceof Uint8Array) return this.fromUint8Array(buffer)
989
- else if (buffer instanceof ArrayBuffer) return this.fromArrayBuffer(buffer)
990
- else if (buffer.name === options.name) return buffer
991
- else if (typeof buffer === 'string') {
992
- if (isHex(buffer)) this.fromHex(buffer);
993
- else if (bs32.isBase32(buffer)) this.fromBs32(buffer);
994
- else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
995
- else throw new Error(`unsupported string ${buffer}`)
996
- } else {
997
- this.create(buffer);
998
- }
999
- }
1000
-
1001
- /**
1002
- * @return {PeernetHash}
1003
- */
1004
- get peernetHash() {
1005
- return new PeernetHash(this.decoded, {name: this.name})
1006
- }
1007
-
1008
- /**
1009
- * @return {peernetHash}
1010
- */
1011
- get hash() {
1012
- const upper = this.hashFormat.charAt(0).toUpperCase();
1013
- const format = `${upper}${this.hashFormat.substring(1, this.hashFormat.length)}`;
1014
- return this.peernetHash[`to${format}`]()
1015
- }
1016
-
1017
- /**
1018
- * @return {Object}
1019
- */
1020
- decode() {
1021
- let encoded = this.encoded;
1022
- const discoCodec = new PeernetCodec(this.encoded);
1023
- encoded = encoded.slice(discoCodec.codecBuffer.length);
1024
- this.name = discoCodec.name;
1025
- this.decoded = this.protoDecode(encoded);
1026
- return this.decoded
1027
- }
1028
-
1029
- /**
1030
- * @return {Buffer}
1031
- */
1032
- encode(decoded) {
1033
- if (!decoded) decoded = this.decoded;
1034
- const codec = new PeernetCodec(this.name);
1035
- const encoded = this.protoEncode(decoded);
1036
- const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length);
1037
- uint8Array.set(codec.codecBuffer);
1038
- uint8Array.set(encoded, codec.codecBuffer.length);
1039
- this.encoded = uint8Array;
1040
- return this.encoded
1041
- }
1042
-
1043
- hasCodec() {
1044
- if (!this.encoded) return false
1045
- const codec = new PeernetCodec(this.encoded);
1046
- if (codec.name) return true
1047
- }
1048
-
1049
- fromUint8Array(buffer) {
1050
- this.encoded = buffer;
1051
- if (!this.hasCodec()) this.create(
1052
- JSON.parse(new TextDecoder().decode(this.encoded))
1053
- );
1054
- else this.decode();
1055
- }
1056
-
1057
- fromArrayBuffer(buffer) {
1058
- this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength);
1059
- if (!this.hasCodec()) this.create(
1060
- JSON.parse(new TextDecoder().decode(this.encoded))
1061
- );
1062
- else this.decode();
1063
- }
1064
-
1065
- /**
1066
- * @param {Buffer} encoded
1067
- */
1068
- fromEncoded(encoded) {
1069
- this.encoded = encoded;
1070
- this.decode();
1071
- }
1072
-
1073
- /**
1074
- * @param {String} encoded
1075
- */
1076
- fromHex(encoded) {
1077
- this.encoded = Buffer.from(encoded, 'hex');
1078
- this.decode();
1079
- }
1080
-
1081
- /**
1082
- * @param {String} encoded
1083
- */
1084
- fromBs32(encoded) {
1085
- this.encoded = bs32.decode(encoded);
1086
- this.decode();
1087
- }
1088
-
1089
- /**
1090
- * @param {String} encoded
1091
- */
1092
- fromBs58(encoded) {
1093
- this.encoded = bs58.decode(encoded);
1094
- this.decode();
1095
- }
1096
-
1097
- /**
1098
- * @return {String} encoded
1099
- */
1100
- toHex() {
1101
- if (!this.encoded) this.encode();
1102
- return this.encoded.toString('hex')
1103
- }
1104
-
1105
- /**
1106
- * @return {String} encoded
1107
- */
1108
- toBs32() {
1109
- if (!this.encoded) this.encode();
1110
- return bs32.encode(this.encoded)
1111
- }
1112
-
1113
- /**
1114
- * @return {String} encoded
1115
- */
1116
- toBs58() {
1117
- if (!this.encoded) this.encode();
1118
- return bs58.encode(this.encoded)
1119
- }
1120
-
1121
- /**
1122
- * @param {Object} data
1123
- */
1124
- create(data) {
1125
- const decoded = {};
1126
- if (this.keys?.length > 0) {
1127
- for (const key of this.keys) {
1128
- Object.defineProperties(decoded, {
1129
- [key]: {
1130
- enumerable: true,
1131
- configurable: true,
1132
- set: (val) => value = data[key],
1133
- get: () => data[key]
1134
- }
1135
- });
1136
- }
1137
-
1138
- this.decoded = decoded;
1139
- this.encode();
1140
- }
1141
- }
977
+ class FormatInterface {
978
+ /**
979
+ * @param {Buffer|String|Object} buffer - data - The data needed to create the desired message
980
+ * @param {Object} proto - {encode, decode}
981
+ * @param {Object} options - {hashFormat, name}
982
+ */
983
+ constructor(buffer, proto, options = {}) {
984
+ this.protoEncode = proto.encode;
985
+ this.protoDecode = proto.decode;
986
+ this.hashFormat = options.hashFormat || 'bs32';
987
+ if (options.name) this.name = options.name;
988
+ if (buffer instanceof Uint8Array) return this.fromUint8Array(buffer)
989
+ else if (buffer instanceof ArrayBuffer) return this.fromArrayBuffer(buffer)
990
+ else if (buffer.name === options.name) return buffer
991
+ else if (typeof buffer === 'string') {
992
+ if (isHex(buffer)) this.fromHex(buffer);
993
+ else if (bs32.isBase32(buffer)) this.fromBs32(buffer);
994
+ else if (bs58.isBase58(buffer)) this.fromBs58(buffer);
995
+ else throw new Error(`unsupported string ${buffer}`)
996
+ } else {
997
+ this.create(buffer);
998
+ }
999
+ }
1000
+
1001
+ /**
1002
+ * @return {PeernetHash}
1003
+ */
1004
+ get peernetHash() {
1005
+ return new PeernetHash(this.decoded, {name: this.name})
1006
+ }
1007
+
1008
+ /**
1009
+ * @return {peernetHash}
1010
+ */
1011
+ get hash() {
1012
+ const upper = this.hashFormat.charAt(0).toUpperCase();
1013
+ const format = `${upper}${this.hashFormat.substring(1, this.hashFormat.length)}`;
1014
+ return this.peernetHash[`to${format}`]()
1015
+ }
1016
+
1017
+ /**
1018
+ * @return {Object}
1019
+ */
1020
+ decode() {
1021
+ let encoded = this.encoded;
1022
+ const discoCodec = new PeernetCodec(this.encoded);
1023
+ encoded = encoded.slice(discoCodec.codecBuffer.length);
1024
+ this.name = discoCodec.name;
1025
+ this.decoded = this.protoDecode(encoded);
1026
+ return this.decoded
1027
+ }
1028
+
1029
+ /**
1030
+ * @return {Buffer}
1031
+ */
1032
+ encode(decoded) {
1033
+ if (!decoded) decoded = this.decoded;
1034
+ const codec = new PeernetCodec(this.name);
1035
+ const encoded = this.protoEncode(decoded);
1036
+ const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length);
1037
+ uint8Array.set(codec.codecBuffer);
1038
+ uint8Array.set(encoded, codec.codecBuffer.length);
1039
+ this.encoded = uint8Array;
1040
+ return this.encoded
1041
+ }
1042
+
1043
+ hasCodec() {
1044
+ if (!this.encoded) return false
1045
+ const codec = new PeernetCodec(this.encoded);
1046
+ if (codec.name) return true
1047
+ }
1048
+
1049
+ fromUint8Array(buffer) {
1050
+ this.encoded = buffer;
1051
+ if (!this.hasCodec()) this.create(
1052
+ JSON.parse(new TextDecoder().decode(this.encoded))
1053
+ );
1054
+ else this.decode();
1055
+ }
1056
+
1057
+ fromArrayBuffer(buffer) {
1058
+ this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength);
1059
+ if (!this.hasCodec()) this.create(
1060
+ JSON.parse(new TextDecoder().decode(this.encoded))
1061
+ );
1062
+ else this.decode();
1063
+ }
1064
+
1065
+ /**
1066
+ * @param {Buffer} encoded
1067
+ */
1068
+ fromEncoded(encoded) {
1069
+ this.encoded = encoded;
1070
+ this.decode();
1071
+ }
1072
+
1073
+ /**
1074
+ * @param {String} encoded
1075
+ */
1076
+ fromHex(encoded) {
1077
+ this.encoded = Buffer.from(encoded, 'hex');
1078
+ this.decode();
1079
+ }
1080
+
1081
+ /**
1082
+ * @param {String} encoded
1083
+ */
1084
+ fromBs32(encoded) {
1085
+ this.encoded = bs32.decode(encoded);
1086
+ this.decode();
1087
+ }
1088
+
1089
+ /**
1090
+ * @param {String} encoded
1091
+ */
1092
+ fromBs58(encoded) {
1093
+ this.encoded = bs58.decode(encoded);
1094
+ this.decode();
1095
+ }
1096
+
1097
+ /**
1098
+ * @return {String} encoded
1099
+ */
1100
+ toHex() {
1101
+ if (!this.encoded) this.encode();
1102
+ return this.encoded.toString('hex')
1103
+ }
1104
+
1105
+ /**
1106
+ * @return {String} encoded
1107
+ */
1108
+ toBs32() {
1109
+ if (!this.encoded) this.encode();
1110
+ return bs32.encode(this.encoded)
1111
+ }
1112
+
1113
+ /**
1114
+ * @return {String} encoded
1115
+ */
1116
+ toBs58() {
1117
+ if (!this.encoded) this.encode();
1118
+ return bs58.encode(this.encoded)
1119
+ }
1120
+
1121
+ /**
1122
+ * @param {Object} data
1123
+ */
1124
+ create(data) {
1125
+ const decoded = {};
1126
+ if (this.keys?.length > 0) {
1127
+ for (const key of this.keys) {
1128
+ Object.defineProperties(decoded, {
1129
+ [key]: {
1130
+ enumerable: true,
1131
+ configurable: true,
1132
+ set: (val) => value = data[key],
1133
+ get: () => data[key]
1134
+ }
1135
+ });
1136
+ }
1137
+
1138
+ this.decoded = decoded;
1139
+ this.encode();
1140
+ }
1141
+ }
1142
1142
  }
1143
1143
 
1144
1144
  class PeernetMessage extends FormatInterface {
@@ -1190,15 +1190,15 @@ message PeernetDHTMessageResponse {
1190
1190
  }
1191
1191
  `;
1192
1192
 
1193
- class DHTMessageResponse extends FormatInterface {
1194
- get keys() {
1195
- return ['hash', 'has']
1196
- }
1197
-
1198
- constructor(data) {
1199
- const name = 'peernet-dht-response';
1200
- super(data, protons(proto$8).PeernetDHTMessageResponse, {name});
1201
- }
1193
+ class DHTMessageResponse extends FormatInterface {
1194
+ get keys() {
1195
+ return ['hash', 'has']
1196
+ }
1197
+
1198
+ constructor(data) {
1199
+ const name = 'peernet-dht-response';
1200
+ super(data, protons(proto$8).PeernetDHTMessageResponse, {name});
1201
+ }
1202
1202
  }
1203
1203
 
1204
1204
  var proto$7 = `
@@ -1333,12 +1333,12 @@ class DataMessageResponse extends FormatInterface {
1333
1333
  }
1334
1334
  }
1335
1335
 
1336
- var proto = `
1337
- message ChatMessage {
1338
- required string value = 1;
1339
- required string author = 2;
1340
- required uint64 timestamp = 3;
1341
- repeated string files = 4;
1336
+ var proto = `
1337
+ message ChatMessage {
1338
+ required string value = 1;
1339
+ required string author = 2;
1340
+ required uint64 timestamp = 3;
1341
+ repeated string files = 4;
1342
1342
  }`;
1343
1343
 
1344
1344
  class ChatMessage extends FormatInterface {
@@ -1352,259 +1352,259 @@ class ChatMessage extends FormatInterface {
1352
1352
  }
1353
1353
  }
1354
1354
 
1355
- const debug = (log) => {
1356
- if (globalThis.DEBUG || globalThis.debug) console.log(`%c ${log}`, 'color: #0080ff;');
1357
- };
1358
-
1359
- const protoFor = (data) => {
1360
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
1361
- const codec = new PeernetCodec(data);
1362
- if (!codec.name) throw new Error('proto not found')
1363
- const Proto = globalThis.peernet.protos[codec.name];
1364
- if (!Proto) throw (new Error(`No proto defined for ${codec.name}`))
1365
- return new Proto(data)
1366
- };
1367
-
1368
- /**
1369
- * wether or not a peernet daemon is active
1370
- * @return {Boolean}
1371
- */
1372
- const hasDaemon = async () => {
1373
- try {
1374
- let response = await fetch('http://127.0.0.1:1000/api/version');
1375
- response = await response.json();
1376
- return Boolean(response.client === '@peernet/api/http')
1377
- } catch (e) {
1378
- return false
1379
- }
1380
- };
1381
-
1382
- const https = () => {
1383
- if (!globalThis.location) return false;
1384
- return Boolean(globalThis.location.protocol === 'https:')
1385
- };
1386
-
1387
- /**
1388
- * Get current environment
1389
- * @return {String} current environment [node, electron, browser]
1390
- */
1391
- const environment = () => {
1392
- const _navigator = globalThis.navigator;
1393
- if (!_navigator) {
1394
- return 'node'
1395
- } else if (_navigator && /electron/i.test(_navigator.userAgent)) {
1396
- return 'electron'
1397
- } else {
1398
- return 'browser'
1399
- }
1400
- };
1401
-
1402
- /**
1403
- * * Get current environment
1404
- * @return {Object} result
1405
- * @property {Boolean} reult.daemon whether or not daemon is running
1406
- * @property {Boolean} reult.environment Current environment
1407
- */
1408
- const target = async () => {
1409
- let daemon = false;
1410
- const env = await environment();
1411
- if (!https()) daemon = await hasDaemon();
1412
-
1413
- return {daemon, environment: env}
1414
- };
1415
-
1416
- class PeerDiscovery {
1417
- constructor(id) {
1418
- this.id = id;
1419
- }
1420
-
1421
- _getPeerId(id) {
1422
- if (!peernet.peerMap || peernet.peerMap && peernet.peerMap.size === 0) return false
1423
-
1424
- for (const entry of [...peernet.peerMap.entries()]) {
1425
- for (const _id of entry[1]) {
1426
- if (_id === id) return entry[0]
1427
- }
1428
- }
1429
- }
1430
-
1431
- async discover(peer) {
1432
- let id = this._getPeerId(peer.id);
1433
- if (id) return id
1434
- const data = new peernet.protos['peernet-peer']({id: this.id});
1435
- const node = await peernet.prepareMessage(peer.id, data.encoded);
1436
-
1437
- let response = await peer.request(node.encoded);
1438
- response = protoFor(response);
1439
- response = new peernet.protos['peernet-peer-response'](response.decoded.data);
1440
-
1441
- id = response.decoded.id;
1442
- if (id === this.id) return;
1443
-
1444
- if (!peernet.peerMap.has(id)) peernet.peerMap.set(id, [peer.id]);
1445
- else {
1446
- const connections = peernet.peerMap.get(id);
1447
- if (connections.indexOf(peer.id) === -1) {
1448
- connections.push(peer.id);
1449
- peernet.peerMap.set(peer.id, connections);
1450
- }
1451
- }
1452
- return id
1453
- }
1454
-
1455
- async discoverHandler(message, peer) {
1456
- const {id, proto} = message;
1457
- // if (typeof message.data === 'string') message.data = Buffer.from(message.data)
1458
- if (proto.name === 'peernet-peer') {
1459
- const from = proto.decoded.id;
1460
- if (from === this.id) return;
1461
-
1462
- if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1463
- else {
1464
- const connections = peernet.peerMap.get(from);
1465
- if (connections.indexOf(peer.id) === -1) {
1466
- connections.push(peer.id);
1467
- peernet.peerMap.set(from, connections);
1468
- }
1469
- }
1470
- const data = new peernet.protos['peernet-peer-response']({id: this.id});
1471
- const node = await peernet.prepareMessage(from, data.encoded);
1472
-
1473
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1474
- } else if (proto.name === 'peernet-peer-response') {
1475
- const from = proto.decoded.id;
1476
- if (from === this.id) return;
1477
-
1478
- if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1479
- else {
1480
- const connections = peernet.peerMap.get(from);
1481
- if (connections.indexOf(peer.id) === -1) {
1482
- connections.push(peer.id);
1483
- peernet.peerMap.set(from, connections);
1484
- }
1485
- }
1486
- }
1487
- }
1488
- }
1489
-
1490
- /**
1491
- * Keep history of fetched address and ptr
1492
- * @property {Object} address
1493
- * @property {Object} ptr
1494
- */
1495
- const lastFetched = {
1496
- address: {
1497
- value: undefined,
1498
- timestamp: 0,
1499
- },
1500
- ptr: {
1501
- value: undefined,
1502
- timestamp: 0,
1503
- },
1504
- };
1505
-
1506
- const getAddress = async () => {
1507
- const {address} = lastFetched;
1508
- const now = Math.round(new Date().getTime() / 1000);
1509
- if (now - address.timestamp > 1200000) {
1510
- address.value = await fetch('https://icanhazip.com/');
1511
- address.value = await address.value.text();
1512
- address.timestamp = Math.round(new Date().getTime() / 1000);
1513
- lastFetched.address = address;
1514
- }
1515
-
1516
- return address.value
1517
- };
1518
-
1519
- const degreesToRadians = (degrees) => {
1520
- return degrees * Math.PI / 180;
1521
- };
1522
-
1523
- const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
1524
- const earthRadiusKm = 6371;
1525
-
1526
- const dLat = degreesToRadians(lat2-lat1);
1527
- const dLon = degreesToRadians(lon2-lon1);
1528
-
1529
- lat1 = degreesToRadians(lat1);
1530
- lat2 = degreesToRadians(lat2);
1531
- const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
1532
- Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
1533
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
1534
- return earthRadiusKm * c;
1355
+ const debug = (log) => {
1356
+ if (globalThis.DEBUG || globalThis.debug) console.log(`%c ${log}`, 'color: #0080ff;');
1357
+ };
1358
+
1359
+ const protoFor = (data) => {
1360
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data);
1361
+ const codec = new PeernetCodec(data);
1362
+ if (!codec.name) throw new Error('proto not found')
1363
+ const Proto = globalThis.peernet.protos[codec.name];
1364
+ if (!Proto) throw (new Error(`No proto defined for ${codec.name}`))
1365
+ return new Proto(data)
1366
+ };
1367
+
1368
+ /**
1369
+ * wether or not a peernet daemon is active
1370
+ * @return {Boolean}
1371
+ */
1372
+ const hasDaemon = async () => {
1373
+ try {
1374
+ let response = await fetch('http://127.0.0.1:1000/api/version');
1375
+ response = await response.json();
1376
+ return Boolean(response.client === '@peernet/api/http')
1377
+ } catch (e) {
1378
+ return false
1379
+ }
1380
+ };
1381
+
1382
+ const https = () => {
1383
+ if (!globalThis.location) return false;
1384
+ return Boolean(globalThis.location.protocol === 'https:')
1385
+ };
1386
+
1387
+ /**
1388
+ * Get current environment
1389
+ * @return {String} current environment [node, electron, browser]
1390
+ */
1391
+ const environment = () => {
1392
+ const _navigator = globalThis.navigator;
1393
+ if (!_navigator) {
1394
+ return 'node'
1395
+ } else if (_navigator && /electron/i.test(_navigator.userAgent)) {
1396
+ return 'electron'
1397
+ } else {
1398
+ return 'browser'
1399
+ }
1400
+ };
1401
+
1402
+ /**
1403
+ * * Get current environment
1404
+ * @return {Object} result
1405
+ * @property {Boolean} reult.daemon whether or not daemon is running
1406
+ * @property {Boolean} reult.environment Current environment
1407
+ */
1408
+ const target = async () => {
1409
+ let daemon = false;
1410
+ const env = await environment();
1411
+ if (!https()) daemon = await hasDaemon();
1412
+
1413
+ return {daemon, environment: env}
1535
1414
  };
1536
1415
 
1537
- class DhtEarth {
1538
- /**
1539
- *
1540
- */
1541
- constructor() {
1542
- this.providerMap = new Map();
1543
- }
1544
-
1545
- /**
1546
- * @param {Object} address
1547
- * @return {Object} {latitude: lat, longitude: lon}
1548
- */
1549
- async getCoordinates(address) {
1550
- // const {address} = parseAddress(provider)
1551
- const request = `https://whereis.leofcoin.org/?ip=${address}`;
1552
- let response = await fetch(request);
1553
- response = await response.json();
1554
- const {lat, lon} = response;
1555
- return {latitude: lat, longitude: lon}
1556
- }
1557
-
1558
- /**
1559
- * @param {Object} peer
1560
- * @param {Object} provider
1561
- * @return {Object} {provider, distance}
1562
- */
1563
- async getDistance(peer, provider) {
1564
- const {latitude, longitude} = await this.getCoordinates(provider.address);
1565
- return {provider, distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)}
1566
- }
1567
-
1568
- /**
1569
- * @param {Array} providers
1570
- * @return {Object} closestPeer
1571
- */
1572
- async closestPeer(providers) {
1573
- let all = [];
1574
- const address = await getAddress();
1575
- const peerLoc = await this.getCoordinates(address);
1576
-
1577
- for (const provider of providers) {
1578
- if (provider.address === '127.0.0.1') all.push({provider, distance: 0});
1579
- else all.push(this.getDistance(peerLoc, provider));
1580
- }
1581
-
1582
- all = await Promise.all(all);
1583
- all = all.sort((previous, current) => previous.distance - current.distance);
1584
- return all[0].provider;
1585
- }
1586
-
1587
- /**
1588
- * @param {String} hash
1589
- * @return {Array} providers
1590
- */
1591
- providersFor(hash) {
1592
- return this.providerMap.get(hash);
1593
- }
1594
-
1595
- /**
1596
- * @param {String} address
1597
- * @param {String} hash
1598
- * @return {Array} providers
1599
- */
1600
- async addProvider(address, hash) {
1601
- let providers = [];
1602
- if (this.providerMap.has(hash)) providers = this.providerMap.get(hash);
1416
+ class PeerDiscovery {
1417
+ constructor(id) {
1418
+ this.id = id;
1419
+ }
1420
+
1421
+ _getPeerId(id) {
1422
+ if (!peernet.peerMap || peernet.peerMap && peernet.peerMap.size === 0) return false
1423
+
1424
+ for (const entry of [...peernet.peerMap.entries()]) {
1425
+ for (const _id of entry[1]) {
1426
+ if (_id === id) return entry[0]
1427
+ }
1428
+ }
1429
+ }
1430
+
1431
+ async discover(peer) {
1432
+ let id = this._getPeerId(peer.id);
1433
+ if (id) return id
1434
+ const data = new peernet.protos['peernet-peer']({id: this.id});
1435
+ const node = await peernet.prepareMessage(peer.id, data.encoded);
1436
+
1437
+ let response = await peer.request(node.encoded);
1438
+ response = protoFor(response);
1439
+ response = new peernet.protos['peernet-peer-response'](response.decoded.data);
1440
+
1441
+ id = response.decoded.id;
1442
+ if (id === this.id) return;
1443
+
1444
+ if (!peernet.peerMap.has(id)) peernet.peerMap.set(id, [peer.id]);
1445
+ else {
1446
+ const connections = peernet.peerMap.get(id);
1447
+ if (connections.indexOf(peer.id) === -1) {
1448
+ connections.push(peer.id);
1449
+ peernet.peerMap.set(peer.id, connections);
1450
+ }
1451
+ }
1452
+ return id
1453
+ }
1454
+
1455
+ async discoverHandler(message, peer) {
1456
+ const {id, proto} = message;
1457
+ // if (typeof message.data === 'string') message.data = Buffer.from(message.data)
1458
+ if (proto.name === 'peernet-peer') {
1459
+ const from = proto.decoded.id;
1460
+ if (from === this.id) return;
1461
+
1462
+ if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1463
+ else {
1464
+ const connections = peernet.peerMap.get(from);
1465
+ if (connections.indexOf(peer.id) === -1) {
1466
+ connections.push(peer.id);
1467
+ peernet.peerMap.set(from, connections);
1468
+ }
1469
+ }
1470
+ const data = new peernet.protos['peernet-peer-response']({id: this.id});
1471
+ const node = await peernet.prepareMessage(from, data.encoded);
1472
+
1473
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1474
+ } else if (proto.name === 'peernet-peer-response') {
1475
+ const from = proto.decoded.id;
1476
+ if (from === this.id) return;
1477
+
1478
+ if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1479
+ else {
1480
+ const connections = peernet.peerMap.get(from);
1481
+ if (connections.indexOf(peer.id) === -1) {
1482
+ connections.push(peer.id);
1483
+ peernet.peerMap.set(from, connections);
1484
+ }
1485
+ }
1486
+ }
1487
+ }
1488
+ }
1603
1489
 
1604
- providers = new Set([...providers, address]);
1605
- this.providerMap.set(hash, providers);
1606
- return providers;
1607
- }
1490
+ /**
1491
+ * Keep history of fetched address and ptr
1492
+ * @property {Object} address
1493
+ * @property {Object} ptr
1494
+ */
1495
+ const lastFetched = {
1496
+ address: {
1497
+ value: undefined,
1498
+ timestamp: 0,
1499
+ },
1500
+ ptr: {
1501
+ value: undefined,
1502
+ timestamp: 0,
1503
+ },
1504
+ };
1505
+
1506
+ const getAddress = async () => {
1507
+ const {address} = lastFetched;
1508
+ const now = Math.round(new Date().getTime() / 1000);
1509
+ if (now - address.timestamp > 1200000) {
1510
+ address.value = await fetch('https://icanhazip.com/');
1511
+ address.value = await address.value.text();
1512
+ address.timestamp = Math.round(new Date().getTime() / 1000);
1513
+ lastFetched.address = address;
1514
+ }
1515
+
1516
+ return address.value
1517
+ };
1518
+
1519
+ const degreesToRadians = (degrees) => {
1520
+ return degrees * Math.PI / 180;
1521
+ };
1522
+
1523
+ const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
1524
+ const earthRadiusKm = 6371;
1525
+
1526
+ const dLat = degreesToRadians(lat2-lat1);
1527
+ const dLon = degreesToRadians(lon2-lon1);
1528
+
1529
+ lat1 = degreesToRadians(lat1);
1530
+ lat2 = degreesToRadians(lat2);
1531
+ const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
1532
+ Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
1533
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
1534
+ return earthRadiusKm * c;
1535
+ };
1536
+
1537
+ class DhtEarth {
1538
+ /**
1539
+ *
1540
+ */
1541
+ constructor() {
1542
+ this.providerMap = new Map();
1543
+ }
1544
+
1545
+ /**
1546
+ * @param {Object} address
1547
+ * @return {Object} {latitude: lat, longitude: lon}
1548
+ */
1549
+ async getCoordinates(address) {
1550
+ // const {address} = parseAddress(provider)
1551
+ const request = `https://whereis.leofcoin.org/?ip=${address}`;
1552
+ let response = await fetch(request);
1553
+ response = await response.json();
1554
+ const {lat, lon} = response;
1555
+ return {latitude: lat, longitude: lon}
1556
+ }
1557
+
1558
+ /**
1559
+ * @param {Object} peer
1560
+ * @param {Object} provider
1561
+ * @return {Object} {provider, distance}
1562
+ */
1563
+ async getDistance(peer, provider) {
1564
+ const {latitude, longitude} = await this.getCoordinates(provider.address);
1565
+ return {provider, distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)}
1566
+ }
1567
+
1568
+ /**
1569
+ * @param {Array} providers
1570
+ * @return {Object} closestPeer
1571
+ */
1572
+ async closestPeer(providers) {
1573
+ let all = [];
1574
+ const address = await getAddress();
1575
+ const peerLoc = await this.getCoordinates(address);
1576
+
1577
+ for (const provider of providers) {
1578
+ if (provider.address === '127.0.0.1') all.push({provider, distance: 0});
1579
+ else all.push(this.getDistance(peerLoc, provider));
1580
+ }
1581
+
1582
+ all = await Promise.all(all);
1583
+ all = all.sort((previous, current) => previous.distance - current.distance);
1584
+ return all[0].provider;
1585
+ }
1586
+
1587
+ /**
1588
+ * @param {String} hash
1589
+ * @return {Array} providers
1590
+ */
1591
+ providersFor(hash) {
1592
+ return this.providerMap.get(hash);
1593
+ }
1594
+
1595
+ /**
1596
+ * @param {String} address
1597
+ * @param {String} hash
1598
+ * @return {Array} providers
1599
+ */
1600
+ async addProvider(address, hash) {
1601
+ let providers = [];
1602
+ if (this.providerMap.has(hash)) providers = this.providerMap.get(hash);
1603
+
1604
+ providers = new Set([...providers, address]);
1605
+ this.providerMap.set(hash, providers);
1606
+ return providers;
1607
+ }
1608
1608
  }
1609
1609
 
1610
1610
  var testnets = {
@@ -1962,776 +1962,685 @@ class MultiWallet extends HDWallet {
1962
1962
  return { version, multiCodec, bs58 };
1963
1963
  }
1964
1964
 
1965
- sign(hash) {
1966
- return new MultiSignature(this.version, this.network.multiCodec)
1967
- .sign(hash, this.privateKeyBuffer);
1965
+ sign(hash) {
1966
+ return new MultiSignature(this.version, this.network.multiCodec)
1967
+ .sign(hash, this.privateKeyBuffer);
1968
+
1969
+ }
1970
+
1971
+ verify(multiSignature, hash) {
1972
+ return new MultiSignature(this.version, this.network.multiCodec)
1973
+ .verify(multiSignature, hash, this.publicKeyBuffer)
1974
+ }
1975
+
1976
+ /**
1977
+ * @param {number} account - account to return chain for
1978
+ * @return { internal(addressIndex), external(addressIndex) }
1979
+ */
1980
+ account(index) {
1981
+ return new HDAccount(new MultiWallet(this.network, this.hdnode), index);
1982
+ }
1983
+
1984
+ /**
1985
+ * m / purpose' / coin_type' / account' / change / aadress_index
1986
+ *
1987
+ * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
1988
+ */
1989
+ derivePath(path) {
1990
+ return new MultiWallet(this.network, this.hdnode.derivePath(path))
1991
+ }
1992
+
1993
+ derive(index) {
1994
+ return new MultiWallet(this.network, this.hdnode.derive(index));
1995
+ }
1996
+ }
1997
+
1998
+ class MessageHandler {
1999
+ constructor(network) {
2000
+ this.network = network;
2001
+ }
2002
+ /**
2003
+ * hash and sign message
2004
+ *
2005
+ * @param {object} message
2006
+ * @param {Buffer} message.from peer id
2007
+ * @param {Buffer} message.to peer id
2008
+ * @param {string} message.data Peernet message
2009
+ * (PeernetMessage excluded) encoded as a string
2010
+ * @return signature
2011
+ */
2012
+ async hashAndSignMessage(message) {
2013
+ const hasher = new PeernetHash(message, {name: 'peernet-message'});
2014
+ const identity = await walletStore.get('identity');
2015
+
2016
+ const wallet = new MultiWallet(this.network);
2017
+ wallet.import(identity.multiWIF);
2018
+ return wallet.sign(hasher.hash.slice(0, 32))
2019
+ }
2020
+
2021
+ /**
2022
+ * @param {String} from - peer id
2023
+ * @param {String} to - peer id
2024
+ * @param {String|PeernetMessage} data - data encoded message string
2025
+ * or the messageNode itself
2026
+ */
2027
+ async prepareMessage(from, to, data, id) {
2028
+ if (!Buffer.isBuffer(from)) from = new Buffer.from(from);
2029
+ if (!Buffer.isBuffer(to)) to = new Buffer.from(to);
2030
+ if (data.encoded) data = data.encoded;
2031
+
2032
+ const message = {
2033
+ from,
2034
+ to,
2035
+ data,
2036
+ };
2037
+ const signature = await this.hashAndSignMessage(message);
2038
+ const node = new PeernetMessage({
2039
+ ...message,
2040
+ signature,
2041
+ });
2042
+
2043
+ return node
2044
+ }
2045
+ }
2046
+
2047
+ const encapsulatedError = () => {
2048
+ return new Error('Nodes/Data should be send encapsulated by peernet-message')
2049
+ };
2050
+
2051
+ const dhtError = (proto) => {
2052
+ const text = `Received proto ${proto.name} expected peernet-dht-response`;
2053
+ return new Error(`Routing error: ${text}`)
2054
+ };
2055
+
2056
+ const nothingFoundError = (hash) => {
2057
+ return new Error(`nothing found for ${hash}`)
2058
+ };
2059
+
2060
+ globalThis.leofcoin = globalThis.leofcoin || {};
2061
+ globalThis.globalSub = globalThis.globalSub || new PubSub({verbose: true});
2062
+
2063
+ /**
2064
+ * @access public
2065
+ * @example
2066
+ * const peernet = new Peernet();
2067
+ */
2068
+ class Peernet {
2069
+ /**
2070
+ * @access public
2071
+ * @param {Object} options
2072
+ * @param {String} options.network - desired network
2073
+ * @param {String} options.root - path to root directory
2074
+ * @param {String} options.storePrefix - prefix for datatores (lfc)
2075
+ *
2076
+ * @return {Promise} instance of Peernet
2077
+ *
2078
+ * @example
2079
+ * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
2080
+ */
2081
+ constructor(options = {}) {
2082
+ this._discovered = [];
2083
+ /**
2084
+ * @property {String} network - current network
2085
+ */
2086
+ this.network = options.network || 'leofcoin';
2087
+ const parts = this.network.split(':');
2088
+
2089
+ if (!options.storePrefix) options.storePrefix = 'lfc';
2090
+ if (!options.port) options.port = 2000;
2091
+ if (!options.root) {
2092
+ if (parts[1]) options.root = `.${parts[0]}/peernet/${parts[1]}`;
2093
+ else options.root = `.${this.network}/peernet`;
2094
+ }
2095
+ globalThis.peernet = this;
2096
+ this.bw = {
2097
+ up: 0,
2098
+ down: 0,
2099
+ };
2100
+ return this._init(options)
2101
+ }
2102
+
2103
+ get defaultStores() {
2104
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
2105
+ }
2106
+
2107
+ addProto(name, proto) {
2108
+ if (!this.protos[name]) this.protos[name] = proto;
2109
+ }
2110
+
2111
+ addCodec(name, codec) {
2112
+ if (!this.codecs[name]) this.codecs[name] = codec;
2113
+ }
2114
+
2115
+ async addStore(name, prefix, root, isPrivate = true) {
2116
+ if (name === 'block' || name === 'transaction' || name === 'chain' ||
2117
+ name === 'data' || name === 'message') isPrivate = false;
2118
+
2119
+ let Storage;
2120
+ if (this.hasDaemon) {
2121
+ Storage = LeofcoinStorageClient;
2122
+ } else {
2123
+ Storage = LeofcoinStorage;
2124
+ }
2125
+ globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
2126
+ await new Storage(`${prefix}-${name}`, root);
2127
+
2128
+ globalThis[`${name}Store`].private = isPrivate;
2129
+ if (!isPrivate) this.stores.push(name);
2130
+ }
2131
+
2132
+
2133
+ /**
2134
+ * @see MessageHandler
2135
+ */
2136
+ prepareMessage(to, data) {
2137
+ return this._messageHandler.prepareMessage(this.id, to, data)
2138
+ }
2139
+
2140
+ /**
2141
+ * @access public
2142
+ *
2143
+ * @return {Array} peerId
2144
+ */
2145
+ get peers() {
2146
+ return [...connections.values()]
2147
+ }
2148
+
2149
+ /**
2150
+ * @private
2151
+ *
2152
+ * @param {Object} options
2153
+ * @param {String} options.root - path to root directory
2154
+ *
2155
+ * @return {Promise} instance of Peernet
2156
+ */
2157
+ async _init(options) {
2158
+ // peernetDHT aka closesPeer by coordinates
2159
+ /**
2160
+ * @type {Object}
2161
+ * @property {Object} peer Instance of Peer
2162
+ */
2163
+ this.dht = new DhtEarth();
2164
+ /**
2165
+ * @type {Map}
2166
+ * @property {Object} peer Instance of Peer
2167
+ */
2168
+ this.peerMap = new Map();
2169
+ this.stores = [];
2170
+ this.requestProtos = {};
2171
+ this.storePrefix = options.storePrefix;
2172
+ this.root = options.root;
2173
+
2174
+ /**
2175
+ * proto Object containing protos
2176
+ * @type {Object}
2177
+ * @property {PeernetMessage} protos[peernet-message] messageNode
2178
+ * @property {DHTMessage} protos[peernet-dht] messageNode
2179
+ * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
2180
+ * @property {DataMessage} protos[peernet-data] messageNode
2181
+ * @property {DataMessageResponse} protos[peernet-data-response] messageNode
2182
+ */
2183
+ globalThis.peernet.protos = {
2184
+ 'peernet-request': RequestMessage,
2185
+ 'peernet-response': ResponseMessage,
2186
+ 'peernet-peer': PeerMessage,
2187
+ 'peernet-peer-response': PeerMessageResponse,
2188
+ 'peernet-message': PeernetMessage,
2189
+ 'peernet-dht': DHTMessage,
2190
+ 'peernet-dht-response': DHTMessageResponse,
2191
+ 'peernet-data': DataMessage,
2192
+ 'peernet-data-response': DataMessageResponse,
2193
+ 'peernet-ps': PsMessage,
2194
+ 'chat-message': ChatMessage,
2195
+ };
2196
+
2197
+ this.protos = globalThis.peernet.protos;
2198
+ this.codecs = codecs;
2199
+
2200
+ this._messageHandler = new MessageHandler(this.network);
2201
+
2202
+ const {daemon, environment} = await target();
2203
+ this.hasDaemon = daemon;
2204
+
2205
+ HTTP_IMPORT;
2206
+
2207
+ for (const store of this.defaultStores) {
2208
+ await this.addStore(store, options.storePrefix, options.root);
2209
+ }
2210
+
2211
+ try {
2212
+ const pub = await accountStore.get('public');
2213
+ this.id = pub.walletId;
2214
+ } catch (e) {
2215
+ if (e.code === 'ERR_NOT_FOUND') {
2216
+ const wallet = {};
2217
+ const {identity, accounts, config} = await generateAccount(this.network);
2218
+ wallet.identity = identity;
2219
+ wallet.accounts = accounts;
2220
+ wallet.version = 1;
2221
+ walletStore.put(wallet);
2222
+ await accountStore.put('config', config);
2223
+ await accountStore.put('public', {walletId: wallet.identity.walletId});
2224
+
2225
+ this.id = wallet.identity.walletId;
2226
+ } else {
2227
+ throw e
2228
+ }
2229
+ }
2230
+ this._peerHandler = new PeerDiscovery(this.id);
2231
+ this.peerId = this.id;
2232
+
2233
+ pubsub.subscribe('peer:connected', async (peer) => {
2234
+ console.log(peer);
2235
+ // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
2236
+ // peer.on('peernet.data', async (message) => {
2237
+ // const id = message.id
2238
+ // message = new PeernetMessage(Buffer.from(message.data.data))
2239
+ // const proto = protoFor(message.decoded.data)
2240
+ // this._protoHandler({id, proto}, peer)
2241
+ // })
2242
+ });
2243
+
2244
+ pubsub.subscribe('peer:data', async message => {
2245
+ if (!message.data) return
2246
+ const {id, data} = JSON.parse(new TextDecoder().decode(message.data));
2247
+ const uint8Array = new Uint8Array(Object.keys(data).length);
2248
+ for (var i = 0; i < Object.keys(data).length; i++) {
2249
+ uint8Array[i] = data[i];
2250
+ }
2251
+ message = new PeernetMessage(uint8Array);
2252
+ const proto = protoFor(message.decoded.data);
2253
+
2254
+ const from = new TextDecoder().decode(message.decoded.from);
2255
+ this._protoHandler({id, proto}, this.client.connections[from], from);
2256
+ });
2257
+
2258
+ /**
2259
+ * @access public
2260
+ * @type {PeernetClient}
2261
+ */
2262
+ this.client = new Client(this.id);
2263
+ if (globalThis.onbeforeunload) {
2264
+ globalThis.addEventListener('beforeunload', async () => this.client.close());
2265
+ }
2266
+ return this
2267
+ }
2268
+
2269
+ _getPeerId(id) {
2270
+ for (const entry of [...this.peerMap.entries()]) {
2271
+ for (const _id of entry[1]) {
2272
+ if (_id === id) return entry[0]
2273
+ }
2274
+ }
2275
+ }
2276
+
2277
+ addRequestHandler(name, method) {
2278
+ this.requestProtos[name] = method;
2279
+ }
2280
+
2281
+ /**
2282
+ * @private
2283
+ *
2284
+ * @param {Buffer} message - peernet message
2285
+ * @param {PeernetPeer} peer - peernet peer
2286
+ */
2287
+ async _protoHandler(message, peer, from) {
2288
+ const {id, proto} = message;
2289
+ this.bw.down += proto.encoded.length;
2290
+
2291
+ if (proto.name === 'peernet-dht') {
2292
+ let { hash, store } = proto.decoded;
2293
+ let has;
2294
+
2295
+ if (!store) {
2296
+ has = await this.has(hash);
2297
+ } else {
2298
+ store = globalThis[`${store}Store`];
2299
+ if (store.private) has = false;
2300
+ else has = await store.has(hash);
2301
+ }
2302
+ const data = new DHTMessageResponse({hash, has});
2303
+ const node = await this.prepareMessage(from, data.encoded);
2304
+
2305
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2306
+ this.bw.up += node.encoded.length;
2307
+ } else if (proto.name === 'peernet-data') {
2308
+ let { hash, store } = proto.decoded;
2309
+ let data;
2310
+ if (!store) {
2311
+ store = await this.whichStore([...this.stores], hash);
2312
+ } else {
2313
+ store = globalThis[`${store}Store`];
2314
+ }
2315
+ if (store && !store.private) {
2316
+ data = await store.get(hash);
2317
+
2318
+ if (data) {
2319
+ data = new DataMessageResponse({hash, data: data.decoded ? Buffer.from(JSON.stringify(data)) : Buffer.from(data)});
2320
+
2321
+ const node = await this.prepareMessage(from, data.encoded);
2322
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2323
+ this.bw.up += node.encoded.length;
2324
+ }
2325
+ }
2326
+
2327
+ } else if (proto.name === 'peernet-request') {
2328
+ // TODO: make dynamic
2329
+ // exposeddevapi[proto.decoded.request](proto.decoded.params)
2330
+ const method = this.requestProtos[proto.decoded.request];
2331
+ if (method) {
2332
+ const data = await method();
2333
+ const node = await this.prepareMessage(from, data.encoded);
2334
+ peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
2335
+ this.bw.up += node.encoded.length;
2336
+ }
2337
+ } else if (proto.name === 'peernet-ps' &&
2338
+ this._getPeerId(peer.id) !== this.id.toString()) {
2339
+ globalSub.publish(proto.decoded.topic.toString(), proto.decoded.data.toString());
2340
+ }
2341
+ // }
2342
+ }
2343
+
2344
+ /**
2345
+ * performs a walk and resolves first encounter
2346
+ *
2347
+ * @param {String} hash
2348
+ */
2349
+ async walk(hash) {
2350
+ if (!hash) throw new Error('hash expected, received undefined')
2351
+ const data = new DHTMessage({hash});
2352
+ this.client.id;
2353
+ for (const peer of this.peers) {
2354
+ const node = await this.prepareMessage(peer.id, data.encoded);
2355
+
2356
+ const result = await peer.request(node.encoded);
2357
+
2358
+ let proto = protoFor(result.data);
2359
+
2360
+ if (proto.name !== 'peernet-message') throw encapsulatedError()
2361
+ const from = proto.decoded.from;
2362
+ proto = protoFor(proto.decoded.data);
2363
+
2364
+ if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
2365
+
2366
+ // TODO: give ip and port (just used for location)
2367
+ if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
2368
+ peer.connection.remoteFamily = 'ipv4';
2369
+ peer.connection.remoteAddress = '127.0.0.1';
2370
+ peer.connection.remotePort = '0000';
2371
+ }
2372
+
2373
+ const peerInfo = {
2374
+ family: peer.connection.remoteFamily || peer.connection.localFamily,
2375
+ address: peer.connection.remoteAddress || peer.connection.localAddress,
2376
+ port: peer.connection.remotePort || peer.connection.localPort,
2377
+ id: from,
2378
+ };
2379
+
2380
+ if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
2381
+ }
2382
+ return
2383
+ }
2384
+
2385
+ /**
2386
+ * Override DHT behavior, try's finding the content three times
2387
+ *
2388
+ * @param {String} hash
2389
+ */
2390
+ async providersFor(hash) {
2391
+ let providers = await this.dht.providersFor(hash);
2392
+ // walk the network to find a provider
2393
+ if (!providers || providers.length === 0) {
2394
+ await this.walk(hash);
2395
+ providers = await this.dht.providersFor(hash);
2396
+ // second walk the network to find a provider
2397
+ if (!providers || providers.length === 0) {
2398
+ await this.walk(hash);
2399
+ providers = await this.dht.providersFor(hash);
2400
+ }
2401
+ // last walk
2402
+ if (!providers || providers.length === 0) {
2403
+ await this.walk(hash);
2404
+ providers = await this.dht.providersFor(hash);
2405
+ }
2406
+ }
2407
+ // undefined if no providers given
2408
+ return providers
2409
+ }
2410
+
2411
+ get block() {
2412
+ return {
2413
+ get: async (hash) => {
2414
+ const data = await blockStore.has(hash);
2415
+ if (data) return await blockStore.get(hash)
2416
+ return this.requestData(hash, 'block')
2417
+ },
2418
+ put: async (hash, data) => {
2419
+ if (await blockStore.has(hash)) return
2420
+ return await blockStore.put(hash, data)
2421
+ },
2422
+ has: async (hash) => await blockStore.has(hash, 'block'),
2423
+ }
2424
+ }
2425
+
2426
+ get transaction() {
2427
+ return {
2428
+ get: async (hash) => {
2429
+ const data = await transactionStore.has(hash);
2430
+ if (data) return await transactionStore.get(hash)
2431
+ return this.requestData(hash, 'transaction')
2432
+ },
2433
+ put: async (hash, data) => {
2434
+ if (await transactionStore.has(hash)) return
2435
+ return await transactionStore.put(hash, data)
2436
+ },
2437
+ has: async (hash) => await transactionStore.has(hash),
2438
+ }
2439
+ }
1968
2440
 
1969
- }
2441
+ async requestData(hash, store) {
2442
+ const providers = await this.providersFor(hash);
2443
+ if (!providers || providers.size === 0) throw nothingFoundError(hash)
2444
+ debug(`found ${providers.size} provider(s) for ${hash}`);
2445
+ // get closest peer on earth
2446
+ const closestPeer = await this.dht.closestPeer(providers);
2447
+ // get peer instance by id
2448
+ if (!closestPeer || !closestPeer.id) return this.requestData(hash, store.name ? store.name : store)
2449
+
2450
+ const id = closestPeer.id.toString();
2451
+ if (this.peers) {
2452
+ let closest = this.peers.filter((peer) => {
2453
+ if (this._getPeerId(peer.id) === id) return peer
2454
+ });
2455
+
2456
+ let data = new DataMessage({hash, store: store.name ? store.name : store});
2457
+
2458
+ const node = await this.prepareMessage(id, data.encoded);
2459
+ if (closest[0]) data = await closest[0].request(node.encoded);
2460
+ else {
2461
+ closest = this.peers.filter((peer) => {
2462
+ if (peer.id.toString() === id) return peer
2463
+ });
2464
+ if (closest[0]) data = await closest[0].request(node.encoded);
2465
+ }
2466
+ if (data.data) {
2467
+ let proto = protoFor(Buffer.from(data.data));
2468
+ proto = protoFor(proto.decoded.data);
2469
+ return proto.decoded.data
2470
+ }
1970
2471
 
1971
- verify(multiSignature, hash) {
1972
- return new MultiSignature(this.version, this.network.multiCodec)
1973
- .verify(multiSignature, hash, this.publicKeyBuffer)
1974
- }
2472
+ // this.put(hash, proto.decoded.data)
2473
+ }
2474
+ return null
2475
+ }
1975
2476
 
1976
- /**
1977
- * @param {number} account - account to return chain for
1978
- * @return { internal(addressIndex), external(addressIndex) }
1979
- */
1980
- account(index) {
1981
- return new HDAccount(new MultiWallet(this.network, this.hdnode), index);
1982
- }
1983
2477
 
1984
- /**
1985
- * m / purpose' / coin_type' / account' / change / aadress_index
1986
- *
1987
- * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
1988
- */
1989
- derivePath(path) {
1990
- return new MultiWallet(this.network, this.hdnode.derivePath(path))
1991
- }
2478
+ get message() {
2479
+ return {
2480
+ /**
2481
+ * Get content for given message hash
2482
+ *
2483
+ * @param {String} hash
2484
+ */
2485
+ get: async (hash) => {
2486
+ debug(`get message ${hash}`);
2487
+ const message = await messageStore.has(hash);
2488
+ if (message) return await messageStore.get(hash)
2489
+ return this.requestData(hash, 'message')
2490
+ },
2491
+ /**
2492
+ * put message content
2493
+ *
2494
+ * @param {String} hash
2495
+ * @param {Buffer} message
2496
+ */
2497
+ put: async (hash, message) => await messageStore.put(hash, message),
2498
+ /**
2499
+ * @param {String} hash
2500
+ * @return {Boolean}
2501
+ */
2502
+ has: async (hash) => await messageStore.has(hash),
2503
+ }
2504
+ }
1992
2505
 
1993
- derive(index) {
1994
- return new MultiWallet(this.network, this.hdnode.derive(index));
1995
- }
1996
- }
1997
-
1998
- class MessageHandler {
1999
- constructor(network) {
2000
- this.network = network;
2506
+ get data() {
2507
+ return {
2508
+ /**
2509
+ * Get content for given data hash
2510
+ *
2511
+ * @param {String} hash
2512
+ */
2513
+ get: async (hash) => {
2514
+ debug(`get data ${hash}`);
2515
+ const data = await dataStore.has(hash);
2516
+ if (data) return await dataStore.get(hash)
2517
+ return this.requestData(hash, 'data')
2518
+ },
2519
+ /**
2520
+ * put data content
2521
+ *
2522
+ * @param {String} hash
2523
+ * @param {Buffer} data
2524
+ */
2525
+ put: async (hash, data) => await dataStore.put(hash, data),
2526
+ /**
2527
+ * @param {String} hash
2528
+ * @return {Boolean}
2529
+ */
2530
+ has: async (hash) => await dataStore.has(hash),
2531
+ }
2001
2532
  }
2533
+
2002
2534
  /**
2003
- * hash and sign message
2535
+ * goes trough given stores and tries to find data for given hash
2536
+ * @param {Array} stores
2537
+ * @param {string} hash
2538
+ */
2539
+ async whichStore(stores, hash) {
2540
+ let store = stores.pop();
2541
+ store = globalThis[`${store}Store`];
2542
+ if (store) {
2543
+ const has = await store.has(hash);
2544
+ if (has) return store
2545
+ if (stores.length > 0) return this.whichStore(stores, hash)
2546
+ } else return null
2547
+ }
2548
+
2549
+ /**
2550
+ * Get content for given hash
2004
2551
  *
2005
- * @param {object} message
2006
- * @param {Buffer} message.from peer id
2007
- * @param {Buffer} message.to peer id
2008
- * @param {string} message.data Peernet message
2009
- * (PeernetMessage excluded) encoded as a string
2010
- * @return signature
2552
+ * @param {String} hash - the hash of the wanted data
2553
+ * @param {String} store - storeName to access
2011
2554
  */
2012
- async hashAndSignMessage(message) {
2013
- const hasher = new PeernetHash(message, {name: 'peernet-message'});
2014
- const identity = await walletStore.get('identity');
2555
+ async get(hash, store) {
2556
+ debug(`get ${hash}`);
2557
+ let data;
2558
+ if (store) store = globalThis[`${store}Store`];
2559
+ if (!store) store = await this.whichStore([...this.stores], hash);
2560
+ if (store && await store.has(hash)) data = await store.get(hash);
2561
+ if (data) return data
2562
+
2563
+ return this.requestData(hash, store.name ? store.name : store)
2564
+ }
2015
2565
 
2016
- const wallet = new MultiWallet(this.network);
2017
- wallet.import(identity.multiWIF);
2018
- return wallet.sign(hasher.hash.slice(0, 32))
2566
+ /**
2567
+ * put content
2568
+ *
2569
+ * @param {String} hash
2570
+ * @param {Buffer} data
2571
+ * @param {String} store - storeName to access
2572
+ */
2573
+ async put(hash, data, store = 'data') {
2574
+ store = globalThis[`${store}Store`];
2575
+ return store.put(hash, data)
2019
2576
  }
2020
2577
 
2021
2578
  /**
2022
- * @param {String} from - peer id
2023
- * @param {String} to - peer id
2024
- * @param {String|PeernetMessage} data - data encoded message string
2025
- * or the messageNode itself
2579
+ * @param {String} hash
2580
+ * @return {Boolean}
2026
2581
  */
2027
- async prepareMessage(from, to, data, id) {
2028
- if (!Buffer.isBuffer(from)) from = new Buffer.from(from);
2029
- if (!Buffer.isBuffer(to)) to = new Buffer.from(to);
2030
- if (data.encoded) data = data.encoded;
2582
+ async has(hash) {
2583
+ const store = await this.whichStore([...this.stores], hash);
2584
+ if (store) {
2585
+ if (store.private) return false
2586
+ else return true
2587
+ }
2588
+ return false
2589
+ }
2031
2590
 
2032
- const message = {
2033
- from,
2034
- to,
2035
- data,
2036
- };
2037
- const signature = await this.hashAndSignMessage(message);
2038
- const node = new PeernetMessage({
2039
- ...message,
2040
- signature,
2041
- });
2591
+ /**
2592
+ *
2593
+ * @param {String} topic
2594
+ * @param {String|Object|Array|Boolean|Buffer} data
2595
+ */
2596
+ async publish(topic, data) {
2597
+ // globalSub.publish(topic, data)
2598
+ if (!Buffer.isBuffer(topic)) topic = Buffer.from(topic);
2599
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data);
2600
+ const id = Math.random().toString(36).slice(-12);
2601
+ data = new PsMessage({data, topic});
2602
+ for (const peer of this.peers) {
2603
+ if (peer.connection._connected) {
2604
+ if (peer.id.toString() !== this.peerId.toString()) {
2605
+ const node = await this.prepareMessage(peer.id, data.encoded);
2606
+ peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2607
+ }
2608
+ } else {
2609
+ this.removePeer(peer);
2610
+ }
2611
+ // TODO: if peer subscribed
2612
+ }
2613
+ }
2042
2614
 
2043
- return node
2615
+ createHash(data, name) {
2616
+ return new PeernetHash(data, {name})
2044
2617
  }
2045
- }
2046
-
2047
- const encapsulatedError = () => {
2048
- return new Error('Nodes/Data should be send encapsulated by peernet-message')
2049
- };
2050
-
2051
- const dhtError = (proto) => {
2052
- const text = `Received proto ${proto.name} expected peernet-dht-response`;
2053
- return new Error(`Routing error: ${text}`)
2054
- };
2055
-
2056
- const nothingFoundError = (hash) => {
2057
- return new Error(`nothing found for ${hash}`)
2058
- };
2059
-
2060
- globalThis.leofcoin = globalThis.leofcoin || {};
2061
- globalThis.globalSub = globalThis.globalSub || new PubSub({verbose: true});
2062
-
2063
- /**
2064
- * @access public
2065
- * @example
2066
- * const peernet = new Peernet();
2067
- */
2068
- class Peernet {
2069
- /**
2070
- * @access public
2071
- * @param {Object} options
2072
- * @param {String} options.network - desired network
2073
- * @param {String} options.root - path to root directory
2074
- * @param {String} options.storePrefix - prefix for datatores (lfc)
2075
- *
2076
- * @return {Promise} instance of Peernet
2077
- *
2078
- * @example
2079
- * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
2080
- */
2081
- constructor(options = {}) {
2082
- this._discovered = [];
2083
- /**
2084
- * @property {String} network - current network
2085
- */
2086
- this.network = options.network || 'leofcoin';
2087
- const parts = this.network.split(':');
2088
-
2089
- if (!options.storePrefix) options.storePrefix = 'lfc';
2090
- if (!options.port) options.port = 2000;
2091
- if (!options.root) {
2092
- if (parts[1]) options.root = `.${parts[0]}/peernet/${parts[1]}`;
2093
- else options.root = `.${this.network}/peernet`;
2094
- }
2095
- globalThis.peernet = this;
2096
- this.bw = {
2097
- up: 0,
2098
- down: 0,
2099
- };
2100
- return this._init(options)
2101
- }
2102
-
2103
- get defaultStores() {
2104
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
2105
- }
2106
-
2107
- addProto(name, proto) {
2108
- if (!this.protos[name]) this.protos[name] = proto;
2109
- }
2110
-
2111
- addCodec(name, codec) {
2112
- if (!this.codecs[name]) this.codecs[name] = codec;
2113
- }
2114
-
2115
- async addStore(name, prefix, root, isPrivate = true) {
2116
- if (name === 'block' || name === 'transaction' || name === 'chain' ||
2117
- name === 'data' || name === 'message') isPrivate = false;
2118
-
2119
- let Storage;
2120
- if (this.hasDaemon) {
2121
- Storage = LeofcoinStorageClient;
2122
- } else {
2123
- Storage = LeofcoinStorage;
2124
- }
2125
- globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
2126
- await new Storage(`${prefix}-${name}`, root);
2127
-
2128
- globalThis[`${name}Store`].private = isPrivate;
2129
- if (!isPrivate) this.stores.push(name);
2130
- }
2131
-
2132
-
2133
- /**
2134
- * @see MessageHandler
2135
- */
2136
- prepareMessage(to, data) {
2137
- return this._messageHandler.prepareMessage(this.id, to, data)
2138
- }
2139
-
2140
- /**
2141
- * @access public
2142
- *
2143
- * @return {Array} peerId
2144
- */
2145
- get peers() {
2146
- return [...connections.values()]
2147
- }
2148
-
2149
- /**
2150
- * @private
2151
- *
2152
- * @param {Object} options
2153
- * @param {String} options.root - path to root directory
2154
- *
2155
- * @return {Promise} instance of Peernet
2156
- */
2157
- async _init(options) {
2158
- // peernetDHT aka closesPeer by coordinates
2159
- /**
2160
- * @type {Object}
2161
- * @property {Object} peer Instance of Peer
2162
- */
2163
- this.dht = new DhtEarth();
2164
- /**
2165
- * @type {Map}
2166
- * @property {Object} peer Instance of Peer
2167
- */
2168
- this.peerMap = new Map();
2169
- this.stores = [];
2170
- this.requestProtos = {};
2171
- this.storePrefix = options.storePrefix;
2172
- this.root = options.root;
2173
-
2174
- /**
2175
- * proto Object containing protos
2176
- * @type {Object}
2177
- * @property {PeernetMessage} protos[peernet-message] messageNode
2178
- * @property {DHTMessage} protos[peernet-dht] messageNode
2179
- * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
2180
- * @property {DataMessage} protos[peernet-data] messageNode
2181
- * @property {DataMessageResponse} protos[peernet-data-response] messageNode
2182
- */
2183
- globalThis.peernet.protos = {
2184
- 'peernet-request': RequestMessage,
2185
- 'peernet-response': ResponseMessage,
2186
- 'peernet-peer': PeerMessage,
2187
- 'peernet-peer-response': PeerMessageResponse,
2188
- 'peernet-message': PeernetMessage,
2189
- 'peernet-dht': DHTMessage,
2190
- 'peernet-dht-response': DHTMessageResponse,
2191
- 'peernet-data': DataMessage,
2192
- 'peernet-data-response': DataMessageResponse,
2193
- 'peernet-ps': PsMessage,
2194
- 'chat-message': ChatMessage,
2195
- };
2196
-
2197
- this.protos = globalThis.peernet.protos;
2198
- this.codecs = codecs;
2199
-
2200
- this._messageHandler = new MessageHandler(this.network);
2201
-
2202
- const {daemon, environment} = await target();
2203
- this.hasDaemon = daemon;
2204
-
2205
- HTTP_IMPORT;
2206
-
2207
- for (const store of this.defaultStores) {
2208
- await this.addStore(store, options.storePrefix, options.root);
2209
- }
2210
-
2211
- try {
2212
- const pub = await accountStore.get('public');
2213
- this.id = pub.walletId;
2214
- } catch (e) {
2215
- if (e.code === 'ERR_NOT_FOUND') {
2216
- const wallet = {};
2217
- const {identity, accounts, config} = await generateAccount(this.network);
2218
- wallet.identity = identity;
2219
- wallet.accounts = accounts;
2220
- wallet.version = 1;
2221
- walletStore.put(wallet);
2222
- await accountStore.put('config', config);
2223
- await accountStore.put('public', {walletId: wallet.identity.walletId});
2224
-
2225
- this.id = wallet.identity.walletId;
2226
- } else {
2227
- throw e
2228
- }
2229
- }
2230
- this._peerHandler = new PeerDiscovery(this.id);
2231
- this.peerId = this.id;
2232
-
2233
- // pubsub.subscribe('peer:discovered', async (peer) => {
2234
- // peer.on('peernet.data', async (message) => {
2235
- // const id = message.id;
2236
- // message = new PeernetMessage(Buffer.from(message.data.data));
2237
- // const proto = protoFor(message.decoded.data);
2238
- // await this._protoHandler({id, proto}, peer);
2239
- // });
2240
- // await this._peerHandler.discover(peer);
2241
- // const fulldId = this._getPeerId(peer.id);
2242
- // if (fulldId && this._discovered.indexOf(peer.id) === -1) {
2243
- // this._discovered.push(peer.id);
2244
- // pubsub.publish('peer:connected', peer);
2245
- // }
2246
- // });
2247
- // pubsub.subscribe('peer:disconnected', async (peer) => {
2248
- // let index = this._discovered.indexOf(peer.id)
2249
- // if (index !== -1) this._discovered.splice(index, 1)
2250
- // const id = this._getPeerId(peer.id)
2251
- // let peerIds = this.peerMap.get(id)
2252
- //
2253
- // if (peerIds) {
2254
- // index = peerIds.indexOf(peer.id)
2255
- // if (index !== -1) peerIds.splice(index, 1)
2256
- // } else {
2257
- // peerIds = []
2258
- // }
2259
- //
2260
- // if (peerIds.length === 0) this.peerMap.delete(id)
2261
- // else this.peerMap.set(id, peerIds)
2262
- // })
2263
- pubsub.subscribe('peer:connected', async (peer) => {
2264
- console.log(peer);
2265
- // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
2266
- // peer.on('peernet.data', async (message) => {
2267
- // const id = message.id
2268
- // message = new PeernetMessage(Buffer.from(message.data.data))
2269
- // const proto = protoFor(message.decoded.data)
2270
- // this._protoHandler({id, proto}, peer)
2271
- // })
2272
- });
2273
-
2274
- pubsub.subscribe('peer:data', async message => {
2275
- console.log({message});
2276
- if (!message.data) return
2277
- const {id, data} = JSON.parse(new TextDecoder().decode(message.data));
2278
- const uint8Array = new Uint8Array(Object.keys(data).length);
2279
- for (var i = 0; i < Object.keys(data).length; i++) {
2280
- uint8Array[i] = data[i];
2281
- }
2282
- message = new PeernetMessage(uint8Array);
2283
- const proto = protoFor(message.decoded.data);
2284
-
2285
- console.log(message.decoded);
2286
- const from = new TextDecoder().decode(message.decoded.from);
2287
- this._protoHandler({id, proto}, this.client.connections[from], from);
2288
- });
2289
-
2290
- /**
2291
- * @access public
2292
- * @type {PeernetClient}
2293
- */
2294
- this.client = new Client(this.id);
2295
- if (globalThis.onbeforeunload) {
2296
- globalThis.addEventListener('beforeunload', async () => this.client.close());
2297
- }
2298
- return this
2299
- }
2300
-
2301
- _getPeerId(id) {
2302
- for (const entry of [...this.peerMap.entries()]) {
2303
- for (const _id of entry[1]) {
2304
- if (_id === id) return entry[0]
2305
- }
2306
- }
2307
- }
2308
-
2309
- addRequestHandler(name, method) {
2310
- this.requestProtos[name] = method;
2311
- }
2312
-
2313
- /**
2314
- * @private
2315
- *
2316
- * @param {Buffer} message - peernet message
2317
- * @param {PeernetPeer} peer - peernet peer
2318
- */
2319
- async _protoHandler(message, peer, from) {
2320
- const {id, proto} = message;
2321
- console.log(message);
2322
- this.bw.down += proto.encoded.length;
2323
- // if (proto.name === 'peernet-peer') {
2324
- // const from = proto.decoded.id
2325
- // if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
2326
- // else {
2327
- // const connections = this.peerMap.get(from)
2328
- // if (connections.indexOf(peer.id) === -1) {
2329
- // connections.push(peer.id)
2330
- // this.peerMap.set(from, connections)
2331
- // }
2332
- // }
2333
- // const data = new PeerMessageResponse({id: this.id})
2334
- // const node = await this.prepareMessage(from, data.encoded)
2335
- //
2336
- // peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})))
2337
- // this.bw.up += node.encoded.length
2338
- // } else if (proto.name === 'peernet-peer-response') {
2339
- // const from = proto.decoded.id
2340
- // if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
2341
- // else {
2342
- // const connections = this.peerMap.get(from)
2343
- // if (connections.indexOf(peer.id) === -1) {
2344
- // connections.push(peer.id)
2345
- // this.peerMap.set(from, connections)
2346
- // }
2347
- // }
2348
- // } else {
2349
- // let from = this._getPeerId(peer.id)
2350
- // if (!from) {
2351
- // const data = new PeerMessage({id: this.id})
2352
- // const node = await this.prepareMessage(peer.id, data.encoded)
2353
- // this.bw.up += node.encoded.length
2354
- // let response = await peer.request(node.encoded)
2355
- // response = protoFor(response)
2356
- //
2357
- // response = new PeerMessageResponse(response.decoded.data)
2358
- //
2359
- // from = response.decoded.id
2360
- // if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id])
2361
- // else {
2362
- // const connections = this.peerMap.get(from)
2363
- // if (connections.indexOf(peer.id) === -1) {
2364
- // connections.push(peer.id)
2365
- // this.peerMap.set(from, connections)
2366
- // }
2367
- // }
2368
- // }
2369
- if (proto.name === 'peernet-dht') {
2370
- let { hash, store } = proto.decoded;
2371
- let has;
2372
-
2373
- if (!store) {
2374
- has = await this.has(hash);
2375
- } else {
2376
- store = globalThis[`${store}Store`];
2377
- if (store.private) has = false;
2378
- else has = await store.has(hash);
2379
- }
2380
- const data = new DHTMessageResponse({hash, has});
2381
- const node = await this.prepareMessage(from, data.encoded);
2382
-
2383
- peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2384
- this.bw.up += node.encoded.length;
2385
- } else if (proto.name === 'peernet-data') {
2386
- let { hash, store } = proto.decoded;
2387
- let data;
2388
- if (!store) {
2389
- store = await this.whichStore([...this.stores], hash);
2390
- } else {
2391
- store = globalThis[`${store}Store`];
2392
- }
2393
- if (store && !store.private) {
2394
- data = await store.get(hash);
2395
-
2396
- if (data) {
2397
- data = new DataMessageResponse({hash, data: data.decoded ? Buffer.from(JSON.stringify(data)) : Buffer.from(data)});
2398
-
2399
- const node = await this.prepareMessage(from, data.encoded);
2400
- peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2401
- this.bw.up += node.encoded.length;
2402
- }
2403
- }
2404
-
2405
- } else if (proto.name === 'peernet-peer') {
2406
- const from = proto.decoded.id;
2407
- if (!this.peerMap.has(from)) this.peerMap.set(from, [peer.id]);
2408
- else {
2409
- const connections = this.peerMap.get(from);
2410
- connections.push(peer.id);
2411
- this.peerMap.set(from, connections);
2412
- }
2413
- const data = new PeerMessage({id: this.id});
2414
- const node = await this.prepareMessage(from, data.encoded);
2415
-
2416
- peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2417
- this.bw.up += node.encoded.length;
2418
- } else if (proto.name === 'peernet-request') {
2419
- // TODO: make dynamic
2420
- // exposeddevapi[proto.decoded.request](proto.decoded.params)
2421
- const method = this.requestProtos[proto.decoded.request];
2422
- if (method) {
2423
- const data = await method();
2424
- const node = await this.prepareMessage(from, data.encoded);
2425
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
2426
- this.bw.up += node.encoded.length;
2427
- }
2428
- } else if (proto.name === 'peernet-ps' &&
2429
- this._getPeerId(peer.id) !== this.id.toString()) {
2430
- globalSub.publish(proto.decoded.topic.toString(), proto.decoded.data.toString());
2431
- }
2432
- // }
2433
- }
2434
-
2435
- /**
2436
- * performs a walk and resolves first encounter
2437
- *
2438
- * @param {String} hash
2439
- */
2440
- async walk(hash) {
2441
- if (!hash) throw new Error('hash expected, received undefined')
2442
- const data = new DHTMessage({hash});
2443
- this.client.id;
2444
- for (const peer of this.peers) {
2445
- const node = await this.prepareMessage(peer.id, data.encoded);
2446
-
2447
- const result = await peer.request(node.encoded);
2448
-
2449
- let proto = protoFor(result.data);
2450
-
2451
- if (proto.name !== 'peernet-message') throw encapsulatedError()
2452
- const from = proto.decoded.from;
2453
- proto = protoFor(proto.decoded.data);
2454
-
2455
- if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
2456
-
2457
- // TODO: give ip and port (just used for location)
2458
- if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
2459
- peer.connection.remoteFamily = 'ipv4';
2460
- peer.connection.remoteAddress = '127.0.0.1';
2461
- peer.connection.remotePort = '0000';
2462
- }
2463
-
2464
- const peerInfo = {
2465
- family: peer.connection.remoteFamily || peer.connection.localFamily,
2466
- address: peer.connection.remoteAddress || peer.connection.localAddress,
2467
- port: peer.connection.remotePort || peer.connection.localPort,
2468
- id: from,
2469
- };
2470
-
2471
- if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
2472
- }
2473
- return
2474
- }
2475
-
2476
- /**
2477
- * Override DHT behavior, try's finding the content three times
2478
- *
2479
- * @param {String} hash
2480
- */
2481
- async providersFor(hash) {
2482
- let providers = await this.dht.providersFor(hash);
2483
- // walk the network to find a provider
2484
- if (!providers || providers.length === 0) {
2485
- await this.walk(hash);
2486
- providers = await this.dht.providersFor(hash);
2487
- // second walk the network to find a provider
2488
- if (!providers || providers.length === 0) {
2489
- await this.walk(hash);
2490
- providers = await this.dht.providersFor(hash);
2491
- }
2492
- // last walk
2493
- if (!providers || providers.length === 0) {
2494
- await this.walk(hash);
2495
- providers = await this.dht.providersFor(hash);
2496
- }
2497
- }
2498
- // undefined if no providers given
2499
- return providers
2500
- }
2501
-
2502
- get block() {
2503
- return {
2504
- get: async (hash) => {
2505
- const data = await blockStore.has(hash);
2506
- if (data) return await blockStore.get(hash)
2507
- return this.requestData(hash, 'block')
2508
- },
2509
- put: async (hash, data) => {
2510
- if (await blockStore.has(hash)) return
2511
- return await blockStore.put(hash, data)
2512
- },
2513
- has: async (hash) => await blockStore.has(hash, 'block'),
2514
- }
2515
- }
2516
-
2517
- get transaction() {
2518
- return {
2519
- get: async (hash) => {
2520
- const data = await transactionStore.has(hash);
2521
- if (data) return await transactionStore.get(hash)
2522
- return this.requestData(hash, 'transaction')
2523
- },
2524
- put: async (hash, data) => {
2525
- if (await transactionStore.has(hash)) return
2526
- return await transactionStore.put(hash, data)
2527
- },
2528
- has: async (hash) => await transactionStore.has(hash),
2529
- }
2530
- }
2531
-
2532
- async requestData(hash, store) {
2533
- const providers = await this.providersFor(hash);
2534
- if (!providers || providers.size === 0) throw nothingFoundError(hash)
2535
- debug(`found ${providers.size} provider(s) for ${hash}`);
2536
- // get closest peer on earth
2537
- const closestPeer = await this.dht.closestPeer(providers);
2538
- // get peer instance by id
2539
- if (!closestPeer || !closestPeer.id) return this.requestData(hash, store.name ? store.name : store)
2540
-
2541
- const id = closestPeer.id.toString();
2542
- if (this.peers) {
2543
- let closest = this.peers.filter((peer) => {
2544
- if (this._getPeerId(peer.id) === id) return peer
2545
- });
2546
-
2547
- let data = new DataMessage({hash, store: store.name ? store.name : store});
2548
-
2549
- const node = await this.prepareMessage(id, data.encoded);
2550
- if (closest[0]) data = await closest[0].request(node.encoded);
2551
- else {
2552
- closest = this.peers.filter((peer) => {
2553
- if (peer.id.toString() === id) return peer
2554
- });
2555
- if (closest[0]) data = await closest[0].request(node.encoded);
2556
- }
2557
- if (data.data) {
2558
- let proto = protoFor(Buffer.from(data.data));
2559
- proto = protoFor(proto.decoded.data);
2560
- return proto.decoded.data
2561
- }
2562
-
2563
- // this.put(hash, proto.decoded.data)
2564
- }
2565
- return null
2566
- }
2567
-
2568
-
2569
- get message() {
2570
- return {
2571
- /**
2572
- * Get content for given message hash
2573
- *
2574
- * @param {String} hash
2575
- */
2576
- get: async (hash) => {
2577
- debug(`get message ${hash}`);
2578
- const message = await messageStore.has(hash);
2579
- if (message) return await messageStore.get(hash)
2580
- return this.requestData(hash, 'message')
2581
- },
2582
- /**
2583
- * put message content
2584
- *
2585
- * @param {String} hash
2586
- * @param {Buffer} message
2587
- */
2588
- put: async (hash, message) => await messageStore.put(hash, message),
2589
- /**
2590
- * @param {String} hash
2591
- * @return {Boolean}
2592
- */
2593
- has: async (hash) => await messageStore.has(hash),
2594
- }
2595
- }
2596
-
2597
- get data() {
2598
- return {
2599
- /**
2600
- * Get content for given data hash
2601
- *
2602
- * @param {String} hash
2603
- */
2604
- get: async (hash) => {
2605
- debug(`get data ${hash}`);
2606
- const data = await dataStore.has(hash);
2607
- if (data) return await dataStore.get(hash)
2608
- return this.requestData(hash, 'data')
2609
- },
2610
- /**
2611
- * put data content
2612
- *
2613
- * @param {String} hash
2614
- * @param {Buffer} data
2615
- */
2616
- put: async (hash, data) => await dataStore.put(hash, data),
2617
- /**
2618
- * @param {String} hash
2619
- * @return {Boolean}
2620
- */
2621
- has: async (hash) => await dataStore.has(hash),
2622
- }
2623
- }
2624
-
2625
- /**
2626
- * goes trough given stores and tries to find data for given hash
2627
- * @param {Array} stores
2628
- * @param {string} hash
2629
- */
2630
- async whichStore(stores, hash) {
2631
- let store = stores.pop();
2632
- store = globalThis[`${store}Store`];
2633
- if (store) {
2634
- const has = await store.has(hash);
2635
- if (has) return store
2636
- if (stores.length > 0) return this.whichStore(stores, hash)
2637
- } else return null
2638
- }
2639
-
2640
- /**
2641
- * Get content for given hash
2642
- *
2643
- * @param {String} hash - the hash of the wanted data
2644
- * @param {String} store - storeName to access
2645
- */
2646
- async get(hash, store) {
2647
- debug(`get ${hash}`);
2648
- let data;
2649
- if (store) store = globalThis[`${store}Store`];
2650
- if (!store) store = await this.whichStore([...this.stores], hash);
2651
- if (store && await store.has(hash)) data = await store.get(hash);
2652
- if (data) return data
2653
-
2654
- return this.requestData(hash, store.name ? store.name : store)
2655
- }
2656
-
2657
- /**
2658
- * put content
2659
- *
2660
- * @param {String} hash
2661
- * @param {Buffer} data
2662
- * @param {String} store - storeName to access
2663
- */
2664
- async put(hash, data, store = 'data') {
2665
- store = globalThis[`${store}Store`];
2666
- return store.put(hash, data)
2667
- }
2668
-
2669
- /**
2670
- * @param {String} hash
2671
- * @return {Boolean}
2672
- */
2673
- async has(hash) {
2674
- const store = await this.whichStore([...this.stores], hash);
2675
- if (store) {
2676
- if (store.private) return false
2677
- else return true
2678
- }
2679
- return false
2680
- }
2681
-
2682
- /**
2683
- *
2684
- * @param {String} topic
2685
- * @param {String|Object|Array|Boolean|Buffer} data
2686
- */
2687
- async publish(topic, data) {
2688
- // globalSub.publish(topic, data)
2689
- if (!Buffer.isBuffer(topic)) topic = Buffer.from(topic);
2690
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
2691
- const id = Math.random().toString(36).slice(-12);
2692
- data = new PsMessage({data, topic});
2693
- for (const peer of this.peers) {
2694
- if (peer.connection._connected) {
2695
- if (peer.id.toString() !== this.peerId.toString()) {
2696
- const node = await this.prepareMessage(peer.id, data.encoded);
2697
- peer.send(Buffer.from(JSON.stringify({id, data: node.encoded})));
2698
- }
2699
- } else {
2700
- this.removePeer(peer);
2701
- }
2702
- // TODO: if peer subscribed
2703
- }
2704
- }
2705
-
2706
- createHash(data, name) {
2707
- return new PeernetHash(data, {name})
2708
- }
2709
-
2710
- /**
2711
- *
2712
- * @param {String} topic
2713
- * @param {Method} cb
2714
- */
2715
- async subscribe(topic, cb) {
2716
- // TODO: if peer subscribed
2717
- globalSub.subscribe(topic, cb);
2718
- }
2719
-
2720
- async removePeer(peer) {
2721
- connections.delete(peer.id);
2722
- }
2723
-
2724
- get Buffer() {
2725
- return Buffer
2726
- }
2727
- // async block(index) {
2728
- // const _values = []
2729
- // for (const peer of this.peers) {
2730
- // const value = await peer.request({type: 'block', index})
2731
- // console.log(value);
2732
- // }
2733
- //
2734
- // }
2618
+
2619
+ /**
2620
+ *
2621
+ * @param {String} topic
2622
+ * @param {Method} cb
2623
+ */
2624
+ async subscribe(topic, cb) {
2625
+ // TODO: if peer subscribed
2626
+ globalSub.subscribe(topic, cb);
2627
+ }
2628
+
2629
+ async removePeer(peer) {
2630
+ connections.delete(peer.id);
2631
+ }
2632
+
2633
+ get Buffer() {
2634
+ return Buffer
2635
+ }
2636
+ // async block(index) {
2637
+ // const _values = []
2638
+ // for (const peer of this.peers) {
2639
+ // const value = await peer.request({type: 'block', index})
2640
+ // console.log(value);
2641
+ // }
2642
+ //
2643
+ // }
2735
2644
  }
2736
2645
 
2737
2646
  export { Peernet as default };