Skip to content

Instantly share code, notes, and snippets.

@dtynn
Created February 4, 2020 10:40
Show Gist options
  • Save dtynn/160419f5b95f71c0e5f20a0dda8c7175 to your computer and use it in GitHub Desktop.
Save dtynn/160419f5b95f71c0e5f20a0dda8c7175 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/json"
"io"
"log"
"math/rand"
"net/http"
"time"
)
type Frame struct {
Index uint64
Seed int64
Data []byte
}
func handleResponseStream(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Transfer-Encoding", "chunked")
rw.WriteHeader(http.StatusOK)
ticker := time.NewTicker(time.Second)
flusher, ok := rw.(http.Flusher)
var index uint64
streamWriter := json.NewEncoder(rw)
for {
select {
case <-req.Context().Done():
return
case <-ticker.C:
if index >= 50 {
return
}
index++
seed := rand.Int63()
reader := rand.New(rand.NewSource(seed))
data := make([]byte, 2<<20)
reader.Read(data)
frame := Frame{
Index: index,
Seed: seed,
Data: data,
}
if err := streamWriter.Encode(frame); err != nil {
log.Printf("[WARN] fail to encoding frame into http.ResponseWriter: %s", err)
return
}
if ok {
flusher.Flush()
}
log.Printf("[INFO] frame written %d, seed %d", index, seed)
}
}
}
func call(addr string) {
resp, err := http.Get(addr)
if err != nil {
log.Fatalln("make http request", err)
}
defer resp.Body.Close()
streamReader := json.NewDecoder(resp.Body)
var index uint64
for {
var frame Frame
if err := streamReader.Decode(&frame); err != nil {
if err == io.EOF {
log.Println("[INFO] stream ended")
return
}
log.Fatalln("unmarshal frame", err)
}
log.Printf("[INFO] frame read %d, seed %d", frame.Index, frame.Seed)
if frame.Index != index+1 {
log.Fatalf("expected index: %d, got %d", index+1, frame.Index)
}
index = frame.Index
expectedData := make([]byte, 2<<20)
rand.New(rand.NewSource(frame.Seed)).Read(expectedData)
if !bytes.Equal(expectedData, frame.Data) {
log.Fatalf("unexpected seed %d", frame.Seed)
}
}
}
func main() {
http.Handle("/", http.HandlerFunc(handleResponseStream))
go func() {
time.Sleep(5 * time.Second)
log.Println("[INFO] try calling...")
call("http://127.0.0.1:10080")
}()
log.Println("[INFO] start lisening")
if err := http.ListenAndServe("127.0.0.1:10080", nil); err != nil {
log.Fatalln("listen and serve ", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment