blob: 9845e10cfd0e4e1717244de74b76128be814fe08 [file] [log] [blame]
Serge Bazanskicc25bdf2018-10-25 14:02:58 +02001// Copyright 2015 go-swagger maintainers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package runtime
16
17import (
18 "bytes"
19 "encoding"
20 "errors"
21 "fmt"
22 "io"
23 "reflect"
24
25 "github.com/go-openapi/swag"
26)
27
28func defaultCloser() error { return nil }
29
30type byteStreamOpt func(opts *byteStreamOpts)
31
32// ClosesStream when the bytestream consumer or producer is finished
33func ClosesStream(opts *byteStreamOpts) {
34 opts.Close = true
35}
36
37type byteStreamOpts struct {
38 Close bool
39}
40
41// ByteStreamConsumer creates a consmer for byte streams,
42// takes a Writer/BinaryUnmarshaler interface or binary slice by reference,
43// and reads from the provided reader
44func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
45 var vals byteStreamOpts
46 for _, opt := range opts {
47 opt(&vals)
48 }
49
50 return ConsumerFunc(func(reader io.Reader, data interface{}) error {
51 if reader == nil {
52 return errors.New("ByteStreamConsumer requires a reader") // early exit
53 }
54
55 close := defaultCloser
56 if vals.Close {
57 if cl, ok := reader.(io.Closer); ok {
58 close = cl.Close
59 }
60 }
61 defer close()
62
63 if wrtr, ok := data.(io.Writer); ok {
64 _, err := io.Copy(wrtr, reader)
65 return err
66 }
67
68 buf := new(bytes.Buffer)
69 _, err := buf.ReadFrom(reader)
70 if err != nil {
71 return err
72 }
73 b := buf.Bytes()
74
75 if bu, ok := data.(encoding.BinaryUnmarshaler); ok {
76 return bu.UnmarshalBinary(b)
77 }
78
79 if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr {
80 v := reflect.Indirect(reflect.ValueOf(data))
81 if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
82 v.SetBytes(b)
83 return nil
84 }
85 }
86
87 return fmt.Errorf("%v (%T) is not supported by the ByteStreamConsumer, %s",
88 data, data, "can be resolved by supporting Writer/BinaryUnmarshaler interface")
89 })
90}
91
92// ByteStreamProducer creates a producer for byte streams,
93// takes a Reader/BinaryMarshaler interface or binary slice,
94// and writes to a writer (essentially a pipe)
95func ByteStreamProducer(opts ...byteStreamOpt) Producer {
96 var vals byteStreamOpts
97 for _, opt := range opts {
98 opt(&vals)
99 }
100 return ProducerFunc(func(writer io.Writer, data interface{}) error {
101 if writer == nil {
102 return errors.New("ByteStreamProducer requires a writer") // early exit
103 }
104 close := defaultCloser
105 if vals.Close {
106 if cl, ok := writer.(io.Closer); ok {
107 close = cl.Close
108 }
109 }
110 defer close()
111
112 if rdr, ok := data.(io.Reader); ok {
113 _, err := io.Copy(writer, rdr)
114 return err
115 }
116
117 if bm, ok := data.(encoding.BinaryMarshaler); ok {
118 bytes, err := bm.MarshalBinary()
119 if err != nil {
120 return err
121 }
122
123 _, err = writer.Write(bytes)
124 return err
125 }
126
127 if data != nil {
128 if e, ok := data.(error); ok {
129 _, err := writer.Write([]byte(e.Error()))
130 return err
131 }
132
133 v := reflect.Indirect(reflect.ValueOf(data))
134 if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
135 _, err := writer.Write(v.Bytes())
136 return err
137 }
138 if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice {
139 b, err := swag.WriteJSON(data)
140 if err != nil {
141 return err
142 }
143 _, err = writer.Write(b)
144 return err
145 }
146 }
147
148 return fmt.Errorf("%v (%T) is not supported by the ByteStreamProducer, %s",
149 data, data, "can be resolved by supporting Reader/BinaryMarshaler interface")
150 })
151}