Merge branch 'master' of github.com:orbitdb/orbit-db into feat/new-acs
@@ -5,7 +5,7 @@ orbitdb/
|
||||
node_modules/
|
||||
|
||||
# Don't distribute examples with the module
|
||||
# See examples at https://github.com/orbitdb/orbit-db
|
||||
# See examples at https://github.com/orbitdb/orbit-db
|
||||
examples/
|
||||
|
||||
# Don't distribute source maps
|
||||
@@ -15,5 +15,5 @@ dist/*.map
|
||||
dist/orbitdb.js
|
||||
|
||||
# Don't distribute screenshot
|
||||
# See examples at https://github.com/orbitdb/orbit-db
|
||||
screenshots/
|
||||
# See examples at https://github.com/orbitdb/orbit-db
|
||||
images/
|
||||
|
||||
23
API.md
@@ -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)
|
||||
@@ -75,6 +76,8 @@ Creates and returns an instance of OrbitDB. Use the optional `directory` argumen
|
||||
|
||||
- `keystore` (Keystore Instance) : By default creates an instance of [Keystore](https://github.com/orbitdb/orbit-db-keystore). A custom keystore instance can be used, see [this](https://github.com/orbitdb/orbit-db/blob/master/test/utils/custom-test-keystore.js) for an example.
|
||||
|
||||
- 'cache' (Cache Instance) : By default creates an instance of [Cache](https://github.com/orbitdb/orbit-db-cache). A custom cache instance can also be used.
|
||||
|
||||
After creating an `OrbitDB` instance , you can access the different data stores. Creating a database instance, eg. with `orbitdb.keyvalue(...)`, returns a *Promise* that resolves to a [database instance](#store-api). See the [Store](#store-api) section for details of common methods and properties.
|
||||
|
||||
*For further details, see usage for [kvstore](https://github.com/orbitdb/orbit-db-kvstore#usage), [eventlog](https://github.com/orbitdb/orbit-db-eventstore#usage), [feed](https://github.com/orbitdb/orbit-db-feedstore#usage), [docstore](https://github.com/orbitdb/orbit-db-docstore#usage) and [counter](https://github.com/orbitdb/orbit-db-counterstore#usage).*
|
||||
@@ -90,7 +93,7 @@ const db = await orbitdb.keyvalue('profile')
|
||||
|
||||
Returns a `Promise` that resolves to [a database instance](#store-api). `name` (string) should be the database name, not an OrbitDB address (i.e. `user.posts`). `type` is a supported database type (i.e. `eventlog` or [an added custom type](https://github.com/orbitdb/orbit-db#custom-store-types)). `options` is an object with any of the following properties:
|
||||
- `directory` (string): The directory where data will be stored (Default: uses directory option passed to OrbitDB constructor or `./orbitdb` if none was provided).
|
||||
- `write` (array): An array of hex encoded public keys which are used to set write acces to the database. `["*"]` can be passed in to give write access to everyone. See the [GETTING STARTED](https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md) guide for more info. (Default: uses the OrbitDB instance key `orbitdb.key`, which would give write access only to yourself)
|
||||
- `write` (array): An array of hex encoded public keys which are used to set write access to the database. `["*"]` can be passed in to give write access to everyone. See the [GETTING STARTED](https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md) guide for more info. (Default: uses the OrbitDB instance key `orbitdb.key`, which would give write access only to yourself)
|
||||
- `overwrite` (boolean): Overwrite an existing database (Default: `false`)
|
||||
- `replicate` (boolean): Replicate the database with peers, requires IPFS PubSub. (Default: `true`)
|
||||
```javascript
|
||||
@@ -104,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.
|
||||
|
||||
@@ -332,7 +350,6 @@ Returns a `Promise` that resolves to the multihash of the entry as a `String`.
|
||||
Returns an `Array` with a single `Object` if key exists.
|
||||
```javascript
|
||||
const profile = db.get('shamb0t')
|
||||
.map((e) => e.payload.value)
|
||||
// [{ _id: 'shamb0t', name: 'shamb0t', followers: 500 }]
|
||||
```
|
||||
|
||||
@@ -356,7 +373,7 @@ Alias for [`orbitdb.docs()`](#orbitdbdocsnameaddress-options)
|
||||
### orbitdb.counter(name|address)
|
||||
> Creates and opens a counter database
|
||||
|
||||
Returns a `Promise` that resolves to a [`DocumentStore` instance](https://github.com/orbitdb/orbit-db-docstore).
|
||||
Returns a `Promise` that resolves to a [`CounterStore` instance](https://github.com/orbitdb/orbit-db-counterstore).
|
||||
|
||||
```javascript
|
||||
const counter = await orbitdb.counter('song_123.play_count')
|
||||
|
||||
71
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [community@orbitdb.org](mailto:community@orbitdb.org), which goes to all members of the @OrbitDB community team, or to [richardlitt@orbitdb.org](mailto:richardlitt@orbitdb.org), which goes only to [@RichardLitt](https://github.com/RichardLitt) or to [haadcode@orbitdb.org](mailto:haadcode@orbitdb.org), which goes only to [@haadcode](https://github.com/haadcode).
|
||||
|
||||
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
4
CONTRIBUTING.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Contributing
|
||||
|
||||
Check out our organization-wide [Contributing Guide](https://github.com/orbitdb/welcome/blob/master/contributing.md) before contributing to this repository. Thank you.
|
||||
|
||||
224
CONTRIBUTORS.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# Contributors
|
||||
|
||||
Many, many people have contributed to OrbitDB, both as individuals and as part of their organizations. Here is a complete list of people who have committed code, opened PRs, reviewed code, or opened or commented in issues - only in this repository. All of these interactions are part of contributing to this community. Thank you, everyone.
|
||||
|
||||
This list is updated every infrequently, to limit noise. It was [generated](https://github.com/orbitdb/orbit-db/issues/287) programmatically using [name-your-contributors](https://github.com/mntnr/name-your-contributors).
|
||||
|
||||
Note: This list is opt-out. If you'd rather not be here, send an email to [richardlitt@orbitdb.org](mailto:richardlitt@orbitdb.org) and you'll be silently removed and excluded from future lists.
|
||||
|
||||
## Thanks to these people
|
||||
|
||||
- [@0xflotus](https://github.com/0xflotus)
|
||||
- [@509dave16](https://github.com/509dave16)
|
||||
- [@5310](https://github.com/5310)
|
||||
- [@7flash](https://github.com/7flash)
|
||||
- [@abh1manyu](https://github.com/abh1manyu)
|
||||
- [@adamski](https://github.com/adamski)
|
||||
- [@adrprado](https://github.com/adrprado)
|
||||
- [@aeschylus](https://github.com/aeschylus)
|
||||
- [@ajayrao80](https://github.com/ajayrao80)
|
||||
- [@alanshaw](https://github.com/alanshaw)
|
||||
- [@AlessandroChecco](https://github.com/AlessandroChecco)
|
||||
- [@Alex-Werner](https://github.com/Alex-Werner)
|
||||
- [@alexanderattar](https://github.com/alexanderattar)
|
||||
- [@alvinzach](https://github.com/alvinzach)
|
||||
- [@ambertch](https://github.com/ambertch)
|
||||
- [@amoreo](https://github.com/amoreo)
|
||||
- [@aphelionz](https://github.com/aphelionz)
|
||||
- [@ashays](https://github.com/ashays)
|
||||
- [@ashwin-yardi](https://github.com/ashwin-yardi)
|
||||
- [@atfornes](https://github.com/atfornes)
|
||||
- [@baimurzin](https://github.com/baimurzin)
|
||||
- [@Bajix](https://github.com/Bajix)
|
||||
- [@balupton](https://github.com/balupton)
|
||||
- [@barlock](https://github.com/barlock)
|
||||
- [@BartKnucle](https://github.com/BartKnucle)
|
||||
- [@bedeho](https://github.com/bedeho)
|
||||
- [@beingmohit](https://github.com/beingmohit)
|
||||
- [@benrogmans](https://github.com/benrogmans)
|
||||
- [@bmuller](https://github.com/bmuller)
|
||||
- [@brainstorm](https://github.com/brainstorm)
|
||||
- [@bronger](https://github.com/bronger)
|
||||
- [@CaptainQuark](https://github.com/CaptainQuark)
|
||||
- [@carlbror](https://github.com/carlbror)
|
||||
- [@CarlChryniszzswics](https://github.com/CarlChryniszzswics)
|
||||
- [@cblgh](https://github.com/cblgh)
|
||||
- [@cbruguera](https://github.com/cbruguera)
|
||||
- [@ccutch](https://github.com/ccutch)
|
||||
- [@christroutner](https://github.com/christroutner)
|
||||
- [@claus](https://github.com/claus)
|
||||
- [@compsocial](https://github.com/compsocial)
|
||||
- [@coodoo](https://github.com/coodoo)
|
||||
- [@coyotespike](https://github.com/coyotespike)
|
||||
- [@crazybuster](https://github.com/crazybuster)
|
||||
- [@cristiano-belloni](https://github.com/cristiano-belloni)
|
||||
- [@cryptoquick](https://github.com/cryptoquick)
|
||||
- [@cyclopse87](https://github.com/cyclopse87)
|
||||
- [@DaniellMesquita](https://github.com/DaniellMesquita)
|
||||
- [@DanielVF](https://github.com/DanielVF)
|
||||
- [@daviddias](https://github.com/daviddias)
|
||||
- [@davidrichard23](https://github.com/davidrichard23)
|
||||
- [@dexterchan](https://github.com/dexterchan)
|
||||
- [@dibu28](https://github.com/dibu28)
|
||||
- [@dignifiedquire](https://github.com/dignifiedquire)
|
||||
- [@dirkmc](https://github.com/dirkmc)
|
||||
- [@drwasho](https://github.com/drwasho)
|
||||
- [@durac](https://github.com/durac)
|
||||
- [@edsilv](https://github.com/edsilv)
|
||||
- [@elsehow](https://github.com/elsehow)
|
||||
- [@eusthace](https://github.com/eusthace)
|
||||
- [@evalsocket](https://github.com/evalsocket)
|
||||
- [@expressflow](https://github.com/expressflow)
|
||||
- [@fazo96](https://github.com/fazo96)
|
||||
- [@fdietze](https://github.com/fdietze)
|
||||
- [@felixSchl](https://github.com/felixSchl)
|
||||
- [@fiatjaf](https://github.com/fiatjaf)
|
||||
- [@filips123](https://github.com/filips123)
|
||||
- [@fluidnotions](https://github.com/fluidnotions)
|
||||
- [@FrauBienenstich](https://github.com/FrauBienenstich)
|
||||
- [@futpib](https://github.com/futpib)
|
||||
- [@gagarin55](https://github.com/gagarin55)
|
||||
- [@garbados](https://github.com/garbados)
|
||||
- [@glensimister](https://github.com/glensimister)
|
||||
- [@greenkeeperio-bot](https://github.com/greenkeeperio-bot)
|
||||
- [@GriffGreen](https://github.com/GriffGreen)
|
||||
- [@grvhi](https://github.com/grvhi)
|
||||
- [@guoliu](https://github.com/guoliu)
|
||||
- [@gyuri-lajos](https://github.com/gyuri-lajos)
|
||||
- [@haadcode](https://github.com/haadcode)
|
||||
- [@haoliangyu](https://github.com/haoliangyu)
|
||||
- [@Hazae41](https://github.com/Hazae41)
|
||||
- [@HenryNguyen5](https://github.com/HenryNguyen5)
|
||||
- [@hugcoday](https://github.com/hugcoday)
|
||||
- [@hushino](https://github.com/hushino)
|
||||
- [@huyhoangCSUH](https://github.com/huyhoangCSUH)
|
||||
- [@IamCarbonMan](https://github.com/IamCarbonMan)
|
||||
- [@imrehg](https://github.com/imrehg)
|
||||
- [@ionicc](https://github.com/ionicc)
|
||||
- [@its-VSP](https://github.com/its-VSP)
|
||||
- [@jamesgibson14](https://github.com/jamesgibson14)
|
||||
- [@jbenet](https://github.com/jbenet)
|
||||
- [@jchris](https://github.com/jchris)
|
||||
- [@jdebeer](https://github.com/jdebeer)
|
||||
- [@jehunter5811](https://github.com/jehunter5811)
|
||||
- [@jenswachtel](https://github.com/jenswachtel)
|
||||
- [@jobando89](https://github.com/jobando89)
|
||||
- [@jonasbostoen](https://github.com/jonasbostoen)
|
||||
- [@joshfraser](https://github.com/joshfraser)
|
||||
- [@joshmh](https://github.com/joshmh)
|
||||
- [@jphastings](https://github.com/jphastings)
|
||||
- [@JulianaDixon](https://github.com/JulianaDixon)
|
||||
- [@KamuelaFranco](https://github.com/KamuelaFranco)
|
||||
- [@KennethHolmSeelig](https://github.com/KennethHolmSeelig)
|
||||
- [@KevinLiLu](https://github.com/KevinLiLu)
|
||||
- [@kidinamoto01](https://github.com/kidinamoto01)
|
||||
- [@klueq](https://github.com/klueq)
|
||||
- [@Kotevode](https://github.com/Kotevode)
|
||||
- [@kouohhashi](https://github.com/kouohhashi)
|
||||
- [@Kubuxu](https://github.com/Kubuxu)
|
||||
- [@LastExile16](https://github.com/LastExile16)
|
||||
- [@lgierth](https://github.com/lgierth)
|
||||
- [@lgleim](https://github.com/lgleim)
|
||||
- [@lufte](https://github.com/lufte)
|
||||
- [@LuigiCerone](https://github.com/LuigiCerone)
|
||||
- [@lukas2005](https://github.com/lukas2005)
|
||||
- [@maht0rz](https://github.com/maht0rz)
|
||||
- [@marciok](https://github.com/marciok)
|
||||
- [@marcusfelix](https://github.com/marcusfelix)
|
||||
- [@maroodb](https://github.com/maroodb)
|
||||
- [@MartianH](https://github.com/MartianH)
|
||||
- [@MartinArens](https://github.com/MartinArens)
|
||||
- [@martinhbramwell](https://github.com/martinhbramwell)
|
||||
- [@matteodem](https://github.com/matteodem)
|
||||
- [@mattisstenejohansen](https://github.com/mattisstenejohansen)
|
||||
- [@maxkerp](https://github.com/maxkerp)
|
||||
- [@maxvisser](https://github.com/maxvisser)
|
||||
- [@mccoysc](https://github.com/mccoysc)
|
||||
- [@MichaelMure](https://github.com/MichaelMure)
|
||||
- [@MikeFair](https://github.com/MikeFair)
|
||||
- [@millette](https://github.com/millette)
|
||||
- [@MirceaKitsune](https://github.com/MirceaKitsune)
|
||||
- [@mistakia](https://github.com/mistakia)
|
||||
- [@mitar](https://github.com/mitar)
|
||||
- [@mmick66](https://github.com/mmick66)
|
||||
- [@mmsqe](https://github.com/mmsqe)
|
||||
- [@natachadelarosa](https://github.com/natachadelarosa)
|
||||
- [@nbanmp](https://github.com/nbanmp)
|
||||
- [@nezzard](https://github.com/nezzard)
|
||||
- [@nightwolfz](https://github.com/nightwolfz)
|
||||
- [@niksmac](https://github.com/niksmac)
|
||||
- [@nillia](https://github.com/nillia)
|
||||
- [@Nipol](https://github.com/Nipol)
|
||||
- [@nmarley](https://github.com/nmarley)
|
||||
- [@nothingismagick](https://github.com/nothingismagick)
|
||||
- [@oed](https://github.com/oed)
|
||||
- [@olegls2000](https://github.com/olegls2000)
|
||||
- [@onionjake](https://github.com/onionjake)
|
||||
- [@OR13](https://github.com/OR13)
|
||||
- [@osarrouy](https://github.com/osarrouy)
|
||||
- [@oskarpyke](https://github.com/oskarpyke)
|
||||
- [@paulogr](https://github.com/paulogr)
|
||||
- [@picrypto](https://github.com/picrypto)
|
||||
- [@piyushmadan](https://github.com/piyushmadan)
|
||||
- [@prabodhmeshram](https://github.com/prabodhmeshram)
|
||||
- [@pranaygp](https://github.com/pranaygp)
|
||||
- [@ra312](https://github.com/ra312)
|
||||
- [@raptortech-js](https://github.com/raptortech-js)
|
||||
- [@rbaid1221](https://github.com/rbaid1221)
|
||||
- [@ricardojmendez](https://github.com/ricardojmendez)
|
||||
- [@RichardLitt](https://github.com/RichardLitt)
|
||||
- [@richardschneider](https://github.com/richardschneider)
|
||||
- [@rikur](https://github.com/rikur)
|
||||
- [@riteable](https://github.com/riteable)
|
||||
- [@rkyleg](https://github.com/rkyleg)
|
||||
- [@RobertChristopher](https://github.com/RobertChristopher)
|
||||
- [@roderik](https://github.com/roderik)
|
||||
- [@rogerlzp](https://github.com/rogerlzp)
|
||||
- [@rusfearuth](https://github.com/rusfearuth)
|
||||
- [@ryancbarry](https://github.com/ryancbarry)
|
||||
- [@shamb0t](https://github.com/shamb0t)
|
||||
- [@shd101wyy](https://github.com/shd101wyy)
|
||||
- [@shi-yan](https://github.com/shi-yan)
|
||||
- [@shotlom](https://github.com/shotlom)
|
||||
- [@singpolyma](https://github.com/singpolyma)
|
||||
- [@sirfumblestone](https://github.com/sirfumblestone)
|
||||
- [@skyne98](https://github.com/skyne98)
|
||||
- [@spaceywolfi](https://github.com/spaceywolfi)
|
||||
- [@Steake](https://github.com/Steake)
|
||||
- [@Stradivario](https://github.com/Stradivario)
|
||||
- [@strotter](https://github.com/strotter)
|
||||
- [@subhasisbanik](https://github.com/subhasisbanik)
|
||||
- [@sundbry](https://github.com/sundbry)
|
||||
- [@telackey](https://github.com/telackey)
|
||||
- [@theD1360](https://github.com/theD1360)
|
||||
- [@theoturner](https://github.com/theoturner)
|
||||
- [@therebelrobot](https://github.com/therebelrobot)
|
||||
- [@thiagodelgado111](https://github.com/thiagodelgado111)
|
||||
- [@thisconnect](https://github.com/thisconnect)
|
||||
- [@ticruz38](https://github.com/ticruz38)
|
||||
- [@tyleryasaka](https://github.com/tyleryasaka)
|
||||
- [@tyvdh](https://github.com/tyvdh)
|
||||
- [@UnsignedInt8](https://github.com/UnsignedInt8)
|
||||
- [@uriva](https://github.com/uriva)
|
||||
- [@varcario](https://github.com/varcario)
|
||||
- [@vasa-develop](https://github.com/vasa-develop)
|
||||
- [@victorb](https://github.com/victorb)
|
||||
- [@vijayee](https://github.com/vijayee)
|
||||
- [@vishalveerareddy](https://github.com/vishalveerareddy)
|
||||
- [@vongohren](https://github.com/vongohren)
|
||||
- [@vrogojin](https://github.com/vrogojin)
|
||||
- [@vvp](https://github.com/vvp)
|
||||
- [@whyrusleeping](https://github.com/whyrusleeping)
|
||||
- [@wigy-opensource-developer](https://github.com/wigy-opensource-developer)
|
||||
- [@willemneal](https://github.com/willemneal)
|
||||
- [@wthompson40](https://github.com/wthompson40)
|
||||
- [@XCJT](https://github.com/XCJT)
|
||||
- [@Xinjie-canya](https://github.com/Xinjie-canya)
|
||||
- [@yashwanth2804](https://github.com/yashwanth2804)
|
||||
- [@ydennisy](https://github.com/ydennisy)
|
||||
- [@yuppies09](https://github.com/yuppies09)
|
||||
- [@zabirauf](https://github.com/zabirauf)
|
||||
- [@zachferland](https://github.com/zachferland)
|
||||
- [@zaptrem](https://github.com/zaptrem)
|
||||
- [@zbyte64](https://github.com/zbyte64)
|
||||
- [@ZeeCoder](https://github.com/ZeeCoder)
|
||||
54
FAQ.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
OrbitDB, like all code, is in a state of constant development. Doubtless, you're going to have some questions. The purpose of this FAQ is to answer the most common questions regarding how to get OrbitDB up and running, how to address common issues, and how to deal with pitfalls and common errors implementing it.
|
||||
|
||||
This is a living document. If you see an answer that could be improved, please [open an issue](https://github.com/orbitdb/orbit-db/issues/new) or submit a PR directly. If you think than a question is missing, please [open an issue](https://github.com/orbitdb/orbit-db/issues/new). If you think that there is a better way to resolve a question - perhaps by improving the `orbitdb --help` docs or by adding a feature - please [open an issue](https://github.com/orbitdb/orbit-db/issues/new). Sense a theme yet? :)
|
||||
|
||||
This document is seeded by questions from people opening issues in this repository. If enough people ask the same question, we'll add one here and point newcomers to it. Please don't be offended if the maintainers say "read the FAQ" - it's our way of making sure we don't spend all of our time answering the same questions.
|
||||
|
||||
**Questions**
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
- [Database replication is not working. Why?](#database-replication-is-not-working-why)
|
||||
- [Can I recreate the entire database on another machine based on the address?](#can-i-recreate-the-entire-database-on-another-machine-based-on-the-address)
|
||||
- [Is every `put` to OrbitDB immediately sent to the network and persisted?](#is-every-put-to-orbitdb-immediately-sent-to-the-network-and-persisted)
|
||||
- [Does OrbitDB already support pinning when using js-ipfs ?](#does-orbitdb-already-support-pinning-when-using-js-ipfs-)
|
||||
- [Does orbit have a shared feed between peers where multiple peers can append to the same feed?](#does-orbit-have-a-shared-feed-between-peers-where-multiple-peers-can-append-to-the-same-feed)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
---
|
||||
|
||||
### Database replication is not working. Why?
|
||||
|
||||
_The answer to this question is a work in progress. See [orbit-db#505](https://github.com/orbitdb/orbit-db/issues/505)._
|
||||
|
||||
### Can I recreate the entire database on another machine based on the address?
|
||||
|
||||
A database can't be "recreated" without downloading the database from other peers. Knowing an address will allow a user to open the database, which automatically connects to other peers who have the database open, and downloads the database which then "recreates" the database state locally, ie. replicates the database.
|
||||
|
||||
### Is every `put` to OrbitDB immediately sent to the network and persisted?
|
||||
|
||||
When calling `put` or any other update operation on a database, the data is 1) saved locally and persisted to IPFS and 2) send to the network, through IPFS Pubsub, to peers who have the database open (ie. peers).
|
||||
|
||||
Upon calling `put` (or other updates), OrbitDB saves the data locally and returns. That is, the operation and its data is saved to the local node only after which `put` returns and *asynchronously* sends a message to pubsub peers. OrbitDB doesn't have a notion of confirming replication status from other peers (although this can be added on user-level) and considers operation a success upon persisting it locally. OrbitDB doesn't use consensus nor does it wait for the network to confirm operations making it an *eventually consistent* system.
|
||||
|
||||
In short: it can't be assumed that data has been replicated to the network after an update-operation call finishes (eg. `put`, `add`).
|
||||
|
||||
### Does OrbitDB already support pinning when using js-ipfs ?
|
||||
|
||||
Currently [js-ipfs](https://github.com/ipfs/js-ipfs) doesn't have GC, so nothing gets removed meaning everything is pinned by default.
|
||||
|
||||
However, this will change in the future as js-ipfs gets GC and we want to make sure that OrbitDB is actually persisting everything (by default), so some work on pinning needs to happen. If you're using OrbitDB with go-ipfs (through js-ipfs-api), then GC happens and data may not be persisted anymore after a time. This is a known issue and we're planning to implement actual pinning (from IPFS perspective) soon.
|
||||
|
||||
### Does orbit have a shared feed between peers where multiple peers can append to the same feed?
|
||||
|
||||
> "...or, is it done more like scuttlebutt, where each peer has their own feed"
|
||||
|
||||
All databases (feeds) are shared between peers, so nobody "owns them" like users do in ssb (afaik). Multiple peers can append to the same db. @tyleryasaka is right in that each peer has their own copy of the db (the log) and they may have different versions between them but, as @tyleryasaka (correctly) describes, through the syncing/replication process the peers exchange "their knowledge of the db" (heads) with each other, the dbs/logs get merged. This is what the "CRDT" in ipfs-log enables. But from address/authority/ownership perspective, they all share the same feed.
|
||||
|
||||
### How can I contribute to this FAQ?
|
||||
|
||||
See the introduction at the top! Please open any issues and pull requests you can to improve this FAQ.md. It is here for you. If you're confused, ask another question publicly; it's possible that other people are, too. If you don't want to open an issue, feel free to jump onto [the Gitter](https://gitter.im/orbitdb/Lobby) and ask us there, too.
|
||||
8
GUIDE.md
@@ -55,7 +55,7 @@ const OrbitDB = require('orbit-db')
|
||||
// OrbitDB uses Pubsub which is an experimental feature
|
||||
// and need to be turned on manually.
|
||||
// Note that these options need to be passed to IPFS in
|
||||
// all examples in this document even if not specfied so.
|
||||
// all examples in this document even if not specified so.
|
||||
const ipfsOptions = {
|
||||
EXPERIMENTAL: {
|
||||
pubsub: true
|
||||
@@ -202,8 +202,8 @@ ipfs.on('ready', async () => {
|
||||
],
|
||||
}
|
||||
|
||||
const db = await orbitdb.keyvalue('first-database', access)
|
||||
console.log(db.address.toString())
|
||||
const db1 = await orbitdb.keyvalue('first-database', access)
|
||||
console.log(db1.address.toString())
|
||||
// /orbitdb/Qmdgwt7w4uBsw8LXduzCd18zfGXeTmBsiR8edQ1hSfzcJC/first-database
|
||||
|
||||
// Second peer opens the database from the address
|
||||
@@ -358,7 +358,7 @@ ipfs1.on('ready', async () => {
|
||||
|
||||
## Custom Stores
|
||||
|
||||
Use a custom store to implement case specifc functionality that is not supported by the default OrbitDB database stores. Then, you can easily add and use your custom store with OrbitDB:
|
||||
Use a custom store to implement case specific functionality that is not supported by the default OrbitDB database stores. Then, you can easily add and use your custom store with OrbitDB:
|
||||
|
||||
```javascript
|
||||
// define custom store type
|
||||
|
||||
6
Makefile
@@ -20,6 +20,10 @@ build: test
|
||||
clean:
|
||||
rm -rf orbitdb/
|
||||
rm -rf node_modules/
|
||||
rm package-lock.json
|
||||
|
||||
clean-dependencies: clean
|
||||
if [ -a package-lock.json ]; then rm package-lock.json; fi;
|
||||
|
||||
rebuild: | clean-dependencies build
|
||||
|
||||
.PHONY: test build
|
||||
|
||||
50
README.md
@@ -1,15 +1,12 @@
|
||||
# OrbitDB
|
||||
|
||||
[](https://gitter.im/orbitdb/Lobby)
|
||||
[](http://webchat.freenode.net/?channels=%23orbitdb)
|
||||
[](https://circleci.com/gh/orbitdb/orbit-db)
|
||||
[](https://www.npmjs.com/package/orbit-db)
|
||||
[](https://www.npmjs.com/package/orbit-db)
|
||||
[](https://waffle.io/orbitdb/orbit-db)
|
||||
<p align="left">
|
||||
<img src="images/orbit_db_logo_color.jpg" width="256" />
|
||||
</p>
|
||||
|
||||
> A peer-to-peer database for the decentralized web
|
||||
[](https://gitter.im/orbitdb/Lobby) [](https://circleci.com/gh/orbitdb/orbit-db) [](https://www.npmjs.com/package/orbit-db) [](https://www.npmjs.com/package/orbit-db)
|
||||
|
||||
OrbitDB is a serverless, distributed, peer-to-peer database. OrbitDB uses [IPFS](https://ipfs.io) as its data storage and [IPFS Pubsub](https://github.com/ipfs/go-ipfs/blob/master/core/commands/pubsub.go#L23) to automatically sync databases with peers. It's an eventually consistent database that uses [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) for conflict-free database merges making OrbitDB an excellent choice for decentralized apps (dApps), blockchain applications and offline-first web applications.
|
||||
OrbitDB is a **serverless, distributed, peer-to-peer database**. OrbitDB uses [IPFS](https://ipfs.io) as its data storage and [IPFS Pubsub](https://github.com/ipfs/go-ipfs/blob/master/core/commands/pubsub.go#L23) to automatically sync databases with peers. It's an eventually consistent database that uses [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) for conflict-free database merges making OrbitDB an excellent choice for decentralized apps (dApps), blockchain applications and offline-first web applications.
|
||||
|
||||
**Test it live at [Live demo 1](https://ipfs.io/ipfs/QmeESXh9wPib8Xz7hdRzHuYLDuEUgkYTSuujZ2phQfvznQ/), [Live demo 2](https://ipfs.io/ipfs/QmasHFRj6unJ3nSmtPn97tWDaQWEZw3W9Eh3gUgZktuZDZ/), or [P2P TodoMVC app](https://ipfs.io/ipfs/QmTJGHccriUtq3qf3bvAQUcDUHnBbHNJG2x2FYwYUecN43/)**!
|
||||
|
||||
@@ -17,7 +14,7 @@ OrbitDB is a serverless, distributed, peer-to-peer database. OrbitDB uses [IPFS]
|
||||
OrbitDB provides various types of databases for different data models and use cases:
|
||||
|
||||
- **[log](https://github.com/orbitdb/orbit-db/blob/master/API.md#orbitdblognameaddress)**: an immutable (append-only) log with traversable history. Useful for *"latest N"* use cases or as a message queue.
|
||||
- **[feed](https://github.com/orbitdb/orbit-db/blob/master/API.md#orbitdbfeednameaddress)**: a mutable log with traversable history. Entries can be added and removed. Useful for *"shopping cart" type of use cases, or for example as a feed of blog posts or "tweets".
|
||||
- **[feed](https://github.com/orbitdb/orbit-db/blob/master/API.md#orbitdbfeednameaddress)**: a mutable log with traversable history. Entries can be added and removed. Useful for *"shopping cart"* type of use cases, or for example as a feed of blog posts or "tweets".
|
||||
- **[keyvalue](https://github.com/orbitdb/orbit-db/blob/master/API.md#orbitdbkeyvaluenameaddress)**: a key-value database just like your favourite key-value database.
|
||||
- **[docs](https://github.com/orbitdb/orbit-db/blob/master/API.md#orbitdbdocsnameaddress-options)**: a document database to which JSON documents can be stored and indexed by a specified key. Useful for building search indices or version controlling documents and data.
|
||||
- **[counter](https://github.com/orbitdb/orbit-db/blob/master/API.md#orbitdbcounternameaddress)**: Useful for counting events separate from log/feed data.
|
||||
@@ -25,7 +22,17 @@ OrbitDB provides various types of databases for different data models and use ca
|
||||
All databases are [implemented](https://github.com/orbitdb/orbit-db-store) on top of [ipfs-log](https://github.com/orbitdb/ipfs-log), an immutable, operation-based conflict-free replicated data structure (CRDT) for distributed systems. If none of the OrbitDB database types match your needs and/or you need case-specific functionality, you can easily [implement and use a custom database store](https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md#custom-stores) of your own.
|
||||
|
||||
#### Project status & support
|
||||
This is the Javascript implementation and it works both in **Browsers** and **Node.js** with support for Linux and OS X (Windows is not supported yet). The minimum required version of Node.js is now 8.0.0. To use with older versions of Node.js, we provide an ES5-compatible build through the npm package, located in `dist/es5/` when installed through npm.
|
||||
|
||||
Status: **in active development**
|
||||
|
||||
***NOTE!*** *OrbitDB is **alpha-stage** software. It means OrbitDB hasn't been security audited and programming APIs and data formats can still change. We encourage you to [reach out to the maintainers](https://gitter.im/orbitdb/Lobby) if you plan to use OrbitDB in mission critical systems.*
|
||||
|
||||
This is the Javascript implementation and it works both in **Browsers** and **Node.js** with support for Linux and OS X (Windows is not supported yet). The minimum required version of Node.js is now 8.6.0 due to the usage of `...` spread syntax. LTS versions (even numbered versions 8, 10, etc) are preferred.
|
||||
|
||||
To use with older versions of Node.js, we provide an ES5-compatible build through the npm package, located in `dist/es5/` when installed through npm.
|
||||
|
||||
#### Community Calls
|
||||
We also have regular community calls, which we announce in the issues in [the @orbitdb welcome repository](https://github.com/orbitdb/welcome/issues). Join us!
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -61,7 +68,7 @@ Read the **[GETTING STARTED](https://github.com/orbitdb/orbit-db/blob/master/GUI
|
||||
|
||||
For the CLI tool to manage orbit-db database, see **[OrbitDB CLI](https://github.com/orbitdb/orbit-db-cli)**.
|
||||
|
||||
It can be installed from Npm with:
|
||||
It can be installed from npm with:
|
||||
|
||||
```
|
||||
npm install orbit-db-cli -g
|
||||
@@ -74,7 +81,7 @@ If you're using `orbitd-db` to develop **browser** or **Node.js** applications,
|
||||
Install dependencies:
|
||||
|
||||
```
|
||||
npm install orbit-db ipfs
|
||||
npm install orbit-db ipfs@0.33.0
|
||||
```
|
||||
|
||||
```javascript
|
||||
@@ -132,8 +139,9 @@ const OrbitDB = require('orbit-db')
|
||||
|
||||
const ipfs = IpfsApi('localhost', '5001')
|
||||
const orbitdb = new OrbitDB(ipfs)
|
||||
const db = await orbitdb.log('hello')
|
||||
...
|
||||
orbitdb.log('hello').then(db => {
|
||||
// Do something with your db.
|
||||
})
|
||||
```
|
||||
|
||||
## API
|
||||
@@ -178,7 +186,7 @@ npm run examples:browser-linux
|
||||
```
|
||||
|
||||
<p align="left">
|
||||
<img src="https://raw.githubusercontent.com/orbitdb/orbit-db/master/screenshots/example1.png" width="33%">
|
||||
<img src="https://raw.githubusercontent.com/orbitdb/orbit-db/master/images/example1.png" width="33%">
|
||||
</p>
|
||||
|
||||
Check the code in [examples/browser/browser.html](https://github.com/orbitdb/orbit-db/blob/master/examples/browser/browser.html) and try the [live example](https://ipfs.io/ipfs/QmRosp97r8GGUEdj5Wvivrn5nBkuyajhRXFUcWCp5Zubbo/).
|
||||
@@ -189,7 +197,7 @@ Check the code in [examples/browser/browser.html](https://github.com/orbitdb/orb
|
||||
npm run examples:node
|
||||
```
|
||||
|
||||
<img src="https://raw.githubusercontent.com/orbitdb/orbit-db/master/screenshots/orbit-db-demo3.gif" width="66%">
|
||||
<img src="https://raw.githubusercontent.com/orbitdb/orbit-db/master/images/orbit-db-demo3.gif" width="66%">
|
||||
|
||||
**Eventlog**
|
||||
|
||||
@@ -222,6 +230,8 @@ OrbitDB uses the following modules:
|
||||
|
||||
To understand a little bit about the architecture, check out a visualization of the data flow at https://github.com/haadcode/proto2 or a live demo: http://celebdil.benet.ai:8080/ipfs/Qmezm7g8mBpWyuPk6D84CNcfLKJwU6mpXuEN5GJZNkX3XK/.
|
||||
|
||||
Community-maintained Typescript typings are available here: https://github.com/orbitdb/orbit-db-types
|
||||
|
||||
## Development
|
||||
|
||||
### Run Tests
|
||||
@@ -251,11 +261,15 @@ LOG=debug node <file>
|
||||
|
||||
## Contributing
|
||||
|
||||
We would be happy to accept PRs! If you want to work on something, it'd be good to talk beforehand to make sure nobody else is working on it. You can reach us on IRC [#orbitdb](http://webchat.freenode.net/?channels=%23orbitdb) on Freenode, or in the comments of the [issues section](https://github.com/orbitdb/orbit-db/issues).
|
||||
**Take a look at our organization-wide [Contributing Guide](https://github.com/orbitdb/welcome/blob/master/contributing.md).** You'll find most of your questions answered there. Some questions may be answered in the [FAQ](FAQ.md), as well.
|
||||
|
||||
As far as code goes, we would be happy to accept PRs! If you want to work on something, it'd be good to talk beforehand to make sure nobody else is working on it. You can reach us [on Gitter](https://gitter.im/orbitdb/Lobby), or in the [issues section](https://github.com/orbitdb/orbit-db/issues).
|
||||
|
||||
We also have **regular community calls**, which we announce in the issues in [the @orbitdb welcome repository](https://github.com/orbitdb/welcome/issues). Join us!
|
||||
|
||||
If you want to code but don't know where to start, check out the issues labelled ["help wanted"](https://github.com/orbitdb/orbit-db/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+sort%3Areactions-%2B1-desc) or the project's [status board](https://waffle.io/orbitdb/orbit-db).
|
||||
If you want to code but don't know where to start, check out the issues labelled ["help wanted"](https://github.com/orbitdb/orbit-db/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+sort%3Areactions-%2B1-desc).
|
||||
|
||||
Please note that we have a [Code of Conduct](CODE_OF_CONDUCT.md), and that all activity in the [@orbitdb](https://github.com/orbitdb) organization falls under it. Read it when you get the chance, as being part of this community means that you agree to abide by it. Thanks.
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
BIN
images/orbit_db_logo_color.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
images/orbit_db_logo_color.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
6746
package-lock.json
generated
@@ -14,6 +14,8 @@
|
||||
"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",
|
||||
"orbit-db-cache": "~0.2.4",
|
||||
@@ -58,7 +60,7 @@
|
||||
"build:examples": "webpack --config conf/webpack.example.config.js --sort-modules-by size && mkdir -p examples/browser/lib && cp node_modules/ipfs/dist/index.js examples/browser/lib/ipfs.js",
|
||||
"build:dist": "webpack --config conf/webpack.config.js --sort-modules-by size && mkdir -p examples/browser/lib && cp dist/orbitdb.min.js examples/browser/lib/orbitdb.min.js",
|
||||
"build:debug": "webpack --config conf/webpack.debug.config.js --sort-modules-by size && mkdir -p examples/browser/lib && cp dist/orbitdb.js examples/browser/lib/orbitdb.js && cp dist/orbitdb.js.map examples/browser/lib/orbitdb.js.map",
|
||||
"build:docs/toc": "markdown-toc --no-first1 -i README.md && markdown-toc --no-first1 -i API.md && markdown-toc --no-first1 -i GUIDE.md && markdown-toc --no-first1 -i CHANGELOG.md",
|
||||
"build:docs/toc": "markdown-toc --no-first1 -i README.md && markdown-toc --no-first1 -i API.md && markdown-toc --no-first1 -i GUIDE.md && markdown-toc --no-first1 -i CHANGELOG.md && markdown-toc --no-first1 -i FAQ.md ",
|
||||
"build:es5": "babel src --out-dir ./dist/es5/ --presets babel-preset-es2015 --plugins babel-plugin-transform-runtime"
|
||||
}
|
||||
}
|
||||
|
||||
108
src/OrbitDB.js
@@ -9,7 +9,6 @@ const DocumentStore = require('orbit-db-docstore')
|
||||
const Pubsub = require('orbit-db-pubsub')
|
||||
const Cache = require('orbit-db-cache')
|
||||
const Keystore = require('orbit-db-keystore')
|
||||
const IdentityProvider = require('orbit-db-identity-provider')
|
||||
const AccessController = require('./ipfs-access-controller')
|
||||
const OrbitDBAddress = require('./orbit-db-address')
|
||||
const createDBManifest = require('./db-manifest')
|
||||
@@ -38,14 +37,11 @@ class OrbitDB {
|
||||
this.stores = {}
|
||||
this.directory = directory || './orbitdb'
|
||||
this.keystore = options.keystore || Keystore.create(path.join(this.directory, this.id, '/keystore'))
|
||||
this.identity = options.identity
|
||||
this.cache = options.cache || Cache
|
||||
this.key = this.keystore.getKey(this.id) || this.keystore.createKey(this.id)
|
||||
this._directConnections = {}
|
||||
}
|
||||
|
||||
async initialize(options = {}) {
|
||||
this.identity = await IdentityProvider.createIdentity(this.keystore, this.id, options.identitySignerFn)
|
||||
}
|
||||
|
||||
/* Databases */
|
||||
async feed (address, options = {}) {
|
||||
options = Object.assign({ create: true, type: 'feed' }, options)
|
||||
@@ -117,11 +113,8 @@ class OrbitDB {
|
||||
|
||||
/* Private methods */
|
||||
async _createStore (type, address, options) {
|
||||
if (!this.identity)
|
||||
await this.initialize()
|
||||
// Get the type -> class mapping
|
||||
const Store = databaseTypes[type]
|
||||
// this.identity = this.identity || await IdentityProvider.createIdentity(this.keystore, this.id, options.identitySignerFn)
|
||||
|
||||
if (!Store)
|
||||
throw new Error(`Invalid database type '${type}'`)
|
||||
@@ -136,11 +129,12 @@ class OrbitDB {
|
||||
|
||||
const opts = Object.assign({ replicate: true }, options, {
|
||||
accessController: accessController,
|
||||
keystore: this.keystore,
|
||||
cache: cache,
|
||||
onClose: this._onClose.bind(this),
|
||||
})
|
||||
|
||||
const store = new Store(this._ipfs, this.identity, address, opts)
|
||||
const store = new Store(this._ipfs, this.id, address, opts)
|
||||
store.events.on('write', this._onWrite.bind(this))
|
||||
|
||||
// ID of the store is the address as a string
|
||||
@@ -210,29 +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()`)
|
||||
|
||||
if (!this.identity)
|
||||
await this.initialize()
|
||||
|
||||
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!`)
|
||||
|
||||
@@ -251,21 +226,43 @@ class OrbitDB {
|
||||
options.write.forEach(e => accessController.add('write', e))
|
||||
} else {
|
||||
// Default is to add ourselves as the admin of the database
|
||||
accessController.add('write', this.identity.publicKey)
|
||||
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))
|
||||
}
|
||||
|
||||
// // Load local cache
|
||||
const haveDB = await this._loadCache(directory, dbAddress)
|
||||
.then(cache => cache ? cache.get(path.join(dbAddress.toString(), '_manifest')) : null)
|
||||
.then(data => data !== undefined && data !== null)
|
||||
/* 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)
|
||||
|
||||
// Check if we have the database locally
|
||||
const haveDB = await this._haveLocalData(cache, dbAddress)
|
||||
|
||||
if (haveDB && !options.overwrite)
|
||||
throw new Error(`Database '${dbAddress}' already exists!`)
|
||||
@@ -279,10 +276,14 @@ 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
|
||||
create: false // wether to create the database
|
||||
create: false // whether to create the database
|
||||
type: TODO
|
||||
overwrite: TODO
|
||||
|
||||
@@ -290,10 +291,6 @@ class OrbitDB {
|
||||
*/
|
||||
async open (address, options = {}) {
|
||||
logger.debug(`open()`)
|
||||
|
||||
if (!this.identity)
|
||||
await this.initialize()
|
||||
|
||||
options = Object.assign({ localOnly: false, create: false }, options)
|
||||
logger.debug(`Open database '${address}'`)
|
||||
|
||||
@@ -317,11 +314,11 @@ class OrbitDB {
|
||||
// Parse the database address
|
||||
const dbAddress = OrbitDBAddress.parse(address)
|
||||
|
||||
// Check if we have the database
|
||||
const haveDB = await this._loadCache(directory, dbAddress)
|
||||
.then(cache => cache ? cache.get(path.join(dbAddress.toString(), '_manifest')) : null)
|
||||
.then(data => data !== undefined && data !== null)
|
||||
// Load the locally saved db information
|
||||
const cache = await this._loadCache(directory, dbAddress)
|
||||
|
||||
// Check if we have the database
|
||||
const haveDB = await this._haveLocalData(cache, dbAddress)
|
||||
logger.debug((haveDB ? 'Found' : 'Didn\'t find') + ` database '${dbAddress}'`)
|
||||
|
||||
// If we want to try and open the database local-only, throw an error
|
||||
@@ -357,10 +354,11 @@ class OrbitDB {
|
||||
logger.debug(`Saved manifest to IPFS as '${dbAddress.root}'`)
|
||||
}
|
||||
|
||||
// Loads the locally saved database information (manifest, head hashes)
|
||||
async _loadCache (directory, dbAddress) {
|
||||
let cache
|
||||
try {
|
||||
cache = await Cache.load(directory, dbAddress)
|
||||
cache = await this.cache.load(directory, dbAddress)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
logger.error("Couldn't load Cache:", e)
|
||||
@@ -369,6 +367,20 @@ class OrbitDB {
|
||||
return cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have the database, or part of it, saved locally
|
||||
* @param {[Cache]} cache [The OrbitDBCache instance containing the local data]
|
||||
* @param {[OrbitDBAddress]} dbAddress [Address of the database to check]
|
||||
* @return {[Boolean]} [Returns true if we have cached the db locally, false if not]
|
||||
*/
|
||||
async _haveLocalData (cache, dbAddress) {
|
||||
if (!cache) {
|
||||
return false
|
||||
}
|
||||
const data = await cache.get(path.join(dbAddress.toString(), '_manifest'))
|
||||
return data !== undefined && data !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns supported database types as an Array of strings
|
||||
* Eg. [ 'counter', 'eventlog', 'feed', 'docstore', 'keyvalue']
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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' })
|
||||
|
||||
58
test/custom-cache.test.js
Normal file
@@ -0,0 +1,58 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('assert')
|
||||
const rmrf = require('rimraf')
|
||||
const OrbitDB = require('../src/OrbitDB')
|
||||
const CustomCache = require('orbit-db-cache')
|
||||
// Include test utilities
|
||||
const {
|
||||
config,
|
||||
startIpfs,
|
||||
stopIpfs,
|
||||
testAPIs,
|
||||
CustomTestCache,
|
||||
databases,
|
||||
} = require('./utils')
|
||||
|
||||
const dbPath = './orbitdb/tests/customKeystore'
|
||||
const ipfsPath = './orbitdb/tests/customKeystore/ipfs'
|
||||
|
||||
Object.keys(testAPIs).forEach(API => {
|
||||
describe(`orbit-db - Use a Custom Cache (${API})`, function() {
|
||||
this.timeout(20000)
|
||||
|
||||
let ipfsd, ipfs, orbitdb1
|
||||
|
||||
before(async () => {
|
||||
config.daemon1.repo = ipfsPath
|
||||
rmrf.sync(config.daemon1.repo)
|
||||
rmrf.sync(dbPath)
|
||||
ipfsd = await startIpfs(API, config.daemon1)
|
||||
ipfs = ipfsd.api
|
||||
orbitdb1 = new OrbitDB(ipfs, dbPath + '/1', {
|
||||
cache: CustomTestCache
|
||||
})
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
if(orbitdb1)
|
||||
await orbitdb1.stop()
|
||||
|
||||
if (ipfsd)
|
||||
await stopIpfs(ipfsd)
|
||||
})
|
||||
|
||||
describe('allows orbit to use a custom cache with different store types', function() {
|
||||
databases.forEach(async (database) => {
|
||||
it(database.type + ' allows custom keystore', async () => {
|
||||
const db1 = await database.create(orbitdb1, 'custom-keystore')
|
||||
await database.tryInsert(db1)
|
||||
|
||||
assert.deepEqual(database.getTestValue(db1), database.expectedValue)
|
||||
|
||||
await db1.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -10,54 +10,12 @@ const {
|
||||
stopIpfs,
|
||||
testAPIs,
|
||||
CustomTestKeystore,
|
||||
databases,
|
||||
} = require('./utils')
|
||||
|
||||
const dbPath = './orbitdb/tests/customKeystore'
|
||||
const ipfsPath = './orbitdb/tests/customKeystore/ipfs'
|
||||
|
||||
const databases = [
|
||||
{
|
||||
type: 'eventlog',
|
||||
create: (orbitdb, name, options) => orbitdb.eventlog(name, options),
|
||||
tryInsert: (db) => db.add('hello'),
|
||||
query: (db) => db.iterator({ limit: -1 }).collect(),
|
||||
getTestValue: (db) => db.iterator({ limit: -1 }).collect()[0].payload.value,
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'feed',
|
||||
create: (orbitdb, name, options) => orbitdb.feed(name, options),
|
||||
tryInsert: (db) => db.add('hello'),
|
||||
query: (db) => db.iterator({ limit: -1 }).collect(),
|
||||
getTestValue: (db) => db.iterator({ limit: -1 }).collect()[0].payload.value,
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'key-value',
|
||||
create: (orbitdb, name, options) => orbitdb.kvstore(name, options),
|
||||
tryInsert: (db) => db.set('one', 'hello'),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.get('one'),
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'documents',
|
||||
create: (orbitdb, name, options) => orbitdb.docstore(name, options),
|
||||
tryInsert: (db) => db.put({ _id: 'hello world', doc: 'all the things'}),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.get('hello world'),
|
||||
expectedValue: [{ _id: 'hello world', doc: 'all the things'}],
|
||||
},
|
||||
{
|
||||
type: 'counter',
|
||||
create: (orbitdb, name, options) => orbitdb.counter(name, options),
|
||||
tryInsert: (db) => db.inc(8),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.value,
|
||||
expectedValue: 8,
|
||||
},
|
||||
]
|
||||
|
||||
Object.keys(testAPIs).forEach(API => {
|
||||
describe(`orbit-db - Use a Custom Keystore (${API})`, function() {
|
||||
this.timeout(20000)
|
||||
|
||||
@@ -66,7 +66,7 @@ Object.keys(testAPIs).forEach(API => {
|
||||
let localDatabases = []
|
||||
let remoteDatabases = []
|
||||
|
||||
// Create two IPFS instances and two OrbitDB instaces (2 nodes/peers)
|
||||
// Create two IPFS instances and two OrbitDB instances (2 nodes/peers)
|
||||
before(async () => {
|
||||
config.daemon1.repo = ipfsPath1
|
||||
config.daemon2.repo = ipfsPath2
|
||||
|
||||
@@ -11,265 +11,279 @@ const {
|
||||
startIpfs,
|
||||
stopIpfs,
|
||||
testAPIs,
|
||||
CustomTestCache
|
||||
} = require('./utils')
|
||||
|
||||
const dbPath = './orbitdb/tests/persistency'
|
||||
const ipfsPath = './orbitdb/tests/persistency/ipfs'
|
||||
|
||||
const tests = [
|
||||
{
|
||||
title: 'Persistency',
|
||||
orbitDBConfig: {}
|
||||
},
|
||||
{
|
||||
title: 'Persistency with custom cache',
|
||||
orbitDBConfig: { cache: CustomTestCache }
|
||||
}
|
||||
]
|
||||
|
||||
Object.keys(testAPIs).forEach(API => {
|
||||
describe(`orbit-db - Persistency (${API})`, function() {
|
||||
this.timeout(config.timeout)
|
||||
tests.forEach(test => {
|
||||
describe(`orbit-db - ${test.title} (${API})`, function() {
|
||||
this.timeout(config.timeout)
|
||||
|
||||
const entryCount = 65
|
||||
const entryCount = 65
|
||||
|
||||
let ipfsd, ipfs, orbitdb1, db, address
|
||||
let ipfsd, ipfs, orbitdb1, db, address
|
||||
|
||||
before(async () => {
|
||||
config.daemon1.repo = ipfsPath
|
||||
rmrf.sync(config.daemon1.repo)
|
||||
rmrf.sync(dbPath)
|
||||
ipfsd = await startIpfs(API, config.daemon1)
|
||||
ipfs = ipfsd.api
|
||||
orbitdb1 = new OrbitDB(ipfs, dbPath + '/1')
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
if(orbitdb1)
|
||||
await orbitdb1.stop()
|
||||
|
||||
if (ipfsd)
|
||||
await stopIpfs(ipfsd)
|
||||
})
|
||||
|
||||
describe('load', function() {
|
||||
beforeEach(async () => {
|
||||
const dbName = new Date().getTime().toString()
|
||||
const entryArr = []
|
||||
|
||||
for (let i = 0; i < entryCount; i ++)
|
||||
entryArr.push(i)
|
||||
|
||||
db = await orbitdb1.eventlog(dbName)
|
||||
address = db.address.toString()
|
||||
await mapSeries(entryArr, (i) => db.add('hello' + i))
|
||||
await db.close()
|
||||
db = null
|
||||
before(async () => {
|
||||
config.daemon1.repo = ipfsPath
|
||||
rmrf.sync(config.daemon1.repo)
|
||||
rmrf.sync(dbPath)
|
||||
ipfsd = await startIpfs(API, config.daemon1)
|
||||
ipfs = ipfsd.api
|
||||
orbitdb1 = new OrbitDB(ipfs, dbPath + '/1', test.orbitDBConfig)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await db.drop()
|
||||
after(async () => {
|
||||
if(orbitdb1)
|
||||
await orbitdb1.stop()
|
||||
|
||||
if (ipfsd)
|
||||
await stopIpfs(ipfsd)
|
||||
})
|
||||
|
||||
it('loads database from local cache', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.load()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
})
|
||||
describe('load', function() {
|
||||
beforeEach(async () => {
|
||||
const dbName = new Date().getTime().toString()
|
||||
const entryArr = []
|
||||
|
||||
it('loads database partially', async () => {
|
||||
const amount = 33
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.load(amount)
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, amount)
|
||||
assert.equal(items[0].payload.value, 'hello' + (entryCount - amount))
|
||||
assert.equal(items[1].payload.value, 'hello' + (entryCount - amount + 1))
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
})
|
||||
for (let i = 0; i < entryCount; i ++)
|
||||
entryArr.push(i)
|
||||
|
||||
it('load and close several times', async () => {
|
||||
const amount = 8
|
||||
for (let i = 0; i < amount; i ++) {
|
||||
db = await orbitdb1.eventlog(dbName)
|
||||
address = db.address.toString()
|
||||
await mapSeries(entryArr, (i) => db.add('hello' + i))
|
||||
await db.close()
|
||||
db = null
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await db.drop()
|
||||
})
|
||||
|
||||
it('loads database from local cache', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.load()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[1].payload.value, 'hello1')
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('closes database while loading', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
db.load() // don't wait for load to finish
|
||||
await db.close()
|
||||
assert.equal(db._cache.store, null)
|
||||
})
|
||||
|
||||
it('load, add one, close - several times', async () => {
|
||||
const amount = 8
|
||||
for (let i = 0; i < amount; i ++) {
|
||||
it('loads database partially', async () => {
|
||||
const amount = 33
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.load()
|
||||
await db.add('hello' + (entryCount + i))
|
||||
await db.load(amount)
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount + i + 1)
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount + i))
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
assert.equal(items.length, amount)
|
||||
assert.equal(items[0].payload.value, 'hello' + (entryCount - amount))
|
||||
assert.equal(items[1].payload.value, 'hello' + (entryCount - amount + 1))
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
})
|
||||
|
||||
it('loading a database emits \'ready\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve) => {
|
||||
db.events.on('ready', () => {
|
||||
it('load and close several times', async () => {
|
||||
const amount = 8
|
||||
for (let i = 0; i < amount; i ++) {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.load()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[1].payload.value, 'hello1')
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
resolve()
|
||||
})
|
||||
await db.load()
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('loading a database emits \'load.progress\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let count = 0
|
||||
db.events.on('load.progress', (address, hash, entry) => {
|
||||
count ++
|
||||
try {
|
||||
assert.equal(address, db.address.toString())
|
||||
|
||||
const { progress, max } = db.replicationStatus
|
||||
assert.equal(max, entryCount)
|
||||
assert.equal(progress, count)
|
||||
|
||||
assert.notEqual(hash, null)
|
||||
assert.notEqual(entry, null)
|
||||
|
||||
if (progress === entryCount && count === entryCount) {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 200)
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
// Start loading the database
|
||||
await db.load()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('load from empty snapshot', function() {
|
||||
it('loads database from an empty snapshot', async () => {
|
||||
db = await orbitdb1.eventlog('empty-snapshot')
|
||||
address = db.address.toString()
|
||||
await db.saveSnapshot()
|
||||
await db.close()
|
||||
|
||||
db = await orbitdb1.open(address)
|
||||
await db.loadFromSnapshot()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, 0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('load from snapshot', function() {
|
||||
beforeEach(async () => {
|
||||
const dbName = new Date().getTime().toString()
|
||||
const entryArr = []
|
||||
|
||||
for (let i = 0; i < entryCount; i ++)
|
||||
entryArr.push(i)
|
||||
|
||||
db = await orbitdb1.eventlog(dbName)
|
||||
address = db.address.toString()
|
||||
await mapSeries(entryArr, (i) => db.add('hello' + i))
|
||||
await db.saveSnapshot()
|
||||
await db.close()
|
||||
db = null
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await db.drop()
|
||||
})
|
||||
|
||||
it('loads database from snapshot', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.loadFromSnapshot()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[entryCount - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
})
|
||||
|
||||
it('load, add one and save snapshot several times', async () => {
|
||||
const amount = 4
|
||||
for (let i = 0; i < amount; i ++) {
|
||||
it('closes database while loading', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.loadFromSnapshot()
|
||||
await db.add('hello' + (entryCount + i))
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount + i + 1)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount + i))
|
||||
db.load() // don't wait for load to finish
|
||||
await db.close()
|
||||
assert.equal(db._cache.store, null)
|
||||
})
|
||||
|
||||
it('load, add one, close - several times', async () => {
|
||||
const amount = 8
|
||||
for (let i = 0; i < amount; i ++) {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.load()
|
||||
await db.add('hello' + (entryCount + i))
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount + i + 1)
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount + i))
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
it('loading a database emits \'ready\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve) => {
|
||||
db.events.on('ready', () => {
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
resolve()
|
||||
})
|
||||
await db.load()
|
||||
})
|
||||
})
|
||||
|
||||
it('loading a database emits \'load.progress\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let count = 0
|
||||
db.events.on('load.progress', (address, hash, entry) => {
|
||||
count ++
|
||||
try {
|
||||
assert.equal(address, db.address.toString())
|
||||
|
||||
const { progress, max } = db.replicationStatus
|
||||
assert.equal(max, entryCount)
|
||||
assert.equal(progress, count)
|
||||
|
||||
assert.notEqual(hash, null)
|
||||
assert.notEqual(entry, null)
|
||||
|
||||
if (progress === entryCount && count === entryCount) {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, 200)
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
// Start loading the database
|
||||
await db.load()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('load from empty snapshot', function() {
|
||||
it('loads database from an empty snapshot', async () => {
|
||||
db = await orbitdb1.eventlog('empty-snapshot')
|
||||
address = db.address.toString()
|
||||
await db.saveSnapshot()
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
it('throws an error when trying to load a missing snapshot', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.drop()
|
||||
db = null
|
||||
db = await orbitdb1.eventlog(address)
|
||||
|
||||
let err
|
||||
try {
|
||||
await db.loadFromSnapshot()
|
||||
} catch (e) {
|
||||
err = e.toString()
|
||||
}
|
||||
assert.equal(err, `Error: Snapshot for ${address} not found!`)
|
||||
})
|
||||
|
||||
it('loading a database emits \'ready\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve) => {
|
||||
db.events.on('ready', () => {
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[entryCount - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
resolve()
|
||||
})
|
||||
db = await orbitdb1.open(address)
|
||||
await db.loadFromSnapshot()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, 0)
|
||||
})
|
||||
})
|
||||
|
||||
it('loading a database emits \'load.progress\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let count = 0
|
||||
db.events.on('load.progress', (address, hash, entry) => {
|
||||
count ++
|
||||
try {
|
||||
assert.equal(address, db.address.toString())
|
||||
describe('load from snapshot', function() {
|
||||
beforeEach(async () => {
|
||||
const dbName = new Date().getTime().toString()
|
||||
const entryArr = []
|
||||
|
||||
const { progress, max } = db.replicationStatus
|
||||
assert.equal(max, entryCount)
|
||||
assert.equal(progress, count)
|
||||
for (let i = 0; i < entryCount; i ++)
|
||||
entryArr.push(i)
|
||||
|
||||
assert.notEqual(hash, null)
|
||||
assert.notEqual(entry, null)
|
||||
if (progress === entryCount && count === entryCount) {
|
||||
resolve()
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
// Start loading the database
|
||||
db = await orbitdb1.eventlog(dbName)
|
||||
address = db.address.toString()
|
||||
await mapSeries(entryArr, (i) => db.add('hello' + i))
|
||||
await db.saveSnapshot()
|
||||
await db.close()
|
||||
db = null
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await db.drop()
|
||||
})
|
||||
|
||||
it('loads database from snapshot', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.loadFromSnapshot()
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[entryCount - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
})
|
||||
|
||||
it('load, add one and save snapshot several times', async () => {
|
||||
const amount = 4
|
||||
for (let i = 0; i < amount; i ++) {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.loadFromSnapshot()
|
||||
await db.add('hello' + (entryCount + i))
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount + i + 1)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[items.length - 1].payload.value, 'hello' + (entryCount + i))
|
||||
await db.saveSnapshot()
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
it('throws an error when trying to load a missing snapshot', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
await db.drop()
|
||||
db = null
|
||||
db = await orbitdb1.eventlog(address)
|
||||
|
||||
let err
|
||||
try {
|
||||
await db.loadFromSnapshot()
|
||||
} catch (e) {
|
||||
err = e.toString()
|
||||
}
|
||||
assert.equal(err, `Error: Snapshot for ${address} not found!`)
|
||||
})
|
||||
|
||||
it('loading a database emits \'ready\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve) => {
|
||||
db.events.on('ready', () => {
|
||||
const items = db.iterator({ limit: -1 }).collect()
|
||||
assert.equal(items.length, entryCount)
|
||||
assert.equal(items[0].payload.value, 'hello0')
|
||||
assert.equal(items[entryCount - 1].payload.value, 'hello' + (entryCount - 1))
|
||||
resolve()
|
||||
})
|
||||
await db.loadFromSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
it('loading a database emits \'load.progress\' event', async () => {
|
||||
db = await orbitdb1.eventlog(address)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let count = 0
|
||||
db.events.on('load.progress', (address, hash, entry) => {
|
||||
count ++
|
||||
try {
|
||||
assert.equal(address, db.address.toString())
|
||||
|
||||
const { progress, max } = db.replicationStatus
|
||||
assert.equal(max, entryCount)
|
||||
assert.equal(progress, count)
|
||||
|
||||
assert.notEqual(hash, null)
|
||||
assert.notEqual(entry, null)
|
||||
if (progress === entryCount && count === entryCount) {
|
||||
resolve()
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
// Start loading the database
|
||||
await db.loadFromSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
9
test/utils/custom-test-cache.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const OrbitDbCache = require('orbit-db-cache/Cache.js')
|
||||
const localdown = require('localstorage-down')
|
||||
|
||||
/**
|
||||
* A custom cache example. To create a differing custom example, orbitdb cache was
|
||||
* used with another abstract-leveldown compliant storage, localdown as an example
|
||||
*/
|
||||
|
||||
module.exports = OrbitDbCache(localdown)
|
||||
44
test/utils/databases.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const databases = [
|
||||
{
|
||||
type: 'eventlog',
|
||||
create: (orbitdb, name, options) => orbitdb.eventlog(name, options),
|
||||
tryInsert: (db) => db.add('hello'),
|
||||
query: (db) => db.iterator({ limit: -1 }).collect(),
|
||||
getTestValue: (db) => db.iterator({ limit: -1 }).collect()[0].payload.value,
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'feed',
|
||||
create: (orbitdb, name, options) => orbitdb.feed(name, options),
|
||||
tryInsert: (db) => db.add('hello'),
|
||||
query: (db) => db.iterator({ limit: -1 }).collect(),
|
||||
getTestValue: (db) => db.iterator({ limit: -1 }).collect()[0].payload.value,
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'key-value',
|
||||
create: (orbitdb, name, options) => orbitdb.kvstore(name, options),
|
||||
tryInsert: (db) => db.set('one', 'hello'),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.get('one'),
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'documents',
|
||||
create: (orbitdb, name, options) => orbitdb.docstore(name, options),
|
||||
tryInsert: (db) => db.put({ _id: 'hello world', doc: 'all the things'}),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.get('hello world'),
|
||||
expectedValue: [{ _id: 'hello world', doc: 'all the things'}],
|
||||
},
|
||||
{
|
||||
type: 'counter',
|
||||
create: (orbitdb, name, options) => orbitdb.counter(name, options),
|
||||
tryInsert: (db) => db.inc(8),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.value,
|
||||
expectedValue: 8,
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = databases
|
||||
@@ -6,3 +6,5 @@ exports.waitForPeers = require('./wait-for-peers')
|
||||
exports.connectPeers = require('./connect-peers')
|
||||
exports.MemStore = require('./mem-store')
|
||||
exports.CustomTestKeystore = require('./custom-test-keystore')
|
||||
exports.CustomTestCache = require('./custom-test-cache')
|
||||
exports.databases = require('./databases')
|
||||
|
||||
@@ -5,59 +5,17 @@ const rmrf = require('rimraf')
|
||||
const OrbitDB = require('../src/OrbitDB')
|
||||
|
||||
// Include test utilities
|
||||
const {
|
||||
config,
|
||||
startIpfs,
|
||||
stopIpfs,
|
||||
testAPIs,
|
||||
const {
|
||||
config,
|
||||
startIpfs,
|
||||
stopIpfs,
|
||||
testAPIs,
|
||||
databases,
|
||||
} = require('./utils')
|
||||
|
||||
const dbPath = './orbitdb/tests/write-permissions'
|
||||
const ipfsPath = './orbitdb/tests/write-permissions/ipfs'
|
||||
|
||||
const databases = [
|
||||
{
|
||||
type: 'eventlog',
|
||||
create: (orbitdb, name, options) => orbitdb.eventlog(name, options),
|
||||
tryInsert: (db) => db.add('hello'),
|
||||
query: (db) => db.iterator({ limit: -1 }).collect(),
|
||||
getTestValue: (db) => db.iterator({ limit: -1 }).collect()[0].payload.value,
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'feed',
|
||||
create: (orbitdb, name, options) => orbitdb.feed(name, options),
|
||||
tryInsert: (db) => db.add('hello'),
|
||||
query: (db) => db.iterator({ limit: -1 }).collect(),
|
||||
getTestValue: (db) => db.iterator({ limit: -1 }).collect()[0].payload.value,
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'key-value',
|
||||
create: (orbitdb, name, options) => orbitdb.kvstore(name, options),
|
||||
tryInsert: (db) => db.set('one', 'hello'),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.get('one'),
|
||||
expectedValue: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'documents',
|
||||
create: (orbitdb, name, options) => orbitdb.docstore(name, options),
|
||||
tryInsert: (db) => db.put({ _id: 'hello world', doc: 'all the things'}),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.get('hello world'),
|
||||
expectedValue: [{ _id: 'hello world', doc: 'all the things'}],
|
||||
},
|
||||
{
|
||||
type: 'counter',
|
||||
create: (orbitdb, name, options) => orbitdb.counter(name, options),
|
||||
tryInsert: (db) => db.inc(8),
|
||||
query: (db) => [],
|
||||
getTestValue: (db) => db.value,
|
||||
expectedValue: 8,
|
||||
},
|
||||
]
|
||||
|
||||
Object.keys(testAPIs).forEach(API => {
|
||||
describe(`orbit-db - Write Permissions (${API})`, function() {
|
||||
this.timeout(20000)
|
||||
@@ -75,10 +33,10 @@ Object.keys(testAPIs).forEach(API => {
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
if(orbitdb1)
|
||||
if(orbitdb1)
|
||||
await orbitdb1.stop()
|
||||
|
||||
if(orbitdb2)
|
||||
if(orbitdb2)
|
||||
await orbitdb2.stop()
|
||||
|
||||
if (ipfsd)
|
||||
@@ -88,10 +46,10 @@ Object.keys(testAPIs).forEach(API => {
|
||||
describe('allows multiple peers to write to the databases', function() {
|
||||
databases.forEach(async (database) => {
|
||||
it(database.type + ' allows multiple writers', async () => {
|
||||
let options = {
|
||||
let options = {
|
||||
// Set write access for both clients
|
||||
write: [
|
||||
orbitdb1.key.getPublic('hex'),
|
||||
orbitdb1.key.getPublic('hex'),
|
||||
orbitdb2.key.getPublic('hex')
|
||||
],
|
||||
}
|
||||
@@ -115,10 +73,10 @@ Object.keys(testAPIs).forEach(API => {
|
||||
describe('syncs databases', function() {
|
||||
databases.forEach(async (database) => {
|
||||
it(database.type + ' syncs', async () => {
|
||||
let options = {
|
||||
let options = {
|
||||
// Set write access for both clients
|
||||
write: [
|
||||
orbitdb1.key.getPublic('hex'),
|
||||
orbitdb1.key.getPublic('hex'),
|
||||
orbitdb2.key.getPublic('hex')
|
||||
],
|
||||
}
|
||||
@@ -148,7 +106,7 @@ Object.keys(testAPIs).forEach(API => {
|
||||
describe('syncs databases that anyone can write to', function() {
|
||||
databases.forEach(async (database) => {
|
||||
it(database.type + ' syncs', async () => {
|
||||
let options = {
|
||||
let options = {
|
||||
// Set write permission for everyone
|
||||
write: ['*'],
|
||||
}
|
||||
@@ -179,7 +137,7 @@ Object.keys(testAPIs).forEach(API => {
|
||||
databases.forEach(async (database) => {
|
||||
it(database.type + ' doesn\'t sync', async () => {
|
||||
|
||||
let options = {
|
||||
let options = {
|
||||
// Only peer 1 can write
|
||||
write: [orbitdb1.key.getPublic('hex')],
|
||||
}
|
||||
@@ -228,7 +186,7 @@ Object.keys(testAPIs).forEach(API => {
|
||||
describe('throws an error if peer is not allowed to write to the database', function() {
|
||||
databases.forEach(async (database) => {
|
||||
it(database.type + ' throws an error', async () => {
|
||||
let options = {
|
||||
let options = {
|
||||
// No write access (only creator of the database can write)
|
||||
write: [],
|
||||
}
|
||||
|
||||