1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | import * as Types from './types';
|
11 | import * as PrivateTypes from './privateTypes';
|
12 |
|
13 | interface InternetReachabilityCheckHandler {
|
14 | promise: Promise<void>;
|
15 | cancel: () => void;
|
16 | }
|
17 |
|
18 | export default class InternetReachability {
|
19 | private _configuration: Types.NetInfoConfiguration;
|
20 | private _listener: PrivateTypes.NetInfoInternetReachabilityChangeListener;
|
21 | private _isInternetReachable: boolean | null | undefined = undefined;
|
22 | private _currentInternetReachabilityCheckHandler: InternetReachabilityCheckHandler | null = null;
|
23 | private _currentTimeoutHandle: ReturnType<typeof setTimeout> | null = null;
|
24 |
|
25 | constructor(
|
26 | configuration: Types.NetInfoConfiguration,
|
27 | listener: PrivateTypes.NetInfoInternetReachabilityChangeListener,
|
28 | ) {
|
29 | this._configuration = configuration;
|
30 | this._listener = listener;
|
31 | }
|
32 |
|
33 | private _setIsInternetReachable = (
|
34 | isInternetReachable: boolean | null | undefined,
|
35 | ): void => {
|
36 | if (this._isInternetReachable === isInternetReachable) {
|
37 | return;
|
38 | }
|
39 |
|
40 | this._isInternetReachable = isInternetReachable;
|
41 | this._listener(this._isInternetReachable);
|
42 | };
|
43 |
|
44 | private _setExpectsConnection = (expectsConnection: boolean): void => {
|
45 |
|
46 | if (this._currentInternetReachabilityCheckHandler !== null) {
|
47 | this._currentInternetReachabilityCheckHandler.cancel();
|
48 | this._currentInternetReachabilityCheckHandler = null;
|
49 | }
|
50 |
|
51 | if (this._currentTimeoutHandle !== null) {
|
52 | clearTimeout(this._currentTimeoutHandle);
|
53 | this._currentTimeoutHandle = null;
|
54 | }
|
55 |
|
56 | if (expectsConnection) {
|
57 |
|
58 |
|
59 | if (!this._isInternetReachable) {
|
60 | this._setIsInternetReachable(null);
|
61 | }
|
62 |
|
63 | this._currentInternetReachabilityCheckHandler = this._checkInternetReachability();
|
64 | } else {
|
65 |
|
66 | this._setIsInternetReachable(false);
|
67 | }
|
68 | };
|
69 |
|
70 | private _checkInternetReachability = (): InternetReachabilityCheckHandler => {
|
71 | const responsePromise = fetch(this._configuration.reachabilityUrl, {
|
72 | method: 'HEAD',
|
73 | cache: 'no-cache',
|
74 | });
|
75 |
|
76 |
|
77 | let timeoutHandle: ReturnType<typeof setTimeout>;
|
78 | const timeoutPromise = new Promise<Response>(
|
79 | (_, reject): void => {
|
80 | timeoutHandle = setTimeout(
|
81 | (): void => reject('timedout'),
|
82 | this._configuration.reachabilityRequestTimeout,
|
83 | );
|
84 | },
|
85 | );
|
86 |
|
87 |
|
88 | let cancel: () => void = (): void => {};
|
89 | const cancelPromise = new Promise<Response>(
|
90 | (_, reject): void => {
|
91 | cancel = (): void => reject('canceled');
|
92 | },
|
93 | );
|
94 |
|
95 | const promise = Promise.race([
|
96 | responsePromise,
|
97 | timeoutPromise,
|
98 | cancelPromise,
|
99 | ])
|
100 | .then(
|
101 | (response): Promise<boolean> => {
|
102 | return this._configuration.reachabilityTest(response);
|
103 | },
|
104 | )
|
105 | .then(
|
106 | (result): void => {
|
107 | this._setIsInternetReachable(result);
|
108 | const nextTimeoutInterval = this._isInternetReachable
|
109 | ? this._configuration.reachabilityLongTimeout
|
110 | : this._configuration.reachabilityShortTimeout;
|
111 | this._currentTimeoutHandle = setTimeout(
|
112 | this._checkInternetReachability,
|
113 | nextTimeoutInterval,
|
114 | );
|
115 | },
|
116 | )
|
117 | .catch(
|
118 | (error: Error | 'timedout' | 'canceled'): void => {
|
119 | if (error !== 'canceled') {
|
120 | this._setIsInternetReachable(false);
|
121 | this._currentTimeoutHandle = setTimeout(
|
122 | this._checkInternetReachability,
|
123 | this._configuration.reachabilityShortTimeout,
|
124 | );
|
125 | }
|
126 | },
|
127 | )
|
128 |
|
129 | .then(
|
130 | (): void => {
|
131 | clearTimeout(timeoutHandle);
|
132 | },
|
133 | (error: Error): void => {
|
134 | clearTimeout(timeoutHandle);
|
135 | throw error;
|
136 | },
|
137 | );
|
138 |
|
139 | return {
|
140 | promise,
|
141 | cancel,
|
142 | };
|
143 | };
|
144 |
|
145 | public update = (state: PrivateTypes.NetInfoNativeModuleState): void => {
|
146 | if (typeof state.isInternetReachable === 'boolean') {
|
147 | this._setIsInternetReachable(state.isInternetReachable);
|
148 | } else {
|
149 | this._setExpectsConnection(state.isConnected);
|
150 | }
|
151 | };
|
152 |
|
153 | public currentState = (): boolean | null | undefined => {
|
154 | return this._isInternetReachable;
|
155 | };
|
156 |
|
157 | public tearDown = (): void => {
|
158 |
|
159 | if (this._currentInternetReachabilityCheckHandler !== null) {
|
160 | this._currentInternetReachabilityCheckHandler.cancel();
|
161 | this._currentInternetReachabilityCheckHandler = null;
|
162 | }
|
163 |
|
164 |
|
165 | if (this._currentTimeoutHandle !== null) {
|
166 | clearTimeout(this._currentTimeoutHandle);
|
167 | this._currentTimeoutHandle = null;
|
168 | }
|
169 | };
|
170 | }
|