feat: weixin login impl + sys-call reply support (v1.4.0)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,22 +3,17 @@
|
||||
/**
|
||||
* sys-call dispatcher.
|
||||
*
|
||||
* Routes incoming sys-call messages (action='request'|'cancel') from VPS
|
||||
* to the correct channel handler, and wires the emit callback so that
|
||||
* handler replies are sent back over the WebSocket.
|
||||
* Routes incoming sys-call messages from VPS to channel handlers.
|
||||
*
|
||||
* Message envelope (shared by all sys-call messages):
|
||||
* {
|
||||
* type: 'sys-call',
|
||||
* id: '<UUID>',
|
||||
* api: 'channel.weixin',
|
||||
* method: 'login',
|
||||
* action: 'request' | 'reply' | 'notify' | 'progress' | 'event' | 'finish' | 'cancel',
|
||||
* event: '',
|
||||
* code: 0,
|
||||
* message: '',
|
||||
* data: {}
|
||||
* }
|
||||
* Supported actions (incoming from VPS):
|
||||
* request — start a new task
|
||||
* cancel — abort a running task
|
||||
* reply — forward input to a running task (e.g. verify code)
|
||||
*
|
||||
* Handler interface:
|
||||
* handler[method](params) → { abort, onReply? }
|
||||
* abort() — called on cancel
|
||||
* onReply(msg) — called on reply (optional)
|
||||
*/
|
||||
|
||||
const log = require('./logger');
|
||||
@@ -28,14 +23,14 @@ const handlers = {
|
||||
'channel.weixin': require('./channel/weixin'),
|
||||
};
|
||||
|
||||
// ── running tasks: callId → abort() ──────────────────────────────────────────
|
||||
// ── running tasks: callId → { abort, onReply? } ───────────────────────────────
|
||||
const running = new Map();
|
||||
|
||||
/**
|
||||
* Handle an incoming sys-call message from VPS.
|
||||
*
|
||||
* @param {object} msg - parsed message object
|
||||
* @param {function} send - send(replyPayload) → forwards to VPS over WS;
|
||||
* @param {function} send - send(replyPayload) → forwarded to VPS over WS
|
||||
* caller prepends { type:'sys-call' }
|
||||
*/
|
||||
function handle(msg, send) {
|
||||
@@ -48,10 +43,10 @@ function handle(msg, send) {
|
||||
|
||||
// ── cancel ────────────────────────────────────────────────────────────────
|
||||
if (action === 'cancel') {
|
||||
const abort = running.get(callId);
|
||||
if (abort) {
|
||||
const task = running.get(callId);
|
||||
if (task) {
|
||||
log.info('sys-call', `cancel callId=${callId}`);
|
||||
try { abort(); } catch (e) { log.warn('sys-call', `abort error: ${e.message}`); }
|
||||
try { task.abort(); } catch (e) { log.warn('sys-call', `abort error: ${e.message}`); }
|
||||
running.delete(callId);
|
||||
} else {
|
||||
log.debug('sys-call', `cancel for unknown/finished callId=${callId}`);
|
||||
@@ -59,6 +54,18 @@ function handle(msg, send) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ── reply (e.g. verify code from frontend) ────────────────────────────────
|
||||
if (action === 'reply') {
|
||||
const task = running.get(callId);
|
||||
if (task && typeof task.onReply === 'function') {
|
||||
log.info('sys-call', `reply callId=${callId} event=${msg.event || ''}`);
|
||||
try { task.onReply(msg); } catch (e) { log.warn('sys-call', `onReply error: ${e.message}`); }
|
||||
} else {
|
||||
log.debug('sys-call', `reply for unknown/no-onReply callId=${callId}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ── request ───────────────────────────────────────────────────────────────
|
||||
if (action !== 'request') {
|
||||
log.warn('sys-call', `unexpected action=${action} callId=${callId}`);
|
||||
@@ -76,7 +83,7 @@ function handle(msg, send) {
|
||||
return;
|
||||
}
|
||||
|
||||
// emit: wraps handler replies, cleans up running map on finish
|
||||
// emit: merges envelope fields, cleans up running map on finish
|
||||
const emit = (payload) => {
|
||||
send({ id: callId, api, method, event: '', code: 0, message: '', ...payload });
|
||||
if (payload.action === 'finish') {
|
||||
@@ -87,9 +94,9 @@ function handle(msg, send) {
|
||||
|
||||
log.info('sys-call', `start api=${api} method=${method} callId=${callId}`);
|
||||
|
||||
let abort;
|
||||
let task;
|
||||
try {
|
||||
abort = handler[method]({ callId, ...(msg.data || {}), emit });
|
||||
task = handler[method]({ callId, ...(msg.data || {}), emit });
|
||||
} catch (e) {
|
||||
log.error('sys-call', `handler threw: ${e.message}`);
|
||||
send({
|
||||
@@ -100,8 +107,13 @@ function handle(msg, send) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof abort === 'function') {
|
||||
running.set(callId, abort);
|
||||
// Normalise: handler may return a function (abort only) or { abort, onReply }
|
||||
if (typeof task === 'function') {
|
||||
task = { abort: task };
|
||||
}
|
||||
|
||||
if (task && typeof task.abort === 'function') {
|
||||
running.set(callId, task);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user