...
 
Commits (3)
//
// Hypha client
//
// Initial key generation
const session25519 = require('session25519')
const generateEFFDicewarePassphrase = require('eff-diceware-passphrase')
......@@ -7,6 +11,12 @@ const { Buffer } = require('buffer')
const ram = require('random-access-memory')
const hypercore = require('hypercore')
// Web socket / replication
const webSocketStream = require('websocket-stream')
const pump = require('pump')
const nextId = require('monotonic-timestamp-base36')
// From libsodium.
function to_hex(input) {
// Disable input checking for this simple spike.
......@@ -88,8 +98,6 @@ function logError(error) {
}
function generatePassphrase () {
console.log('--- generatePassphrase() ---')
resetForm()
showProgressIndicator()
......@@ -120,9 +128,6 @@ function clearOutputFields() {
}
function generateKeys() {
console.log('--- generateKeys() ---')
const passphrase = setupForm.elements.passphrase.value
const domain = setupForm.elements.domain.value
......@@ -171,7 +176,10 @@ function generateKeys() {
feed.on('ready', () => {
console.log(`Feed: [Ready] ${to_hex(feed.key)}`)
const feedKey = feed.key
const feedKeyInHex = to_hex(feedKey)
console.log(`Feed: [Ready] ${feedKeyInHex}`)
blinkSignal('ready')
generatedTextField.value = 'Yes'
......@@ -181,6 +189,30 @@ function generateKeys() {
return
}
// Hypercore feed is ready: connect to web socket and start replicating.
const remoteStream = webSocketStream(`wss://localhost/hypha/${feedKeyInHex}`)
const localStream = feed.replicate({
encrypt: false,
live: true
})
// Create a duplex stream.
//
// What’s actually happening:
//
// remoteStream.write -> localStream.read
// localStream.write -> remoteStream.read
pump(
remoteStream,
localStream,
remoteStream,
(error) => {
console.log(`Pipe closed for ${feedKeyInHex}`, error && error.message)
logError(error.message)
}
)
//
// Note: the order of execution for an append appears to be:
//
......@@ -210,7 +242,6 @@ function generateKeys() {
let counter = 0
const intervalToUpdateInMS = 500
Date.prototype.getUnixTime = function() { return this.getTime()/1000|0 }
updateInterval = setInterval(() => {
counter++
if (counter === NUMBER_TO_APPEND) {
......@@ -219,7 +250,7 @@ function generateKeys() {
updateInterval = null
}
const key = (new Date()).getUnixTime()
const key = nextId()
const value = Math.random()*1000000000000000000 // simple random number
let obj = {}
obj[key] = value
......
//
// Hypha: A native client for testing replication of a single hypercore.
//
const hypercore = require('hypercore')
const ram = require('random-access-memory')
const hyperswarm = require('@hyperswarm/network')
const { pipeline } = require('stream')
const { discoveryKey } = require('hypercore/lib/crypto')
const swarm = hyperswarm()
//////////////////////////////////////////////////////////////////////////////////////////
//
// Manually entered for now.
//
const readKeyInHex = '0b77c7fc5a7dd4be30bf8e7c02c2c1a87798f0218697ce07b2bce93a5da82ba4'
//
//////////////////////////////////////////////////////////////////////////////////////////
const readKeyBuffer = Buffer.from(readKeyInHex, 'hex')
const discoveryKeyBuffer = discoveryKey(readKeyBuffer)
const discoveryKeyInHex = discoveryKeyBuffer.toString('hex')
// Create the local hypercore instance
const localCore = hypercore((filename) => ram(filename), readKeyBuffer, {
createIfMissing: false,
overwrite: false,
valueEncoding: 'json',
onwrite: (index, data, peer, next) => {
// console.log(`Feed: [onWrite] index = ${index}, peer = ${peer}, data:`)
// console.log(data)
next()
}
})
const localReadStream = localCore.createReadStream({live: true})
localReadStream.on('data', (data) => {
console.log('[Replicate]', data)
})
localCore.on('ready', () => {
console.log('Local core ready.')
// HACK: Just for now, make sure we only connect once
let connected = false
//
// Join the swarm
//
swarm.join(discoveryKeyBuffer, {
lookup: true, // find and connect to peers.
announce: true // optional: announce self as a connection target.
})
swarm.on('connection', (remoteNativeStream, details) => {
// HACK: only handle first connection
if (connected) return
connected = true
console.log(`Joined swarm for read key ${readKeyInHex}, discovery key ${discoveryKeyInHex}`)
// Replicate!
console.log('About to replicate!')
// Create the local replication stream.
const localReplicationStream = localCore.replicate({
// TODO: why is Jim’s shopping list example setting encrypt to false?
// The encryption of __what__ does this affect?
// (I haven’t even tested this yet with it set to true to limit the variables.)
encrypt: false,
live: true
})
pipeline(
remoteNativeStream,
localReplicationStream,
remoteNativeStream,
(error) => {
console.log(`Pipe closed for ${readKeyInHex}`, error && error.message)
}
)
})
})
This diff is collapsed.
......@@ -5,7 +5,7 @@
"main": "server/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server/index.js"
"start": "nodemon server/index.js --watch server/index.js"
},
"repository": {
"type": "git",
......@@ -20,12 +20,18 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"@babel/core": "^7.2.2",
"@hyperswarm/network": "0.0.4",
"babelify": "^10.0.0",
"budo": "github:aral/budo",
"buffer": "^5.2.1",
"eff-diceware-passphrase": "^1.0.0",
"express": "^4.16.4",
"express-ws": "^4.0.0",
"hypercore": "^6.22.4",
"monotonic-timestamp-base36": "^1.0.0",
"pump": "^3.0.0",
"random-access-memory": "^3.1.1",
"session25519": "github:aral/session25519"
"session25519": "github:aral/session25519",
"websocket-stream": "^5.1.2"
}
}
//
// Hypha server.
//
const fs = require('fs')
const https = require('https')
const { pipeline } = require('stream')
const express = require('express')
const expressWebSocket = require('express-ws')
const websocketStream = require('websocket-stream/stream')
const ram = require('random-access-memory')
const hypercore = require('hypercore')
const hyperswarm = require('@hyperswarm/network')
const budo = require('budo')
const babelify = require('babelify')
const router = express.Router()
const hypercores = {}
const server = budo('client/index.js', {
live: true,
live: false,
port: 443,
ssl: true,
dir: 'client/static/', // Static content directory
......@@ -16,10 +30,112 @@ const server = budo('client/index.js', {
stream: process.stdout, // Log to console
browserify: {
transform: babelify
}
},
middleware: [
router
]
})
server.on('connect', (event) => {
// Setup our web socket server (in addition to Budo’s, which is
// used for live reload).
expressWebSocket(router, event.server, {
perMessageDeflate: false
})
// Add web socket routes.
router.ws('/hypha/:readKey', (webSocket, request) => {
const readKey = request.params.readKey
console.log('Got web socket request for ', readKey)
if (hypercores[readKey] !== undefined) {
console.log(`Hypercore with read key ${readKey} already exists. Ignoring.`)
return
}
// Create a new hypercore with the passed read key and replicate.
const newCore = hypercore((filename) => ram(filename), readKey, {
createIfMissing: false,
overwrite: false,
valueEncoding: 'json',
onwrite: (index, data, peer, next) => {
// console.log(`Feed: [onWrite] index = ${index}, peer = ${peer}, data:`)
// console.log(data)
next()
}
})
newCore.on('ready', () => {
console.log(`Hypercore ready (${readKey})`)
const remoteWebStream = websocketStream(webSocket)
const localReadStream = newCore.createReadStream({live: true})
localReadStream.on('data', (data) => {
console.log('[Replicate]', data)
})
//
// Replicate :)
//
const localReplicationStream = newCore.replicate({
encrypt: false,
live: true
})
pipeline(
remoteWebStream,
localReplicationStream,
remoteWebStream,
(error) => {
console.log(`Pipe closed for ${readKey}`, error && error.message)
}
)
//
// Connect to the hyperswarm for this hypercore.
//
const swarm = hyperswarm()
const discoveryKey = newCore.discoveryKey
const discoveryKeyInHex = discoveryKey.toString('hex')
console.log(discoveryKeyInHex)
console.log('About to join the swarm!')
// Join the swarm
swarm.join(newCore.discoveryKey, {
lookup: true, // find and connect to peers.
announce: true // optional: announce self as a connection target.
})
swarm.on('connection', (remoteNativeStream, details) => {
console.log(`Joined swarm for read key ${readKey} (discovery key: ${discoveryKeyInHex})`)
// Create a new replication stream
const nativeReplicationStream = newCore.replicate({
encrypt: false,
live: true
})
// Replicate!
pipeline(
remoteNativeStream,
nativeReplicationStream,
remoteNativeStream,
(error) => {
console.log(`(Native stream from swarm) Pipe closed for ${readKey}`, error && error.message)
}
)
})
})
})
// TODO: Join swarm, add cancellation, etc.
// Display connection info.
const horizontalRule = new Array(60).fill('⎺').join('')
console.log('\nHypha Spike: DAT 1')
console.log(horizontalRule)
......