mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-03 11:57:39 +03:00
130 lines
2.6 KiB
Go
130 lines
2.6 KiB
Go
package bufio
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/sagernet/sing/common"
|
|
"github.com/sagernet/sing/common/buf"
|
|
N "github.com/sagernet/sing/common/network"
|
|
)
|
|
|
|
type ChunkReader struct {
|
|
upstream N.ExtendedReader
|
|
maxChunkSize int
|
|
cache *buf.Buffer
|
|
}
|
|
|
|
func NewChunkReader(upstream io.Reader, maxChunkSize int) *ChunkReader {
|
|
return &ChunkReader{
|
|
upstream: NewExtendedReader(upstream),
|
|
maxChunkSize: maxChunkSize,
|
|
}
|
|
}
|
|
|
|
func (c *ChunkReader) ReadBuffer(buffer *buf.Buffer) error {
|
|
if buffer.FreeLen() >= c.maxChunkSize {
|
|
return c.upstream.ReadBuffer(buffer)
|
|
}
|
|
if c.cache == nil {
|
|
c.cache = buf.NewSize(c.maxChunkSize)
|
|
} else if !c.cache.IsEmpty() {
|
|
return common.Error(buffer.ReadFrom(c.cache))
|
|
}
|
|
c.cache.FullReset()
|
|
err := c.upstream.ReadBuffer(c.cache)
|
|
if err != nil {
|
|
c.cache.Release()
|
|
c.cache = nil
|
|
return err
|
|
}
|
|
return common.Error(buffer.ReadFrom(c.cache))
|
|
}
|
|
|
|
func (c *ChunkReader) Read(p []byte) (n int, err error) {
|
|
if c.cache == nil {
|
|
c.cache = buf.NewSize(c.maxChunkSize)
|
|
} else if !c.cache.IsEmpty() {
|
|
return c.cache.Read(p)
|
|
}
|
|
c.cache.FullReset()
|
|
err = c.upstream.ReadBuffer(c.cache)
|
|
if err != nil {
|
|
c.cache.Release()
|
|
c.cache = nil
|
|
return
|
|
}
|
|
return c.cache.Read(p)
|
|
}
|
|
|
|
func (c *ChunkReader) ReadChunk() (*buf.Buffer, error) {
|
|
if c.cache == nil {
|
|
c.cache = buf.NewSize(c.maxChunkSize)
|
|
} else if !c.cache.IsEmpty() {
|
|
return c.cache, nil
|
|
}
|
|
c.cache.FullReset()
|
|
err := c.upstream.ReadBuffer(c.cache)
|
|
if err != nil {
|
|
c.cache.Release()
|
|
c.cache = nil
|
|
return nil, err
|
|
}
|
|
return c.cache, nil
|
|
}
|
|
|
|
func (c *ChunkReader) MTU() int {
|
|
return c.maxChunkSize
|
|
}
|
|
|
|
func (c *ChunkReader) Upstream() any {
|
|
return c.upstream
|
|
}
|
|
|
|
type ChunkWriter struct {
|
|
upstream N.ExtendedWriter
|
|
maxChunkSize int
|
|
}
|
|
|
|
func NewChunkWriter(writer io.Writer, maxChunkSize int) *ChunkWriter {
|
|
return &ChunkWriter{
|
|
upstream: NewExtendedWriter(writer),
|
|
maxChunkSize: maxChunkSize,
|
|
}
|
|
}
|
|
|
|
func (w *ChunkWriter) Write(p []byte) (n int, err error) {
|
|
for pLen := len(p); pLen > 0; {
|
|
var data []byte
|
|
if pLen > w.maxChunkSize {
|
|
data = p[:w.maxChunkSize]
|
|
p = p[w.maxChunkSize:]
|
|
pLen -= w.maxChunkSize
|
|
} else {
|
|
data = p
|
|
pLen = 0
|
|
}
|
|
var writeN int
|
|
writeN, err = w.upstream.Write(data)
|
|
n += writeN
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w *ChunkWriter) WriteBuffer(buffer *buf.Buffer) error {
|
|
if buffer.Len() > w.maxChunkSize {
|
|
defer buffer.Release()
|
|
return common.Error(w.Write(buffer.Bytes()))
|
|
}
|
|
return w.upstream.WriteBuffer(buffer)
|
|
}
|
|
|
|
func (w *ChunkWriter) Upstream() any {
|
|
return w.upstream
|
|
}
|
|
|
|
func (w *ChunkWriter) MTU() int {
|
|
return w.maxChunkSize
|
|
}
|