From 0a48adeac9c1034f72e5191d2f71380438776e13 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 22 May 2018 15:23:38 +0300 Subject: [PATCH] OrbitDB improvements --- contracts/Forum.sol | 22 +++++++++++----- package.json | 5 ++-- src/containers/LoadingContainer.js | 2 +- src/contractReducer.js | 16 ++++++++++++ src/contractSaga.js | 19 ++++++++++++++ src/layouts/home/HomeContainer.js | 3 +++ src/reducer.js | 2 ++ src/rootSaga.js | 4 ++- src/userSaga.js | 27 ++++++++----------- src/util/orbit.js | 25 +++++++++++++++--- src/util/orbitReducer.js | 26 ++++++++++++++---- src/util/orbitSaga.js | 42 ++++++++++++++++++++++++++++++ 12 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 src/contractReducer.js create mode 100644 src/contractSaga.js create mode 100644 src/util/orbitSaga.js diff --git a/contracts/Forum.sol b/contracts/Forum.sol index c91eaa3..81f2990 100644 --- a/contracts/Forum.sol +++ b/contracts/Forum.sol @@ -80,17 +80,27 @@ contract Forum { return users[userAddress].orbitdb.postsDB; } - function getOrbitPublicKey() public view returns (string) { - require (hasUserSignedUp(msg.sender), "User hasn't signed up."); - return users[msg.sender].orbitdb.publicKey; + function getOrbitPublicKey(address userAddress) public view returns (string) { + require (hasUserSignedUp(userAddress), "User hasn't signed up."); + return users[userAddress].orbitdb.publicKey; } //TODO: encrypt using Metamask in the future - function getOrbitPrivateKey() public view returns (string) { - require (hasUserSignedUp(msg.sender), "User hasn't signed up."); - return users[msg.sender].orbitdb.privateKey; + function getOrbitPrivateKey(address userAddress) public view returns (string) { + require (hasUserSignedUp(userAddress), "User hasn't signed up."); + return users[userAddress].orbitdb.privateKey; } + function getOrbitDBInfo(address userAddress) public view returns (string, string, string, string, string) { + require (hasUserSignedUp(userAddress), "User hasn't signed up."); + return ( + users[userAddress].orbitdb.id, + users[userAddress].orbitdb.topicsDB, + users[userAddress].orbitdb.postsDB, + users[userAddress].orbitdb.publicKey, + users[userAddress].orbitdb.privateKey + ); + } //----------------------------------------POSTING---------------------------------------- diff --git a/package.json b/package.json index f0f3b4c..45e18c0 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "drizzle-react": "^1.1.1", "drizzle-react-components": "^1.1.0", "eth-block-tracker-es5": "^2.3.2", - "ipfs":"^0.28.2", - "orbit-db":"^0.19.7", + "ipfs": "^0.28.2", + "orbit-db": "^0.19.7", + "orbit-db-keystore": "^0.1.0", "prop-types": "^15.6.1", "react": "^16.3.2", "react-dom": "^16.3.2", diff --git a/src/containers/LoadingContainer.js b/src/containers/LoadingContainer.js index 4a08b5f..ff731f4 100644 --- a/src/containers/LoadingContainer.js +++ b/src/containers/LoadingContainer.js @@ -42,7 +42,7 @@ class LoadingContainer extends Component { ) } - if (!this.props.orbitDB.initialized) + if (!this.props.orbitDB.ipfsInitialized) { return(
diff --git a/src/contractReducer.js b/src/contractReducer.js new file mode 100644 index 0000000..dc79abe --- /dev/null +++ b/src/contractReducer.js @@ -0,0 +1,16 @@ +const initialState = { + grabbed: false +}; + +const contractReducer = (state = initialState, action) => { + switch (action.type) { + case 'CONTRACT_GRABBED': + return { + grabbed: true, + }; + default: + return state + } +}; + +export default contractReducer diff --git a/src/contractSaga.js b/src/contractSaga.js new file mode 100644 index 0000000..22cec1f --- /dev/null +++ b/src/contractSaga.js @@ -0,0 +1,19 @@ +import { put, takeLatest } from 'redux-saga/effects' + +let contractGrabbed=false; +let grabbedContract; + +function* grabContract({contract}) { + if(!contractGrabbed) + { + contractGrabbed=true; + grabbedContract = contract; + yield put({type: 'CONTRACT_GRABBED', ...[]}); + } +} + +function* contractSaga() { + yield takeLatest('LISTEN_FOR_EVENT', grabContract); +} + +export { contractSaga, grabbedContract }; diff --git a/src/layouts/home/HomeContainer.js b/src/layouts/home/HomeContainer.js index 44ed953..bc2ff58 100644 --- a/src/layouts/home/HomeContainer.js +++ b/src/layouts/home/HomeContainer.js @@ -14,6 +14,8 @@ class Home extends Component {

Account

Username: {this.props.user.username}

+

Account: {this.props.user.address}

+

OrbitDB: {this.props.orbitDB.id}



@@ -29,6 +31,7 @@ const mapStateToProps = state => { accounts: state.accounts, Forum: state.contracts.Forum, user: state.user, + orbitDB: state.orbitDB, drizzleStatus: state.drizzleStatus } }; diff --git a/src/reducer.js b/src/reducer.js index bf815d1..9ce40e8 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -2,12 +2,14 @@ import { combineReducers } from 'redux' import { routerReducer } from 'react-router-redux' import { drizzleReducers } from 'drizzle' import userReducer from "./userReducer"; +import contractReducer from "./contractReducer"; import orbitReducer from "./util/orbitReducer"; const reducer = combineReducers({ routing: routerReducer, user: userReducer, orbitDB: orbitReducer, + forumContract: contractReducer, ...drizzleReducers }); diff --git a/src/rootSaga.js b/src/rootSaga.js index 8206b5a..bac291f 100644 --- a/src/rootSaga.js +++ b/src/rootSaga.js @@ -1,9 +1,11 @@ import { all, fork } from 'redux-saga/effects' import { drizzleSagas } from 'drizzle' +import { contractSaga } from "./contractSaga"; import userSaga from "./userSaga"; +import orbitSaga from "./util/orbitSaga"; export default function* root() { - let sagas = [...drizzleSagas,userSaga]; + let sagas = [...drizzleSagas,userSaga,orbitSaga,contractSaga]; yield all( sagas.map(saga => fork(saga)) ) diff --git a/src/userSaga.js b/src/userSaga.js index 0ac00a3..91d3f15 100644 --- a/src/userSaga.js +++ b/src/userSaga.js @@ -1,19 +1,18 @@ import { call, put, select, takeLatest, takeEvery } from 'redux-saga/effects' +import {grabbedContract as contract} from "./contractSaga"; +const contractWasGrabbed = (state) => state.forumContract.grabbed; const accounts = (state) => state.accounts; let account; let initFlag = false; -let forumContract; -let contractGrabbed = false; - function* initUser() { if(!initFlag) { while(true) - if(contractGrabbed) + if(yield select(contractWasGrabbed)) { yield call(getUserData); initFlag=true; @@ -22,13 +21,6 @@ function* initUser() { } } -function grabContract({contract}) { - if(!contractGrabbed) - { - forumContract = contract; - contractGrabbed=true; - } -} function* updateUserData() { if(initFlag) @@ -37,14 +29,18 @@ function* updateUserData() { function* getUserData() { - account = (yield select(accounts))[0]; - forumContract.methods["hasUserSignedUp"].cacheCall(...[account]); - const txObj1 = yield call(forumContract.methods["hasUserSignedUp"], ...[account]); + const currentAccount = (yield select(accounts))[0]; + if(currentAccount!==account) + { + account = currentAccount; + yield put({type: 'ACCOUNT_CHANGED', ...[]}); + } + const txObj1 = yield call(contract.methods["hasUserSignedUp"], ...[account]); try { const callResult = yield call(txObj1.call, {address:account}); if(callResult) { - const txObj2 = yield call(forumContract.methods["getUsername"], ...[account]); + const txObj2 = yield call(contract.methods["getUsername"], ...[account]); const username = yield call(txObj2.call, {address:account}); const dispatchArgs = { address: account, @@ -67,7 +63,6 @@ function* getUserData() { function* userSaga() { - yield takeLatest('LISTEN_FOR_EVENT', grabContract); yield takeLatest("DRIZZLE_INITIALIZED", initUser); yield takeEvery("ACCOUNTS_FETCHED", updateUserData); } diff --git a/src/util/orbit.js b/src/util/orbit.js index 8a13422..db8a3cb 100644 --- a/src/util/orbit.js +++ b/src/util/orbit.js @@ -1,6 +1,7 @@ import IPFS from 'ipfs'; import OrbitDB from 'orbit-db'; - +import Keystore from 'orbit-db-keystore'; +import path from 'path'; import store from './../store'; // OrbitDB uses Pubsub which is an experimental feature @@ -17,7 +18,7 @@ const ipfsOptions = { const ipfs = new IPFS(ipfsOptions); ipfs.on('ready', async () => { - store.dispatch({type: "IPFS_READY"}); + store.dispatch({type: "IPFS_INITIALIZED"}); }); @@ -25,9 +26,25 @@ async function createDatabases() { const orbitdb = new OrbitDB(ipfs); const topicsDB = await orbitdb.keyvalue('topics'); const postsDB = await orbitdb.keyvalue('posts'); - console.log("OrbitDBs created successfully!"); + store.dispatch({type: "DATABASES_CREATED", id: orbitdb.id}); return {id: orbitdb.id, topicsDB: topicsDB.address.root, postsDB: postsDB.address.root, publicKey: orbitdb.key.getPublic('hex'), privateKey:orbitdb.key.getPrivate('hex')}; } -export { createDatabases } \ No newline at end of file +async function loadDatabases(id,topicsDB, postsDB,publicKey,privateKey) { //TODO: does this work? does IPFS need reinitializng? + let directory = "./orbitdb"; + let keystore = Keystore.create(path.join(directory, id, '/keystore')); + keystore._storage.setItem(id, JSON.stringify({ + publicKey: publicKey, + privateKey: privateKey + })); + const orbitdb = new OrbitDB(ipfs,directory,{peerId:id, keystore:keystore}); + await orbitdb.keyvalue('/orbitdb/' + topicsDB +'/topics'); + await orbitdb.keyvalue('/orbitdb/' + postsDB +'/posts'); + //todo: loadedDBs.load() (?) + store.dispatch({type: "DATABASES_LOADED", id: orbitdb.id}); +} + + + +export { createDatabases, loadDatabases } \ No newline at end of file diff --git a/src/util/orbitReducer.js b/src/util/orbitReducer.js index dd6bbbb..3f4a82e 100644 --- a/src/util/orbitReducer.js +++ b/src/util/orbitReducer.js @@ -1,17 +1,33 @@ const initialState = { - initialized: false, - databasesReady: false + ipfsInitialized: false, + ready: false, + id: null }; const orbitReducer = (state = initialState, action) => { switch (action.type) { - case 'IPFS_READY': + case 'IPFS_INITIALIZED': return { - initialized: true + ...state, + ipfsInitialized: true }; case 'DATABASES_CREATED': return { - databasesReady: true + ...state, + ready: true, + id: action.id + }; + case 'DATABASES_LOADED': + return { + ...state, + ready: true, + id: action.id + }; + case 'DATABASES_NOT_READY': + return { + ...state, + ready: false, + id: null }; default: return state diff --git a/src/util/orbitSaga.js b/src/util/orbitSaga.js new file mode 100644 index 0000000..c09ec2b --- /dev/null +++ b/src/util/orbitSaga.js @@ -0,0 +1,42 @@ +import { loadDatabases } from './../util/orbit' +import { call, put, select, takeLatest } from 'redux-saga/effects' +import {grabbedContract as contract} from "../contractSaga"; + +const accounts = (state) => state.accounts; + +let latestAccount; + +function* getOrbitDBInfo() { + yield put({type: 'ORRBIT_GETTING_INFO', ...[]}); + const account = (yield select(accounts))[0]; + if(account!==latestAccount) + { + console.log("Deleting local storage.."); + localStorage.clear(); + const txObj1 = yield call(contract.methods["hasUserSignedUp"], ...[account]); + try { + const callResult = yield call(txObj1.call, {address:account}); + if(callResult) { + const txObj2 = yield call(contract.methods["getOrbitDBInfo"], ...[account]); + const info = yield call(txObj2.call, {address: account}); + //TODO: update localStorage OrbitDB stuff + yield call(loadDatabases, info[0], info[1], info[2],info[3], info[4]); + } + else + yield put({type: 'DATABASES_NOT_READY', ...[]}); + + latestAccount=account; + } + catch (error) { + console.error(error); + yield put({type: 'ORBIT_SAGA_ERROR', ...[]}); + } + + } +} + +function* orbitSaga() { + yield takeLatest("ACCOUNT_CHANGED", getOrbitDBInfo); +} + +export default orbitSaga;