mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(discord): use libopus structured decode errors
This commit is contained in:
8
extensions/discord/npm-shrinkwrap.json
generated
8
extensions/discord/npm-shrinkwrap.json
generated
@@ -10,7 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/voice": "0.19.2",
|
"@discordjs/voice": "0.19.2",
|
||||||
"discord-api-types": "0.38.48",
|
"discord-api-types": "0.38.48",
|
||||||
"libopus-wasm": "0.1.0",
|
"libopus-wasm": "0.2.0",
|
||||||
"typebox": "1.1.39",
|
"typebox": "1.1.39",
|
||||||
"undici": "8.3.0",
|
"undici": "8.3.0",
|
||||||
"ws": "8.21.0"
|
"ws": "8.21.0"
|
||||||
@@ -352,9 +352,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/libopus-wasm": {
|
"node_modules/libopus-wasm": {
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/libopus-wasm/-/libopus-wasm-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/libopus-wasm/-/libopus-wasm-0.2.0.tgz",
|
||||||
"integrity": "sha512-/aurGcAVgy0GcBEUzFaX9pm9qv7zYcy8W5hBXFiK+cyqOXAX4lOS6rlFogkY9CcSIajhjnuXyixsbmziSHCDMQ==",
|
"integrity": "sha512-x/2Gu1/C6L3IICY09zyfp984AWiOYjn53u4WfdY3yh+3KTzMN8Xkm77q3lenWMVIk5SnSzjGEkQT+VQMFHLBHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/voice": "0.19.2",
|
"@discordjs/voice": "0.19.2",
|
||||||
"discord-api-types": "0.38.48",
|
"discord-api-types": "0.38.48",
|
||||||
"libopus-wasm": "0.1.0",
|
"libopus-wasm": "0.2.0",
|
||||||
"typebox": "1.1.39",
|
"typebox": "1.1.39",
|
||||||
"undici": "8.3.0",
|
"undici": "8.3.0",
|
||||||
"ws": "8.21.0"
|
"ws": "8.21.0"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OpusError } from "libopus-wasm";
|
import { OpusError, OpusErrorCode } from "libopus-wasm";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import {
|
import {
|
||||||
analyzeVoiceReceiveError,
|
analyzeVoiceReceiveError,
|
||||||
@@ -33,7 +33,11 @@ describe("voice receive recovery", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("treats corrupt Opus packets as non-recoverable decode noise", () => {
|
it("treats corrupt Opus packets as non-recoverable decode noise", () => {
|
||||||
expect(analyzeVoiceReceiveError(new OpusError(-4, "not inspected", "decode"))).toEqual({
|
expect(
|
||||||
|
analyzeVoiceReceiveError(
|
||||||
|
new OpusError(OpusErrorCode.InvalidPacket, "not inspected", "decode"),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
message: "not inspected",
|
message: "not inspected",
|
||||||
isAbortLike: false,
|
isAbortLike: false,
|
||||||
isDecodeCorruption: true,
|
isDecodeCorruption: true,
|
||||||
@@ -42,6 +46,23 @@ describe("voice receive recovery", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("treats structurally equivalent Opus errors as decode corruption", () => {
|
||||||
|
const analysis = analyzeVoiceReceiveError({
|
||||||
|
name: "OpusError",
|
||||||
|
message: "libopus decode failed (-4): corrupted stream",
|
||||||
|
code: OpusErrorCode.InvalidPacket,
|
||||||
|
codeName: "InvalidPacket",
|
||||||
|
operation: "decode",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(analysis).toMatchObject({
|
||||||
|
isAbortLike: false,
|
||||||
|
isDecodeCorruption: true,
|
||||||
|
shouldAttemptPassthrough: false,
|
||||||
|
countsAsDecryptFailure: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("does not classify corrupt Opus packet text without the Opus error contract", () => {
|
it("does not classify corrupt Opus packet text without the Opus error contract", () => {
|
||||||
expect(
|
expect(
|
||||||
analyzeVoiceReceiveError(new Error("libopus decode failed (-4): corrupted stream")),
|
analyzeVoiceReceiveError(new Error("libopus decode failed (-4): corrupted stream")),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OpusError } from "libopus-wasm";
|
import { OpusErrorCode, isOpusError } from "libopus-wasm";
|
||||||
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||||
|
|
||||||
const DECRYPT_FAILURE_WINDOW_MS = 30_000;
|
const DECRYPT_FAILURE_WINDOW_MS = 30_000;
|
||||||
@@ -6,7 +6,6 @@ const DECRYPT_FAILURE_RECONNECT_THRESHOLD = 3;
|
|||||||
const DECRYPT_FAILURE_MARKER = "DecryptionFailed(";
|
const DECRYPT_FAILURE_MARKER = "DecryptionFailed(";
|
||||||
const DAVE_PASSTHROUGH_DISABLED_MARKER = "UnencryptedWhenPassthroughDisabled";
|
const DAVE_PASSTHROUGH_DISABLED_MARKER = "UnencryptedWhenPassthroughDisabled";
|
||||||
const WASM_MEMORY_ACCESS_MARKER = "memory access out of bounds";
|
const WASM_MEMORY_ACCESS_MARKER = "memory access out of bounds";
|
||||||
const OPUS_INVALID_PACKET_CODE = -4;
|
|
||||||
|
|
||||||
export const DAVE_RECEIVE_PASSTHROUGH_INITIAL_EXPIRY_SECONDS = 30;
|
export const DAVE_RECEIVE_PASSTHROUGH_INITIAL_EXPIRY_SECONDS = 30;
|
||||||
export const DAVE_RECEIVE_PASSTHROUGH_REARM_EXPIRY_SECONDS = 15;
|
export const DAVE_RECEIVE_PASSTHROUGH_REARM_EXPIRY_SECONDS = 15;
|
||||||
@@ -85,8 +84,8 @@ function isAbortLikeReceiveError(err: unknown): boolean {
|
|||||||
|
|
||||||
function isOpusDecodeInvalidPacketError(err: unknown): boolean {
|
function isOpusDecodeInvalidPacketError(err: unknown): boolean {
|
||||||
return (
|
return (
|
||||||
err instanceof OpusError &&
|
isOpusError(err) &&
|
||||||
err.code === OPUS_INVALID_PACKET_CODE &&
|
err.code === OpusErrorCode.InvalidPacket &&
|
||||||
(err.operation === "decode" || err.operation === "decodeFloat")
|
(err.operation === "decode" || err.operation === "decodeFloat")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -678,8 +678,8 @@ importers:
|
|||||||
specifier: 0.38.48
|
specifier: 0.38.48
|
||||||
version: 0.38.48
|
version: 0.38.48
|
||||||
libopus-wasm:
|
libopus-wasm:
|
||||||
specifier: 0.1.0
|
specifier: 0.2.0
|
||||||
version: 0.1.0
|
version: 0.2.0
|
||||||
typebox:
|
typebox:
|
||||||
specifier: 1.1.39
|
specifier: 1.1.39
|
||||||
version: 1.1.39
|
version: 1.1.39
|
||||||
@@ -5541,8 +5541,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==}
|
resolution: {integrity: sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==}
|
||||||
engines: {node: '>=22.0.0'}
|
engines: {node: '>=22.0.0'}
|
||||||
|
|
||||||
libopus-wasm@0.1.0:
|
libopus-wasm@0.2.0:
|
||||||
resolution: {integrity: sha512-/aurGcAVgy0GcBEUzFaX9pm9qv7zYcy8W5hBXFiK+cyqOXAX4lOS6rlFogkY9CcSIajhjnuXyixsbmziSHCDMQ==}
|
resolution: {integrity: sha512-x/2Gu1/C6L3IICY09zyfp984AWiOYjn53u4WfdY3yh+3KTzMN8Xkm77q3lenWMVIk5SnSzjGEkQT+VQMFHLBHQ==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
libsignal@6.0.0:
|
libsignal@6.0.0:
|
||||||
@@ -11150,7 +11150,7 @@ snapshots:
|
|||||||
|
|
||||||
kysely@0.29.2: {}
|
kysely@0.29.2: {}
|
||||||
|
|
||||||
libopus-wasm@0.1.0: {}
|
libopus-wasm@0.2.0: {}
|
||||||
|
|
||||||
libsignal@6.0.0:
|
libsignal@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ minimumReleaseAgeExclude:
|
|||||||
- "basic-ftp"
|
- "basic-ftp"
|
||||||
- "baileys@7.0.0-rc13"
|
- "baileys@7.0.0-rc13"
|
||||||
- "hono"
|
- "hono"
|
||||||
- "libopus-wasm@0.1.0"
|
- "libopus-wasm@0.2.0"
|
||||||
- "libsignal@6.0.0"
|
- "libsignal@6.0.0"
|
||||||
- "openclaw"
|
- "openclaw"
|
||||||
- "protobufjs"
|
- "protobufjs"
|
||||||
|
|||||||
Reference in New Issue
Block a user