From bd14b0a98ec1d381a9380a8e169993ea360968e2 Mon Sep 17 00:00:00 2001 From: DrSmoothl <1787882683@qq.com> Date: Fri, 30 Oct 2026 12:53:08 +0800 Subject: [PATCH] fix(protocol): report rejected card deliveries Surface delivery failures instead of reporting success for rejected image and text cards. Reject responses without a delivery result. Fixes #611 --- .../src/oidb-actions/contact-ark.ts | 11 ++++- .../oidb-services/contacts/send-tuwen-ark.ts | 19 +++++++- .../contacts/send-tuwen-ark.test.ts | 45 +++++++++++++++---- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/packages/proto-defs/src/oidb-actions/contact-ark.ts b/packages/proto-defs/src/oidb-actions/contact-ark.ts index ea2de673..74633c3d 100644 --- a/packages/proto-defs/src/oidb-actions/contact-ark.ts +++ b/packages/proto-defs/src/oidb-actions/contact-ark.ts @@ -8,7 +8,7 @@ // reads {1:bussness_error_code, 5:ark_json}. // Both return a server-built ark JSON string (the share card payload). -import type { pb, pb_optional, uint_32 } from '@snowluma/proton'; +import type { pb, pb_optional, pb_repeated, uint_32 } from '@snowluma/proton'; export interface OidbBuddyRecommendArkReq { uin?: pb<1, uint_32>; @@ -67,4 +67,11 @@ export interface Oidb0xdc2_34Req { meta?: pb<2, Oidb0xdc2Meta>; } -export interface Oidb0xdc2_34Resp {} +export interface Oidb0xdc2CardResult { + errorCode?: pb<4, uint_32>; + errorMessage?: pb<5, string>; +} + +export interface Oidb0xdc2_34Resp { + results?: pb_repeated<1, Oidb0xdc2CardResult>; +} diff --git a/packages/protocol/src/oidb-services/contacts/send-tuwen-ark.ts b/packages/protocol/src/oidb-services/contacts/send-tuwen-ark.ts index 475ae18a..43ca3c8e 100644 --- a/packages/protocol/src/oidb-services/contacts/send-tuwen-ark.ts +++ b/packages/protocol/src/oidb-services/contacts/send-tuwen-ark.ts @@ -10,7 +10,7 @@ import type { Oidb0xdc2_34Req, Oidb0xdc2_34Resp, } from '@snowluma/proto-defs/oidb-actions/contact-ark'; -import { invokeOidb, type OidbSender } from '../../oidb-service'; +import { invokeOidb, OidbError, type OidbSender } from '../../oidb-service'; const TUWEN_ARK_APPID = 100446242; @@ -54,7 +54,22 @@ export namespace SendTuwenArk { }, }); - export const deserialize = (_ctx: Deps, _body: Oidb0xdc2_34Resp): void => undefined; + export const deserialize = (_ctx: Deps, body: Oidb0xdc2_34Resp): void => { + if (!body.results?.length) { + throw new Error('send_tuwen_ark response has no delivery result'); + } + + for (const result of body.results) { + if (result.errorCode) { + throw new OidbError( + result.errorCode, + result.errorMessage ?? '', + command, + subCommand, + ); + } + } + }; export const encode = (env: OidbBase): Uint8Array => protobuf_encode>(env); diff --git a/packages/protocol/tests/oidb-services/contacts/send-tuwen-ark.test.ts b/packages/protocol/tests/oidb-services/contacts/send-tuwen-ark.test.ts index 43f1bc97..27e1ada8 100644 --- a/packages/protocol/tests/oidb-services/contacts/send-tuwen-ark.test.ts +++ b/packages/protocol/tests/oidb-services/contacts/send-tuwen-ark.test.ts @@ -1,19 +1,15 @@ import { describe, expect, it, vi } from 'vitest'; -import { protobuf_encode } from '@snowluma/proton'; -import type { OidbBase } from '@snowluma/proto-defs/oidb'; -import type { Oidb0xdc2_34Resp } from '@snowluma/proto-defs/oidb-actions/contact-ark'; import type { SendPacketResult } from '@snowluma/common/packet-sender'; import { SendTuwenArk } from '../../../src/oidb-services/contacts/send-tuwen-ark'; import { env, v, s, m } from '../_pb-oracle'; -function makeSender() { - const respEnv: OidbBase = { command: 0xdc2, subCommand: 34, body: {} }; +function makeSender(body = m(1, [...v(2, 10001), ...v(4, 0)])) { const r: SendPacketResult = { success: true, gotResponse: true, errorCode: 0, errorMessage: '', - responseData: Buffer.from(protobuf_encode>(respEnv)), + responseData: Buffer.from(env(0xdc2, 34, body, false), 'hex'), }; return { sendRawPacket: vi.fn(async () => r) }; } @@ -128,7 +124,40 @@ describe('SendTuwenArk namespace', () => { expect(Buffer.from(bytes).toString('hex')).toBe(env(0xdc2, 34, body, false)); }); - it('deserialize returns undefined (void response)', () => { - expect(SendTuwenArk.deserialize({} as any, {})).toBeUndefined(); + it('rejects a delivery refusal even when the outer envelope succeeds', async () => { + const sender = makeSender( + m(1, [ + ...v(1, 0), + ...v(2, 10001), + ...s(3, ''), + ...v(4, 901501), + ...s(5, 'imagent service_error:319_[oidb] rule type not match appid'), + ]), + ); + await expect( + SendTuwenArk.invoke(sender, { + targetId: 10001, + peerType: 0, + title: 'title', + desc: '', + summary: '', + jumpUrl: 'https://example.com', + previewUrl: '', + }), + ).rejects.toThrow(/901501.*rule type not match appid/); + }); + + it('checks every delivery result and requires an acknowledgement', () => { + const sender = makeSender(); + expect(() => SendTuwenArk.deserialize(sender, {})).toThrow('no delivery result'); + expect(() => SendTuwenArk.deserialize(sender, { results: [] })).toThrow( + 'no delivery result', + ); + expect(() => + SendTuwenArk.deserialize(sender, { + results: [{ errorCode: 0 }, { errorCode: 901501, errorMessage: 'refused' }], + }), + ).toThrow('refused'); + expect(SendTuwenArk.deserialize(sender, { results: [{}] })).toBeUndefined(); }); });