turbo_tasks_fetch/
error.rs1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, Vc};
4use turbo_tasks_fs::FileSystemPath;
5use turbopack_core::issue::{Issue, IssueSeverity, IssueStage, OptionStyledString, StyledString};
6
7#[derive(Debug)]
8#[turbo_tasks::value(shared)]
9pub enum FetchErrorKind {
10 Connect,
11 Timeout,
12 Status(u16),
13 Other,
14}
15
16#[turbo_tasks::value(shared)]
17pub struct FetchError {
18 pub url: ResolvedVc<RcStr>,
19 pub kind: ResolvedVc<FetchErrorKind>,
20 pub detail: ResolvedVc<StyledString>,
21}
22
23impl FetchError {
24 pub(crate) fn from_reqwest_error(error: &reqwest::Error, url: &str) -> FetchError {
25 let kind = if error.is_connect() {
26 FetchErrorKind::Connect
27 } else if error.is_timeout() {
28 FetchErrorKind::Timeout
29 } else if let Some(status) = error.status() {
30 FetchErrorKind::Status(status.as_u16())
31 } else {
32 FetchErrorKind::Other
33 };
34
35 FetchError {
36 detail: StyledString::Text(error.to_string().into()).resolved_cell(),
37 url: ResolvedVc::cell(url.into()),
38 kind: kind.resolved_cell(),
39 }
40 }
41}
42
43#[turbo_tasks::value_impl]
44impl FetchError {
45 #[turbo_tasks::function]
46 pub fn to_issue(
47 &self,
48 severity: IssueSeverity,
49 issue_context: FileSystemPath,
50 ) -> Vc<FetchIssue> {
51 FetchIssue {
52 issue_context,
53 severity,
54 url: self.url,
55 kind: self.kind,
56 detail: self.detail,
57 }
58 .cell()
59 }
60}
61
62#[turbo_tasks::value(shared)]
63pub struct FetchIssue {
64 pub issue_context: FileSystemPath,
65 pub severity: IssueSeverity,
66 pub url: ResolvedVc<RcStr>,
67 pub kind: ResolvedVc<FetchErrorKind>,
68 pub detail: ResolvedVc<StyledString>,
69}
70
71#[turbo_tasks::value_impl]
72impl Issue for FetchIssue {
73 #[turbo_tasks::function]
74 fn file_path(&self) -> Vc<FileSystemPath> {
75 self.issue_context.clone().cell()
76 }
77
78 fn severity(&self) -> IssueSeverity {
79 self.severity
80 }
81
82 #[turbo_tasks::function]
83 fn title(&self) -> Vc<StyledString> {
84 StyledString::Text(rcstr!("Error while requesting resource")).cell()
85 }
86
87 #[turbo_tasks::function]
88 fn stage(&self) -> Vc<IssueStage> {
89 IssueStage::Load.cell()
90 }
91
92 #[turbo_tasks::function]
93 async fn description(&self) -> Result<Vc<OptionStyledString>> {
94 let url = &*self.url.await?;
95 let kind = &*self.kind.await?;
96
97 Ok(Vc::cell(Some(
98 match kind {
99 FetchErrorKind::Connect => StyledString::Line(vec![
100 StyledString::Text(rcstr!(
101 "There was an issue establishing a connection while requesting "
102 )),
103 StyledString::Code(url.clone()),
104 ]),
105 FetchErrorKind::Status(status) => StyledString::Line(vec![
106 StyledString::Text(rcstr!("Received response with status ")),
107 StyledString::Code(RcStr::from(status.to_string())),
108 StyledString::Text(rcstr!(" when requesting ")),
109 StyledString::Code(url.clone()),
110 ]),
111 FetchErrorKind::Timeout => StyledString::Line(vec![
112 StyledString::Text(rcstr!("Connection timed out when requesting ")),
113 StyledString::Code(url.clone()),
114 ]),
115 FetchErrorKind::Other => StyledString::Line(vec![
116 StyledString::Text(rcstr!("There was an issue requesting ")),
117 StyledString::Code(url.clone()),
118 ]),
119 }
120 .resolved_cell(),
121 )))
122 }
123
124 #[turbo_tasks::function]
125 fn detail(&self) -> Vc<OptionStyledString> {
126 Vc::cell(Some(self.detail))
127 }
128}