Browse Source

Version 0.4.0

master v0.4.0
Ezerous 4 years ago
parent
commit
6ccec8f34d
  1. 4
      package.json
  2. 34
      src/Breeze.js
  3. 5
      src/index.js
  4. 37
      src/orbit/orbitActions.js
  5. 1
      src/orbit/orbitConstants.js
  6. 64
      src/orbit/orbitReducer.js
  7. 100
      src/orbit/orbitSaga.js
  8. 5
      src/orbit/orbitUtils.js
  9. 1881
      yarn.lock

4
package.json

@ -1,6 +1,6 @@
{
"name": "@ezerous/breeze",
"version": "0.3.0",
"version": "0.4.0",
"description": "A reactive data-store for OrbitDB.",
"license": "MIT",
"author": "Ezerous <ezerous@gmail.com>",
@ -8,7 +8,7 @@
"repository": "github:Ezerous/breeze",
"dependencies": {
"deepmerge": "~4.2.2",
"ipfs": "~0.51.0",
"ipfs": "~0.52.0",
"is-plain-object": "~5.0.0",
"orbit-db": "~0.26.0",
"orbit-db-identity-provider": "~0.3.1",

34
src/Breeze.js

@ -1,20 +1,19 @@
import { BREEZE_INITIALIZING } from './breezeStatus/breezeActions'
import { BREEZE_INITIALIZING } from "./breezeStatus/breezeActions"
import defaultOptions from "./misc/defaultOptions";
import merge from './misc/mergeUtils'
import {createOrbitDatabase, orbitInit} from "./orbit/orbitActions";
import merge from "./misc/mergeUtils"
import {addOrbitDB, removeOrbitDB, orbitInit} from "./orbit/orbitActions";
// Load as promise so that async Breeze initialization can still resolve
const isEnvReadyPromise = new Promise((resolve) => {
const hasWindow = typeof window !== 'undefined'
const hasDocument = typeof document !== 'undefined'
const hasWindow = typeof window !== 'undefined';
const hasDocument = typeof document !== 'undefined';
if (hasWindow)
return window.addEventListener('load', resolve)
return window.addEventListener('load', resolve);
// Resolve in any case if we missed the load event and the document is already loaded
if (hasDocument && document.readyState === `complete`) {
return resolve()
}
if (hasDocument && document.readyState === `complete`)
return resolve();
})
class Breeze {
@ -28,9 +27,9 @@ class Breeze {
this.ipfsOptions = options.ipfs;
this.orbitOptions = options.orbit;
// Wait for window load event in case of injected web3.
// Wait for window load event
isEnvReadyPromise.then(() => {
// Begin Breeze initialization.
// Begin Breeze initialization
this.store.dispatch({
type: BREEZE_INITIALIZING,
breeze: this
@ -39,12 +38,17 @@ class Breeze {
}
initOrbit(id) {
this.store.dispatch(orbitInit (this, id));
this.store.dispatch(orbitInit(this, id));
}
// dbInfo = {address, type} (where address can also be a name)
addOrbitDB (dbInfo){
this.store.dispatch(addOrbitDB(dbInfo));
}
// db = {name, type}
createOrbitDatabase (db){
this.store.dispatch(createOrbitDatabase (this.orbit, db));
// dbInfo = {address[, type]} (where address can also be a name, in which case type must be supplied)
removeOrbitDB (dbInfo){
this.store.dispatch(removeOrbitDB(dbInfo));
}
}

5
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
}

37
src/orbit/orbitActions.js

@ -9,17 +9,20 @@ export const ORBIT_IDENTITY_PROVIDER_ADDED = 'ORBIT_IDENTITY_PROVIDER_ADDED';
export const ORBIT_IDENTITY_PROVIDER_FAILED = 'ORBIT_IDENTITY_PROVIDER_FAILED';
// Database Status
export const ORBIT_DATABASE_CREATING = 'ORBIT_DATABASE_CREATING';
export const ORBIT_DATABASE_CREATED = 'ORBIT_DATABASE_CREATED';
export const ORBIT_DATABASE_ALREADY_EXISTS = 'ORBIT_DATABASE_ALREADY_EXISTS';
export const ORBIT_DATABASE_FAILED = 'ORBIT_DATABASE_FAILED';
export const ORBIT_DATABASE_LISTEN = 'ORBIT_DATABASE_LISTEN';
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_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_DATABASE_READY = 'ORBIT_DATABASE_READY';
export const ORBIT_DATABASE_REPLICATING = 'ORBIT_DATABASE_REPLICATING';
export const ORBIT_DATABASE_REPLICATED = 'ORBIT_DATABASE_REPLICATED';
export const ORBIT_DATABASE_WRITE = 'ORBIT_DATABASE_WRITE';
export const ORBIT_DB_READY = 'ORBIT_DB_READY';
export const ORBIT_DB_REPLICATING = 'ORBIT_DB_REPLICATING';
export const ORBIT_DB_REPLICATED = 'ORBIT_DB_REPLICATED';
export const ORBIT_DB_WRITE = 'ORBIT_DB_WRITE';
export function orbitInit (breeze, id) {
return {
@ -29,11 +32,19 @@ export function orbitInit (breeze, id) {
}
}
export function createOrbitDatabase (orbit, db) {
// dbInfo = {address, type} (where address can also be a name)
export function addOrbitDB (dbInfo) {
return {
type: ORBIT_DATABASE_CREATING,
orbit,
db
type: ORBIT_DB_ADD,
dbInfo
}
}
// dbInfo = {address, type} (where address can also be a name)
export function removeOrbitDB (dbInfo) {
return {
type: ORBIT_DB_REMOVE,
dbInfo
}
}

1
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';

64
src/orbit/orbitReducer.js

@ -1,12 +1,13 @@
import {
ORBIT_DATABASE_CREATED,
ORBIT_DATABASE_READY,
ORBIT_DATABASE_REPLICATED,
ORBIT_DATABASE_REPLICATING,
ORBIT_DB_ADDED,
ORBIT_DB_READY,
ORBIT_DB_REMOVED,
ORBIT_DB_REPLICATED,
ORBIT_DB_REPLICATING,
ORBIT_INITIALIZING,
ORBIT_INITIALIZED,
ORBIT_INIT_FAILED,
ORBIT_DATABASE_WRITE
ORBIT_DB_WRITE
} from "./orbitActions";
import {
@ -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";
@ -41,40 +43,52 @@ const orbitReducer = (state = initialState, action) => {
...state,
status: STATUS_FAILED
};
case ORBIT_DATABASE_CREATED:
case ORBIT_DB_ADDED:
return newDatabasesStatus(state, action, DB_STATUS_INIT);
case ORBIT_DATABASE_READY:
case ORBIT_DB_READY:
return newDatabasesStatus(state, action, DB_STATUS_READY);
case ORBIT_DATABASE_REPLICATING:
case ORBIT_DB_REPLICATING:
return newDatabasesStatus(state, action, DB_STATUS_REPLICATING);
case ORBIT_DATABASE_REPLICATED:
case ORBIT_DB_REPLICATED:
return newDatabasesStatus(state, action, DB_STATUS_REPLICATED);
case ORBIT_DATABASE_WRITE:
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;

100
src/orbit/orbitSaga.js

@ -4,25 +4,31 @@ import OrbitDB from 'orbit-db';
import Identities from 'orbit-db-identity-provider'
import {
ORBIT_DATABASE_ALREADY_EXISTS,
ORBIT_DATABASE_CREATED,
ORBIT_DATABASE_CREATING,
ORBIT_DATABASE_FAILED,
ORBIT_DATABASE_LISTEN,
ORBIT_DATABASE_READY,
ORBIT_DATABASE_REPLICATED,
ORBIT_DATABASE_REPLICATING,
ORBIT_DATABASE_WRITE,
ORBIT_DB_ADDED,
ORBIT_DB_ADD,
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,
ORBIT_IDENTITY_PROVIDER_ADD,
ORBIT_IDENTITY_PROVIDER_ADDED,
ORBIT_IDENTITY_PROVIDER_FAILED,
ORBIT_INIT_FAILED,
ORBIT_INITIALIZED,
ORBIT_INITIALIZING
ORBIT_INITIALIZING, ORBIT_DB_ALREADY_REMOVED,
} from './orbitActions';
import { determineDBAddress }from "./orbitUtils";
const LOGGING_PREFIX = 'orbitSaga: ';
let orbit = {};
/*
* Add Orbit Identity Provider
*/
@ -49,13 +55,13 @@ function * initOrbit(action) {
const identity = yield call(Identities.createIdentity, { id, type: identityProvider.type});
const orbit = yield call (OrbitDB.createInstance, ...[ipfs, { identity }]);
orbit = yield call (OrbitDB.createInstance, ...[ipfs, { identity }]);
breeze.orbit = orbit;
// Create initial databases from options
yield all(databases.map(db => {
return call(createDatabase, { orbit, db });
yield all(databases.map(dbInfo => {
return call(addDatabase, {dbInfo});
}));
yield put({ type: ORBIT_INITIALIZED, orbit });
@ -72,38 +78,73 @@ function * initOrbit(action) {
let databases = new Set();
/*
* Creates and loads an orbit database given a name and a type as its parameters
* Note: db.name can also be an OrbitDB address
* 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)
*/
function * createDatabase({ orbit, db }) {
function * addDatabase({dbInfo}) {
try {
let {address, type} = dbInfo;
if(!OrbitDB.isValidAddress(address))
address = yield call(determineDBAddress,{orbit, name: address, type});
const { size } = databases;
databases.add(orbit.id + db.name);
databases.add(address);
if (databases.size > size) {
const createdDB = yield call([orbit, orbit.open], ...[db.name, { type: db.type, create: true }]);
const createdDB = yield call([orbit, orbit.open], ...[address, { type, create: true }]);
yield put({ type: ORBIT_DATABASE_CREATED, database: createdDB, timestamp: +new Date });
yield put({ type: ORBIT_DB_ADDED, database: createdDB, timestamp: +new Date });
// Event channel setup
yield spawn(callListenForOrbitDatabaseEvent, { database: createdDB });
// Wait for event channel setup before loading
yield take(action => action.type === ORBIT_DATABASE_LISTEN && action.id === createdDB.id);
yield take(action => action.type === ORBIT_DB_LISTEN && action.id === createdDB.id);
yield call([createdDB, createdDB.load]);
return createdDB;
}
else
yield put({ type: ORBIT_DATABASE_ALREADY_EXISTS, database: db.name });
yield put({ type: ORBIT_DB_ALREADY_ADDED, address });
} catch (error) {
yield put({ type: ORBIT_DATABASE_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);
}
}
/*
* Database Events
@ -112,16 +153,16 @@ function * createDatabase({ orbit, db }) {
function createOrbitDatabaseChannel (database){
return eventChannel(emit => {
const onReady = () => {
emit({ type: ORBIT_DATABASE_READY, database, timestamp: +new Date });
emit({ type: ORBIT_DB_READY, database, timestamp: +new Date });
};
const onReplicate = () => {
emit({ type: ORBIT_DATABASE_REPLICATING, database, timestamp: +new Date });
emit({ type: ORBIT_DB_REPLICATING, database, timestamp: +new Date });
};
const onReplicated = () => {
emit({ type: ORBIT_DATABASE_REPLICATED, database, timestamp: +new Date });
emit({ type: ORBIT_DB_REPLICATED, database, timestamp: +new Date });
};
const onWrite = (address, entry) => {
emit({ type: ORBIT_DATABASE_WRITE, database, entry, timestamp: +new Date });
emit({ type: ORBIT_DB_WRITE, database, entry, timestamp: +new Date });
};
const eventListener = database.events
@ -142,7 +183,7 @@ function createOrbitDatabaseChannel (database){
function * callListenForOrbitDatabaseEvent ({ database }) {
const orbitDatabaseChannel = yield call(createOrbitDatabaseChannel, database);
yield put({type: ORBIT_DATABASE_LISTEN, id: database.id});
yield put({type: ORBIT_DB_LISTEN, id: database.id});
try {
while (true) {
@ -156,7 +197,8 @@ function * callListenForOrbitDatabaseEvent ({ database }) {
function * orbitSaga () {
yield takeLatest(ORBIT_INITIALIZING, initOrbit);
yield takeEvery(ORBIT_DATABASE_CREATING, createDatabase);
yield takeEvery(ORBIT_DB_ADD, addDatabase);
yield takeEvery(ORBIT_DB_REMOVE, removeDatabase);
}
export default orbitSaga

5
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}`;
}

1881
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save