github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2013/oscon-dl/server-compose.go (about)

     1  // +build ignore,OMIT
     2  
     3  package main
     4  
     5  import (
     6  	"io"
     7  	"log"
     8  	"net/http"
     9  	"sort"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  var modTime = time.Unix(1374708739, 0)
    15  
    16  // START OMIT
    17  func part(s string) SizeReaderAt {
    18  	return io.NewSectionReader(strings.NewReader(s), 0, int64(len(s)))
    19  }
    20  
    21  func handler(w http.ResponseWriter, r *http.Request) {
    22  	sra := NewMultiReaderAt(
    23  		part("Hello, "), part(" world! "),
    24  		part("You requested "+r.URL.Path+"\n"),
    25  	)
    26  	rs := io.NewSectionReader(sra, 0, sra.Size())
    27  	http.ServeContent(w, r, "foo.txt", modTime, rs)
    28  }
    29  
    30  //END OMIT
    31  
    32  func main() {
    33  	log.Printf("Running...")
    34  	http.HandleFunc("/", handler)
    35  	log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
    36  }
    37  
    38  // START_1 OMIT
    39  // A SizeReaderAt is a ReaderAt with a Size method.
    40  //
    41  // An io.SectionReader implements SizeReaderAt.
    42  type SizeReaderAt interface {
    43  	Size() int64
    44  	io.ReaderAt
    45  }
    46  
    47  // NewMultiReaderAt is like io.MultiReader but produces a ReaderAt
    48  // (and Size), instead of just a reader.
    49  func NewMultiReaderAt(parts ...SizeReaderAt) SizeReaderAt {
    50  	m := &multi{
    51  		parts: make([]offsetAndSource, 0, len(parts)),
    52  	}
    53  	var off int64
    54  	for _, p := range parts {
    55  		m.parts = append(m.parts, offsetAndSource{off, p})
    56  		off += p.Size()
    57  	}
    58  	m.size = off
    59  	return m
    60  }
    61  
    62  // END_1 OMIT
    63  
    64  type offsetAndSource struct {
    65  	off int64
    66  	SizeReaderAt
    67  }
    68  
    69  type multi struct {
    70  	parts []offsetAndSource
    71  	size  int64
    72  }
    73  
    74  func (m *multi) Size() int64 { return m.size }
    75  
    76  func (m *multi) ReadAt(p []byte, off int64) (n int, err error) {
    77  	wantN := len(p)
    78  
    79  	// Skip past the requested offset.
    80  	skipParts := sort.Search(len(m.parts), func(i int) bool {
    81  		// This function returns whether parts[i] will
    82  		// contribute any bytes to our output.
    83  		part := m.parts[i]
    84  		return part.off+part.Size() > off
    85  	})
    86  	parts := m.parts[skipParts:]
    87  
    88  	// How far to skip in the first part.
    89  	needSkip := off
    90  	if len(parts) > 0 {
    91  		needSkip -= parts[0].off
    92  	}
    93  
    94  	for len(parts) > 0 && len(p) > 0 {
    95  		readP := p
    96  		partSize := parts[0].Size()
    97  		if int64(len(readP)) > partSize-needSkip {
    98  			readP = readP[:partSize-needSkip]
    99  		}
   100  		pn, err0 := parts[0].ReadAt(readP, needSkip)
   101  		if err0 != nil {
   102  			return n, err0
   103  		}
   104  		n += pn
   105  		p = p[pn:]
   106  		if int64(pn)+needSkip == partSize {
   107  			parts = parts[1:]
   108  		}
   109  		needSkip = 0
   110  	}
   111  
   112  	if n != wantN {
   113  		err = io.ErrUnexpectedEOF
   114  	}
   115  	return
   116  }