github.com/circl-dev/go-swagger@v0.31.0/examples/stream-client/jigsaw.go (about) 1 // +build ignore 2 3 package main 4 5 import ( 6 "bufio" 7 "bytes" 8 "context" 9 "crypto/tls" 10 "io" 11 "io/ioutil" 12 "log" 13 "net/http" 14 "os" 15 "sync" 16 17 "github.com/circl-dev/go-swagger/fixtures/bugs/883/gen-fixture-883/client" 18 "github.com/circl-dev/go-swagger/fixtures/bugs/883/gen-fixture-883/client/operations" 19 "github.com/circl-dev/runtime" 20 httptransport "github.com/circl-dev/runtime/client" 21 ) 22 23 // Buffer knows how to UnmarshalText 24 type Buffer struct { 25 *bytes.Buffer 26 } 27 28 // UnmarshalText handles text/plain 29 func (b *Buffer) UnmarshalText(text []byte) error { 30 _, err := b.Write(text) 31 return err 32 } 33 34 // NewBuffer creates a new buffer that knows how to unmarshal text/plain 35 func NewBuffer() *Buffer { 36 return &Buffer{ 37 Buffer: bytes.NewBuffer(nil), 38 } 39 } 40 41 func main() { 42 43 blockingMode := true 44 chunkingMode := true 45 46 if len(os.Args) > 1 { 47 for _, arg := range os.Args { 48 switch arg { 49 case "nonblocking": 50 blockingMode = false 51 case "nochunking": 52 chunkingMode = false 53 } 54 } 55 } 56 57 log.Printf("asking jigsaw server with blockingMode: %t, chunkingMode: %t", blockingMode, chunkingMode) 58 59 if blockingMode { 60 if err := chunkedBlocking(chunkingMode); err != nil { 61 log.Fatalf("error: %v", err) 62 } 63 return 64 } 65 66 if err := chunkedNonBlocking(chunkingMode); err != nil { 67 log.Fatalf("error: %v", err) 68 } 69 } 70 71 func customTransport(withChunks bool) *httptransport.Runtime { 72 // calling htts://jigsaw.w3.org/ 73 transport := httptransport.New("jigsaw.w3.org", "/", []string{"https"}) 74 75 if withChunks { 76 // the jigsaw API enables chunks for http 1.1 clients. 77 // No chunking takes place with http 2.0 78 http1Only := http.DefaultTransport.(*http.Transport) 79 // this disables http 2.0 80 http1Only.TLSNextProto = map[string]func(authority string, c *tls.Conn) http.RoundTripper{} 81 transport.Transport = http1Only 82 } 83 84 return transport 85 } 86 87 // chunkedBlocking consumes some text/plain resource, blocking for the response to be completely sent 88 func chunkedBlocking(withChunks bool) error { 89 90 c := client.New(customTransport(withChunks), nil).Operations 91 92 // we just need to specify a buffer that knows how to UnmarshalText() 93 buf := NewBuffer() 94 _, err := c.Chunked(operations.NewChunkedParams(), buf) 95 if err != nil { 96 return err 97 } 98 99 data, err := ioutil.ReadAll(buf) 100 if err != nil { 101 return err 102 } 103 104 log.Printf("result: %v", string(data)) 105 return nil 106 } 107 108 // chunkedNonBlocking consumes some text/plain resource asynchronously 109 func chunkedNonBlocking(withChunks bool) error { 110 transport := customTransport(withChunks) 111 112 // override text/plain consumer to consume this as a stream 113 transport.Consumers[runtime.TextMime] = runtime.ByteStreamConsumer() 114 115 c := client.New(transport, nil).Operations 116 117 reader, writer := io.Pipe() 118 119 scanner := bufio.NewScanner(reader) 120 121 ctx, cancel := context.WithCancel(context.Background()) 122 123 // consumes asynchronously the response buffer 124 var wg sync.WaitGroup 125 126 wg.Add(1) 127 go func(wg *sync.WaitGroup) { 128 defer wg.Done() 129 defer cancel() 130 131 line := 1 132 // read response items line by line 133 for scanner.Scan() { 134 // each response item is JSON 135 txt := scanner.Text() 136 log.Printf("line[%d]: %s", line, txt) 137 line++ 138 } 139 140 if err := scanner.Err(); err != nil { 141 log.Printf("scanner err: %v", err) 142 } 143 144 log.Println("EOF") 145 }(&wg) 146 147 _, err := c.Chunked(operations.NewChunkedParamsWithContext(ctx), writer) 148 149 if err == nil { 150 log.Printf("response complete") 151 } else { 152 log.Printf("got an error") 153 } 154 155 _ = writer.Close() 156 157 wg.Wait() 158 return err 159 }