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  }