mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
fix(logging): Prevent race conditions in FileStreamingLogWriter
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces"
|
||||
@@ -493,6 +494,12 @@ type FileStreamingLogWriter struct {
|
||||
|
||||
// statusWritten indicates whether the response status has been written.
|
||||
statusWritten bool
|
||||
|
||||
// mu protects concurrent access to the writer state.
|
||||
mu sync.RWMutex
|
||||
|
||||
// closed indicates whether the streaming writer has been closed.
|
||||
closed bool
|
||||
}
|
||||
|
||||
// WriteChunkAsync writes a response chunk asynchronously (non-blocking).
|
||||
@@ -500,7 +507,10 @@ type FileStreamingLogWriter struct {
|
||||
// Parameters:
|
||||
// - chunk: The response chunk to write
|
||||
func (w *FileStreamingLogWriter) WriteChunkAsync(chunk []byte) {
|
||||
if w.chunkChan == nil {
|
||||
w.mu.RLock()
|
||||
defer w.mu.RUnlock()
|
||||
|
||||
if w.chunkChan == nil || w.closed {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -525,6 +535,9 @@ func (w *FileStreamingLogWriter) WriteChunkAsync(chunk []byte) {
|
||||
// Returns:
|
||||
// - error: An error if writing fails, nil otherwise
|
||||
func (w *FileStreamingLogWriter) WriteStatus(status int, headers map[string][]string) error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.file == nil || w.statusWritten {
|
||||
return nil
|
||||
}
|
||||
@@ -553,21 +566,38 @@ func (w *FileStreamingLogWriter) WriteStatus(status int, headers map[string][]st
|
||||
// Returns:
|
||||
// - error: An error if closing fails, nil otherwise
|
||||
func (w *FileStreamingLogWriter) Close() error {
|
||||
if w.chunkChan != nil {
|
||||
close(w.chunkChan)
|
||||
w.mu.Lock()
|
||||
if w.closed {
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
w.closed = true
|
||||
chunkChan := w.chunkChan
|
||||
closeChan := w.closeChan
|
||||
file := w.file
|
||||
w.mu.Unlock()
|
||||
|
||||
if chunkChan != nil {
|
||||
close(chunkChan)
|
||||
}
|
||||
|
||||
// Wait for async writer to finish
|
||||
if w.closeChan != nil {
|
||||
<-w.closeChan
|
||||
w.chunkChan = nil
|
||||
if closeChan != nil {
|
||||
<-closeChan
|
||||
}
|
||||
|
||||
if w.file != nil {
|
||||
return w.file.Close()
|
||||
var err error
|
||||
if file != nil {
|
||||
err = file.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
w.mu.Lock()
|
||||
w.chunkChan = nil
|
||||
w.closeChan = nil
|
||||
w.file = nil
|
||||
w.mu.Unlock()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// asyncWriter runs in a goroutine to handle async chunk writing.
|
||||
|
||||
Reference in New Issue
Block a user