1
1
use std:: pin:: Pin ;
2
2
3
- use anyhow:: { bail , Result } ;
3
+ use anyhow:: Result ;
4
4
use futures:: { prelude:: * , Stream } ;
5
5
use tokio:: sync:: mpsc:: Sender ;
6
6
use tokio_stream:: wrappers:: ReceiverStream ;
7
- use turbo_tasks:: { CollectiblesSource , IntoTraitRef , State , TraitRef , TransientInstance } ;
7
+ use turbo_tasks:: {
8
+ primitives:: StringVc , CollectiblesSource , IntoTraitRef , State , TraitRef , TransientInstance ,
9
+ } ;
10
+ use turbo_tasks_fs:: { FileSystem , FileSystemPathVc } ;
8
11
use turbopack_core:: {
9
- issue:: { IssueVc , PlainIssueReadRef } ,
12
+ error:: PrettyPrintError ,
13
+ issue:: {
14
+ Issue , IssueSeverity , IssueSeverityVc , IssueVc , OptionIssueProcessingPathItemsVc ,
15
+ PlainIssueReadRef ,
16
+ } ,
17
+ server_fs:: ServerFileSystemVc ,
10
18
version:: {
11
19
NotFoundVersionVc , PartialUpdate , TotalUpdate , Update , UpdateReadRef , VersionVc ,
12
20
VersionedContent ,
@@ -38,12 +46,43 @@ fn extend_issues(issues: &mut Vec<PlainIssueReadRef>, new_issues: Vec<PlainIssue
38
46
39
47
#[ turbo_tasks:: function]
40
48
async fn get_update_stream_item (
49
+ resource : & str ,
41
50
from : VersionStateVc ,
42
51
get_content : TransientInstance < GetContentFn > ,
43
52
) -> Result < UpdateStreamItemVc > {
44
53
let content = get_content ( ) ;
54
+ let mut plain_issues = peek_issues ( content) . await ?;
55
+
56
+ let content_value = match content. await {
57
+ Ok ( content) => content,
58
+ Err ( e) => {
59
+ plain_issues. push (
60
+ FatalStreamIssue {
61
+ resource : resource. to_string ( ) ,
62
+ description : StringVc :: cell ( format ! ( "{}" , PrettyPrintError ( & e) ) ) ,
63
+ }
64
+ . cell ( )
65
+ . as_issue ( )
66
+ . into_plain ( OptionIssueProcessingPathItemsVc :: none ( ) )
67
+ . await ?,
68
+ ) ;
69
+
70
+ let update = Update :: Total ( TotalUpdate {
71
+ to : NotFoundVersionVc :: new ( )
72
+ . as_version ( )
73
+ . into_trait_ref ( )
74
+ . await ?,
75
+ } )
76
+ . cell ( ) ;
77
+ return Ok ( UpdateStreamItem :: Found {
78
+ update : update. await ?,
79
+ issues : plain_issues,
80
+ }
81
+ . cell ( ) ) ;
82
+ }
83
+ } ;
45
84
46
- match * content . await ? {
85
+ match * content_value {
47
86
ResolveSourceRequestResult :: Static ( static_content_vc, _) => {
48
87
let static_content = static_content_vc. await ?;
49
88
@@ -56,8 +95,7 @@ async fn get_update_stream_item(
56
95
let from = from. get ( ) ;
57
96
let update = resolved_content. update ( from) ;
58
97
59
- let mut plain_issues = peek_issues ( update) . await ?;
60
- extend_issues ( & mut plain_issues, peek_issues ( content) . await ?) ;
98
+ extend_issues ( & mut plain_issues, peek_issues ( update) . await ?) ;
61
99
62
100
let update = update. await ?;
63
101
@@ -74,7 +112,7 @@ async fn get_update_stream_item(
74
112
return Ok ( UpdateStreamItem :: NotFound . cell ( ) ) ;
75
113
}
76
114
77
- let plain_issues = peek_issues ( proxy_result) . await ?;
115
+ extend_issues ( & mut plain_issues, peek_issues ( proxy_result) . await ?) ;
78
116
79
117
let from = from. get ( ) ;
80
118
if let Some ( from) = ProxyResultVc :: resolve_from ( from) . await ? {
@@ -98,8 +136,6 @@ async fn get_update_stream_item(
98
136
. cell ( ) )
99
137
}
100
138
_ => {
101
- let plain_issues = peek_issues ( content) . await ?;
102
-
103
139
let update = if plain_issues. is_empty ( ) {
104
140
// Client requested a non-existing asset
105
141
// It might be removed in meantime, reload client
@@ -127,19 +163,17 @@ async fn get_update_stream_item(
127
163
128
164
#[ turbo_tasks:: function]
129
165
async fn compute_update_stream (
166
+ resource : & str ,
130
167
from : VersionStateVc ,
131
168
get_content : TransientInstance < GetContentFn > ,
132
- sender : TransientInstance < Sender < UpdateStreamItemReadRef > > ,
133
- ) -> Result < ( ) > {
134
- let item = get_update_stream_item ( from, get_content)
169
+ sender : TransientInstance < Sender < Result < UpdateStreamItemReadRef > > > ,
170
+ ) {
171
+ let item = get_update_stream_item ( resource , from, get_content)
135
172
. strongly_consistent ( )
136
- . await ?;
137
-
138
- if sender. send ( item) . await . is_err ( ) {
139
- bail ! ( "channel closed" ) ;
140
- }
173
+ . await ;
141
174
142
- Ok ( ( ) )
175
+ // Send update. Ignore channel closed error.
176
+ let _ = sender. send ( item) . await ;
143
177
}
144
178
145
179
#[ turbo_tasks:: value]
@@ -172,10 +206,15 @@ impl VersionStateVc {
172
206
}
173
207
}
174
208
175
- pub ( super ) struct UpdateStream ( Pin < Box < dyn Stream < Item = UpdateStreamItemReadRef > + Send + Sync > > ) ;
209
+ pub ( super ) struct UpdateStream (
210
+ Pin < Box < dyn Stream < Item = Result < UpdateStreamItemReadRef > > + Send + Sync > > ,
211
+ ) ;
176
212
177
213
impl UpdateStream {
178
- pub async fn new ( get_content : TransientInstance < GetContentFn > ) -> Result < UpdateStream > {
214
+ pub async fn new (
215
+ resource : String ,
216
+ get_content : TransientInstance < GetContentFn > ,
217
+ ) -> Result < UpdateStream > {
179
218
let ( sx, rx) = tokio:: sync:: mpsc:: channel ( 32 ) ;
180
219
181
220
let content = get_content ( ) ;
@@ -190,13 +229,18 @@ impl UpdateStream {
190
229
} ;
191
230
let version_state = VersionStateVc :: new ( version. into_trait_ref ( ) . await ?) . await ?;
192
231
193
- compute_update_stream ( version_state, get_content, TransientInstance :: new ( sx) ) ;
232
+ compute_update_stream (
233
+ & resource,
234
+ version_state,
235
+ get_content,
236
+ TransientInstance :: new ( sx) ,
237
+ ) ;
194
238
195
239
let mut last_had_issues = false ;
196
240
197
241
let stream = ReceiverStream :: new ( rx) . filter_map ( move |item| {
198
242
let ( has_issues, issues_changed) =
199
- if let UpdateStreamItem :: Found { issues, .. } = & * item {
243
+ if let Some ( UpdateStreamItem :: Found { issues, .. } ) = item. as_deref ( ) . ok ( ) {
200
244
let has_issues = !issues. is_empty ( ) ;
201
245
let issues_changed = has_issues != last_had_issues;
202
246
last_had_issues = has_issues;
@@ -206,12 +250,8 @@ impl UpdateStream {
206
250
} ;
207
251
208
252
async move {
209
- match & * item {
210
- UpdateStreamItem :: NotFound => {
211
- // Propagate not found updates so we can drop this update stream.
212
- Some ( item)
213
- }
214
- UpdateStreamItem :: Found { update, .. } => {
253
+ match item. as_deref ( ) {
254
+ Ok ( UpdateStreamItem :: Found { update, .. } ) => {
215
255
match & * * update {
216
256
Update :: Partial ( PartialUpdate { to, .. } )
217
257
| Update :: Total ( TotalUpdate { to } ) => {
@@ -232,6 +272,10 @@ impl UpdateStream {
232
272
}
233
273
}
234
274
}
275
+ _ => {
276
+ // Propagate other updates
277
+ Some ( item)
278
+ }
235
279
}
236
280
}
237
281
} ) ;
@@ -241,7 +285,7 @@ impl UpdateStream {
241
285
}
242
286
243
287
impl Stream for UpdateStream {
244
- type Item = UpdateStreamItemReadRef ;
288
+ type Item = Result < UpdateStreamItemReadRef > ;
245
289
246
290
fn poll_next (
247
291
self : Pin < & mut Self > ,
@@ -260,3 +304,37 @@ pub enum UpdateStreamItem {
260
304
issues : Vec < PlainIssueReadRef > ,
261
305
} ,
262
306
}
307
+
308
+ #[ turbo_tasks:: value( serialization = "none" ) ]
309
+ struct FatalStreamIssue {
310
+ description : StringVc ,
311
+ resource : String ,
312
+ }
313
+
314
+ #[ turbo_tasks:: value_impl]
315
+ impl Issue for FatalStreamIssue {
316
+ #[ turbo_tasks:: function]
317
+ fn severity ( & self ) -> IssueSeverityVc {
318
+ IssueSeverity :: Fatal . into ( )
319
+ }
320
+
321
+ #[ turbo_tasks:: function]
322
+ fn context ( & self ) -> FileSystemPathVc {
323
+ ServerFileSystemVc :: new ( ) . root ( ) . join ( & self . resource )
324
+ }
325
+
326
+ #[ turbo_tasks:: function]
327
+ fn category ( & self ) -> StringVc {
328
+ StringVc :: cell ( "websocket" . to_string ( ) )
329
+ }
330
+
331
+ #[ turbo_tasks:: function]
332
+ fn title ( & self ) -> StringVc {
333
+ StringVc :: cell ( "Fatal error while getting content to stream" . to_string ( ) )
334
+ }
335
+
336
+ #[ turbo_tasks:: function]
337
+ fn description ( & self ) -> StringVc {
338
+ self . description
339
+ }
340
+ }
0 commit comments