@@ -2,7 +2,7 @@ package cmds
2
2
3
3
import (
4
4
"context"
5
- "fmt "
5
+ "errors "
6
6
"io"
7
7
"sync"
8
8
@@ -15,43 +15,54 @@ func NewChanResponsePair(req *Request) (ResponseEmitter, Response) {
15
15
wait := make (chan struct {})
16
16
17
17
r := & chanResponse {
18
- req : req ,
19
- ch : ch ,
20
- wait : wait ,
21
- closed : make (chan struct {}),
18
+ req : req ,
19
+ ch : ch ,
20
+ wait : wait ,
22
21
}
23
22
24
23
re := (* chanResponseEmitter )(r )
25
24
26
25
return re , r
27
26
}
28
27
29
- type chanResponse struct {
30
- wl sync.Mutex // lock for writing calls, i.e. Emit et al.
31
- rl sync.Mutex // lock for reading calls, i.e. Next
28
+ // chanStream is the struct of both the Response and ResponseEmitter.
29
+ // The methods are defined on chanResponse and chanResponseEmitter, which are
30
+ // just type definitions on chanStream.
31
+ type chanStream struct {
32
32
req * Request
33
33
34
- // wait makes header requests block until the body is sent
35
- wait chan struct {}
36
- // waitOnce makes sure we only close wait once
37
- waitOnce sync.Once
34
+ // rl is a lock for reading calls, i.e. Next.
35
+ rl sync.Mutex
38
36
39
- // ch is used to send values from emitter to response
37
+ // ch is used to send values from emitter to response.
38
+ // When Emit received a channel close, it sets it to nil.
39
+ // It is protected by rl.
40
40
ch chan interface {}
41
41
42
- emitted bool
43
- err error
44
- length uint64
42
+ // wl is a lock for writing calls, i.e. Emit, Close(WithError) and SetLength.
43
+ wl sync.Mutex
44
+
45
+ // closed stores whether this stream is closed.
46
+ // It is protected by wl.
47
+ closed bool
48
+
49
+ // wait is closed when the stream is closed or the first value is emitted.
50
+ // Error and Length both wait for wait to be closed.
51
+ // It is protected by wl.
52
+ wait chan struct {}
53
+
54
+ // err is the error that the stream was closed with.
55
+ // It is written once under lock wl, but only read after wait is closed (which also happens under wl)
56
+ err error
45
57
46
- closeOnce sync.Once
47
- closed chan struct {}
58
+ // length is the length of the response.
59
+ // It can be set by calling SetLength, but only before the first call to Emit, Close or CloseWithError.
60
+ length uint64
48
61
}
49
62
50
- func (r * chanResponse ) Request () * Request {
51
- if r == nil {
52
- return nil
53
- }
63
+ type chanResponse chanStream
54
64
65
+ func (r * chanResponse ) Request () * Request {
55
66
return r .req
56
67
}
57
68
@@ -75,25 +86,6 @@ func (r *chanResponse) Length() uint64 {
75
86
return r .length
76
87
}
77
88
78
- func (re * chanResponse ) Head () Head {
79
- <- re .wait
80
-
81
- var err error
82
- if re .err != io .EOF {
83
- err = re .err
84
- }
85
-
86
- cmdErr , ok := err .(* cmdkit.Error )
87
- if ! ok && err != nil {
88
- cmdErr = & cmdkit.Error {Message : err .Error ()}
89
- }
90
-
91
- return Head {
92
- Len : re .length ,
93
- Err : cmdErr ,
94
- }
95
- }
96
-
97
89
func (r * chanResponse ) Next () (interface {}, error ) {
98
90
if r == nil {
99
91
return nil , io .EOF
@@ -111,18 +103,11 @@ func (r *chanResponse) Next() (interface{}, error) {
111
103
defer r .rl .Unlock ()
112
104
113
105
select {
114
- case <- r .closed :
115
- return nil , r .err
116
106
case v , ok := <- r .ch :
117
107
if ! ok {
118
- r .ch = nil
119
108
return nil , r .err
120
109
}
121
110
122
- if err , ok := v .(cmdkit.Error ); ok {
123
- v = & err
124
- }
125
-
126
111
switch val := v .(type ) {
127
112
case Single :
128
113
return val .Value , nil
@@ -138,69 +123,83 @@ type chanResponseEmitter chanResponse
138
123
139
124
func (re * chanResponseEmitter ) Emit (v interface {}) error {
140
125
// channel emission iteration
141
- // TODO maybe remove this and use EmitChan instead of calling Emit directly?
142
126
if ch , ok := v .(chan interface {}); ok {
143
127
v = (<- chan interface {})(ch )
144
128
}
145
129
if ch , isChan := v .(<- chan interface {}); isChan {
146
130
return EmitChan (re , ch )
147
131
}
148
132
149
- // unblock Length(), Error() and Head()
150
- re .waitOnce .Do (func () {
151
- close (re .wait )
152
- })
153
-
154
133
re .wl .Lock ()
155
134
defer re .wl .Unlock ()
156
135
157
136
if _ , ok := v .(Single ); ok {
158
- defer re .closeWithError (io .EOF )
137
+ defer re .closeWithError (nil )
138
+ }
159
139
160
140
// Initially this library allowed commands to return errors by sending an
161
141
// error value along a stream. We removed that in favour of CloseWithError,
162
142
// so we want to make sure we catch situations where some code still uses the
163
143
// old error emitting semantics and _panic_ in those situations.
164
144
debug .AssertNotError (v )
165
145
146
+ // unblock Length() and Error()
147
+ select {
148
+ case <- re .wait :
149
+ default :
150
+ close (re .wait )
151
+ }
152
+
153
+ // make sure we check whether the stream is closed *before accessing re.ch*!
154
+ // re.ch is set to nil, but is not protected by a shared mutex (because that
155
+ // wouldn't make sense).
156
+ // re.closed is set in a critical section protected by re.wl (we also took
157
+ // that lock), so we can be sure that this check is not racy.
158
+ if re .closed {
159
+ return ErrClosedEmitter
166
160
}
167
161
168
162
ctx := re .req .Context
169
163
170
164
select {
171
- case <- re .closed :
172
- return fmt .Errorf ("emitter closed" )
173
165
case re .ch <- v :
174
166
return nil
175
167
case <- ctx .Done ():
176
168
return ctx .Err ()
177
169
}
178
170
}
179
171
172
+ func (re * chanResponseEmitter ) Close () error {
173
+ return re .CloseWithError (nil )
174
+ }
175
+
180
176
func (re * chanResponseEmitter ) SetLength (l uint64 ) {
181
177
re .wl .Lock ()
182
178
defer re .wl .Unlock ()
183
179
184
- // don't change value after emitting
185
- if re .emitted {
186
- return
180
+ // don't change value after emitting or closing
181
+ select {
182
+ case <- re .wait :
183
+ default :
184
+ re .length = l
187
185
}
188
-
189
- re .length = l
190
- }
191
-
192
- func (re * chanResponseEmitter ) Close () error {
193
- return re .CloseWithError (nil )
194
186
}
195
187
196
188
func (re * chanResponseEmitter ) CloseWithError (err error ) error {
197
189
re .wl .Lock ()
198
190
defer re .wl .Unlock ()
199
191
200
- return re .closeWithError (err )
192
+ if re .closed {
193
+ return errors .New ("close of closed emitter" )
194
+ }
195
+
196
+ re .closeWithError (err )
197
+ return nil
201
198
}
202
199
203
- func (re * chanResponseEmitter ) closeWithError (err error ) error {
200
+ func (re * chanResponseEmitter ) closeWithError (err error ) {
201
+ re .closed = true
202
+
204
203
if err == nil {
205
204
err = io .EOF
206
205
}
@@ -209,16 +208,13 @@ func (re *chanResponseEmitter) closeWithError(err error) error {
209
208
err = & e
210
209
}
211
210
212
- re .closeOnce .Do (func () {
213
- re .err = err
214
- close (re .ch )
215
- close (re .closed )
216
- })
211
+ re .err = err
212
+ close (re .ch )
217
213
218
- // unblock Length(), Error() and Head()
219
- re .waitOnce .Do (func () {
214
+ // unblock Length() and Error()
215
+ select {
216
+ case <- re .wait :
217
+ default :
220
218
close (re .wait )
221
- })
222
-
223
- return nil
219
+ }
224
220
}
0 commit comments