Skip to content

Instantly share code, notes, and snippets.

@sescobb27
Forked from rodaine/bytesreader.go
Last active August 29, 2015 14:20
Show Gist options
  • Save sescobb27/198236af7dfc69e09cf4 to your computer and use it in GitHub Desktop.
Save sescobb27/198236af7dfc69e09cf4 to your computer and use it in GitHub Desktop.
Code snippets for the blog post "Asynchronously Split an io.Reader in Go" (http://rodaine.com/2015/04/async-split-io-reader-in-golang/)
func handleUpload(u io.Reader) (err error) {
// capture all bytes from upload
b, err := ioutil.ReadAll(u)
if err != nil {
return
}
// wrap the bytes in a ReadSeeker
r := bytes.NewReader(b)
// process the meta data
err = processMetaData(r)
if err != nil {
return
}
// rewind the reader back to the start
r.Seek(0, 0)
// upload the data
err = uploadFile(r)
if err != nil {
return
}
return nil
}
func handleUpload(u io.Reader) (err error) {
// create a temporary file for the upload
f, err := ioutil.TempFile("", "upload")
if err != nil {
return
}
// destroy the file once done
defer func() {
n := f.Name()
f.Close()
os.Remove(n)
}()
// transfer the bytes to the file
_, err = io.Copy(f, u)
if err != nil {
return
}
// rewind the file
f.Seek(0, 0)
// process the meta data
err = processMetaData(f)
if err != nil {
return
}
// rewind the file again
f.Seek(0, 0)
// upload the file
err = uploadFile(f)
if err != nil {
return
}
return nil
}
func handleUpload(u io.Reader) (err error) {
// read in the first two bytes
b := make([]byte, 2)
_, err = u.Read(b)
if err != nil {
return
}
// check that they match the JPEG header
jpg := []byte{0xFF, 0xD8}
if !bytes.Equal(b, jpg) {
return errors.New("not a JPEG")
}
// glue those bytes back onto the reader
r := io.MultiReader(bytes.NewReader(b), u)
// upload the file
err = uploadFile(r)
if err != nil {
return
}
return nil
}
func handleUpload(u io.Reader) (err error) {
// create the pipes
mp4R, mp4W := io.Pipe()
webmR, webmW := io.Pipe()
oggR, oggW := io.Pipe()
wavR, wavW := io.Pipe()
// create channels to synchronize
done := make(chan bool)
errs := make(chan error)
defer close(done)
defer close(errs)
// spawn all the task goroutines. These look identical to
// the TeeReader example, but pulled out into separate
// methods for clarity
go uploadMP4(mp4R, done, errs)
go transcodeAndUploadWebM(webmR, done, errs)
go transcodeAndUploadOgg(oggR, done, errs)
go transcodeAndUploadWav(wavR, done, errs)
go func() {
// after completing the copy, we need to close
// the PipeWriters to propagate the EOF to all
// PipeReaders to avoid deadlock
defer mp4W.Close()
defer webmW.Close()
defer oggW.Close()
defer wavW.Close()
// build the multiwriter for all the pipes
mw := io.MultiWriter(mp4W, webmW, oggW, wavW)
// copy the data into the multiwriter
_, err := io.Copy(mw, u)
if err != nil {
errs <- err
}
}()
// wait until all are done
// or an error occurs
for c := 0; c < 4; c++ {
select {
case err := <-errs:
return err
case <-done:
}
}
return nil
}
func handleUpload(u io.Reader) (err error) {
// create the pipe and tee reader
pr, pw := io.Pipe()
tr := io.TeeReader(u, pw)
// create channels to synchronize
done := make(chan bool)
errs := make(chan error)
defer close(done)
defer close(errs)
go func() {
// close the PipeWriter after the
// TeeReader completes to trigger EOF
defer pw.Close()
// upload the original MP4 data
err := uploadFile(tr)
if err != nil {
errs <- err
return
}
done <- true
}()
go func() {
// transcode to WebM
webmr, err := transcode(pr)
if err != nil {
errs <- err
return
}
// upload to storage
err = uploadFile(webmr)
if err != nil {
errs <- err
return
}
done <- true
}()
// wait until both are done
// or an error occurs
for c := 0; c < 2; {
select {
case err := <-errs:
return err
case <-done:
c++
}
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment