Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .mise/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ run = "go test ./..."

[tasks.coverage]
description = "Run the tests with coverage"
run = "go test -cover ./..."
run = "mkdir -p ./ressources && go test -cover ./... -coverprofile=ressources/coverage.out"

[tasks.coverage-html]
description = "Run the tests with coverage"
run = "go tool cover -html=ressources/coverage.out"

[tasks.lint]
description = "Run the linter"
Expand Down
6 changes: 3 additions & 3 deletions internal/command/acknowledge/acknowledge.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import (
"github.com/AutoDruid/photon-parser/internal/types"
)

func Parse(reader *reader.Reader, out *types.Acknowledge) error {
func ParseInto(reader *reader.Reader, dest *types.Acknowledge) error {
var err error

out.AckReliableSequenceNumber, err = reader.ReadUInt32BE()
dest.AckReliableSequenceNumber, err = reader.ReadUInt32BE()
if err != nil {
return err
}

out.AckSentTime, err = reader.ReadUInt32BE()
dest.AckSentTime, err = reader.ReadUInt32BE()
if err != nil {
return err
}
Expand Down
122 changes: 61 additions & 61 deletions internal/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,140 +25,140 @@ import (
// The returned Command struct contains all header fields and the raw payload
// in the Data field. For SendReliable commands, the Data can be further parsed
// using the reliable package.
func Parse[P types.ParameterView](ctx *context.Context[P], out *types.Command[P]) error {
err := parseHeader(out, ctx.Reader)
func ParseInto[P types.ParameterView](ctx *context.Context[P], dest *types.Command[P]) error {
err := readCommandHeaderInto(ctx.Reader, dest)

if out.Type > types.SendReliableFragmentCommand {
if dest.Type > types.SendReliableFragmentCommand {
remaining := ctx.Reader.Max - ctx.Reader.Cursor - 1
rest, err := ctx.Reader.ReadBytes(remaining)
if err != nil {
return err
}
out.UnknownPayload = types.UnknownPayload{Raw: rest, Kind: out.Type}
dest.UnknownPayload = types.UnknownPayload{Raw: rest, Kind: dest.Type}
return nil
}

if err != nil {
return err
}

if out.Length < types.COMMAND_HEADER_SIZE {
if dest.Length < types.COMMAND_HEADER_SIZE {
return errors.ErrHeaderSize
}

err = parsePayload(out, ctx)
err = readCommandPayloadInto(ctx, dest)
if err != nil {
rest, _ := ctx.Reader.ReadBytes(int(out.Length - types.COMMAND_HEADER_SIZE))
rest, _ := ctx.Reader.ReadBytes(int(dest.Length - types.COMMAND_HEADER_SIZE))
// don't fatal — just store raw for encrypted packets
out.UnknownPayload = types.UnknownPayload{Raw: rest, Kind: out.Type}
dest.UnknownPayload = types.UnknownPayload{Raw: rest, Kind: dest.Type}
}

emit(ctx.Hooks, out)
emit(ctx.Hooks, dest)

return nil
}

func emit[P types.ParameterView](hooks *hooks.Hooks[P], out *types.Command[P]) {
if hooks == nil {
return
func readCommandHeaderInto[P types.ParameterView](r *reader.Reader, dest *types.Command[P]) error {
var err error

b, err := r.ReadUInt8()
if err != nil {
return err
}

if hooks.SyncHooks.OnCommand != nil {
hooks.SyncHooks.OnCommand(*out)
dest.Type = types.CommandType(b)

if dest.Type > types.SendReliableFragmentCommand {
return nil
}

if hooks.AsyncHooks.OnCommand == nil {
return
dest.ChannelID, err = r.ReadUInt8()
if err != nil {
return err
}

select {
case hooks.AsyncHooks.OnCommand <- *out:
default: // don't block parser
dest.Flags, err = r.ReadUInt8()
if err != nil {
return err
}

dest.ReservedByte, err = r.ReadUInt8()
if err != nil {
return err
}

dest.Length, err = r.ReadUInt32BE()
if err != nil {
return err
}

dest.ReliableSequenceNumber, err = r.ReadUInt32BE()
if err != nil {
return err
}

return nil
}

func parsePayload[P types.ParameterView](out *types.Command[P], ctx *context.Context[P]) error {
switch out.Type {
func readCommandPayloadInto[P types.ParameterView](ctx *context.Context[P], dest *types.Command[P]) error {
switch dest.Type {
case types.SendUnreliableCommand:

_, err := ctx.Reader.ReadBytes(4)
if err != nil {
return err
}
err = reliable.Parse(ctx, &out.UnreliablePayload, out.Length)
err = reliable.ParseInto(ctx, dest.Length, &dest.UnreliablePayload)
if err != nil {
return err
}
case types.SendReliableCommand:
err := reliable.Parse(ctx, &out.ReliablePayload, out.Length)
err := reliable.ParseInto(ctx, dest.Length, &dest.ReliablePayload)
if err != nil {
return err
}
case types.AcknowledgeCommand:
err := acknowledge.Parse(ctx.Reader, &out.AcknowledgePayload)
err := acknowledge.ParseInto(ctx.Reader, &dest.AcknowledgePayload)
if err != nil {
return err
}
case types.ConnectCommand, types.VerifyConnectCommand:
err := connect.Parse(ctx.Reader, &out.ConnectPayload)
err := connect.ParseInto(ctx.Reader, &dest.ConnectPayload)
if err != nil {
return err
}
case types.SendReliableFragmentCommand:
err := reliable.ParseFragment(ctx, &out.ReliableFragmentPayload, &out.ReliablePayload, out.Length)
err := reliable.ParseIntoFragment(ctx, dest.Length, &dest.ReliableFragmentPayload, &dest.ReliablePayload)
if err != nil {
return err
}
case types.PingCommand:
out.PingPayload = struct{}{}
dest.PingPayload = struct{}{}
case types.DisconnectCommand:
out.DisconnectPayload = struct{}{}
dest.DisconnectPayload = struct{}{}
default:
return fmt.Errorf("unsupported command type %d", out.Type)
return fmt.Errorf("unsupported command type %d", dest.Type)
}

return nil
}

func parseHeader[P types.ParameterView](out *types.Command[P], r *reader.Reader) error {
var err error

b, err := r.ReadUInt8()
if err != nil {
return err
}

out.Type = types.CommandType(b)

if out.Type > types.SendReliableFragmentCommand {
return nil
}

out.ChannelID, err = r.ReadUInt8()
if err != nil {
return err
}

out.Flags, err = r.ReadUInt8()
if err != nil {
return err
func emit[P types.ParameterView](hooks *hooks.Hooks[P], dest *types.Command[P]) {
if hooks == nil {
return
}

out.ReservedByte, err = r.ReadUInt8()
if err != nil {
return err
if hooks.SyncHooks.OnCommand != nil {
hooks.SyncHooks.OnCommand(*dest)
}

out.Length, err = r.ReadUInt32BE()
if err != nil {
return err
if hooks.AsyncHooks.OnCommand == nil {
return
}

out.ReliableSequenceNumber, err = r.ReadUInt32BE()
if err != nil {
return err
select {
case hooks.AsyncHooks.OnCommand <- *dest:
default: // don't block parser
}

return nil
}
2 changes: 1 addition & 1 deletion internal/command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestParseSession(t *testing.T) {

var cmd types.Command[v16.Parameter]

err := command.Parse(ctx, &cmd)
err := command.ParseInto(ctx, &cmd)

if err != nil {
t.Fatalf("LoadFromWiresharkExport() failed: %v", err)
Expand Down
18 changes: 9 additions & 9 deletions internal/command/connect/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,38 @@ import (
"github.com/AutoDruid/photon-parser/internal/types"
)

func Parse(reader *reader.Reader, out *types.Connect) error {
func ParseInto(reader *reader.Reader, dest *types.Connect) error {
var err error

out.Mtu, err = reader.ReadUInt32BE()
dest.Mtu, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.WindowSize, err = reader.ReadUInt32BE()
dest.WindowSize, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.ChannelCount, err = reader.ReadUInt32BE()
dest.ChannelCount, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.IncomingBandwidth, err = reader.ReadUInt32BE()
dest.IncomingBandwidth, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.OutgoingBandwidth, err = reader.ReadUInt32BE()
dest.OutgoingBandwidth, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.DisconnectThrottle, err = reader.ReadUInt32BE()
dest.DisconnectThrottle, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.PacketThrottleAcceleration, err = reader.ReadUInt32BE()
dest.PacketThrottleAcceleration, err = reader.ReadUInt32BE()
if err != nil {
return err
}
out.PacketThrottleDeceleration, err = reader.ReadUInt32BE()
dest.PacketThrottleDeceleration, err = reader.ReadUInt32BE()
if err != nil {
return err
}
Expand Down
7 changes: 0 additions & 7 deletions internal/command/disconnect/disconnect.go

This file was deleted.

7 changes: 0 additions & 7 deletions internal/command/ping/ping.go

This file was deleted.

26 changes: 15 additions & 11 deletions internal/command/reliable/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,56 @@ import (
"github.com/AutoDruid/photon-parser/internal/types"
)

func ParseFragment[P types.ParameterView](ctx *context.Context[P], out *types.Fragment, outt *types.Reliable[P], length uint32) error {
// ParseIntoFragment parses a Photon reliable fragment from a parser.Reader.
// It reads the fragment header, then feeds the fragment into the assembler.
// If the fragment is complete, it parses the reliable message into the destination.
// Returns an error if any part of parsing fails.
func ParseIntoFragment[P types.ParameterView](ctx *context.Context[P], length uint32, destFragment *types.Fragment, destReliable *types.Reliable[P]) error {

err := parseMetadata(ctx.Reader, out)
err := readFragmentHeader(ctx.Reader, destFragment)
if err != nil {
return err
}

data, completed := ctx.Assembler.Feed(*out)
data, completed := ctx.Assembler.Feed(*destFragment)

if completed {
ctx.Reader.Reset(data)
return Parse(ctx, outt, length)
return ParseInto(ctx, length, destReliable)
}

return nil
}

func parseMetadata(reader *reader.Reader, out *types.Fragment) error {
func readFragmentHeader(reader *reader.Reader, dest *types.Fragment) error {
var err error

out.ID, err = reader.ReadUInt32BE()
dest.ID, err = reader.ReadUInt32BE()
if err != nil {
return err
}

out.Count, err = reader.ReadUInt32BE()
dest.Count, err = reader.ReadUInt32BE()
if err != nil {
return err
}

out.Index, err = reader.ReadUInt32BE()
dest.Index, err = reader.ReadUInt32BE()
if err != nil {
return err
}

out.Size, err = reader.ReadUInt32BE()
dest.Size, err = reader.ReadUInt32BE()
if err != nil {
return err
}

out.Offset, err = reader.ReadUInt32BE()
dest.Offset, err = reader.ReadUInt32BE()
if err != nil {
return err
}

out.Data = reader.ReadRemaining()
dest.Data = reader.ReadRemaining()

return nil
}
Loading
Loading