org.duniter.client.actions.NetworkAction.java Source code

Java tutorial

Introduction

Here is the source code for org.duniter.client.actions.NetworkAction.java

Source

package org.duniter.client.actions;

/*
 * #%L
 * Duniter4j :: Client
 * %%
 * Copyright (C) 2014 - 2017 EIS
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.beust.jcommander.ParametersDelegate;
import dnl.utils.text.table.TextTable;
import org.duniter.client.actions.params.PeerParameters;
import org.duniter.client.actions.utils.RegexAnsiConsole;
import org.duniter.client.actions.utils.Formatters;
import org.apache.commons.io.IOUtils;
import org.duniter.core.client.config.Configuration;
import org.duniter.core.client.config.ConfigurationOption;
import org.duniter.core.client.model.local.Peer;
import org.duniter.core.client.service.ServiceLocator;
import org.duniter.core.client.service.local.NetworkService;
import org.duniter.core.util.CollectionUtils;
import org.duniter.core.util.FileUtils;
import org.fusesource.jansi.Ansi;
import org.nuiton.i18n.I18n;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by blavenie on 22/03/17.
 */
@Parameters(resourceBundle = "i18n.duniter4j-client", commandDescription = "Display network peers", commandDescriptionKey = "duniter4j.client.network.action")
public class NetworkAction extends AbstractAction {

    @ParametersDelegate
    public PeerParameters peerParameters = new PeerParameters();

    @Parameter(names = "--continue", description = "Continue scanning ?", descriptionKey = "duniter4j.client.network.params.continue")
    private boolean autoRefresh = false;

    @Parameter(names = "--output", description = "Output file (CSV format)", descriptionKey = "duniter4j.client.network.params.output")
    private File outputFile = null;

    private RegexAnsiConsole console;

    private DateFormat dateFormat;

    public NetworkAction() {
        super();
    }

    @Override
    public void run() {

        peerParameters.parse();
        final Peer mainPeer = peerParameters.getPeer();
        checkOutputFileIfNotNull(); // make sure the file (if any) is writable

        // Reducing node timeout when broadcast
        if (peerParameters.timeout != null) {
            Configuration.instance().getApplicationConfig().setOption(ConfigurationOption.NETWORK_TIMEOUT.getKey(),
                    peerParameters.timeout.toString());
        }

        dateFormat = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.MEDIUM,
                I18n.getDefaultLocale());

        console = new RegexAnsiConsole();
        System.setOut(console);

        log.info(I18n.t("duniter4j.client.network.loadingPeers"));

        NetworkService service = ServiceLocator.instance().getNetworkService();

        if (!autoRefresh) {
            List<Peer> peers = service.getPeers(mainPeer);
            showPeersTable(peers, false);
        } else {
            service.addPeersChangeListener(mainPeer, peers -> showPeersTable(peers, true));

            try {
                while (true) {
                    Thread.sleep(10000); // 10 s
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    /* -- protected methods -- */

    public void showPeersTable(Collection<Peer> peers, boolean clearConsole) {

        // Clearing console
        if (clearConsole) {
            clearConsole();
        }

        if (CollectionUtils.isEmpty(peers)) {
            console.println(I18n.t("duniter4j.client.network.noPeers"));
            return;
        }

        Peer mainConsensusPeer = peers.iterator().next();
        Peer.Stats mainConsensusStats = mainConsensusPeer.getStats();
        if (mainConsensusStats.isMainConsensus()) {
            Long mediantTime = mainConsensusStats.getMedianTime();
            String medianTime = dateFormat.format(new Date(mediantTime * 1000));
            String mainBuid = formatBuid(mainConsensusStats);

            console.reset().fgString(I18n.t("duniter4j.client.network.ssl"), Ansi.Color.MAGENTA)
                    .fgString(I18n.t("duniter4j.client.network.mirror"), Ansi.Color.CYAN)
                    .fgString(mainBuid, Ansi.Color.GREEN).fgString(medianTime, Ansi.Color.GREEN);

            peers.stream().filter(peer -> peer.getStats().isForkConsensus())
                    .map(peer -> formatBuid(peer.getStats())).forEach(forkConsensusBuid -> console
                            .fgString(Formatters.formatBuid(forkConsensusBuid), Ansi.Color.YELLOW));

            // Log blockchain info
            console.println("\t" + I18n.t("duniter4j.client.network.header", mainBuid, medianTime,
                    mainConsensusStats.getConsensusPct()));
        }

        String[] columnNames = { "Uid", "Pubkey", "Address", "Status", "API", "Version", "Difficulty", "Block #" };

        List<Object[]> data = peers.stream().map(peer -> {
            boolean isUp = peer.getStats().getStatus() == Peer.PeerStatus.UP;
            return new Object[] { Formatters.formatUid(peer.getStats().getUid()),
                    Formatters.formatPubkey(peer.getPubkey()), peer.getHost() + ":" + peer.getPort(),
                    peer.getStats().getStatus().name(),
                    isUp && peer.isUseSsl() ? I18n.t("duniter4j.client.network.ssl") : "",
                    isUp ? peer.getStats().getVersion() : "",
                    (isUp && peer.getStats().getHardshipLevel() != null) ? peer.getStats().getHardshipLevel()
                            : I18n.t("duniter4j.client.network.mirror"),
                    isUp ? formatBuid(peer.getStats()) : "" };
        }).collect(Collectors.toList());

        Object[][] rows = new Object[data.size()][];
        int i = 0;
        for (Object[] row : data) {
            rows[i++] = row;
        }

        TextTable tt = new TextTable(columnNames, rows);

        // Write result to filCSV
        if (outputFile != null) {
            checkOutputFileIfNotNull();

            OutputStream os = null;
            try {
                os = new BufferedOutputStream(new FileOutputStream(outputFile));
                tt.toCsv(os);
                os.flush();
            } catch (IOException e) {
                fail(e);
            } finally {
                IOUtils.closeQuietly(os);
            }
        }

        // Print result to console
        else {
            // this adds the numbering on the left
            tt.setAddRowNumbering(true);
            tt.printTable(console, 0);
        }
    }

    protected void checkOutputFileIfNotNull() {
        if (outputFile != null) {
            if (outputFile.getParentFile() != null && !outputFile.getParentFile().exists()) {
                try {
                    FileUtils.forceMkdir(outputFile.getParentFile());
                } catch (IOException e) {
                    fail(e);
                }
            }

            if (outputFile.exists()) {
                if (!outputFile.delete() && !outputFile.canWrite()) {
                    fail(I18n.t("duniter4j.client.network.error.outputFieNotWritable"));
                }
            }
        }
    }

    protected void clearConsole() {
        console.eraseScreen();
    }

    protected String formatBuid(Peer.Stats stats) {
        return Formatters.formatBuid(stats.getBlockNumber() + "-" + stats.getBlockHash());
    }
}