From aaeb5ae3c9afa6f351005e0021d34599ede8c8c5 Mon Sep 17 00:00:00 2001 From: Jake Huggart Date: Sat, 27 Feb 2021 07:10:02 -0600 Subject: [PATCH] first pass at using ticker over handrolled timing --- .gitignore | 5 +- go.mod | 4 +- go.sum | 11 ++++ internal/printer/printer.go | 16 ++--- internal/ratiospoof/ratiospoof.go | 105 ++++++++++++++++-------------- 5 files changed, 80 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 2561303..9355b7a 100644 --- a/.gitignore +++ b/.gitignore @@ -128,7 +128,8 @@ dmypy.json # Pyre type checker .pyre/ -#vscode folder +#ide folders /.vscode +.idea -out/ \ No newline at end of file +out/ diff --git a/go.mod b/go.mod index b742036..fc43eb5 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ go 1.15 require ( github.com/gammazero/deque v0.0.0-20201010052221-3932da5530cc + github.com/magefile/mage v1.11.0 // indirect github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 - golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect + github.com/sirupsen/logrus v1.8.0 + golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d // indirect ) diff --git a/go.sum b/go.sum index ab6ce33..83b88f1 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,17 @@ +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gammazero/deque v0.0.0-20201010052221-3932da5530cc h1:F7BbnLACph7UYiz9ZHi6npcROwKaZUyviDjsNERsoMM= github.com/gammazero/deque v0.0.0-20201010052221-3932da5530cc/go.mod h1:IlBLfYXnuw9sspy1XS6ctu5exGb6WHGKQsyo4s7bOEA= +github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= +github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= +github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw= github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= +github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d h1:9fH9JvLNoSpsDWcXJ4dSE3lZW99Z3OCUZLr07g60U6o= +golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/printer/printer.go b/internal/printer/printer.go index 86c2f27..1a68cd2 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -10,12 +10,13 @@ import ( "github.com/ap-pauloafonso/ratio-spoof/internal/ratiospoof" "github.com/olekukonko/ts" + log "github.com/sirupsen/logrus" ) func PrintState(state *ratiospoof.RatioSpoof) { exit := false go func() { - _ = <-state.StopPrintCH + <-state.StopPrintCH exit = true }() @@ -62,12 +63,14 @@ func PrintState(state *ratiospoof.RatioSpoof) { fmt.Printf("#%v downloaded: %v(%.2f%%) | left: %v | uploaded: %v | announced\n", dequeItem.Count, humanReadableSize(float64(dequeItem.Downloaded)), dequeItem.PercentDownloaded, humanReadableSize(float64(dequeItem.Left)), humanReadableSize(float64(dequeItem.Uploaded))) } lastDequeItem := state.AnnounceHistory.At(state.AnnounceHistory.Len() - 1).(ratiospoof.AnnounceEntry) + nextAnnounceSeconds := time.Until(state.NextAnnounce) * time.Second + fmt.Printf("#%v downloaded: %v(%.2f%%) | left: %v | uploaded: %v | next announce in: %v %v\n", lastDequeItem.Count, humanReadableSize(float64(lastDequeItem.Downloaded)), lastDequeItem.PercentDownloaded, humanReadableSize(float64(lastDequeItem.Left)), humanReadableSize(float64(lastDequeItem.Uploaded)), - fmtDuration(state.CurrentAnnounceTimer), + nextAnnounceSeconds, retryStr) if state.Input.Debug { @@ -91,7 +94,9 @@ func clear() { if runtime.GOOS == "windows" { cmd := exec.Command("cmd", "/c", "cls") cmd.Stdout = os.Stdout - cmd.Run() + if err := cmd.Run(); err != nil { + log.Warn("Failed to run printer.clear()", err) + } } else { fmt.Print("\033c") } @@ -113,8 +118,3 @@ func humanReadableSize(byteSize float64) string { } return fmt.Sprintf("%.2f%v", byteSize, unitFound) } - -func fmtDuration(seconds int) string { - d := time.Duration(seconds) * time.Second - return fmt.Sprintf("%s", d) -} diff --git a/internal/ratiospoof/ratiospoof.go b/internal/ratiospoof/ratiospoof.go index 2c51e33..dcfb786 100644 --- a/internal/ratiospoof/ratiospoof.go +++ b/internal/ratiospoof/ratiospoof.go @@ -4,19 +4,19 @@ import ( "errors" "fmt" "io/ioutil" - "log" "math/rand" "os" "os/signal" "strings" - "sync" "syscall" "time" + "github.com/gammazero/deque" + log "github.com/sirupsen/logrus" + "github.com/ap-pauloafonso/ratio-spoof/internal/bencode" "github.com/ap-pauloafonso/ratio-spoof/internal/input" "github.com/ap-pauloafonso/ratio-spoof/internal/tracker" - "github.com/gammazero/deque" ) const ( @@ -24,21 +24,20 @@ const ( ) type RatioSpoof struct { - mutex *sync.Mutex - TorrentInfo *bencode.TorrentInfo - Input *input.InputParsed - Tracker *tracker.HttpTracker - BitTorrentClient TorrentClientEmulation - CurrentAnnounceTimer int - AnnounceInterval int - NumWant int - Seeders int - Leechers int - AnnounceCount int - Status string - AnnounceHistory announceHistory - timerUpdateCh chan int - StopPrintCH chan interface{} + TorrentInfo *bencode.TorrentInfo + Input *input.InputParsed + Tracker *tracker.HttpTracker + BitTorrentClient TorrentClientEmulation + NextAnnounce time.Time + AnnounceInterval int + NumWant int + Seeders int + Leechers int + AnnounceCount int + Status string + AnnounceHistory announceHistory + timerUpdateCh chan int + StopPrintCH chan interface{} } type TorrentClientEmulation interface { @@ -92,7 +91,6 @@ func NewRatioSpoofState(input input.InputArgs, torrentClient TorrentClientEmulat Input: inputParsed, NumWant: 200, Status: "started", - mutex: &sync.Mutex{}, timerUpdateCh: changeTimerCh, StopPrintCH: stopPrintCh, }, nil @@ -109,33 +107,53 @@ func (R *RatioSpoof) gracefullyExit() { fmt.Printf("\nGracefully exiting...\n") R.Status = "stopped" R.NumWant = 0 - R.fireAnnounce(false) + + if err := R.fireAnnounce(false); err != nil { + log.Info("final fireAnnounce failed") + } + fmt.Printf("Gracefully exited successfully.\n") } func (R *RatioSpoof) Run() { rand.Seed(time.Now().UnixNano()) - sigCh := make(chan os.Signal) - + sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) R.firstAnnounce() - go R.decreaseTimer() - go R.updateTimer() - go func() { - for { + + duration := time.Duration(R.AnnounceInterval) * time.Second + ticker := time.NewTicker(duration) + defer ticker.Stop() + + runLoop := true + + for runLoop { + select { + case <-ticker.C: + //TODO: Eliminate shared state + R.NextAnnounce = time.Now().Add(duration) + + if err := R.fireAnnounce(true); err != nil { + //Log and continue (maintains former functionality) + log.Warn("failed to fire announce", err) + } + R.generateNextAnnounce() - time.Sleep(time.Duration(R.AnnounceInterval) * time.Second) - R.fireAnnounce(true) + case <-sigCh: + fmt.Println("done") + runLoop = false } - }() - <-sigCh + } + R.StopPrintCH <- "exit print" R.gracefullyExit() } func (R *RatioSpoof) firstAnnounce() { R.addAnnounce(R.Input.InitialDownloaded, R.Input.InitialUploaded, calculateBytesLeft(R.Input.InitialDownloaded, R.TorrentInfo.TotalSize), (float32(R.Input.InitialDownloaded)/float32(R.TorrentInfo.TotalSize))*100) - R.fireAnnounce(false) + if err := R.fireAnnounce(false); err != nil { + log.Warn("failed to fire first announce", err) + } } func (R *RatioSpoof) updateInterval(resp tracker.TrackerResponse) { @@ -155,6 +173,12 @@ func (R *RatioSpoof) addAnnounce(currentDownloaded, currentUploaded, currentLeft R.AnnounceHistory.pushValueHistory(AnnounceEntry{Count: R.AnnounceCount, Downloaded: currentDownloaded, Uploaded: currentUploaded, Left: currentLeft, PercentDownloaded: percentDownloaded}) } func (R *RatioSpoof) fireAnnounce(retry bool) error { + //Guard against empty queue, Back() panics when empty + if R.AnnounceHistory.Len() == 0 { + log.Info("skipping fireAnnounce, queue empty") + return nil + } + lastAnnounce := R.AnnounceHistory.Back().(AnnounceEntry) replacer := strings.NewReplacer("{infohash}", R.TorrentInfo.InfoHashURLEncoded, "{port}", fmt.Sprint(R.Input.Port), @@ -198,25 +222,6 @@ func (R *RatioSpoof) generateNextAnnounce() { R.addAnnounce(d, u, l, (float32(d)/float32(R.TorrentInfo.TotalSize))*100) } -func (R *RatioSpoof) decreaseTimer() { - for { - time.Sleep(1 * time.Second) - R.mutex.Lock() - if R.CurrentAnnounceTimer > 0 { - R.CurrentAnnounceTimer-- - } - R.mutex.Unlock() - } -} - -func (R *RatioSpoof) updateTimer() { - for { - newValue := <-R.timerUpdateCh - R.mutex.Lock() - R.CurrentAnnounceTimer = newValue - R.mutex.Unlock() - } -} func calculateNextTotalSizeByte(speedBytePerSecond, currentByte, pieceSizeByte, seconds, limitTotalBytes int) int { if speedBytePerSecond == 0 {