package protocol
import (
"bytes"
"github.com/golang/protobuf/proto"
"encoding/binary"
"fmt"
. "github.com/Philipp15b/go-steam/protocol/steamlang"
)
// TODO: Headers are always deserialized twice.
// Represents an incoming, partially unread message.
type Packet struct {
EMsg EMsg
IsProto bool
TargetJobId JobId
SourceJobId JobId
Data []byte
}
func NewPacket(data []byte) (*Packet, error) {
var rawEMsg uint32
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &rawEMsg)
if err != nil {
return nil, err
}
eMsg := NewEMsg(rawEMsg)
buf := bytes.NewReader(data)
if eMsg == EMsg_ChannelEncryptRequest || eMsg == EMsg_ChannelEncryptResult {
header := NewMsgHdr()
header.Msg = eMsg
err = header.Deserialize(buf)
if err != nil {
return nil, err
}
return &Packet{
EMsg: eMsg,
IsProto: false,
TargetJobId: JobId(header.TargetJobID),
SourceJobId: JobId(header.SourceJobID),
Data: data,
}, nil
} else if IsProto(rawEMsg) {
header := NewMsgHdrProtoBuf()
header.Msg = eMsg
err = header.Deserialize(buf)
if err != nil {
return nil, err
}
return &Packet{
EMsg: eMsg,
IsProto: true,
TargetJobId: JobId(header.Proto.GetJobidTarget()),
SourceJobId: JobId(header.Proto.GetJobidSource()),
Data: data,
}, nil
} else {
header := NewExtendedClientMsgHdr()
header.Msg = eMsg
err = header.Deserialize(buf)
if err != nil {
return nil, err
}
return &Packet{
EMsg: eMsg,
IsProto: false,
TargetJobId: JobId(header.TargetJobID),
SourceJobId: JobId(header.SourceJobID),
Data: data,
}, nil
}
}
func (p *Packet) String() string {
return fmt.Sprintf("Packet{EMsg = %v, Proto = %v, Len = %v, TargetJobId = %v, SourceJobId = %v}", p.EMsg, p.IsProto, len(p.Data), p.TargetJobId, p.SourceJobId)
}
func (p *Packet) ReadProtoMsg(body proto.Message) *ClientMsgProtobuf {
header := NewMsgHdrProtoBuf()
buf := bytes.NewBuffer(p.Data)
header.Deserialize(buf)
proto.Unmarshal(buf.Bytes(), body)
return &ClientMsgProtobuf{ // protobuf messages have no payload
Header: header,
Body: body,
}
}
func (p *Packet) ReadClientMsg(body MessageBody) *ClientMsg {
header := NewExtendedClientMsgHdr()
buf := bytes.NewReader(p.Data)
header.Deserialize(buf)
body.Deserialize(buf)
payload := make([]byte, buf.Len())
buf.Read(payload)
return &ClientMsg{
Header: header,
Body: body,
Payload: payload,
}
}
func (p *Packet) ReadMsg(body MessageBody) *Msg {
header := NewMsgHdr()
buf := bytes.NewReader(p.Data)
header.Deserialize(buf)
body.Deserialize(buf)
payload := make([]byte, buf.Len())
buf.Read(payload)
return &Msg{
Header: header,
Body: body,
Payload: payload,
}
}