1/**
2 * Copyright (c) 650 Industries.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9import { Platform } from 'react-native';
10// @ts-expect-error
11import Networking from 'react-native/Libraries/Network/RCTNetworking';
12
13type Subscriber = { remove: () => void };
14
15export function fetchAsync(
16  url: string
17): Promise<{ body: string; headers: Record<string, string> }> {
18  let id: string | null = null;
19  let responseText: string | null = null;
20  let headers: Record<string, string> = {};
21  let dataListener: Subscriber | null = null;
22  let completeListener: Subscriber | null = null;
23  let responseListener: Subscriber | null = null;
24  return new Promise<{ body: string; headers: Record<string, string> }>((resolve, reject) => {
25    const addListener = Networking.addListener as (
26      event: string,
27      callback: (props: [string, any, any]) => any
28    ) => Subscriber;
29    dataListener = addListener('didReceiveNetworkData', ([requestId, response]) => {
30      if (requestId === id) {
31        responseText = response;
32      }
33    });
34    responseListener = addListener(
35      'didReceiveNetworkResponse',
36      ([requestId, status, responseHeaders]) => {
37        if (requestId === id) {
38          headers = responseHeaders;
39        }
40      }
41    );
42    completeListener = addListener('didCompleteNetworkResponse', ([requestId, error]) => {
43      if (requestId === id) {
44        if (error) {
45          reject(error);
46        } else {
47          resolve({ body: responseText!, headers });
48        }
49      }
50    });
51    (Networking.sendRequest as any)(
52      'GET',
53      'asyncRequest',
54      url,
55      {
56        'expo-platform': Platform.OS,
57      },
58      '',
59      'text',
60      false,
61      0,
62      (requestId: string) => {
63        id = requestId;
64      },
65      true
66    );
67  }).finally(() => {
68    dataListener?.remove();
69    completeListener?.remove();
70    responseListener?.remove();
71  });
72}
73