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.into()
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 StyledString::Text(match kind {
99 FetchErrorKind::Connect => {
100 format!("There was an issue establishing a connection while requesting {url}.")
101 .into()
102 }
103 FetchErrorKind::Status(status) => {
104 format!("Received response with status {status} when requesting {url}").into()
105 }
106 FetchErrorKind::Timeout => {
107 format!("Connection timed out when requesting {url}").into()
108 }
109 FetchErrorKind::Other => format!("There was an issue requesting {url}").into(),
110 })
111 .resolved_cell(),
112 )))
113 }
114
115 #[turbo_tasks::function]
116 fn detail(&self) -> Vc<OptionStyledString> {
117 Vc::cell(Some(self.detail))
118 }
119}