Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reopened/Fix: User experienced big delay when posting the messages #30605

Merged
merged 15 commits into from
Jan 11, 2024
17 changes: 17 additions & 0 deletions src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ Onyx.connect({
},
});

let networkTimeSkew = 0;
Onyx.connect({
key: ONYXKEYS.NETWORK,
callback: (value) => (networkTimeSkew = value?.timeSkew ?? 0),
});

/**
* Get the day of the week that the week starts on
*/
Expand Down Expand Up @@ -359,6 +365,16 @@ function getDBTime(timestamp: string | number = ''): string {
return datetime.toISOString().replace('T', ' ').replace('Z', '');
}

/**
* Returns the current time plus skew in milliseconds in the format expected by the database
*/
function getDBTimeWithSkew(): string {
if (networkTimeSkew > 0) {
return getDBTime(new Date().valueOf() + networkTimeSkew);
}
return getDBTime();
}

function subtractMillisecondsFromDateTime(dateTime: string, milliseconds: number): string {
const date = zonedTimeToUtc(dateTime, 'UTC');
const newTimestamp = subMilliseconds(date, milliseconds).valueOf();
Expand Down Expand Up @@ -728,6 +744,7 @@ const DateUtils = {
setTimezoneUpdated,
getMicroseconds,
getDBTime,
getDBTimeWithSkew,
setLocale,
subtractMillisecondsFromDateTime,
getDateStringFromISOTimestamp,
Expand Down
24 changes: 24 additions & 0 deletions src/libs/HttpUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {RequestType} from '@src/types/onyx/Request';
import type Response from '@src/types/onyx/Response';
import * as NetworkActions from './actions/Network';
import * as ApiUtils from './ApiUtils';
import HttpsError from './Errors/HttpsError';

Expand All @@ -25,17 +26,40 @@ 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 APICommandRegex = /[?&]command=([^&]+)/;

/**
* Send an HTTP request, and attempt to resolve the json response.
* If there is a network error, we'll set the application offline.
*/
function processHTTPRequest(url: string, method: RequestType = 'get', body: FormData | null = null, canCancel = true): Promise<Response> {
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(APICommandRegex)?.[1];
if (match && addSkewList.includes(match) && response.headers) {
const dateHeaderValue = response.headers.get('Date');
const serverTime = dateHeaderValue ? new Date(dateHeaderValue).valueOf() : new Date().valueOf();
const endTime = new Date().valueOf();
const latency = (endTime - startTime) / 2;
const skew = serverTime - startTime + latency;
NetworkActions.setTimeSkew(dateHeaderValue ? skew : 0);
}
return response;
})
waterim marked this conversation as resolved.
Show resolved Hide resolved
.then((response) => {
// Test mode where all requests will succeed in the server, but fail to return a response
if (shouldFailAllRequests || shouldForceOffline) {
Expand Down
2 changes: 1 addition & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2412,7 +2412,7 @@ function buildOptimisticAddCommentReportAction(text?: string, file?: File): Opti
],
automatic: false,
avatar: allPersonalDetails?.[currentUserAccountID ?? -1]?.avatar ?? UserUtils.getDefaultAvatarURL(currentUserAccountID),
created: DateUtils.getDBTime(),
created: DateUtils.getDBTimeWithSkew(),
message: [
{
translationKey: isAttachment ? CONST.TRANSLATION_KEYS.ATTACHMENT : '',
Expand Down
6 changes: 5 additions & 1 deletion src/libs/actions/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}
Expand All @@ -16,4 +20,4 @@ function setShouldFailAllRequests(shouldFailAllRequests: boolean) {
Onyx.merge(ONYXKEYS.NETWORK, {shouldFailAllRequests});
}

export {setIsOffline, setShouldForceOffline, setShouldFailAllRequests};
export {setIsOffline, setShouldForceOffline, setShouldFailAllRequests, setTimeSkew};
2 changes: 1 addition & 1 deletion src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ function addActions(reportID: string, text = '', file?: File) {

// Always prefer the file as the last action over text
const lastAction = attachmentAction ?? reportCommentAction;
const currentTime = DateUtils.getDBTime();
const currentTime = DateUtils.getDBTimeWithSkew();
const lastComment = lastAction?.message?.[0];
const lastCommentText = ReportUtils.formatReportLastMessageText(lastComment?.text ?? '');

Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading