Compare commits

...

6 Commits

Author SHA1 Message Date
Florian Rival
0a35bc3272 Bump newIDE version 2018-01-22 23:35:55 +01:00
Florian Rival
d8b737a31f Fix LocalS3Export always reusing the same folder leading to useless files in exported game 2018-01-22 23:35:32 +01:00
Florian Rival
cfd2655f6c Bump newIDE version 2018-01-22 23:29:21 +01:00
Florian Rival
1896241b9d Move AWS S3 credentials to an .env file for games deployment on GDevelop hosting 2018-01-22 23:25:42 +01:00
Florian Rival
0ed22a6ee1 Fix upload to GDevelop hosting of exported games with large files 2018-01-22 22:52:44 +01:00
Florian Rival
2bfcb99c3e Add analytics when a signup is done 2018-01-22 00:20:32 +01:00
17 changed files with 2949 additions and 202 deletions

View File

@@ -1,4 +1,4 @@
# Rename this file as .env.local and complete the following values.
# Copy this file as ".env.local" and complete the following values.
# If values are not completed, some features will be unavailable.
REACT_APP_PREVIEW_S3_ACCESS_KEY_ID=

View File

@@ -5,6 +5,7 @@ import BrowserPreviewLinkDialog from './BrowserPreviewLinkDialog';
import { findGDJS } from './BrowserS3GDJSFinder';
import assignIn from 'lodash/assignIn';
import { GDevelopGamesPreview } from '../../Utils/GDevelopServices/ApiConfigs';
import { makeTimestampedId } from '../../Utils/TimestampedId';
const awsS3 = require('aws-sdk/clients/s3');
const gd = global.gd;
@@ -41,8 +42,7 @@ export default class BrowserS3PreviewLauncher {
}
console.info('GDJS found in ', gdjsRoot);
const prefix =
'' + Date.now() + '-' + Math.floor(Math.random() * 1000000);
const prefix = makeTimestampedId();
const outputDir = destinationBucketBaseUrl + prefix;
const browserS3FileSystem = new BrowserS3FileSystem({

View File

@@ -8,6 +8,7 @@ import optionalRequire from '../../Utils/OptionalRequire';
import { Column, Line, Spacer } from '../../UI/Grid';
import LinearProgress from 'material-ui/LinearProgress';
import { GDevelopHostingApi } from '../../Utils/GDevelopServices/ApiConfigs';
import { makeTimestampedId } from '../../Utils/TimestampedId';
import TextField from 'material-ui/TextField';
const os = optionalRequire('os');
const electron = optionalRequire('electron');
@@ -31,11 +32,13 @@ export default class LocalS3Export extends Component {
ipcRenderer.removeAllListeners('s3-folder-upload-done');
return new Promise((resolve, reject) => {
ipcRenderer.on('s3-folder-upload-progress', (event, uploadProgress, uploadMax) =>
this.setState({
uploadProgress,
uploadMax,
})
ipcRenderer.on(
's3-folder-upload-progress',
(event, uploadProgress, uploadMax) =>
this.setState({
uploadProgress,
uploadMax,
})
);
ipcRenderer.on('s3-folder-upload-done', (event, err, prefix) => {
if (err) return reject(err);
@@ -51,7 +54,8 @@ export default class LocalS3Export extends Component {
_deploy = prefix => {
return sleep(200)
.then(() => //TODO: Move this to a GDevelopServices/Hosting.js file
.then(() =>
//TODO: Move this to a GDevelopServices/Hosting.js file
axios(GDevelopHostingApi.deployEndpoint, {
method: 'post',
params: {
@@ -79,7 +83,7 @@ export default class LocalS3Export extends Component {
deployDone: false,
});
const outputDir = os.tmpdir() + '/GDS3Export';
const outputDir = os.tmpdir() + '/GDS3Export-' + makeTimestampedId();
LocalExport.prepareExporter()
.then(({ exporter }) => {
const exportForCordova = false;

View File

@@ -17,6 +17,7 @@ import Authentification, {
import LoginDialog from './LoginDialog';
import { watchPromiseInState } from '../Utils/WatchPromiseInState';
import { showWarningBox } from '../UI/Messages/MessageBox';
import { sendSignupDone } from '../Utils/Analytics/EventSender';
type Props = {
open: boolean,
@@ -181,6 +182,7 @@ export const withUserProfile = (
() => {
this._fetchUserProfile();
this.openLogin(false);
sendSignupDone(form.email);
},
(loginError: LoginError) => {
this.setState({

View File

@@ -117,3 +117,11 @@ export const sendErrorMessage = (errorMessage, type, rawError) => {
rawError,
});
};
export const sendSignupDone = email => {
if (isDev) return;
client.recordEvent('signup', {
email,
});
};

View File

@@ -0,0 +1,4 @@
// @flow
export const makeTimestampedId = () =>
'' + Date.now() + '-' + Math.floor(Math.random() * 1000000);

View File

@@ -0,0 +1,5 @@
# Copy this file as ".env" and complete the following values.
# If values are not completed, some features will be unavailable.
UPLOAD_S3_ACCESS_KEY_ID=
UPLOAD_S3_SECRET_ACCESS_KEY=

View File

@@ -1,2 +1,3 @@
dist/
app/www/
.env

View File

@@ -0,0 +1,119 @@
const fs = require('fs');
const path = require('path');
const async = require('async');
const awsS3 = require('aws-sdk/clients/s3');
const { makeTimestampedId } = require('./Utils/TimestampedId');
const recursive = require('recursive-readdir');
const accessKeyId = process.env.UPLOAD_S3_ACCESS_KEY_ID;
const secretAccessKey = process.env.UPLOAD_S3_SECRET_ACCESS_KEY;
const destinationBucket = `gd-games-in`;
const region = 'eu-west-1';
const mime = {
'.js': 'text/javascript',
'.html': 'text/html',
};
if (!accessKeyId || !secretAccessKey) {
console.warn(
"⚠️ Either UPLOAD_S3_ACCESS_KEY_ID or UPLOAD_S3_SECRET_ACCESS_KEY are not defined. Upload won't be working."
);
console.info(
' Copy .env.dist file to .env and fill the values to fix this warning.'
);
}
module.exports = {
/**
* Upload the specified directory to GDevelop
* Amazon S3 inbound bucket.
*/
uploadGameFolderToBucket: (localDir, onProgress, onDone) => {
if (!accessKeyId || !secretAccessKey) {
onDone('Missing S3 configuration');
return;
}
const awsS3Client = new awsS3({
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
region: region,
correctClockSkew: true,
});
const prefix = 'game-' + makeTimestampedId();
recursive(localDir)
.then(allFiles => {
const updateProgress = (fileIndex, loaded, total) => {
onProgress(fileIndex + (total ? loaded / total : 0), allFiles.length);
};
async.series(
allFiles.map((localFile, fileIndex) => callback => {
const body = fs.createReadStream(localFile);
const filename = path.relative(localDir, localFile);
const fileExtension = path.extname(filename);
awsS3Client
.upload({
Body: body,
Bucket: destinationBucket,
Key: prefix + '/' + filename,
ContentType: mime[fileExtension],
})
.on('httpUploadProgress', function(progress) {
updateProgress(fileIndex, progress.loaded, progress.total || 0);
})
.send(function(err, data) {
callback(err, prefix + '/' + filename);
});
}),
(err, results) => {
if (err) {
onDone(err);
}
onDone(null, prefix);
}
);
})
.catch(err => {
console.error('Unable to recursively read directory ' + localDir);
onDone(err);
});
},
/**
* Upload the specified file to GDevelop
* Amazon S3 inbound bucket.
*/
uploadArchiveToBucket: (localFile, onProgress, onDone) => {
if (!accessKeyId || !secretAccessKey) {
onDone('Missing S3 configuration');
return;
}
const awsS3Client = new awsS3({
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
region: region,
correctClockSkew: true,
});
const prefix = 'game-archive-' + makeTimestampedId();
const filename = 'game-archive.zip';
const body = fs.createReadStream(localFile);
awsS3Client
.upload({
Body: body,
Bucket: destinationBucket,
Key: prefix + '/' + filename,
})
.on('httpUploadProgress', function(progress) {
onProgress(progress.loaded, progress.total || 0);
})
.send(function(err, data) {
onDone(err, prefix + '/' + filename);
});
},
};

View File

@@ -0,0 +1,8 @@
// @flow
const makeTimestampedId = () =>
'' + Date.now() + '-' + Math.floor(Math.random() * 1000000);
module.exports = {
makeTimestampedId,
};

View File

@@ -1,3 +1,4 @@
require('dotenv').config();
const electron = require('electron');
const app = electron.app; // Module to control application life.
const BrowserWindow = electron.BrowserWindow; // Module to create native browser window.
@@ -10,8 +11,8 @@ const log = require('electron-log');
const {
uploadGameFolderToBucket,
uploadArchiveToBucket,
} = require('./s3upload');
const { buildMainMenuFor } = require('./main-menu');
} = require('./S3Upload');
const { buildMainMenuFor } = require('./MainMenu');
const throttle = require('lodash.throttle');
// Logs made with electron-logs can be found
@@ -102,9 +103,9 @@ app.on('ready', function() {
uploadGameFolderToBucket(
localDir,
(current, max) => {
throttle((current, max) => {
event.sender.send('s3-folder-upload-progress', current, max);
},
}, 200),
(err, prefix) => {
event.sender.send('s3-folder-upload-done', err, prefix);
}

View File

@@ -1,6 +1,6 @@
{
"name": "gdevelop-electron-app",
"version": "5.0.0-beta13",
"name": "gdevelop",
"version": "5.0.0-beta19",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -287,19 +287,6 @@
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"requires": {
"pend": "1.2.0"
}
},
"findit2": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz",
"integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY="
},
"fs-extra": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz",
@@ -469,11 +456,6 @@
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"mime": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -487,31 +469,11 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"natives": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/natives/-/natives-1.1.1.tgz",
"integrity": "sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA=="
},
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@@ -533,11 +495,6 @@
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
@@ -567,16 +524,29 @@
"util-deprecate": "1.0.2"
}
},
"recursive-readdir": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.1.tgz",
"integrity": "sha1-kO8jHQd4xc4JPJpI105cVCLROpk=",
"requires": {
"minimatch": "3.0.3"
},
"dependencies": {
"minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
"requires": {
"brace-expansion": "1.1.8"
}
}
}
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
},
"rimraf": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
"integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI="
},
"ripemd160": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
@@ -586,59 +556,6 @@
"inherits": "2.0.3"
}
},
"s3": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/s3/-/s3-4.4.0.tgz",
"integrity": "sha1-VqT3dVFae2ucjlxrGrUfkDdmnx8=",
"requires": {
"aws-sdk": "2.0.31",
"fd-slicer": "1.0.1",
"findit2": "2.2.3",
"graceful-fs": "3.0.11",
"mime": "1.2.11",
"mkdirp": "0.5.1",
"pend": "1.2.0",
"rimraf": "2.2.8",
"streamsink": "1.2.0"
},
"dependencies": {
"aws-sdk": {
"version": "2.0.31",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.0.31.tgz",
"integrity": "sha1-5yzx/caQFb2f0r3z07iMFlB9Jo4=",
"requires": {
"xml2js": "0.2.6",
"xmlbuilder": "0.4.2"
}
},
"graceful-fs": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz",
"integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
"requires": {
"natives": "1.1.1"
}
},
"sax": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/sax/-/sax-0.4.2.tgz",
"integrity": "sha1-OfO2AXM9a+yXEFskKipA/Wl4rDw="
},
"xml2js": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.6.tgz",
"integrity": "sha1-0gnE5N2h/JxFIUHvQcB39a399sQ=",
"requires": {
"sax": "0.4.2"
}
},
"xmlbuilder": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz",
"integrity": "sha1-F3bWXz/brUcKCNhgTN6xxOVA/4M="
}
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
@@ -681,11 +598,6 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"streamsink": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/streamsink/-/streamsink-1.2.0.tgz",
"integrity": "sha1-76/unx4i01ke1949yqlcP1559zw="
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",

View File

@@ -2,13 +2,14 @@
"name": "gdevelop",
"productName": "GDevelop 5",
"description": "GDevelop 5 IDE running on the Electron runtime",
"version": "5.0.0-beta19",
"version": "5.0.0-beta21",
"author": "Florian Rival",
"license": "MIT",
"homepage": "http://compilgames.net",
"main": "main.js",
"dependencies": {
"archiver": "^2.1.1",
"async": "^2.6.0",
"aws-sdk": "^2.58.0",
"electron-editor-context-menu": "^1.1.1",
"electron-is": "^2.4.0",
@@ -17,6 +18,6 @@
"fs-extra": "^3.0.1",
"lodash.throttle": "^4.1.1",
"minimist": "^1.2.0",
"s3": "^4.4.0"
"recursive-readdir": "^2.2.1"
}
}

View File

@@ -1,77 +0,0 @@
const fs = require('fs');
const s3 = require('s3');
const awsS3 = require('aws-sdk/clients/s3');
const destinationBucket = `gd-games-in`;
const accessKeyId = 'AKIAJPLGZ22GBISUYFJQ';
const secretAccessKey = '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';
const region = 'eu-west-1';
module.exports = {
/**
* Upload the specified directory to GDevelop
* Amazon S3 inbound bucket.
*/
uploadGameFolderToBucket: (localDir, onProgress, onDone) => {
const awsS3Client = new awsS3({
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
region: region,
correctClockSkew: true,
});
// TODO: Switch to a more robust module for uploading files
const s3Client = s3.createClient({
s3Client: awsS3Client,
});
const timestamp = '' + Date.now();
const prefix = 'game-' + timestamp;
var uploader = s3Client.uploadDir({
localDir,
s3Params: {
Bucket: destinationBucket,
Prefix: prefix + '/',
},
});
uploader.on('error', onDone);
uploader.on('progress', function() {
onProgress(uploader.progressAmount, uploader.progressTotal);
});
uploader.on('end', function() {
onDone(null, prefix);
});
},
/**
* Upload the specified file to GDevelop
* Amazon S3 inbound bucket.
*/
uploadArchiveToBucket: (localFile, onProgress, onDone) => {
const awsS3Client = new awsS3({
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
region: region,
correctClockSkew: true,
});
const timestamp = '' + Date.now();
const prefix = 'game-archive-' + timestamp;
const filename = 'game-archive.zip';
var body = fs.createReadStream(localFile);
awsS3Client
.upload({
Body: body,
Bucket: destinationBucket,
Key: prefix + '/' + filename,
})
.on('httpUploadProgress', function(progress) {
onProgress(progress.loaded, progress.total || 0);
})
.send(function(err, data) {
onDone(err, prefix + '/' + filename);
});
},
};

2754
newIDE/electron-app/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,11 @@
"mac": {
"category": "public.app-category.developer-tools"
},
"publish": [{"provider": "github"}]
"publish": [
{
"provider": "github"
}
]
},
"devDependencies": {
"electron": "1.7.9",
@@ -37,6 +41,7 @@
"shelljs": "^0.7.7"
},
"dependencies": {
"dotenv": "^4.0.0",
"electron-is": "^2.4.0"
}
}