quick refactor

This commit is contained in:
ap-pauloafonso 2020-12-12 19:52:32 -03:00
parent 8c3dc91ce5
commit 144c8adf3c
8 changed files with 231 additions and 275 deletions

View file

@ -6,7 +6,7 @@ import (
"net/http"
"runtime"
"github.com/ap-pauloafonso/ratio-spoof/qbittorrent"
"github.com/ap-pauloafonso/ratio-spoof/emulation"
"github.com/ap-pauloafonso/ratio-spoof/ratiospoof"
)
@ -57,7 +57,7 @@ required arguments:
return
}
qbit := qbittorrent.NewQbitTorrent()
qbit := emulation.NewQbitTorrent()
r, err := ratiospoof.NewRatioSPoofState(
ratiospoof.InputArgs{
TorrentPath: *torrentPath,

View file

@ -1,4 +1,4 @@
package qbittorrent
package emulation
import (
"encoding/hex"

View file

@ -1,4 +1,4 @@
package qbittorrent
package emulation
import (
"strings"

124
ratiospoof/printstate.go Normal file
View file

@ -0,0 +1,124 @@
package ratiospoof
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"time"
"github.com/olekukonko/ts"
)
func (R *ratioSpoofState) PrintState(exitedCH <-chan string) {
exit := false
go func() {
_ = <-exitedCH
exit = true
}()
for {
if exit {
break
}
width := terminalSize()
clear()
if R.announceHistory.Len() > 0 {
seedersStr := fmt.Sprint(R.seeders)
leechersStr := fmt.Sprint(R.leechers)
if R.seeders == 0 {
seedersStr = "not informed"
}
if R.leechers == 0 {
leechersStr = "not informed"
}
var retryStr string
if R.retryAttempt > 0 {
retryStr = fmt.Sprintf("(*Retry %v - check your connection)", R.retryAttempt)
}
fmt.Println(center(" RATIO-SPOOF ", width-len(" RATIO-SPOOF "), "#"))
fmt.Printf(`
Torrent: %v
Tracker: %v
Seeders: %v
Leechers:%v
Download Speed: %v/s
Upload Speed: %v/s
Size: %v
Emulation: %v | Port: %v`, R.torrentInfo.name, R.torrentInfo.trackerInfo.main, seedersStr, leechersStr, humanReadableSize(float64(R.input.downloadSpeed)),
humanReadableSize(float64(R.input.uploadSpeed)), humanReadableSize(float64(R.torrentInfo.totalSize)), R.bitTorrentClient.Name(), R.input.port)
fmt.Println()
fmt.Println()
fmt.Println(center(" GITHUB.COM/AP-PAULOAFONSO/RATIO-SPOOF ", width-len(" GITHUB.COM/AP-PAULOAFONSO/RATIO-SPOOF "), "#"))
fmt.Println()
for i := 0; i <= R.announceHistory.Len()-2; i++ {
dequeItem := R.announceHistory.At(i).(announceEntry)
fmt.Printf("#%v downloaded: %v(%.2f%%) | left: %v | uploaded: %v | announced", dequeItem.count, humanReadableSize(float64(dequeItem.downloaded)), dequeItem.percentDownloaded, humanReadableSize(float64(dequeItem.left)), humanReadableSize(float64(dequeItem.uploaded)))
fmt.Println()
}
lastDequeItem := R.announceHistory.At(R.announceHistory.Len() - 1).(announceEntry)
fmt.Printf("#%v downloaded: %v(%.2f%%) | left: %v | uploaded: %v | next announce in: %v %v", lastDequeItem.count,
humanReadableSize(float64(lastDequeItem.downloaded)),
lastDequeItem.percentDownloaded,
humanReadableSize(float64(lastDequeItem.left)),
humanReadableSize(float64(lastDequeItem.uploaded)),
fmtDuration(R.currentAnnounceTimer),
retryStr)
if R.input.debug {
fmt.Println()
fmt.Println()
fmt.Println(center(" DEBUG ", width-len(" DEBUG "), "#"))
fmt.Println()
fmt.Print(R.lastAnounceRequest)
fmt.Println()
fmt.Println()
fmt.Print(R.lastTackerResponse)
}
time.Sleep(1 * time.Second)
}
}
}
func terminalSize() int {
size, _ := ts.GetSize()
width := size.Col()
if width < 40 {
width = 40
}
return width
}
func clear() {
if runtime.GOOS == "windows" {
cmd := exec.Command("cmd", "/c", "cls")
cmd.Stdout = os.Stdout
cmd.Run()
} else {
fmt.Print("\033c")
}
}
func center(s string, n int, fill string) string {
div := n / 2
return strings.Repeat(fill, div) + s + strings.Repeat(fill, div)
}
func humanReadableSize(byteSize float64) string {
var unitFound string
for _, unit := range []string{"B", "KiB", "MiB", "GiB", "TiB"} {
if byteSize < 1024.0 {
unitFound = unit
break
}
byteSize /= 1024.0
}
return fmt.Sprintf("%.2f%v", byteSize, unitFound)
}
func fmtDuration(seconds int) string {
d := time.Duration(seconds) * time.Second
return fmt.Sprintf("%s", d)
}

View file

@ -0,0 +1,31 @@
package ratiospoof
import (
"fmt"
"testing"
)
func TestHumanReadableSize(T *testing.T) {
data := []struct {
in float64
out string
}{
{1536, "1.50KiB"},
{379040563, "361.48MiB"},
{6291456, "6.00MiB"},
{372749107, "355.48MiB"},
{10485760, "10.00MiB"},
{15728640, "15.00MiB"},
{363311923, "346.48MiB"},
{16777216, "16.00MiB"},
{379040563, "361.48MiB"},
}
for idx, td := range data {
T.Run(fmt.Sprint(idx), func(t *testing.T) {
got := humanReadableSize(td.in)
if got != td.out {
t.Errorf("got %q, want %q", got, td.out)
}
})
}
}

View file

@ -1,141 +0,0 @@
package ratiospoof
import (
"io/ioutil"
"testing"
"github.com/ap-pauloafonso/ratio-spoof/beencode"
)
func assertAreEqual(t *testing.T, got, want interface{}) {
t.Helper()
if got != want {
t.Errorf("\ngot: %v\n want: %v", got, want)
}
}
// func TestStrSize2ByteSize(T *testing.T) {
// T.Run("100kb", func(t *testing.T) {
// got := strSize2ByteSize("100kb", 100)
// want := 102400
// assertAreEqual(t, got, want)
// })
// T.Run("1kb", func(t *testing.T) {
// got := strSize2ByteSize("1kb", 0)
// want := 1024
// assertAreEqual(t, got, want)
// })
// T.Run("1mb", func(t *testing.T) {
// got := strSize2ByteSize("1mb", 0)
// want := 1048576
// assertAreEqual(t, got, want)
// })
// T.Run("1gb", func(t *testing.T) {
// got := strSize2ByteSize("1gb", 0)
// want := 1073741824
// assertAreEqual(t, got, want)
// })
// T.Run("1.5gb", func(t *testing.T) {
// got := strSize2ByteSize("1.5gb", 0)
// want := 1610612736
// assertAreEqual(t, got, want)
// })
// T.Run("1tb", func(t *testing.T) {
// got := strSize2ByteSize("1tb", 0)
// want := 1099511627776
// assertAreEqual(t, got, want)
// })
// T.Run("1b", func(t *testing.T) {
// got := strSize2ByteSize("1b", 0)
// want := 1
// assertAreEqual(t, got, want)
// })
// T.Run("100%% of 10gb ", func(t *testing.T) {
// got := strSize2ByteSize("100%", 10737418240)
// want := 10737418240
// assertAreEqual(t, got, want)
// })
// T.Run("55%% of 900mb ", func(t *testing.T) {
// got := strSize2ByteSize("55%", 943718400)
// want := 519045120
// assertAreEqual(t, got, want)
// })
// T.Run("55%% of 900mb ", func(t *testing.T) {
// got := strSize2ByteSize("55%", 943718400)
// want := 519045120
// assertAreEqual(t, got, want)
// })
// }
// func TestHumanReadableSize(T *testing.T) {
// T.Run("#1", func(t *testing.T) {
// got := humanReadableSize(1536, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#2", func(t *testing.T) {
// got := humanReadableSize(379040563, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#3", func(t *testing.T) {
// got := humanReadableSize(6291456, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#4", func(t *testing.T) {
// got := humanReadableSize(372749107, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#5", func(t *testing.T) {
// got := humanReadableSize(10485760, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#6", func(t *testing.T) {
// got := humanReadableSize(15728640, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#7", func(t *testing.T) {
// got := humanReadableSize(363311923, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#8", func(t *testing.T) {
// got := humanReadableSize(16777216, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// T.Run("#9", func(t *testing.T) {
// got := humanReadableSize(379040563, true)
// want := "1.50KiB"
// assertAreEqual(t, got, want)
// })
// }
func TestClculateNextTotalSizeByte(T *testing.T) {
got := calculateNextTotalSizeByte(100, 0, 512, 30, 87979879)
want := 3074560
assertAreEqual(T, got, want)
}
func TestUrlEncodeInfoHash(T *testing.T) {
b, _ := ioutil.ReadFile("")
got := extractInfoHashURLEncoded(b, beencode.Decode(b))
want := "%60N%7d%1f%8b%3a%9bT%d5%fc%ad%d1%27%ab5%02%1c%fb%03%b0"
assertAreEqual(T, got, want)
}

View file

@ -12,9 +12,7 @@ import (
"net/http"
"net/url"
"os"
"os/exec"
"os/signal"
"runtime"
"strconv"
"strings"
"sync"
@ -23,7 +21,6 @@ import (
"github.com/ap-pauloafonso/ratio-spoof/beencode"
"github.com/gammazero/deque"
"github.com/olekukonko/ts"
)
const (
@ -33,7 +30,7 @@ const (
var validInitialSufixes = [...]string{"%", "b", "kb", "mb", "gb", "tb"}
var validSpeedSufixes = [...]string{"kbps", "mbps"}
type ratioSPoofState struct {
type ratioSpoofState struct {
mutex *sync.Mutex
httpClient HttpClient
torrentInfo *torrentInfo
@ -124,7 +121,7 @@ func (I *InputArgs) parseInput(torrentInfo *torrentInfo) (*inputParsed, error) {
}, nil
}
func NewRatioSPoofState(input InputArgs, torrentClient TorrentClient, httpclient HttpClient) (*ratioSPoofState, error) {
func NewRatioSPoofState(input InputArgs, torrentClient TorrentClient, httpclient HttpClient) (*ratioSpoofState, error) {
torrentInfo, err := extractTorrentInfo(input.TorrentPath)
if err != nil {
@ -136,7 +133,7 @@ func NewRatioSPoofState(input InputArgs, torrentClient TorrentClient, httpclient
panic(err)
}
return &ratioSPoofState{
return &ratioSpoofState{
bitTorrentClient: torrentClient,
httpClient: httpclient,
torrentInfo: torrentInfo,
@ -235,14 +232,14 @@ func (A *announceHistory) pushValueHistory(value announceEntry) {
A.PushBack(value)
}
func (R *ratioSPoofState) gracefullyExit() {
func (R *ratioSpoofState) gracefullyExit() {
fmt.Printf("\nGracefully exiting...\n")
R.status = "stopped"
R.numWant = 0
R.fireAnnounce(false)
}
func (R *ratioSPoofState) Run() {
func (R *ratioSpoofState) Run() {
rand.Seed(time.Now().UnixNano())
sigCh := make(chan os.Signal)
stopPrintCh := make(chan string)
@ -250,7 +247,7 @@ func (R *ratioSPoofState) Run() {
signal.Notify(sigCh, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
R.firstAnnounce()
go R.decreaseTimer()
go R.printState(stopPrintCh)
go R.PrintState(stopPrintCh)
go func() {
for {
R.generateNextAnnounce()
@ -262,13 +259,13 @@ func (R *ratioSPoofState) Run() {
stopPrintCh <- "exit print"
R.gracefullyExit()
}
func (R *ratioSPoofState) firstAnnounce() {
func (R *ratioSpoofState) firstAnnounce() {
println("Trying to connect to the tracker...")
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)
}
func (R *ratioSPoofState) updateInterval(resp trackerResponse) {
func (R *ratioSpoofState) updateInterval(resp trackerResponse) {
if resp.minInterval > 0 {
R.announceInterval = resp.minInterval
} else {
@ -276,15 +273,15 @@ func (R *ratioSPoofState) updateInterval(resp trackerResponse) {
}
}
func (R *ratioSPoofState) updateSeedersAndLeechers(resp trackerResponse) {
func (R *ratioSpoofState) updateSeedersAndLeechers(resp trackerResponse) {
R.seeders = resp.seeders
R.leechers = resp.leechers
}
func (R *ratioSPoofState) addAnnounce(currentDownloaded, currentUploaded, currentLeft int, percentDownloaded float32) {
func (R *ratioSpoofState) addAnnounce(currentDownloaded, currentUploaded, currentLeft int, percentDownloaded float32) {
R.announceCount++
R.announceHistory.pushValueHistory(announceEntry{count: R.announceCount, downloaded: currentDownloaded, uploaded: currentUploaded, left: currentLeft, percentDownloaded: percentDownloaded})
}
func (R *ratioSPoofState) fireAnnounce(retry bool) {
func (R *ratioSpoofState) fireAnnounce(retry bool) {
lastAnnounce := R.announceHistory.Back().(announceEntry)
replacer := strings.NewReplacer("{infohash}", R.torrentInfo.infoHashURLEncoded,
"{port}", fmt.Sprint(R.input.port),
@ -331,7 +328,7 @@ func (R *ratioSPoofState) fireAnnounce(retry bool) {
R.updateInterval(*trackerResp)
}
}
func (R *ratioSPoofState) generateNextAnnounce() {
func (R *ratioSpoofState) generateNextAnnounce() {
R.changeCurrentTimer(R.announceInterval)
lastAnnounce := R.announceHistory.Back().(announceEntry)
currentDownloaded := lastAnnounce.downloaded
@ -352,7 +349,7 @@ func (R *ratioSPoofState) generateNextAnnounce() {
R.addAnnounce(d, u, l, (float32(d)/float32(R.torrentInfo.totalSize))*100)
}
func (R *ratioSPoofState) decreaseTimer() {
func (R *ratioSpoofState) decreaseTimer() {
for {
time.Sleep(1 * time.Second)
R.mutex.Lock()
@ -362,126 +359,14 @@ func (R *ratioSPoofState) decreaseTimer() {
R.mutex.Unlock()
}
}
func (R *ratioSPoofState) printState(exitedCH <-chan string) {
terminalSize := func() int {
size, _ := ts.GetSize()
width := size.Col()
if width < 40 {
width = 40
}
return width
}
clear := func() {
if runtime.GOOS == "windows" {
cmd := exec.Command("cmd", "/c", "cls")
cmd.Stdout = os.Stdout
cmd.Run()
} else {
fmt.Print("\033c")
}
}
center := func(s string, n int, fill string) string {
div := n / 2
return strings.Repeat(fill, div) + s + strings.Repeat(fill, div)
}
humanReadableSize := func(byteSize float64) string {
var unitFound string
for _, unit := range []string{"B", "KiB", "MiB", "GiB", "TiB"} {
if byteSize < 1024.0 {
unitFound = unit
break
}
byteSize /= 1024.0
}
return fmt.Sprintf("%.2f%v", byteSize, unitFound)
}
fmtDuration := func(seconds int) string {
d := time.Duration(seconds) * time.Second
return fmt.Sprintf("%s", d)
}
exit := false
go func() {
_ = <-exitedCH
exit = true
}()
for {
if exit {
break
}
width := terminalSize()
clear()
if R.announceHistory.Len() > 0 {
seedersStr := fmt.Sprint(R.seeders)
leechersStr := fmt.Sprint(R.leechers)
if R.seeders == 0 {
seedersStr = "not informed"
}
if R.leechers == 0 {
leechersStr = "not informed"
}
var retryStr string
if R.retryAttempt > 0 {
retryStr = fmt.Sprintf("(*Retry %v - check your connection)", R.retryAttempt)
}
fmt.Println(center(" RATIO-SPOOF ", width-len(" RATIO-SPOOF "), "#"))
fmt.Printf(`
Torrent: %v
Tracker: %v
Seeders: %v
Leechers:%v
Download Speed: %v/s
Upload Speed: %v/s
Size: %v
Emulation: %v | Port: %v`, R.torrentInfo.name, R.torrentInfo.trackerInfo.main, seedersStr, leechersStr, humanReadableSize(float64(R.input.downloadSpeed)),
humanReadableSize(float64(R.input.uploadSpeed)), humanReadableSize(float64(R.torrentInfo.totalSize)), R.bitTorrentClient.Name(), R.input.port)
fmt.Println()
fmt.Println()
fmt.Println(center(" GITHUB.COM/AP-PAULOAFONSO/RATIO-SPOOF ", width-len(" GITHUB.COM/AP-PAULOAFONSO/RATIO-SPOOF "), "#"))
fmt.Println()
for i := 0; i <= R.announceHistory.Len()-2; i++ {
dequeItem := R.announceHistory.At(i).(announceEntry)
fmt.Printf("#%v downloaded: %v(%.2f%%) | left: %v | uploaded: %v | announced", dequeItem.count, humanReadableSize(float64(dequeItem.downloaded)), dequeItem.percentDownloaded, humanReadableSize(float64(dequeItem.left)), humanReadableSize(float64(dequeItem.uploaded)))
fmt.Println()
}
lastDequeItem := R.announceHistory.At(R.announceHistory.Len() - 1).(announceEntry)
fmt.Printf("#%v downloaded: %v(%.2f%%) | left: %v | uploaded: %v | next announce in: %v %v", lastDequeItem.count,
humanReadableSize(float64(lastDequeItem.downloaded)),
lastDequeItem.percentDownloaded,
humanReadableSize(float64(lastDequeItem.left)),
humanReadableSize(float64(lastDequeItem.uploaded)),
fmtDuration(R.currentAnnounceTimer),
retryStr)
if R.input.debug {
fmt.Println()
fmt.Println()
fmt.Println(center(" DEBUG ", width-len(" DEBUG "), "#"))
fmt.Println()
fmt.Print(R.lastAnounceRequest)
fmt.Println()
fmt.Println()
fmt.Print(R.lastTackerResponse)
}
time.Sleep(1 * time.Second)
}
}
}
func (R *ratioSPoofState) changeCurrentTimer(newAnnounceRate int) {
func (R *ratioSpoofState) changeCurrentTimer(newAnnounceRate int) {
R.mutex.Lock()
R.currentAnnounceTimer = newAnnounceRate
R.mutex.Unlock()
}
func (R *ratioSPoofState) tryMakeRequest(query string) *trackerResponse {
func (R *ratioSpoofState) tryMakeRequest(query string) *trackerResponse {
for idx, url := range R.torrentInfo.trackerInfo.urls {
completeURL := url + "?" + strings.TrimLeft(query, "?")
R.lastAnounceRequest = completeURL

View file

@ -0,0 +1,57 @@
package ratiospoof
import (
"fmt"
"testing"
)
func assertAreEqual(t *testing.T, got, want interface{}) {
t.Helper()
if got != want {
t.Errorf("\ngot: %v\n want: %v", got, want)
}
}
func TestStrSize2ByteSize(T *testing.T) {
data := []struct {
in string
inTotalSize int
out int
}{
{"100kb", 100, 102400},
{"1kb", 0, 1024},
{"1mb", 0, 1048576},
{"1gb", 0, 1073741824},
{"1.5gb", 0, 1610612736},
{"1tb", 0, 1099511627776},
{"1b", 0, 1},
{"100%", 10737418240, 10737418240},
{"55%", 943718400, 519045120},
}
for idx, td := range data {
T.Run(fmt.Sprint(idx), func(t *testing.T) {
got := strSize2ByteSize(td.in, td.inTotalSize)
if got != td.out {
t.Errorf("got %v, want %v", got, td.out)
}
})
}
}
func TestClculateNextTotalSizeByte(T *testing.T) {
got := calculateNextTotalSizeByte(100*1024, 0, 512, 30, 87979879)
want := 3075072
assertAreEqual(T, got, want)
}
// func TestUrlEncodeInfoHash(T *testing.T) {
// b, _ := ioutil.ReadFile("")
// got := extractInfoHashURLEncoded(b, beencode.Decode(b))
// want := "%60N%7d%1f%8b%3a%9bT%d5%fc%ad%d1%27%ab5%02%1c%fb%03%b0"
// assertAreEqual(T, got, want)
// }