/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * A JSWindowActor that is responsible for marshalling information between * the BackupService singleton and any registered UI widgets that need to * represent data from that service. Any UI widgets that want to receive * state updates from BackupService should emit a BackupUI:InitWidget * event in a document that this actor pair is registered for. */ export class BackupUIChild extends JSWindowActorChild { #inittedWidgets = new WeakSet(); /** * Handles custom events fired by widgets that want to register with * BackupUIChild. * * @param {Event} event * The custom event that the widget fired. */ async handleEvent(event) { /** * BackupUI:InitWidget sends a message to the parent to request the BackupService state * which will result in a `backupServiceState` property of the widget to be set when that * state is received. Subsequent state updates will also cause that state property to * be set. */ if (event.type == "BackupUI:InitWidget") { this.#inittedWidgets.add(event.target); this.sendAsyncMessage("RequestState"); } else if (event.type == "BackupUI:EnableScheduledBackups") { const target = event.target; const result = await this.sendQuery( "EnableScheduledBackups", event.detail ); if (result.success) { target.close(); } else { target.enableBackupErrorCode = result.errorCode; } } else if (event.type == "BackupUI:DisableScheduledBackups") { const target = event.target; this.sendAsyncMessage("DisableScheduledBackups", event.detail); // backups will always end up disabled even if there was an error // with other bookkeeping related to turning off backups target.close(); } else if (event.type == "BackupUI:ShowFilepicker") { let targetNodeName = event.target.nodeName; let { path, filename, iconURL } = await this.sendQuery("ShowFilepicker", { win: event.detail?.win, filter: event.detail?.filter, displayDirectoryPath: event.detail?.displayDirectoryPath, }); let widgets = ChromeUtils.nondeterministicGetWeakSetKeys( this.#inittedWidgets ); for (let widget of widgets) { if (widget.isConnected && widget.nodeName == targetNodeName) { widget.dispatchEvent( new CustomEvent("BackupUI:SelectNewFilepickerPath", { bubbles: true, detail: { path, filename, iconURL, }, }) ); break; } } } else if (event.type == "BackupUI:GetBackupFileInfo") { let { backupFile } = event.detail; this.sendAsyncMessage("GetBackupFileInfo", { backupFile, }); } else if (event.type == "BackupUI:RestoreFromBackupFile") { let { backupFile, backupPassword } = event.detail; event.target.recoveryInProgress = true; event.target.recoveryErrorCode = 0; let result = await this.sendQuery("RestoreFromBackupFile", { backupFile, backupPassword, }); event.target.recoveryInProgress = false; if (result.success) { event.target.restoreFromBackupDialogEl?.close(); } else { event.target.recoveryErrorCode = result.errorCode; } } else if (event.type == "BackupUI:RestoreFromBackupChooseFile") { this.sendAsyncMessage("RestoreFromBackupChooseFile"); } else if (event.type == "BackupUI:EnableEncryption") { const target = event.target; const result = await this.sendQuery("EnableEncryption", event.detail); if (result.success) { target.close(); } else { target.enableEncryptionErrorCode = result.errorCode; } } else if (event.type == "BackupUI:DisableEncryption") { const target = event.target; const result = await this.sendQuery("DisableEncryption", event.detail); if (result.success) { target.close(); } else { target.disableEncryptionErrorCode = result.errorCode; } } else if (event.type == "BackupUI:RerunEncryption") { const target = event.target; const result = await this.sendQuery("RerunEncryption", event.detail); if (result.success) { target.close(); } else { target.rerunEncryptionErrorCode = result.errorCode; } } else if (event.type == "BackupUI:ShowBackupLocation") { this.sendAsyncMessage("ShowBackupLocation"); } else if (event.type == "BackupUI:EditBackupLocation") { this.sendAsyncMessage("EditBackupLocation"); } } /** * Handles messages sent by BackupUIParent. * * @param {ReceiveMessageArgument} message * The message received from the BackupUIParent. */ receiveMessage(message) { if (message.name == "StateUpdate") { let widgets = ChromeUtils.nondeterministicGetWeakSetKeys( this.#inittedWidgets ); for (let widget of widgets) { if (widget.isConnected) { // Note: we might need to switch to using Cu.cloneInto here in the // event that these widgets are embedded in a non-parent-process // context, like in an onboarding card. widget.backupServiceState = message.data.state; } } } } }