1
0
mirror of https://github.com/veggiedefender/torrent-client.git synced 2025-11-06 09:29:16 +02:00
Files
torrent-client/message/message.go

107 lines
2.1 KiB
Go
Raw Normal View History

2019-12-22 14:57:10 -05:00
package message
2019-12-22 12:51:59 -05:00
import (
"encoding/binary"
2019-12-22 14:45:16 -05:00
"fmt"
2019-12-22 12:51:59 -05:00
"io"
)
2019-12-22 14:45:16 -05:00
type messageID uint8
2019-12-22 12:51:59 -05:00
// Message ID
const (
2019-12-22 14:45:16 -05:00
MsgChoke messageID = 0
MsgUnchoke messageID = 1
MsgInterested messageID = 2
MsgNotInterested messageID = 3
MsgHave messageID = 4
MsgBitfield messageID = 5
MsgRequest messageID = 6
MsgPiece messageID = 7
MsgCancel messageID = 8
MsgPort messageID = 9
2019-12-22 12:51:59 -05:00
)
// Message stores ID and payload of a message
2019-12-22 12:51:59 -05:00
type Message struct {
2019-12-22 14:45:16 -05:00
ID messageID
2019-12-22 12:51:59 -05:00
Payload []byte
}
// Serialize serializes a message into a buffer of the form
// <length prefix><message ID><payload>
// Interprets `nil` as a keep-alive message
2019-12-22 12:51:59 -05:00
func (m *Message) Serialize() []byte {
if m == nil {
return make([]byte, 4)
}
length := uint32(len(m.Payload) + 1) // +1 for id
buf := make([]byte, 4+length)
binary.BigEndian.PutUint32(buf[0:4], length)
buf[4] = byte(m.ID)
copy(buf[5:], m.Payload)
return buf
}
// ReadMessage parses a message from a stream. Returns `nil` on keep-alive message
func ReadMessage(r io.Reader) (*Message, error) {
2019-12-22 12:51:59 -05:00
lengthBuf := make([]byte, 4)
_, err := io.ReadFull(r, lengthBuf)
if err != nil {
return nil, err
}
length := binary.BigEndian.Uint32(lengthBuf)
2019-12-22 14:45:16 -05:00
// keep-alive message
2019-12-22 12:51:59 -05:00
if length == 0 {
return nil, nil
}
messageBuf := make([]byte, length)
_, err = io.ReadFull(r, messageBuf)
if err != nil {
return nil, err
}
m := Message{
2019-12-22 14:45:16 -05:00
ID: messageID(messageBuf[0]),
2019-12-22 12:51:59 -05:00
Payload: messageBuf[1:],
}
return &m, nil
}
2019-12-22 14:45:16 -05:00
func (m *Message) String() string {
if m == nil {
return "KeepAlive"
}
var idName string
switch m.ID {
case MsgChoke:
idName = "Choke"
case MsgUnchoke:
idName = "Unchoke"
case MsgInterested:
idName = "Interested"
case MsgNotInterested:
idName = "NotInterested"
case MsgHave:
idName = "Have"
case MsgBitfield:
idName = "Bitfield"
case MsgRequest:
idName = "Request"
case MsgPiece:
idName = "Piece"
case MsgCancel:
idName = "Cancel"
case MsgPort:
idName = "Port"
default:
idName = fmt.Sprintf("Unknown#%d", m.ID)
}
return fmt.Sprintf("%s\t[% x]", idName, m.Payload)
}