Merge pull request #3539 from kchadha/cloud-connect

Cloud Data Provider
This commit is contained in:
Karishma Chadha authored and GitHub committed 2018-10-30 14:06:46 -04:00
commit a00a529858
5 files changed
+152 -2

No files matched your search

+1 -1
View File
@@ -105,7 +105,7 @@
"scratch-render": "0.1.0-prerelease.20181029125804",
"scratch-storage": "1.1.0",
"scratch-svg-renderer": "0.2.0-prerelease.20181024192149",
"scratch-vm": "0.2.0-prerelease.20181025092837",
"scratch-vm": "0.2.0-prerelease.20181030160328",
"selenium-webdriver": "3.6.0",
"startaudiocontext": "1.2.1",
"style-loader": "^0.23.0",
+2
View File
@@ -73,6 +73,7 @@ class GUI extends React.Component {
const {
/* eslint-disable no-unused-vars */
assetHost,
cloudHost,
error,
hideIntro,
isError,
@@ -104,6 +105,7 @@ class GUI extends React.Component {
GUI.propTypes = {
assetHost: PropTypes.string,
children: PropTypes.node,
cloudHost: PropTypes.string,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
fetchingProject: PropTypes.bool,
hideIntro: PropTypes.bool,
+132
View File
@@ -0,0 +1,132 @@
import log from './log.js';
class CloudProvider {
/**
* A cloud data provider which creates and manages a web socket connection
* to the Scratch cloud data server. This provider is responsible for
* interfacing with the VM's cloud io device.
* @param {string} cloudHost The url for the cloud data server
* @param {VirtualMachine} vm The Scratch virtual machine to interface with
* @param {string} username The username to associate cloud data updates with
* @param {string} projectId The id associated with the project containing
* cloud data.
*/
constructor (cloudHost, vm, username, projectId) {
this.vm = vm;
this.username = username;
this.projectId = projectId;
// Open a websocket connection to the clouddata server
this.openConnection(cloudHost);
}
/**
* Open a new websocket connection to the clouddata server.
* @param {string} cloudHost The cloud data server to connect to.
*/
openConnection (cloudHost) {
if (window.WebSocket === null) {
log.warn('Websocket support is not available in this browser');
this.connection = null;
return;
}
this.connection = new WebSocket((location.protocol === 'http:' ? 'ws://' : 'wss://') + cloudHost);
this.connection.onerror = e => {
log.error(`Websocket connection error: ${JSON.stringify(e)}`);
// TODO Add re-connection attempt logic here
};
this.connection.onmessage = event => {
const messageString = event.data;
log.info(`Received websocket message: ${messageString}`);
const message = JSON.parse(messageString);
if (message.method === 'set') {
const varData = {
varUpdate: {
name: message.name,
value: message.value
}
};
this.vm.postIOData('cloud', varData);
}
};
this.connection.onopen = () => {
this.writeToServer('handshake');
log.info(`Successfully connected to clouddata server.`);
};
this.connection.onclose = () => {
log.info(`Closed connection to websocket`);
};
}
/**
* Format and send a message to the cloud data server.
* @param {string} methodName The message method, indicating the action to perform.
* @param {string} dataName The name of the cloud variable this message pertains to
* @param {string | number} dataValue The value to set the cloud variable to
* @param {number} dataIndex The index of the item to update (for cloud lists)
* @param {string} dataNewName The new name for the cloud variable (if renaming)
*/
writeToServer (methodName, dataName, dataValue, dataIndex, dataNewName) {
const msg = {};
msg.method = methodName;
msg.user = this.username;
msg.project_id = this.projectId;
if (dataName) msg.name = dataName;
if (dataValue) msg.value = dataValue;
if (dataIndex) msg.index = dataIndex;
if (dataNewName) msg.new_name = dataNewName;
const dataToWrite = JSON.stringify(msg);
this.sendCloudData(dataToWrite);
}
/**
* Send a formatted message to the cloud data server.
* @param {string} data The formatted message to send.
*/
sendCloudData (data) {
this.connection.send(`${data}\n`);
log.info(`Sent message to clouddata server: ${data}`);
}
/**
* Provides an API for the VM's cloud IO device to update
* a cloud variable on the server.
* @param {string} name The name of the variable to update
* @param {string | number} value The new value for the variable
*/
updateVariable (name, value) {
this.writeToServer('set', name, value);
}
/**
* Closes the connection to the web socket and clears the cloud
* provider of references related to the cloud data project.
*/
requestCloseConnection () {
this.connection.close();
this.clear();
}
/**
* Clear this provider of references related to the project
* and current state.
*/
clear () {
this.connection = null;
this.vm = null;
this.username = null;
this.projectId = null;
}
}
export default CloudProvider;
-1
View File
@@ -102,7 +102,6 @@ const vmListenerHOC = function (WrappedComponent) {
/* eslint-disable no-unused-vars */
attachKeyboardEvents,
shouldEmitTargetsUpdate,
username,
onBlockDragUpdate,
onKeyDown,
onKeyUp,
+17
View File
@@ -5,6 +5,7 @@ import {connect} from 'react-redux';
import VM from 'scratch-vm';
import AudioEngine from 'scratch-audio';
import CloudProvider from '../lib/cloud-provider';
import {
LoadingStates,
@@ -46,6 +47,18 @@ const vmManagerHOC = function (WrappedComponent) {
return this.props.vm.loadProject(this.props.projectData)
.then(() => {
this.props.onLoadedProject(this.props.loadingState, this.props.canSave);
// If the cloud host exists, open a cloud connection and
// set the vm's cloud provider.
if (this.props.cloudHost) {
// TODO check if we should actually
// connect to cloud data based on info from the loaded project and
// info about the user (e.g. scratcher status)
this.props.vm.setCloudProvider(new CloudProvider(
this.props.cloudHost,
this.props.vm,
this.props.username,
this.props.projectId));
}
})
.catch(e => {
this.props.onError(e);
@@ -54,12 +67,14 @@ const vmManagerHOC = function (WrappedComponent) {
render () {
const {
/* eslint-disable no-unused-vars */
cloudHost,
fontsLoaded,
loadingState,
onError: onErrorProp,
onLoadedProject: onLoadedProjectProp,
projectData,
projectId,
username,
/* eslint-enable no-unused-vars */
isLoadingWithId: isLoadingWithIdProp,
vm,
@@ -77,6 +92,7 @@ const vmManagerHOC = function (WrappedComponent) {
VMManager.propTypes = {
canSave: PropTypes.bool,
cloudHost: PropTypes.string,
fontsLoaded: PropTypes.bool,
isLoadingWithId: PropTypes.bool,
loadingState: PropTypes.oneOf(LoadingStates),
@@ -84,6 +100,7 @@ const vmManagerHOC = function (WrappedComponent) {
onLoadedProject: PropTypes.func,
projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
username: PropTypes.string,
vm: PropTypes.instanceOf(VM).isRequired
};