Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 6b097d8

Browse files
committed
fix: make it experimental
1 parent 6e8d9c5 commit 6b097d8

File tree

12 files changed

+317
-281
lines changed

12 files changed

+317
-281
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@
148148
"multihashes": "~0.4.14",
149149
"multihashing-async": "~0.6.0",
150150
"node-fetch": "^2.3.0",
151+
"p-any": "^2.1.0",
152+
"p-settle": "^3.1.0",
151153
"peer-book": "~0.9.0",
152154
"peer-id": "~0.12.0",
153155
"peer-info": "~0.15.0",

src/cli/commands/daemon.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ module.exports = {
2020
type: 'boolean',
2121
default: false
2222
})
23+
.option('enable-ipns-experiment', {
24+
type: 'boolean',
25+
default: false,
26+
desc: 'EXPERIMENTAL ipns routers.'
27+
})
28+
.option('experimental-ipns-alias', {
29+
type: 'string',
30+
default: '',
31+
desc: 'EXPERIMENTAL human readable alias for ipns subdomains.'
32+
})
2333
.option('offline', {
2434
type: 'boolean',
2535
desc: 'Run offline. Do not connect to the rest of the network but provide local API.',
@@ -54,9 +64,13 @@ module.exports = {
5464
preload: { enabled: argv.enablePreload },
5565
EXPERIMENTAL: {
5666
pubsub: argv.enablePubsubExperiment,
67+
ipnsDNS: argv.enableIpnsExperiment,
5768
ipnsPubsub: argv.enableNamesysPubsub,
5869
dht: argv.enableDhtExperiment,
5970
sharding: argv.enableShardingExperiment
71+
},
72+
ipns: {
73+
alias: argv.experimentalIpnsAlias
6074
}
6175
})
6276

src/core/config.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ const configSchema = s({
4646
EXPERIMENTAL: optional(s({
4747
pubsub: 'boolean?',
4848
ipnsPubsub: 'boolean?',
49+
ipnsDNS: 'boolean?',
4950
sharding: 'boolean?',
5051
dht: 'boolean?'
51-
}, { dht: false, pubsub: false, ipnsPubsub: false, sharding: false })),
52+
}, { dht: false, pubsub: false, ipnsDNS: false, ipnsPubsub: false, sharding: false })),
5253
connectionManager: 'object?',
5354
config: optional(s({
5455
API: 'object?',
@@ -69,9 +70,11 @@ const configSchema = s({
6970
Bootstrap: optional(s(['multiaddr-ipfs']))
7071
})),
7172
ipld: 'object?',
73+
ipns: 'object?',
7274
libp2p: optional(union(['function', 'object'])) // libp2p validates this
7375
}, {
74-
repoOwner: true
76+
repoOwner: true,
77+
ipns: {}
7578
})
7679

