@leofcoin/peernet 1.1.79 → 1.1.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.esdoc.json +10 -10
- package/.gitattributes +2 -2
- package/.prettierrc +7 -7
- package/.travis.yml +27 -27
- package/BREAKING_CHANGES.md +34 -34
- package/LICENSE +21 -21
- package/README.md +72 -72
- package/deploy.js +8 -8
- package/exports/browser/{browser-WUe24rfW.js → browser-DQJ6xf_F.js} +3 -3
- package/exports/browser/browser-store.js +168 -22
- package/exports/browser/{client-I9x7CFr1.js → client-C0VVXIWm.js} +66 -32
- package/exports/browser/{peernet-DULgegxE.js → identity-CQ_ieRiz.js} +2232 -13425
- package/exports/browser/identity.d.ts +1 -1
- package/exports/browser/identity.js +1 -0
- package/exports/browser/{index-sw14JvKD.js → index-BeqbCwUk.js} +1 -2
- package/exports/browser/{index-In1Jzp-v.js → index-CEwkDK9g.js} +10 -489
- package/exports/browser/{messages-lzTD4EMU.js → messages-BdevLRCA.js} +167 -166
- package/exports/browser/peernet-DEIKLS2i.js +13220 -0
- package/exports/browser/peernet.d.ts +7 -7
- package/exports/browser/peernet.js +3 -2
- package/exports/identity.js +92 -0
- package/exports/{messages-T3M-Ff1E.js → messages-BmpgEM4y.js} +163 -163
- package/exports/peernet.js +189 -273
- package/exports/src/prompts/password.js +3 -3
- package/exports/store.js +9 -2
- package/exports/types/identity.d.ts +1 -1
- package/exports/types/peernet.d.ts +7 -7
- package/index.html +19 -19
- package/package.json +71 -62
- package/rollup.config.js +63 -63
- package/src/dht/dht.ts +147 -147
- package/src/discovery/peer-discovery.js +75 -75
- package/src/errors/errors.js +12 -12
- package/src/handlers/data.js +15 -15
- package/src/handlers/message.js +34 -34
- package/src/identity.ts +104 -104
- package/src/messages/chat.js +13 -13
- package/src/messages/data-response.js +13 -13
- package/src/messages/data.js +17 -17
- package/src/messages/dht-response.js +13 -13
- package/src/messages/dht.js +21 -21
- package/src/messages/file-link.js +17 -17
- package/src/messages/file.js +17 -17
- package/src/messages/peer-response.js +13 -13
- package/src/messages/peer.js +13 -13
- package/src/messages/peernet.js +13 -13
- package/src/messages/ps.js +13 -13
- package/src/messages/request.js +13 -13
- package/src/messages/response.js +13 -13
- package/src/messages.js +13 -13
- package/src/peer-info.js +9 -9
- package/src/peernet.ts +817 -817
- package/src/prompts/password/browser.js +1 -1
- package/src/prompts/password/node.js +6 -6
- package/src/proto/chat-message.proto.js +6 -6
- package/src/proto/data-response.proto.js +4 -4
- package/src/proto/data.proto.js +4 -4
- package/src/proto/dht-response.proto.js +4 -4
- package/src/proto/dht.proto.js +4 -4
- package/src/proto/file-link.proto.js +5 -5
- package/src/proto/file.proto.js +5 -5
- package/src/proto/peer-response.proto.js +3 -3
- package/src/proto/peer.proto.js +3 -3
- package/src/proto/peernet.proto.js +7 -7
- package/src/proto/ps.proto.js +4 -4
- package/src/proto/request.proto.js +4 -4
- package/src/proto/response.proto.js +3 -3
- package/src/types.ts +25 -25
- package/src/utils/utils.js +77 -77
- package/test/client.js +14 -14
- package/test/codec.js +56 -56
- package/test/hash.js +13 -13
- package/test/index.js +3 -3
- package/test/lastBlock.js +7 -7
- package/test/messages.js +26 -26
- package/test/peernet.js +17 -17
- package/test/peernet.test.js +159 -0
- package/test.js +62 -62
- package/test2.js +13 -13
- package/test3.js +15 -15
- package/test4.js +7 -7
- package/tsconfig.json +11 -13
- /package/exports/browser/{browser-AyxSBUXj.js → browser-pguCHlVu.js} +0 -0
- /package/exports/browser/{qr-scanner-worker.min-RaSiJc_R.js → qr-scanner-worker.min-Dy0qkKA4.js} +0 -0
- /package/exports/browser/{value-wzPYMxsX.js → value-C3vAp-wb.js} +0 -0
package/package.json
CHANGED
|
@@ -1,62 +1,71 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@leofcoin/peernet",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "",
|
|
5
|
-
"browser": "./exports/browser/peernet.js",
|
|
6
|
-
"exports": {
|
|
7
|
-
".": {
|
|
8
|
-
"import": "./exports/peernet.js",
|
|
9
|
-
"require": "./exports/commonjs/peernet.js",
|
|
10
|
-
"types": "./exports/types/peernet.d.ts"
|
|
11
|
-
},
|
|
12
|
-
"./
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"@leofcoin/
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"@
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"@
|
|
59
|
-
"@
|
|
60
|
-
"rollup": "^
|
|
61
|
-
|
|
62
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@leofcoin/peernet",
|
|
3
|
+
"version": "1.1.81",
|
|
4
|
+
"description": "",
|
|
5
|
+
"browser": "./exports/browser/peernet.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./exports/peernet.js",
|
|
9
|
+
"require": "./exports/commonjs/peernet.js",
|
|
10
|
+
"types": "./exports/types/peernet.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./identity": {
|
|
13
|
+
"import": "./exports/identity.js",
|
|
14
|
+
"require": "./exports/commonjs/identity.js",
|
|
15
|
+
"types": "./exports/types/identity.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./browser": "./exports/browser/peernet.js"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=19.0.0"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "rollup -c",
|
|
25
|
+
"watch": "rollup -c -w",
|
|
26
|
+
"test": "npx mocha test/peernet.test.ts",
|
|
27
|
+
"server": "discovery-swarm-webrtc --port=4000",
|
|
28
|
+
"demo": "jsproject --serve ./ --port 6868"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@leofcoin/codec-format-interface": "^1.7.11",
|
|
35
|
+
"@leofcoin/codecs": "^1.0.6",
|
|
36
|
+
"@leofcoin/generate-account": "^2.0.3",
|
|
37
|
+
"@leofcoin/identity-utils": "^1.0.2",
|
|
38
|
+
"@leofcoin/multi-wallet": "^3.1.8",
|
|
39
|
+
"@leofcoin/storage": "^3.5.32",
|
|
40
|
+
"@netpeer/p2pt-swarm": "^1.3.6",
|
|
41
|
+
"@netpeer/swarm": "^0.8.16",
|
|
42
|
+
"@vandeurenglenn/base32": "^1.2.4",
|
|
43
|
+
"@vandeurenglenn/base58": "^1.1.9",
|
|
44
|
+
"@vandeurenglenn/debug": "^1.2.5",
|
|
45
|
+
"@vandeurenglenn/is-hex": "^1.1.1",
|
|
46
|
+
"@vandeurenglenn/little-pubsub": "^1.5.1",
|
|
47
|
+
"inquirer": "^10.2.2",
|
|
48
|
+
"multi-signature": "^1.3.1",
|
|
49
|
+
"qr-scanner": "^1.4.2",
|
|
50
|
+
"qrcode": "^1.5.4",
|
|
51
|
+
"socket-request-client": "^2.0.9",
|
|
52
|
+
"socket-request-server": "^1.6.17"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@jest/globals": "^29.7.0",
|
|
56
|
+
"@rollup/plugin-commonjs": "^26.0.1",
|
|
57
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
58
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
59
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
60
|
+
"@rollup/plugin-wasm": "^6.2.2",
|
|
61
|
+
"@types/bs58check": "^2.1.2",
|
|
62
|
+
"@types/node": "^22.5.5",
|
|
63
|
+
"@types/qrcode": "^1.5.5",
|
|
64
|
+
"@types/secp256k1": "^4.0.6",
|
|
65
|
+
"@types/varint": "^6.0.3",
|
|
66
|
+
"chai": "^5.1.1",
|
|
67
|
+
"cross-env": "^7.0.3",
|
|
68
|
+
"rollup": "^4.21.3",
|
|
69
|
+
"sinon": "^19.0.2"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/rollup.config.js
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import resolve from '@rollup/plugin-node-resolve'
|
|
2
|
-
import commonjs from '@rollup/plugin-commonjs'
|
|
3
|
-
import json from '@rollup/plugin-json'
|
|
4
|
-
import wasm from '@rollup/plugin-wasm'
|
|
5
|
-
import rimraf from 'rimraf'
|
|
6
|
-
import typescript from '@rollup/plugin-typescript'
|
|
7
|
-
|
|
8
|
-
rimraf.sync('./exports/**')
|
|
9
|
-
|
|
10
|
-
export default [
|
|
11
|
-
{
|
|
12
|
-
input: ['./src/peernet.ts', './node_modules/@leofcoin/storage/exports/browser-store.js'],
|
|
13
|
-
output: {
|
|
14
|
-
format: 'es',
|
|
15
|
-
dir: './exports/browser'
|
|
16
|
-
},
|
|
17
|
-
plugins: [
|
|
18
|
-
json(),
|
|
19
|
-
wasm(),
|
|
20
|
-
resolve({
|
|
21
|
-
browser: true,
|
|
22
|
-
preferBuiltins: false,
|
|
23
|
-
mainFields: ['browser', 'module', 'main']
|
|
24
|
-
}),
|
|
25
|
-
commonjs({
|
|
26
|
-
mainFields: ['browser', 'module', 'main']
|
|
27
|
-
}),
|
|
28
|
-
|
|
29
|
-
typescript({ compilerOptions: { outDir: './exports/browser' } })
|
|
30
|
-
],
|
|
31
|
-
external: ['./prompts/password.js']
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
input: ['./src/peernet.ts', './node_modules/@leofcoin/storage/exports/store.js'],
|
|
35
|
-
output: {
|
|
36
|
-
format: 'es',
|
|
37
|
-
dir: './exports'
|
|
38
|
-
},
|
|
39
|
-
plugins: [
|
|
40
|
-
typescript({
|
|
41
|
-
compilerOptions: {
|
|
42
|
-
outDir: './exports',
|
|
43
|
-
declarationDir: './exports/types'
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
],
|
|
47
|
-
external: ['./prompts/password.js']
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
input: ['./src/prompts/password/browser.js'],
|
|
51
|
-
output: {
|
|
52
|
-
format: 'es',
|
|
53
|
-
file: './exports/browser/src/prompts/password.js'
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
input: ['./src/prompts/password/node.js'],
|
|
58
|
-
output: {
|
|
59
|
-
format: 'es',
|
|
60
|
-
file: './exports/src/prompts/password.js'
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
]
|
|
1
|
+
import resolve from '@rollup/plugin-node-resolve'
|
|
2
|
+
import commonjs from '@rollup/plugin-commonjs'
|
|
3
|
+
import json from '@rollup/plugin-json'
|
|
4
|
+
import wasm from '@rollup/plugin-wasm'
|
|
5
|
+
import rimraf from 'rimraf'
|
|
6
|
+
import typescript from '@rollup/plugin-typescript'
|
|
7
|
+
|
|
8
|
+
rimraf.sync('./exports/**')
|
|
9
|
+
|
|
10
|
+
export default [
|
|
11
|
+
{
|
|
12
|
+
input: ['./src/peernet.ts', './src/identity.ts', './node_modules/@leofcoin/storage/exports/browser-store.js'],
|
|
13
|
+
output: {
|
|
14
|
+
format: 'es',
|
|
15
|
+
dir: './exports/browser'
|
|
16
|
+
},
|
|
17
|
+
plugins: [
|
|
18
|
+
json(),
|
|
19
|
+
wasm(),
|
|
20
|
+
resolve({
|
|
21
|
+
browser: true,
|
|
22
|
+
preferBuiltins: false,
|
|
23
|
+
mainFields: ['browser', 'module', 'main']
|
|
24
|
+
}),
|
|
25
|
+
commonjs({
|
|
26
|
+
mainFields: ['browser', 'module', 'main']
|
|
27
|
+
}),
|
|
28
|
+
|
|
29
|
+
typescript({ compilerOptions: { outDir: './exports/browser' } })
|
|
30
|
+
],
|
|
31
|
+
external: ['./prompts/password.js']
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
input: ['./src/peernet.ts', './src/identity.ts', './node_modules/@leofcoin/storage/exports/store.js'],
|
|
35
|
+
output: {
|
|
36
|
+
format: 'es',
|
|
37
|
+
dir: './exports'
|
|
38
|
+
},
|
|
39
|
+
plugins: [
|
|
40
|
+
typescript({
|
|
41
|
+
compilerOptions: {
|
|
42
|
+
outDir: './exports',
|
|
43
|
+
declarationDir: './exports/types'
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
],
|
|
47
|
+
external: ['./prompts/password.js']
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
input: ['./src/prompts/password/browser.js'],
|
|
51
|
+
output: {
|
|
52
|
+
format: 'es',
|
|
53
|
+
file: './exports/browser/src/prompts/password.js'
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
input: ['./src/prompts/password/node.js'],
|
|
58
|
+
output: {
|
|
59
|
+
format: 'es',
|
|
60
|
+
file: './exports/src/prompts/password.js'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]
|
package/src/dht/dht.ts
CHANGED
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
export declare type DHTProvider = {
|
|
2
|
-
address: string
|
|
3
|
-
id: string
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export declare type DHTProviderDistanceResult = {
|
|
7
|
-
provider: DHTProvider
|
|
8
|
-
/**
|
|
9
|
-
* distance on earth between peers in km
|
|
10
|
-
*/
|
|
11
|
-
distance: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export declare type DHTProviderMapValue = { [index: string]: DHTProvider }
|
|
15
|
-
|
|
16
|
-
declare type Coordinates = {
|
|
17
|
-
longitude: number
|
|
18
|
-
latitude: number
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Keep history of fetched address and ptr
|
|
23
|
-
* @property {Object} address
|
|
24
|
-
* @property {Object} ptr
|
|
25
|
-
*/
|
|
26
|
-
const lastFetched = {
|
|
27
|
-
address: {
|
|
28
|
-
value: undefined,
|
|
29
|
-
timestamp: 0
|
|
30
|
-
},
|
|
31
|
-
ptr: {
|
|
32
|
-
value: undefined,
|
|
33
|
-
timestamp: 0
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const fetchedCoordinates = {}
|
|
38
|
-
|
|
39
|
-
const getAddress = async () => {
|
|
40
|
-
const { address } = lastFetched
|
|
41
|
-
if (address) {
|
|
42
|
-
address.value = await fetch('https://icanhazip.com/')
|
|
43
|
-
address.value = await address.value.text()
|
|
44
|
-
address.timestamp = Math.round(new Date().getTime() / 1000)
|
|
45
|
-
lastFetched.address = address
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return address.value
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const degreesToRadians = (degrees) => {
|
|
52
|
-
return (degrees * Math.PI) / 180
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
|
|
56
|
-
const earthRadiusKm = 6371
|
|
57
|
-
|
|
58
|
-
const dLat = degreesToRadians(lat2 - lat1)
|
|
59
|
-
const dLon = degreesToRadians(lon2 - lon1)
|
|
60
|
-
|
|
61
|
-
lat1 = degreesToRadians(lat1)
|
|
62
|
-
lat2 = degreesToRadians(lat2)
|
|
63
|
-
const a =
|
|
64
|
-
Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2)
|
|
65
|
-
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
|
66
|
-
return earthRadiusKm * c
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export default class DhtEarth {
|
|
70
|
-
providerMap = new Map<string, DHTProviderMapValue>()
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
*
|
|
74
|
-
*/
|
|
75
|
-
constructor() {
|
|
76
|
-
this.providerMap = new Map()
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async getCoordinates(address: string): Promise<Coordinates> {
|
|
80
|
-
if (!fetchedCoordinates[address]) {
|
|
81
|
-
const request = `https://whereis.leofcoin.org/?ip=${address}`
|
|
82
|
-
let response = await fetch(request)
|
|
83
|
-
const { lat, lon } = (await response.json()) as { lat: number; lon: number }
|
|
84
|
-
fetchedCoordinates[address] = { latitude: lat, longitude: lon }
|
|
85
|
-
}
|
|
86
|
-
return fetchedCoordinates[address]
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @param {Object} peer
|
|
91
|
-
* @param {Object} provider
|
|
92
|
-
* @return {Object} {provider, distance}
|
|
93
|
-
*/
|
|
94
|
-
async getDistance(
|
|
95
|
-
peer: { latitude: number; longitude: number },
|
|
96
|
-
provider: DHTProvider
|
|
97
|
-
): Promise<DHTProviderDistanceResult> {
|
|
98
|
-
const { latitude, longitude } = await this.getCoordinates(provider.address)
|
|
99
|
-
return {
|
|
100
|
-
provider,
|
|
101
|
-
distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async closestPeer(providers: Array<any>): Promise<DHTProvider> {
|
|
106
|
-
let all = []
|
|
107
|
-
const address = await getAddress()
|
|
108
|
-
const peerLoc = await this.getCoordinates(address)
|
|
109
|
-
|
|
110
|
-
for (const provider of providers) {
|
|
111
|
-
if (provider.address === '127.0.0.1' || provider.address === '::1') all.push({ provider, distance: 0 })
|
|
112
|
-
else all.push(this.getDistance(peerLoc, provider))
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// todo queue
|
|
116
|
-
all = await Promise.all(all)
|
|
117
|
-
all = all.sort((previous, current) => previous.distance - current.distance)
|
|
118
|
-
return all[0].provider
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
hasProvider(hash: string): boolean {
|
|
122
|
-
return this.providerMap.has(hash)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
providersFor(hash: string): DHTProviderMapValue {
|
|
126
|
-
let providers: DHTProviderMapValue
|
|
127
|
-
if (this.providerMap.has(hash)) providers = this.providerMap.get(hash)
|
|
128
|
-
return providers
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
addProvider(provider: DHTProvider, hash: string) {
|
|
132
|
-
let providers: DHTProviderMapValue = {}
|
|
133
|
-
if (this.providerMap.has(hash)) {
|
|
134
|
-
providers = this.providerMap.get(hash)
|
|
135
|
-
}
|
|
136
|
-
providers[provider.address] = provider
|
|
137
|
-
this.providerMap.set(hash, providers)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
removeProvider(address: string, hash: string) {
|
|
141
|
-
if (this.providerMap.has(hash)) {
|
|
142
|
-
const providers = this.providerMap.get(hash)
|
|
143
|
-
delete providers[address]
|
|
144
|
-
this.providerMap.set(hash, providers)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
1
|
+
export declare type DHTProvider = {
|
|
2
|
+
address: string
|
|
3
|
+
id: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export declare type DHTProviderDistanceResult = {
|
|
7
|
+
provider: DHTProvider
|
|
8
|
+
/**
|
|
9
|
+
* distance on earth between peers in km
|
|
10
|
+
*/
|
|
11
|
+
distance: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export declare type DHTProviderMapValue = { [index: string]: DHTProvider }
|
|
15
|
+
|
|
16
|
+
declare type Coordinates = {
|
|
17
|
+
longitude: number
|
|
18
|
+
latitude: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Keep history of fetched address and ptr
|
|
23
|
+
* @property {Object} address
|
|
24
|
+
* @property {Object} ptr
|
|
25
|
+
*/
|
|
26
|
+
const lastFetched = {
|
|
27
|
+
address: {
|
|
28
|
+
value: undefined,
|
|
29
|
+
timestamp: 0
|
|
30
|
+
},
|
|
31
|
+
ptr: {
|
|
32
|
+
value: undefined,
|
|
33
|
+
timestamp: 0
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const fetchedCoordinates = {}
|
|
38
|
+
|
|
39
|
+
const getAddress = async () => {
|
|
40
|
+
const { address } = lastFetched
|
|
41
|
+
if (address) {
|
|
42
|
+
address.value = await fetch('https://icanhazip.com/')
|
|
43
|
+
address.value = await address.value.text()
|
|
44
|
+
address.timestamp = Math.round(new Date().getTime() / 1000)
|
|
45
|
+
lastFetched.address = address
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return address.value
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const degreesToRadians = (degrees) => {
|
|
52
|
+
return (degrees * Math.PI) / 180
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
|
|
56
|
+
const earthRadiusKm = 6371
|
|
57
|
+
|
|
58
|
+
const dLat = degreesToRadians(lat2 - lat1)
|
|
59
|
+
const dLon = degreesToRadians(lon2 - lon1)
|
|
60
|
+
|
|
61
|
+
lat1 = degreesToRadians(lat1)
|
|
62
|
+
lat2 = degreesToRadians(lat2)
|
|
63
|
+
const a =
|
|
64
|
+
Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2)
|
|
65
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
|
66
|
+
return earthRadiusKm * c
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default class DhtEarth {
|
|
70
|
+
providerMap = new Map<string, DHTProviderMapValue>()
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
*/
|
|
75
|
+
constructor() {
|
|
76
|
+
this.providerMap = new Map()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getCoordinates(address: string): Promise<Coordinates> {
|
|
80
|
+
if (!fetchedCoordinates[address]) {
|
|
81
|
+
const request = `https://whereis.leofcoin.org/?ip=${address}`
|
|
82
|
+
let response = await fetch(request)
|
|
83
|
+
const { lat, lon } = (await response.json()) as { lat: number; lon: number }
|
|
84
|
+
fetchedCoordinates[address] = { latitude: lat, longitude: lon }
|
|
85
|
+
}
|
|
86
|
+
return fetchedCoordinates[address]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {Object} peer
|
|
91
|
+
* @param {Object} provider
|
|
92
|
+
* @return {Object} {provider, distance}
|
|
93
|
+
*/
|
|
94
|
+
async getDistance(
|
|
95
|
+
peer: { latitude: number; longitude: number },
|
|
96
|
+
provider: DHTProvider
|
|
97
|
+
): Promise<DHTProviderDistanceResult> {
|
|
98
|
+
const { latitude, longitude } = await this.getCoordinates(provider.address)
|
|
99
|
+
return {
|
|
100
|
+
provider,
|
|
101
|
+
distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async closestPeer(providers: Array<any>): Promise<DHTProvider> {
|
|
106
|
+
let all = []
|
|
107
|
+
const address = await getAddress()
|
|
108
|
+
const peerLoc = await this.getCoordinates(address)
|
|
109
|
+
|
|
110
|
+
for (const provider of providers) {
|
|
111
|
+
if (provider.address === '127.0.0.1' || provider.address === '::1') all.push({ provider, distance: 0 })
|
|
112
|
+
else all.push(this.getDistance(peerLoc, provider))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// todo queue
|
|
116
|
+
all = await Promise.all(all)
|
|
117
|
+
all = all.sort((previous, current) => previous.distance - current.distance)
|
|
118
|
+
return all[0].provider
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
hasProvider(hash: string): boolean {
|
|
122
|
+
return this.providerMap.has(hash)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
providersFor(hash: string): DHTProviderMapValue {
|
|
126
|
+
let providers: DHTProviderMapValue
|
|
127
|
+
if (this.providerMap.has(hash)) providers = this.providerMap.get(hash)
|
|
128
|
+
return providers
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
addProvider(provider: DHTProvider, hash: string) {
|
|
132
|
+
let providers: DHTProviderMapValue = {}
|
|
133
|
+
if (this.providerMap.has(hash)) {
|
|
134
|
+
providers = this.providerMap.get(hash)
|
|
135
|
+
}
|
|
136
|
+
providers[provider.address] = provider
|
|
137
|
+
this.providerMap.set(hash, providers)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
removeProvider(address: string, hash: string) {
|
|
141
|
+
if (this.providerMap.has(hash)) {
|
|
142
|
+
const providers = this.providerMap.get(hash)
|
|
143
|
+
delete providers[address]
|
|
144
|
+
this.providerMap.set(hash, providers)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|