Browse Source

Init orbit peer replication sagas

develop
Apostolos Fanakis 4 years ago
parent
commit
ec2ac7205c
  1. 36
      packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx
  2. 4
      packages/concordia-app/src/options/breezeOptions.js
  3. 9
      packages/concordia-app/src/redux/actions/peerDbReplicationActions.js
  4. 52
      packages/concordia-app/src/redux/reducers/peerDbReplicationReducer.js
  5. 100
      packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js
  6. 2
      packages/concordia-app/src/redux/sagas/rootSaga.js
  7. 5
      packages/concordia-app/src/redux/store.js

36
packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx

@ -1,14 +1,17 @@
import React, { useContext, useEffect, useState } from 'react';
import { List } from 'semantic-ui-react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import AppContext from '../../AppContext';
import { FETCH_USER_TOPIC } from '../../../redux/actions/peerDbReplicationActions';
const TopicListRow = (props) => {
const { topicData, topicId } = props;
const { breeze: { orbit } } = useContext(AppContext.Context);
const [topicSubject, setTopicSubject] = useState();
const userAddress = useSelector((state) => state.user.address);
const topics = useSelector((state) => state.orbitData.topics);
const dispatch = useDispatch();
useEffect(() => {
if (userAddress === topicData.userAddress) {
@ -18,24 +21,21 @@ const TopicListRow = (props) => {
return;
}
// TODO: this is not correct, each TopicListRow inside the TopicList overrides the on.replicated callback. As a
// result, for the topics of each user, only the callback of the last TopicListRow in the list survives and gets
// executed. Moving these calls up on the TopicList helps with this issue but introduces other problems.
orbit
.determineAddress('topics', 'keyvalue', { accessController: { write: [topicData.userAddress] } })
.then((ipfsMultihash) => {
const peerDbAddress = `/orbitdb/${ipfsMultihash.root}/topics`;
return orbit.keyvalue(peerDbAddress)
.then((keyValueStore) => {
keyValueStore.events.on('replicated', () => {
setTopicSubject(keyValueStore.get(topicId));
dispatch({
type: FETCH_USER_TOPIC,
orbit,
userAddress: topicData.userAddress,
topicId,
});
})
.catch((error) => console.error(`Error opening a peer's db: ${error}`));
})
.catch((error) => console.error(`Error opening a peer's db: ${error}`));
}, [orbit, topicData.userAddress, topicId, userAddress]);
}, [dispatch, orbit, topicData.userAddress, topicId, userAddress]);
useEffect(() => {
const topicFound = topics.find((topic) => topic.topicId === topicId);
if (topicFound) {
setTopicSubject(topicFound);
}
}, [topicId, topics]);
return (
<>

4
packages/concordia-app/src/options/breezeOptions.js

@ -32,11 +32,11 @@ const breezeOptions = {
databases: [
{
name: 'topics',
type: orbitConstants.ORBIT_TYPE_KEYVALUE,
type: 'keyvalue',
},
{
name: 'posts',
type: orbitConstants.ORBIT_TYPE_KEYVALUE,
type: 'keyvalue',
},
],
},

9
packages/concordia-app/src/redux/actions/peerDbReplicationActions.js

@ -0,0 +1,9 @@
export const FETCH_USER_TOPIC = 'FETCH_USER_TOPIC';
export const ADD_USER_TOPIC = 'ADD_USER_TOPIC';
export const UPDATE_USER_TOPICS = 'UPDATE_USER_TOPICS';
export const FETCH_USER_POST = 'FETCH_USER_POST';
export const ADD_USER_POST = 'ADD_USER_POST';
export const UPDATE_USER_POSTS = 'UPDATE_USER_POSTS';
export const UPDATE_ORBIT_DATA = 'UPDATE_ORBIT_DATA';

52
packages/concordia-app/src/redux/reducers/peerDbReplicationReducer.js

@ -0,0 +1,52 @@
import { ADD_USER_POST, ADD_USER_TOPIC, UPDATE_ORBIT_DATA } from '../actions/peerDbReplicationActions';
const initialState = {
topics: [],
posts: [],
};
const peerDbReplicationReducer = (state = initialState, action) => {
const { type } = action;
if (type === ADD_USER_TOPIC) {
const { topic } = action;
return {
...state,
topics: [
...state.topics,
topic,
],
};
}
if (type === ADD_USER_POST) {
const { post } = action;
return {
...state,
posts: [
...state.posts,
post,
],
};
}
if (type === UPDATE_ORBIT_DATA) {
const { topics, posts } = action;
return {
...state,
topics: [
...topics,
],
posts: [
...posts,
],
};
}
return state;
};
export default peerDbReplicationReducer;

100
packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js

@ -0,0 +1,100 @@
import {
call, put, select, takeEvery,
} from 'redux-saga/effects';
import {
createOrbitDatabase,
ORBIT_DATABASE_READY,
ORBIT_DATABASE_REPLICATED,
} from '@ezerous/breeze/src/orbit/orbitActions';
import determineDBAddress from '../../orbit/orbitUtils';
import {
ADD_USER_POST,
ADD_USER_TOPIC,
FETCH_USER_POST,
FETCH_USER_TOPIC,
UPDATE_ORBIT_DATA,
} from '../actions/peerDbReplicationActions';
function* fetchUserDb({ orbit, peerDbAddress }) {
yield put(createOrbitDatabase(orbit, { name: peerDbAddress, type: 'keyvalue' }));
}
function* fetchTopic({ orbit, userAddress, topicId }) {
const previousTopics = yield select((state) => state.orbitData.topics);
const peerDbAddress = yield call(determineDBAddress, {
orbit, dbName: 'topics', type: 'keyvalue', identityId: userAddress,
});
if (previousTopics === undefined || !previousTopics.some((topic) => topic.topicId === topicId)) {
yield put({
type: ADD_USER_TOPIC,
topic: {
userAddress,
dbAddress: peerDbAddress,
topicId,
subject: null,
},
});
}
yield call(fetchUserDb, { orbit, peerDbAddress });
}
function* fetchUserPost({ orbit, userAddress, postId }) {
const previousPosts = yield select((state) => state.orbitData.posts);
const peerDbAddress = yield call(determineDBAddress, {
orbit, dbName: 'posts', type: 'keyvalue', identityId: userAddress,
});
if (previousPosts === undefined || !previousPosts.some((post) => post.postId === postId)) {
yield put({
type: ADD_USER_POST,
posts: {
userAddress,
dbAddress: peerDbAddress,
postId,
subject: null,
message: null,
},
});
}
yield call(fetchUserDb, { orbit, peerDbAddress });
}
function* updateReduxState({ database }) {
const { topics, posts } = yield select((state) => ({ topics: state.orbitData.topics, posts: state.orbitData.posts }));
yield put({
type: UPDATE_ORBIT_DATA,
topics: topics.map((topic) => {
if (database.id === topic.dbAddress) {
return ({
...topic,
...database.get(topic.topicId),
});
}
return { ...topic };
}),
posts: posts.map((post) => {
if (database.id === post.dbAddress) {
return ({
...post,
...database.get(post.postId),
});
}
return { ...post };
}),
});
}
function* peerDbReplicationSaga() {
yield takeEvery(FETCH_USER_TOPIC, fetchTopic);
yield takeEvery(FETCH_USER_POST, fetchUserPost);
yield takeEvery(ORBIT_DATABASE_REPLICATED, updateReduxState);
yield takeEvery(ORBIT_DATABASE_READY, updateReduxState);
}
export default peerDbReplicationSaga;

2
packages/concordia-app/src/redux/sagas/rootSaga.js

@ -3,6 +3,7 @@ import { drizzleSagas } from '@ezerous/drizzle';
import { breezeSagas } from '@ezerous/breeze';
import orbitSaga from './orbitSaga';
import userSaga from './userSaga';
import peerDbReplicationSaga from './peerDbReplicationSaga';
export default function* root() {
const sagas = [
@ -10,6 +11,7 @@ export default function* root() {
...breezeSagas,
orbitSaga,
userSaga,
peerDbReplicationSaga,
];
yield all(
sagas.map((saga) => fork(saga)),

5
packages/concordia-app/src/redux/store.js

@ -5,6 +5,7 @@ import createSagaMiddleware from 'redux-saga';
import userReducer from './reducers/userReducer';
import rootSaga from './sagas/rootSaga';
import drizzleOptions from '../options/drizzleOptions';
import peerDbReplicationReducer from './reducers/peerDbReplicationReducer';
const initialState = {
contracts: generateContractsInitialState(drizzleOptions),
@ -13,7 +14,9 @@ const initialState = {
const sagaMiddleware = createSagaMiddleware();
const store = configureStore({
reducer: { ...drizzleReducers, ...breezeReducers, user: userReducer },
reducer: {
...drizzleReducers, ...breezeReducers, user: userReducer, orbitData: peerDbReplicationReducer,
},
middleware: getDefaultMiddleware({
// https://redux.js.org/style-guide/style-guide/#do-not-put-non-serializable-values-in-state-or-actions
serializableCheck: false,

Loading…
Cancel
Save