0.0.002
ddat interop with dat js cable interop with cabal js ddat's frontend = dat-thang cable fe = cable-thang dillo support based on cel's dillo-dat bootstrap node xplatform support Signed-off-by: divo <418@cryspace.space>
This commit is contained in:
1 parent
f0f91540be
commit
b735900f2e
323 files changed
+134347
-343
No files matched your search
@@ -0,0 +1,87 @@
|
||||
'use strict'
|
||||
|
||||
// Opens the native Cable user log with the bundled legacy Hypercore 7.7.1,
|
||||
// appends a JS record, and leaves the C side to read it back in the runner.
|
||||
const assert = require('assert')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const root = path.resolve(__dirname, '../../..')
|
||||
const home = path.resolve(process.argv[2])
|
||||
const roomKey = process.argv[3]
|
||||
assert.match(roomKey, /^[0-9a-f]{64}$/)
|
||||
const roomDir = path.join(home, '.cable', 'rooms', roomKey)
|
||||
const feedDir = path.join(roomDir, '0')
|
||||
const feedKey = fs.readFileSync(path.join(feedDir, 'key'))
|
||||
const secretKey = fs.readFileSync(path.join(roomDir, 'user-feed.key'))
|
||||
assert.strictEqual(feedKey.length, 32)
|
||||
assert.strictEqual(secretKey.length, 64)
|
||||
|
||||
const Hypercore = require(path.join(root, 'extra/dillo-dat/node_modules/hypercore'))
|
||||
const randomAccessFile = require(path.join(root, 'extra/dillo-dat/node_modules/random-access-file'))
|
||||
function memoryStorage () {
|
||||
let bytes = Buffer.alloc(0)
|
||||
return {
|
||||
read (offset, length, callback) {
|
||||
const value = Buffer.alloc(length)
|
||||
bytes.copy(value, 0, offset, offset + length)
|
||||
callback(null, value)
|
||||
},
|
||||
write (offset, value, callback) {
|
||||
if (bytes.length < offset + value.length) {
|
||||
const grown = Buffer.alloc(offset + value.length)
|
||||
bytes.copy(grown)
|
||||
bytes = grown
|
||||
}
|
||||
value.copy(bytes, offset)
|
||||
callback(null)
|
||||
},
|
||||
stat (callback) { callback(null, { size: bytes.length }) },
|
||||
close (callback) { callback(null) }
|
||||
}
|
||||
}
|
||||
const storage = name => name === 'secret_key'
|
||||
? memoryStorage()
|
||||
: randomAccessFile(name, { directory: feedDir })
|
||||
|
||||
function ready (feed) {
|
||||
return new Promise((resolve, reject) => feed.ready(err => err ? reject(err) : resolve()))
|
||||
}
|
||||
|
||||
function get (feed, index) {
|
||||
return new Promise((resolve, reject) => feed.get(index, (err, value) => err ? reject(err) : resolve(value)))
|
||||
}
|
||||
|
||||
function append (feed, value) {
|
||||
return new Promise((resolve, reject) => feed.append(Buffer.from(JSON.stringify(value)), err => err ? reject(err) : resolve()))
|
||||
}
|
||||
|
||||
function close (feed) {
|
||||
return new Promise((resolve, reject) => feed.close(err => err ? reject(err) : resolve()))
|
||||
}
|
||||
|
||||
async function main () {
|
||||
const feed = Hypercore(storage, feedKey, { secretKey })
|
||||
feed.on('error', err => { throw err })
|
||||
try {
|
||||
await ready(feed)
|
||||
assert.strictEqual(feed.length, 2, 'C should have written two Cabal records')
|
||||
const nick = JSON.parse((await get(feed, 0)).toString('utf8'))
|
||||
const message = JSON.parse((await get(feed, 1)).toString('utf8'))
|
||||
assert.strictEqual(nick.type, 'about')
|
||||
assert.strictEqual(nick.content.name, 'cable-c-user')
|
||||
assert.strictEqual(message.type, 'chat/text')
|
||||
assert.strictEqual(message.content.channel, 'interop')
|
||||
assert.strictEqual(message.content.text, 'hello from C Hypercore')
|
||||
await append(feed, {
|
||||
type: 'chat/text',
|
||||
content: { channel: 'interop', text: 'hello from Cabal JavaScript Hypercore' },
|
||||
timestamp: Date.now()
|
||||
})
|
||||
process.stdout.write(`Cabal Hypercore v7.7.1 read C user feed and appended reply: PASS key=${feedKey.toString('hex')}\n`)
|
||||
} finally {
|
||||
await close(feed)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => { console.error(err); process.exitCode = 1 })
|
||||
@@ -0,0 +1,44 @@
|
||||
param([switch]$KeepFixture)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$root = (Resolve-Path (Join-Path $PSScriptRoot '..\..\..')).Path
|
||||
$buildDir = [System.IO.Path]::GetFullPath((Join-Path $root 'build\linux'))
|
||||
$binary = Join-Path $buildDir 'cable'
|
||||
$nodeScript = Join-Path $PSScriptRoot 'cable_hypercore_compat.js'
|
||||
$runRoot = [System.IO.Path]::GetFullPath((Join-Path $root 'local-data\test-runs'))
|
||||
$fixtureHome = Join-Path $runRoot ('cable-hypercore-interop-' + [guid]::NewGuid().ToString('N'))
|
||||
$linuxRoot = '/mnt/' + $root.Substring(0, 1).ToLower() + '/' + $root.Substring(3).Replace('\', '/')
|
||||
$linuxHome = $linuxRoot + '/local-data/test-runs/' + (Split-Path $fixtureHome -Leaf)
|
||||
$room = '42' * 32
|
||||
|
||||
function Invoke-WslCable([string[]]$Arguments) {
|
||||
& wsl.exe --exec env "HOME=$linuxHome" "$linuxRoot/build/linux/cable" @Arguments
|
||||
if ($LASTEXITCODE -ne 0) { throw "C cable command failed with exit code $LASTEXITCODE" }
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $fixtureHome -Force | Out-Null
|
||||
try {
|
||||
& wsl.exe --exec make -C $linuxRoot build/linux/cable
|
||||
if ($LASTEXITCODE -ne 0) { throw "WSL Cable build failed with exit code $LASTEXITCODE" }
|
||||
Invoke-WslCable @('nick', "cabal://$room", 'cable-c-user') | Out-Null
|
||||
Invoke-WslCable @('publish', "cabal://$room", 'interop', 'hello from C Hypercore') | Out-Null
|
||||
|
||||
& node $nodeScript $fixtureHome $room
|
||||
if ($LASTEXITCODE -ne 0) { throw "JavaScript Hypercore check failed with exit code $LASTEXITCODE" }
|
||||
|
||||
$records = Invoke-WslCable @('feed', "cabal://$room")
|
||||
if (($records -join "`n") -notmatch 'hello from Cabal JavaScript Hypercore') {
|
||||
throw 'C did not read the JavaScript-appended block'
|
||||
}
|
||||
Write-Output 'Cabal Core room/0 storage + Hypercore v7.7.1 read/write: PASS'
|
||||
Write-Output 'C read JavaScript-appended Hypercore block: PASS'
|
||||
} finally {
|
||||
if (-not $KeepFixture -and (Test-Path -LiteralPath $fixtureHome)) {
|
||||
$resolvedFixture = [System.IO.Path]::GetFullPath((Resolve-Path -LiteralPath $fixtureHome).Path)
|
||||
$runPrefix = $runRoot.TrimEnd('\') + '\'
|
||||
if (-not $resolvedFixture.StartsWith($runPrefix, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "Refusing to remove fixture outside local-data/test-runs/: $resolvedFixture"
|
||||
}
|
||||
Remove-Item -LiteralPath $resolvedFixture -Recurse -Force
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const hyperdrive = require('../../extra/dillo-dat/node_modules/hyperdrive')
|
||||
const hyperdiscovery = require('../../extra/dillo-dat/node_modules/hyperdiscovery')
|
||||
|
||||
function ready (archive) {
|
||||
return new Promise((resolve, reject) => archive.ready(err => err ? reject(err) : resolve()))
|
||||
}
|
||||
|
||||
function writeFile (archive, name, data) {
|
||||
return new Promise((resolve, reject) => archive.writeFile(name, data, err => err ? reject(err) : resolve()))
|
||||
}
|
||||
|
||||
function readFile (archive, name) {
|
||||
return new Promise((resolve, reject) => archive.readFile(name, (err, data) => err ? reject(err) : resolve(data)))
|
||||
}
|
||||
|
||||
function listening (swarm) {
|
||||
if (swarm.address()) return Promise.resolve(swarm.address())
|
||||
return new Promise(resolve => swarm.once('listening', () => resolve(swarm.address())))
|
||||
}
|
||||
|
||||
function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms)) }
|
||||
|
||||
async function main () {
|
||||
const root = fs.mkdtempSync(path.join(process.env.DDAT_TEST_DIR || os.tmpdir(), 'ddat-js-p2p-'))
|
||||
let source, replica, sourceSwarm, replicaSwarm
|
||||
try {
|
||||
source = hyperdrive(path.join(root, 'source'))
|
||||
await ready(source)
|
||||
const key = source.key.toString('hex')
|
||||
const address = 'dat://' + key
|
||||
await writeFile(source, 'hello.txt', 'hello from old dillo-dat v1')
|
||||
await writeFile(source, 'hello.txt', 'hello from old dillo-dat v2')
|
||||
if (source.key.toString('hex') !== key) throw new Error('JS archive address changed after update')
|
||||
replica = hyperdrive(path.join(root, 'replica'), source.key, {sparse: true})
|
||||
await ready(replica)
|
||||
|
||||
sourceSwarm = hyperdiscovery(source, {port: 0, discovery: false, dht: false, dns: false, utp: false})
|
||||
replicaSwarm = hyperdiscovery(replica, {port: 0, discovery: false, dht: false, dns: false, utp: false})
|
||||
const sourceAddress = await listening(sourceSwarm)
|
||||
const replicaAddress = await listening(replicaSwarm)
|
||||
const topic = source.discoveryKey
|
||||
sourceSwarm.addPeer(topic, {host: '127.0.0.1', port: replicaAddress.port})
|
||||
replicaSwarm.addPeer(topic, {host: '127.0.0.1', port: sourceAddress.port})
|
||||
|
||||
const deadline = Date.now() + 15000
|
||||
let result
|
||||
while (Date.now() < deadline) {
|
||||
try { result = await readFile(replica, 'hello.txt'); break } catch (_) { await sleep(100) }
|
||||
}
|
||||
if (!result || result.toString() !== 'hello from old dillo-dat v2') throw new Error('old JS replication did not deliver the latest file')
|
||||
process.stdout.write('old Dillo Dat JS create/update/address/xfer: PASS ' + address +
|
||||
' metadata=' + source.metadata.length + ' content=' + source.content.length + '\n')
|
||||
} finally {
|
||||
if (sourceSwarm) sourceSwarm.destroy()
|
||||
if (replicaSwarm) replicaSwarm.destroy()
|
||||
if (source) source.close()
|
||||
if (replica) replica.close()
|
||||
if (process.env.DDAT_TEST_KEEP === '1') {
|
||||
process.stdout.write('kept old JS source and replica at ' + root + '\n')
|
||||
} else {
|
||||
fs.rmSync(root, {recursive: true, force: true})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => { console.error(err); process.exitCode = 1 })
|
||||
Reference in new issue
Block a user