New block Header ws API + Client
This commit is contained in:
parent
6243d7c453
commit
bfd123b133
|
@ -18,6 +18,8 @@ export const RECEIVE_BLOCKS_ERROR = 'RECEIVE_BLOCKS_ERROR';
|
||||||
export const FETCH_TRANSACTIONS = 'FETCH_TRANSACTIONS';
|
export const FETCH_TRANSACTIONS = 'FETCH_TRANSACTIONS';
|
||||||
export const RECEIVE_TRANSACTIONS = 'RECEIVE_TRANSACTIONS';
|
export const RECEIVE_TRANSACTIONS = 'RECEIVE_TRANSACTIONS';
|
||||||
export const RECEIVE_TRANSACTIONS_ERROR = 'RECEIVE_TRANSACTIONS_ERROR';
|
export const RECEIVE_TRANSACTIONS_ERROR = 'RECEIVE_TRANSACTIONS_ERROR';
|
||||||
|
// BlockHeader
|
||||||
|
export const INIT_BLOCK_HEADER = 'INIT_BLOCK_HEADER';
|
||||||
|
|
||||||
export function fetchAccounts() {
|
export function fetchAccounts() {
|
||||||
return {
|
return {
|
||||||
|
@ -119,3 +121,9 @@ export function receiveTransactionsError() {
|
||||||
type: RECEIVE_TRANSACTIONS_ERROR
|
type: RECEIVE_TRANSACTIONS_ERROR
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initBlockHeader(){
|
||||||
|
return {
|
||||||
|
type: INIT_BLOCK_HEADER
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import constants from '../constants';
|
import constants from '../constants';
|
||||||
|
|
||||||
const BASE_URL = 'http://localhost:8000/embark-api';
|
|
||||||
|
|
||||||
export function fetchAccounts() {
|
export function fetchAccounts() {
|
||||||
return axios.get(constants.httpEndpoint + '/blockchain/accounts');
|
return axios.get(`${constants.httpEndpoint}/blockchain/accounts`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchBlocks(from) {
|
export function fetchBlocks(from) {
|
||||||
return axios.get(`${BASE_URL}/blockchain/blocks`, {params: {from}});
|
return axios.get(`${constants.httpEndpoint}/blockchain/blocks`, {params: {from}});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchTransactions(blockFrom) {
|
export function fetchTransactions(blockFrom) {
|
||||||
return axios.get(`${BASE_URL}/blockchain/transactions`, {params: {blockFrom}});
|
return axios.get(`${constants.httpEndpoint}/blockchain/transactions`, {params: {blockFrom}});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchProcesses() {
|
export function fetchProcesses() {
|
||||||
return axios.get(constants.httpEndpoint + '/processes');
|
return axios.get(`${constants.httpEndpoint}/processes`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchProcessLogs(processName) {
|
export function fetchProcessLogs(processName) {
|
||||||
return axios.get(`${constants.httpEndpoint}/process-logs/${processName}`);
|
return axios.get(`${constants.httpEndpoint}/process-logs/${processName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function webSocketBlockHeader() {
|
||||||
|
return new WebSocket(`${constants.wsEndpoint}/blockchain/blockHeader`);
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
import {ConnectedRouter} from "connected-react-router";
|
import {ConnectedRouter} from "connected-react-router";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import {connect} from 'react-redux';
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
|
|
||||||
import history from '../history';
|
import history from '../history';
|
||||||
import Layout from '../components/Layout';
|
import Layout from '../components/Layout';
|
||||||
import routes from '../routes';
|
import routes from '../routes';
|
||||||
|
import {initBlockHeader} from '../actions';
|
||||||
|
|
||||||
class AppContainer extends Component {
|
class AppContainer extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.initBlockHeader();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ConnectedRouter history={history}>
|
<ConnectedRouter history={history}>
|
||||||
|
@ -17,4 +24,13 @@ class AppContainer extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppContainer;
|
AppContainer.propTypes = {
|
||||||
|
initBlockHeader: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
initBlockHeader
|
||||||
|
},
|
||||||
|
)(AppContainer);
|
||||||
|
|
|
@ -9,9 +9,7 @@ import LoadMore from '../components/LoadMore';
|
||||||
|
|
||||||
class BlocksContainer extends Component {
|
class BlocksContainer extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!this.props.blocks.data) {
|
this.props.fetchBlocks();
|
||||||
this.props.fetchBlocks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMore() {
|
loadMore() {
|
||||||
|
|
|
@ -9,9 +9,7 @@ import LoadMore from '../components/LoadMore';
|
||||||
|
|
||||||
class TransactionsContainer extends Component {
|
class TransactionsContainer extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!this.props.transactions.data) {
|
this.props.fetchTransactions();
|
||||||
this.props.fetchTransactions();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMore() {
|
loadMore() {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {RECEIVE_ACCOUNTS, RECEIVE_ACCOUNTS_ERROR} from "../actions";
|
||||||
export default function accounts(state = {}, action) {
|
export default function accounts(state = {}, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case RECEIVE_ACCOUNTS:
|
case RECEIVE_ACCOUNTS:
|
||||||
return {...state, data: [...state.data || [], ...action.accounts.data]};
|
return Object.assign({}, state, {data: action.accounts.data});
|
||||||
case RECEIVE_ACCOUNTS_ERROR:
|
case RECEIVE_ACCOUNTS_ERROR:
|
||||||
return Object.assign({}, state, {error: true});
|
return Object.assign({}, state, {error: true});
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -3,7 +3,11 @@ import {RECEIVE_BLOCKS, RECEIVE_BLOCKS_ERROR} from "../actions";
|
||||||
export default function blocks(state = {}, action) {
|
export default function blocks(state = {}, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case RECEIVE_BLOCKS:
|
case RECEIVE_BLOCKS:
|
||||||
return {...state, data: [...state.data || [], ...action.blocks.data]};
|
return {
|
||||||
|
...state, data: [...state.data || [], ...action.blocks.data]
|
||||||
|
.filter((block, index, self) => index === self.findIndex((t) => t.number === block.number))
|
||||||
|
.sort((a, b) => b.number - a.number)
|
||||||
|
};
|
||||||
case RECEIVE_BLOCKS_ERROR:
|
case RECEIVE_BLOCKS_ERROR:
|
||||||
return Object.assign({}, state, {error: true});
|
return Object.assign({}, state, {error: true});
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
import {RECEIVE_TRANSACTIONS, RECEIVE_TRANSACTIONS_ERROR} from "../actions";
|
import {RECEIVE_TRANSACTIONS, RECEIVE_TRANSACTIONS_ERROR} from "../actions";
|
||||||
|
|
||||||
|
const BN_FACTOR = 10000;
|
||||||
|
|
||||||
export default function transactions(state = {}, action) {
|
export default function transactions(state = {}, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case RECEIVE_TRANSACTIONS:
|
case RECEIVE_TRANSACTIONS:
|
||||||
return {...state, data: [...state.data || [], ...action.transactions.data]};
|
return {
|
||||||
|
...state, data: [...state.data || [], ...action.transactions.data]
|
||||||
|
.filter((tx, index, self) => index === self.findIndex((t) => (
|
||||||
|
t.blockNumber === tx.blockNumber && t.transactionIndex === tx.transactionIndex
|
||||||
|
)))
|
||||||
|
.sort((a, b) => (
|
||||||
|
((BN_FACTOR * b.blockNumber) + b.transactionIndex) - ((BN_FACTOR * a.blockNumber) + a.transactionIndex))
|
||||||
|
)
|
||||||
|
};
|
||||||
case RECEIVE_TRANSACTIONS_ERROR:
|
case RECEIVE_TRANSACTIONS_ERROR:
|
||||||
return Object.assign({}, state, {error: true});
|
return Object.assign({}, state, {error: true});
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as actions from '../actions';
|
import * as actions from '../actions';
|
||||||
import * as api from '../api';
|
import * as api from '../api';
|
||||||
import {all, call, fork, put, takeEvery} from 'redux-saga/effects';
|
import {eventChannel} from 'redux-saga';
|
||||||
|
import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects';
|
||||||
|
|
||||||
export function *fetchTransactions(payload) {
|
export function *fetchTransactions(payload) {
|
||||||
try {
|
try {
|
||||||
|
@ -67,8 +68,34 @@ export function *watchFetchProcessLogs() {
|
||||||
yield takeEvery(actions.FETCH_PROCESS_LOGS, fetchProcessLogs);
|
yield takeEvery(actions.FETCH_PROCESS_LOGS, fetchProcessLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createChannel(socket) {
|
||||||
|
return eventChannel(emit => {
|
||||||
|
socket.onmessage = ((message) => {
|
||||||
|
emit(JSON.parse(message.data));
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
socket.close();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function *initBlockHeader() {
|
||||||
|
const socket = api.webSocketBlockHeader();
|
||||||
|
const channel = yield call(createChannel, socket);
|
||||||
|
while (true) {
|
||||||
|
yield take(channel);
|
||||||
|
yield put({type: actions.FETCH_BLOCKS});
|
||||||
|
yield put({type: actions.FETCH_TRANSACTIONS});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function *watchInitBlockHeader() {
|
||||||
|
yield takeEvery(actions.INIT_BLOCK_HEADER, initBlockHeader);
|
||||||
|
}
|
||||||
|
|
||||||
export default function *root() {
|
export default function *root() {
|
||||||
yield all([
|
yield all([
|
||||||
|
fork(watchInitBlockHeader),
|
||||||
fork(watchFetchAccounts),
|
fork(watchFetchAccounts),
|
||||||
fork(watchFetchProcesses),
|
fork(watchFetchProcesses),
|
||||||
fork(watchFetchProcessLogs),
|
fork(watchFetchProcessLogs),
|
||||||
|
|
|
@ -138,8 +138,10 @@ class BlockchainConnector {
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
self.provider.fundAccounts(() => {
|
self.provider.fundAccounts(() => {
|
||||||
self._emitWeb3Ready();
|
self.isWeb3Ready = true;
|
||||||
cb();
|
self.events.emit(WEB3_READY);
|
||||||
|
self.registerWeb3Object();
|
||||||
|
self.subscribeToNewBlockHeaders();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -320,9 +322,7 @@ class BlockchainConnector {
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function () {
|
], eachCb);
|
||||||
eachCb();
|
|
||||||
});
|
|
||||||
}, function () {
|
}, function () {
|
||||||
res.send(results);
|
res.send(results);
|
||||||
});
|
});
|
||||||
|
@ -349,6 +349,17 @@ class BlockchainConnector {
|
||||||
self.getTransactions(blockFrom, blockLimit, res.send.bind(res));
|
self.getTransactions(blockFrom, blockLimit, res.send.bind(res));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
plugin.registerAPICall(
|
||||||
|
'ws',
|
||||||
|
'/embark-api/blockchain/blockHeader',
|
||||||
|
(ws) => {
|
||||||
|
self.events.on('blockchain:newBlockHeaders', (block) => {
|
||||||
|
ws.send(JSON.stringify({block: block}), () => {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTransactions(blockFrom, blockLimit, callback) {
|
getTransactions(blockFrom, blockLimit, callback) {
|
||||||
|
@ -393,6 +404,17 @@ class BlockchainConnector {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscribeToNewBlockHeaders() {
|
||||||
|
let self = this;
|
||||||
|
self.web3.eth.subscribe("newBlockHeaders", (err) => {
|
||||||
|
if (err) {
|
||||||
|
self.logger.error(err.message);
|
||||||
|
}
|
||||||
|
}).on("data", (block) => {
|
||||||
|
self.events.emit("blockchain:newBlockHeaders", block);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
defaultAccount() {
|
defaultAccount() {
|
||||||
return this.web3.eth.defaultAccount;
|
return this.web3.eth.defaultAccount;
|
||||||
|
|
|
@ -4,8 +4,8 @@ module.exports = {
|
||||||
// Blockchain node to deploy the contracts
|
// Blockchain node to deploy the contracts
|
||||||
deployment: {
|
deployment: {
|
||||||
host: "localhost", // Host of the blockchain node
|
host: "localhost", // Host of the blockchain node
|
||||||
port: 8545, // Port of the blockchain node
|
port: 8546, // Port of the blockchain node
|
||||||
type: "rpc" // Type of connection (ws or rpc),
|
type: "ws" // Type of connection (ws or rpc),
|
||||||
// Accounts to use instead of the default account to populate your wallet
|
// Accounts to use instead of the default account to populate your wallet
|
||||||
/*,accounts: [
|
/*,accounts: [
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue