@ -4,8 +4,10 @@ import (
"bufio"
"bufio"
"fmt"
"fmt"
"io"
"io"
"reflect"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/proto"
"github.com/golang/snappy"
"github.com/jordanorelli/hyperstone/dota"
"github.com/jordanorelli/hyperstone/dota"
)
)
@ -13,8 +15,8 @@ type parser struct {
// the source of replay bytes. Must NOT be compressed.
// the source of replay bytes. Must NOT be compressed.
source * bufio . Reader
source * bufio . Reader
dump Message s bool
dump Datagram s bool
dumpPackets bool
dumpPackets bool
}
}
func newParser ( r io . Reader ) * parser {
func newParser ( r io . Reader ) * parser {
@ -38,26 +40,29 @@ func (p *parser) start() error {
func ( p * parser ) run ( ) error {
func ( p * parser ) run ( ) error {
for {
for {
msg , err := p . read Message ( )
gra m, err := p . read Datagram ( )
if err != nil {
if err != nil {
return wrap ( err , "read message error in run loop")
return wrap ( err , "read datagram error in run loop")
}
}
if p . dump Message s {
if p . dump Datagram s {
fmt . Println ( msg )
fmt . Println ( gra m)
}
}
switch msg . cmd {
if len ( gram . body ) == 0 {
continue
}
switch gram . cmd {
case dota . EDemoCommands_DEM_Packet :
case dota . EDemoCommands_DEM_Packet :
if err := msg . check ( p . dumpPackets ) ; err != nil {
if err := gra m. check ( p . dumpPackets ) ; err != nil {
fmt . Printf ( "error: %v\n" , err )
fmt . Printf ( "error: %v\n" , err )
}
}
default :
default :
m := cmdFactory . BuildMessage ( int ( msg . cmd ) )
m := cmdFactory . BuildMessage ( int ( gra m. cmd ) )
if m != nil {
if m != nil {
err := proto . Unmarshal ( msg . body , m )
err := proto . Unmarshal ( gra m. body , m )
if err != nil {
if err != nil {
fmt . Printf ( "cmd unmarshal error: %v\n" , err )
fmt . Printf ( "cmd unmarshal error unpacking data of length %d with cmd type %s into message type %v: %v\n" , len ( gram . body ) , gram . cmd , reflect . TypeOf ( m ) , err )
} else {
fmt . Println ( m )
}
}
}
}
}
}
@ -133,31 +138,39 @@ func (p *parser) readCommand() (dota.EDemoCommands, bool, error) {
return dota . EDemoCommands ( n ) , compressed , nil
return dota . EDemoCommands ( n ) , compressed , nil
}
}
func ( p * parser ) read Message ( ) ( * dataGram , error ) {
func ( p * parser ) read Datagram ( ) ( * dataGram , error ) {
cmd , compressed , err := p . readCommand ( )
cmd , compressed , err := p . readCommand ( )
if err != nil {
if err != nil {
return nil , wrap ( err , "read Message couldn't get a command")
return nil , wrap ( err , "read Datagram couldn't get a command")
}
}
tick , err := p . decodeVarint ( )
tick , err := p . decodeVarint ( )
if err != nil {
if err != nil {
return nil , wrap ( err , "read Message couldn't read the tick value")
return nil , wrap ( err , "read Datagram couldn't read the tick value")
}
}
size , err := p . decodeVarint ( )
size , err := p . decodeVarint ( )
if err != nil {
if err != nil {
return nil , wrap ( err , "read Message couldn't read the size value")
return nil , wrap ( err , "read Datagram couldn't read the size value")
}
}
if size > 0 {
if size > 0 {
buf := make ( [ ] byte , int ( size ) )
buf := make ( [ ] byte , int ( size ) )
if _ , err := io . ReadFull ( p . source , buf ) ; err != nil {
if _ , err := io . ReadFull ( p . source , buf ) ; err != nil {
return nil , wrap ( err , "readMessage couldn't read message body" )
return nil , wrap ( err , "readDatagram couldn't read datagram body" )
}
if compressed {
var err error
buf , err = snappy . Decode ( nil , buf )
if err != nil {
return nil , wrap ( err , "readDatagram couldn't snappy decode body" )
}
}
}
// TODO: pool these!
// TODO: pool these!
return & dataGram { cmd , int64 ( tick ) , compressed , buf } , nil
return & dataGram { cmd , int64 ( tick ) , buf} , nil
}
}
// TODO: pool these!
// TODO: pool these!
return & dataGram { cmd , int64 ( tick ) , compressed , nil } , nil
return & dataGram { cmd , int64 ( tick ) , nil } , nil
}
}