/* * Copyright 2018-2019 Baoyi Chen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.moilioncircle.redis.rdb.cli.util; import java.io.Closeable; import java.io.IOException; import java.util.concurrent.atomic.AtomicLong; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; /** * @author Baoyi Chen */ public class ProgressBar implements Closeable { private final long ctime; private final long total; private volatile int max = 0; private volatile boolean bit; private volatile String file; private final Terminal terminal; private volatile double percentage; private AtomicLong num = new AtomicLong(); private volatile long atime = System.currentTimeMillis(); public ProgressBar(long total) throws IOException { this.total = total; this.ctime = System.currentTimeMillis(); this.terminal = TerminalBuilder.builder().dumb(true).build(); } public void react(long num) { react(num, true, null); } public void react(long num, String file) { react(num, true, file); } public void react(long num, boolean increment, String file) { if (increment) this.num.addAndGet(num); else this.num.set(num); if (total <= 0) { show(-1, -1, this.num.get(), file); return; } double percentage = this.num.get() / (double) total * 100; int prev = (int) this.percentage; this.percentage = percentage; int next = (int) this.percentage; show(prev, next, this.num.get(), file); } private void show(int prev, int next, long num, String file) { long now = System.currentTimeMillis(); long elapsed = now - atime; if (elapsed < 1000 && prev == next && (file == null || file.equals(this.file))) return; int speed = (int) ((double) num / (now - ctime) * 1000); String strSpeed = Strings.lappend(Strings.pretty(speed), 7, ' '); this.file = file; this.atime = now; this.max = Math.max(Strings.length(file), max); int len = Math.max(terminal.getWidth(), 120); StringBuilder builder = new StringBuilder(); if (bit) { builder.append('/'); bit = false; } else { builder.append('\\'); bit = true; } builder.append('[').append(Strings.lappend(Strings.pretty(num), 7, ' ')); if (total <= 0) { if (file != null) { builder.append('|'); builder.append(Strings.lappend(file, max, ' ')); } } else { builder.append('/').append(Strings.lappend(Strings.pretty(total), 7, ' ')).append('|'); builder.append(Strings.lappend(next, 3, ' ')).append('%'); if (file != null) { builder.append('|'); builder.append(Strings.lappend(file, max, ' ')); } builder.append(']'); int used = builder.length(); if (len - used >= 30 + 5 + strSpeed.length()) { int ret = len - used - 5 - strSpeed.length(); int n = (int) (next * (ret / 100d)); builder.append('['); for (int i = 0; i < ret; i++) { if (i < n) { builder.append('#'); } else { builder.append('-'); } } } } builder.append('|'); builder.append(strSpeed).append("/s"); builder.append(']'); System.out.print('\r'); System.out.print(builder.toString()); } @Override public void close() { System.out.println(); } }