7780
const validate = (opts) => {

src/core/ipns/routing/config.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
const { TieredDatastore } = require('datastore-core')
44
const PubsubDatastore = require('./pubsub-datastore')
55
const OfflineDatastore = require('./offline-datastore')
6-
const DnsDatastore = require('./dns-datastore')
7-
const MDnsDatastore = require('./mdns-datastore')
8-
const WorkersDatastore = require('./workers-datastore')
6+
const DnsDatastore = require('./experimental/dns-datastore')
7+
const MDnsDatastore = require('./experimental/mdns-datastore')
8+
const WorkersDatastore = require('./experimental/workers-datastore')
9+
const ExperimentalTieredDatastore = require('./experimental/tiered-datastore')
910
/**
1011
* @typedef { import("../../index") } IPFS
1112
*/
@@ -19,6 +20,12 @@ const WorkersDatastore = require('./workers-datastore')
1920
module.exports = (ipfs) => {
2021
// Setup online routing for IPNS with a tiered routing composed by a DHT and a Pubsub router (if properly enabled)
2122
const ipnsStores = []
23+
if (ipfs._options.EXPERIMENTAL.ipnsDNS) {
24+
ipnsStores.push(new WorkersDatastore(ipfs._options.ipns))
25+
ipnsStores.push(new DnsDatastore(ipfs._options.ipns))
26+
ipnsStores.push(new MDnsDatastore(ipfs._options.ipns))
27+
return new ExperimentalTieredDatastore(ipnsStores)
28+
}
2229

2330
// // Add IPNS pubsub if enabled
2431
if (ipfs._options.EXPERIMENTAL.ipnsPubsub) {
@@ -32,10 +39,6 @@ module.exports = (ipfs) => {
3239
ipnsStores.push(new OfflineDatastore(ipfs._repo))
3340
}
3441

35-
ipnsStores.push(new MDnsDatastore())
36-
ipnsStores.push(new DnsDatastore())
37-
ipnsStores.push(new WorkersDatastore())
38-
3942
// Create ipns routing with a set of datastores
4043
return new TieredDatastore(ipnsStores)
4144
}

src/core/ipns/routing/dns-datastore.js

Lines changed: 0 additions & 80 deletions
This file was deleted.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* eslint-disable no-console */
2+
'use strict'
3+
4+
const ky = require('ky-universal').default
5+
const errcode = require('err-code')
6+
const debug = require('debug')
7+
const { dohBinary, keyToBase32 } = require('./utils')
8+
9+
const log = debug('ipfs:ipns:dns-datastore')
10+
log.error = debug('ipfs:ipns:dns-datastore:error')
11+
12+
class DNSDataStore {
13+
constructor (options) {
14+
this.options = options
15+
}
16+
17+
/**
18+
* Put a key value pair into the datastore
19+
* @param {Buffer} key identifier of the value.
20+
* @param {Buffer} value value to be stored.
21+
* @returns {Promise}
22+
*/
23+
async put (key, value) {
24+
const start = Date.now()
25+
if (key.toString().startsWith('/pk/')) {
26+
return
27+
}
28+
if (!Buffer.isBuffer(key)) {
29+
throw errcode(new Error('DNS datastore key must be a buffer'), 'ERR_INVALID_KEY')
30+
}
31+
if (!Buffer.isBuffer(value)) {
32+
throw errcode(new Error(`DNS datastore value must be a buffer`), 'ERR_INVALID_VALUE')
33+
}
34+
35+
const keyStr = keyToBase32(key)
36+
const data = await ky
37+
.put(
38+
'https://ipns.dev',
39+
{
40+
json: {
41+
key: keyStr,
42+
record: value.toString('base64'),
43+
subdomain: true,
44+
alias: this.options.alias
45+
}
46+
}
47+
)
48+
.json()
49+
50+
console.log(`
51+
DNS Store
52+
Domain: ipns.dev
53+
Key: ${keyStr}
54+
Subdomain: ${data.subdomain}
55+
Alias: ${data.alias}
56+
Time: ${(Date.now() - start)}ms
57+
`)
58+
}
59+
60+
/**
61+
* Get a value from the local datastore indexed by the received key properly encoded.
62+
* @param {Buffer} key identifier of the value to be obtained.
63+
* @returns {Promise}
64+
*/
65+
get (key) {
66+
if (!Buffer.isBuffer(key)) {
67+
throw errcode(new Error(`DNS datastore key must be a buffer`), 'ERR_INVALID_KEY')
68+
}
69+
// https://dns.google.com/experimental
70+
// https://cloudflare-dns.com/dns-query
71+
// https://mozilla.cloudflare-dns.com/dns-query
72+
return dohBinary('https://cloudflare-dns.com/dns-query', 'dns.ipns.dev', key)
73+
}
74+
}
75+
76+
module.exports = DNSDataStore

src/core/ipns/routing/mdns-datastore.js renamed to src/core/ipns/routing/experimental/mdns-datastore.js

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable no-console */
12
'use strict'
23

34
const ky = require('ky-universal').default
@@ -11,61 +12,55 @@ log.error = debug('ipfs:ipns:mdns-datastore:error')
1112
// DNS datastore aims to mimic the same encoding as routing when storing records
1213
// to the local datastore
1314
class MDNSDataStore {
15+
constructor (options) {
16+
this.options = options
17+
}
1418
/**
15-
* Put a value to the local datastore indexed by the received key properly encoded.
19+
* Put a key value pair into the datastore
1620
* @param {Buffer} key identifier of the value.
1721
* @param {Buffer} value value to be stored.
18-
* @param {function(Error)} callback
19-
* @returns {void}
22+
* @returns {Promise}
2023
*/
21-
put (key, value, callback) {
24+
async put (key, value) {
25+
const start = Date.now()
2226
if (key.toString().startsWith('/pk/')) {
23-
return callback()
27+
return
2428
}
2529
if (!Buffer.isBuffer(key)) {
26-
return callback(errcode(new Error('MDNS datastore key must be a buffer'), 'ERR_INVALID_KEY'))
30+
throw errcode(new Error('MDNS datastore key must be a buffer'), 'ERR_INVALID_KEY')
2731
}
2832
if (!Buffer.isBuffer(value)) {
29-
return callback(errcode(new Error(`MDNS datastore value must be a buffer`), 'ERR_INVALID_VALUE'))
33+
throw errcode(new Error(`MDNS datastore value must be a buffer`), 'ERR_INVALID_VALUE')
3034
}
3135

32-
let keyStr
33-
try {
34-
keyStr = keyToBase32(key)
35-
} catch (err) {
36-
log.error(err)
37-
return callback(err)
38-
}
39-
ky.put(
36+
const keyStr = keyToBase32(key)
37+
await ky.put(
4038
'http://ipns.local:8000',
4139
{
4240
json: {
4341
key: keyStr,
4442
record: value.toString('base64')
4543
}
4644
})
47-
.then(data => {
48-
log(`publish key: ${keyStr}`)
49-
setImmediate(() => callback())
50-
})
51-
.catch(err => {
52-
log.error(err)
53-
setImmediate(() => callback(err))
54-
})
45+
console.log(`
46+
Local Store
47+
Domain: ipns.local
48+
Key: ${keyStr}
49+
Time: ${(Date.now() - start)}ms
50+
`)
5551
}
5652

5753
/**
5854
* Get a value from the local datastore indexed by the received key properly encoded.
5955
* @param {Buffer} key identifier of the value to be obtained.
60-
* @param {function(Error, Buffer)} callback
61-
* @returns {void}
56+
* @returns {Promise}
6257
*/
63-
get (key, callback) {
58+
get (key) {
6459
if (!Buffer.isBuffer(key)) {
65-
return callback(errcode(new Error(`MDNS datastore key must be a buffer`), 'ERR_INVALID_KEY'))
60+
throw errcode(new Error(`MDNS datastore key must be a buffer`), 'ERR_INVALID_KEY')
6661
}
6762

68-
dohBinary('http://ipns.local:8000/dns-query', 'ipns.local', key, callback)
63+
return dohBinary('http://ipns.local:8000/dns-query', 'ipns.local', key)
6964
}
7065
}
7166

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict'
2+
3+
const pany = require('p-any')
4+
const pSettle = require('p-settle')
5+
const debug = require('debug')
6+
const Errors = require('interface-datastore').Errors
7+
8+
const log = debug('ipfs:ipns:tiered-datastore')
9+
log.error = debug('ipfs:ipns:tiered-datastore:error')
10+
11+
class TieredDatastore {
12+
constructor (stores) {
13+
this.stores = stores.slice()
14+
}
15+
16+
put (key, value, callback) {
17+
pSettle(this.stores.map(s => s.put(key, value)))
18+
.then(results => {
19+
let fulfilled = false
20+
results.forEach(r => {
21+
if (r.isFulfilled) {
22+
fulfilled = true
23+
} else {
24+
log.error(r.reason)
25+
}
26+
})
27+
28+
if (fulfilled) {
29+
return setImmediate(() => callback())
30+
}
31+
setImmediate(() => callback(Errors.dbWriteFailedError()))
32+
})
33+
}
34+
35+
get (key, callback) {
36+
pany(this.stores.map(s => s.get(key)))
37+
.then(r => setImmediate(() => callback(null, r)))
38+
.catch(err => {
39+
log.error(err)
40+
setImmediate(() => callback(Errors.notFoundError()))
41+
})
42+
}
43+
}
44+
45+
module.exports = TieredDatastore

0 commit comments

Comments
 (0)