Skip to content

Instantly share code, notes, and snippets.

@mh-cbon
Created May 16, 2017 11:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mh-cbon/0e9f3f1b842948e6a36a9e115b921105 to your computer and use it in GitHub Desktop.
Save mh-cbon/0e9f3f1b842948e6a36a9e115b921105 to your computer and use it in GitHub Desktop.
read stdin, maybe, if it has data.
package stdinMaybe
import (
"bytes"
"errors"
"io"
"os"
"time"
)
// TryReadStdin is a non blocking func to read stdin
func TryReadStdin() (io.Reader, error) {
var ret bytes.Buffer
signalAllDone := make(chan error)
signalCopyErr := make(chan error)
go func() {
temp := make([]byte, 1024)
for {
n, readErr := os.Stdin.Read(temp)
if n == 0 && ret.Len() == 0 {
signalCopyErr <- &EmptyDataError{errors.New("Empty stdin")}
}
if readErr != nil && readErr != io.EOF {
signalCopyErr <- readErr
}
if n == 0 && readErr == nil {
break
}
_, writeErr := ret.Write(temp[:n])
temp = temp[:0]
if writeErr != nil {
signalCopyErr <- writeErr
}
if readErr == io.EOF {
break
}
if writeErr == io.EOF {
break
}
}
signalCopyErr <- nil
}()
go func() {
select {
case signalAllDone <- <-signalCopyErr:
case <-time.After(time.Millisecond * 100):
signalAllDone <- &EmptyDataError{errors.New("Empty stdin")}
}
}()
return &ret, <-signalAllDone
}
// EmptyDataError to signal empty feed.
type EmptyDataError struct {
error
}
// Empty returns true.
func (e EmptyDataError) Empty() bool {
return true
}
// EmptyDataErrorer is the contract to signal an empty feed.
type EmptyDataErrorer interface {
Empty() bool
}
// IsEmpty is an helper to determine if the error is about an empty feed.
func IsEmpty(err error) bool {
if err == nil {
return false
}
_, ok := err.(EmptyDataErrorer)
return ok
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment