binary-com/binary-next-gen

View on GitHub
src/_reducers/TickReducer.js

Summary

Maintainability
B
6 hrs
Test Coverage
import { fromJS, List, Map } from 'immutable';
import { mergeSortedArrays, getLast } from 'binary-utils';

import {
    SERVER_DATA_TICK_STREAM,
    SERVER_DATA_TICK_HISTORY,
    UPDATE_CHART_DATA_BY_SYMBOL,
} from '../_constants/ActionTypes';

const initialState = new Map();

// it will skip merging if existing ticks already contains new ticks
export const mergeTicks = (existingTicks, newTicks) => {
    if (!existingTicks || existingTicks.length === 0) {
        return newTicks;
    }

    if (!newTicks || newTicks.length === 0) {
        return existingTicks;
    }

    const lastNewTicksEpoch = getLast(newTicks).epoch;
    const lastExistingTickEpoch = getLast(existingTicks).epoch;

    // if existing ticks contains new ticks, ignore new ticks
    if (
        newTicks[0].epoch > existingTicks[0].epoch &&
            lastNewTicksEpoch < lastExistingTickEpoch
    ) {
        return existingTicks;
    }
    return mergeSortedArrays(existingTicks, newTicks, x => x.epoch, x => x.epoch);
};

export default (state = initialState, action) => {
    switch (action.type) {
        case SERVER_DATA_TICK_STREAM: {
            const symbol = action.serverResponse.tick.symbol;
            const { tick } = action.serverResponse;

            // Do not take old tick
            const selectedSymbol = state.get(symbol);
            const latestExistingTickEpoch = selectedSymbol && selectedSymbol.takeLast(1).getIn([0, 'epoch']);
            if (latestExistingTickEpoch && latestExistingTickEpoch > +tick.epoch) {
                return state;
            }

            const newTick = {
                epoch: +tick.epoch,
                quote: +tick.quote,
            };
            return state.update(symbol, List.of(), v => v.takeLast(10000).push(fromJS(newTick)));
        }
        case SERVER_DATA_TICK_HISTORY: {
            const { times, prices } = action.serverResponse.history;

            const symbol = action.serverResponse.echo_req.ticks_history;

            const formattedHistory = times.map((t, idx) => {
                const quote = prices[idx];
                return { epoch: +t, quote: +quote };
            });

            const liveTicks = state.get(symbol) ? state.get(symbol).toJS() : [];
            const merged = mergeTicks(liveTicks, formattedHistory);
            if (merged.length === liveTicks.length) {
                return state;
            }
            return state.set(symbol, fromJS(merged));
        }
        case UPDATE_CHART_DATA_BY_SYMBOL: {
            const { symbol, data, dataType } = action;
            if (dataType !== 'ticks') {
                return state;
            }
            const liveTicks = state.get(symbol) ? state.get(symbol).toJS() : [];
            const merged = mergeTicks(liveTicks, data);
            if (merged.length === liveTicks.length) {
                return state;
            }
            return state.set(symbol, fromJS(merged));
        }
        default:
            return state;
    }
};