Merge pull request #3564 from LLK/hotfix/project-creation-replication-lag

[Master] Work around replication lag problems on project creation
This commit is contained in:
Ray Schamp 2019-11-22 14:53:09 -05:00 committed by GitHub
commit 73cfd78b12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 3 deletions

25
package-lock.json generated
View file

@ -12032,6 +12032,24 @@
"prepend-http": "^1.0.0",
"query-string": "^4.1.0",
"sort-keys": "^1.0.0"
},
"dependencies": {
"query-string": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
"dev": true,
"requires": {
"object-assign": "^4.1.0",
"strict-uri-encode": "^1.0.0"
}
},
"strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
"dev": true
}
}
},
"npm-run-path": {
@ -13907,11 +13925,12 @@
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"query-string": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
"dev": true,
"requires": {
"decode-uri-component": "^0.2.0",
"object-assign": "^4.1.0",
"strict-uri-encode": "^1.0.0"
}

View file

@ -112,6 +112,7 @@
"po2icu": "0.0.2",
"postcss-loader": "2.0.10",
"prop-types": "15.6.0",
"query-string": "^5.1.1",
"react": "16.2.0",
"react-dom": "16.2.0",
"react-intl": "2.8.0",

View file

@ -111,6 +111,7 @@ const PreviewPresentation = ({
onSocialClosed,
onToggleComments,
onToggleStudio,
onUpdateProjectData,
onUpdateProjectId,
onUpdateProjectThumbnail,
originalInfo,
@ -345,6 +346,7 @@ const PreviewPresentation = ({
onProjectLoaded={onProjectLoaded}
onRemixing={onRemixing}
onSetProjectThumbnailer={onSetProjectThumbnailer}
onUpdateProjectData={onUpdateProjectData}
onUpdateProjectId={onUpdateProjectId}
onUpdateProjectThumbnail={onUpdateProjectThumbnail}
/>
@ -725,6 +727,7 @@ PreviewPresentation.propTypes = {
onSocialClosed: PropTypes.func,
onToggleComments: PropTypes.func,
onToggleStudio: PropTypes.func,
onUpdateProjectData: PropTypes.func,
onUpdateProjectId: PropTypes.func,
onUpdateProjectThumbnail: PropTypes.func,
originalInfo: projectShape,

View file

@ -8,7 +8,9 @@ const PropTypes = require('prop-types');
const connect = require('react-redux').connect;
const injectIntl = require('react-intl').injectIntl;
const parser = require('scratch-parser');
const queryString = require('query-string');
const api = require('../../lib/api');
const Page = require('../../components/page/www/page.jsx');
const storage = require('../../lib/storage.js').default;
const log = require('../../lib/log');
@ -36,6 +38,7 @@ const IntlGUI = injectIntl(GUI.default);
const localStorageAvailable = 'localStorage' in window && window.localStorage !== null;
const initSentry = require('../../lib/sentry.js');
const xhr = require('xhr');
initSentry();
class Preview extends React.Component {
@ -73,6 +76,7 @@ class Preview extends React.Component {
'handleSeeInside',
'handleSetProjectThumbnailer',
'handleShare',
'handleUpdateProjectData',
'handleUpdateProjectId',
'handleUpdateProjectTitle',
'handleToggleComments',
@ -219,6 +223,84 @@ class Preview extends React.Component {
this.props.getRemixes(this.state.projectId);
}
}
// This is copy of what is in save-project-to-server in GUI that adds
// an extra get of the project info from api. We do this to wait for replication
// lag to pass. This is intended to be a temporary fix until we use the data
// from the create request to fill the projectInfo state.
handleUpdateProjectData (projectId, vmState, params) {
const opts = {
body: vmState,
// If we set json:true then the body is double-stringified, so don't
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
};
const creatingProject = projectId === null || typeof projectId === 'undefined';
const queryParams = {};
if (params.hasOwnProperty('originalId')) queryParams.original_id = params.originalId;
if (params.hasOwnProperty('isCopy')) queryParams.is_copy = params.isCopy;
if (params.hasOwnProperty('isRemix')) queryParams.is_remix = params.isRemix;
if (params.hasOwnProperty('title')) queryParams.title = params.title;
let qs = queryString.stringify(queryParams);
if (qs) qs = `?${qs}`;
if (creatingProject) {
Object.assign(opts, {
method: 'post',
url: `${this.props.projectHost}/${qs}`
});
} else {
Object.assign(opts, {
method: 'put',
url: `${this.props.projectHost}/${projectId}${qs}`
});
}
return new Promise((resolve, reject) => {
xhr(opts, (err, response) => {
if (err) return reject(err);
if (response.statusCode !== 200) return reject(response.statusCode);
let body;
try {
// Since we didn't set json: true, we have to parse manually
body = JSON.parse(response.body);
} catch (e) {
return reject(e);
}
body.id = projectId;
if (creatingProject) {
body.id = body['content-name'];
}
resolve(body);
});
}).then(body => {
const fetchProjectInfo = (count, resolve) => {
api({
uri: `/projects/${body.id}`,
authentication: this.props.user.token
}, (err, projectInfo, response) => {
if (err) {
log.error(`Could not fetch project after creating: ${err}`);
return resolve(body);
}
if (typeof body === 'undefined' || response.statusCode === 404) {
// Retry after 500ms, 1.5s, 3.5s, 7.5s and then stop.
if (count > 4) {
return resolve(body);
}
return setTimeout(
fetchProjectInfo.bind(this, count + 1, resolve),
500 * Math.pow(2, count));
}
return resolve(body);
});
};
if (creatingProject) {
return new Promise((resolve, reject) => fetchProjectInfo(1, resolve, reject));
}
return body;
});
}
setScreenFromOrientation () {
/*
* If the user is on a mobile device, switching to
@ -702,6 +784,7 @@ class Preview extends React.Component {
onSocialClosed={this.handleSocialClose}
onToggleComments={this.handleToggleComments}
onToggleStudio={this.handleToggleStudio}
onUpdateProjectData={this.handleUpdateProjectData}
onUpdateProjectId={this.handleUpdateProjectId}
onUpdateProjectThumbnail={this.props.handleUpdateProjectThumbnail}
/>
@ -739,6 +822,7 @@ class Preview extends React.Component {
onSetLanguage={this.handleSetLanguage}
onShare={this.handleShare}
onToggleLoginOpen={this.props.handleToggleLoginOpen}
onUpdateProjectData={this.handleUpdateProjectData}
onUpdateProjectId={this.handleUpdateProjectId}
onUpdateProjectThumbnail={this.props.handleUpdateProjectThumbnail}
onUpdateProjectTitle={this.handleUpdateProjectTitle}