package input import ( "errors" "fmt" "math" "strconv" "strings" "github.com/ap-pauloafonso/ratio-spoof/internal/bencode" ) const ( minPortNumber = 1 maxPortNumber = 65535 speedSuffixLength = 4 ) type InputArgs struct { TorrentPath string InitialDownloaded string DownloadSpeed string InitialUploaded string Client string UploadSpeed string Port int Debug bool } type InputParsed struct { TorrentPath string InitialDownloaded int DownloadSpeed int InitialUploaded int UploadSpeed int Port int Debug bool } var validInitialSufixes = [...]string{"%", "b", "kb", "mb", "gb", "tb"} var validSpeedSufixes = [...]string{"kbps", "mbps"} func (I *InputArgs) ParseInput(torrentInfo *bencode.TorrentInfo) (*InputParsed, error) { downloaded, err := extractInputInitialByteCount(I.InitialDownloaded, torrentInfo.TotalSize, true) if err != nil { return nil, err } uploaded, err := extractInputInitialByteCount(I.InitialUploaded, torrentInfo.TotalSize, false) if err != nil { return nil, err } downloadSpeed, err := extractInputByteSpeed(I.DownloadSpeed) if err != nil { return nil, err } uploadSpeed, err := extractInputByteSpeed(I.UploadSpeed) if err != nil { return nil, err } if I.Port < minPortNumber || I.Port > maxPortNumber { return nil, errors.New(fmt.Sprint("port number must be between %i and %i", minPortNumber, maxPortNumber)) } return &InputParsed{InitialDownloaded: downloaded, DownloadSpeed: downloadSpeed, InitialUploaded: uploaded, UploadSpeed: uploadSpeed, Debug: I.Debug, Port: I.Port, }, nil } func checkSpeedSufix(input string) (valid bool, suffix string) { for _, v := range validSpeedSufixes { if strings.HasSuffix(strings.ToLower(input), v) { return true, input[len(input)-4:] } } return false, "" } func extractInputInitialByteCount(initialSizeInput string, totalBytes int, errorIfHigher bool) (int, error) { byteCount, err := strSize2ByteSize(initialSizeInput, totalBytes) if err != nil { return 0, err } if errorIfHigher && byteCount > totalBytes { return 0, errors.New("initial downloaded can not be higher than the torrent size") } if byteCount < 0 { return 0, errors.New("initial value can not be negative") } return byteCount, nil } //Takes an dirty speed input and returns the bytes per second based on the suffixes // example 1kbps(string) > 1024 bytes per second (int) func extractInputByteSpeed(initialSpeedInput string) (int, error) { ok, suffix := checkSpeedSufix(initialSpeedInput) if !ok { return 0, fmt.Errorf("speed must be in %v", validSpeedSufixes) } speedVal, err := strconv.ParseFloat(initialSpeedInput[:len(initialSpeedInput)-speedSuffixLength], 64) if err != nil { return 0, errors.New("invalid speed number") } if speedVal < 0 { return 0, errors.New("speed can not be negative") } if suffix == "kbps" { speedVal *= 1024 } else { speedVal = speedVal * 1024 * 1024 } ret := int(speedVal) return ret, nil } func extractByteSizeNumber(strWithSufix string, sufixLength, power int) (int, error) { v, err := strconv.ParseFloat(strWithSufix[:len(strWithSufix)-sufixLength], 64) if err != nil { return 0, err } result := v * math.Pow(1024, float64(power)) return int(result), nil } func strSize2ByteSize(input string, totalSize int) (int, error) { lowerInput := strings.ToLower(input) invalidSizeError := errors.New("invalid input size") switch { case strings.HasSuffix(lowerInput, "kb"): { v, err := extractByteSizeNumber(lowerInput, 2, 1) if err != nil { return 0, invalidSizeError } return v, nil } case strings.HasSuffix(lowerInput, "mb"): { v, err := extractByteSizeNumber(lowerInput, 2, 2) if err != nil { return 0, invalidSizeError } return v, nil } case strings.HasSuffix(lowerInput, "gb"): { v, err := extractByteSizeNumber(lowerInput, 2, 3) if err != nil { return 0, invalidSizeError } return v, nil } case strings.HasSuffix(lowerInput, "tb"): { v, err := extractByteSizeNumber(lowerInput, 2, 4) if err != nil { return 0, invalidSizeError } return v, nil } case strings.HasSuffix(lowerInput, "b"): { v, err := extractByteSizeNumber(lowerInput, 1, 0) if err != nil { return 0, invalidSizeError } return v, nil } case strings.HasSuffix(lowerInput, "%"): { v, err := strconv.ParseFloat(lowerInput[:len(lowerInput)-1], 64) if v < 0 || v > 100 || err != nil { return 0, errors.New("percent value must be in (0-100)") } result := int(float64(v/100) * float64(totalSize)) return result, nil } default: return 0, errors.New("Size not found") } }