Skip to main content

turbo_tasks_fetch/
error.rs

1use 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}