mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-13 18:21:51 +00:00
Refactor file system electron event handling
This commit is contained in:
parent
a0071681e7
commit
f12f81a125
@ -55,8 +55,8 @@ function createWindow() {
|
|||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
webSecurity: false,
|
webSecurity: true,
|
||||||
// sandbox: true,
|
sandbox: true,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
preload: path.join(__dirname, "preload.js"),
|
preload: path.join(__dirname, "preload.js"),
|
||||||
},
|
},
|
||||||
@ -229,70 +229,33 @@ async function writeFileSafe(filename, contents) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function performFsJob(job) {
|
ipcMain.handle("fs-job", async (event, job) => {
|
||||||
const fname = path.join(storePath, job.filename);
|
const filenameSafe = job.filename.replace(/[^a-z\.\-_0-9]/i, "");
|
||||||
|
const fname = path.join(storePath, filenameSafe);
|
||||||
switch (job.type) {
|
switch (job.type) {
|
||||||
case "read": {
|
case "read": {
|
||||||
if (!fs.existsSync(fname)) {
|
if (!fs.existsSync(fname)) {
|
||||||
return {
|
// Special FILE_NOT_FOUND error code
|
||||||
// Special FILE_NOT_FOUND error code
|
return { error: "file_not_found" };
|
||||||
error: "file_not_found",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await fs.promises.readFile(fname, "utf8");
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
} catch (ex) {
|
|
||||||
return {
|
|
||||||
error: ex,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return await fs.promises.readFile(fname, "utf8");
|
||||||
}
|
}
|
||||||
case "write": {
|
case "write": {
|
||||||
try {
|
await writeFileSafe(fname, job.contents);
|
||||||
await writeFileSafe(fname, job.contents);
|
return job.contents;
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: job.contents,
|
|
||||||
};
|
|
||||||
} catch (ex) {
|
|
||||||
return {
|
|
||||||
error: ex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case "delete": {
|
case "delete": {
|
||||||
try {
|
await fs.promises.unlink(fname);
|
||||||
await fs.promises.unlink(fname);
|
return;
|
||||||
} catch (ex) {
|
|
||||||
return {
|
|
||||||
error: ex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error("Unknown fs job: " + job.type);
|
throw new Error("Unknown fs job: " + job.type);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.on("fs-job", async (event, arg) => {
|
|
||||||
const result = await performFsJob(arg);
|
|
||||||
event.reply("fs-response", { id: arg.id, result });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on("open-mods-folder", async () => {
|
ipcMain.handle("open-mods-folder", async () => {
|
||||||
shell.openPath(modsPath);
|
shell.openPath(modsPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
const { contextBridge, ipcRenderer } = require("electron");
|
const { contextBridge, ipcRenderer } = require("electron");
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld("ipcRenderer", ipcRenderer);
|
contextBridge.exposeInMainWorld("ipcRenderer", {
|
||||||
|
invoke: ipcRenderer.invoke.bind(ipcRenderer),
|
||||||
|
on: ipcRenderer.on.bind(ipcRenderer),
|
||||||
|
send: ipcRenderer.send.bind(ipcRenderer),
|
||||||
|
});
|
||||||
|
|||||||
@ -49,9 +49,12 @@ function createWindow() {
|
|||||||
// fullscreen: true,
|
// fullscreen: true,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: false,
|
||||||
webSecurity: false,
|
webSecurity: true,
|
||||||
contextIsolation: false,
|
sandbox: true,
|
||||||
|
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(__dirname, "preload.js"),
|
||||||
},
|
},
|
||||||
allowRunningInsecureContent: false,
|
allowRunningInsecureContent: false,
|
||||||
});
|
});
|
||||||
@ -165,20 +168,20 @@ async function writeFileSafe(filename, contents) {
|
|||||||
console.warn(prefix, "Concurrent write process on", filename);
|
console.warn(prefix, "Concurrent write process on", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
await fileLock.acquire(filename, async () => {
|
fileLock.acquire(filename, async () => {
|
||||||
console.log(prefix, "Starting write on", niceFileName(filename), "in transaction", transactionId);
|
console.log(prefix, "Starting write on", niceFileName(filename), "in transaction", transactionId);
|
||||||
|
|
||||||
if (!fs.existsSync(filename)) {
|
if (!fs.existsSync(filename)) {
|
||||||
// this one is easy
|
// this one is easy
|
||||||
console.log(prefix, "Writing file instantly because it does not exist:", niceFileName(filename));
|
console.log(prefix, "Writing file instantly because it does not exist:", niceFileName(filename));
|
||||||
fs.writeFileSync(filename, contents, { encoding: "utf8" });
|
await fs.promises.writeFile(filename, contents, "utf8");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, write a temporary file (.tmp-XXX)
|
// first, write a temporary file (.tmp-XXX)
|
||||||
const tempName = filename + ".tmp-" + transactionId;
|
const tempName = filename + ".tmp-" + transactionId;
|
||||||
console.log(prefix, "Writing temporary file", niceFileName(tempName));
|
console.log(prefix, "Writing temporary file", niceFileName(tempName));
|
||||||
fs.writeFileSync(tempName, contents, { encoding: "utf8" });
|
await fs.promises.writeFile(tempName, contents, "utf8");
|
||||||
|
|
||||||
// now, rename the original file to (.backup-XXX)
|
// now, rename the original file to (.backup-XXX)
|
||||||
const oldTemporaryName = filename + ".backup-" + transactionId;
|
const oldTemporaryName = filename + ".backup-" + transactionId;
|
||||||
@ -189,7 +192,7 @@ async function writeFileSafe(filename, contents) {
|
|||||||
"to",
|
"to",
|
||||||
niceFileName(oldTemporaryName)
|
niceFileName(oldTemporaryName)
|
||||||
);
|
);
|
||||||
fs.renameSync(filename, oldTemporaryName);
|
await fs.promises.rename(filename, oldTemporaryName);
|
||||||
|
|
||||||
// now, rename the temporary file (.tmp-XXX) to the target
|
// now, rename the temporary file (.tmp-XXX) to the target
|
||||||
console.log(
|
console.log(
|
||||||
@ -199,7 +202,7 @@ async function writeFileSafe(filename, contents) {
|
|||||||
"to the original",
|
"to the original",
|
||||||
niceFileName(filename)
|
niceFileName(filename)
|
||||||
);
|
);
|
||||||
fs.renameSync(tempName, filename);
|
await fs.promises.rename(tempName, filename);
|
||||||
|
|
||||||
// we are done now, try to create a backup, but don't fail if the backup fails
|
// we are done now, try to create a backup, but don't fail if the backup fails
|
||||||
try {
|
try {
|
||||||
@ -208,82 +211,43 @@ async function writeFileSafe(filename, contents) {
|
|||||||
if (fs.existsSync(backupFileName)) {
|
if (fs.existsSync(backupFileName)) {
|
||||||
console.log(prefix, "Deleting old backup file", niceFileName(backupFileName));
|
console.log(prefix, "Deleting old backup file", niceFileName(backupFileName));
|
||||||
// delete the old backup
|
// delete the old backup
|
||||||
fs.unlinkSync(backupFileName);
|
await fs.promises.unlink(backupFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rename the old file to the new backup file
|
// rename the old file to the new backup file
|
||||||
console.log(prefix, "Moving", niceFileName(oldTemporaryName), "to the backup file location");
|
console.log(prefix, "Moving", niceFileName(oldTemporaryName), "to the backup file location");
|
||||||
fs.renameSync(oldTemporaryName, backupFileName);
|
await fs.promises.rename(oldTemporaryName, backupFileName);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(prefix, "Failed to switch backup files:", ex);
|
console.error(prefix, "Failed to switch backup files:", ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function performFsJob(job) {
|
ipcMain.handle("fs-job", async (event, job) => {
|
||||||
const fname = path.join(storePath, job.filename);
|
const filenameSafe = job.filename.replace(/[^a-z\.\-_0-9]/i, "");
|
||||||
|
const fname = path.join(storePath, filenameSafe);
|
||||||
switch (job.type) {
|
switch (job.type) {
|
||||||
case "read": {
|
case "read": {
|
||||||
if (!fs.existsSync(fname)) {
|
if (!fs.existsSync(fname)) {
|
||||||
return {
|
// Special FILE_NOT_FOUND error code
|
||||||
// Special FILE_NOT_FOUND error code
|
return { error: "file_not_found" };
|
||||||
error: "file_not_found",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = fs.readFileSync(fname, { encoding: "utf8" });
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
return {
|
|
||||||
error: ex,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return await fs.promises.readFile(fname, "utf8");
|
||||||
}
|
}
|
||||||
case "write": {
|
case "write": {
|
||||||
try {
|
await writeFileSafe(fname, job.contents);
|
||||||
writeFileSafe(fname, job.contents);
|
return job.contents;
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: job.contents,
|
|
||||||
};
|
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
return {
|
|
||||||
error: ex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case "delete": {
|
case "delete": {
|
||||||
try {
|
await fs.promises.unlink(fname);
|
||||||
fs.unlinkSync(fname);
|
return;
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
return {
|
|
||||||
error: ex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error("Unkown fs job: " + job.type);
|
throw new Error("Unknown fs job: " + job.type);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.on("fs-job", async (event, arg) => {
|
|
||||||
const result = await performFsJob(arg);
|
|
||||||
event.sender.send("fs-response", { id: arg.id, result });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
wegame.init(isDev);
|
wegame.init(isDev);
|
||||||
wegame.listen();
|
wegame.listen();
|
||||||
|
|||||||
@ -1,29 +1,8 @@
|
|||||||
import { StorageInterface } from "../storage";
|
import { FILE_NOT_FOUND, StorageInterface } from "../storage";
|
||||||
import { createLogger } from "../../core/logging";
|
|
||||||
|
|
||||||
const logger = createLogger("electron-storage");
|
|
||||||
|
|
||||||
export class StorageImplElectron extends StorageInterface {
|
export class StorageImplElectron extends StorageInterface {
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
super(app);
|
super(app);
|
||||||
|
|
||||||
/** @type {Object.<number, {resolve:Function, reject: Function}>} */
|
|
||||||
this.jobs = {};
|
|
||||||
this.jobId = 0;
|
|
||||||
|
|
||||||
ipcRenderer.on("fs-response", (event, arg) => {
|
|
||||||
const id = arg.id;
|
|
||||||
if (!this.jobs[id]) {
|
|
||||||
logger.warn("Got unhandled FS response, job not known:", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { resolve, reject } = this.jobs[id];
|
|
||||||
if (arg.result.success) {
|
|
||||||
resolve(arg.result.data);
|
|
||||||
} else {
|
|
||||||
reject(arg.result.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
@ -31,44 +10,32 @@ export class StorageImplElectron extends StorageInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeFileAsync(filename, contents) {
|
writeFileAsync(filename, contents) {
|
||||||
return new Promise((resolve, reject) => {
|
return ipcRenderer.invoke("fs-job", {
|
||||||
// ipcMain
|
type: "write",
|
||||||
const jobId = ++this.jobId;
|
filename,
|
||||||
this.jobs[jobId] = { resolve, reject };
|
contents,
|
||||||
|
|
||||||
ipcRenderer.send("fs-job", {
|
|
||||||
type: "write",
|
|
||||||
filename,
|
|
||||||
contents,
|
|
||||||
id: jobId,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
readFileAsync(filename) {
|
readFileAsync(filename) {
|
||||||
return new Promise((resolve, reject) => {
|
return ipcRenderer
|
||||||
// ipcMain
|
.invoke("fs-job", {
|
||||||
const jobId = ++this.jobId;
|
|
||||||
this.jobs[jobId] = { resolve, reject };
|
|
||||||
|
|
||||||
ipcRenderer.send("fs-job", {
|
|
||||||
type: "read",
|
type: "read",
|
||||||
filename,
|
filename,
|
||||||
id: jobId,
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res && res.error === FILE_NOT_FOUND) {
|
||||||
|
throw FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFileAsync(filename) {
|
deleteFileAsync(filename) {
|
||||||
return new Promise((resolve, reject) => {
|
return ipcRenderer.invoke("fs-job", {
|
||||||
// ipcMain
|
type: "delete",
|
||||||
const jobId = ++this.jobId;
|
filename,
|
||||||
this.jobs[jobId] = { resolve, reject };
|
|
||||||
ipcRenderer.send("fs-job", {
|
|
||||||
type: "delete",
|
|
||||||
filename,
|
|
||||||
id: jobId,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,7 +116,7 @@ export class ModsState extends TextualGameState {
|
|||||||
this.dialogs.showWarning(T.global.error, T.mods.folderOnlyStandalone);
|
this.dialogs.showWarning(T.global.error, T.mods.folderOnlyStandalone);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ipcRenderer.send("open-mods-folder");
|
ipcRenderer.invoke("open-mods-folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
onSteamLinkClicked() {
|
onSteamLinkClicked() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user