Add timeline pagination

This commit is contained in:
tezlm 2023-12-07 08:50:14 -08:00
parent 20b78d0bea
commit 14acca5b62
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
17 changed files with 175 additions and 37 deletions

8
dist/src/net.d.ts vendored
View file

@ -19,13 +19,13 @@ export declare class Network {
roomId: t.RoomId;
dir: "b" | "f";
limit?: number;
from: string;
from?: string;
to?: string;
}): Promise<t.MessagesResponse>;
fetchRelations(roomId: t.RoomId, eventId: t.EventId, opts: {
relType?: string;
eventType?: string;
limit?: string;
limit?: number;
dir: "b" | "f";
from?: string;
to?: string;
@ -34,8 +34,8 @@ export declare class Network {
from?: string;
limit?: number;
roomIds?: Array<t.RoomId>;
watching: boolean;
include: Array<t.IncludeThreads>;
watching?: boolean;
include?: Array<t.IncludeThreads>;
}): Promise<t.ThreadsResponse>;
fetchInbox(opts: {
roomIds?: Array<t.RoomId>;

8
dist/src/net.js vendored
View file

@ -91,7 +91,9 @@ export class Network {
});
}
async fetchMessages(opts) {
let path = `/_matrix/client/v3/rooms/${e(opts.roomId)}/messages?limit=${opts.limit || 50}&from=${e(opts.from)}&dir=${e(opts.dir)}`;
let path = `/_matrix/client/v3/rooms/${e(opts.roomId)}/messages?limit=${opts.limit || 50}&dir=${e(opts.dir)}`;
if (opts.from)
path += `&from=${e(opts.from)}`;
if (opts.to)
path += `&to=${e(opts.to)}`;
return this.fetch({ method: "GET", path });
@ -114,7 +116,7 @@ export class Network {
async fetchThreads(opts) {
return this.fetch({
method: "POST",
path: `/_matrix/client/v1/threads?limit=${opts.limit}${opts.from ? `&from=${e(opts.from)}` : ""}`,
path: `/_matrix/client/v1/threads?limit=${opts.limit || 50}${opts.from ? `&from=${e(opts.from)}` : ""}`,
body: {
watching: opts.watching,
room_ids: opts.roomIds,
@ -125,7 +127,7 @@ export class Network {
async fetchInbox(opts) {
return this.fetch({
method: "POST",
path: `/_matrix/client/v1/inbox?limit=${opts.limit}${opts.from ? `&from=${e(opts.from)}` : ""}`,
path: `/_matrix/client/v1/inbox?limit=${opts.limit || 50}${opts.from ? `&from=${e(opts.from)}` : ""}`,
body: {
filter: opts.filter,
room_ids: opts.roomIds,

2
dist/src/net.js.map vendored

File diff suppressed because one or more lines are too long

5
dist/src/room.d.ts vendored
View file

@ -1,8 +1,9 @@
import TypedEmitter from "typed-emitter";
import { ApiEphemeralEvent, SyncResponseRoom, Unreads } from "./api.js";
import { ApiEphemeralEvent, EventId, SyncResponseRoom, Unreads } from "./api.js";
import { Client } from "./client.js";
import { Event, StateEvent } from "./event.js";
import { TimelineSet } from "./timeline.js";
import { Thread } from "./thread.js";
type RoomEvents = {
timeline: (event: Event) => void;
ephemeral: (event: ApiEphemeralEvent) => void;
@ -20,6 +21,8 @@ export declare class Room extends Room_base {
id: string;
private state;
timelines: TimelineSet;
events: Map<EventId, Event>;
threads: Map<EventId, Thread>;
constructor(client: Client, id: string, data: SyncResponseRoom);
_merge(data: SyncResponseRoom): void;
getState(type: string, stateKey?: string): StateEvent | null;

16
dist/src/room.js vendored
View file

@ -44,6 +44,18 @@ export class Room extends EventEmitter {
writable: true,
value: void 0
});
Object.defineProperty(this, "events", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "threads", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
this.timelines = new TimelineSet(this);
this.timelines.live.prevBatch = data.prev_batch || null;
this._merge(data);
@ -71,12 +83,12 @@ export class Room extends EventEmitter {
getAllState(type) {
return [...this.state.get(type)?.values() ?? []];
}
// TODO: return event
// TODO: local echo, return event
async sendState(type, stateKey, content) {
// const { event_id } = await this.client.net.sendState(this.id, type, stateKey, content);
await this.client.net.sendState(this.id, type, stateKey, content);
}
// TODO: return event
// TODO: local echo(?), return event
async sendEvent(type, content) {
await this.client.net.sendEvent(this.id, type, nanoid(), content);
}

View file

@ -1 +1 @@
{"version":3,"file":"room.js","sourceRoot":"","sources":["../../src/room.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"room.js","sourceRoot":"","sources":["../../src/room.ts"],"names":[],"mappings":"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"}

View file

@ -10,6 +10,7 @@ declare const Thread_base: new () => TypedEmitter<ThreadEvents>;
export declare class Thread extends Thread_base {
baseEvent: Event;
room: Room;
timeline: null;
constructor(baseEvent: Event);
}
export {};

6
dist/src/thread.js vendored
View file

@ -14,6 +14,12 @@ export class Thread extends EventEmitter {
writable: true,
value: this.baseEvent.room
});
Object.defineProperty(this, "timeline", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
}
}
//# sourceMappingURL=thread.js.map

View file

@ -1 +1 @@
{"version":3,"file":"thread.js","sourceRoot":"","sources":["../../src/thread.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAclC,MAAM,OAAO,MAAO,SAAS,YAAgE;IAG3F,YAAmB,SAAgB;QACjC,KAAK,EAAE,CAAC;QADE;;;;mBAAO,SAAS;WAAO;QAF5B;;;;mBAAa,IAAI,CAAC,SAAS,CAAC,IAAI;WAAC;IAIxC,CAAC;CACF"}
{"version":3,"file":"thread.js","sourceRoot":"","sources":["../../src/thread.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAclC,MAAM,OAAO,MAAO,SAAS,YAAgE;IAI3F,YAAmB,SAAgB;QACjC,KAAK,EAAE,CAAC;QADE;;;;mBAAO,SAAS;WAAO;QAH5B;;;;mBAAa,IAAI,CAAC,SAAS,CAAC,IAAI;WAAC;QACjC;;;;mBAAiB,IAAI;WAAC;IAI7B,CAAC;CACF"}

View file

@ -16,7 +16,7 @@ export declare class RoomTimeline implements Timeline {
}
export declare class ThreadTimeline implements Timeline {
thread: Thread;
events: never[];
events: Array<Event>;
isLive: boolean;
prevBatch: string | null;
nextBatch: string | null;
@ -28,5 +28,6 @@ export declare class TimelineSet {
private timelines;
constructor(room: Room);
forEvent(eventId: EventId): Promise<RoomTimeline>;
paginate(timeline: Timeline, dir: "f" | "b", limit?: number): Promise<boolean>;
_appendEvents(events: Array<Event>): void;
}

66
dist/src/timeline.js vendored
View file

@ -116,13 +116,71 @@ export class TimelineSet {
return tl;
}
// Paginate a timeline for more events
// public paginate(timeline: Timeline, dir: "f" | "b", limit: number = 50) {
// throw "todo";
// }
// TODO: fuse two neighboring timelines together
async paginate(timeline, dir, limit = 50) {
const { net } = this.room.client;
if (timeline instanceof ThreadTimeline) {
const from = (dir === "f" ? timeline.nextBatch : timeline.prevBatch) || undefined;
if (!from)
return false;
const data = await net.fetchRelations(this.room.id, timeline.thread.baseEvent.id, {
dir,
from,
limit,
});
if (dir === "f") {
const events = data.chunk.map(raw => new Event(this.room, raw));
timeline.nextBatch = data.next_batch;
timeline.events.push(...events);
for (const event of events)
this.room.events.set(event.id, event);
}
else {
const events = data.chunk.map(raw => new Event(this.room, raw));
timeline.prevBatch = data.prev_batch;
timeline.events.push(...events);
for (const event of events)
this.room.events.set(event.id, event);
}
return true;
}
else if (timeline instanceof RoomTimeline) {
const from = (dir === "f" ? timeline.nextBatch : timeline.prevBatch) || undefined;
if (!from)
return false;
const data = await net.fetchMessages({
roomId: this.room.id,
dir,
limit,
from,
});
if (dir === "f") {
const events = data.chunk.map(raw => new Event(this.room, raw));
timeline.nextBatch = data.end;
timeline.events.push(...events);
for (const event of events)
this.room.events.set(event.id, event);
}
else {
const events = data.chunk.reverse().map(raw => new Event(this.room, raw));
timeline.prevBatch = data.end;
timeline.events.push(...events);
for (const event of events)
this.room.events.set(event.id, event);
}
return true;
}
else {
throw new Error("todo");
}
}
_appendEvents(events) {
// FIXME: merge timelines together
for (const event of events)
this.room.events.set(event.id, event);
for (const timeline of this.timelines) {
if (timeline.isLive)
// if (timeline.isLive) timeline.events.push(...events);
if (timeline.isLive && timeline instanceof RoomTimeline)
timeline.events.push(...events);
}
}

View file

@ -1 +1 @@
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/timeline.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAK7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAQnC,MAAM,OAAO,YAAY;IAOvB,YAAmB,IAAU;QAAjB;;;;mBAAO,IAAI;WAAM;QANtB;;;;mBAAuB,EAAE;WAAC;QAC1B;;;;mBAAkB,KAAK;WAAC;QAE/B;;;;mBAA2B,IAAI;WAAC;QAChC;;;;mBAA2B,IAAI;WAAC;IAIhC,CAAC;CAQF;AAED,MAAM,OAAO,cAAc;IAOzB,YAAmB,MAAc;QAArB;;;;mBAAO,MAAM;WAAQ;QAN1B;;;;mBAAS,EAAE;WAAC;QACZ;;;;mBAAkB,KAAK;WAAC;QAE/B;;;;mBAA2B,IAAI;WAAC;QAChC;;;;mBAA2B,IAAI;WAAC;IAEI,CAAC;CACtC;AAED,MAAM,OAAO,WAAW;IAItB,iEAAiE;IAEjE,YAAmB,IAAU;QAAjB;;;;mBAAO,IAAI;WAAM;QAL7B,uEAAuE;QAChE;;;;;WAAmB;QAClB;;;;mBAA2B,IAAI,GAAG,EAAE;WAAC;QAI3C,IAAI,CAAC,IAAI,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,0EAA0E;IAC1E,sFAAsF;IACtF,kBAAkB;IAClB,oCAAoC;IACpC,8CAA8C;IAC9C,kBAAkB;IAClB,IAAI;IAEJ,yCAAyC;IAClC,KAAK,CAAC,QAAQ,CAAC,OAAgB;QACpC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/E,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,aAAa;aAC9B,OAAO,EAAE;aACT,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aACvB,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;aAC5B,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACzC,EAAE,CAAC,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC;QAC7B,EAAE,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;QAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,sCAAsC;IACtC,4EAA4E;IAC5E,kBAAkB;IAClB,IAAI;IAEJ,aAAa,CAAC,MAAoB;QAChC,kCAAkC;QAClC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,QAAQ,CAAC,MAAM;gBAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF"}
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/timeline.ts"],"names":[],"mappings":"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"}

File diff suppressed because one or more lines are too long

View file

@ -102,8 +102,9 @@ export class Network {
});
}
public async fetchMessages(opts: { roomId: t.RoomId, dir: "b" | "f", limit?: number, from: string, to?: string }): Promise<t.MessagesResponse> {
let path = `/_matrix/client/v3/rooms/${e(opts.roomId)}/messages?limit=${opts.limit || 50}&from=${e(opts.from)}&dir=${e(opts.dir)}`;
public async fetchMessages(opts: { roomId: t.RoomId, dir: "b" | "f", limit?: number, from?: string, to?: string }): Promise<t.MessagesResponse> {
let path = `/_matrix/client/v3/rooms/${e(opts.roomId)}/messages?limit=${opts.limit || 50}&dir=${e(opts.dir)}`;
if (opts.from) path += `&from=${e(opts.from)}`;
if (opts.to) path += `&to=${e(opts.to)}`;
return this.fetch({ method: "GET", path });
}
@ -114,7 +115,7 @@ export class Network {
opts: {
relType?: string,
eventType?: string,
limit?: string,
limit?: number,
dir: "b" | "f",
from?: string,
to?: string,
@ -129,10 +130,10 @@ export class Network {
return this.fetch({ method: "GET", path });
}
public async fetchThreads(opts: { from?: string, limit?: number, roomIds?: Array<t.RoomId>, watching: boolean, include: Array<t.IncludeThreads> }): Promise<t.ThreadsResponse> {
public async fetchThreads(opts: { from?: string, limit?: number, roomIds?: Array<t.RoomId>, watching?: boolean, include?: Array<t.IncludeThreads> }): Promise<t.ThreadsResponse> {
return this.fetch({
method: "POST",
path: `/_matrix/client/v1/threads?limit=${opts.limit}${opts.from ? `&from=${e(opts.from)}`: ""}`,
path: `/_matrix/client/v1/threads?limit=${opts.limit || 50}${opts.from ? `&from=${e(opts.from)}`: ""}`,
body: {
watching: opts.watching,
room_ids: opts.roomIds,
@ -144,7 +145,7 @@ export class Network {
public async fetchInbox(opts: { roomIds?: Array<t.RoomId>, from?: string, filter?: t.InboxFilter, limit?: number }): Promise<t.InboxResponse> {
return this.fetch({
method: "POST",
path: `/_matrix/client/v1/inbox?limit=${opts.limit}${opts.from ? `&from=${e(opts.from)}`: ""}`,
path: `/_matrix/client/v1/inbox?limit=${opts.limit || 50}${opts.from ? `&from=${e(opts.from)}`: ""}`,
body: {
filter: opts.filter,
room_ids: opts.roomIds,

View file

@ -1,10 +1,11 @@
import EventEmitter from "events";
import TypedEmitter from "typed-emitter";
import { ApiEphemeralEvent, SyncResponseRoom, Unreads } from "./api.js";
import { ApiEphemeralEvent, EventId, SyncResponseRoom, Unreads } from "./api.js";
import { Client } from "./client.js";
import { Event, StateEvent } from "./event.js";
import { TimelineSet } from "./timeline.js";
import { nanoid } from "nanoid";
import { Thread } from "./thread.js";
type RoomEvents = {
// an event is appended to this room's live timeline
@ -31,6 +32,8 @@ export class Room extends (EventEmitter as unknown as new () => TypedEmitter<Roo
private state: Map<string, Map<string, StateEvent>> = new Map();
public timelines: TimelineSet;
public events: Map<EventId, Event> = new Map();
public threads: Map<EventId, Thread> = new Map();
// public members: Members;
/*
@ -83,13 +86,13 @@ room.unban(userid)
return [...this.state.get(type)?.values() ?? []];
}
// TODO: return event
// TODO: local echo, return event
async sendState(type: string, stateKey: string, content: any) {
// const { event_id } = await this.client.net.sendState(this.id, type, stateKey, content);
await this.client.net.sendState(this.id, type, stateKey, content);
}
// TODO: return event
// TODO: local echo(?), return event
async sendEvent(type: string, content: any) {
await this.client.net.sendEvent(this.id, type, nanoid(), content);
}

View file

@ -14,6 +14,7 @@ type ThreadEvents = {
export class Thread extends (EventEmitter as unknown as new () => TypedEmitter<ThreadEvents>) {
public room: Room = this.baseEvent.room;
public timeline: null = null;
constructor(public baseEvent: Event) {
super();

View file

@ -7,7 +7,12 @@ import { Event } from "./event.js";
import { Thread } from "./thread.js";
export interface Timeline {
// if this timeline is actively receiving new events
isLive: boolean,
// isPaginating: boolean,
// the events in this timeline
events: Array<Event>,
}
@ -18,9 +23,7 @@ export class RoomTimeline implements Timeline {
prevBatch: string | null = null;
nextBatch: string | null = null;
constructor(public room: Room) {
}
constructor(public room: Room) {}
// concat(other: RoomTimeline): RoomTimeline {
// if (this.events.length === 0) return other;
@ -31,7 +34,7 @@ export class RoomTimeline implements Timeline {
}
export class ThreadTimeline implements Timeline {
public events = [];
public events: Array<Event> = [];
public isLive: boolean = false;
prevBatch: string | null = null;
@ -76,14 +79,61 @@ export class TimelineSet {
}
// Paginate a timeline for more events
// public paginate(timeline: Timeline, dir: "f" | "b", limit: number = 50) {
// throw "todo";
// }
// TODO: fuse two neighboring timelines together
public async paginate(timeline: Timeline, dir: "f" | "b", limit: number = 50): Promise<boolean> {
const { net } = this.room.client;
if (timeline instanceof ThreadTimeline) {
const from = (dir === "f" ? timeline.nextBatch : timeline.prevBatch) || undefined;
if (!from) return false;
const data = await net.fetchRelations(this.room.id, timeline.thread.baseEvent.id, {
dir,
from,
limit,
});
if (dir === "f") {
const events = data.chunk.map(raw => new Event(this.room, raw));
timeline.nextBatch = data.next_batch;
timeline.events.push(...events);
for (const event of events) this.room.events.set(event.id, event);
} else {
const events = data.chunk.map(raw => new Event(this.room, raw));
timeline.prevBatch = data.prev_batch;
timeline.events.push(...events);
for (const event of events) this.room.events.set(event.id, event);
}
return true;
} else if (timeline instanceof RoomTimeline) {
const from = (dir === "f" ? timeline.nextBatch : timeline.prevBatch) || undefined;
if (!from) return false;
const data = await net.fetchMessages({
roomId: this.room.id,
dir,
limit,
from,
});
if (dir === "f") {
const events = data.chunk.map(raw => new Event(this.room, raw));
timeline.nextBatch = data.end;
timeline.events.push(...events);
for (const event of events) this.room.events.set(event.id, event);
} else {
const events = data.chunk.reverse().map(raw => new Event(this.room, raw));
timeline.prevBatch = data.end;
timeline.events.push(...events);
for (const event of events) this.room.events.set(event.id, event);
}
return true;
} else {
throw new Error("todo");
}
}
_appendEvents(events: Array<Event>) {
// FIXME: merge timelines together
for (const event of events) this.room.events.set(event.id, event);
for (const timeline of this.timelines) {
if (timeline.isLive) timeline.events.push(...events);
// if (timeline.isLive) timeline.events.push(...events);
if (timeline.isLive && timeline instanceof RoomTimeline) timeline.events.push(...events);
}
}
}