mpvfs

9P file server for controlling mpv playback

git clone https://git.8pit.net/mpvfs.git

 1package playlistfs
 2
 3import (
 4	"errors"
 5	"io"
 6	"strings"
 7)
 8
 9type RecvInput interface {
10	CurrentReader() *strings.Reader
11	NextReader() *strings.Reader
12}
13
14// BlockRecv implements io.Reader on top of RecvInput. When the
15// implemented Read() returns io.EOF and the caller calls Read()
16// again the reader implemented by BlockRecv will block until
17// new data is available.
18type BlockRecv struct {
19	// Absolute offset at which (and beyond which) EOF will be returned.
20	// This member must be initalized with -1.
21	eofAt int64
22
23	// Absolute base offset used to calculate a relative offset for
24	// the current string reader.
25	baseOff int64
26
27	// Current string reader on which the read function operates.
28	reader *strings.Reader
29
30	in RecvInput
31}
32
33func NewBlockRecv(in RecvInput) *BlockRecv {
34	return &BlockRecv{eofAt: -1, in: in}
35}
36
37func (e *BlockRecv) Read(off int64, p []byte) (int, error) {
38	if e.reader == nil {
39		e.reader = e.in.CurrentReader()
40	} else if e.eofAt > 0 && off >= e.eofAt {
41		// We are reading beyond EOF for the second time.
42		// Block until new data is available and return it.
43		e.baseOff += e.reader.Size()
44		e.reader = e.in.NextReader()
45	} else if off < e.baseOff {
46		return 0, errors.New("invalid seek")
47	}
48
49	// Calculate offset relative to current reader
50	relOff := off - e.baseOff
51
52	_, err := e.reader.Seek(relOff, io.SeekStart)
53	if err != nil {
54		e.eofAt = off
55		return 0, io.EOF
56	}
57
58	n, err := e.reader.Read(p)
59	if err == io.EOF || (err != nil && n == 0) {
60		e.eofAt = off + int64(n)
61		return 0, io.EOF
62	}
63
64	return n, nil
65}