fix: check all Close() return values for errcheck lint

Add explicit error discards (_ =) for Close() calls on network
connections, SQL rows, and file handles across 28 files. Also add
.golangci.yml with standard linter defaults to match CI configuration.
This commit is contained in:
Houmgaor
2026-02-17 23:57:14 +01:00
parent abb40f163c
commit c64dabc3ba
29 changed files with 61 additions and 53 deletions

7
.golangci.yml Normal file
View File

@@ -0,0 +1,7 @@
version: "2"
run:
timeout: 5m
linters:
default: standard

View File

@@ -334,6 +334,7 @@ func TestGenerate_ConsistentCharacterSet(t *testing.T) {
func TestRNG_Type(t *testing.T) {
// Verify RNG is of type *SafeRand
var _ *SafeRand = RNG
var _ *SafeRand = NewSafeRand()
var _ = (*SafeRand)(nil)
_ = RNG
_ = NewSafeRand()
}

View File

@@ -337,7 +337,7 @@ func getOutboundIP4() net.IP {
if err != nil {
log.Fatal(err)
}
defer conn.Close()
defer func() { _ = conn.Close() }()
localAddr := conn.LocalAddr().(*net.UDPAddr)

View File

@@ -124,7 +124,7 @@ func TestAPIServerStart(t *testing.T) {
// This might fail if the server didn't start properly or port is blocked
t.Logf("Failed to connect to server: %v", err)
} else {
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNotFound {
t.Logf("Unexpected status code: %d", resp.StatusCode)
}

View File

@@ -319,7 +319,7 @@ func (s *APIServer) ScreenShotGet(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Image not found", http.StatusNotFound)
return
}
defer file.Close()
defer func() { _ = file.Close() }()
// Set content type header to image/jpeg
w.Header().Set("Content-Type", "image/jpeg")
// Copy the image content to the response writer
@@ -390,7 +390,7 @@ func (s *APIServer) ScreenShot(w http.ResponseWriter, r *http.Request) {
if err != nil {
result = Result{Code: "500"}
}
defer outputFile.Close()
defer func() { _ = outputFile.Close() }()
// Encode the image and write it to the file
err = jpeg.Encode(outputFile, img, &jpeg.Options{Quality: s.erupeConfig.Screenshots.UploadQuality})

View File

@@ -132,7 +132,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
var token string
err := s.server.db.QueryRow("SELECT token FROM sign_sessions ss INNER JOIN public.users u on ss.user_id = u.id WHERE token=$1 AND ss.id=$2 AND u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.LoginTokenString, pkt.LoginTokenNumber, pkt.CharID0).Scan(&token)
if err != nil {
s.rawConn.Close()
_ = s.rawConn.Close()
s.logger.Warn(fmt.Sprintf("Invalid login token, offending CID: (%d)", pkt.CharID0))
return
}
@@ -342,7 +342,7 @@ func logoutPlayer(s *Session) {
// NOW do cleanup (after save is complete)
s.server.Lock()
delete(s.server.sessions, s.rawConn)
s.rawConn.Close()
_ = s.rawConn.Close()
s.server.Unlock()
// Stage cleanup
@@ -1126,7 +1126,7 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) {
var scenario Scenario
scenarioData, err := s.server.db.Queryx("SELECT scenario_id, category_id FROM scenario_counter")
if err != nil {
scenarioData.Close()
_ = scenarioData.Close()
s.logger.Error("Failed to get scenario counter info from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return

View File

@@ -129,7 +129,7 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
s.logger.Error("Failed to get savedata", zap.Error(err), zap.Uint32("charID", charID))
return nil, err
}
defer result.Close()
defer func() { _ = result.Close() }()
if !result.Next() {
err = errors.New("no savedata found")
s.logger.Error("No savedata found", zap.Uint32("charID", charID))

View File

@@ -75,7 +75,7 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
characterSaveData.Save(s)
s.logger.Info("Wrote recompressed savedata back to DB.")
} else {
s.rawConn.Close()
_ = s.rawConn.Close()
s.logger.Warn("Save cancelled due to corruption.")
if s.server.erupeConfig.DeleteOnSaveCorruption {
if _, err := s.server.db.Exec("UPDATE characters SET deleted=true WHERE id=$1", s.charID); err != nil {
@@ -164,7 +164,7 @@ func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRow("SELECT savedata FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil || len(data) == 0 {
s.logger.Warn(fmt.Sprintf("Failed to load savedata (CID: %d)", s.charID), zap.Error(err))
s.rawConn.Close() // Terminate the connection
_ = s.rawConn.Close() // Terminate the connection
return
}
doAckBufSucceed(s, pkt.AckHandle, data)

View File

@@ -73,7 +73,7 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
s.logger.Error("Failed to query diva schedule", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
_ = rows.Scan(&id, &start)
}

View File

@@ -139,7 +139,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
var loginBoosts []loginBoost
rows, err := s.server.db.Queryx("SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", s.charID)
if err != nil || s.server.erupeConfig.GameplayOptions.DisableLoginBoost {
rows.Close()
_ = rows.Close()
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35))
return
}

View File

@@ -193,7 +193,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
s.logger.Error("Failed to query festa schedule", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
_ = rows.Scan(&id, &start)
}
@@ -252,7 +252,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
s.logger.Error("Failed to query festa trials", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
if err := rows.StructScan(&trial); err != nil {
continue
@@ -575,7 +575,7 @@ func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket)
if err != nil {
s.logger.Error("Failed to query festa personal prizes", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
prize := &Prize{}
if err := rows.StructScan(&prize); err != nil {
@@ -605,7 +605,7 @@ func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPack
if err != nil {
s.logger.Error("Failed to query festa intermediate prizes", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
prize := &Prize{}
if err := rows.StructScan(&prize); err != nil {

View File

@@ -556,7 +556,7 @@ func GetGuildInfoByID(s *Session, guildID uint32) (*Guild, error) {
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
hasRow := rows.Next()
@@ -591,7 +591,7 @@ func GetGuildInfoByCharacterId(s *Session, charID uint32) (*Guild, error) {
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
hasRow := rows.Next()
@@ -1884,7 +1884,7 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {
continue
}
if count == 255 {
rows.Close()
_ = rows.Close()
break
}
count++

View File

@@ -52,7 +52,7 @@ func GetAllianceData(s *Session, AllianceID uint32) (*GuildAlliance, error) {
s.logger.Error("Failed to retrieve alliance data from database", zap.Error(err))
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
hasRow := rows.Next()
if !hasRow {
return nil, nil

View File

@@ -103,7 +103,7 @@ func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMembe
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
members := make([]*GuildMember, 0)
@@ -128,7 +128,7 @@ func GetCharacterGuildData(s *Session, charID uint32) (*GuildMember, error) {
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
hasRow := rows.Next()

View File

@@ -216,7 +216,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
return
}
defer rows.Close()
defer func() { _ = rows.Close() }()
bf := byteframe.NewByteFrame()

View File

@@ -50,7 +50,7 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {
WHERE gh.guild_id=$2 AND gh.level=2 AND gh.acquired=TRUE
`, s.charID, guild.ID)
if err != nil {
rows.Close()
_ = rows.Close()
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} else {

View File

@@ -101,7 +101,7 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
s.logger.Error("Failed to query houses by name", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
if err := rows.StructScan(&house); err == nil {
houses = append(houses, house)

View File

@@ -108,7 +108,7 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
allMail := make([]Mail, 0)

View File

@@ -227,7 +227,7 @@ func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
s.logger.Error("Failed to query mercenary loans", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
if err := rows.Scan(&name, &cid, &pactID); err != nil {
continue

View File

@@ -422,7 +422,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
}
}
rows.Close()
_ = rows.Close()
_ = tx.Commit()
}

View File

@@ -159,7 +159,7 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11))
return
}
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
_ = rows.StructScan(&score)

View File

@@ -327,7 +327,7 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
s.logger.Error("Failed to query tower mission scores", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
temp := TenrouiraiCharScore{}
_ = rows.Scan(&temp.Name, &temp.Score)

View File

@@ -223,7 +223,7 @@ func (s *Server) Shutdown() {
s.isShuttingDown = true
s.Unlock()
s.listener.Close()
_ = s.listener.Close()
close(s.acceptConns)
}
@@ -420,7 +420,7 @@ func (s *Server) DisconnectUser(uid uint32) {
if err != nil {
s.logger.Error("Failed to query characters for disconnect", zap.Error(err))
} else {
defer rows.Close()
defer func() { _ = rows.Close() }()
for rows.Next() {
_ = rows.Scan(&cid)
cids = append(cids, cid)
@@ -430,7 +430,7 @@ func (s *Server) DisconnectUser(uid uint32) {
for _, session := range c.sessions {
for _, cid := range cids {
if session.charID == cid {
session.rawConn.Close()
_ = session.rawConn.Close()
break
}
}

View File

@@ -60,7 +60,7 @@ func SetupTestDB(t *testing.T) *sqlx.DB {
// Test connection
if err := db.Ping(); err != nil {
db.Close()
_ = db.Close()
t.Skipf("Test database not available: %v. Run: docker compose -f docker/docker-compose.test.yml up -d", err)
return nil
}
@@ -207,7 +207,7 @@ func findProjectRoot(t *testing.T) string {
func TeardownTestDB(t *testing.T, db *sqlx.DB) {
t.Helper()
if db != nil {
db.Close()
_ = db.Close()
}
}

View File

@@ -65,7 +65,7 @@ func (s *Server) Shutdown() {
s.Unlock()
// This will cause the acceptor goroutine to error and exit gracefully.
s.listener.Close()
_ = s.listener.Close()
}
// acceptClients handles accepting new clients in a loop.
@@ -91,7 +91,7 @@ func (s *Server) acceptClients() {
}
func (s *Server) handleEntranceServerConnection(conn net.Conn) {
defer conn.Close()
defer func() { _ = conn.Close() }()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
n, err := io.ReadFull(conn, nullInit)

View File

@@ -445,7 +445,7 @@ func TestServerHandleConnectionImmediateClose(t *testing.T) {
if err != nil {
t.Fatalf("Dial() error: %v", err)
}
conn.Close()
_ = conn.Close()
time.Sleep(50 * time.Millisecond)
}
@@ -477,7 +477,7 @@ func TestServerHandleConnectionShortInit(t *testing.T) {
t.Fatalf("Dial() error: %v", err)
}
_, _ = conn.Write([]byte{0, 0, 0, 0})
conn.Close()
_ = conn.Close()
time.Sleep(50 * time.Millisecond)
}
@@ -517,6 +517,6 @@ func TestServerMultipleConnections(t *testing.T) {
time.Sleep(50 * time.Millisecond)
for _, conn := range conns {
conn.Close()
_ = conn.Close()
}
}

View File

@@ -354,8 +354,8 @@ func TestSessionWorkWithDevModeLogging(t *testing.T) {
}
clientConn, serverConn := net.Pipe()
defer clientConn.Close()
defer serverConn.Close()
defer func() { _ = clientConn.Close() }()
defer func() { _ = serverConn.Close() }()
session := &Session{
logger: logger,
@@ -364,7 +364,7 @@ func TestSessionWorkWithDevModeLogging(t *testing.T) {
cryptConn: network.NewCryptConn(serverConn),
}
clientConn.Close()
_ = clientConn.Close()
session.work()
}
@@ -380,7 +380,7 @@ func TestSessionWorkWithEmptyRead(t *testing.T) {
}
clientConn, serverConn := net.Pipe()
defer serverConn.Close()
defer func() { _ = serverConn.Close() }()
session := &Session{
logger: logger,
@@ -389,7 +389,7 @@ func TestSessionWorkWithEmptyRead(t *testing.T) {
cryptConn: network.NewCryptConn(serverConn),
}
clientConn.Close()
_ = clientConn.Close()
session.work()
}

View File

@@ -61,7 +61,7 @@ func (s *Server) Shutdown() {
s.Unlock()
// This will cause the acceptor goroutine to error and exit gracefully.
s.listener.Close()
_ = s.listener.Close()
}
func (s *Server) acceptClients() {
@@ -86,7 +86,7 @@ func (s *Server) acceptClients() {
func (s *Server) handleConnection(conn net.Conn) {
s.logger.Debug("New connection", zap.String("RemoteAddr", conn.RemoteAddr().String()))
defer conn.Close()
defer func() { _ = conn.Close() }()
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)

View File

@@ -434,7 +434,7 @@ func TestServerHandleConnection(t *testing.T) {
if err != nil {
t.Fatalf("Dial() error: %v", err)
}
defer conn.Close()
defer func() { _ = conn.Close() }()
nullInit := make([]byte, 8)
_, err = conn.Write(nullInit)
@@ -472,7 +472,7 @@ func TestServerHandleConnectionWithShortInit(t *testing.T) {
}
_, _ = conn.Write([]byte{0, 0, 0, 0})
conn.Close()
_ = conn.Close()
time.Sleep(50 * time.Millisecond)
}
@@ -502,7 +502,7 @@ func TestServerHandleConnectionImmediateClose(t *testing.T) {
if err != nil {
t.Fatalf("Dial() error: %v", err)
}
conn.Close()
_ = conn.Close()
time.Sleep(50 * time.Millisecond)
}
@@ -544,7 +544,7 @@ func TestServerMultipleConnections(t *testing.T) {
time.Sleep(50 * time.Millisecond)
for _, conn := range conns {
conn.Close()
_ = conn.Close()
}
}