aboutsummaryrefslogtreecommitdiff
path: root/cmd/mybittorrent
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/mybittorrent')
-rw-r--r--cmd/mybittorrent/file.go85
-rw-r--r--cmd/mybittorrent/main.go51
2 files changed, 105 insertions, 31 deletions
diff --git a/cmd/mybittorrent/file.go b/cmd/mybittorrent/file.go
new file mode 100644
index 0000000..2302976
--- /dev/null
+++ b/cmd/mybittorrent/file.go
@@ -0,0 +1,85 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+type File struct {
+ Announce string `bencode:"announce"`
+ Info FileInfo `bencode:"info"`
+}
+
+type FileInfo struct {
+ Length int `bencode:"length"`
+ Name string `bencode:"name"`
+ PieceLength int `bencode:"piece length"`
+ Pieces string `bencode:"pieces"`
+}
+
+func NewFile() *File {
+ return &File{}
+}
+
+func (f *File) ReadFrom(r io.ReadCloser) error {
+ buf := new(bytes.Buffer)
+
+ _, err := buf.ReadFrom(r)
+ if err != nil {
+ return err
+ }
+
+ defer func(r io.ReadCloser) {
+ err := r.Close()
+ if err != nil {
+ fmt.Printf("failed to close: %v+\n", err)
+ }
+ }(r)
+
+ if err != nil {
+ return err
+ }
+
+ decoded, err := NewDecoder(buf.String()).Decode()
+ if err != nil {
+ return err
+ }
+
+ content, ok := decoded.(map[string]any)
+ if !ok {
+ return fmt.Errorf("invalid contents")
+ }
+
+ f.Announce, ok = content["announce"].(string)
+ if !ok {
+ return fmt.Errorf("invalid announce field")
+ }
+
+ info, ok := content["info"].(map[string]any)
+ if !ok {
+ return fmt.Errorf("invalid info field")
+ }
+
+ f.Info.Length, ok = info["length"].(int)
+ if !ok {
+ return fmt.Errorf("invalid info.length field")
+ }
+
+ f.Info.Name, ok = info["name"].(string)
+ if !ok {
+ return fmt.Errorf("invalid info.name field")
+ }
+
+ f.Info.PieceLength, ok = info["piece length"].(int)
+ if !ok {
+ return fmt.Errorf("invalid info.piece length field")
+ }
+
+ f.Info.Pieces, ok = info["pieces"].(string)
+ if !ok {
+ return fmt.Errorf("invalid info.pieces field")
+ }
+
+ return nil
+}
diff --git a/cmd/mybittorrent/main.go b/cmd/mybittorrent/main.go
index e3e902a..7905e01 100644
--- a/cmd/mybittorrent/main.go
+++ b/cmd/mybittorrent/main.go
@@ -4,42 +4,14 @@ import (
"encoding/json"
"fmt"
"os"
- "strconv"
- "strings"
- "unicode"
// bencode "github.com/jackpal/bencode-go" // Available if you need it!
)
-func decodeBencode(bencodedString string) (interface{}, error) {
- if unicode.IsDigit(rune(bencodedString[0])) {
- var firstColonIndex int
-
- for i := 0; i < len(bencodedString); i++ {
- if bencodedString[i] == ':' {
- firstColonIndex = i
- break
- }
- }
-
- lengthStr := bencodedString[:firstColonIndex]
-
- length, err := strconv.Atoi(lengthStr)
- if err != nil {
- return "", err
- }
-
- return bencodedString[firstColonIndex+1 : firstColonIndex+1+length], nil
- } else if rune(bencodedString[0]) == 'i' {
- return strconv.Atoi(bencodedString[1:strings.IndexByte(bencodedString, 'e')])
- } else {
- return "", fmt.Errorf("only strings are supported at the moment")
- }
-}
-
func main() {
command := os.Args[1]
- if command == "decode" {
+ switch command {
+ case "decode":
bencodedValue := os.Args[2]
decoded, err := NewDecoder(bencodedValue).Decode()
@@ -50,7 +22,24 @@ func main() {
jsonOutput, _ := json.Marshal(decoded)
fmt.Println(string(jsonOutput))
- } else {
+
+ case "info":
+ f, err := os.Open(os.Args[2])
+ if err != nil {
+ fmt.Println("Failed to open file: " + os.Args[2])
+ }
+
+ tf := NewFile()
+
+ err = tf.ReadFrom(f)
+ if err != nil {
+ fmt.Println("Failed to parse file: " + os.Args[2])
+ panic(err)
+ }
+
+ fmt.Printf("Tracker URL: %s\nLength: %d", tf.Announce, tf.Info.Length)
+
+ default:
fmt.Println("Unknown command: " + command)
os.Exit(1)
}