云变量接口

This commit is contained in:
chengyu 2023-10-09 15:52:31 +08:00
parent 8deb5b52f2
commit 80532795cd
12 changed files with 160 additions and 39 deletions

View File

@ -70,6 +70,16 @@ window.scratchConfig = {
enable: true, // enable backpack
api: "/api/teaching/scratch/backpack", //backpack API
},
cloudData:{
enable: true, //enable cloud data
id: "create", //default cloud data ID
api: "127.0.0.1:1234/api/websocket/scratch/cloudData" //cloud data API
},
projectInfo: {//project info
projectName: "",
authorUsername: "admin",
authorAvatar: './static/avatar.png',
},
logo: {
show: true, //is visible
url: "./static/logo.png", //logo url, support base64 images
@ -349,6 +359,9 @@ window.scratch.pushSoundLibrary(
)
```
#### set cloud data ID
`window.scratch.setCloudId(id)`
# Appendix
## block catagory code

View File

@ -78,6 +78,16 @@ https://www.213.name/archives/1739
enable: true, // 是否启用背包
api: "/api/teaching/scratch/backpack", //背包API接口
},
cloudData:{
enable: true, //是否开启云变量功能
id: "create", //默认云变量ID可使用window.scratch.setCloudId更换ID
api: "127.0.0.1:1234/api/websocket/scratch/cloudData" //云变量API地址
},
projectInfo: {//作品信息
projectName: "",
authorUsername: "admin",
authorAvatar: './static/avatar.png',
},
logo: {
show: true, //是否显示
url: "./static/logo.png", //logo地址支持base64图片
@ -367,6 +377,9 @@ window.scratch.pushSoundsLibrary(
)
```
#### 设置云变量ID
`window.scratch.setCloudId(id)`
# 附录
## Scratch项目结构

View File

@ -74,7 +74,6 @@ const GUIComponent = props => {
canSave,
canCreateCopy,
canShare,
canUseCloud,
children,
connectionModalVisible,
costumeLibraryVisible,
@ -300,7 +299,6 @@ const GUIComponent = props => {
<TabPanel className={tabClassNames.tabPanel}>
<Box className={styles.blocksWrapper}>
<Blocks
canUseCloud={canUseCloud}
grow={1}
isVisible={blocksTabVisible}
options={{
@ -381,7 +379,6 @@ GUIComponent.propTypes = {
canRemix: PropTypes.bool,
canSave: PropTypes.bool,
canShare: PropTypes.bool,
canUseCloud: PropTypes.bool,
cardsVisible: PropTypes.bool,
children: PropTypes.node,
costumeLibraryVisible: PropTypes.bool,
@ -437,7 +434,6 @@ GUIComponent.defaultProps = {
canSave: false,
canCreateCopy: false,
canShare: false,
canUseCloud: false,
enableCommunity: false,
isCreating: false,
isShared: false,

View File

@ -822,8 +822,8 @@ const mapStateToProps = (state, ownProps) => {
loginMenuOpen: loginMenuOpen(state),
projectTitle: state.scratchGui.projectTitle,
sessionExists: state.session && typeof state.session.session !== 'undefined',
username: window.scratchConfig.menuBar.userAvatar.username || '',
avatar: window.scratchConfig.menuBar.userAvatar.avatar || null,
username: window.scratchConfig.session.username || '',
avatar: window.scratchConfig.session.avatar || null,
onAvatarClick: window.scratchConfig.menuBar.userAvatar.handleClick,
userOwnsProject: ownProps.authorUsername && user &&
(ownProps.authorUsername === user.username),

View File

@ -38,6 +38,7 @@ const PromptComponent = props => (
className={styles.modalContent}
contentLabel={props.title}
onRequestClose={props.onCancel}
id={"cloudData"}
>
<Box className={styles.body}>
<Box className={styles.label}>

View File

@ -465,7 +465,7 @@ class Blocks extends React.Component {
optVarType !== this.ScratchBlocks.BROADCAST_MESSAGE_VARIABLE_TYPE &&
p.prompt.title !== this.ScratchBlocks.Msg.RENAME_VARIABLE_MODAL_TITLE &&
p.prompt.title !== this.ScratchBlocks.Msg.RENAME_LIST_MODAL_TITLE;
p.prompt.showCloudOption = (optVarType === this.ScratchBlocks.SCALAR_VARIABLE_TYPE) && this.props.canUseCloud;
p.prompt.showCloudOption = (optVarType === this.ScratchBlocks.SCALAR_VARIABLE_TYPE) && window.scratchConfig.cloudData.enable;
this.setState(p);
}
handleConnectionModalStart (extensionId) {
@ -512,7 +512,6 @@ class Blocks extends React.Component {
/* eslint-disable no-unused-vars */
const {
anyModalVisible,
canUseCloud,
customProceduresVisible,
extensionLibraryVisible,
options,
@ -575,7 +574,6 @@ class Blocks extends React.Component {
Blocks.propTypes = {
anyModalVisible: PropTypes.bool,
canUseCloud: PropTypes.bool,
customProceduresVisible: PropTypes.bool,
extensionLibraryVisible: PropTypes.bool,
isRtl: PropTypes.bool,

View File

@ -164,6 +164,7 @@ class GUI extends React.Component {
/* eslint-disable no-unused-vars */
assetHost,
cloudHost,
cloudId,
error,
isError,
isScratchDesktop,
@ -196,6 +197,7 @@ GUI.propTypes = {
assetHost: PropTypes.string,
children: PropTypes.node,
cloudHost: PropTypes.string,
cloudId: PropTypes.string,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
fetchingProject: PropTypes.bool,
intl: intlShape,

View File

@ -179,19 +179,20 @@ const alerts = [
description="Info about cloud variable limitations"
id="gui.alerts.cloudInfo"
values={{
learnMoreLink: (
<a
href="https://scratch.mit.edu/info/faq/#clouddata"
rel="noopener noreferrer"
target="_blank"
>
<FormattedMessage
defaultMessage="Learn more."
description="Link text to cloud var faq"
id="gui.alerts.cloudInfoLearnMore"
/>
</a>
)
learnMoreLink: ""
// (
// <a
// href="https://scratch.mit.edu/info/faq/#clouddata"
// rel="noopener noreferrer"
// target="_blank"
// >
// <FormattedMessage
// defaultMessage="Learn more."
// description="Link text to cloud var faq"
// id="gui.alerts.cloudInfoLearnMore"
// />
// </a>
// )
}}
/>
),

View File

@ -28,6 +28,55 @@ const cloudManagerHOC = function (WrappedComponent) {
'handleCloudDataUpdate'
]);
this.enable = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.enable || false
this.token = window.scratchConfig && window.scratchConfig.session && window.scratchConfig.session.token,
this.username = window.scratchConfig && window.scratchConfig.session && window.scratchConfig.session.username || '';
this.authorUsername = window.scratchConfig && window.scratchConfig.projectInfo && window.scratchConfig.projectInfo.authorUsername,
this.cloudId = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.id
this.cloudHost = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.api
//
let that = this
document.addEventListener("setEnableCouldData",function(e){
that.enable = e.detail.enable;
window.scratchConfig.cloudData.enable = e.detail.enable;
that.handleCloudDataUpdate(that.enable)
})
window.scratch.setEnableCouldData = function(enable){
var event = new CustomEvent('setEnableCouldData', {"detail": {enable: enable}});
document.dispatchEvent(event);
}
//cloudId
document.addEventListener("setCloudId",function(e){
if(that.cloudId != e.detail.id){
window.scratchConfig.cloudData.id = e.detail.id;
that.cloudId = e.detail.id;
that.handleCloudDataUpdate(that.enable)
}
})
window.scratch.setCloudId = function(id){
var event = new CustomEvent('setCloudId', {"detail": {id: id}});
document.dispatchEvent(event);
}
//authorUsername
document.addEventListener("setAuthorUsername",function(e){
if(that.authorUsername != e.detail.authorUsername){
window.scratchConfig.projectInfo.authorUsername = e.detail.authorUsername;
that.authorUsername = e.detail.authorUsername;
that.handleCloudDataUpdate(that.enable)
}
})
window.scratch.setAuthorUsername = function(authorUsername){
var event = new CustomEvent('setAuthorUsername', {"detail": {authorUsername: authorUsername}});
document.dispatchEvent(event);
}
this.props.vm.on('HAS_CLOUD_DATA_UPDATE', this.handleCloudDataUpdate);
}
componentDidMount () {
@ -52,14 +101,25 @@ const cloudManagerHOC = function (WrappedComponent) {
this.disconnectFromCloud();
}
canUseCloud (props) {
return !!(props.cloudHost && props.username && props.vm && props.projectId && props.hasCloudPermission);
// return !!(props.cloudHost && props.username && props.vm && props.projectId && props.hasCloudPermission);
// console.log(props.vm);
// console.log(props.projectId);
// console.log(props.hasCloudPermission);
return this.enable;
}
shouldConnect (props) {
return !this.isConnected() && this.canUseCloud(props) &&
props.isShowingWithId && props.vm.runtime.hasCloudData() &&
props.canModifyCloudData;
shouldConnect (props) {
console.log("should connnet");
console.log(this.enable);
console.log(props.vm.runtime.hasCloudData());
// return !this.isConnected() && this.canUseCloud(props) &&
// props.isShowingWithId && props.vm.runtime.hasCloudData() &&
// props.canModifyCloudData;
//
return this.enable && props.vm.runtime.hasCloudData();
}
shouldDisconnect (props, prevProps) {
//
return !this.canUseCloud(props)||!props.vm.runtime.hasCloudData();
return this.isConnected() &&
( // Can no longer use cloud or cloud provider info is now stale
!this.canUseCloud(props) ||
@ -75,10 +135,11 @@ const cloudManagerHOC = function (WrappedComponent) {
}
connectToCloud () {
this.cloudProvider = new CloudProvider(
this.props.cloudHost,
this.cloudHost,
this.props.vm,
this.props.username,
this.props.projectId);
this.authorUsername,
this.token,
this.cloudId);
this.props.vm.setCloudProvider(this.cloudProvider);
}
disconnectFromCloud () {
@ -100,9 +161,8 @@ const cloudManagerHOC = function (WrappedComponent) {
const {
/* eslint-disable no-unused-vars */
canModifyCloudData,
cloudHost,
projectId,
username,
// username,
hasCloudPermission,
isShowingWithId,
onShowCloudInfo,
@ -112,7 +172,6 @@ const cloudManagerHOC = function (WrappedComponent) {
} = this.props;
return (
<WrappedComponent
canUseCloud={this.canUseCloud(this.props)}
vm={vm}
{...componentProps}
/>
@ -122,20 +181,16 @@ const cloudManagerHOC = function (WrappedComponent) {
CloudManager.propTypes = {
canModifyCloudData: PropTypes.bool.isRequired,
cloudHost: PropTypes.string,
hasCloudPermission: PropTypes.bool,
isShowingWithId: PropTypes.bool.isRequired,
onShowCloudInfo: PropTypes.func,
projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
username: PropTypes.string,
vm: PropTypes.instanceOf(VM).isRequired
};
CloudManager.defaultProps = {
cloudHost: null,
hasCloudPermission: false,
onShowCloudInfo: () => {},
username: null
};
const mapStateToProps = (state, ownProps) => {
@ -144,7 +199,7 @@ const cloudManagerHOC = function (WrappedComponent) {
isShowingWithId: getIsShowingWithId(loadingState),
projectId: state.scratchGui.projectState.projectId,
// if you're editing someone else's project, you can't modify cloud data
canModifyCloudData: (!state.scratchGui.mode.hasEverEnteredEditor || ownProps.canSave)
canModifyCloudData: (!state.scratchGui.mode.hasEverEnteredEditor || ownProps.canSave),
};
};

View File

@ -13,9 +13,10 @@ class CloudProvider {
* @param {string} projectId The id associated with the project containing
* cloud data.
*/
constructor (cloudHost, vm, username, projectId) {
constructor (cloudHost, vm, username, token, projectId) {
this.vm = vm;
this.username = username;
this.token = token;
this.projectId = projectId;
this.cloudHost = cloudHost;
@ -113,6 +114,10 @@ class CloudProvider {
value: message.value
};
break;
}
//初始化云变量
case 'init': {
}
}
return varData;
@ -130,6 +135,7 @@ class CloudProvider {
msg.method = methodName;
msg.user = this.username;
msg.project_id = this.projectId;
msg.token = this.token
// Optional string params can use simple falsey undefined check
if (dataName) msg.name = dataName;
@ -221,6 +227,7 @@ class CloudProvider {
this.connection = null;
this.vm = null;
this.username = null;
this.token = null;
this.projectId = null;
if (this._connectionTimeout) {
clearTimeout(this._connectionTimeout);

View File

@ -25,6 +25,16 @@
enable: true, // 是否启用背包
api: "/api/teaching/scratch/backpack", //背包API接口
},
cloudData:{
enable: true, //是否开启云变量功能
id: "create", //默认云变量ID可使用window.scratch.setCloudId更换ID
api: "127.0.0.1:1234/api/websocket/scratch/cloudData" //云变量API地址
},
projectInfo: {//作品信息
projectName: "",
authorUsername: "admin",
authorAvatar: './static/avatar.png',
},
logo: {
show: true, //是否显示
url: window.location.protocol+"//"+window.location.host + "/static/logo.png", //logo地址支持base64图片
@ -194,6 +204,21 @@
},
}
//api
/**
* window.scratch.loadPorject(url, callback)
* window.scratch.getProjectFile(callback(file))
* window.scratch.getProjectCover(callback(file))
* window.scratch.getProjectName()
* window.scratch.setProjectName(projectName)
* window.scratch.setPlayerOnly(isPlayerOnly)
* window.scratch.setFullScreen(isFullScreen)
*
* window.scratch.setEnableCouldData(isEnable) //设置是否开启云变量(会开启或关闭当前连接)
* window.scratch.setCloudId(id) //设置云变量ID会触发一次重连
* window.scratch.setAuthorUsername(authorUsername) //设置作者用户名
* window.vm.runtime.hasCloudData() //是否包含云变量
*/
</script>
</head>

View File

@ -23,6 +23,10 @@ const handleTelemetryModalOptOut = () => {
log('User opted out of telemetry');
};
const onVmInit = (vm) =>{
console.log("scratch vm init");
console.log(vm);
}
/*
* Render the GUI playground. This is a separate function because importing anything
* that instantiates the VM causes unsupported browsers to crash
@ -46,6 +50,8 @@ export default appTarget => {
const backpackShow = window.scratchConfig.session && window.scratchConfig.session.token
&& window.scratchConfig && window.scratchConfig.backpack && window.scratchConfig.backpack.enable
|| false
const cloudHost = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.api
const scratchDesktopMatches = window.location.href.match(/[?&]isScratchDesktop=([^&]+)/);
let simulateScratchDesktop;
@ -82,7 +88,11 @@ export default appTarget => {
backpackVisible={backpackShow}
// showComingSoon
backpackApi={backpackApi}
// canUseCloud={canUseCloud}
hasCloudPermission={true}
canSave={false}
onVmInit={onVmInit}
onClickLogo={onClickLogo}
/>,
appTarget);