Files
waf-platform/EdgeNode/internal/utils/readers/readers_concurrent_file.go
2026-02-04 20:27:13 +08:00

118 lines
2.1 KiB
Go

// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package readers
import (
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"io"
"os"
"sync"
)
type subFileReader struct {
fp *os.File
notify chan zero.Zero
parentIsClosed bool
}
func newSubFileReader(fp *os.File) *subFileReader {
return &subFileReader{
fp: fp,
notify: make(chan zero.Zero, 2),
}
}
func (this *subFileReader) Read(p []byte) (n int, err error) {
n, err = this.fp.Read(p)
if n > 0 {
return n, nil
}
if err != nil {
if this.parentIsClosed {
return
}
if err != io.EOF {
return
}
// try next read
<-this.notify
return this.Read(p)
}
return
}
func (this *subFileReader) Close() error {
close(this.notify)
return this.fp.Close()
}
func (this *subFileReader) NotifyRead() {
select {
case this.notify <- zero.Zero{}:
default:
}
}
func (this *subFileReader) NotifyClose() {
select {
case this.notify <- zero.Zero{}:
default:
}
this.parentIsClosed = true
}
type ConcurrentFileReaders struct {
filePath string
isClosed bool
subReaders []*subFileReader
locker sync.RWMutex
}
func NewConcurrentFileReaders(filePath string) *ConcurrentFileReaders {
return &ConcurrentFileReaders{
filePath: filePath,
}
}
func (this *ConcurrentFileReaders) Get() (io.ReadCloser, error) {
this.locker.Lock()
if this.isClosed {
this.locker.Unlock()
return nil, os.ErrNotExist
}
this.locker.Unlock()
fp, err := os.OpenFile(this.filePath, os.O_RDONLY, 0444)
if err != nil {
return nil, os.ErrNotExist
}
var subReader = newSubFileReader(fp)
this.locker.Lock()
this.subReaders = append(this.subReaders, subReader)
this.locker.Unlock()
return subReader, nil
}
func (this *ConcurrentFileReaders) NotifyRead() {
this.locker.RLock()
for _, subReader := range this.subReaders {
subReader.NotifyRead()
}
this.locker.RUnlock()
}
func (this *ConcurrentFileReaders) NotifyClose() {
this.locker.Lock()
this.isClosed = true
this.locker.Unlock()
this.locker.RLock()
for _, subReader := range this.subReaders {
subReader.NotifyClose()
}
this.locker.RUnlock()
}