diff --git a/package.json b/package.json index de81f894..90a22ff0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "build": "preact build --no-prerender", "serve": "sirv build --port 8080 --cors --single", - "dev": "preact watch", + "dev": "echo 'dev server will start at http://localhost:8080';preact watch", "lint": "eslint src", "test": "jest" }, diff --git a/src/js/PeerManager.js b/src/js/PeerManager.js index ae7e172d..8307b619 100644 --- a/src/js/PeerManager.js +++ b/src/js/PeerManager.js @@ -9,7 +9,7 @@ const ELECTRON_GUN_URL = 'http://localhost:8767/gun'; let maxConnectedPeers = Helpers.isElectron ? 2 : 1; const DEFAULT_PEERS = {}; -if (window.location.hostname.endsWith('herokuapp.com') || window.location.host === 'localhost:5000') { +if (window.location.hostname.endsWith('herokuapp.com') || window.location.host === 'localhost:4944') { DEFAULT_PEERS[window.location.origin + '/gun'] = {}; } else { DEFAULT_PEERS['https://gun-rs.iris.to/gun'] = {}; diff --git a/src/js/components/ExplorerNode.js b/src/js/components/ExplorerNode.js new file mode 100644 index 00000000..1bf7cca7 --- /dev/null +++ b/src/js/components/ExplorerNode.js @@ -0,0 +1,251 @@ +import BaseComponent from "../BaseComponent"; +import Session from "../Session"; +import Gun from "gun"; +import {html} from "htm/preact"; + +const hashRegex = /^(?:[A-Za-z0-9+/]{4}){10}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)+$/; +const pubKeyRegex = /^[A-Za-z0-9\-\_]{40,50}\.[A-Za-z0-9\_\-]{40,50}$/; +const SHOW_CHILDREN_COUNT = 50; + +const chevronDown = html` + +`; + +const chevronRight = html` + +`; + +class ExplorerNode extends BaseComponent { + constructor() { + super(); + this.children = {}; + this.state = {children: {}, shownChildrenCount: SHOW_CHILDREN_COUNT}; + } + + getNode() { + if (this.props.path.length > 1) { + const path = this.props.path.split('/'); + return path.slice(1).reduce((sum, current) => (current && sum.get(decodeURIComponent(current))) || sum, this.props.gun); + } + return this.props.gun; + } + + shouldComponentUpdate() { + return true; + } + + componentDidMount() { + this.isMine = this.props.path.indexOf(`public/~${ Session.getPubKey()}`) === 0; + this.isGroup = this.props.path.indexOf('group') === 0; + + this.children = {}; + if (this.props.children && typeof this.props.children === "object") { + this.children = Object.assign(this.children, this.props.children); + } + this.setState({children: {}, shownChildrenCount: SHOW_CHILDREN_COUNT}); + + const cb = this.sub( + async (v, k, c, e, from) => { + if (k === '_') { return; } + let encryption; + if (typeof v === 'string' && v.indexOf('SEA{') === 0) { + try { + const myKey = Session.getKey(); + let dec = await Gun.SEA.decrypt(v, myKey); + if (dec === undefined) { + if (!this.mySecret) { + this.mySecret = await Gun.SEA.secret(myKey.epub, myKey); + dec = await Gun.SEA.decrypt(v, this.mySecret); + } + } + if (dec !== undefined) { + v = dec; + encryption = 'Decrypted'; + } else { + encryption = 'Encrypted'; + } + } catch(e) { + null; + } + } + const prev = this.children[k] || {}; + this.children[k] = Object.assign(prev, { value: v, encryption, from }); + this.setState({children: this.children}); + } + ); + + if (this.isGroup) { + const path = this.props.path.split('/').slice(2).join('/'); + this.props.gun.map(path, cb); // TODO: make State.group() provide the normal gun api + } else { + this.getNode().map().on(cb); + } + } + + onChildObjectClick(e, k) { + e.preventDefault(); + this.children[k].open = !this.children[k].open; + this.setState({children: this.children}); + } + + onShowMoreClick(e, k) { + e.preventDefault(); + this.children[k].showMore = !this.children[k].showMore; + this.setState({children: this.children}); + } + + renderChildObject(k) { + const path = `${this.props.path }/${ encodeURIComponent(k)}`; + return html` +
+ this.onExpandClicked()}>${this.state.expandAll ? 'Close all' : 'Expand all'} + this.showNewItemClicked('object')}>New object + this.showNewItemClicked('value')}>New value + ${children.length} items +
+ `: ''} + ${this.state.showNewItem ? html` ++
+ + ` : ''} +