From adf38a1dbd085c19c4c87ad242e0b340f1655fcb Mon Sep 17 00:00:00 2001 From: jet2tlf Date: Mon, 3 Jun 2024 14:59:28 -0300 Subject: codecrafters submit [skip ci] --- cmd/mybittorrent/client.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'cmd/mybittorrent/client.go') diff --git a/cmd/mybittorrent/client.go b/cmd/mybittorrent/client.go index f3988b6..ef3d860 100644 --- a/cmd/mybittorrent/client.go +++ b/cmd/mybittorrent/client.go @@ -1,9 +1,13 @@ package main import ( + "bytes" "encoding/binary" + "encoding/hex" "fmt" + "io" "log/slog" + "net" "net/http" "net/url" "os" @@ -30,6 +34,8 @@ type PeerResponse struct { Peers []string } +type HandshakeMessage []byte + func NewClient(peerId string, port int) *Client { return &Client{ PeerId: peerId, @@ -134,3 +140,51 @@ func (c *Client) GetPeers(filename string) (PeerResponse, error) { Peers: DecodePeers([]byte(resp.Peers)), }, err } + +func (m HandshakeMessage) PeerIdHex() string { + + return hex.EncodeToString(m[48:]) + +} + +func (c *Client) Handshake(filename, peerAddr string) (HandshakeMessage, error) { + ct, ok := c.Torrents[filename] + if !ok { + return nil, fmt.Errorf("missing torrent file: %s", filename) + } + + buf := new(bytes.Buffer) + buf.WriteByte(19) + buf.WriteString("BitTorrent protocol") + buf.Write([]byte{0, 0, 0, 0, 0, 0, 0, 0}) + + hash, err := ct.Meta.InfoHash() + if err != nil { + return nil, err + } + + buf.Write(hash) + buf.WriteString(c.PeerId) + + conn, err := net.Dial("tcp", peerAddr) + defer func(conn net.Conn) { + err := conn.Close() + if err != nil { + slog.Error("failed to close connection", "peerAddr", peerAddr) + } + }(conn) + + if err != nil { + return nil, err + } + + _, err = buf.WriteTo(conn) + if err != nil { + return nil, err + } + + respBuf := make([]byte, 68) + _, err = io.LimitReader(conn, 68).Read(respBuf) + + return respBuf, nil +} -- cgit v1.2.3