mempool-cli/ui/fee_distribution.go
2020-03-29 22:57:15 +02:00

132 lines
2.6 KiB
Go

package ui
import (
"context"
"fmt"
"sort"
"sync"
"github.com/fatih/color"
"github.com/jroimartin/gocui"
"github.com/mempool/mempool-cli/client"
)
type FeeDistribution struct {
gui *gocui.Gui
m sync.Mutex
loading bool
isProjected bool
cancelFn context.CancelFunc
fees client.Fees
title string
}
func NewFeeDistribution(g *gocui.Gui) *FeeDistribution {
return &FeeDistribution{gui: g}
}
func (fd *FeeDistribution) newCtx() context.Context {
ctx, cancel := context.WithCancel(context.Background())
fd.cancelFn = cancel
return ctx
}
func (fd *FeeDistribution) FetchProjection(n int) error {
fn := func(ctx context.Context) (client.Fees, error) {
return client.GetMempoolFee(ctx, n)
}
return fd.fetch(fn)
}
func (fd *FeeDistribution) FetchBlock(n int) error {
fn := func(ctx context.Context) (client.Fees, error) {
return client.GetBlockFee(ctx, n)
}
return fd.fetch(fn)
}
func (fd *FeeDistribution) fetch(fn func(ctx context.Context) (client.Fees, error)) error {
fd.m.Lock()
defer fd.m.Unlock()
if fn := fd.cancelFn; fn != nil {
fn()
}
fd.loading = true
ctx := fd.newCtx()
go func() {
fees, err := fn(ctx)
if err != nil {
return
}
fd.fees = fees
fd.loading = false
fd.gui.Update(fd.Layout)
}()
return nil
}
func (fd *FeeDistribution) Layout(g *gocui.Gui) error {
fd.m.Lock()
defer fd.m.Unlock()
if fd.loading == false && (fd.fees == nil || len(fd.fees) == 0) {
return nil
}
x, y := g.Size()
name := "fee_distribution"
v, err := g.SetView(name, x/2-20, y/2-3, x/2+20, y/2+3)
if err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Title = "Fee distribution" + fd.title + "('esc' to close)"
g.SetCurrentView(name)
g.SetViewOnTop(name)
g.SetKeybinding(name, gocui.KeyEsc, gocui.ModNone, fd.close)
}
v.Clear()
if fd.loading == true {
fmt.Fprint(v, "Loading...")
return nil
}
sort.Sort(fd.fees)
txs := len(fd.fees)
min, max := fd.fees[0].FPV, fd.fees[txs-1].FPV
var (
white = color.New(color.FgWhite).SprintfFunc()
yellow = color.New(color.FgYellow).SprintfFunc()
)
fmt.Fprintf(v, white("Fee span:")+" %d - %d "+yellow("sat/vByte\n"), ceil(min), ceil(max))
fmt.Fprintf(v, white("Tx count:")+" %d "+white("transactions\n"), txs)
fmt.Fprintf(v, white("Median: ")+" ~%d "+yellow("sat/vBytes\n"), ceil(fd.fees[txs/2].FPV))
return nil
}
func (fd *FeeDistribution) close(g *gocui.Gui, v *gocui.View) error {
fd.m.Lock()
defer fd.m.Unlock()
if fn := fd.cancelFn; fn != nil {
fn()
}
fd.cancelFn = nil
fd.loading = false
fd.fees = nil
g.DeleteView(v.Name())
return nil
}