Backport from dev
This commit is contained in:
parent
2cc7fa6ac1
commit
dd1a3a703b
|
@ -5,3 +5,4 @@ HellPot
|
|||
*.save
|
||||
*.toml
|
||||
*.yaml
|
||||
.backups/
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package heffalump
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/yunginnanet/HellPot/internal/util"
|
||||
)
|
||||
|
||||
func TestHeffalump_WriteHell(t *testing.T) {
|
||||
sp := util.NewCappedSpeedometer(io.Discard, 55555)
|
||||
var err error
|
||||
var count int64
|
||||
for err == nil {
|
||||
var cnt int64
|
||||
cnt, err = DefaultHeffalump.WriteHell(sp.BufioWriter)
|
||||
t.Logf("written: %d", cnt)
|
||||
count += cnt
|
||||
}
|
||||
if !errors.Is(err, util.ErrLimitReached) {
|
||||
t.Errorf("expected %v, got %v", util.ErrLimitReached, err)
|
||||
} else {
|
||||
t.Logf("err: %v", err)
|
||||
}
|
||||
t.Logf("count: %d", count)
|
||||
t.Logf("rate: %f per second", sp.Rate())
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,7 @@ func init() {
|
|||
if home, err = os.UserHomeDir(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defOpts["logger"]["directory"] = path.Join(home, ".local", "share", Title+"logs")
|
||||
defOpts["logger"]["directory"] = path.Join(home, ".local", "share", Title, "logs")
|
||||
prefConfigLocation = path.Join(home, ".config", Title)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,15 +22,22 @@ func rc(s []string) string {
|
|||
|
||||
func process(in string) (s string) {
|
||||
var v = strings.Split(config.Version, "")
|
||||
maj := v[0]
|
||||
min := v[2]
|
||||
smin := v[4]
|
||||
var maj, min, smin = "", "", ""
|
||||
if len(config.Version) > 0 {
|
||||
maj = v[0]
|
||||
}
|
||||
if len(config.Version) > 2 {
|
||||
min = v[2]
|
||||
}
|
||||
if len(config.Version) > 4 {
|
||||
smin = v[4]
|
||||
}
|
||||
defl8, _ := squish.UnpackStr(in)
|
||||
sp := strings.Split(defl8, "|")
|
||||
s = sp[0]
|
||||
if smin == "" || len(config.Version) == 7 {
|
||||
if smin == "" || len(config.Version) == 7 || config.Version == "dev" {
|
||||
s = strings.ReplaceAll(s, "$1;40m.", "$1;40m")
|
||||
if len(config.Version) == 7 {
|
||||
if len(config.Version) == 7 || config.Version == "dev" {
|
||||
s = strings.ReplaceAll(s, "$3;40m.", "$3;40m")
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +53,7 @@ func process(in string) (s string) {
|
|||
for n := 1; n < 5; n++ {
|
||||
s = cproc(s, fmt.Sprintf("%d", n))
|
||||
}
|
||||
if len(config.Version) == 7 {
|
||||
if len(config.Version) == 7 || config.Version == "dev" {
|
||||
maj = "[" + config.Version + "]"
|
||||
min = ""
|
||||
smin = ""
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrLimitReached = errors.New("limit reached")
|
||||
|
||||
type Speedometer struct {
|
||||
cap int64
|
||||
speedLimit SpeedLimit
|
||||
birth *time.Time
|
||||
duration time.Duration
|
||||
internal atomics
|
||||
w io.Writer
|
||||
BufioWriter *bufio.Writer
|
||||
}
|
||||
|
||||
type atomics struct {
|
||||
closed *atomic.Bool
|
||||
count *int64
|
||||
start *sync.Once
|
||||
stop *sync.Once
|
||||
}
|
||||
|
||||
func NewSpeedometer(w io.Writer) *Speedometer {
|
||||
z := int64(0)
|
||||
speedo := &Speedometer{
|
||||
w: w,
|
||||
cap: -1,
|
||||
internal: atomics{
|
||||
count: &z,
|
||||
closed: new(atomic.Bool),
|
||||
stop: new(sync.Once),
|
||||
start: new(sync.Once),
|
||||
},
|
||||
}
|
||||
speedo.internal.closed.Store(false)
|
||||
speedo.BufioWriter = bufio.NewWriter(speedo)
|
||||
return speedo
|
||||
}
|
||||
|
||||
type SpeedLimit struct {
|
||||
Bytes int
|
||||
Per time.Duration
|
||||
CheckEveryBytes int
|
||||
Delay time.Duration
|
||||
}
|
||||
|
||||
func NewLimitedSpeedometer(w io.Writer, speedLimit SpeedLimit) *Speedometer {
|
||||
z := int64(0)
|
||||
speedo := &Speedometer{
|
||||
w: w,
|
||||
cap: -1,
|
||||
speedLimit: speedLimit,
|
||||
internal: atomics{
|
||||
count: &z,
|
||||
closed: new(atomic.Bool),
|
||||
stop: new(sync.Once),
|
||||
start: new(sync.Once),
|
||||
},
|
||||
}
|
||||
speedo.internal.closed.Store(false)
|
||||
speedo.BufioWriter = bufio.NewWriterSize(speedo, speedLimit.CheckEveryBytes)
|
||||
return speedo
|
||||
}
|
||||
|
||||
func NewCappedSpeedometer(w io.Writer, cap int64) *Speedometer {
|
||||
z := int64(0)
|
||||
speedo := &Speedometer{
|
||||
w: w,
|
||||
cap: cap,
|
||||
internal: atomics{
|
||||
count: &z,
|
||||
closed: new(atomic.Bool),
|
||||
stop: new(sync.Once),
|
||||
start: new(sync.Once),
|
||||
},
|
||||
}
|
||||
speedo.internal.closed.Store(false)
|
||||
speedo.BufioWriter = bufio.NewWriterSize(speedo, int(cap)/10)
|
||||
return speedo
|
||||
}
|
||||
|
||||
func (s *Speedometer) increment(inc int64) (int, error) {
|
||||
if s.internal.closed.Load() {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
var err error
|
||||
if s.cap > 0 && s.Total()+inc > s.cap {
|
||||
_ = s.Close()
|
||||
err = ErrLimitReached
|
||||
inc = s.cap - s.Total()
|
||||
}
|
||||
atomic.AddInt64(s.internal.count, inc)
|
||||
return int(inc), err
|
||||
}
|
||||
|
||||
func (s *Speedometer) Running() bool {
|
||||
return !s.internal.closed.Load()
|
||||
}
|
||||
|
||||
func (s *Speedometer) Total() int64 {
|
||||
return atomic.LoadInt64(s.internal.count)
|
||||
}
|
||||
|
||||
func (s *Speedometer) Reset() {
|
||||
s.internal.count = new(int64)
|
||||
s.internal.closed = new(atomic.Bool)
|
||||
s.internal.start = new(sync.Once)
|
||||
s.internal.stop = new(sync.Once)
|
||||
s.BufioWriter = bufio.NewWriter(s)
|
||||
s.internal.closed.Store(false)
|
||||
}
|
||||
|
||||
func (s *Speedometer) Close() error {
|
||||
s.internal.stop.Do(func() {
|
||||
s.internal.closed.Store(true)
|
||||
stopped := time.Now()
|
||||
s.duration = stopped.Sub(*s.birth)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Speedometer) Rate() float64 {
|
||||
if s.internal.closed.Load() {
|
||||
return float64(s.Total()) / s.duration.Seconds()
|
||||
}
|
||||
return float64(s.Total()) / time.Since(*s.birth).Seconds()
|
||||
}
|
||||
|
||||
func (s *Speedometer) Write(p []byte) (n int, err error) {
|
||||
s.internal.start.Do(func() {
|
||||
tn := time.Now()
|
||||
s.birth = &tn
|
||||
})
|
||||
accepted, err := s.increment(int64(len(p)))
|
||||
if err != nil {
|
||||
wn, innerErr := s.w.Write(p[:accepted])
|
||||
if innerErr != nil {
|
||||
err = innerErr
|
||||
}
|
||||
if wn < accepted {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
return wn, err
|
||||
}
|
||||
return s.w.Write(p)
|
||||
}
|
||||
|
||||
/*func BenchmarkHeffalump_WriteHell(b *testing.B) {
|
||||
|
||||
}*/
|
|
@ -1,101 +0,0 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func writeStuff(target *bufio.Writer, count int) error {
|
||||
write := func() error {
|
||||
_, err := target.WriteString("a")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if count < 0 {
|
||||
for {
|
||||
if err := write(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < count; i++ {
|
||||
if err := write(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_Speedometer(t *testing.T) {
|
||||
type results struct {
|
||||
total int64
|
||||
written int
|
||||
rate float64
|
||||
err error
|
||||
}
|
||||
|
||||
isIt := func(want, have results) {
|
||||
if have.total != want.total {
|
||||
t.Errorf("total: want %d, have %d", want.total, have.total)
|
||||
}
|
||||
if have.written != want.written {
|
||||
t.Errorf("written: want %d, have %d", want.written, have.written)
|
||||
}
|
||||
if have.rate != want.rate {
|
||||
t.Errorf("rate: want %f, have %f", want.rate, have.rate)
|
||||
}
|
||||
if have.err != want.err {
|
||||
t.Errorf("wantErr: want %v, have %v", want.err, have.err)
|
||||
}
|
||||
}
|
||||
|
||||
sp := NewSpeedometer(io.Discard)
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
errChan <- writeStuff(sp.BufioWriter, -1)
|
||||
}()
|
||||
time.Sleep(1 * time.Second)
|
||||
_ = sp.Close()
|
||||
err := <-errChan
|
||||
cnt, err := sp.Write([]byte("a"))
|
||||
isIt(results{err: io.ErrClosedPipe, written: 0}, results{err: err, written: cnt})
|
||||
sp.Reset()
|
||||
cnt, err = sp.Write([]byte("a"))
|
||||
isIt(results{err: nil, written: 1, total: 1}, results{err: err, written: cnt, total: sp.Total()})
|
||||
cnt, err = sp.Write([]byte("aa"))
|
||||
isIt(results{err: nil, written: 2, total: 3}, results{err: err, written: cnt, total: sp.Total()})
|
||||
cnt, err = sp.Write([]byte("a"))
|
||||
isIt(results{err: nil, written: 1, total: 4}, results{err: err, written: cnt, total: sp.Total()})
|
||||
cnt, err = sp.Write([]byte("a"))
|
||||
isIt(results{err: nil, written: 1, total: 5}, results{err: err, written: cnt, total: sp.Total()})
|
||||
go func() {
|
||||
errChan <- writeStuff(sp.BufioWriter, -1)
|
||||
}()
|
||||
var count = 0
|
||||
for sp.Running() {
|
||||
select {
|
||||
case err = <-errChan:
|
||||
if !errors.Is(err, io.ErrClosedPipe) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
} else {
|
||||
if count < 5 {
|
||||
t.Errorf("too few iterations: %d", count)
|
||||
}
|
||||
t.Logf("final rate: %v per second", sp.Rate())
|
||||
}
|
||||
default:
|
||||
if count > 5 {
|
||||
_ = sp.Close()
|
||||
}
|
||||
t.Logf("rate: %v per second", sp.Rate())
|
||||
time.Sleep(1 * time.Second)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue