Skip to content

Instantly share code, notes, and snippets.

@disq
Last active November 15, 2016 09:41
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 disq/652b8d6674ad7b86645b80e599a638bd to your computer and use it in GitHub Desktop.
Save disq/652b8d6674ad7b86645b80e599a638bd to your computer and use it in GitHub Desktop.
import (
"bufio"
"context"
"io"
)
type CancelableScanner struct {
*bufio.Scanner
data chan string
err chan error
ctx context.Context
}
func NewCancelableScanner(ctx context.Context, r io.Reader) *CancelableScanner {
return &CancelableScanner{
bufio.NewScanner(r),
make(chan string),
make(chan error),
ctx,
}
}
func (s *CancelableScanner) Start() *CancelableScanner {
go func() {
for s.Scan() {
s.data <- s.Text()
}
if err := s.Err(); err != nil {
s.err <- err
}
close(s.data)
close(s.err)
}()
return s
}
func (s *CancelableScanner) ReadOne() (string, error) {
select {
case <-s.ctx.Done():
return "", context.Canceled
case str, ok := <-s.data:
if !ok {
return "", io.EOF
}
return str, nil
case err, ok := <-s.err:
if !ok {
return "", io.EOF
}
return "", err
}
}
@disq
Copy link
Author

disq commented Nov 15, 2016

Usage

	s := NewCancelableScanner(p.ctx, r).Start()

	for {
		line, err := s.ReadOne()
		if err != nil {
			if err == context.Canceled || err == io.EOF {
				break
			}
			log.Printf("Error reading: %v", err)
			break
		}

		job, err := ParseJob(line)
		if err != nil {
			log.Print(`Could not parse line "`, line, `": `, err)
			continue
		}
		p.jobQueue <- job
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment