diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..790e86d --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,73 @@ +linters-settings: + dupl: + threshold: 100 + goconst: + min-len: 3 + min-occurrences: 4 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - whyNoLint + gomnd: + checks: + - argument + - case + - condition + - return + ignored-numbers: + - '0' + - '1' + - '2' + - '3' + - '4' + - '5' + ignored-functions: + - strings.SplitN + govet: + check-shadowing: false + lll: + line-length: 140 + misspell: + locale: US + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + +linters: + disable-all: true + enable: + - bodyclose + - depguard + - dogsled + - dupl + - errcheck + - exportloopref + - gochecknoinits + - gocritic + - gofmt + - gomnd + - goprintffuncname + - gosec + - gosimple + - govet + - lll + - misspell + - nakedret + - noctx + - nolintlint + - staticcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - whitespace + +run: + go: '1.18' \ No newline at end of file diff --git a/csgo/demo_loader.go b/csgo/demo_loader.go index 7f24179..6912760 100644 --- a/csgo/demo_loader.go +++ b/csgo/demo_loader.go @@ -7,7 +7,6 @@ import ( "git.harting.dev/csgowtf/csgowtfd/utils" "github.com/an0nfunc/go-steam/v3" "github.com/an0nfunc/go-steam/v3/csgo/protocol/protobuf" - "github.com/an0nfunc/go-steam/v3/netutil" "github.com/an0nfunc/go-steam/v3/protocol/gamecoordinator" "github.com/an0nfunc/go-steam/v3/protocol/steamlang" "github.com/go-redis/cache/v8" @@ -34,9 +33,9 @@ type DemoMatchLoaderConfig struct { AuthCode string Sentry string LoginKey string - Db *ent.Client + DB *ent.Client Worker int - ApiKey string + APIKey string RateLimit *rate.Limiter Cache *cache.Cache SprayTimeout int @@ -48,7 +47,6 @@ type DemoMatchLoader struct { GCReady bool steamLogin *steam.LogOnDetails matchRecv chan *protobuf.CMsgGCCStrike15V2_MatchList - cmList []*netutil.PortAddr sentryFile string loginKey string db *ent.Client @@ -63,18 +61,20 @@ type DemoMatchLoader struct { LoggedIn bool } -func AccountId2SteamId(accId uint32) uint64 { - return uint64(accId) + 76561197960265728 +func AccountID2SteamID(accID uint32) uint64 { + return uint64(accID) + 76561197960265728 //nolint:gomnd } -func SteamId2AccountId(steamId uint64) uint32 { - return uint32(steamId - 76561197960265728) +func SteamID2AccountID(steamID uint64) uint32 { + return uint32(steamID - 76561197960265728) //nolint:gomnd } -func playerStatsFromRound(round *protobuf.CMsgGCCStrike15V2_MatchmakingServerRoundStats, p *ent.Player) (kills int32, deaths int32, assists int32, headshots int32, score int32, mvps int32) { +func playerStatsFromRound(round *protobuf.CMsgGCCStrike15V2_MatchmakingServerRoundStats, p *ent.Player) (kills int32, + deaths int32, assists int32, headshots int32, score int32, mvps int32) { for i, acc := range round.GetReservation().GetAccountIds() { - if AccountId2SteamId(acc) == p.ID { - return round.GetKills()[i], round.GetDeaths()[i], round.GetAssists()[i], round.GetEnemyHeadshots()[i], round.GetScores()[i], round.GetMvps()[i] + if AccountID2SteamID(acc) == p.ID { + return round.GetKills()[i], round.GetDeaths()[i], round.GetAssists()[i], round.GetEnemyHeadshots()[i], + round.GetScores()[i], round.GetMvps()[i] } } @@ -149,25 +149,23 @@ func (dml *DemoMatchLoader) getMatchDetails(sharecode string) (*protobuf.CMsgGCC return nil, fmt.Errorf("gc not ready") } - matchId, outcomeId, tokenId, err := DecodeSharecode(sharecode) + matchID, outcomeID, tokenID, err := DecodeSharecode(sharecode) if err != nil { return nil, err } - err = dml.requestDemoInfo(matchId, outcomeId, uint32(tokenId)) + err = dml.requestDemoInfo(matchID, outcomeID, uint32(tokenID)) if err != nil { return nil, err } - for { - select { - case matchDetails := <-dml.matchRecv: - if *matchDetails.Matches[0].Matchid == matchId { - return matchDetails, nil - } else { - dml.matchRecv <- matchDetails - } + for matchDetails := range dml.matchRecv { + if *matchDetails.Matches[0].Matchid == matchID { + return matchDetails, nil + } else { + dml.matchRecv <- matchDetails } } + return nil, err } func (dml *DemoMatchLoader) connectToSteam() error { @@ -185,15 +183,15 @@ func (dml *DemoMatchLoader) connectToSteam() error { func (dml *DemoMatchLoader) Setup(config *DemoMatchLoaderConfig) error { dml.loginKey = config.LoginKey dml.sentryFile = config.Sentry - dml.db = config.Db + dml.db = config.DB dml.dp = &DemoParser{} dml.parseMap = map[string]bool{} dml.parseMapL = new(sync.RWMutex) dml.cache = config.Cache - dml.connectFeedback = make(chan int, 10) + dml.connectFeedback = make(chan int, 10) //nolint:gomnd dml.connectionWait = retry.WithCappedDuration(time.Minute*time.Duration(config.RetryTimeout), retry.NewExponential(time.Minute)) dml.connectionWaitTmpl = retry.WithCappedDuration(time.Minute*time.Duration(config.RetryTimeout), retry.NewExponential(time.Minute)) - err := dml.dp.Setup(config.Db, config.Worker, config.SprayTimeout) + err := dml.dp.Setup(config.DB, config.Worker, config.SprayTimeout) if err != nil { return err } @@ -225,15 +223,15 @@ func (dml *DemoMatchLoader) Setup(config *DemoMatchLoaderConfig) error { if err != nil { return err } - dml.matchRecv = make(chan *protobuf.CMsgGCCStrike15V2_MatchList, 1000) - dml.parseDemo = make(chan *Demo, 1000) + dml.matchRecv = make(chan *protobuf.CMsgGCCStrike15V2_MatchList, 1000) //nolint:gomnd + dml.parseDemo = make(chan *Demo, 1000) //nolint:gomnd go dml.connectLoop() go dml.steamEventHandler() go dml.demoWorker() for i := 0; i < config.Worker; i++ { - go dml.gcWorker(config.ApiKey, config.RateLimit) + go dml.gcWorker(config.APIKey, config.RateLimit) } dml.connectFeedback <- LoginFailed @@ -258,28 +256,25 @@ func (dml *DemoMatchLoader) LoadDemo(demo *Demo) error { } func (dml *DemoMatchLoader) connectLoop() { - for { - select { - case res := <-dml.connectFeedback: - switch res { - case LoginFailed: - if sleep, ok := dml.connectionWait.Next(); !ok { - time.Sleep(sleep) - } else { - panic("retry should never be stop") - } - if !dml.LoggedIn { - log.Infof("[DL] Connecting to steam...") - - err := dml.connectToSteam() - if err != nil { - log.Warningf("[DL] Error connecting to steam: %v", err) - } - } - case LoginSuccess: - log.Info("[DL] Steam login successfully restored") - dml.connectionWait = dml.connectionWaitTmpl + for res := range dml.connectFeedback { + switch res { + case LoginFailed: + if sleep, ok := dml.connectionWait.Next(); !ok { + time.Sleep(sleep) + } else { + panic("retry should never be stop") } + if !dml.LoggedIn { + log.Infof("[DL] Connecting to steam...") + + err := dml.connectToSteam() + if err != nil { + log.Warningf("[DL] Error connecting to steam: %v", err) + } + } + case LoginSuccess: + log.Info("[DL] Steam login successfully restored") + dml.connectionWait = dml.connectionWaitTmpl } } } @@ -355,16 +350,19 @@ func (dml *DemoMatchLoader) greetGC() { } } -func (dml *DemoMatchLoader) requestDemoInfo(matchId uint64, conclusionId uint64, tokenId uint32) error { +func (dml *DemoMatchLoader) requestDemoInfo(matchID, conclusionID uint64, tokenID uint32) error { if !dml.GCReady { return fmt.Errorf("gc not ready") } - msg := protobuf.CMsgGCCStrike15V2_MatchListRequestFullGameInfo{Matchid: &matchId, - Outcomeid: &conclusionId, - Token: &tokenId} + msg := protobuf.CMsgGCCStrike15V2_MatchListRequestFullGameInfo{ + Matchid: &matchID, + Outcomeid: &conclusionID, + Token: &tokenID, + } - dml.client.GC.Write(gamecoordinator.NewGCMsgProtobuf(APPID, uint32(protobuf.ECsgoGCMsg_k_EMsgGCCStrike15_v2_MatchListRequestFullGameInfo), &msg)) + dml.client.GC.Write(gamecoordinator.NewGCMsgProtobuf(APPID, + uint32(protobuf.ECsgoGCMsg_k_EMsgGCCStrike15_v2_MatchListRequestFullGameInfo), &msg)) return nil } @@ -379,46 +377,46 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit defer dml.unlockDemo(demo) if !dml.GCReady { - log.Infof("[DL] Postponing match %d (%s): GC not ready", demo.MatchId, demo.ShareCode) + log.Infof("[DL] Postponing match %d (%s): GC not ready", demo.MatchID, demo.ShareCode) time.Sleep(5 * time.Second) dml.parseDemo <- demo return nil } - matchId, _, _, err := DecodeSharecode(demo.ShareCode) - if err != nil || matchId == 0 { + matchID, _, _, err := DecodeSharecode(demo.ShareCode) + if err != nil || matchID == 0 { return fmt.Errorf("error decoding sharecode %s: %w", demo.ShareCode, err) } - iMatch, err := dml.db.Match.Get(context.Background(), matchId) + iMatch, err := dml.db.Match.Get(context.Background(), matchID) if err != nil && !ent.IsNotFound(err) { return fmt.Errorf("error looking up match: %w", err) } else if err == nil { - if iMatch.DemoParsed == false && iMatch.Date.After(time.Now().UTC().AddDate(0, 0, -30)) { + if !iMatch.DemoParsed && iMatch.Date.After(time.Now().UTC().AddDate(0, 0, -30)) { log.Infof("[DL] Match %d is loaded, but not parsed. Try parsing.", iMatch.ID) - demo.MatchId = matchId - demo.Url = iMatch.ReplayURL + demo.MatchID = matchID + demo.URL = iMatch.ReplayURL demo.DecryptionKey = iMatch.DecryptionKey err := dml.dp.ParseDemo(demo) if err != nil { - return fmt.Errorf("error parsing match %d: %w", demo.MatchId, err) + return fmt.Errorf("error parsing match %d: %w", demo.MatchID, err) } return nil } - log.Infof("[DL] Skipped match %d: already loaded", matchId) + log.Infof("[DL] Skipped match %d: already loaded", matchID) return nil } - log.Infof("[DL] Requesting match %d from GC", matchId) + log.Infof("[DL] Requesting match %d from GC", matchID) t := time.Now() matchDetails, err := dml.getMatchDetails(demo.ShareCode) if err != nil { - return fmt.Errorf("error getting match-details for %d: %w", demo.MatchId, err) + return fmt.Errorf("error getting match-details for %d: %w", demo.MatchID, err) } - log.Infof("[DL] Recieved matchdetails for match %d (%s)", matchId, time.Since(t)) + log.Infof("[DL] Received matchdetails for match %d (%s)", matchID, time.Since(t)) // init tx tx, err := dml.db.Tx(context.Background()) @@ -430,17 +428,17 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit lastRound := matchZero.GetRoundstatsall()[len(matchZero.Roundstatsall)-1] var players []*ent.Player - for _, accountId := range lastRound.GetReservation().GetAccountIds() { - tPlayer, err := utils.Player(tx.Client(), AccountId2SteamId(accountId), apiKey, rl) + for _, accountID := range lastRound.GetReservation().GetAccountIds() { + tPlayer, err := utils.Player(tx.Client(), AccountID2SteamID(accountID), apiKey, rl) if err != nil { err = utils.Rollback(tx, err) - return fmt.Errorf("error getting player for steamid %d: %w", AccountId2SteamId(accountId), err) + return fmt.Errorf("error getting player for steamid %d: %w", AccountID2SteamID(accountID), err) } players = append(players, tPlayer) } - demo.Url = lastRound.GetMap() - demo.MatchId = matchZero.GetMatchid() + demo.URL = lastRound.GetMap() + demo.MatchID = matchZero.GetMatchid() demo.DecryptionKey = []byte(strings.ToUpper(fmt.Sprintf("%016x", matchZero.GetWatchablematchinfo().GetClDecryptdataKeyPub()))) tMatch, err := tx.Match.Create(). @@ -463,14 +461,14 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit for i, mPlayer := range players { var ( - teamId int + teamID int mk2, mk3, mk4, mk5 uint ) if i > 4 { - teamId = 2 + teamID = 2 } else { - teamId = 1 + teamID = 1 } var oldKills int32 @@ -494,7 +492,7 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit err = tx.MatchPlayer.Create(). SetMatches(tMatch). SetPlayers(mPlayer). - SetTeamID(teamId). + SetTeamID(teamID). SetKills(int(kills)). SetDeaths(int(deaths)). SetAssists(int(assists)). @@ -539,7 +537,7 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit err = dml.dp.ParseDemo(demo) if err != nil { - return fmt.Errorf("error queueing demo %d for parsing: %w", demo.MatchId, err) + return fmt.Errorf("error queueing demo %d for parsing: %w", demo.MatchID, err) } return nil } diff --git a/csgo/demo_parser.go b/csgo/demo_parser.go index 5d83827..ae5c0f8 100644 --- a/csgo/demo_parser.go +++ b/csgo/demo_parser.go @@ -8,9 +8,7 @@ import ( "errors" "fmt" "git.harting.dev/csgowtf/csgowtfd/ent" - "git.harting.dev/csgowtf/csgowtfd/ent/match" "git.harting.dev/csgowtf/csgowtfd/ent/matchplayer" - "git.harting.dev/csgowtf/csgowtfd/ent/player" "git.harting.dev/csgowtf/csgowtfd/utils" "github.com/golang/geo/r2" "github.com/markus-wa/demoinfocs-golang/v3/pkg/demoinfocs" @@ -24,14 +22,13 @@ import ( type Demo struct { ShareCode string - MatchId uint64 - Url string + MatchID uint64 + URL string DecryptionKey []byte } type DemoParser struct { demoQueue chan *Demo - tempDir string db *ent.Client sprayTimeout int Done chan *Demo @@ -108,8 +105,8 @@ func (s *Sprays) Avg() (avg [][]float32) { return } -func (dp *DemoParser) Setup(db *ent.Client, worker int, sprayTimeout int) error { - dp.demoQueue = make(chan *Demo, 1000) +func (dp *DemoParser) Setup(db *ent.Client, worker, sprayTimeout int) error { + dp.demoQueue = make(chan *Demo, 1000) //nolint:gomnd dp.db = db dp.sprayTimeout = sprayTimeout dp.Done = make(chan *Demo, worker) @@ -129,9 +126,12 @@ func (dp *DemoParser) ParseDemo(demo *Demo) error { } func (d *Demo) download() (io.Reader, error) { - log.Debugf("[DP] Downloading replay for %d", d.MatchId) + log.Debugf("[DP] Downloading replay for %d", d.MatchID) - r, err := http.Get(d.Url) + r, err := http.Get(d.URL) + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(r.Body) if err != nil { return nil, err } @@ -142,26 +142,13 @@ func (d *Demo) download() (io.Reader, error) { return bzip2.NewReader(r.Body), nil } -func (dp *DemoParser) getDBPlayer(demo *Demo, demoPlayer *common.Player) (*ent.MatchPlayer, error) { - tMatchPlayer, err := dp.db.MatchPlayer.Query().WithMatches(func(q *ent.MatchQuery) { - q.Where(match.ID(demo.MatchId)) - }).WithPlayers(func(q *ent.PlayerQuery) { - q.Where(player.ID(demoPlayer.SteamID64)) - }).Only(context.Background()) - if err != nil { - return nil, err - } - - return tMatchPlayer, nil -} - -func (dp *DemoParser) MatchPlayerBySteamID(stats []*ent.MatchPlayer, steamId uint64) (*ent.MatchPlayer, error) { +func (dp *DemoParser) MatchPlayerBySteamID(stats []*ent.MatchPlayer, steamID uint64) (*ent.MatchPlayer, error) { for _, tStats := range stats { tPLayer, err := tStats.Edges.PlayersOrErr() if err != nil { return nil, fmt.Errorf("unable to get stats from statList: %w", err) } - if tPLayer.ID == steamId { + if tPLayer.ID == steamID { return tStats, nil } } @@ -179,19 +166,14 @@ func setMatchPlayerColor(matchPlayer *ent.MatchPlayer, demoPlayer *common.Player switch color { case common.Yellow: matchPlayer.Color = matchplayer.ColorYellow - break case common.Green: matchPlayer.Color = matchplayer.ColorGreen - break case common.Purple: matchPlayer.Color = matchplayer.ColorPurple - break case common.Blue: matchPlayer.Color = matchplayer.ColorBlue - break case common.Orange: matchPlayer.Color = matchplayer.ColorOrange - break case common.Grey: matchPlayer.Color = matchplayer.ColorGrey } @@ -200,7 +182,7 @@ func setMatchPlayerColor(matchPlayer *ent.MatchPlayer, demoPlayer *common.Player func (dp *DemoParser) parseWorker() { workloop: for demo := range dp.demoQueue { - if demo.MatchId == 0 { + if demo.MatchID == 0 { log.Warningf("[DP] can't parse match %s: no matchid found", demo.ShareCode) dp.Done <- demo continue @@ -214,17 +196,17 @@ workloop: return } - tMatch, err := tx.Match.Get(context.Background(), demo.MatchId) + tMatch, err := tx.Match.Get(context.Background(), demo.MatchID) if err != nil { err = utils.Rollback(tx, err) - log.Errorf("[DP] Unable to get match %d: %v", demo.MatchId, err) + log.Errorf("[DP] Unable to get match %d: %v", demo.MatchID, err) dp.Done <- demo continue } if tMatch.DemoParsed { - err = utils.Rollback(tx, err) - log.Infof("[DP] skipped already parsed %d", demo.MatchId) + _ = utils.Rollback(tx, err) + log.Infof("[DP] skipped already parsed %d", demo.MatchID) dp.Done <- demo continue } @@ -233,17 +215,17 @@ workloop: fDemo, err := demo.download() if err != nil { if errors.Is(err, DemoNotFoundError{}) { - err = utils.Rollback(tx, err) + _ = utils.Rollback(tx, err) if tMatch.Date.Before(time.Now().UTC().AddDate(0, 0, -30)) { log.Infof("[DP] demo expired for match %d", tMatch.ID) } else { - log.Infof("[DP] demo 404 not found for match %d. Retrying later.", demo.MatchId) + log.Infof("[DP] demo 404 not found for match %d. Retrying later.", demo.MatchID) } dp.Done <- demo continue } else { err = utils.Rollback(tx, err) - log.Errorf("[DP] Unable to download demo for %d: %v", demo.MatchId, err) + log.Errorf("[DP] Unable to download demo for %d: %v", demo.MatchID, err) dp.Done <- demo continue } @@ -253,7 +235,7 @@ workloop: tStats, err := tMatch.QueryStats().WithPlayers().All(context.Background()) if err != nil { err = utils.Rollback(tx, err) - log.Errorf("[DP] Failed to find players for match %d: %v", demo.MatchId, err) + log.Errorf("[DP] Failed to find players for match %d: %v", demo.MatchID, err) dp.Done <- demo continue } @@ -274,7 +256,7 @@ workloop: spays := make([]*Sprays, 0) cfg := demoinfocs.DefaultParserConfig - if len(demo.DecryptionKey) == 16 { + if len(demo.DecryptionKey) == 16 { //nolint:gomnd cfg.NetMessageDecryptionKey = demo.DecryptionKey } demoParser := demoinfocs.NewParserWithConfig(fDemo, cfg) @@ -484,7 +466,7 @@ workloop: Exec(context.Background()) if err != nil { err = utils.Rollback(tx, err) - log.Errorf("[DP] Unable to update match %d in database: %v", demo.MatchId, err) + log.Errorf("[DP] Unable to update match %d in database: %v", demo.MatchID, err) dp.Done <- demo continue } @@ -522,7 +504,13 @@ workloop: } for _, eqDmg := range eqMap[tMatchPlayer.PlayerStats] { - err = tx.Weapon.Create().SetStat(nMatchPLayer).SetDmg(eqDmg.Dmg).SetVictim(eqDmg.To).SetHitGroup(eqDmg.HitGroup).SetEqType(eqDmg.Eq).Exec(context.Background()) + err = tx.Weapon.Create(). + SetStat(nMatchPLayer). + SetDmg(eqDmg.Dmg). + SetVictim(eqDmg.To). + SetHitGroup(eqDmg.HitGroup). + SetEqType(eqDmg.Eq). + Exec(context.Background()) if err != nil { err = utils.Rollback(tx, err) log.Errorf("[DP] Unable to create WeaponStat: %v", err) @@ -532,7 +520,13 @@ workloop: } for _, eco := range ecoMap[tMatchPlayer.PlayerStats] { - err := tx.RoundStats.Create().SetMatchPlayer(nMatchPLayer).SetRound(uint(eco.Round)).SetBank(uint(eco.Bank)).SetEquipment(uint(eco.EqV)).SetSpent(uint(eco.Spent)).Exec(context.Background()) + err := tx.RoundStats.Create(). + SetMatchPlayer(nMatchPLayer). + SetRound(uint(eco.Round)). + SetBank(uint(eco.Bank)). + SetEquipment(uint(eco.EqV)). + SetSpent(uint(eco.Spent)). + Exec(context.Background()) if err != nil { err = utils.Rollback(tx, err) log.Errorf("[DP] Unable to create RoundStat: %v", err) @@ -554,7 +548,11 @@ workloop: continue workloop } - err = tx.Spray.Create().SetMatchPlayers(nMatchPLayer).SetWeapon(spray.Weapon).SetSpray(sprayBuf.Bytes()).Exec(context.Background()) + err = tx.Spray.Create(). + SetMatchPlayers(nMatchPLayer). + SetWeapon(spray.Weapon). + SetSpray(sprayBuf.Bytes()). + Exec(context.Background()) if err != nil { err = utils.Rollback(tx, err) log.Warningf("[DP] Failure adding spray to database: %v", err) @@ -567,7 +565,11 @@ workloop: var bulk []*ent.MessagesCreate for _, msg := range tMatchPlayer.Edges.Messages { - bulk = append(bulk, tx.Messages.Create().SetMessage(msg.Message).SetAllChat(msg.AllChat).SetTick(msg.Tick).SetMatchPlayer(tMatchPlayer)) + bulk = append(bulk, tx.Messages.Create(). + SetMessage(msg.Message). + SetAllChat(msg.AllChat). + SetTick(msg.Tick). + SetMatchPlayer(tMatchPlayer)) } if len(bulk) > 0 { err = tx.Messages.CreateBulk(bulk...).Exec(context.Background()) @@ -587,11 +589,11 @@ workloop: continue } - log.Infof("[DP] parsed match %d (took %s/%s)", demo.MatchId, downloadTime, time.Since(startTime)) + log.Infof("[DP] parsed match %d (took %s/%s)", demo.MatchID, downloadTime, time.Since(startTime)) err = demoParser.Close() if err != nil { - log.Errorf("[DP] Unable close demo file for match %d: %v", demo.MatchId, err) + log.Errorf("[DP] Unable close demo file for match %d: %v", demo.MatchID, err) } dp.Done <- demo } diff --git a/csgo/sharecode.go b/csgo/sharecode.go index 4e41bdd..3037d22 100644 --- a/csgo/sharecode.go +++ b/csgo/sharecode.go @@ -10,9 +10,9 @@ import ( //goland:noinspection SpellCheckingInspection var DICT = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789" -var sharecodeRexEx = regexp.MustCompile("^CSGO(?:-?\\w{5}){5}$") +var sharecodeRexEx = regexp.MustCompile(`^CSGO(?:-?\w{5}){5}$`) -func DecodeSharecode(code string) (uint64, uint64, uint16, error) { +func DecodeSharecode(code string) (matchID, outcomeID uint64, tokenID uint16, err error) { if !sharecodeRexEx.MatchString(code) { return 0, 0, 0, fmt.Errorf("not a CSGO sharecode: %s", code) } @@ -28,17 +28,17 @@ func DecodeSharecode(code string) (uint64, uint64, uint16, error) { bigInt.Add(bigInt, big.NewInt(int64(strings.Index(DICT, c)))) } - if bigInt.BitLen() > 144 { + if bigInt.BitLen() > 144 { //nolint:gomnd return 0, 0, 0, fmt.Errorf("invalid sharecode") } - bytes := make([]byte, 18) + bytes := make([]byte, 18) //nolint:gomnd bigInt.FillBytes(bytes) - matchId := binary.LittleEndian.Uint64(bytes[0:8]) - outcomeId := binary.LittleEndian.Uint64(bytes[8:16]) - tokenId := binary.LittleEndian.Uint16(bytes[16:18]) + matchID = binary.LittleEndian.Uint64(bytes[0:8]) + outcomeID = binary.LittleEndian.Uint64(bytes[8:16]) + tokenID = binary.LittleEndian.Uint16(bytes[16:18]) - return matchId, outcomeId, tokenId, nil + return } func ReverseString(numbers []string) []string { diff --git a/go.mod b/go.mod index 39461e5..4f63453 100644 --- a/go.mod +++ b/go.mod @@ -59,13 +59,13 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/ugorji/go/codec v1.2.7 // indirect github.com/vmihailenco/go-tinylfu v0.2.2 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.12.1 // indirect - golang.org/x/crypto v0.2.0 // indirect + golang.org/x/crypto v0.3.0 // indirect golang.org/x/exp v0.0.0-20221114191408-850992195362 // indirect golang.org/x/mod v0.7.0 // indirect golang.org/x/net v0.2.0 // indirect diff --git a/go.sum b/go.sum index 7e3e1ca..5bc0133 100644 --- a/go.sum +++ b/go.sum @@ -360,8 +360,8 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -430,8 +430,9 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -439,8 +440,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= @@ -499,8 +501,8 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= -golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA= diff --git a/main.go b/main.go index e9f89c9..9c000e3 100644 --- a/main.go +++ b/main.go @@ -138,7 +138,7 @@ func housekeeping() { } for _, m := range tMatches { - demo := &csgo.Demo{MatchId: m.ID, ShareCode: m.ShareCode} + demo := &csgo.Demo{MatchID: m.ID, ShareCode: m.ShareCode} if demoLoader.IsLoading(demo) { log.Infof("[HK] Skipping %s: parsing in progress", m.ShareCode) continue @@ -216,24 +216,25 @@ func housekeeping() { for _, tPlayer := range tPlayerNeedShareCodeUpdate { shareCodes, err := utils.GetNewShareCodesForPlayer(tPlayer, conf.Steam.APIKey, rL) if err != nil { - if errors.Is(err, utils.AuthcodeUnauthorizedError) { + switch { + case errors.Is(err, utils.AuthcodeUnauthorizedError): log.Infof("[HK] authCode for player %d is no longer valid", tPlayer.ID) err = tPlayer.Update().ClearAuthCode().ClearSharecodeUpdated().Exec(context.Background()) if err != nil { log.Errorf("[HK] Unable to clear authcode for player %d: %v", tPlayer.ID, err) } continue - } else if errors.Is(err, utils.SharecodeNoMatchError) { + case errors.Is(err, utils.SharecodeNoMatchError): log.Warningf("[HK] last shareCode for player %d does not match player", tPlayer.ID) continue - } else if errors.Is(err, utils.NoMatchError) { + case errors.Is(err, utils.NoMatchError): log.Infof("[HK] tracked player %d with no matches found, untracked", tPlayer.ID) err = tPlayer.Update().ClearAuthCode().ClearSharecodeUpdated().Exec(context.Background()) if err != nil { log.Errorf("[HK] Unable to clear authcode for player %d: %v", tPlayer.ID, err) } continue - } else { + default: log.Errorf("[HK] Error while requesting sharecodes for %d: %v", tPlayer.ID, err) continue } @@ -533,15 +534,16 @@ func postPlayerTrack(c *gin.Context) { _, err = utils.IsAuthCodeValid(tPlayer, conf.Steam.APIKey, shareCode, authCode, rL) if err != nil { - if errors.Is(err, utils.AuthcodeUnauthorizedError) { + switch { + case errors.Is(err, utils.AuthcodeUnauthorizedError): log.Infof("[PPT] authCode provided for player %s is invalid: %v", id, err) c.Status(http.StatusUnauthorized) return - } else if errors.Is(err, utils.SharecodeNoMatchError) { + case errors.Is(err, utils.SharecodeNoMatchError): log.Infof("[PPT] shareCode provided for player %s (%s) is invalid: %v", id, shareCode, err) c.Status(http.StatusPreconditionFailed) return - } else { + default: log.Infof("[PPT] problem with request: %v", err) c.Status(http.StatusServiceUnavailable) return @@ -1093,7 +1095,7 @@ func main() { migrate.WithDropIndex(true), migrate.WithDropColumn(true), ); err != nil { - log.Fatalf("Automigrate failed: %v", err) + log.Panicf("Automigrate failed: %v", err) } rdb = redis.NewClient(&redis.Options{ @@ -1116,16 +1118,16 @@ func main() { AuthCode: conf.Steam.AuthCode, Sentry: conf.Steam.Sentry, LoginKey: conf.Steam.LoginKey, - Db: db, + DB: db, Worker: conf.Parser.Worker, - ApiKey: conf.Steam.APIKey, + APIKey: conf.Steam.APIKey, RateLimit: rL, Cache: rdc, SprayTimeout: conf.Csgowtfd.SprayTimeout, RetryTimeout: conf.Steam.MaxRetryWait, }) if err != nil { - log.Fatalf("Error setting up DemoLoader: %v", err) + log.Panicf("Error setting up DemoLoader: %v", err) } // start housekeeper @@ -1174,7 +1176,7 @@ func main() { sL, err := net.Listen("unix", l.Socket) log.Infof("Listening on %s", l.Socket) if err != nil { - log.Fatalf("Failure listing on socket %s: %v", l.Socket, err) + log.Panicf("Failure listing on socket %s: %v", l.Socket, err) } sockets = append(sockets, sL) go func() { diff --git a/utils/utils.go b/utils/utils.go index df6608c..a2ef26f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -690,11 +690,12 @@ func TranslateWithDeepL(text string, language string, baseURL string, apiKey str v.Set("text", text) v.Set("target_lang", language) dlResp, err := c.PostForm("https://"+baseURL+"/v2/translate", v) - if err != nil { + switch { + case err != nil: return "", "", fmt.Errorf("deepl response: %w", err) - } else if dlResp.StatusCode != http.StatusOK { + case dlResp.StatusCode != http.StatusOK: return "", "", fmt.Errorf("deepl response %d", dlResp.StatusCode) - } else { + default: respBytes, err := io.ReadAll(dlResp.Body) defer func(Body io.ReadCloser) { _ = Body.Close() @@ -707,7 +708,6 @@ func TranslateWithDeepL(text string, language string, baseURL string, apiKey str if err != nil { return "", "", fmt.Errorf("error decoding json from deepl: %w", err) } - return dlRespJSON.Translations[0].Text, strings.ToLower(dlRespJSON.Translations[0].DetectedSourceLanguage), nil } }