boot v2 progress: disks, ssh, success...
This commit is contained in:
118
shio/shio.go
Normal file
118
shio/shio.go
Normal file
@ -0,0 +1,118 @@
|
||||
// Shared IO
|
||||
package shio
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"novit.nc/direktil/initrd/colorio"
|
||||
)
|
||||
|
||||
type ShIO struct {
|
||||
buf []byte
|
||||
closed bool
|
||||
cond *sync.Cond
|
||||
hideInput bool
|
||||
}
|
||||
|
||||
func New() *ShIO {
|
||||
return NewWithCap(1024)
|
||||
}
|
||||
func NewWithCap(capacity int) *ShIO {
|
||||
return NewWithBytes(make([]byte, 0, capacity))
|
||||
}
|
||||
func NewWithBytes(content []byte) *ShIO {
|
||||
return &ShIO{
|
||||
buf: content,
|
||||
cond: sync.NewCond(&sync.Mutex{}),
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
_ io.WriteCloser = New()
|
||||
)
|
||||
|
||||
func (s *ShIO) Write(data []byte) (n int, err error) {
|
||||
s.cond.L.Lock()
|
||||
defer s.cond.L.Unlock()
|
||||
|
||||
if s.closed {
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
if s.hideInput {
|
||||
s.buf = append(s.buf, colorio.Reset...)
|
||||
}
|
||||
|
||||
s.buf = append(s.buf, data...)
|
||||
n = len(data)
|
||||
|
||||
if s.hideInput {
|
||||
s.buf = append(s.buf, colorio.Hidden...)
|
||||
}
|
||||
|
||||
s.cond.Broadcast()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *ShIO) HideInput() {
|
||||
s.cond.L.Lock()
|
||||
defer s.cond.L.Unlock()
|
||||
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
|
||||
s.buf = append(s.buf, colorio.Hidden...)
|
||||
s.hideInput = true
|
||||
}
|
||||
func (s *ShIO) ShowInput() {
|
||||
s.cond.L.Lock()
|
||||
defer s.cond.L.Unlock()
|
||||
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
|
||||
s.buf = append(s.buf, colorio.Reset...)
|
||||
s.hideInput = false
|
||||
}
|
||||
|
||||
func (s *ShIO) Close() (err error) {
|
||||
s.cond.L.Lock()
|
||||
defer s.cond.L.Unlock()
|
||||
|
||||
s.closed = true
|
||||
|
||||
s.cond.Broadcast()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *ShIO) NewReader() io.Reader {
|
||||
return &shioReader{s, 0}
|
||||
}
|
||||
|
||||
type shioReader struct {
|
||||
in *ShIO
|
||||
pos int
|
||||
}
|
||||
|
||||
func (r *shioReader) Read(ba []byte) (n int, err error) {
|
||||
r.in.cond.L.Lock()
|
||||
defer r.in.cond.L.Unlock()
|
||||
|
||||
for r.pos == len(r.in.buf) && !r.in.closed {
|
||||
r.in.cond.Wait()
|
||||
}
|
||||
|
||||
if r.pos == len(r.in.buf) && r.in.closed {
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
n = copy(ba, r.in.buf[r.pos:])
|
||||
r.pos += n
|
||||
|
||||
return
|
||||
}
|
52
shio/shio_test.go
Normal file
52
shio/shio_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package shio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleOutput() {
|
||||
done := false
|
||||
defer func() { done = true }()
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
if !done {
|
||||
panic("timeout")
|
||||
}
|
||||
}()
|
||||
|
||||
shio := NewWithCap(3)
|
||||
|
||||
r1 := shio.NewReader()
|
||||
|
||||
// read as you write
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
io.Copy(os.Stdout, r1)
|
||||
fmt.Println("-- r1 done --")
|
||||
}()
|
||||
|
||||
fmt.Fprintln(shio, "hello1")
|
||||
fmt.Fprintln(shio, "hello2")
|
||||
shio.Close()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// read after close
|
||||
r2 := shio.NewReader()
|
||||
io.Copy(os.Stdout, r2)
|
||||
fmt.Println("-- r2 done --")
|
||||
|
||||
// Output:
|
||||
// hello1
|
||||
// hello2
|
||||
// -- r1 done --
|
||||
// hello1
|
||||
// hello2
|
||||
// -- r2 done --
|
||||
}
|
Reference in New Issue
Block a user