更新 shenyan-app: 双桥通信 + 定制横幅推送 + APNs Key

- 双桥:Mac桥(Claude Code异步) + IDC桥(DeepSeek同步)
- 推送:自制定制Animated横幅 + 震动,替代Alert弹窗
- APNs:Key已创建(3VJ5X6V9Q8),桥端apns.js已写好
- 图标:已替换为定制图标
- BlurView/notifee:iOS 26兼容问题已回退
- 记忆库更新

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 01:49:32 +08:00
parent a61696f0a1
commit 5c50698d64
6 changed files with 287 additions and 99 deletions

View File

@@ -1,12 +1,14 @@
const http = require('http');
const fs = require('fs');
const path = require('path');
const { sendAPNs } = require('./apns');
const PORT = 3003;
const DATA_DIR = path.join(require('os').homedir(), '.shenyan-bridge');
const INBOX = path.join(DATA_DIR, 'inbox.jsonl');
const OUTBOX = path.join(DATA_DIR, 'outbox.jsonl');
const PUSHBOX = path.join(DATA_DIR, 'pushbox.jsonl');
const DEVICE_TOKEN_FILE = path.join(DATA_DIR, 'device-token.txt');
// ensure data dir and files
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
@@ -104,13 +106,44 @@ const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/push') {
let body = '';
req.on('data', c => body += c);
req.on('end', () => {
req.on('end', async () => {
try {
const { title, body: msgBody } = JSON.parse(body);
if (!title && !msgBody) return json(res, { error: 'empty' }, 400);
const entry = { id: getNextId(PUSHBOX), title: title || '', body: msgBody || '', time: Date.now() };
appendJSONL(PUSHBOX, entry);
json(res, { ok: true, id: entry.id });
// try APNs if device token is registered
let apnsOk = false;
try {
if (fs.existsSync(DEVICE_TOKEN_FILE)) {
const token = fs.readFileSync(DEVICE_TOKEN_FILE, 'utf-8').trim();
if (token) {
await sendAPNs(token, title, msgBody);
apnsOk = true;
}
}
} catch (e) {
console.error('APNs failed:', e.message);
}
json(res, { ok: true, id: entry.id, apns: apnsOk });
} catch (e) { json(res, { error: e.message }, 400); }
});
return;
}
// ---- app registers its device token ----
if (req.method === 'POST' && req.url === '/register-device') {
let body = '';
req.on('data', c => body += c);
req.on('end', () => {
try {
const { token } = JSON.parse(body);
if (!token) return json(res, { error: 'no token' }, 400);
fs.writeFileSync(DEVICE_TOKEN_FILE, token.trim(), 'utf-8');
console.log('device registered:', token.slice(0, 16) + '...');
json(res, { ok: true });
} catch (e) { json(res, { error: e.message }, 400); }
});
return;