package deadline import ( "io" "os" "time" "github.com/sagernet/sing/common/atomic" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" N "github.com/sagernet/sing/common/network" ) type TimeoutReader interface { io.Reader SetReadDeadline(t time.Time) error } type Reader interface { N.ExtendedReader TimeoutReader N.WithUpstreamReader N.ReaderWithUpstream } type reader struct { N.ExtendedReader timeoutReader TimeoutReader deadline atomic.TypedValue[time.Time] pipeDeadline pipeDeadline result chan *readResult done chan struct{} } type readResult struct { buffer *buf.Buffer err error } func NewReader(timeoutReader TimeoutReader) Reader { return &reader{ ExtendedReader: bufio.NewExtendedReader(timeoutReader), timeoutReader: timeoutReader, pipeDeadline: makePipeDeadline(), result: make(chan *readResult, 1), done: makeFilledChan(), } } func (r *reader) Read(p []byte) (n int, err error) { select { case result := <-r.result: return r.pipeReturn(result, p) default: } select { case result := <-r.result: return r.pipeReturn(result, p) case <-r.pipeDeadline.wait(): return 0, os.ErrDeadlineExceeded case <-r.done: go r.pipeRead(len(p)) } select { case result := <-r.result: return r.pipeReturn(result, p) case <-r.pipeDeadline.wait(): return 0, os.ErrDeadlineExceeded } } func (r *reader) pipeReturn(result *readResult, p []byte) (n int, err error) { n = copy(p, result.buffer.Bytes()) result.buffer.Advance(n) if result.buffer.IsEmpty() { result.buffer.Release() err = result.err } else { r.result <- result } return } func (r *reader) pipeRead(pLen int) { buffer := buf.NewSize(pLen) _, err := buffer.ReadOnceFrom(r.ExtendedReader) r.result <- &readResult{ buffer: buffer, err: err, } r.done <- struct{}{} } func (r *reader) ReadBuffer(buffer *buf.Buffer) error { select { case result := <-r.result: return r.pipeReturnBuffer(result, buffer) default: } select { case result := <-r.result: return r.pipeReturnBuffer(result, buffer) case <-r.pipeDeadline.wait(): return os.ErrDeadlineExceeded case <-r.done: go r.pipeRead(buffer.FreeLen()) } select { case result := <-r.result: return r.pipeReturnBuffer(result, buffer) case <-r.pipeDeadline.wait(): return os.ErrDeadlineExceeded } } func (r *reader) pipeReturnBuffer(result *readResult, buffer *buf.Buffer) error { n, _ := buffer.Write(result.buffer.Bytes()) result.buffer.Advance(n) if !result.buffer.IsEmpty() { r.result <- result return nil } else { result.buffer.Release() return result.err } } func (r *reader) SetReadDeadline(t time.Time) error { r.deadline.Store(t) r.pipeDeadline.set(t) return nil } func (r *reader) ReaderReplaceable() bool { select { case <-r.done: r.done <- struct{}{} default: return false } select { case result := <-r.result: r.result <- result return false default: } return r.deadline.Load().IsZero() } func (r *reader) UpstreamReader() any { return r.ExtendedReader }