Merge pull request #500 from tyleryasaka/determine-address

Determine address
This commit is contained in:
Mark Robert Henderson 2018-12-07 06:06:04 -05:00 committed by GitHub
commit 9d674766a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 3524 additions and 3003 deletions

16
API.md
View File

@ -10,6 +10,7 @@ Read the **[GETTING STARTED](https://github.com/orbitdb/orbit-db/blob/master/GUI
* [constructor(ipfs, [directory], [options])](#constructoripfs-directory-options)
- [Public Instance Methods](#public-instance-methods)
* [orbitdb.create(name, type, [options])](#orbitdbcreatename-type-options)
* [orbitdb.determineAddress(name, type, [options])](#orbitdbdetermineaddressname-type-options)
* [orbitdb.open(address, [options])](#orbitdbopenaddress-options)
* [orbitdb.disconnect()](#orbitdbdisconnect)
* [orbitdb.stop()](#orbitdbstop)
@ -106,6 +107,21 @@ const db = await orbitdb.create('user.posts', 'eventlog', {
})
// db created & opened
```
### orbitdb.determineAddress(name, type, [options])
> Returns the orbit-db address for given parameters
Returns a `Promise` that resolves to an orbit-db address. The parameters correspond exactly with the parameters of [orbit-db.create](#orbitdbcreatename-type-options). This is useful for determining a database address ahead of time, or deriving another peer's address from their public key and the database name and type. *No database is actually created.*
```javascript
const dbAddress = await orbitdb.determineAddress('user.posts', 'eventlog', {
write: [
// This could be someone else's public key
'042c07044e7ea51a489c02854db5e09f0191690dc59db0afd95328c9db614a2976e088cab7c86d7e48183191258fc59dc699653508ce25bf0369d67f33d5d77839'
]
})
```
### orbitdb.open(address, [options])
> Opens an OrbitDB database.

6381
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
"main": "src/OrbitDB.js",
"dependencies": {
"ipfs-pubsub-1on1": "~0.0.4",
"ipld-dag-pb": "0.14.11",
"localstorage-down": "^0.6.7",
"logplease": "^1.2.14",
"multihashes": "^0.4.12",

View File

@ -204,26 +204,10 @@ class OrbitDB {
delete this.stores[address]
}
/* Create and Open databases */
/*
options = {
admin: [], // array of keys that are the admins of this database (same as write access)
write: [], // array of keys that can write to this database
directory: './orbitdb', // directory in which to place the database files
overwrite: false, // whether we should overwrite the existing database if it exists
}
*/
async create (name, type, options = {}) {
logger.debug(`create()`)
async _determineAddress(name, type, options = {}, onlyHash) {
if (!OrbitDB.isValidType(type))
throw new Error(`Invalid database type '${type}'`)
// The directory to look databases from can be passed in as an option
const directory = options.directory || this.directory
logger.debug(`Creating database '${name}' as ${type} in '${directory}'`)
if (OrbitDBAddress.isValid(name))
throw new Error(`Given database name is an address. Please give only the name of the database!`)
@ -245,13 +229,34 @@ class OrbitDB {
accessController.add('write', this.key.getPublic('hex'))
}
// Save the Access Controller in IPFS
const accessControllerAddress = await accessController.save()
const accessControllerAddress = await accessController.save(onlyHash)
// Save the manifest to IPFS
const manifestHash = await createDBManifest(this._ipfs, name, type, accessControllerAddress)
const manifestHash = await createDBManifest(this._ipfs, name, type, accessControllerAddress, onlyHash)
// Create the database address
const dbAddress = OrbitDBAddress.parse(path.join('/orbitdb', manifestHash, name))
return OrbitDBAddress.parse(path.join('/orbitdb', manifestHash, name))
}
/* Create and Open databases */
/*
options = {
admin: [], // array of keys that are the admins of this database (same as write access)
write: [], // array of keys that can write to this database
directory: './orbitdb', // directory in which to place the database files
overwrite: false, // whether we should overwrite the existing database if it exists
}
*/
async create (name, type, options = {}) {
logger.debug(`create()`)
// The directory to look databases from can be passed in as an option
const directory = options.directory || this.directory
logger.debug(`Creating database '${name}' as ${type} in '${directory}'`)
// Create the database address
const dbAddress = await this._determineAddress(name, type, options)
// Load the locally saved database information
const cache = await this._loadCache(directory, dbAddress)
@ -271,6 +276,10 @@ class OrbitDB {
return this.open(dbAddress, options)
}
async determineAddress(name, type, options = {}) {
return this._determineAddress(name, type, options, true)
}
/*
options = {
localOnly: false // if set to true, throws an error if database can't be found locally
@ -368,7 +377,7 @@ class OrbitDB {
if (!cache) {
return false
}
const data = await cache.get(path.join(dbAddress.toString(), '_manifest'))
const data = await cache.get(path.join(dbAddress.toString(), '_manifest'))
return data !== undefined && data !== null
}

View File

@ -1,13 +1,27 @@
const path = require('path')
const { DAGNode } = require('ipld-dag-pb')
// Creates a DB manifest file and saves it in IPFS
const createDBManifest = async (ipfs, name, type, accessControllerAddress) => {
const createDBManifest = async (ipfs, name, type, accessControllerAddress, onlyHash) => {
const manifest = {
name: name,
type: type,
accessController: path.join('/ipfs', accessControllerAddress),
}
const dag = await ipfs.object.put(Buffer.from(JSON.stringify(manifest)))
let dag
const manifestJSON = JSON.stringify(manifest)
if (onlyHash) {
dag = await new Promise(resolve => {
DAGNode.create(Buffer.from(manifestJSON), (err, n) => {
if (err) {
throw err
}
resolve(n)
})
})
} else {
dag = await ipfs.object.put(Buffer.from(manifestJSON))
}
return dag.toJSON().multihash.toString()
}

View File

@ -1,6 +1,8 @@
'use strict'
const AccessController = require('./access-controller')
const { DAGNode } = require('ipld-dag-pb')
class IPFSAccessController extends AccessController {
constructor (ipfs) {
@ -23,11 +25,23 @@ class IPFSAccessController extends AccessController {
}
}
async save () {
async save (onlyHash) {
let hash
try {
const access = JSON.stringify(this._access, null, 2)
const dag = await this._ipfs.object.put(new Buffer(access))
let dag
if (onlyHash) {
dag = await new Promise(resolve => {
DAGNode.create(Buffer.from(access), (err, n) => {
if (err) {
throw err
}
resolve(n)
})
})
} else {
dag = await this._ipfs.object.put(new Buffer(access))
}
hash = dag.toJSON().multihash.toString()
} catch (e) {
console.log("ACCESS ERROR:", e)

View File

@ -186,6 +186,48 @@ Object.keys(testAPIs).forEach(API => {
})
})
describe('determineAddress', function() {
describe('Errors', function() {
it('throws an error if given an invalid database type', async () => {
let err
try {
await orbitdb.determineAddress('first', 'invalid-type')
} catch (e) {
err = e.toString()
}
assert.equal(err, 'Error: Invalid database type \'invalid-type\'')
})
it('throws an error if given an address instead of name', async () => {
let err
try {
await orbitdb.determineAddress('/orbitdb/Qmc9PMho3LwTXSaUXJ8WjeBZyXesAwUofdkGeadFXsqMzW/first', 'feed')
} catch (e) {
err = e.toString()
}
assert.equal(err, 'Error: Given database name is an address. Please give only the name of the database!')
})
})
describe('Success', function() {
before(async () => {
address = await orbitdb.determineAddress('third', 'feed', { replicate: false })
localDataPath = path.join(dbPath, address.root, address.path)
})
it('does not save the address locally', async () => {
assert.equal(fs.existsSync(localDataPath), false)
})
it('returns the address that would have been created', async () => {
db = await orbitdb.create('third', 'feed', { replicate: false })
assert.equal(address.toString().indexOf('/orbitdb'), 0)
assert.equal(address.toString().indexOf('Qm'), 9)
assert.equal(address.toString(), db.address.toString())
})
})
})
describe('Open', function() {
before(async () => {
db = await orbitdb.open('abc', { create: true, type: 'feed' })