From 217dfc3eed0c5f018a986ddc4f1c05a1a31b5960 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 12 Nov 2019 11:40:38 +0000 Subject: [PATCH 1/7] Replace all trivial Promise.defer usages with regular Promises (cherry picked from commit 44401d73b44b6de4daeb91613456d2760d50456d) --- src/ContentMessages.js | 174 +++++++++--------- src/Lifecycle.js | 8 +- src/components/views/rooms/Autocomplete.js | 29 ++- .../views/settings/ChangePassword.js | 9 +- src/rageshake/submit-rageshake.js | 40 ++-- 5 files changed, 122 insertions(+), 138 deletions(-) diff --git a/src/ContentMessages.js b/src/ContentMessages.js index 2d58622db8..dab8de2465 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -59,40 +59,38 @@ export class UploadCanceledError extends Error {} * and a thumbnail key. */ function createThumbnail(element, inputWidth, inputHeight, mimeType) { - const deferred = Promise.defer(); + return new Promise((resolve) => { + let targetWidth = inputWidth; + let targetHeight = inputHeight; + if (targetHeight > MAX_HEIGHT) { + targetWidth = Math.floor(targetWidth * (MAX_HEIGHT / targetHeight)); + targetHeight = MAX_HEIGHT; + } + if (targetWidth > MAX_WIDTH) { + targetHeight = Math.floor(targetHeight * (MAX_WIDTH / targetWidth)); + targetWidth = MAX_WIDTH; + } - let targetWidth = inputWidth; - let targetHeight = inputHeight; - if (targetHeight > MAX_HEIGHT) { - targetWidth = Math.floor(targetWidth * (MAX_HEIGHT / targetHeight)); - targetHeight = MAX_HEIGHT; - } - if (targetWidth > MAX_WIDTH) { - targetHeight = Math.floor(targetHeight * (MAX_WIDTH / targetWidth)); - targetWidth = MAX_WIDTH; - } - - const canvas = document.createElement("canvas"); - canvas.width = targetWidth; - canvas.height = targetHeight; - canvas.getContext("2d").drawImage(element, 0, 0, targetWidth, targetHeight); - canvas.toBlob(function(thumbnail) { - deferred.resolve({ - info: { - thumbnail_info: { - w: targetWidth, - h: targetHeight, - mimetype: thumbnail.type, - size: thumbnail.size, + const canvas = document.createElement("canvas"); + canvas.width = targetWidth; + canvas.height = targetHeight; + canvas.getContext("2d").drawImage(element, 0, 0, targetWidth, targetHeight); + canvas.toBlob(function(thumbnail) { + resolve({ + info: { + thumbnail_info: { + w: targetWidth, + h: targetHeight, + mimetype: thumbnail.type, + size: thumbnail.size, + }, + w: inputWidth, + h: inputHeight, }, - w: inputWidth, - h: inputHeight, - }, - thumbnail: thumbnail, - }); - }, mimeType); - - return deferred.promise; + thumbnail: thumbnail, + }); + }, mimeType); + }); } /** @@ -179,30 +177,29 @@ function infoForImageFile(matrixClient, roomId, imageFile) { * @return {Promise} A promise that resolves with the video image element. */ function loadVideoElement(videoFile) { - const deferred = Promise.defer(); + return new Promise((resolve, reject) => { + // Load the file into an html element + const video = document.createElement("video"); - // Load the file into an html element - const video = document.createElement("video"); + const reader = new FileReader(); - const reader = new FileReader(); - reader.onload = function(e) { - video.src = e.target.result; + reader.onload = function(e) { + video.src = e.target.result; - // Once ready, returns its size - // Wait until we have enough data to thumbnail the first frame. - video.onloadeddata = function() { - deferred.resolve(video); + // Once ready, returns its size + // Wait until we have enough data to thumbnail the first frame. + video.onloadeddata = function() { + resolve(video); + }; + video.onerror = function(e) { + reject(e); + }; }; - video.onerror = function(e) { - deferred.reject(e); + reader.onerror = function(e) { + reject(e); }; - }; - reader.onerror = function(e) { - deferred.reject(e); - }; - reader.readAsDataURL(videoFile); - - return deferred.promise; + reader.readAsDataURL(videoFile); + }); } /** @@ -236,16 +233,16 @@ function infoForVideoFile(matrixClient, roomId, videoFile) { * is read. */ function readFileAsArrayBuffer(file) { - const deferred = Promise.defer(); - const reader = new FileReader(); - reader.onload = function(e) { - deferred.resolve(e.target.result); - }; - reader.onerror = function(e) { - deferred.reject(e); - }; - reader.readAsArrayBuffer(file); - return deferred.promise; + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = function(e) { + resolve(e.target.result); + }; + reader.onerror = function(e) { + reject(e); + }; + reader.readAsArrayBuffer(file); + }); } /** @@ -461,33 +458,34 @@ export default class ContentMessages { content.info.mimetype = file.type; } - const def = Promise.defer(); - if (file.type.indexOf('image/') == 0) { - content.msgtype = 'm.image'; - infoForImageFile(matrixClient, roomId, file).then((imageInfo)=>{ - extend(content.info, imageInfo); - def.resolve(); - }, (error)=>{ - console.error(error); + const prom = new Promise((resolve) => { + if (file.type.indexOf('image/') == 0) { + content.msgtype = 'm.image'; + infoForImageFile(matrixClient, roomId, file).then((imageInfo)=>{ + extend(content.info, imageInfo); + resolve(); + }, (error)=>{ + console.error(error); + content.msgtype = 'm.file'; + resolve(); + }); + } else if (file.type.indexOf('audio/') == 0) { + content.msgtype = 'm.audio'; + resolve(); + } else if (file.type.indexOf('video/') == 0) { + content.msgtype = 'm.video'; + infoForVideoFile(matrixClient, roomId, file).then((videoInfo)=>{ + extend(content.info, videoInfo); + resolve(); + }, (error)=>{ + content.msgtype = 'm.file'; + resolve(); + }); + } else { content.msgtype = 'm.file'; - def.resolve(); - }); - } else if (file.type.indexOf('audio/') == 0) { - content.msgtype = 'm.audio'; - def.resolve(); - } else if (file.type.indexOf('video/') == 0) { - content.msgtype = 'm.video'; - infoForVideoFile(matrixClient, roomId, file).then((videoInfo)=>{ - extend(content.info, videoInfo); - def.resolve(); - }, (error)=>{ - content.msgtype = 'm.file'; - def.resolve(); - }); - } else { - content.msgtype = 'm.file'; - def.resolve(); - } + resolve(); + } + }); const upload = { fileName: file.name || 'Attachment', @@ -509,7 +507,7 @@ export default class ContentMessages { dis.dispatch({action: 'upload_progress', upload: upload}); } - return def.promise.then(function() { + return prom.then(function() { // XXX: upload.promise must be the promise that // is returned by uploadFile as it has an abort() // method hacked onto it. diff --git a/src/Lifecycle.js b/src/Lifecycle.js index 13f3abccb1..53a9b7a998 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -312,18 +312,14 @@ async function _restoreFromLocalStorage(opts) { function _handleLoadSessionFailure(e) { console.error("Unable to load session", e); - const def = Promise.defer(); const SessionRestoreErrorDialog = sdk.getComponent('views.dialogs.SessionRestoreErrorDialog'); - Modal.createTrackedDialog('Session Restore Error', '', SessionRestoreErrorDialog, { + const modal = Modal.createTrackedDialog('Session Restore Error', '', SessionRestoreErrorDialog, { error: e.message, - onFinished: (success) => { - def.resolve(success); - }, }); - return def.promise.then((success) => { + return modal.finished.then(([success]) => { if (success) { // user clicked continue. _clearStorage(); diff --git a/src/components/views/rooms/Autocomplete.js b/src/components/views/rooms/Autocomplete.js index ad5fa198a3..d4b51081f4 100644 --- a/src/components/views/rooms/Autocomplete.js +++ b/src/components/views/rooms/Autocomplete.js @@ -26,6 +26,7 @@ import { Room } from 'matrix-js-sdk'; import SettingsStore from "../../../settings/SettingsStore"; import Autocompleter from '../../../autocomplete/Autocompleter'; +import {sleep} from "../../../utils/promise"; const COMPOSER_SELECTED = 0; @@ -105,13 +106,11 @@ export default class Autocomplete extends React.Component { autocompleteDelay = 0; } - const deferred = Promise.defer(); - this.debounceCompletionsRequest = setTimeout(() => { - this.processQuery(query, selection).then(() => { - deferred.resolve(); - }); - }, autocompleteDelay); - return deferred.promise; + return new Promise((resolve) => { + this.debounceCompletionsRequest = setTimeout(() => { + resolve(this.processQuery(query, selection)); + }, autocompleteDelay); + }); } processQuery(query, selection) { @@ -197,16 +196,16 @@ export default class Autocomplete extends React.Component { } forceComplete() { - const done = Promise.defer(); - this.setState({ - forceComplete: true, - hide: false, - }, () => { - this.complete(this.props.query, this.props.selection).then(() => { - done.resolve(this.countCompletions()); + return new Promise((resolve) => { + this.setState({ + forceComplete: true, + hide: false, + }, () => { + this.complete(this.props.query, this.props.selection).then(() => { + resolve(this.countCompletions()); + }); }); }); - return done.promise; } onCompletionClicked(selectionOffset: number): boolean { diff --git a/src/components/views/settings/ChangePassword.js b/src/components/views/settings/ChangePassword.js index a086efaa6d..91292b19f9 100644 --- a/src/components/views/settings/ChangePassword.js +++ b/src/components/views/settings/ChangePassword.js @@ -178,17 +178,12 @@ module.exports = createReactClass({ }, _optionallySetEmail: function() { - const deferred = Promise.defer(); // Ask for an email otherwise the user has no way to reset their password const SetEmailDialog = sdk.getComponent("dialogs.SetEmailDialog"); - Modal.createTrackedDialog('Do you want to set an email address?', '', SetEmailDialog, { + const modal = Modal.createTrackedDialog('Do you want to set an email address?', '', SetEmailDialog, { title: _t('Do you want to set an email address?'), - onFinished: (confirmed) => { - // ignore confirmed, setting an email is optional - deferred.resolve(confirmed); - }, }); - return deferred.promise; + return modal.finished.then(([confirmed]) => confirmed); }, _onExportE2eKeysClicked: function() { diff --git a/src/rageshake/submit-rageshake.js b/src/rageshake/submit-rageshake.js index 99c412a6ab..e772912e48 100644 --- a/src/rageshake/submit-rageshake.js +++ b/src/rageshake/submit-rageshake.js @@ -105,26 +105,22 @@ export default async function sendBugReport(bugReportEndpoint, opts) { } function _submitReport(endpoint, body, progressCallback) { - const deferred = Promise.defer(); - - const req = new XMLHttpRequest(); - req.open("POST", endpoint); - req.timeout = 5 * 60 * 1000; - req.onreadystatechange = function() { - if (req.readyState === XMLHttpRequest.LOADING) { - progressCallback(_t("Waiting for response from server")); - } else if (req.readyState === XMLHttpRequest.DONE) { - on_done(); - } - }; - req.send(body); - return deferred.promise; - - function on_done() { - if (req.status < 200 || req.status >= 400) { - deferred.reject(new Error(`HTTP ${req.status}`)); - return; - } - deferred.resolve(); - } + return new Promise((resolve, reject) => { + const req = new XMLHttpRequest(); + req.open("POST", endpoint); + req.timeout = 5 * 60 * 1000; + req.onreadystatechange = function() { + if (req.readyState === XMLHttpRequest.LOADING) { + progressCallback(_t("Waiting for response from server")); + } else if (req.readyState === XMLHttpRequest.DONE) { + // on done + if (req.status < 200 || req.status >= 400) { + reject(new Error(`HTTP ${req.status}`)); + return; + } + resolve(); + } + }; + req.send(body); + }); } From 2ea239d1923170ef9d226eeae99dcfc12432dc30 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 12 Nov 2019 11:45:28 +0000 Subject: [PATCH 2/7] Replace rest of defer usages using small shim. Add homebrew promise utils (cherry picked from commit 6850c147393ba7be8b98d97dfc8d7244fa503461) --- src/Modal.js | 3 +- src/components/structures/MatrixChat.js | 5 +-- src/utils/MultiInviter.js | 3 +- src/utils/promise.js | 46 +++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 src/utils/promise.js diff --git a/src/Modal.js b/src/Modal.js index 26c9da8bbb..cb19731f01 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -24,6 +24,7 @@ import sdk from './index'; import dis from './dispatcher'; import { _t } from './languageHandler'; import Promise from "bluebird"; +import {defer} from "./utils/promise"; const DIALOG_CONTAINER_ID = "mx_Dialog_Container"; const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer"; @@ -202,7 +203,7 @@ class ModalManager { } _getCloseFn(modal, props) { - const deferred = Promise.defer(); + const deferred = defer(); return [(...args) => { deferred.resolve(args); if (props && props.onFinished) props.onFinished.apply(null, args); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index da67416400..d12eba88f7 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -60,6 +60,7 @@ import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils"; import DMRoomMap from '../../utils/DMRoomMap'; import { countRoomsWithNotif } from '../../RoomNotifs'; import { setTheme } from "../../theme"; +import {defer} from "../../utils/promise"; // Disable warnings for now: we use deprecated bluebird functions // and need to migrate, but they spam the console with warnings. @@ -236,7 +237,7 @@ export default createReactClass({ // Used by _viewRoom before getting state from sync this.firstSyncComplete = false; - this.firstSyncPromise = Promise.defer(); + this.firstSyncPromise = defer(); if (this.props.config.sync_timeline_limit) { MatrixClientPeg.opts.initialSyncLimit = this.props.config.sync_timeline_limit; @@ -1261,7 +1262,7 @@ export default createReactClass({ // since we're about to start the client and therefore about // to do the first sync this.firstSyncComplete = false; - this.firstSyncPromise = Promise.defer(); + this.firstSyncPromise = defer(); const cli = MatrixClientPeg.get(); const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog'); diff --git a/src/utils/MultiInviter.js b/src/utils/MultiInviter.js index e8995b46d7..de5c2e7610 100644 --- a/src/utils/MultiInviter.js +++ b/src/utils/MultiInviter.js @@ -24,6 +24,7 @@ import {_t} from "../languageHandler"; import sdk from "../index"; import Modal from "../Modal"; import SettingsStore from "../settings/SettingsStore"; +import {defer} from "./promise"; /** * Invites multiple addresses to a room or group, handling rate limiting from the server @@ -71,7 +72,7 @@ export default class MultiInviter { }; } } - this.deferred = Promise.defer(); + this.deferred = defer(); this._inviteMore(0); return this.deferred.promise; diff --git a/src/utils/promise.js b/src/utils/promise.js new file mode 100644 index 0000000000..dd10f7fdd7 --- /dev/null +++ b/src/utils/promise.js @@ -0,0 +1,46 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// @flow + +// Returns a promise which resolves with a given value after the given number of ms +export const sleep = (ms: number, value: any): Promise => new Promise((resolve => { setTimeout(resolve, ms, value); })); + +// Returns a promise which resolves when the input promise resolves with its value +// or when the timeout of ms is reached with the value of given timeoutValue +export async function timeout(promise: Promise, timeoutValue: any, ms: number): Promise { + const timeoutPromise = new Promise((resolve) => { + const timeoutId = setTimeout(resolve, ms, timeoutValue); + promise.then(() => { + clearTimeout(timeoutId); + }); + }); + + return Promise.race([promise, timeoutPromise]); +} + +// Returns a Deferred +export function defer(): {resolve: () => {}, reject: () => {}, promise: Promise} { + let resolve; + let reject; + + const promise = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; + }); + + return {resolve, reject, promise}; +} From 2b34cf4362ab03b0409da6086199ef2eab54dee7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 12 Nov 2019 11:46:58 +0000 Subject: [PATCH 3/7] Replace Promise.delay with promise utils sleep (cherry picked from commit 0a21957b2cac0cc2d0169f428187bc2e468251a9) --- src/components/structures/GroupView.js | 9 +++++---- .../views/context_menus/RoomTileContextMenu.js | 7 ++++--- src/components/views/dialogs/AddressPickerDialog.js | 3 ++- .../views/settings/tabs/user/SecurityUserSettingsTab.js | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 4d8f47003c..4056557a7c 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -38,6 +38,7 @@ import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks"; import {Group} from "matrix-js-sdk"; +import {sleep} from "../../utils/promise"; const LONG_DESC_PLACEHOLDER = _td( `

HTML for your community's page

@@ -692,7 +693,7 @@ export default createReactClass({ // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. - await Promise.delay(500); + await sleep(500); GroupStore.acceptGroupInvite(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync @@ -711,7 +712,7 @@ export default createReactClass({ // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. - await Promise.delay(500); + await sleep(500); GroupStore.leaveGroup(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync @@ -735,7 +736,7 @@ export default createReactClass({ // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. - await Promise.delay(500); + await sleep(500); GroupStore.joinGroup(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync @@ -787,7 +788,7 @@ export default createReactClass({ // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. - await Promise.delay(500); + await sleep(500); GroupStore.leaveGroup(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js index 9bb573026f..541daef27f 100644 --- a/src/components/views/context_menus/RoomTileContextMenu.js +++ b/src/components/views/context_menus/RoomTileContextMenu.js @@ -32,6 +32,7 @@ import * as RoomNotifs from '../../../RoomNotifs'; import Modal from '../../../Modal'; import RoomListActions from '../../../actions/RoomListActions'; import RoomViewStore from '../../../stores/RoomViewStore'; +import {sleep} from "../../../utils/promise"; module.exports = createReactClass({ displayName: 'RoomTileContextMenu', @@ -62,7 +63,7 @@ module.exports = createReactClass({ _toggleTag: function(tagNameOn, tagNameOff) { if (!MatrixClientPeg.get().isGuest()) { - Promise.delay(500).then(() => { + sleep(500).then(() => { dis.dispatch(RoomListActions.tagRoom( MatrixClientPeg.get(), this.props.room, @@ -119,7 +120,7 @@ module.exports = createReactClass({ Rooms.guessAndSetDMRoom( this.props.room, newIsDirectMessage, - ).delay(500).finally(() => { + ).then(sleep(500)).finally(() => { // Close the context menu if (this.props.onFinished) { this.props.onFinished(); @@ -193,7 +194,7 @@ module.exports = createReactClass({ RoomNotifs.setRoomNotifsState(roomId, newState).done(() => { // delay slightly so that the user can see their state change // before closing the menu - return Promise.delay(500).then(() => { + return sleep(500).then(() => { if (this._unmounted) return; // Close the context menu if (this.props.onFinished) { diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index fb779fa96f..dc61f23956 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -32,6 +32,7 @@ import * as Email from '../../../email'; import IdentityAuthClient from '../../../IdentityAuthClient'; import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../utils/IdentityServerUtils'; import { abbreviateUrl } from '../../../utils/UrlUtils'; +import {sleep} from "../../../utils/promise"; const TRUNCATE_QUERY_LIST = 40; const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200; @@ -533,7 +534,7 @@ module.exports = createReactClass({ }; // wait a bit to let the user finish typing - await Promise.delay(500); + await sleep(500); if (cancelled) return null; try { diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index e619791b01..222af48fa1 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -25,6 +25,7 @@ import Analytics from "../../../../../Analytics"; import Promise from "bluebird"; import Modal from "../../../../../Modal"; import sdk from "../../../../.."; +import {sleep} from "../../../../../utils/promise"; export class IgnoredUser extends React.Component { static propTypes = { @@ -129,7 +130,7 @@ export default class SecurityUserSettingsTab extends React.Component { if (e.errcode === "M_LIMIT_EXCEEDED") { // Add a delay between each invite change in order to avoid rate // limiting by the server. - await Promise.delay(e.retry_after_ms || 2500); + await sleep(e.retry_after_ms || 2500); // Redo last action i--; From f5d467b3917849cb1f17445b75fe9ea1ba38098e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 12 Nov 2019 12:26:07 +0000 Subject: [PATCH 4/7] delint --- src/components/views/context_menus/RoomTileContextMenu.js | 1 - src/components/views/dialogs/AddressPickerDialog.js | 1 - .../views/settings/tabs/user/SecurityUserSettingsTab.js | 1 - 3 files changed, 3 deletions(-) diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js index 541daef27f..fb056ee47f 100644 --- a/src/components/views/context_menus/RoomTileContextMenu.js +++ b/src/components/views/context_menus/RoomTileContextMenu.js @@ -17,7 +17,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Promise from 'bluebird'; import React from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index dc61f23956..24d8b96e0c 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -25,7 +25,6 @@ import { _t, _td } from '../../../languageHandler'; import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; import dis from '../../../dispatcher'; -import Promise from 'bluebird'; import { addressTypes, getAddressType } from '../../../UserAddress.js'; import GroupStore from '../../../stores/GroupStore'; import * as Email from '../../../email'; diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 222af48fa1..0732bcf926 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -22,7 +22,6 @@ import MatrixClientPeg from "../../../../../MatrixClientPeg"; import * as FormattingUtils from "../../../../../utils/FormattingUtils"; import AccessibleButton from "../../../elements/AccessibleButton"; import Analytics from "../../../../../Analytics"; -import Promise from "bluebird"; import Modal from "../../../../../Modal"; import sdk from "../../../../.."; import {sleep} from "../../../../../utils/promise"; From c3df2f941dccf5e135ac48408fccc25cf3c5da30 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 12 Nov 2019 12:30:05 +0000 Subject: [PATCH 5/7] attach promise utils atop bluebird --- src/utils/promise.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/utils/promise.js b/src/utils/promise.js index dd10f7fdd7..f7a2e7c3e7 100644 --- a/src/utils/promise.js +++ b/src/utils/promise.js @@ -14,6 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +// This is only here to allow access to methods like done for the time being +import Promise from "bluebird"; + // @flow // Returns a promise which resolves with a given value after the given number of ms From bc90789c71b5b6d90e445061b1692269c93dbf3c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 14 Nov 2019 00:39:48 +0000 Subject: [PATCH 6/7] Remove unused promise utils method Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/utils/promise.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/utils/promise.js b/src/utils/promise.js index f7a2e7c3e7..8842bfa1b7 100644 --- a/src/utils/promise.js +++ b/src/utils/promise.js @@ -22,19 +22,6 @@ import Promise from "bluebird"; // Returns a promise which resolves with a given value after the given number of ms export const sleep = (ms: number, value: any): Promise => new Promise((resolve => { setTimeout(resolve, ms, value); })); -// Returns a promise which resolves when the input promise resolves with its value -// or when the timeout of ms is reached with the value of given timeoutValue -export async function timeout(promise: Promise, timeoutValue: any, ms: number): Promise { - const timeoutPromise = new Promise((resolve) => { - const timeoutId = setTimeout(resolve, ms, timeoutValue); - promise.then(() => { - clearTimeout(timeoutId); - }); - }); - - return Promise.race([promise, timeoutPromise]); -} - // Returns a Deferred export function defer(): {resolve: () => {}, reject: () => {}, promise: Promise} { let resolve; From 5c24547ef5215b00333da3e9e7b61a55f222f7f6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 14 Nov 2019 09:37:26 +0000 Subject: [PATCH 7/7] re-add and actually use promise timeout util Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/settings/SetIdServer.js | 12 +++++------- src/utils/promise.js | 13 +++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/components/views/settings/SetIdServer.js b/src/components/views/settings/SetIdServer.js index 126cdc9557..a7a2e01c22 100644 --- a/src/components/views/settings/SetIdServer.js +++ b/src/components/views/settings/SetIdServer.js @@ -26,6 +26,7 @@ import { getThreepidsWithBindStatus } from '../../../boundThreepids'; import IdentityAuthClient from "../../../IdentityAuthClient"; import {abbreviateUrl, unabbreviateUrl} from "../../../utils/UrlUtils"; import { getDefaultIdentityServerUrl, doesIdentityServerHaveTerms } from '../../../utils/IdentityServerUtils'; +import {timeout} from "../../../utils/promise"; // We'll wait up to this long when checking for 3PID bindings on the IS. const REACHABILITY_TIMEOUT = 10000; // ms @@ -245,14 +246,11 @@ export default class SetIdServer extends React.Component { let threepids = []; let currentServerReachable = true; try { - threepids = await Promise.race([ + threepids = await timeout( getThreepidsWithBindStatus(MatrixClientPeg.get()), - new Promise((resolve, reject) => { - setTimeout(() => { - reject(new Error("Timeout attempting to reach identity server")); - }, REACHABILITY_TIMEOUT); - }), - ]); + Promise.reject(new Error("Timeout attempting to reach identity server")), + REACHABILITY_TIMEOUT, + ); } catch (e) { currentServerReachable = false; console.warn( diff --git a/src/utils/promise.js b/src/utils/promise.js index 8842bfa1b7..f7a2e7c3e7 100644 --- a/src/utils/promise.js +++ b/src/utils/promise.js @@ -22,6 +22,19 @@ import Promise from "bluebird"; // Returns a promise which resolves with a given value after the given number of ms export const sleep = (ms: number, value: any): Promise => new Promise((resolve => { setTimeout(resolve, ms, value); })); +// Returns a promise which resolves when the input promise resolves with its value +// or when the timeout of ms is reached with the value of given timeoutValue +export async function timeout(promise: Promise, timeoutValue: any, ms: number): Promise { + const timeoutPromise = new Promise((resolve) => { + const timeoutId = setTimeout(resolve, ms, timeoutValue); + promise.then(() => { + clearTimeout(timeoutId); + }); + }); + + return Promise.race([promise, timeoutPromise]); +} + // Returns a Deferred export function defer(): {resolve: () => {}, reject: () => {}, promise: Promise} { let resolve;