1 // NNCP -- Node to Node copy, utilities for store-and-forward data exchange
2 // Copyright (C) 2016-2024 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
25 "github.com/dustin/go-humanize"
26 "go.cypherpunks.ru/nncp/v8/uilive"
30 uilive.Out = os.Stderr
33 var progressBars = make(map[string]*ProgressBar)
34 var progressBarsLock sync.RWMutex
36 type ProgressBar struct {
43 func ProgressBarNew(initial, full int64) *ProgressBar {
54 func (pb ProgressBar) Render(what string, size int64) {
55 now := time.Now().UTC()
56 timeDiff := now.Sub(pb.started).Seconds()
60 percentage := int64(100)
62 percentage = 100 * size / pb.full
65 pb.w, "%s %s %s/%s %d%% (%s/sec)\n",
66 now.Format(time.RFC3339), what,
67 humanize.IBytes(uint64(size)),
68 humanize.IBytes(uint64(pb.full)),
70 humanize.IBytes(uint64(float64(size-pb.initial)/timeDiff)),
74 func (pb ProgressBar) Kill() {
84 ) (written int64, err error) {
85 buf := make([]byte, EncBlkSize)
89 nr, er = src.Read(buf)
91 nw, ew = dst.Write(buf[:nr])
95 Progress(prgrsPrefix, append(les, LE{"Size", written}))
103 err = io.ErrShortWrite
115 for _, le := range les {
116 if le.K == "FullSize" {
117 if le.V.(int64) == 0 {
118 Progress(prgrsPrefix, append(
119 les, LE{"Size", written}, LE{"FullSize", written},
129 func Progress(prefix string, les LEs) {
133 for _, le := range les {
138 fullsize = le.V.(int64)
143 progressBarsLock.RLock()
144 pb := progressBars[pkt]
145 progressBarsLock.RUnlock()
147 progressBarsLock.Lock()
148 pb = ProgressBarNew(size, fullsize)
149 progressBars[pkt] = pb
150 progressBarsLock.Unlock()
153 if len(what) >= Base32Encoded32Len { // Base32 encoded
154 what = what[:16] + ".." + what[len(what)-16:]
156 what = prefix + " " + what
157 pb.Render(what, size)
158 if fullsize != 0 && size >= fullsize {
160 progressBarsLock.Lock()
161 delete(progressBars, pkt)
162 progressBarsLock.Unlock()
166 func ProgressKill(pkt string) {
167 progressBarsLock.Lock()
168 pb := progressBars[pkt]
171 delete(progressBars, pkt)
173 progressBarsLock.Unlock()