Hyperdrive is a secure, real-time distributed file system designed for easy peer-to-peer file sharing. In the same way that a Hyperbee is just a wrapper around a Hypercore, a Hyperdrive is a wrapper around two Hypercores: one is a Hyperbee index for storing file metadata, and the other is used to store file contents.
This How-to consists of three applications: drive-writer-app, drive-reader-app and bee-reader-app.
Now let's mirror a local directory into a Hyperdrive, replicate it with a reader peer, who then mirrors it into their own local copy. When the writer modifies its drive, by adding, removing, or changing files, the reader's local copy will be updated to reflect that. To do this, we'll use two additional tools: MirrorDrive and LocalDrive, which handle all interactions between Hyperdrives and the local filesystem.
Start by creating the drive-writer-app project with these commands:
Alter driver-writer-app/index.js to the following:
import Hyperswarm from'hyperswarm'import Hyperdrive from'hyperdrive'import Localdrive from'localdrive'import Corestore from'corestore'import debounce from'debounceify'import b4a from'b4a'import stdio from'pear-stdio'// create a Corestore instance conststore=newCorestore(Pear.config.storage)constswarm=newHyperswarm()Pear.teardown(() =>swarm.destroy())// replication of the corestore instance on connection with other peersswarm.on('connection', conn =>store.replicate(conn))// A local drive provides a Hyperdrive interface to a local directoryconstlocal=newLocaldrive('./writer-dir')// A Hyperdrive takes a Corestore because it needs to create many cores// One for a file metadata Hyperbee, and one for a content Hypercoreconstdrive=newHyperdrive(store)// wait till the properties of the hyperdrive instance are initializedawaitdrive.ready()// Import changes from the local drive into the Hyperdriveconstmirror=debounce(mirrorDrive)constdiscovery=swarm.join(drive.discoveryKey)awaitdiscovery.flushed()console.log('drive key:',b4a.toString(drive.key,'hex'))// start the mirroring process (i.e copying) of content from writer-dir to the drive// whenever something is entered (other than '/n' or Enter )in the command-linestdio.in.setEncoding('utf-8')stdio.in.on('data', (data) => {if (!data.match('\n')) returnmirror()})// this function copies the contents from writer-dir directory to the driveasyncfunctionmirrorDrive () {console.log('started mirroring changes from \'./writer-dir\' into the drive...')constmirror=local.mirror(drive)awaitmirror.done()console.log('finished mirroring:',mirror.count)}
Open the drive-writer-app with pear dev:
cd drive-writer-app
pear dev
The drive-writer-app creates a LocalDrive instance for a local directory and then mirrors the LocalDrive into the Hyperdrive instance.
The store used to create the Hyperdrive instance is replicated using Hyperswarm to make the data of Hyperdrive accessible to other peers.
It outputs a key which will be passed to drive-reader-app upon execution.
Leave the driver-writer-app running and in a new terminal create the drive-reader-app project with these commands:
import Hyperswarm from'hyperswarm'import Hyperdrive from'hyperdrive'import Localdrive from'localdrive'import Corestore from'corestore'import debounce from'debounceify'import b4a from'b4a'constkey=Pear.config.args[0]if (!key) thrownewError('provide a key')// create a Corestore instanceconststore=newCorestore(Pear.config.storage)constswarm=newHyperswarm()Pear.teardown(() =>swarm.destroy())// replication of store on connection with other peersswarm.on('connection', conn =>store.replicate(conn))// create a local copy of the remote driveconstlocal=newLocaldrive('./reader-dir')// create a hyperdrive using the public key passed as a command-line argumentconstdrive=newHyperdrive(store,b4a.from(key,'hex'))// wait till all the properties of the drive are initializedawaitdrive.ready()constmirror=debounce(mirrorDrive)// call the mirror function whenever content gets appended // to the Hypercore instance of the hyperdrivedrive.core.on('append', mirror)constfoundPeers=store.findingPeers()// join a topicswarm.join(drive.discoveryKey, { client:true, server:false })swarm.flush().then(() =>foundPeers())// start the mirroring process (i.e copying the contents from remote drive to local dir)mirror()asyncfunctionmirrorDrive () {console.log('started mirroring remote drive into \'./reader-dir\'...')constmirror=drive.mirror(local)awaitmirror.done()console.log('finished mirroring:',mirror.count)}
The drive-reader-app creates a LocalDrive instance for a local directory and then mirrors the contents of the local Hyperdrive instance into the LocalDrive instance (which will write the contents to the local directory).
In a new terminal, execute the drive-reader-app with pear dev, passing the key that the drive-writer-app already output:
cd drive-reader-app
pear dev -- <SUPPLY_KEY_HERE>
LocalDrive does not create the directory passed to it until something has been written, so create the drive-writer-app/writer-dir (mkdir writer-dir) and then add/remove/modify files inside drive-writer-app/writer-dir then press Enter in the writer's terminal (to import the local changes into the writer's drive). Observe that all new changes mirror into reader-app/reader-dir.
Just as a Hyperbee is just a Hypercore, a Hyperdrive is just a Hyperbee - which is just a Hypercore.
In a new terminal, create the bee-reader-app project with these commands:
import Hyperswarm from'hyperswarm'import Corestore from'corestore'import Hyperbee from'hyperbee'import b4a from'b4a'import process from'bare-process'// create a Corestore instance conststore=newCorestore(Pear.config.storage)constswarm=newHyperswarm()Pear.teardown(() =>swarm.destroy())// replicate corestore instance on connection with other peersswarm.on('connection', conn =>store.replicate(conn))// create/get the hypercore instance using the public key supplied as command-line argconstcore=store.get({ key:b4a.from(process.argv[3],'hex') })// create a hyperbee instance using the hypercore instanceconstbee=newHyperbee(core, { keyEncoding:'utf-8', valueEncoding:'json'})// wait till the properties of the hypercore instance are initializedawaitcore.ready()constfoundPeers=store.findingPeers()swarm.join(core.discoveryKey)swarm.flush().then(() =>foundPeers())// execute the listBee function whenever the data is appended to the underlying hypercorecore.on('append', listBee)listBee()// listBee function will list the key-value pairs present in the hyperbee instanceasyncfunctionlistBee () {console.log('\n***************')console.log('hyperbee contents are now:')forawait (constnodeofbee.createReadStream()) {console.log(' ',node.key,'->',node.value) }}
Now the Hyperdrive can be inspected as though it were a Hyperbee, and log out some file metadata.
Execute the bee-reader-app with pear dev, passing it the key output by the driver-writer-app:
cd bee-reader-app
pear dev
The bee-reader-app creates a Hyperbee instance using the Hypercore instance created with the copied public key. Every time the Hyperbee is updated (an append event is emitted on the underlying Hypercore), all file metadata nodes will be logged out.
Try adding or removing a few files from the writer's data directory, then pressing Enter in the writer's terminal to mirror the changes.