From f158e5c115472ed9751dff971389d79d03fcef7b Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 30 Oct 2023 20:18:33 +0100 Subject: [PATCH 01/11] fix delay --- src/libs/DateUtils.ts | 16 ++++++++++++++++ src/libs/HttpUtils.js | 22 ++++++++++++++++++++++ src/libs/ReportUtils.js | 2 +- src/libs/actions/Network.ts | 6 +++++- src/libs/actions/Report.js | 2 +- src/types/onyx/Network.ts | 3 +++ 6 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 13853189ed26..a1e156a9b7cc 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -55,6 +55,12 @@ Onyx.connect({ }, }); +let networkTimeSkew: number = 0; +Onyx.connect({ + key: ONYXKEYS.NETWORK, + callback: (value) => (networkTimeSkew = value?.timeSkew), +}); + /** * Gets the locale string and setting default locale for date-fns */ @@ -304,6 +310,15 @@ function getDateStringFromISOTimestamp(isoTimestamp: string): string { return dateString; } +/** + * Returns the current time plus skew in milliseconds in the format expected by the database + * + * @returns {String} + */ +function getDBTimeWithSkew() { + return getDBTime(new Date().valueOf() + networkTimeSkew); +} + /** * receive date like 2020-05-16 05:34:14 and format it to show in string like "Until 05:34 PM" */ @@ -374,6 +389,7 @@ const DateUtils = { isTomorrow, isYesterday, formatWithUTCTimeZone, + getDBTimeWithSkew, }; export default DateUtils; diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js index 2df7421ea91c..fca7fdf76bb9 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.js @@ -22,6 +22,16 @@ Onyx.connect({ // We use the AbortController API to terminate pending request in `cancelPendingRequests` let cancellationController = new AbortController(); +/** + * The API commands that require the skew calculation + */ +const addSkewList = ['OpenReport', 'ReconnectApp', 'OpenApp']; + +/** + * Regex to get API command from the command + */ +const regex = /[?&]command=([^&]+)/; + /** * Send an HTTP request, and attempt to resolve the json response. * If there is a network error, we'll set the application offline. @@ -33,12 +43,24 @@ let cancellationController = new AbortController(); * @returns {Promise} */ function processHTTPRequest(url, method = 'get', body = null, canCancel = true) { + const startTime = new Date().valueOf(); return fetch(url, { // We hook requests to the same Controller signal, so we can cancel them all at once signal: canCancel ? cancellationController.signal : undefined, method, body, }) + .then((response) => { + const match = url.match(regex)[1]; + if (addSkewList.includes(match) && response.headers) { + const serverTime = new Date(response.headers.get('Date')).valueOf(); + const endTime = new Date().valueOf(); + const latency = (endTime - startTime) / 2; + const skew = serverTime - startTime + latency; + NetworkActions.setTimeSkew(skew); + } + return response; + }) .then((response) => { // Test mode where all requests will succeed in the server, but fail to return a response if (shouldFailAllRequests || shouldForceOffline) { diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 8cadc6dcc8ec..862ed1da4379 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2206,7 +2206,7 @@ function buildOptimisticAddCommentReportAction(text, file) { ], automatic: false, avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatarURL(currentUserAccountID)), - created: DateUtils.getDBTime(), + created: DateUtils.getDBTimeWithSkew(), message: [ { translationKey: isAttachment ? CONST.TRANSLATION_KEYS.ATTACHMENT : '', diff --git a/src/libs/actions/Network.ts b/src/libs/actions/Network.ts index 17580c214376..e71094eded05 100644 --- a/src/libs/actions/Network.ts +++ b/src/libs/actions/Network.ts @@ -5,6 +5,10 @@ function setIsOffline(isOffline: boolean) { Onyx.merge(ONYXKEYS.NETWORK, {isOffline}); } +function setTimeSkew(skew: number) { + Onyx.merge(ONYXKEYS.NETWORK, {timeSkew: skew}); +} + function setShouldForceOffline(shouldForceOffline: boolean) { Onyx.merge(ONYXKEYS.NETWORK, {shouldForceOffline}); } @@ -16,4 +20,4 @@ function setShouldFailAllRequests(shouldFailAllRequests: boolean) { Onyx.merge(ONYXKEYS.NETWORK, {shouldFailAllRequests}); } -export {setIsOffline, setShouldForceOffline, setShouldFailAllRequests}; +export {setIsOffline, setShouldForceOffline, setShouldFailAllRequests, setTimeSkew}; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 3f7dc76b174d..363f159fd7f2 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -315,7 +315,7 @@ function addActions(reportID, text = '', file) { // Always prefer the file as the last action over text const lastAction = attachmentAction || reportCommentAction; - const currentTime = DateUtils.getDBTime(); + const currentTime = DateUtils.getDBTimeWithSkew(); const lastCommentText = ReportUtils.formatReportLastMessageText(lastAction.message[0].text); diff --git a/src/types/onyx/Network.ts b/src/types/onyx/Network.ts index 5af4c1170c3f..32b084bbf2f7 100644 --- a/src/types/onyx/Network.ts +++ b/src/types/onyx/Network.ts @@ -7,6 +7,9 @@ type Network = { /** Whether we should fail all network requests */ shouldFailAllRequests?: boolean; + + /** Skew between the client and server clocks */ + timeSkew?: number; }; export default Network; From 5704405e083297510919af0f44cc3a08319f43d2 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 30 Oct 2023 20:21:34 +0100 Subject: [PATCH 02/11] added lib --- src/libs/HttpUtils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js index fca7fdf76bb9..f555991f19c6 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.js @@ -3,6 +3,7 @@ import _ from 'underscore'; import alert from '@components/Alert'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import * as NetworkActions from './actions/Network'; import * as ApiUtils from './ApiUtils'; import HttpsError from './Errors/HttpsError'; @@ -44,6 +45,7 @@ const regex = /[?&]command=([^&]+)/; */ function processHTTPRequest(url, method = 'get', body = null, canCancel = true) { const startTime = new Date().valueOf(); + return fetch(url, { // We hook requests to the same Controller signal, so we can cancel them all at once signal: canCancel ? cancellationController.signal : undefined, From 9738d5231a98f3148a93b2eefb78e5163960b3ab Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 31 Oct 2023 15:35:09 +0100 Subject: [PATCH 03/11] lint fix --- src/libs/DateUtils.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index a1e156a9b7cc..0b127009484e 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -55,7 +55,7 @@ Onyx.connect({ }, }); -let networkTimeSkew: number = 0; +let networkTimeSkew = 0; Onyx.connect({ key: ONYXKEYS.NETWORK, callback: (value) => (networkTimeSkew = value?.timeSkew), @@ -312,10 +312,8 @@ function getDateStringFromISOTimestamp(isoTimestamp: string): string { /** * Returns the current time plus skew in milliseconds in the format expected by the database - * - * @returns {String} */ -function getDBTimeWithSkew() { +function getDBTimeWithSkew(): string { return getDBTime(new Date().valueOf() + networkTimeSkew); } From e4722b1957949da556b846583b09a5291ce4acc2 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 31 Oct 2023 15:44:36 +0100 Subject: [PATCH 04/11] ts check fix --- src/libs/DateUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 0b127009484e..f4346f6ff7c0 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -55,7 +55,7 @@ Onyx.connect({ }, }); -let networkTimeSkew = 0; +let networkTimeSkew: number | undefined = 0; Onyx.connect({ key: ONYXKEYS.NETWORK, callback: (value) => (networkTimeSkew = value?.timeSkew), From 10983780352ae87ffdb123d608169ca4dd4f5fbb Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 31 Oct 2023 15:49:50 +0100 Subject: [PATCH 05/11] ts check fix --- src/libs/DateUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index f4346f6ff7c0..b87d5d6e8973 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -55,10 +55,10 @@ Onyx.connect({ }, }); -let networkTimeSkew: number | undefined = 0; +let networkTimeSkew = 0; Onyx.connect({ key: ONYXKEYS.NETWORK, - callback: (value) => (networkTimeSkew = value?.timeSkew), + callback: (value) => (networkTimeSkew = value?.timeSkew || 0), }); /** From 0428382bcf6640a77f8057791a823e9674c2170f Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 31 Oct 2023 18:20:20 +0100 Subject: [PATCH 06/11] lint fix --- src/libs/DateUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index b87d5d6e8973..63f87a97eed2 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -58,7 +58,7 @@ Onyx.connect({ let networkTimeSkew = 0; Onyx.connect({ key: ONYXKEYS.NETWORK, - callback: (value) => (networkTimeSkew = value?.timeSkew || 0), + callback: (value) => (networkTimeSkew = value?.timeSkew ?? 0), }); /** From fbe9c2836315fc74b4170c345c32efe66a8d03bd Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Thu, 2 Nov 2023 16:08:22 +0100 Subject: [PATCH 07/11] fix --- src/libs/DateUtils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 695dcd573291..62a760e8427a 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -348,7 +348,10 @@ function getDateStringFromISOTimestamp(isoTimestamp: string): string { * Returns the current time plus skew in milliseconds in the format expected by the database */ function getDBTimeWithSkew(): string { - return getDBTime(new Date().valueOf() + networkTimeSkew); + if (networkTimeSkew > 0) { + return getDBTime(new Date().valueOf() + networkTimeSkew); + } + return getDBTime(); } /** From 532a64d0a5a822b8fd0950d2b4b57d7644c596a1 Mon Sep 17 00:00:00 2001 From: Artem Makushov <39777589+waterim@users.noreply.github.com> Date: Mon, 13 Nov 2023 18:04:17 +0100 Subject: [PATCH 08/11] Update src/libs/HttpUtils.js Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/libs/HttpUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js index f555991f19c6..b8fa11ae325f 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.js @@ -31,7 +31,7 @@ const addSkewList = ['OpenReport', 'ReconnectApp', 'OpenApp']; /** * Regex to get API command from the command */ -const regex = /[?&]command=([^&]+)/; +const APICommandRegex = /[?&]command=([^&]+)/; /** * Send an HTTP request, and attempt to resolve the json response. From 405a8ad33a93acd30288054a2a2bc21810957ebe Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 13 Nov 2023 18:32:05 +0100 Subject: [PATCH 09/11] fix tests --- src/libs/HttpUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js index b8fa11ae325f..93deaffe412f 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.js @@ -53,7 +53,7 @@ function processHTTPRequest(url, method = 'get', body = null, canCancel = true) body, }) .then((response) => { - const match = url.match(regex)[1]; + const match = url.match(APICommandRegex)[1]; if (addSkewList.includes(match) && response.headers) { const serverTime = new Date(response.headers.get('Date')).valueOf(); const endTime = new Date().valueOf(); From ea2ba21257e96091e45da326a1cc5780cf281192 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 29 Nov 2023 15:48:32 +0100 Subject: [PATCH 10/11] fix --- src/libs/HttpUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index dbb0717c571a..3fe92b5b1a89 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -56,7 +56,7 @@ function processHTTPRequest(url: string, method: RequestType = 'get', body: Form const endTime = new Date().valueOf(); const latency = (endTime - startTime) / 2; const skew = serverTime - startTime + latency; - NetworkActions.setTimeSkew(skew); + NetworkActions.setTimeSkew(dateHeaderValue ? skew : 0); } return response; }) From 7d5dd5e5f9991723c62cfed6f2d781865d2f517f Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 10 Jan 2024 18:35:06 +0100 Subject: [PATCH 11/11] add comment --- src/libs/HttpUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index 58c126518188..22e342ac847b 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -49,6 +49,7 @@ function processHTTPRequest(url: string, method: RequestType = 'get', body: Form body, }) .then((response) => { + // We are calculating the skew to minimize the delay when posting the messages const match = url.match(APICommandRegex)?.[1]; if (match && addSkewList.includes(match) && response.headers) { const dateHeaderValue = response.headers.get('Date');