Skip to content

Commit 75773ea

Browse files
authored
refactor(update): support beta upgrade to stable (netless-io#821)
1 parent 600a069 commit 75773ea

File tree

12 files changed

+71
-67
lines changed

12 files changed

+71
-67
lines changed

desktop/main-app/src/utils/IPCActions.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { ipc } from "flat-types";
33
import { app, ipcMain, powerSaveBlocker } from "electron";
44
import runtime from "./Runtime";
55
import { updateService } from "./UpdateService";
6+
import { update } from "flat-types";
7+
import { gt } from "semver";
68

79
const windowActionAsync = (customWindow: CustomSingleWindow): ipc.WindowActionAsync => {
810
const { window, options } = customWindow;
@@ -70,8 +72,8 @@ const windowActionAsync = (customWindow: CustomSingleWindow): ipc.WindowActionAs
7072
}
7173
};
7274
})(),
73-
"start-update": () => {
74-
updateService.update();
75+
"start-update": args => {
76+
updateService.update(args.prereleaseTag);
7577
},
7678
"cancel-update": () => {
7779
updateService.cancel();
@@ -90,18 +92,31 @@ export const appActionAsync: ipc.AppActionAsync = {
9092

9193
export const appActionSync: ipc.AppActionSync = {
9294
"get-runtime": () => {
93-
return runtime;
95+
return Promise.resolve(runtime);
9496
},
9597
"get-open-at-login": () => {
96-
return app.getLoginItemSettings().openAtLogin;
98+
return Promise.resolve(app.getLoginItemSettings().openAtLogin);
9799
},
98-
"get-update-info": () => {
99-
return updateService.check().catch((err: Error) => {
100-
console.error(err.message);
101-
return {
102-
hasNewVersion: false,
103-
};
104-
}) as any;
100+
"get-update-info": async () => {
101+
const warpUpdateCheck = async (
102+
prereleaseTag: update.PrereleaseTag,
103+
): Promise<update.UpdateCheckInfo> => {
104+
return await updateService.check(prereleaseTag).catch((err: Error) => {
105+
console.error(err.message);
106+
return {
107+
hasNewVersion: false,
108+
};
109+
});
110+
};
111+
112+
const beta = await warpUpdateCheck("beta");
113+
const stable = await warpUpdateCheck("stable");
114+
115+
if (beta.hasNewVersion && stable.hasNewVersion) {
116+
return gt(beta.version, stable.version) ? beta : stable;
117+
}
118+
119+
return beta.hasNewVersion ? beta : stable;
105120
},
106121
};
107122

desktop/main-app/src/utils/Runtime.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import path from "path";
22
import { app } from "electron";
33
import { platform } from "os";
44
import { runtime as Runtime } from "flat-types";
5-
import { prerelease } from "semver";
65

76
const isDevelopment = process.env.NODE_ENV === "development";
87

@@ -33,19 +32,6 @@ const appVersion = isProduction ? app.getVersion() : require("../../package.json
3332

3433
const downloadsDirectory = path.join(app.getPath("userData"), "downloads");
3534

36-
const prereleaseTag = (() => {
37-
// e.g:
38-
// version: 1.0.0-beta.1
39-
// tag: ["beta", 1];
40-
const tag = prerelease(require("../../package.json").version);
41-
42-
if (tag) {
43-
return tag[0] as "alpha" | "beta" | "stable";
44-
}
45-
46-
return "stable";
47-
})();
48-
4935
const runtime: Runtime.Type = {
5036
isDevelopment,
5137
isProduction,
@@ -57,7 +43,6 @@ const runtime: Runtime.Type = {
5743
appVersion,
5844
downloadsDirectory,
5945
assetsPath,
60-
prereleaseTag,
6146
};
6247

6348
export default runtime;

desktop/main-app/src/utils/UpdateService.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { update } from "flat-types";
77
class UpdateService {
88
private cancellationToken: UpdateCheckResult["cancellationToken"];
99

10-
public check(): Promise<update.UpdateCheckInfo> {
10+
public check(prereleaseTag: update.PrereleaseTag): Promise<update.UpdateCheckInfo> {
1111
autoUpdater.autoDownload = false;
12-
UpdateService.setUpdateURL();
12+
UpdateService.setUpdateURL(prereleaseTag);
1313

1414
return new Promise((resolve, reject) => {
1515
const updateAvailable = (info: UpdateCheckResult["updateInfo"]) => {
@@ -22,6 +22,7 @@ class UpdateService {
2222
typeof info.releaseNotes === "string"
2323
? JSON.parse(info.releaseNotes)
2424
: undefined,
25+
prereleaseTag,
2526
});
2627
};
2728

@@ -53,7 +54,7 @@ class UpdateService {
5354
});
5455
}
5556

56-
public update(): void {
57+
public update(prereleaseTag: update.PrereleaseTag): void {
5758
autoUpdater.autoDownload = true;
5859

5960
// must be set to false here
@@ -63,7 +64,7 @@ class UpdateService {
6364
// domain: 'RACCommandErrorDomain'
6465
autoUpdater.autoInstallOnAppQuit = false;
6566

66-
UpdateService.setUpdateURL();
67+
UpdateService.setUpdateURL(prereleaseTag);
6768

6869
const updateNotAvailable = () => {
6970
removeListeners();
@@ -122,9 +123,9 @@ class UpdateService {
122123
this.cancellationToken?.cancel();
123124
}
124125

125-
private static setUpdateURL(): void {
126+
private static setUpdateURL(prereleaseTag: update.PrereleaseTag): void {
126127
const osName = runtime.isWin ? "win" : "mac";
127-
const updateURL = `${process.env.UPDATE_DOMAIN}/latest/${runtime.prereleaseTag}/${osName}`;
128+
const updateURL = `${process.env.UPDATE_DOMAIN}/latest/${prereleaseTag}/${osName}`;
128129

129130
autoUpdater.setFeedURL({
130131
provider: "generic",

desktop/renderer-app/src/components/AppUpgradeModal/index.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ import { observer } from "mobx-react-lite";
44
import React, { useEffect, useState } from "react";
55
import { ipcAsyncByMainWindow, ipcReceive, ipcReceiveRemove } from "../../utils/ipc";
66
import { useTranslation } from "react-i18next";
7+
import { update } from "flat-types";
78

89
export interface AppUpgradeModalProps {
9-
/** open modal when newVersion has truthy value */
10-
newVersion?: string;
11-
/** close modal */
10+
updateInfo:
11+
| (update.UpdateCheckInfo & {
12+
hasNewVersion: true;
13+
})
14+
| null;
1215
onClose: () => void;
1316
}
1417

1518
export const AppUpgradeModal = observer<AppUpgradeModalProps>(function AppUpgradeModal({
16-
newVersion,
19+
updateInfo,
1720
onClose,
1821
}) {
1922
const { t } = useTranslation();
@@ -22,7 +25,7 @@ export const AppUpgradeModal = observer<AppUpgradeModalProps>(function AppUpgrad
2225
const [upgradeFail, setUpgradeFail] = useState(false);
2326

2427
useEffect(() => {
25-
if (showUpgradeProgress) {
28+
if (showUpgradeProgress && updateInfo !== null) {
2629
ipcReceive("update-progress", args => {
2730
if (args.status) {
2831
setUpgradePercent(args.percent);
@@ -31,12 +34,14 @@ export const AppUpgradeModal = observer<AppUpgradeModalProps>(function AppUpgrad
3134
}
3235
});
3336

34-
ipcAsyncByMainWindow("start-update", undefined);
37+
ipcAsyncByMainWindow("start-update", {
38+
prereleaseTag: updateInfo.prereleaseTag,
39+
});
3540
}
3641
return () => {
3742
ipcReceiveRemove("update-progress");
3843
};
39-
}, [showUpgradeProgress]);
44+
}, [showUpgradeProgress, updateInfo]);
4045

4146
const renderModalTitle = (): React.ReactNode => {
4247
return <div className="app-upgrade-modal-title">{t("version-updates")}</div>;
@@ -58,7 +63,7 @@ export const AppUpgradeModal = observer<AppUpgradeModalProps>(function AppUpgrad
5863
maskClosable={false}
5964
title={renderModalTitle()}
6065
footer={[]}
61-
visible={Boolean(newVersion)}
66+
visible={updateInfo !== null}
6267
onCancel={cancelUpgrade}
6368
wrapClassName="app-upgrade-modal-container"
6469
closable={false}
@@ -68,11 +73,11 @@ export const AppUpgradeModal = observer<AppUpgradeModalProps>(function AppUpgrad
6873
<span className="app-upgrade-modal-font">
6974
{t("downloading")} ({upgradePercent.toFixed(2)}%)...
7075
</span>
71-
<div className="app-upgrade-modal-progress"></div>
76+
<div className="app-upgrade-modal-progress" />
7277
<div
7378
className="app-upgrade-active-progress"
7479
style={{ width: `${upgradePercent}%` }}
75-
></div>
80+
/>
7681
{upgradeFail && (
7782
<div>
7883
<span className="app-upgrade-modal-font">
@@ -89,7 +94,7 @@ export const AppUpgradeModal = observer<AppUpgradeModalProps>(function AppUpgrad
8994
) : (
9095
<div>
9196
<span className="app-upgrade-modal-font">
92-
{t("new-version-tips", { version: newVersion || " " })}
97+
{t("new-version-tips", { version: updateInfo?.version || " " })}
9398
</span>
9499
<div className="app-upgrade-modal-btn">
95100
<Button type="primary" onClick={upgradeStart}>

desktop/renderer-app/src/pages/HomePage/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { useLastLocation } from "react-router-last-location";
1010
import { shouldWindowCenter } from "./utils";
1111
import { constants } from "flat-types";
1212
import { MainPageLayoutContainer } from "../../components/MainPageLayoutContainer";
13-
import { AppUpgradeModal } from "../../components/AppUpgradeModal";
13+
import { AppUpgradeModal, AppUpgradeModalProps } from "../../components/AppUpgradeModal";
1414
import { useSafePromise } from "../../utils/hooks/lifecycle";
1515
import { runtime } from "../../utils/runtime";
1616
import { globalStore } from "../../stores/GlobalStore";
@@ -20,7 +20,7 @@ export type HomePageProps = {};
2020

2121
export const HomePage = observer<HomePageProps>(function HomePage() {
2222
const lastLocation = useLastLocation();
23-
const [newVersion, setNewVersion] = useState<string>();
23+
const [updateInfo, setUpdateInfo] = useState<AppUpgradeModalProps["updateInfo"]>(null);
2424
const sp = useSafePromise();
2525

2626
useEffect(() => {
@@ -44,7 +44,7 @@ export const HomePage = observer<HomePageProps>(function HomePage() {
4444
`[Auto Updater]: Remote Version "${data.version}", Local Version "${runtime.appVersion}"`,
4545
);
4646
if (data.version !== runtime.appVersion) {
47-
setNewVersion(data.version);
47+
setUpdateInfo(data);
4848
}
4949
}
5050
})
@@ -64,7 +64,7 @@ export const HomePage = observer<HomePageProps>(function HomePage() {
6464
<MainRoomHistoryPanel />
6565
</div>
6666
</div>
67-
<AppUpgradeModal newVersion={newVersion} onClose={() => setNewVersion(void 0)} />
67+
<AppUpgradeModal updateInfo={updateInfo} onClose={() => setUpdateInfo(null)} />
6868
</MainPageLayoutContainer>
6969
);
7070
});

desktop/renderer-app/src/pages/LoginPage/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { LoginDisposer } from "./utils";
99
import { githubLogin } from "./githubLogin";
1010
import { RouteNameType, usePushHistory } from "../../utils/routes";
1111
import { GlobalStoreContext } from "../../components/StoreProvider";
12-
import { AppUpgradeModal } from "../../components/AppUpgradeModal";
12+
import { AppUpgradeModal, AppUpgradeModalProps } from "../../components/AppUpgradeModal";
1313
import { runtime } from "../../utils/runtime";
1414
import { useSafePromise } from "../../utils/hooks/lifecycle";
1515
import { WeChatLogin } from "./WeChatLogin";
@@ -21,7 +21,7 @@ export const LoginPage = observer(function LoginPage() {
2121
const pushHistory = usePushHistory();
2222
const globalStore = useContext(GlobalStoreContext);
2323
const loginDisposer = useRef<LoginDisposer>();
24-
const [newVersion, setNewVersion] = useState<string>();
24+
const [updateInfo, setUpdateInfo] = useState<AppUpgradeModalProps["updateInfo"]>(null);
2525
const sp = useSafePromise();
2626

2727
useEffect(() => {
@@ -47,7 +47,7 @@ export const LoginPage = observer(function LoginPage() {
4747
`[Auto Updater]: Remote Version "${data.version}", Local Version "${runtime.appVersion}"`,
4848
);
4949
if (data.version !== runtime.appVersion) {
50-
setNewVersion(data.version);
50+
setUpdateInfo(data);
5151
}
5252
}
5353
})
@@ -85,7 +85,7 @@ export const LoginPage = observer(function LoginPage() {
8585
return (
8686
<div className="login-page-container">
8787
<LoginPanel onLogin={handleLogin} privacyURL={privacyURL} serviceURL={serviceURL} />
88-
<AppUpgradeModal newVersion={newVersion} onClose={() => setNewVersion(void 0)} />
88+
<AppUpgradeModal updateInfo={updateInfo} onClose={() => setUpdateInfo(null)} />
8989
</div>
9090
);
9191
});

desktop/renderer-app/src/pages/UserSettingPage/AboutPage/index.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@ import { UserSettingLayoutContainer } from "../UserSettingLayoutContainer";
77
import { Button, message } from "antd";
88
import { runtime } from "../../../utils/runtime";
99
import { ipcSyncByApp } from "../../../utils/ipc";
10-
import { AppUpgradeModal } from "../../../components/AppUpgradeModal";
10+
import { AppUpgradeModal, AppUpgradeModalProps } from "../../../components/AppUpgradeModal";
1111
import { useSafePromise } from "../../../utils/hooks/lifecycle";
1212
import { useTranslation } from "react-i18next";
1313

1414
export const AboutPage = (): React.ReactElement => {
1515
const { t } = useTranslation();
1616
const sp = useSafePromise();
17-
const [newVersion, setNewVersion] = useState<string>();
17+
const [updateInfo, setUpdateInfo] = useState<AppUpgradeModalProps["updateInfo"]>(null);
1818

1919
const checkUpgradeVersion = (): void => {
2020
void sp(ipcSyncByApp("get-update-info")).then(data => {
2121
if (!data.hasNewVersion || data.version === runtime.appVersion) {
2222
void message.info(t("latest-version-tips"));
2323
} else {
24-
setNewVersion(data.version);
24+
setUpdateInfo(data);
2525
}
2626
});
2727
};
@@ -38,11 +38,8 @@ export const AboutPage = (): React.ReactElement => {
3838
{t("check-updates")}
3939
</Button>
4040
</div>
41-
{/* <div className="about-page-bottom-container">
42-
<a href="">服务协议</a>|<a href="">隐私政策</a>|<a href="">GitHub</a>
43-
</div> */}
4441
</div>
45-
<AppUpgradeModal newVersion={newVersion} onClose={() => setNewVersion(void 0)} />
42+
<AppUpgradeModal updateInfo={updateInfo} onClose={() => setUpdateInfo(null)} />
4643
</UserSettingLayoutContainer>
4744
);
4845
};

desktop/renderer-app/src/utils/ipc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ export const ipcSyncByApp = <
6060
>(
6161
action: T,
6262
args?: U,
63-
): Promise<ReturnType<ipc.AppActionSync[T]>> => {
64-
return ipcRenderer.invoke(action, args);
63+
): ReturnType<ipc.AppActionSync[T]> => {
64+
return ipcRenderer.invoke(action, args) as any;
6565
};
6666

6767
export const ipcReceive = <T extends keyof ipc.EmitEvents, U extends ipc.EmitEvents[T]>(

desktop/renderer-app/src/utils/runtime.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@ export const runtime: Runtime.Type = {
1111
assetsPath: "",
1212
appVersion: "",
1313
downloadsDirectory: "",
14-
prereleaseTag: "stable",
1514
};

packages/flat-types/src/ipc/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Type as RuntimeType } from "../runtime";
2-
import type { UpdateCheckInfo } from "../update";
2+
import type { UpdateCheckInfo, PrereleaseTag } from "../update";
33

44
export type WindowActionAsync = {
55
"set-win-size": (args: {
@@ -18,7 +18,7 @@ export type WindowActionAsync = {
1818
"disable-window": (args: { disable: boolean }) => void;
1919
"set-title": (args: { title: string }) => void;
2020
"set-prevent-sleep": (args: { enable: boolean }) => void;
21-
"start-update": () => void;
21+
"start-update": (args: { prereleaseTag: PrereleaseTag }) => void;
2222
"cancel-update": () => void;
2323
};
2424

@@ -27,9 +27,9 @@ export type AppActionAsync = {
2727
};
2828

2929
export type AppActionSync = {
30-
"get-runtime": () => RuntimeType;
31-
"get-open-at-login": () => boolean;
32-
"get-update-info": () => UpdateCheckInfo;
30+
"get-runtime": () => Promise<RuntimeType>;
31+
"get-open-at-login": () => Promise<boolean>;
32+
"get-update-info": () => Promise<UpdateCheckInfo>;
3333
};
3434

3535
export interface EmitEvents {

0 commit comments

Comments
 (0)