desktop-pet-app 0.2.7 → 0.2.9
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.
|
Binary file
|
|
Binary file
|
package/out/main/index.js
CHANGED
|
@@ -23,11 +23,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
const electron = require("electron");
|
|
25
25
|
const node_path = require("node:path");
|
|
26
|
+
const node_fs = require("node:fs");
|
|
26
27
|
const path = require("path");
|
|
27
28
|
const os = require("os");
|
|
28
29
|
const node_crypto = require("node:crypto");
|
|
29
30
|
const node_http = require("node:http");
|
|
30
|
-
const node_fs = require("node:fs");
|
|
31
31
|
const node_os = require("node:os");
|
|
32
32
|
const crypto = require("crypto");
|
|
33
33
|
const WebSocket = require("ws");
|
|
@@ -66,7 +66,20 @@ function levelFromEnv() {
|
|
|
66
66
|
const v = (process.env.DESKTOP_PET_LOG_LEVEL ?? "info").toLowerCase();
|
|
67
67
|
return v === "debug" || v === "warn" || v === "error" ? v : "info";
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
function mainLogDirectory() {
|
|
70
|
+
return node_path.join(electron.app.getPath("userData"), "logs");
|
|
71
|
+
}
|
|
72
|
+
function writeMainLog(line) {
|
|
73
|
+
console.log(line);
|
|
74
|
+
try {
|
|
75
|
+
const directory = mainLogDirectory();
|
|
76
|
+
node_fs.mkdirSync(directory, { recursive: true });
|
|
77
|
+
node_fs.appendFileSync(node_path.join(directory, "main.log"), `${line}
|
|
78
|
+
`, "utf8");
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const logger = new Logger(levelFromEnv(), writeMainLog);
|
|
70
83
|
const PORT_FILE = process.env.DESKTOP_PET_PORT_FILE?.trim() || path.join(os.homedir(), ".desktop-pet-port");
|
|
71
84
|
const LOCAL_PET_PROTOCOL_VERSION = "1.0";
|
|
72
85
|
const LOCAL_PET_MAX_BODY_BYTES = 64 * 1024;
|
|
@@ -268,9 +281,11 @@ class PetManager {
|
|
|
268
281
|
pets = /* @__PURE__ */ new Map();
|
|
269
282
|
lastGreetAt = /* @__PURE__ */ new Map();
|
|
270
283
|
timer;
|
|
284
|
+
petsVisible = true;
|
|
271
285
|
register(id, win, skin, identity) {
|
|
272
286
|
this.pets.set(id, { id, win, skin, identity });
|
|
273
287
|
win.on("closed", () => this.pets.delete(id));
|
|
288
|
+
if (!this.petsVisible) win.hide();
|
|
274
289
|
if (!this.timer) this.timer = setInterval(() => this.checkProximity(), PROXIMITY_SCAN_MS);
|
|
275
290
|
logger.info("pet registered", { id, skin, total: this.pets.size });
|
|
276
291
|
}
|
|
@@ -282,6 +297,17 @@ class PetManager {
|
|
|
282
297
|
(pet) => !pet.win.isDestroyed() && pet.identity.kind === "primary"
|
|
283
298
|
);
|
|
284
299
|
}
|
|
300
|
+
arePetsVisible() {
|
|
301
|
+
return this.petsVisible;
|
|
302
|
+
}
|
|
303
|
+
setPetsVisible(visible) {
|
|
304
|
+
this.petsVisible = visible;
|
|
305
|
+
for (const pet of this.pets.values()) {
|
|
306
|
+
if (pet.win.isDestroyed()) continue;
|
|
307
|
+
if (visible) pet.win.showInactive();
|
|
308
|
+
else pet.win.hide();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
285
311
|
findRemoteFriend(username) {
|
|
286
312
|
const normalized = username.trim().toLowerCase();
|
|
287
313
|
return [...this.pets.values()].find(
|
|
@@ -1653,7 +1679,7 @@ async function fallbackChat(operationId) {
|
|
|
1653
1679
|
const REQUEST_TIMEOUT_MS = 6e3;
|
|
1654
1680
|
const DOWNLOAD_TIMEOUT_MS = 10 * 6e4;
|
|
1655
1681
|
const LEGACY_OFFICIAL_HTTP_HOST = "47.94.20.104";
|
|
1656
|
-
const
|
|
1682
|
+
const MAC_BUNDLE_ID = "com.xinshu.desktoppet";
|
|
1657
1683
|
let status = { kind: "idle" };
|
|
1658
1684
|
function updateCheckURL() {
|
|
1659
1685
|
const override = process.env.DESKTOP_PET_UPDATE_API?.trim();
|
|
@@ -1767,8 +1793,8 @@ async function installDownloadedUpdate() {
|
|
|
1767
1793
|
downloaded.artifactPath,
|
|
1768
1794
|
downloaded.update.sha256,
|
|
1769
1795
|
process.platform,
|
|
1770
|
-
|
|
1771
|
-
|
|
1796
|
+
process.execPath,
|
|
1797
|
+
JSON.stringify(restartArgumentsAfterUpdate())
|
|
1772
1798
|
], {
|
|
1773
1799
|
detached: true,
|
|
1774
1800
|
stdio: "ignore",
|
|
@@ -1783,11 +1809,8 @@ async function installDownloadedUpdate() {
|
|
|
1783
1809
|
function supportsInAppInstall() {
|
|
1784
1810
|
return electron.app.isPackaged || process.env.DESKTOP_PET_NPM_DISTRIBUTION === "1";
|
|
1785
1811
|
}
|
|
1786
|
-
function
|
|
1787
|
-
|
|
1788
|
-
return MAC_INSTALLED_APP_EXECUTABLE;
|
|
1789
|
-
}
|
|
1790
|
-
return process.execPath;
|
|
1812
|
+
function restartArgumentsAfterUpdate() {
|
|
1813
|
+
return !electron.app.isPackaged && process.argv[1] ? [process.argv[1]] : [];
|
|
1791
1814
|
}
|
|
1792
1815
|
async function saveAndHash(body, destination, onChunk) {
|
|
1793
1816
|
const hash = node_crypto.createHash("sha256");
|
|
@@ -1838,8 +1861,9 @@ const { dirname, join } = require('node:path')
|
|
|
1838
1861
|
const { execFile, spawn } = require('node:child_process')
|
|
1839
1862
|
const { promisify } = require('node:util')
|
|
1840
1863
|
|
|
1841
|
-
const [, , parentPidText, sourcePath, expectedSHA256, platform,
|
|
1864
|
+
const [, , parentPidText, sourcePath, expectedSHA256, platform, fallbackExecutable, fallbackArgsJSON] = process.argv
|
|
1842
1865
|
const parentPid = Number(parentPidText)
|
|
1866
|
+
const fallbackArgs = JSON.parse(fallbackArgsJSON || '[]')
|
|
1843
1867
|
const run = promisify(execFile)
|
|
1844
1868
|
|
|
1845
1869
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
@@ -1853,10 +1877,21 @@ const sha256 = (path) => new Promise((resolve, reject) => {
|
|
|
1853
1877
|
input.on('error', reject)
|
|
1854
1878
|
input.on('end', () => resolve(hash.digest('hex')))
|
|
1855
1879
|
})
|
|
1856
|
-
const
|
|
1880
|
+
const restartFallback = () => {
|
|
1857
1881
|
const env = { ...process.env }
|
|
1858
1882
|
delete env.ELECTRON_RUN_AS_NODE
|
|
1859
|
-
spawn(
|
|
1883
|
+
const child = spawn(fallbackExecutable, fallbackArgs, { detached: true, stdio: 'ignore', env })
|
|
1884
|
+
child.on('error', () => undefined)
|
|
1885
|
+
child.unref()
|
|
1886
|
+
}
|
|
1887
|
+
const restartInstalledApp = async () => {
|
|
1888
|
+
// 安装器可能会保留已有应用的位置(开发构建尤其如此),不能假设它在 /Applications。
|
|
1889
|
+
// 让 LaunchServices 按 bundle ID 查找刚安装的实际应用位置。
|
|
1890
|
+
if (platform === 'darwin') {
|
|
1891
|
+
await run('/usr/bin/open', ['-b', '${MAC_BUNDLE_ID}'])
|
|
1892
|
+
return
|
|
1893
|
+
}
|
|
1894
|
+
restartFallback()
|
|
1860
1895
|
}
|
|
1861
1896
|
const shellQuote = (value) => "'" + value.replace(/'/g, "'\\''") + "'"
|
|
1862
1897
|
|
|
@@ -1885,11 +1920,20 @@ async function main() {
|
|
|
1885
1920
|
} catch (error) {
|
|
1886
1921
|
await fs.writeFile(join(dirname(sourcePath), 'last-install-error.log'), String(error)).catch(() => undefined)
|
|
1887
1922
|
} finally {
|
|
1888
|
-
|
|
1923
|
+
if (installed) {
|
|
1924
|
+
try {
|
|
1925
|
+
await restartInstalledApp()
|
|
1926
|
+
} catch (error) {
|
|
1927
|
+
await fs.writeFile(join(dirname(sourcePath), 'last-restart-error.log'), String(error)).catch(() => undefined)
|
|
1928
|
+
restartFallback()
|
|
1929
|
+
}
|
|
1930
|
+
} else {
|
|
1931
|
+
restartFallback()
|
|
1932
|
+
}
|
|
1889
1933
|
}
|
|
1890
1934
|
}
|
|
1891
1935
|
|
|
1892
|
-
main().catch(() =>
|
|
1936
|
+
main().catch(() => restartFallback())
|
|
1893
1937
|
`;
|
|
1894
1938
|
function installerExtension(releaseUrl) {
|
|
1895
1939
|
const pathname = new URL(releaseUrl).pathname.toLowerCase();
|
|
@@ -1999,6 +2043,7 @@ function createPetWindow(skin, options) {
|
|
|
1999
2043
|
const x = options.near?.x ?? workArea.x + workArea.width - W - 120;
|
|
2000
2044
|
const y = options.near?.y ?? workArea.y + workArea.height - H - 60;
|
|
2001
2045
|
const win = new electron.BrowserWindow({
|
|
2046
|
+
show: petManager.arePetsVisible(),
|
|
2002
2047
|
width: W,
|
|
2003
2048
|
height: H,
|
|
2004
2049
|
x,
|
|
@@ -2132,11 +2177,20 @@ function createPetWindow(skin, options) {
|
|
|
2132
2177
|
dispatch({ type: "bubble", text: result.message, ttl: 6e3 }, id);
|
|
2133
2178
|
}
|
|
2134
2179
|
},
|
|
2180
|
+
{
|
|
2181
|
+
label: "打开日志文件夹",
|
|
2182
|
+
click: () => {
|
|
2183
|
+
void electron.shell.openPath(mainLogDirectory()).then((error) => {
|
|
2184
|
+
if (error) dispatch({ type: "bubble", text: "无法打开日志文件夹", ttl: 6e3 }, id);
|
|
2185
|
+
});
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2135
2188
|
{
|
|
2136
2189
|
label: updateMenuLabel(),
|
|
2137
2190
|
submenu: updateMenuItems(id)
|
|
2138
2191
|
},
|
|
2139
2192
|
{ type: "separator" },
|
|
2193
|
+
{ label: "隐藏所有桌面宠物", click: () => petManager.setPetsVisible(false) },
|
|
2140
2194
|
...canSendAwayPet(identity) ? [{ label: "送走这只宠物", click: () => win.close() }] : [],
|
|
2141
2195
|
{ label: "退出", click: () => electron.app.quit() }
|
|
2142
2196
|
]);
|
|
@@ -3046,6 +3100,39 @@ async function dutyLoop(adapter) {
|
|
|
3046
3100
|
}
|
|
3047
3101
|
}
|
|
3048
3102
|
}
|
|
3103
|
+
const trayIcon1xPath = path.join(__dirname, "./chunks/tray-iconTemplate-BIK86F-0.png");
|
|
3104
|
+
const trayIcon2xPath = path.join(__dirname, "./chunks/tray-iconTemplate@2x-B19HpcaE.png");
|
|
3105
|
+
let tray;
|
|
3106
|
+
function createMenuBar() {
|
|
3107
|
+
if (process.platform !== "darwin" || tray) return;
|
|
3108
|
+
tray = new electron.Tray(createPetTemplateImage());
|
|
3109
|
+
tray.setToolTip("Desktop Pet");
|
|
3110
|
+
tray.on("click", showMenu);
|
|
3111
|
+
tray.on("right-click", showMenu);
|
|
3112
|
+
}
|
|
3113
|
+
function destroyMenuBar() {
|
|
3114
|
+
tray?.destroy();
|
|
3115
|
+
tray = void 0;
|
|
3116
|
+
}
|
|
3117
|
+
function showMenu() {
|
|
3118
|
+
tray?.popUpContextMenu(electron.Menu.buildFromTemplate([
|
|
3119
|
+
{ label: `Desktop Pet v${electron.app.getVersion()}`, enabled: false },
|
|
3120
|
+
{ type: "separator" },
|
|
3121
|
+
{
|
|
3122
|
+
label: petManager.arePetsVisible() ? "隐藏所有桌面宠物" : "显示所有桌面宠物",
|
|
3123
|
+
click: () => petManager.setPetsVisible(!petManager.arePetsVisible())
|
|
3124
|
+
},
|
|
3125
|
+
{ type: "separator" },
|
|
3126
|
+
{ label: "退出 Desktop Pet", click: () => electron.app.quit() }
|
|
3127
|
+
]));
|
|
3128
|
+
}
|
|
3129
|
+
function createPetTemplateImage() {
|
|
3130
|
+
let image = electron.nativeImage.createFromBuffer(node_fs.readFileSync(trayIcon2xPath), { scaleFactor: 2 });
|
|
3131
|
+
if (image.isEmpty()) image = electron.nativeImage.createFromPath(trayIcon1xPath);
|
|
3132
|
+
if (image.isEmpty()) throw new Error("无法加载 macOS 菜单栏图标");
|
|
3133
|
+
image.setTemplateImage(true);
|
|
3134
|
+
return image;
|
|
3135
|
+
}
|
|
3049
3136
|
const profileDirectory = process.env.DESKTOP_PET_PROFILE?.trim();
|
|
3050
3137
|
if (profileDirectory) {
|
|
3051
3138
|
electron.app.setPath("userData", node_path.resolve(profileDirectory));
|
|
@@ -3058,6 +3145,7 @@ if (!singleInstance) {
|
|
|
3058
3145
|
electron.app.on("second-instance", (_event, argv) => {
|
|
3059
3146
|
const callback = argv.find((value) => value.startsWith("desktop-pet://"));
|
|
3060
3147
|
if (callback) handleAccountCallback(callback);
|
|
3148
|
+
petManager.setPetsVisible(true);
|
|
3061
3149
|
ensurePrimaryPet();
|
|
3062
3150
|
});
|
|
3063
3151
|
}
|
|
@@ -3068,6 +3156,7 @@ function ensurePrimaryPet() {
|
|
|
3068
3156
|
});
|
|
3069
3157
|
}
|
|
3070
3158
|
electron.app.whenReady().then(async () => {
|
|
3159
|
+
createMenuBar();
|
|
3071
3160
|
await startAccountCallbackRouter();
|
|
3072
3161
|
startEventServer();
|
|
3073
3162
|
const activated = await activateStoredDevice().catch((err) => {
|
|
@@ -3092,9 +3181,10 @@ electron.app.whenReady().then(async () => {
|
|
|
3092
3181
|
logger.info("app started", { firstPet: id });
|
|
3093
3182
|
});
|
|
3094
3183
|
electron.app.on("window-all-closed", () => {
|
|
3095
|
-
electron.app.quit();
|
|
3184
|
+
if (process.platform !== "darwin") electron.app.quit();
|
|
3096
3185
|
});
|
|
3097
3186
|
electron.app.on("quit", () => {
|
|
3187
|
+
destroyMenuBar();
|
|
3098
3188
|
stopAccountCallbackRouter();
|
|
3099
3189
|
stopRelay();
|
|
3100
3190
|
stopP2PWindow();
|