mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
refactor(matrix): dedupe action limit and pin/reaction helpers
This commit is contained in:
6
extensions/matrix/src/matrix/actions/limits.ts
Normal file
6
extensions/matrix/src/matrix/actions/limits.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export function resolveMatrixActionLimit(raw: unknown, fallback: number): number {
|
||||
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
||||
return fallback;
|
||||
}
|
||||
return Math.max(1, Math.floor(raw));
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { resolveMatrixRoomId, sendMessageMatrix } from "../send.js";
|
||||
import { resolveActionClient } from "./client.js";
|
||||
import { resolveMatrixActionLimit } from "./limits.js";
|
||||
import { summarizeMatrixRawEvent } from "./summary.js";
|
||||
import {
|
||||
EventType,
|
||||
@@ -95,10 +96,7 @@ export async function readMatrixMessages(
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
const limit =
|
||||
typeof opts.limit === "number" && Number.isFinite(opts.limit)
|
||||
? Math.max(1, Math.floor(opts.limit))
|
||||
: 20;
|
||||
const limit = resolveMatrixActionLimit(opts.limit, 20);
|
||||
const token = opts.before?.trim() || opts.after?.trim() || undefined;
|
||||
const dir = opts.after ? "f" : "b";
|
||||
// @vector-im/matrix-bot-sdk uses doRequest for room messages
|
||||
|
||||
@@ -4,28 +4,52 @@ import { fetchEventSummary, readPinnedEvents } from "./summary.js";
|
||||
import {
|
||||
EventType,
|
||||
type MatrixActionClientOpts,
|
||||
type MatrixActionClient,
|
||||
type MatrixMessageSummary,
|
||||
type RoomPinnedEventsEventContent,
|
||||
} from "./types.js";
|
||||
|
||||
type ActionClient = MatrixActionClient["client"];
|
||||
|
||||
async function withResolvedPinRoom<T>(
|
||||
roomId: string,
|
||||
opts: MatrixActionClientOpts,
|
||||
run: (client: ActionClient, resolvedRoom: string) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
return await run(client, resolvedRoom);
|
||||
} finally {
|
||||
if (stopOnDone) {
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateMatrixPins(
|
||||
roomId: string,
|
||||
messageId: string,
|
||||
opts: MatrixActionClientOpts,
|
||||
update: (current: string[]) => string[],
|
||||
): Promise<{ pinned: string[] }> {
|
||||
return await withResolvedPinRoom(roomId, opts, async (client, resolvedRoom) => {
|
||||
const current = await readPinnedEvents(client, resolvedRoom);
|
||||
const next = update(current);
|
||||
const payload: RoomPinnedEventsEventContent = { pinned: next };
|
||||
await client.sendStateEvent(resolvedRoom, EventType.RoomPinnedEvents, "", payload);
|
||||
return { pinned: next };
|
||||
});
|
||||
}
|
||||
|
||||
export async function pinMatrixMessage(
|
||||
roomId: string,
|
||||
messageId: string,
|
||||
opts: MatrixActionClientOpts = {},
|
||||
): Promise<{ pinned: string[] }> {
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
const current = await readPinnedEvents(client, resolvedRoom);
|
||||
const next = current.includes(messageId) ? current : [...current, messageId];
|
||||
const payload: RoomPinnedEventsEventContent = { pinned: next };
|
||||
await client.sendStateEvent(resolvedRoom, EventType.RoomPinnedEvents, "", payload);
|
||||
return { pinned: next };
|
||||
} finally {
|
||||
if (stopOnDone) {
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
return await updateMatrixPins(roomId, messageId, opts, (current) =>
|
||||
current.includes(messageId) ? current : [...current, messageId],
|
||||
);
|
||||
}
|
||||
|
||||
export async function unpinMatrixMessage(
|
||||
@@ -33,28 +57,16 @@ export async function unpinMatrixMessage(
|
||||
messageId: string,
|
||||
opts: MatrixActionClientOpts = {},
|
||||
): Promise<{ pinned: string[] }> {
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
const current = await readPinnedEvents(client, resolvedRoom);
|
||||
const next = current.filter((id) => id !== messageId);
|
||||
const payload: RoomPinnedEventsEventContent = { pinned: next };
|
||||
await client.sendStateEvent(resolvedRoom, EventType.RoomPinnedEvents, "", payload);
|
||||
return { pinned: next };
|
||||
} finally {
|
||||
if (stopOnDone) {
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
return await updateMatrixPins(roomId, messageId, opts, (current) =>
|
||||
current.filter((id) => id !== messageId),
|
||||
);
|
||||
}
|
||||
|
||||
export async function listMatrixPins(
|
||||
roomId: string,
|
||||
opts: MatrixActionClientOpts = {},
|
||||
): Promise<{ pinned: string[]; events: MatrixMessageSummary[] }> {
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
return await withResolvedPinRoom(roomId, opts, async (client, resolvedRoom) => {
|
||||
const pinned = await readPinnedEvents(client, resolvedRoom);
|
||||
const events = (
|
||||
await Promise.all(
|
||||
@@ -68,9 +80,5 @@ export async function listMatrixPins(
|
||||
)
|
||||
).filter((event): event is MatrixMessageSummary => Boolean(event));
|
||||
return { pinned, events };
|
||||
} finally {
|
||||
if (stopOnDone) {
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { resolveMatrixRoomId } from "../send.js";
|
||||
import { resolveActionClient } from "./client.js";
|
||||
import { resolveMatrixActionLimit } from "./limits.js";
|
||||
import {
|
||||
EventType,
|
||||
RelationType,
|
||||
@@ -9,6 +10,23 @@ import {
|
||||
type ReactionEventContent,
|
||||
} from "./types.js";
|
||||
|
||||
function getReactionsPath(roomId: string, messageId: string): string {
|
||||
return `/_matrix/client/v1/rooms/${encodeURIComponent(roomId)}/relations/${encodeURIComponent(messageId)}/${RelationType.Annotation}/${EventType.Reaction}`;
|
||||
}
|
||||
|
||||
async function listReactionEvents(
|
||||
client: NonNullable<MatrixActionClientOpts["client"]>,
|
||||
roomId: string,
|
||||
messageId: string,
|
||||
limit: number,
|
||||
): Promise<MatrixRawEvent[]> {
|
||||
const res = (await client.doRequest("GET", getReactionsPath(roomId, messageId), {
|
||||
dir: "b",
|
||||
limit,
|
||||
})) as { chunk: MatrixRawEvent[] };
|
||||
return res.chunk;
|
||||
}
|
||||
|
||||
export async function listMatrixReactions(
|
||||
roomId: string,
|
||||
messageId: string,
|
||||
@@ -17,18 +35,10 @@ export async function listMatrixReactions(
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
const limit =
|
||||
typeof opts.limit === "number" && Number.isFinite(opts.limit)
|
||||
? Math.max(1, Math.floor(opts.limit))
|
||||
: 100;
|
||||
// @vector-im/matrix-bot-sdk uses doRequest for relations
|
||||
const res = (await client.doRequest(
|
||||
"GET",
|
||||
`/_matrix/client/v1/rooms/${encodeURIComponent(resolvedRoom)}/relations/${encodeURIComponent(messageId)}/${RelationType.Annotation}/${EventType.Reaction}`,
|
||||
{ dir: "b", limit },
|
||||
)) as { chunk: MatrixRawEvent[] };
|
||||
const limit = resolveMatrixActionLimit(opts.limit, 100);
|
||||
const chunk = await listReactionEvents(client, resolvedRoom, messageId, limit);
|
||||
const summaries = new Map<string, MatrixReactionSummary>();
|
||||
for (const event of res.chunk) {
|
||||
for (const event of chunk) {
|
||||
const content = event.content as ReactionEventContent;
|
||||
const key = content["m.relates_to"]?.key;
|
||||
if (!key) {
|
||||
@@ -62,17 +72,13 @@ export async function removeMatrixReactions(
|
||||
const { client, stopOnDone } = await resolveActionClient(opts);
|
||||
try {
|
||||
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
||||
const res = (await client.doRequest(
|
||||
"GET",
|
||||
`/_matrix/client/v1/rooms/${encodeURIComponent(resolvedRoom)}/relations/${encodeURIComponent(messageId)}/${RelationType.Annotation}/${EventType.Reaction}`,
|
||||
{ dir: "b", limit: 200 },
|
||||
)) as { chunk: MatrixRawEvent[] };
|
||||
const chunk = await listReactionEvents(client, resolvedRoom, messageId, 200);
|
||||
const userId = await client.getUserId();
|
||||
if (!userId) {
|
||||
return { removed: 0 };
|
||||
}
|
||||
const targetEmoji = opts.emoji?.trim();
|
||||
const toRemove = res.chunk
|
||||
const toRemove = chunk
|
||||
.filter((event) => event.sender === userId)
|
||||
.filter((event) => {
|
||||
if (!targetEmoji) {
|
||||
|
||||
Reference in New Issue
Block a user