desktop-pet-app 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/cli.js +2 -1
- package/out/main/index.js +63 -10
- package/package.json +1 -1
package/README.md
CHANGED
package/bin/cli.js
CHANGED
|
@@ -25,7 +25,8 @@ const appPath = path.join(__dirname, '..')
|
|
|
25
25
|
|
|
26
26
|
const child = spawn(electron, [appPath, ...process.argv.slice(2)], {
|
|
27
27
|
stdio: 'ignore',
|
|
28
|
-
detached: true
|
|
28
|
+
detached: true,
|
|
29
|
+
env: { ...process.env, DESKTOP_PET_NPM_DISTRIBUTION: '1' }
|
|
29
30
|
})
|
|
30
31
|
|
|
31
32
|
child.unref()
|
package/out/main/index.js
CHANGED
|
@@ -1653,6 +1653,7 @@ async function fallbackChat(operationId) {
|
|
|
1653
1653
|
const REQUEST_TIMEOUT_MS = 6e3;
|
|
1654
1654
|
const DOWNLOAD_TIMEOUT_MS = 10 * 6e4;
|
|
1655
1655
|
const LEGACY_OFFICIAL_HTTP_HOST = "47.94.20.104";
|
|
1656
|
+
const MAC_INSTALLED_APP_EXECUTABLE = "/Applications/Desktop Pet.app/Contents/MacOS/Desktop Pet";
|
|
1656
1657
|
let status = { kind: "idle" };
|
|
1657
1658
|
function updateCheckURL() {
|
|
1658
1659
|
const override = process.env.DESKTOP_PET_UPDATE_API?.trim();
|
|
@@ -1669,6 +1670,7 @@ function getUpdateStatus() {
|
|
|
1669
1670
|
return status;
|
|
1670
1671
|
}
|
|
1671
1672
|
async function checkForUpdates(currentVersion = electron.app.getVersion()) {
|
|
1673
|
+
if (status.kind === "downloading") return status;
|
|
1672
1674
|
status = { kind: "checking" };
|
|
1673
1675
|
try {
|
|
1674
1676
|
const endpoint = new URL(updateCheckURL());
|
|
@@ -1713,7 +1715,7 @@ function updateCheckHeaders(endpoint) {
|
|
|
1713
1715
|
async function downloadAvailableUpdate() {
|
|
1714
1716
|
const available = status.kind === "available" ? status.update : void 0;
|
|
1715
1717
|
if (!available) return status;
|
|
1716
|
-
status = { kind: "downloading", update: available };
|
|
1718
|
+
status = { kind: "downloading", update: available, downloadedBytes: 0 };
|
|
1717
1719
|
const updateDirectory = node_path.join(electron.app.getPath("userData"), "updates");
|
|
1718
1720
|
const artifactPath = node_path.join(updateDirectory, `desktop-pet-${available.version}${installerExtension(available.releaseUrl)}`);
|
|
1719
1721
|
const temporaryPath = `${artifactPath}.${node_crypto.randomUUID()}.download`;
|
|
@@ -1730,7 +1732,13 @@ async function downloadAvailableUpdate() {
|
|
|
1730
1732
|
if (response.url && new URL(response.url).protocol !== "https:") {
|
|
1731
1733
|
throw new Error("更新下载地址必须使用 HTTPS");
|
|
1732
1734
|
}
|
|
1733
|
-
const
|
|
1735
|
+
const totalBytes = parseContentLength(response.headers.get("content-length"));
|
|
1736
|
+
let downloadedBytes = 0;
|
|
1737
|
+
status = { kind: "downloading", update: available, downloadedBytes, totalBytes };
|
|
1738
|
+
const digest = await saveAndHash(response.body, temporaryPath, (chunkBytes) => {
|
|
1739
|
+
downloadedBytes += chunkBytes;
|
|
1740
|
+
status = { kind: "downloading", update: available, downloadedBytes, totalBytes };
|
|
1741
|
+
});
|
|
1734
1742
|
if (digest !== available.sha256) throw new Error("更新包校验失败,文件未安装");
|
|
1735
1743
|
await promises.rm(artifactPath, { force: true });
|
|
1736
1744
|
await moveFile(temporaryPath, artifactPath);
|
|
@@ -1747,7 +1755,7 @@ async function downloadAvailableUpdate() {
|
|
|
1747
1755
|
}
|
|
1748
1756
|
async function installDownloadedUpdate() {
|
|
1749
1757
|
if (status.kind !== "downloaded") return void 0;
|
|
1750
|
-
if (!
|
|
1758
|
+
if (!supportsInAppInstall()) throw new Error("当前运行方式不支持应用内安装,请使用正式发布版");
|
|
1751
1759
|
if (process.platform !== "darwin" && process.platform !== "win32") {
|
|
1752
1760
|
throw new Error("当前平台暂不支持应用内安装,请下载对应安装包更新");
|
|
1753
1761
|
}
|
|
@@ -1759,6 +1767,7 @@ async function installDownloadedUpdate() {
|
|
|
1759
1767
|
downloaded.artifactPath,
|
|
1760
1768
|
downloaded.update.sha256,
|
|
1761
1769
|
process.platform,
|
|
1770
|
+
restartExecutableAfterUpdate(),
|
|
1762
1771
|
process.execPath
|
|
1763
1772
|
], {
|
|
1764
1773
|
detached: true,
|
|
@@ -1771,11 +1780,21 @@ async function installDownloadedUpdate() {
|
|
|
1771
1780
|
electron.app.quit();
|
|
1772
1781
|
return downloaded.update;
|
|
1773
1782
|
}
|
|
1774
|
-
|
|
1783
|
+
function supportsInAppInstall() {
|
|
1784
|
+
return electron.app.isPackaged || process.env.DESKTOP_PET_NPM_DISTRIBUTION === "1";
|
|
1785
|
+
}
|
|
1786
|
+
function restartExecutableAfterUpdate() {
|
|
1787
|
+
if (!electron.app.isPackaged && process.env.DESKTOP_PET_NPM_DISTRIBUTION === "1" && process.platform === "darwin") {
|
|
1788
|
+
return MAC_INSTALLED_APP_EXECUTABLE;
|
|
1789
|
+
}
|
|
1790
|
+
return process.execPath;
|
|
1791
|
+
}
|
|
1792
|
+
async function saveAndHash(body, destination, onChunk) {
|
|
1775
1793
|
const hash = node_crypto.createHash("sha256");
|
|
1776
1794
|
const meter = new node_stream.Transform({
|
|
1777
1795
|
transform(chunk, _encoding, done) {
|
|
1778
1796
|
hash.update(chunk);
|
|
1797
|
+
onChunk(chunk.length);
|
|
1779
1798
|
done(null, chunk);
|
|
1780
1799
|
}
|
|
1781
1800
|
});
|
|
@@ -1786,6 +1805,23 @@ async function saveAndHash(body, destination) {
|
|
|
1786
1805
|
);
|
|
1787
1806
|
return hash.digest("hex");
|
|
1788
1807
|
}
|
|
1808
|
+
function parseContentLength(value) {
|
|
1809
|
+
if (!value) return void 0;
|
|
1810
|
+
const bytes = Number(value);
|
|
1811
|
+
return Number.isSafeInteger(bytes) && bytes > 0 ? bytes : void 0;
|
|
1812
|
+
}
|
|
1813
|
+
function downloadProgressText(progress) {
|
|
1814
|
+
if (progress.totalBytes) {
|
|
1815
|
+
const percent = Math.min(100, Math.floor(progress.downloadedBytes / progress.totalBytes * 100));
|
|
1816
|
+
return `${percent}%`;
|
|
1817
|
+
}
|
|
1818
|
+
return formatBytes(progress.downloadedBytes);
|
|
1819
|
+
}
|
|
1820
|
+
function formatBytes(bytes) {
|
|
1821
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1822
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1823
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1824
|
+
}
|
|
1789
1825
|
async function moveFile(source, destination) {
|
|
1790
1826
|
const { rename } = await import("node:fs/promises");
|
|
1791
1827
|
await rename(source, destination);
|
|
@@ -1802,7 +1838,7 @@ const { dirname, join } = require('node:path')
|
|
|
1802
1838
|
const { execFile, spawn } = require('node:child_process')
|
|
1803
1839
|
const { promisify } = require('node:util')
|
|
1804
1840
|
|
|
1805
|
-
const [, , parentPidText, sourcePath, expectedSHA256, platform,
|
|
1841
|
+
const [, , parentPidText, sourcePath, expectedSHA256, platform, installedAppExecutable, fallbackExecutable] = process.argv
|
|
1806
1842
|
const parentPid = Number(parentPidText)
|
|
1807
1843
|
const run = promisify(execFile)
|
|
1808
1844
|
|
|
@@ -1817,7 +1853,11 @@ const sha256 = (path) => new Promise((resolve, reject) => {
|
|
|
1817
1853
|
input.on('error', reject)
|
|
1818
1854
|
input.on('end', () => resolve(hash.digest('hex')))
|
|
1819
1855
|
})
|
|
1820
|
-
const restart = () =>
|
|
1856
|
+
const restart = (executable) => {
|
|
1857
|
+
const env = { ...process.env }
|
|
1858
|
+
delete env.ELECTRON_RUN_AS_NODE
|
|
1859
|
+
spawn(executable, [], { detached: true, stdio: 'ignore', env }).unref()
|
|
1860
|
+
}
|
|
1821
1861
|
const shellQuote = (value) => "'" + value.replace(/'/g, "'\\''") + "'"
|
|
1822
1862
|
|
|
1823
1863
|
async function install() {
|
|
@@ -1837,17 +1877,19 @@ async function install() {
|
|
|
1837
1877
|
async function main() {
|
|
1838
1878
|
while (parentIsRunning()) await sleep(200)
|
|
1839
1879
|
|
|
1880
|
+
let installed = false
|
|
1840
1881
|
try {
|
|
1841
1882
|
if (await sha256(sourcePath) !== expectedSHA256) throw new Error('downloaded update hash changed')
|
|
1842
1883
|
await install()
|
|
1884
|
+
installed = true
|
|
1843
1885
|
} catch (error) {
|
|
1844
1886
|
await fs.writeFile(join(dirname(sourcePath), 'last-install-error.log'), String(error)).catch(() => undefined)
|
|
1845
1887
|
} finally {
|
|
1846
|
-
restart()
|
|
1888
|
+
restart(installed ? installedAppExecutable : fallbackExecutable)
|
|
1847
1889
|
}
|
|
1848
1890
|
}
|
|
1849
1891
|
|
|
1850
|
-
main().catch(() => restart())
|
|
1892
|
+
main().catch(() => restart(fallbackExecutable))
|
|
1851
1893
|
`;
|
|
1852
1894
|
function installerExtension(releaseUrl) {
|
|
1853
1895
|
const pathname = new URL(releaseUrl).pathname.toLowerCase();
|
|
@@ -2115,7 +2157,9 @@ function createPetWindow(skin, options) {
|
|
|
2115
2157
|
function updateMenuLabel() {
|
|
2116
2158
|
const status2 = getUpdateStatus();
|
|
2117
2159
|
if (status2.kind === "available") return `软件更新(v${status2.update.version} 可下载)`;
|
|
2118
|
-
if (status2.kind === "downloading")
|
|
2160
|
+
if (status2.kind === "downloading") {
|
|
2161
|
+
return `软件更新(v${status2.update.version} 下载 ${downloadProgressText(status2)})`;
|
|
2162
|
+
}
|
|
2119
2163
|
if (status2.kind === "downloaded") return `软件更新(v${status2.update.version} 已下载)`;
|
|
2120
2164
|
return "软件更新";
|
|
2121
2165
|
}
|
|
@@ -2131,6 +2175,12 @@ function updateMenuItems(petId) {
|
|
|
2131
2175
|
dispatch({ type: "bubble", text: `发现 v${result.update.version},可从“软件更新”安装`, ttl: 6e3 }, petId);
|
|
2132
2176
|
} else if (result.kind === "up-to-date") {
|
|
2133
2177
|
dispatch({ type: "bubble", text: "已经是最新版本啦", ttl: 4500 }, petId);
|
|
2178
|
+
} else if (result.kind === "downloading") {
|
|
2179
|
+
dispatch({
|
|
2180
|
+
type: "bubble",
|
|
2181
|
+
text: `v${result.update.version} 正在下载:${downloadProgressText(result)}`,
|
|
2182
|
+
ttl: 4500
|
|
2183
|
+
}, petId);
|
|
2134
2184
|
} else if (result.kind === "error") {
|
|
2135
2185
|
dispatch({ type: "bubble", text: result.message, ttl: 7e3 }, petId);
|
|
2136
2186
|
}
|
|
@@ -2154,7 +2204,10 @@ function updateMenuItems(petId) {
|
|
|
2154
2204
|
});
|
|
2155
2205
|
}
|
|
2156
2206
|
if (status2.kind === "downloading") {
|
|
2157
|
-
items.splice(1, 0, {
|
|
2207
|
+
items.splice(1, 0, {
|
|
2208
|
+
label: `正在下载 v${status2.update.version} · ${downloadProgressText(status2)}`,
|
|
2209
|
+
enabled: false
|
|
2210
|
+
});
|
|
2158
2211
|
}
|
|
2159
2212
|
if (status2.kind === "downloaded") {
|
|
2160
2213
|
items.splice(1, 0, {
|