From 1a0542dad8d841959a409f1dc55a3e5fb53d30c9 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 12 Nov 2020 16:45:28 +0200 Subject: [PATCH] Add ability to remove databases --- src/Breeze.js | 9 +++++-- src/index.js | 5 +++- src/orbit/orbitActions.js | 13 +++++++++- src/orbit/orbitConstants.js | 1 + src/orbit/orbitReducer.js | 44 +++++++++++++++++++++------------ src/orbit/orbitSaga.js | 49 ++++++++++++++++++++++++++++++++----- src/orbit/orbitUtils.js | 5 ++++ 7 files changed, 101 insertions(+), 25 deletions(-) create mode 100644 src/orbit/orbitUtils.js diff --git a/src/Breeze.js b/src/Breeze.js index d16923d..c62861f 100644 --- a/src/Breeze.js +++ b/src/Breeze.js @@ -1,7 +1,7 @@ import { BREEZE_INITIALIZING } from "./breezeStatus/breezeActions" import defaultOptions from "./misc/defaultOptions"; import merge from "./misc/mergeUtils" -import {addOrbitDB, orbitInit} from "./orbit/orbitActions"; +import {addOrbitDB, removeOrbitDB, orbitInit} from "./orbit/orbitActions"; // Load as promise so that async Breeze initialization can still resolve const isEnvReadyPromise = new Promise((resolve) => { @@ -41,10 +41,15 @@ class Breeze { this.store.dispatch(orbitInit(this, id)); } - // dbInfo = {name, type} (where name can also be an address) + // dbInfo = {address, type} (where address can also be a name) addOrbitDB (dbInfo){ this.store.dispatch(addOrbitDB(dbInfo)); } + + // dbInfo = {address[, type]} (where address can also be a name, in which case type must be supplied) + removeOrbitDB (dbInfo){ + this.store.dispatch(removeOrbitDB(dbInfo)); + } } export default Breeze diff --git a/src/index.js b/src/index.js index c286ddb..d4e7167 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,8 @@ import * as OrbitActions from './orbit/orbitActions' import * as breezeConstants from './constants' import * as orbitConstants from './orbit/orbitConstants' +import * as orbitUtils from './orbit/orbitUtils' + const breezeReducers = { breezeStatus: breezeStatusReducer, ipfs: ipfsReducer, @@ -34,6 +36,7 @@ export { breezeActions, breezeReducers, breezeSagas, - orbitConstants + orbitConstants, + orbitUtils } diff --git a/src/orbit/orbitActions.js b/src/orbit/orbitActions.js index 939a446..397a502 100644 --- a/src/orbit/orbitActions.js +++ b/src/orbit/orbitActions.js @@ -11,9 +11,12 @@ export const ORBIT_IDENTITY_PROVIDER_FAILED = 'ORBIT_IDENTITY_PROVIDER_FAILED'; // Database Status export const ORBIT_DB_ADD = 'ORBIT_DB_ADD'; export const ORBIT_DB_ADDED = 'ORBIT_DB_ADDED'; +export const ORBIT_DB_REMOVE = 'ORBIT_DB_REMOVE'; +export const ORBIT_DB_REMOVED = 'ORBIT_DB_REMOVED'; export const ORBIT_DB_ALREADY_ADDED = 'ORBIT_DB_ALREADY_ADDED'; -export const ORBIT_DB_FAILED = 'ORBIT_DB_FAILED'; +export const ORBIT_DB_ALREADY_REMOVED = 'ORBIT_DB_ALREADY_REMOVED'; export const ORBIT_DB_LISTEN = 'ORBIT_DB_LISTEN'; +export const ORBIT_DB_ERROR = 'ORBIT_DB_ERROR'; // Database Events export const ORBIT_DB_READY = 'ORBIT_DB_READY'; @@ -37,3 +40,11 @@ export function addOrbitDB (dbInfo) { } } +// dbInfo = {address, type} (where address can also be a name) +export function removeOrbitDB (dbInfo) { + return { + type: ORBIT_DB_REMOVE, + dbInfo + } +} + diff --git a/src/orbit/orbitConstants.js b/src/orbit/orbitConstants.js index 987efd7..5efa43f 100644 --- a/src/orbit/orbitConstants.js +++ b/src/orbit/orbitConstants.js @@ -4,3 +4,4 @@ export const DB_STATUS_READY = 'ready'; export const DB_STATUS_REPLICATING = 'replicating'; export const DB_STATUS_REPLICATED = 'replicated'; export const DB_STATUS_WRITTEN = 'written'; +export const DB_STATUS_REMOVED = 'removed'; diff --git a/src/orbit/orbitReducer.js b/src/orbit/orbitReducer.js index 57d71a1..8797364 100644 --- a/src/orbit/orbitReducer.js +++ b/src/orbit/orbitReducer.js @@ -1,6 +1,7 @@ import { ORBIT_DB_ADDED, ORBIT_DB_READY, + ORBIT_DB_REMOVED, ORBIT_DB_REPLICATED, ORBIT_DB_REPLICATING, ORBIT_INITIALIZING, @@ -14,7 +15,8 @@ import { DB_STATUS_READY, DB_STATUS_REPLICATED, DB_STATUS_REPLICATING, - DB_STATUS_WRITTEN + DB_STATUS_WRITTEN, + DB_STATUS_REMOVED } from "./orbitConstants"; import {STATUS_INITIALIZING, STATUS_INITIALIZED, STATUS_FAILED } from "../constants"; @@ -51,30 +53,42 @@ const orbitReducer = (state = initialState, action) => { return newDatabasesStatus(state, action, DB_STATUS_REPLICATED); case ORBIT_DB_WRITE: return newDatabasesStatus(state, action, DB_STATUS_WRITTEN); + case ORBIT_DB_REMOVED: + return newDatabasesStatus(state, action, DB_STATUS_REMOVED); default: return state; } }; function newDatabasesStatus (state, action, status) { - const { timestamp, database: {id} } = action; - // Previous values, if exist - const lastReplication = state.databases[id] ? state.databases[id].lastReplication : null; - const lastWrite = state.databases[id] ? state.databases[id].lastWrite : null; + if(status !== DB_STATUS_REMOVED){ + const { timestamp, database: {id} } = action; + // Previous values, if exist + const lastReplication = state.databases[id] ? state.databases[id].lastReplication : null; + const lastWrite = state.databases[id] ? state.databases[id].lastWrite : null; - return { - ...state, - databases:{ - ...state.databases, - [id]: { - ...state.databases[id], - status, - timestamp, - lastReplication: status === DB_STATUS_REPLICATED ? timestamp : lastReplication, - lastWrite: status === DB_STATUS_WRITTEN ? timestamp : lastWrite, + return { + ...state, + databases:{ + ...state.databases, + [id]: { + ...state.databases[id], + status, + timestamp, + lastReplication: status === DB_STATUS_REPLICATED ? timestamp : lastReplication, + lastWrite: status === DB_STATUS_WRITTEN ? timestamp : lastWrite, + } } } } + else{ + const { address } = action; + const {[address]: _, ...remainingDBs} = state.databases; + return { + ...state, + databases: remainingDBs + } + } } export default orbitReducer; diff --git a/src/orbit/orbitSaga.js b/src/orbit/orbitSaga.js index 8ea5934..fb4820d 100644 --- a/src/orbit/orbitSaga.js +++ b/src/orbit/orbitSaga.js @@ -6,9 +6,12 @@ import Identities from 'orbit-db-identity-provider' import { ORBIT_DB_ADDED, ORBIT_DB_ADD, - ORBIT_DB_FAILED, + ORBIT_DB_ALREADY_ADDED, + ORBIT_DB_ERROR, ORBIT_DB_LISTEN, ORBIT_DB_READY, + ORBIT_DB_REMOVE, + ORBIT_DB_REMOVED, ORBIT_DB_REPLICATED, ORBIT_DB_REPLICATING, ORBIT_DB_WRITE, @@ -17,9 +20,11 @@ import { ORBIT_IDENTITY_PROVIDER_FAILED, ORBIT_INIT_FAILED, ORBIT_INITIALIZED, - ORBIT_INITIALIZING, ORBIT_DB_ALREADY_ADDED + ORBIT_INITIALIZING, ORBIT_DB_ALREADY_REMOVED, } from './orbitActions'; +import { determineDBAddress }from "./orbitUtils"; + const LOGGING_PREFIX = 'orbitSaga: '; let orbit = {}; @@ -73,7 +78,8 @@ function * initOrbit(action) { let databases = new Set(); /* - * Adds an Orbit database to the set of the tracked databases. The database is created and loaded, with an event channel + * Adds an Orbit database to the set of the tracked databases. + * The database is created and loaded, with an event channel * that listens to emitted events and dispatches corresponding actions. * dbInfo = {address, type} (where address can also be a name) */ @@ -81,7 +87,7 @@ function * addDatabase({dbInfo}) { try { let {address, type} = dbInfo; if(!OrbitDB.isValidAddress(address)) - address = yield call([orbit, orbit.determineAddress],...[address, type]); + address = yield call(determineDBAddress,{orbit, name: address, type}); const { size } = databases; databases.add(address); @@ -104,8 +110,38 @@ function * addDatabase({dbInfo}) { else yield put({ type: ORBIT_DB_ALREADY_ADDED, address }); } catch (error) { - yield put({ type: ORBIT_DB_FAILED, error }); - console.error(LOGGING_PREFIX + 'OrbitDB database creation error:'); + yield put({ type: ORBIT_DB_ERROR, error }); + console.error(LOGGING_PREFIX + 'OrbitDB database adding error:'); + console.error(error); + } +} + +/* + * Removes an Orbit database from the set of the tracked databases. + * The database is closed. + * dbInfo = {address[, type]} (where address can also be a name, in which case type must be supplied) + */ +function * removeDatabase({dbInfo}) { + try { + let {address, type} = dbInfo; + if(!OrbitDB.isValidAddress(address)) + address = yield call(determineDBAddress,{orbit, name: address, type}); + + const store = orbit.stores[address]; + + if(databases.has(address)) { + databases.delete(address); + + if(store){ + yield call([store, store.close]); + yield put({ type: ORBIT_DB_REMOVED, address }); + return; + } + } + yield put({ type: ORBIT_DB_ALREADY_REMOVED, address }); //or never existed + } catch (error) { + yield put({ type: ORBIT_DB_ERROR, error }); + console.error(LOGGING_PREFIX + 'OrbitDB database removing error:'); console.error(error); } } @@ -162,6 +198,7 @@ function * callListenForOrbitDatabaseEvent ({ database }) { function * orbitSaga () { yield takeLatest(ORBIT_INITIALIZING, initOrbit); yield takeEvery(ORBIT_DB_ADD, addDatabase); + yield takeEvery(ORBIT_DB_REMOVE, removeDatabase); } export default orbitSaga diff --git a/src/orbit/orbitUtils.js b/src/orbit/orbitUtils.js new file mode 100644 index 0000000..3abc82e --- /dev/null +++ b/src/orbit/orbitUtils.js @@ -0,0 +1,5 @@ +export async function determineDBAddress({ orbit, name, type, identityId }) { + const options = identityId ? {accessController: { write: [identityId] } } : {}; + const ipfsMultihash = (await orbit.determineAddress(name, type, options)).root; + return `/orbitdb/${ipfsMultihash}/${name}`; +}