diff --git a/package.json b/package.json index 83ef85d..cee8cf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ezerous/breeze", - "version": "0.6.0", + "version": "0.7.0", "description": "A reactive data-store for OrbitDB.", "license": "MIT", "author": "Ezerous ", diff --git a/src/ipfs/ipfsActions.js b/src/ipfs/ipfsActions.js index b0857a9..4a47e7a 100644 --- a/src/ipfs/ipfsActions.js +++ b/src/ipfs/ipfsActions.js @@ -5,3 +5,5 @@ export const IPFS_FAILED = 'IPFS_FAILED'; export const IPFS_PEER_EVENT_LISTEN = 'IPFS_PEER_EVENT_LISTEN'; export const IPFS_PEER_CONNECTED = 'IPFS_PEER_CONNECTED'; export const IPFS_PEER_DISCONNECTED = 'IPFS_PEER_DISCONNECTED'; +export const IPFS_BOOTSTRAP_PEER_CONNECTED = 'IPFS_BOOTSTRAP_PEER_CONNECTED'; +export const IPFS_BOOTSTRAP_PEER_DISCONNECTED = 'IPFS_BOOTSTRAP_PEER_DISCONNECTED'; diff --git a/src/ipfs/ipfsReducer.js b/src/ipfs/ipfsReducer.js index 80833f9..6ce0db0 100644 --- a/src/ipfs/ipfsReducer.js +++ b/src/ipfs/ipfsReducer.js @@ -3,54 +3,71 @@ import { IPFS_INITIALIZED, IPFS_FAILED, IPFS_PEER_CONNECTED, - IPFS_PEER_DISCONNECTED + IPFS_PEER_DISCONNECTED, + IPFS_BOOTSTRAP_PEER_CONNECTED, + IPFS_BOOTSTRAP_PEER_DISCONNECTED } from "./ipfsActions"; import { STATUS_UNINITIALIZED, STATUS_INITIALIZING, STATUS_INITIALIZED, STATUS_FAILED } from "../constants"; const initialState = { status: STATUS_UNINITIALIZED, id: null, - peers:[] + peers:[], + bootstrapPeers:[] }; const ipfsReducer = (state = initialState, action) => { /* * IPFS Status */ - switch (action.type) { - case IPFS_INITIALIZING: + if (action.type === IPFS_INITIALIZING) { + return { + ...state, + status: STATUS_INITIALIZING + }; + } else if (action.type === IPFS_INITIALIZED) { + return { + ...state, + status: STATUS_INITIALIZED, + id: action.id + }; + } else if (action.type === IPFS_FAILED) { + return { + ...state, + status: STATUS_FAILED + }; + } else if (action.type === IPFS_PEER_CONNECTED) { + const {peerId} = action; + const index = state.peers.findIndex(peer => peer === peerId); + if (index === -1) return { ...state, - status: STATUS_INITIALIZING + peers: [...state.peers, peerId] }; - case IPFS_INITIALIZED: + return state; + } else if (action.type === IPFS_PEER_DISCONNECTED) { + const peerIndex = state.peers.findIndex(peer => peer === action.peerId); + return { + ...state, + peers: state.peers.filter((peer, index) => index !== peerIndex) + }; + } else if (action.type === IPFS_BOOTSTRAP_PEER_CONNECTED) { + const {peerId} = action; + const index = state.bootstrapPeers.findIndex(peer => peer === peerId); + if (index === -1) return { ...state, - status: STATUS_INITIALIZED, - id: action.id + bootstrapPeers: [...state.bootstrapPeers, peerId] }; - case IPFS_FAILED: - return { - ...state, - status: STATUS_FAILED - }; - case IPFS_PEER_CONNECTED: - const { peerId } = action; - const index = state.peers.findIndex(peer => peer === peerId); - if(index === -1) - return { - ...state, - peers: [...state.peers, peerId] - }; - return state; - case IPFS_PEER_DISCONNECTED: - const peerIndex = state.peers.findIndex(peer => peer === action.peerId); - return { - ...state, - peers: state.peers.filter((peer, index) => index !== peerIndex) - }; - default: - return state; + return state; + } else if (action.type === IPFS_BOOTSTRAP_PEER_DISCONNECTED) { + const peerIndex = state.bootstrapPeers.findIndex(peer => peer === action.peerId); + return { + ...state, + bootstrapPeers: state.bootstrapPeers.filter((peer, index) => index !== peerIndex) + }; + } else { + return state; } }; diff --git a/src/ipfs/ipfsSaga.js b/src/ipfs/ipfsSaga.js index 9f6393f..8639e66 100644 --- a/src/ipfs/ipfsSaga.js +++ b/src/ipfs/ipfsSaga.js @@ -1,30 +1,41 @@ -import {call, put, spawn, take} from 'redux-saga/effects' +import { call, put, spawn, take } from 'redux-saga/effects' import IPFS from 'ipfs'; - -import * as IpfsActions from "./ipfsActions"; -import {eventChannel} from "redux-saga"; +import { eventChannel } from "redux-saga"; +import { + IPFS_BOOTSTRAP_PEER_CONNECTED, + IPFS_BOOTSTRAP_PEER_DISCONNECTED, IPFS_FAILED, IPFS_INITIALIZED, IPFS_INITIALIZING, + IPFS_PEER_CONNECTED, + IPFS_PEER_DISCONNECTED, + IPFS_PEER_EVENT_LISTEN +} from "./ipfsActions"; const LOGGING_PREFIX = 'ipfsSaga: '; /* * Initialization */ +let bootstrapPeerIds = []; + export function * initializeIPFS (ipfsOptions) { try { - yield put({ type: IpfsActions.IPFS_INITIALIZING }); + yield put({ type: IPFS_INITIALIZING }); // Initialize IPFS const ipfs = yield call(IPFS.create, ipfsOptions); const { id } = yield call(ipfs.id); - yield put({ type: IpfsActions.IPFS_INITIALIZED, ipfs, id }); + // Keep a list of the initial bootstrap peers (warning: this list will not be updated with ipfs.bootstrap.add!) + const { Peers } = yield call(ipfs.bootstrap.list); + bootstrapPeerIds = Peers.map(peer => peer.getPeerId()); + + yield put({ type: IPFS_INITIALIZED, ipfs, id }); // Event channel setup yield spawn(callListenForIpfsPeerEvent, { ipfs }); return ipfs; } catch (error) { - yield put({ type: IpfsActions.IPFS_FAILED, error }); + yield put({ type: IPFS_FAILED, error }); console.error(LOGGING_PREFIX + 'IPFS Initialization error:'); console.error(error); } @@ -36,10 +47,14 @@ export function * initializeIPFS (ipfsOptions) { function createIpfsPeerChannel (ipfs){ return eventChannel(emit => { const onPeerConnected = (peerInfo) => { - emit({ type: IpfsActions.IPFS_PEER_CONNECTED, peerId: peerInfo.remotePeer.toB58String() }); + const peerId = peerInfo.remotePeer.toB58String(); + const type = bootstrapPeerIds.includes(peerId) ? IPFS_BOOTSTRAP_PEER_CONNECTED : IPFS_PEER_CONNECTED; + emit({ type, peerId: peerInfo.remotePeer.toB58String() }); }; const onPeerDisconnected = (peerInfo) => { - emit({ type: IpfsActions.IPFS_PEER_DISCONNECTED, peerId: peerInfo.remotePeer.toB58String() }); + const peerId = peerInfo.remotePeer.toB58String(); + const type = bootstrapPeerIds.includes(peerId) ? IPFS_BOOTSTRAP_PEER_DISCONNECTED : IPFS_PEER_DISCONNECTED; + emit({ type, peerId: peerInfo.remotePeer.toB58String() }); }; const eventListener = ipfs.libp2p.connectionManager @@ -55,8 +70,7 @@ function createIpfsPeerChannel (ipfs){ function * callListenForIpfsPeerEvent ({ ipfs }) { const ipfsPeerChannel = yield call(createIpfsPeerChannel, ipfs); - - yield put({type: IpfsActions.IPFS_PEER_EVENT_LISTEN}); + yield put({type: IPFS_PEER_EVENT_LISTEN}); try { while (true) { diff --git a/yarn.lock b/yarn.lock index ac474d1..2fe240a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4732,9 +4732,9 @@ libp2p-websockets@^0.15.0: p-timeout "^3.2.0" libp2p@^0.30.7: - version "0.30.7" - resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-0.30.7.tgz#965fe05a9045b7614d268c4050918182d8ca81f3" - integrity sha512-W+uaMY7K9KJh9L9LFw/D2NjH63TS6skjlNRqzhG99b//IJqdNQoVWeGNGsjgMPqKu+BMngtMn+iH3+Jjz2Bk2w== + version "0.30.8" + resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-0.30.8.tgz#a06719f9dade3d886678a3cda4446f894dc3e24f" + integrity sha512-czvp/0Pyvo2tJ3n9RFdyyE05oqQEtg/etZLFjlzqYtzNn79h1UZH2cTM87F3Rm3wGUWqhEnjFZJkgHfhNE5Xdw== dependencies: "@motrix/nat-api" "^0.3.1" abort-controller "^3.0.0"