From 5ecd9378d76e4a439ea504fe740daaa3f54a8a4b Mon Sep 17 00:00:00 2001 From: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com> Date: Fri, 28 Jan 2022 01:58:17 +0500 Subject: [PATCH] Feat request timeout (#25) * feat: add request timeout * feat: add prop `requestTimeout` * add docs for `requestTimeout` prop * Update README.md Co-authored-by: Thomas P. Co-authored-by: Thomas P. --- README.md | 1 + src/LinkPreview.tsx | 6 ++++-- src/utils.ts | 15 +++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 87ad1fa..c3e7a50 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ return ( | renderTitle | (string) => ReactNode | Custom title render prop | | textContainerStyle | [ViewStyle](https://reactnative.dev/docs/view-style-props) | Text, title, description and minimized image container style | | touchableWithoutFeedbackProps | TouchableWithoutFeedbackProps | Top level touchable props | +| requestTimeout | number | Timeout after which request to get preview data should abort | ## License diff --git a/src/LinkPreview.tsx b/src/LinkPreview.tsx index 098b2ae..636d79b 100644 --- a/src/LinkPreview.tsx +++ b/src/LinkPreview.tsx @@ -37,7 +37,8 @@ export interface LinkPreviewProps { renderTitle?: (title: string) => React.ReactNode text: string textContainerStyle?: StyleProp - touchableWithoutFeedbackProps?: TouchableWithoutFeedbackProps + touchableWithoutFeedbackProps?: TouchableWithoutFeedbackProps, + requestTimeout?:number } export const LinkPreview = React.memo( @@ -59,6 +60,7 @@ export const LinkPreview = React.memo( text, textContainerStyle, touchableWithoutFeedbackProps, + requestTimeout = 5000 }: LinkPreviewProps) => { const [containerWidth, setContainerWidth] = React.useState(0) const [data, setData] = React.useState(previewData) @@ -75,7 +77,7 @@ export const LinkPreview = React.memo( const fetchData = async () => { setData(undefined) - const newData = await getPreviewData(text) + const newData = await getPreviewData(text, requestTimeout) // Set data only if component is still mounted /* istanbul ignore next */ if (!isCancelled) { diff --git a/src/utils.ts b/src/utils.ts index 808c696..b03a57d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -54,7 +54,7 @@ export const getImageSize = (url: string) => { // Functions below use functions from the same file and mocks are not working /* istanbul ignore next */ -export const getPreviewData = async (text: string) => { +export const getPreviewData = async (text: string, requestTimeout=5000) => { const previewData: PreviewData = { description: undefined, image: undefined, @@ -77,13 +77,24 @@ export const getPreviewData = async (text: string) => { url = 'https://' + url } - const response = await fetch(url, { + let abortControllerTimeout: NodeJS.Timeout; + const abortController = new AbortController(); + + const request = fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', }, + signal:abortController.signal }) + abortControllerTimeout = setTimeout(() => { + abortController.abort(); + }, requestTimeout); + const response = await request; + + clearTimeout(abortControllerTimeout); + previewData.link = url const contentType = response.headers.get('content-type') ?? ''