Skip to content

Commit 7f5a03d

Browse files
committed
core: don't panic, return errors instead (#183)
1 parent cf7da23 commit 7f5a03d

File tree

7 files changed

+58
-41
lines changed

7 files changed

+58
-41
lines changed

datatables.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func (p *Parser) bindTeamStates() {
132132
case "Spectator": // Ignore
133133

134134
default:
135-
panic(fmt.Sprintf("Unexpected team %q", team))
135+
p.setError(fmt.Errorf("unexpected team %q", team))
136136
}
137137

138138
if s != nil {
@@ -505,7 +505,7 @@ func (p *Parser) bindWeapon(entity *st.Entity, wepType common.EquipmentElement)
505505
if strings.Contains(eq.OriginalString, altName) {
506506
eq.Weapon = alt
507507
} else if !strings.Contains(eq.OriginalString, defaultName) {
508-
panic(fmt.Sprintf("Unknown weapon model %q", eq.OriginalString))
508+
p.setError(fmt.Errorf("unknown weapon model %q", eq.OriginalString))
509509
}
510510
}
511511

demoinfocs_test.go

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -100,41 +100,29 @@ func TestDemoInfoCs(t *testing.T) {
100100

101101
// bomb planting checks
102102
p.RegisterEventHandler(func(begin events.BombPlantBegin) {
103-
if !begin.Player.IsPlanting {
104-
t.Error("Player started planting but IsPlanting is false")
105-
}
103+
assertions.True(begin.Player.IsPlanting, "Player started planting but IsPlanting is false")
106104
})
107105
p.RegisterEventHandler(func(abort events.BombPlantAborted) {
108-
if abort.Player.IsPlanting {
109-
t.Error("Player aborted planting but IsPlanting is true")
110-
}
106+
assertions.False(abort.Player.IsPlanting, "Player aborted planting but IsPlanting is true")
111107
})
112108
p.RegisterEventHandler(func(planted events.BombPlanted) {
113-
if planted.Player.IsPlanting {
114-
t.Error("Player finished planting but IsPlanting is true")
115-
}
109+
assertions.False(planted.Player.IsPlanting, "Player finished planting but IsPlanting is true")
116110
})
117111

118112
// airborne checks
119113
// we don't check RoundStart or RoundFreezetimeEnd since players may spawn airborne
120114
p.RegisterEventHandler(func(plantBegin events.BombPlantBegin) {
121-
if plantBegin.Player.IsAirborne() {
122-
t.Error("Player is airborne during plant")
123-
}
115+
assertions.False(plantBegin.Player.IsAirborne(), "Player can't be airborne during plant")
124116
})
125117

126118
// reload checks
127119
p.RegisterEventHandler(func(reload events.WeaponReload) {
128-
if !reload.Player.IsReloading {
129-
t.Error("Player started reloading but IsReloading is false")
130-
}
120+
assertions.True(reload.Player.IsReloading, "Player started reloading but IsReloading is false")
131121
})
132122

133123
p.RegisterEventHandler(func(start events.RoundFreezetimeEnd) {
134124
for _, pl := range p.GameState().Participants().All() {
135-
if pl.IsReloading {
136-
t.Error("Player is reloading at the start of the round")
137-
}
125+
assertions.False(pl.IsReloading, "Player can't be reloading at the start of the round")
138126
}
139127
})
140128

game_events.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package demoinfocs
22

33
import (
4+
"errors"
45
"fmt"
56
"strconv"
67

@@ -419,7 +420,12 @@ func (geh gameEventHandler) playerConnect(data map[string]*msg.CSVCMsg_GameEvent
419420
guid: data["networkid"].GetValString(),
420421
}
421422

422-
pl.xuid = getCommunityID(pl.guid)
423+
var err error
424+
pl.xuid, err = getCommunityID(pl.guid)
425+
426+
if err != nil {
427+
geh.parser.setError(fmt.Errorf("failed to parse player XUID: %v", err.Error()))
428+
}
423429

424430
geh.parser.rawPlayers[int(data["index"].GetValByte())] = pl
425431
}
@@ -511,7 +517,7 @@ func (geh gameEventHandler) bombEvent(data map[string]*msg.CSVCMsg_GameEventKeyT
511517
t := geh.parser.triggers[site]
512518

513519
if t == nil {
514-
panic(fmt.Sprintf("Bombsite with index %d not found", site))
520+
geh.parser.setError(fmt.Errorf("bombsite with index %d not found", site))
515521
}
516522

517523
if t.contains(geh.parser.bombsiteA.center) {
@@ -521,7 +527,7 @@ func (geh gameEventHandler) bombEvent(data map[string]*msg.CSVCMsg_GameEventKeyT
521527
bombEvent.Site = events.BombsiteB
522528
geh.parser.bombsiteB.index = site
523529
} else {
524-
panic("Bomb not planted on bombsite A or B")
530+
geh.parser.setError(errors.New("bomb not planted on bombsite A or B"))
525531
}
526532
}
527533

@@ -703,21 +709,21 @@ func mapGameEventData(d *msg.CSVCMsg_GameEventListDescriptorT, e *msg.CSVCMsg_Ga
703709
// We're all better off not asking questions
704710
const valveMagicNumber = 76561197960265728
705711

706-
func getCommunityID(guid string) int64 {
712+
func getCommunityID(guid string) (int64, error) {
707713
if guid == "BOT" {
708-
return 0
714+
return 0, nil
709715
}
710716

711717
authSrv, errSrv := strconv.ParseInt(guid[8:9], 10, 64)
712718
authID, errID := strconv.ParseInt(guid[10:], 10, 64)
713719

714720
if errSrv != nil {
715-
panic(errSrv.Error())
721+
return 0, errSrv
716722
}
717723
if errID != nil {
718-
panic(errID.Error())
724+
return 0, errID
719725
}
720726

721727
// WTF are we doing here?
722-
return valveMagicNumber + authID*2 + authSrv
728+
return valveMagicNumber + authID*2 + authSrv, nil
723729
}

net_messages.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const entitySentinel = 9999
1212

1313
func (p *Parser) handlePacketEntities(pe *msg.CSVCMsg_PacketEntities) {
1414
defer func() {
15-
p.setError(recoverFromUnexpectedEOF(recover()))
15+
p.setError(recoverFromPanic(recover()))
1616
}()
1717

1818
r := bit.NewSmallBitReader(bytes.NewReader(pe.EntityData))

parser_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package demoinfocs
22

33
import (
4+
"errors"
5+
"io"
46
"math"
57
"testing"
68
"time"
@@ -62,3 +64,15 @@ func TestParser_Progress_NoHeader(t *testing.T) {
6264
assert.Zero(t, new(Parser).Progress())
6365
assert.Zero(t, (&Parser{header: &common.DemoHeader{}}).Progress())
6466
}
67+
68+
func TestRecoverFromPanic(t *testing.T) {
69+
assert.Nil(t, recoverFromPanic(nil))
70+
assert.Equal(t, ErrUnexpectedEndOfDemo, recoverFromPanic(io.ErrUnexpectedEOF))
71+
assert.Equal(t, ErrUnexpectedEndOfDemo, recoverFromPanic(io.EOF))
72+
73+
err := errors.New("test")
74+
assert.Equal(t, err, recoverFromPanic(err))
75+
76+
assert.Equal(t, "test", recoverFromPanic("test").Error())
77+
assert.Equal(t, "unexpected error: 1", recoverFromPanic(1).Error())
78+
}

parsing.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (p *Parser) ParseToEnd() (err error) {
8484
}
8585

8686
if err == nil {
87-
err = recoverFromUnexpectedEOF(recover())
87+
err = recoverFromPanic(recover())
8888
}
8989
}()
9090

@@ -112,14 +112,23 @@ func (p *Parser) ParseToEnd() (err error) {
112112
}
113113
}
114114

115-
func recoverFromUnexpectedEOF(r interface{}) error {
116-
if r != nil {
117-
if r == io.ErrUnexpectedEOF || r == io.EOF {
118-
return ErrUnexpectedEndOfDemo
119-
}
120-
panic(r)
115+
func recoverFromPanic(r interface{}) error {
116+
if r == nil {
117+
return nil
118+
}
119+
120+
if r == io.ErrUnexpectedEOF || r == io.EOF {
121+
return ErrUnexpectedEndOfDemo
122+
}
123+
124+
switch err := r.(type) {
125+
case error:
126+
return err
127+
case string:
128+
return errors.New(err)
129+
default:
130+
return fmt.Errorf("unexpected error: %v", err)
121131
}
122-
return nil
123132
}
124133

125134
// Cancel aborts ParseToEnd().
@@ -149,7 +158,7 @@ func (p *Parser) ParseNextFrame() (moreFrames bool, err error) {
149158
}
150159

151160
if err == nil {
152-
err = recoverFromUnexpectedEOF(recover())
161+
err = recoverFromPanic(recover())
153162
}
154163
}()
155164

stringtables.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (p *Parser) parseSingleStringTable(name string) {
9999
}
100100

101101
func (p *Parser) handleUpdateStringTable(tab *msg.CSVCMsg_UpdateStringTable) {
102-
// No need for recoverFromUnexpectedEOF here as we do that in processStringTable already
102+
// No need for recoverFromPanic here as we do that in processStringTable already
103103

104104
cTab := p.stringTables[tab.TableId]
105105
switch cTab.Name {
@@ -117,7 +117,7 @@ func (p *Parser) handleUpdateStringTable(tab *msg.CSVCMsg_UpdateStringTable) {
117117
}
118118

119119
func (p *Parser) handleCreateStringTable(tab *msg.CSVCMsg_CreateStringTable) {
120-
// No need for recoverFromUnexpectedEOF here as we do that in processStringTable already
120+
// No need for recoverFromPanic here as we do that in processStringTable already
121121

122122
p.processStringTable(tab)
123123

@@ -128,7 +128,7 @@ func (p *Parser) handleCreateStringTable(tab *msg.CSVCMsg_CreateStringTable) {
128128

129129
func (p *Parser) processStringTable(tab *msg.CSVCMsg_CreateStringTable) {
130130
defer func() {
131-
p.setError(recoverFromUnexpectedEOF(recover()))
131+
p.setError(recoverFromPanic(recover()))
132132
}()
133133

134134
if tab.Name == stNameModelPreCache {

0 commit comments

Comments
 (0)