Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloud variable kill switch #7877

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions addons-l10n/en/cloud-off.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"cloud-off/reenable": "Re-enable Cloud Variables",
"cloud-off/reloadRequired": "You must reload the page to reconnect Cloud variables.",
"cloud-off/confirm": "Reload",
"cloud-off/cancel": "Cancel"
}
1 change: 1 addition & 0 deletions addons/addons.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
"asset-conflict-dialog",
"remaining-replies",
"forum-user-agent",
"cloud-off",

"// NEW ADDONS ABOVE THIS ↑↑",
"// Note: these themes need this exact order to work properly,",
Expand Down
29 changes: 29 additions & 0 deletions addons/cloud-off/addon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "Cloud variable kill switch",
"description": "Allows you to cut the connection to the Cloud Data server when running projects with Cloud variables by flicking a switch, making them act as normal variables.",
"credits": [
{
"name": "DNin01",
"link": "https://github.com/DNin01"
}
],
"info": [
{
"type": "notice",
"id": "reloadToReconnect",
"text": "Once disconnected, a page reload is required to reconnect to Cloud Data."
}
],
"userscripts": [
{
"url": "userscript.js",
"matches": ["projects"],
"runAtComplete": true
}
],
"dynamicEnable": true,
"dynamicDisable": true,
"tags": ["editor", "projectPlayer"],
"versionAdded": "1.40.0",
"enabledByDefault": false
}
85 changes: 85 additions & 0 deletions addons/cloud-off/userscript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
export default async function ({ addon, console, msg }) {
const cloud = addon.tab.traps.vm.runtime.ioDevices.cloud;
/** Disconnects the Cloud variables, in response to the user turning off the switch. */
function disableCloud() {
if (cloud.provider.connection.readyState === WebSocket.OPEN) {
// First override the events that trigger a connection retry, then close the connection
cloud.provider.connection.onclose = () => {};
cloud.provider.connection.onerror = () => {};
cloud.provider.connection.close();
connected = false;
} else {
// WebSocket isn't open, we're not going to try to stop it now
console.warn("Not disconnecting because WebSocket is closed");
setCheckbox(true);
}
}
/** Opens a confirmation dialog to reload the page and reconnect, in response to the user turning on the switch. */
function reloadPrompt() {
setCheckbox(false);
addon.tab.scratchClassReady().then(() => {
addon.tab
.confirm(msg("reenable"), msg("reloadRequired"), {
okButtonLabel: msg("confirm"),
cancelButtonLabel: msg("cancel"),
useEditorClasses: false, // The toggle switch that opens this dialog is outside the editor
})
.then((confirmed) => {
if (confirmed) {
location.reload();
}
});
});
}

function addToggleSwitch() {
const sliderContainer = Object.assign(document.createElement("div"), {
className: "sa-toggle-cloud-off",
});
const label = Object.assign(document.createElement("label"), {
className: "toggle-switch",
});
const checkbox = Object.assign(document.createElement("input"), {
type: "checkbox",
checked: connected && !addon.tab.redux.state.scratchGui.mode.hasEverEnteredEditor,
});
const sliderSpan = Object.assign(document.createElement("span"), {
className: "slider",
});
label.append(checkbox, sliderSpan);
sliderContainer.append(label);
addon.tab.displayNoneWhileDisabled(sliderContainer);
const extChip = document.querySelector(".extension-content a[href^='/cloudmonitor']").parentElement.parentElement;
extChip.appendChild(sliderContainer);

checkbox.addEventListener("change", () => {
checkbox.checked ? reloadPrompt() : disableCloud();
});
}
/** Sets the state of the toggle switch. */
function setCheckbox(checked) {
document.querySelector(".sa-toggle-cloud-off input").checked = checked;
}

let connected = true;

await addon.tab.redux.waitForState((state) => state.scratchGui.projectState.loadingState.startsWith("SHOWING"));

if (addon.tab.traps.vm.runtime.hasCloudData()) {
let checkCnt = 0;
while (cloud.provider?.connection.readyState !== WebSocket.OPEN) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible optimization: do not enter while loop when signed out and for New Scratchers

checkCnt++;
// Check at an interval of 200ms for 5 seconds, then 2s
await new Promise((resolve) => setTimeout(resolve, checkCnt > 25 ? 2000 : 200));
}

while (true) {
await addon.tab.waitForElement(".extension-content a[href^='/cloudmonitor']", {
markAsSeen: true,
reduxCondition: (state) => !state.scratchGui.mode.hasEverEnteredEditor,
});

addToggleSwitch();
}
}
}
Loading