From 7b993f3550dd37acec92754aaae944da41046e04 Mon Sep 17 00:00:00 2001 From: catloversg <152669316+catloversg@users.noreply.github.com> Date: Sat, 20 Apr 2024 03:38:44 +0700 Subject: [PATCH] MISC: Remove file-saver (#1217) Also refactor to dedup our own download code --- package-lock.json | 6 ------ package.json | 1 - src/Paths/ContentFile.ts | 1 - src/SaveObject.ts | 20 +++----------------- src/Script/Script.ts | 16 ---------------- src/Terminal/commands/download.ts | 8 ++++---- src/TextFile.ts | 15 --------------- src/ui/React/RecoveryRoot.tsx | 4 ++-- src/utils/FileUtils.ts | 11 +++++++++++ 9 files changed, 20 insertions(+), 62 deletions(-) create mode 100644 src/utils/FileUtils.ts diff --git a/package-lock.json b/package-lock.json index cf17e412f..680d6678f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "clsx": "^1.2.1", "date-fns": "^2.30.0", "escodegen": "^2.1.0", - "file-saver": "^2.0.5", "js-sha256": "^0.9.0", "jszip": "^3.10.1", "material-ui-color": "^1.2.0", @@ -8458,11 +8457,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-saver": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", - "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" - }, "node_modules/filename-reserved-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", diff --git a/package.json b/package.json index 29e81d3c7..d43ef3f8b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "clsx": "^1.2.1", "date-fns": "^2.30.0", "escodegen": "^2.1.0", - "file-saver": "^2.0.5", "js-sha256": "^0.9.0", "jszip": "^3.10.1", "material-ui-color": "^1.2.0", diff --git a/src/Paths/ContentFile.ts b/src/Paths/ContentFile.ts index 862e1a580..e3bdb73eb 100644 --- a/src/Paths/ContentFile.ts +++ b/src/Paths/ContentFile.ts @@ -7,7 +7,6 @@ export type ContentFilePath = ScriptFilePath | TextFilePath; export interface ContentFile { filename: ContentFilePath; content: string; - download: () => void; deleteFromServer: (server: BaseServer) => boolean; } export type ContentFileMap = Map; diff --git a/src/SaveObject.ts b/src/SaveObject.ts index e8c9fd883..732f027c4 100644 --- a/src/SaveObject.ts +++ b/src/SaveObject.ts @@ -41,6 +41,7 @@ import { getGoSave, loadGo } from "./Go/SaveLoad"; import { SaveData } from "./types"; import { SaveDataError, canUseBinaryFormat, decodeSaveData, encodeJsonSaveString } from "./utils/SaveDataUtils"; import { isBinaryFormat } from "../electron/saveDataBinaryFormat"; +import { downloadContentAsFile } from "./utils/FileUtils"; /* SaveObject.js * Defines the object used to save/load games @@ -158,7 +159,7 @@ class BitburnerSaveObject { async exportGame(): Promise { const saveData = await this.getSaveData(); const filename = this.getSaveFileName(); - download(filename, saveData); + downloadContentAsFile(saveData, filename); } async importGame(saveData: SaveData, reload = true): Promise { @@ -853,23 +854,8 @@ function createBetaUpdateText() { ); } -function download(filename: string, content: SaveData): void { - const file = new Blob([content], { type: "text/plain" }); - - const a = document.createElement("a"), - url = URL.createObjectURL(file); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - setTimeout(function () { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); -} - constructorsForReviver.BitburnerSaveObject = BitburnerSaveObject; -export { saveObject, loadGame, download }; +export { saveObject, loadGame }; const saveObject = new BitburnerSaveObject(); diff --git a/src/Script/Script.ts b/src/Script/Script.ts index da8db54d5..9e6139f0b 100644 --- a/src/Script/Script.ts +++ b/src/Script/Script.ts @@ -45,22 +45,6 @@ export class Script implements ContentFile { this.server = server; // hostname of server this script is on } - /** Download the script as a file */ - download(): void { - const filename = this.filename; - const file = new Blob([this.code], { type: "text/plain" }); - const a = document.createElement("a"), - url = URL.createObjectURL(file); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - setTimeout(function () { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } - /** Invalidates the current script module and related data, e.g. when modifying the file. */ invalidateModule(): void { // Always clear ram usage diff --git a/src/Terminal/commands/download.ts b/src/Terminal/commands/download.ts index 6f7f9fa38..6d4f8de7d 100644 --- a/src/Terminal/commands/download.ts +++ b/src/Terminal/commands/download.ts @@ -1,11 +1,11 @@ import { Terminal } from "../../Terminal"; import { BaseServer } from "../../Server/BaseServer"; -import FileSaver from "file-saver"; import JSZip from "jszip"; import { root } from "../../Paths/Directory"; import { hasScriptExtension } from "../../Paths/ScriptFilePath"; import { hasTextExtension } from "../../Paths/TextFilePath"; import { getGlobbedFileMap } from "../../Paths/GlobbedFiles"; +import { downloadContentAsFile } from "../../utils/FileUtils"; // Basic globbing implementation only supporting * and ?. Can be broken out somewhere else later. export function exportScripts(pattern: string, server: BaseServer, currDir = root): void { @@ -17,10 +17,10 @@ export function exportScripts(pattern: string, server: BaseServer, currDir = roo // Return an error if no files matched, rather than an empty zip folder if (Object.keys(zip.files).length == 0) throw new Error(`No files match the pattern ${pattern}`); - const zipFn = `bitburner${ + const filename = `bitburner${ hasScriptExtension(pattern) ? "Scripts" : pattern.endsWith(".txt") ? "Texts" : "Files" }.zip`; - zip.generateAsync({ type: "blob" }).then((content: Blob) => FileSaver.saveAs(content, zipFn)); + zip.generateAsync({ type: "blob" }).then((content: Blob) => downloadContentAsFile(content, filename)); } export function download(args: (string | number | boolean)[], server: BaseServer): void { @@ -45,5 +45,5 @@ export function download(args: (string | number | boolean)[], server: BaseServer } const file = server.getContentFile(path); if (!file) return Terminal.error(`File not found: ${path}`); - return file.download(); + return downloadContentAsFile(file.content, file.filename); } diff --git a/src/TextFile.ts b/src/TextFile.ts index 7754d016f..8db7ea435 100644 --- a/src/TextFile.ts +++ b/src/TextFile.ts @@ -24,21 +24,6 @@ export class TextFile implements ContentFile { this.text = txt; } - /** Serves the file to the user as a downloadable resource through the browser. */ - download(): void { - const file: Blob = new Blob([this.text], { type: "text/plain" }); - const a: HTMLAnchorElement = document.createElement("a"); - const url: string = URL.createObjectURL(file); - a.href = url; - a.download = this.filename; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - URL.revokeObjectURL(url); - }, 0); - } - /** Serialize the current file to a JSON save state. */ toJSON(): IReviverValue { return Generic_toJSON("TextFile", this); diff --git a/src/ui/React/RecoveryRoot.tsx b/src/ui/React/RecoveryRoot.tsx index e06e46f14..f9b1bc5c8 100644 --- a/src/ui/React/RecoveryRoot.tsx +++ b/src/ui/React/RecoveryRoot.tsx @@ -5,7 +5,6 @@ import { Settings } from "../../Settings/Settings"; import { load } from "../../db"; import { Router } from "../GameRoot"; import { Page } from "../Router"; -import { download } from "../../SaveObject"; import { IErrorData, newIssueUrl } from "../../utils/ErrorHelper"; import { DeleteGameButton } from "./DeleteGameButton"; import { SoftResetButton } from "./SoftResetButton"; @@ -14,6 +13,7 @@ import DirectionsRunIcon from "@mui/icons-material/DirectionsRun"; import GitHubIcon from "@mui/icons-material/GitHub"; import { isBinaryFormat } from "../../../electron/saveDataBinaryFormat"; import { InvalidSaveData, UnsupportedSaveData } from "../../utils/SaveDataUtils"; +import { downloadContentAsFile } from "../../utils/FileUtils"; export let RecoveryMode = false; let sourceError: unknown; @@ -44,7 +44,7 @@ export function RecoveryRoot({ softReset, errorData, resetError }: IProps): Reac const epochTime = Math.round(Date.now() / 1000); const extension = isBinaryFormat(content) ? "json.gz" : "json"; const filename = `RECOVERY_BITBURNER_${epochTime}.${extension}`; - download(filename, content); + downloadContentAsFile(content, filename); }) .catch((err) => console.error(err)); }, []); diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts new file mode 100644 index 000000000..b462d2258 --- /dev/null +++ b/src/utils/FileUtils.ts @@ -0,0 +1,11 @@ +export function downloadContentAsFile(content: BlobPart, filename: string): void { + const blob = new Blob([content]); + const anchorElement = document.createElement("a"); + const url = URL.createObjectURL(blob); + anchorElement.href = url; + anchorElement.download = filename; + anchorElement.click(); + setTimeout(function () { + URL.revokeObjectURL(url); + }, 0); +}