Skip to content

Commit 795a52f

Browse files
committed
refactor: redux reducer and actions
1 parent 2ea7ec3 commit 795a52f

20 files changed

Lines changed: 296 additions & 315 deletions

forge.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = {
1616
name: "@electron-forge/plugin-vite",
1717
config: {
1818
build: [
19-
{ entry: "src/main.ts", config: "vite.main.config.mjs" },
19+
{ entry: "src/main/main.ts", config: "vite.main.config.mjs" },
2020
{
2121
entry: "src/preload.ts",
2222
config: "vite.preload.config.mjs",

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
]
2323
},
2424
"dependencies": {
25-
"electron-redux": "2.0.0-alpha.9",
2625
"electron-squirrel-startup": "^1.0.0",
2726
"registry-js": "^1.16.0",
2827
"simple-plist": "^1.3.1",
@@ -54,6 +53,7 @@
5453
"@typescript-eslint/parser": "^7.8.0",
5554
"electron": "^30.0.2",
5655
"electron-devtools-installer": "^3.2.0",
56+
"electron-redux": "2.0.0-alpha.9",
5757
"electron-update-notification": "^0.1.0",
5858
"eslint": "^9.1.1",
5959
"eslint-define-config": "^2.1.0",
@@ -72,6 +72,7 @@
7272
"react-redux": "^9.1.2",
7373
"react-use": "^17.5.0",
7474
"redux-logger": "^3.0.6",
75+
"ts-pattern": "^5.1.1",
7576
"ts-results": "^3.3.0",
7677
"typescript": "^5.4.5",
7778
"universal-analytics": "^0.5.3",

src/global.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/main/actions.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import type { AppInfo, PageInfo, ThunkActionCreator } from "../reducer";
2+
import { importByPlatform } from "./platforms";
3+
import { spawn } from "child_process";
4+
import { dialog } from "electron";
5+
import getPort from "get-port";
6+
import path from "node:path";
7+
import { v4 } from "uuid";
8+
9+
export const init: ThunkActionCreator = () => async (dispatch, getState) => {
10+
// first load
11+
const { adapter } = await importByPlatform();
12+
const apps = await adapter.readAll();
13+
14+
if (!apps.ok) throw new Error("Failed to read apps");
15+
dispatch({
16+
type: "app/loaded",
17+
payload: apps.unwrap(),
18+
});
19+
20+
// timer
21+
setInterval(async () => {
22+
const { session } = getState();
23+
const sessions = Object.values(session);
24+
const ports = sessions.flatMap((s) => [s.nodePort, s.windowPort]);
25+
26+
const payloads = await Promise.allSettled<PageInfo>(
27+
ports.map((port) =>
28+
fetch(`http://127.0.0.1:${port}/json`).then((res) => res.json()),
29+
),
30+
);
31+
const pages = payloads.flatMap((p) =>
32+
p.status === "fulfilled" ? p.value : [],
33+
);
34+
console.log(ports, pages);
35+
}, 3000);
36+
};
37+
38+
export const debug: ThunkActionCreator<AppInfo> = (app) => async (dispatch) => {
39+
const nodePort = await getPort();
40+
const windowPort = await getPort();
41+
42+
const sp = spawn(
43+
app.exePath,
44+
[`--inspect=${nodePort}`, `--remote-debugging-port=${windowPort}`],
45+
{
46+
cwd: process.platform === "win32" ? path.dirname(app.exePath) : "/",
47+
},
48+
);
49+
50+
const sessionId = v4();
51+
dispatch({
52+
type: "session/added",
53+
payload: { sessionId, appId: app.id, nodePort, windowPort },
54+
});
55+
56+
sp.on("error", (err) => {
57+
dialog.showErrorBox(`Error: ${app.name}`, err.message);
58+
});
59+
sp.on("close", () => {
60+
// console.log(`child process exited with code ${code}`)
61+
dispatch({ type: "session/removed", payload: sessionId });
62+
});
63+
64+
const handleStdout =
65+
(isError = false) =>
66+
(chunk: Buffer) => {
67+
// TODO: stderr colors
68+
console.log(isError);
69+
dispatch({
70+
type: "session/logAppended",
71+
payload: {
72+
sessionId,
73+
content: chunk.toString(),
74+
},
75+
});
76+
};
77+
78+
if (sp.stdout) {
79+
sp.stdout.on("data", handleStdout());
80+
}
81+
if (sp.stderr) {
82+
sp.stderr.on("data", handleStdout(true));
83+
}
84+
};
85+
86+
export const debugPath: ThunkActionCreator<string> =
87+
(path) => async (dispatch) => {
88+
// TODO:
89+
};

src/main.ts renamed to src/main/main.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import { setUpdater, setReporter } from "./main/utils";
2-
import { reducers } from "./reducers";
3-
import { appSlice } from "./reducers/app";
4-
import { configureStore } from "@reduxjs/toolkit";
1+
import { reducer, type AppInfo } from "../reducer";
2+
import { debug, debugPath, init } from "./actions";
3+
import { setUpdater, setReporter } from "./utils";
4+
import { applyMiddleware, legacy_createStore } from "@reduxjs/toolkit";
55
import {
66
app,
77
BrowserWindow,
88
Menu,
99
MenuItem,
1010
shell,
1111
nativeImage,
12+
ipcMain,
1213
} from "electron";
13-
import { stateSyncEnhancer } from "electron-redux/main";
14+
import { composeWithStateSync } from "electron-redux/main";
1415
import path from "path";
15-
import { logger } from "redux-logger";
16+
import logger from "redux-logger";
17+
import { thunk } from "redux-thunk";
1618

1719
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
1820
if (require("electron-squirrel-startup")) {
@@ -59,12 +61,19 @@ const gotTheLock = app.requestSingleInstanceLock();
5961
if (!gotTheLock) {
6062
app.quit();
6163
} else {
62-
const store = configureStore({
63-
reducer: reducers,
64-
middleware: (getDefault) => getDefault().concat(logger),
65-
enhancers: (getDefault) => getDefault().concat(stateSyncEnhancer()),
66-
});
67-
store.dispatch(appSlice.actions.read(null));
64+
const store = legacy_createStore(
65+
reducer,
66+
composeWithStateSync(
67+
applyMiddleware(
68+
//logger,
69+
thunk,
70+
),
71+
),
72+
);
73+
store.dispatch(
74+
// @ts-ignore
75+
init(),
76+
);
6877

6978
app.on("second-instance", () => {
7079
if (mainWindow) {
@@ -111,9 +120,23 @@ if (!gotTheLock) {
111120
);
112121
}
113122

114-
// ipcMain.on("dispatch-from-renderer", () => {
115-
116-
// })
123+
ipcMain.on("debug", (e, appInfo: AppInfo) => {
124+
store.dispatch(
125+
// @ts-ignore
126+
debug(appInfo),
127+
);
128+
});
129+
ipcMain.on("debug-path", (e, path: string) => {
130+
store.dispatch(
131+
// @ts-ignore
132+
debugPath(path),
133+
);
134+
});
135+
ipcMain.on("open-window", (e, url: string) => {
136+
const win = new BrowserWindow();
137+
// console.log(url)
138+
win.loadURL(url);
139+
});
117140

118141
setUpdater();
119142
createWindow();
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
export function importByPlatform() {
22
switch (process.platform) {
3-
case "win32":
4-
return import("../platforms/win");
3+
// case "win32":
4+
// return import("../platforms/win");
55
case "darwin":
6-
return import("../platforms/macos");
6+
return import("./macos");
77
case "linux":
8-
return import("../platforms/linux");
8+
return import("./linux");
99
default:
1010
throw new Error("platform not supported");
1111
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,10 @@ export const adapter: AppReader = {
7272
if (!isElectronBased) throw new Error("Not an electron app");
7373

7474
const info = await readPlistFile(path.join(p, "Contents/Info.plist"));
75-
const icon = await readIcnsAsImageUri(
76-
path.join(p, "Contents/Resources", info.CFBundleIconFile),
77-
);
75+
// const icon = await readIcnsAsImageUri(
76+
// path.join(p, "Contents/Resources", info.CFBundleIconFile),
77+
// );
78+
const icon = "";
7879

7980
return {
8081
id: info.CFBundleIdentifier,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AppInfo } from "../reducers/app";
1+
import type { AppInfo } from "../../reducer";
22
import { Result } from "ts-results";
33

44
export interface AppReader {

0 commit comments

Comments
 (0)