147 lines
3.1 KiB
Go
147 lines
3.1 KiB
Go
// Sshwifty - A Web SSH client
|
|
//
|
|
// Copyright (C) 2019-2021 NI Rui <ranqus@gmail.com>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package rw
|
|
|
|
import "errors"
|
|
|
|
// Errors
|
|
var (
|
|
ErrFetchReaderNotEnoughBuffer = errors.New(
|
|
"Not enough buffer")
|
|
)
|
|
|
|
// FetchReaderFetcher generates data for SourceReader
|
|
type FetchReaderFetcher func() ([]byte, error)
|
|
|
|
// FetchReader read from the source and increase your lifespan if used correctly
|
|
type FetchReader struct {
|
|
source FetchReaderFetcher // Source data fetcher
|
|
data []byte // Fetched source data
|
|
dataUsed int // Used source data
|
|
}
|
|
|
|
// Fetch fetchs
|
|
type Fetch func(n int) ([]byte, error)
|
|
|
|
// FetchOneByte fetchs one byte from the Fetch, or return an error when it fails
|
|
func FetchOneByte(f Fetch) ([]byte, error) {
|
|
for {
|
|
d, dErr := f(1)
|
|
|
|
if dErr != nil {
|
|
return nil, dErr
|
|
}
|
|
|
|
if len(d) <= 0 {
|
|
continue
|
|
}
|
|
|
|
return d, nil
|
|
}
|
|
}
|
|
|
|
// NewFetchReader creates a new FetchReader
|
|
func NewFetchReader(g FetchReaderFetcher) FetchReader {
|
|
return FetchReader{
|
|
source: g,
|
|
data: nil,
|
|
dataUsed: 0,
|
|
}
|
|
}
|
|
|
|
func (r FetchReader) dataRemain() int {
|
|
return len(r.data) - r.dataUsed
|
|
}
|
|
|
|
// Remain Returns how many bytes is waiting to be readed
|
|
func (r *FetchReader) Remain() int {
|
|
return r.dataRemain()
|
|
}
|
|
|
|
// Export directly exports from buffer, never read from source
|
|
//
|
|
// Params:
|
|
// - n: Exact amount of bytes to fetch (0 to n, n included). If number n is
|
|
// unreachable, an error will be returned, and no internal status will
|
|
// be changed
|
|
//
|
|
// Returns:
|
|
// - Fetched data
|
|
// - Read error
|
|
func (r *FetchReader) Export(n int) ([]byte, error) {
|
|
remain := r.dataRemain()
|
|
|
|
if n > remain {
|
|
return nil, ErrFetchReaderNotEnoughBuffer
|
|
}
|
|
|
|
newUsed := r.dataUsed + n
|
|
data := r.data[r.dataUsed:newUsed]
|
|
|
|
r.dataUsed = newUsed
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// Fetch fetchs data from the source
|
|
//
|
|
// Params:
|
|
// - n: Max bytes to fetch (0 to n, n included)
|
|
//
|
|
// Returns:
|
|
// - Fetched data
|
|
// - Read error
|
|
func (r *FetchReader) Fetch(n int) ([]byte, error) {
|
|
remain := r.dataRemain()
|
|
|
|
if remain <= 0 {
|
|
data, dataFetchErr := r.source()
|
|
|
|
if dataFetchErr != nil {
|
|
return nil, dataFetchErr
|
|
}
|
|
|
|
r.data = data
|
|
r.dataUsed = 0
|
|
|
|
remain = r.dataRemain()
|
|
}
|
|
|
|
if n > remain {
|
|
n = remain
|
|
}
|
|
|
|
newUsed := r.dataUsed + n
|
|
data := r.data[r.dataUsed:newUsed]
|
|
|
|
r.dataUsed = newUsed
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// Read implements io.Read
|
|
func (r *FetchReader) Read(b []byte) (int, error) {
|
|
d, dErr := r.Fetch(len(b))
|
|
|
|
if dErr != nil {
|
|
return 0, dErr
|
|
}
|
|
|
|
return copy(b, d), nil
|
|
}
|