diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5f19d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +package-lock.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c3701c0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Lucas Barrena + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5c8f32 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# use-hyper + +React hooks for the hypercore-protocol stack + +![](https://img.shields.io/npm/v/use-hyper.svg) ![](https://img.shields.io/npm/dt/use-hyper.svg) ![](https://img.shields.io/github/license/LuKks/use-hyper.svg) + +``` +npm i use-hyper +``` + +Warning: this is very experimental, and API might change until v1. + +## Usage +First you need to have `react` installed. + +Every hook requires the related library installed: +- `useCore` depends on `hypercore`. +- `useDHT` depends on `@hyperswarm/dht-relay`. +- `useSwarm` depends on `hyperswarm`. + +```javascript +import useKey from 'use-hyper/key' +import useCore from 'use-hyper/core' +import useDHT from 'use-hyper/dht' +import useSwarm from 'use-hyper/swarm' +``` + +## License +MIT diff --git a/core.mjs b/core.mjs new file mode 100644 index 0000000..51bae66 --- /dev/null +++ b/core.mjs @@ -0,0 +1,34 @@ +import { useEffect, useState } from 'react' +import Hypercore from 'hypercore' +// import b4a from 'b4a' + +export default function useCore (storage, key) { + const [core, setCore] = useState(null) + const [options, setOptions] = useState({}) + + useEffect(() => { + if (!key) return + + // const opts = (isOptions(args[0]) ? args[0] : args[1]) || {} + + const c = new Hypercore(storage, key, options) + const promise = main().catch(console.error) + + return () => { + promise.then(async () => { + await c.close() + }) + } + + async function main () { + await c.ready() + setCore(c) + } + }, [storage, key, options]) + + return [core, options, setOptions] +} + +/* function isOptions (value) { + return value && typeof value === 'object' && !b4a.isBuffer(value) +} */ diff --git a/dht.mjs b/dht.mjs new file mode 100644 index 0000000..aa17610 --- /dev/null +++ b/dht.mjs @@ -0,0 +1,30 @@ +import { useEffect, useState } from 'react' +import DHT from '@hyperswarm/dht-relay' +import Stream from '@hyperswarm/dht-relay/ws' +import b4a from 'b4a' +import useKey from './key.mjs' + +// + probably a global WebSocket instance? + +export default function useDHT () { + const [primaryKey] = useKey() + const [dht, setDHT] = useState(null) + + useEffect(() => { + if (primaryKey === null) return + + const ws = new window.WebSocket('wss://dht1-relay.leet.ar:49443') // + add more relays + const dht = new DHT(new Stream(true, ws), { + keyPair: DHT.keyPair(b4a.from(primaryKey, 'hex')) + }) + + setDHT(dht) + + return () => { + dht.destroy() + setDHT(null) + } + }, [primaryKey]) + + return [dht] +} diff --git a/key.mjs b/key.mjs new file mode 100644 index 0000000..114bd00 --- /dev/null +++ b/key.mjs @@ -0,0 +1,26 @@ +import { useEffect, useState } from 'react' +import b4a from 'b4a' +import sodium from 'sodium-universal' + +export default function useKey () { + const [key, setKey] = useState(null) + + useEffect(() => { + let primaryKey = window.localStorage.getItem('primary-key') + + if (primaryKey === null) { + primaryKey = b4a.toString(randomBytes(32), 'hex') + window.localStorage.setItem('primary-key', primaryKey) + } + + setKey(b4a.from(primaryKey)) + }, []) + + return [key] +} + +function randomBytes (n) { + const buf = b4a.allocUnsafe(n) + sodium.randombytes_buf(buf) + return buf +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..90e84b1 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "use-hyper", + "version": "0.0.0", + "description": "React hooks for the hypercore-protocol stack", + "main": "", + "scripts": { + "test": "standard" + }, + "repository": { + "type": "git", + "url": "https://github.com/LuKks/use-hyper.git" + }, + "author": "Lucas Barrena (LuKks)", + "license": "MIT", + "bugs": { + "url": "https://github.com/LuKks/use-hyper/issues" + }, + "homepage": "https://github.com/LuKks/use-hyper", + "devDependencies": { + "standard": "^17.0.0" + }, + "dependencies": { + "b4a": "^1.6.2", + "sodium-universal": "^4.0.0" + } +} diff --git a/swarm.mjs b/swarm.mjs new file mode 100644 index 0000000..164c867 --- /dev/null +++ b/swarm.mjs @@ -0,0 +1,21 @@ +import { useEffect, useState } from 'react' +import Hyperswarm from 'hyperswarm' + +export default function useSwarm (dht) { + const [swarm, setSwarm] = useState(null) + + useEffect(() => { + if (dht === null) return + + const swarm = new Hyperswarm({ dht, keyPair: dht.defaultKeyPair }) + + setSwarm(swarm) + + return () => { + swarm.destroy() + for (const socket of swarm.connections) socket.destroy() + } + }, [dht]) + + return [swarm] +}