Fix threads and make timelines emitters
This commit is contained in:
parent
ac59e44ac5
commit
1e7daac4d5
19 changed files with 255 additions and 95 deletions
2
dist/src/client.d.ts
vendored
2
dist/src/client.d.ts
vendored
|
@ -39,7 +39,7 @@ interface CreateRoom {
|
|||
initialState?: Array<{
|
||||
type: string;
|
||||
content: any;
|
||||
stateKey: string;
|
||||
stateKey?: string;
|
||||
}>;
|
||||
version?: string;
|
||||
}
|
||||
|
|
3
dist/src/client.js
vendored
3
dist/src/client.js
vendored
|
@ -18,7 +18,7 @@ class Rooms extends Map {
|
|||
initial_state: options.initialState?.map(ev => ({
|
||||
type: ev.type,
|
||||
content: ev.content,
|
||||
state_key: ev.stateKey,
|
||||
state_key: ev.stateKey ?? "",
|
||||
})),
|
||||
creation_content: options.creationContent,
|
||||
});
|
||||
|
@ -111,6 +111,7 @@ export class Client extends EventEmitter {
|
|||
await this.conn.sync();
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
this.setState({ state: "error", reason: err });
|
||||
}
|
||||
}
|
||||
|
|
2
dist/src/client.js.map
vendored
2
dist/src/client.js.map
vendored
|
@ -1 +1 @@
|
|||
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
16
dist/src/room.d.ts
vendored
16
dist/src/room.d.ts
vendored
|
@ -22,7 +22,7 @@ export declare class Room extends Room_base {
|
|||
private state;
|
||||
timelines: TimelineSet;
|
||||
events: Map<EventId, Event>;
|
||||
threads: Map<EventId, Thread>;
|
||||
threads: RoomThreads;
|
||||
constructor(client: Client, id: string, data: SyncResponseRoom);
|
||||
_merge(data: SyncResponseRoom): void;
|
||||
getState(type: string, stateKey?: string): StateEvent | null;
|
||||
|
@ -32,6 +32,20 @@ export declare class Room extends Room_base {
|
|||
leave(reason?: string): Promise<void>;
|
||||
ack(eventId?: EventId): Promise<void>;
|
||||
}
|
||||
declare class RoomThreads extends Map<EventId, Thread> {
|
||||
room: Room;
|
||||
constructor(room: Room);
|
||||
fetch(eventId: EventId): Promise<Thread>;
|
||||
paginate(opts?: {
|
||||
from?: string;
|
||||
limit?: number;
|
||||
watching?: boolean;
|
||||
include?: Array<IncludeThreads>;
|
||||
}): Promise<{
|
||||
threads: Thread[];
|
||||
nextBatch: string | undefined;
|
||||
}>;
|
||||
}
|
||||
export declare class ThreadPaginator extends Map<EventId, Thread> {
|
||||
client: Client;
|
||||
rooms: Array<Room>;
|
||||
|
|
6
dist/src/room.js
vendored
6
dist/src/room.js
vendored
|
@ -43,7 +43,7 @@ export class Room extends EventEmitter {
|
|||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
value: new TimelineSet(this)
|
||||
});
|
||||
Object.defineProperty(this, "events", {
|
||||
enumerable: true,
|
||||
|
@ -55,11 +55,9 @@ export class Room extends EventEmitter {
|
|||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new Map()
|
||||
value: new RoomThreads(this)
|
||||
});
|
||||
this.timelines = new TimelineSet(this);
|
||||
this.timelines.live.prevBatch = data.prev_batch;
|
||||
this.threads = new RoomThreads(this);
|
||||
this._merge(data);
|
||||
}
|
||||
// should be private to only the library like pub(crate), but there's no way currently
|
||||
|
|
2
dist/src/room.js.map
vendored
2
dist/src/room.js.map
vendored
File diff suppressed because one or more lines are too long
5
dist/src/thread.d.ts
vendored
5
dist/src/thread.d.ts
vendored
|
@ -11,8 +11,11 @@ declare const Thread_base: new () => TypedEmitter<ThreadEvents>;
|
|||
export declare class Thread extends Thread_base {
|
||||
baseEvent: Event;
|
||||
room: Room;
|
||||
timeline: ThreadTimeline;
|
||||
id: string;
|
||||
participation: string;
|
||||
messageCount: number;
|
||||
latestEvent: Event;
|
||||
timeline: ThreadTimeline;
|
||||
constructor(baseEvent: Event);
|
||||
ack(eventId?: EventId): Promise<void>;
|
||||
}
|
||||
|
|
42
dist/src/thread.js
vendored
42
dist/src/thread.js
vendored
|
@ -1,7 +1,11 @@
|
|||
import EventEmitter from "events";
|
||||
import { Event } from "./event.js";
|
||||
import { ThreadTimeline } from "./timeline.js";
|
||||
export class Thread extends EventEmitter {
|
||||
constructor(baseEvent) {
|
||||
const threadRel = baseEvent.unsigned["m.relations"]?.["m.thread"];
|
||||
if (!threadRel)
|
||||
throw new Error("Tried to create a thread from a non-thread event!");
|
||||
super();
|
||||
Object.defineProperty(this, "baseEvent", {
|
||||
enumerable: true,
|
||||
|
@ -15,18 +19,44 @@ export class Thread extends EventEmitter {
|
|||
writable: true,
|
||||
value: this.baseEvent.room
|
||||
});
|
||||
Object.defineProperty(this, "timeline", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new ThreadTimeline(this)
|
||||
});
|
||||
Object.defineProperty(this, "id", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: this.baseEvent.id
|
||||
});
|
||||
Object.defineProperty(this, "participation", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: "participating"
|
||||
});
|
||||
Object.defineProperty(this, "messageCount", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "latestEvent", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
// @deprecated: Threads will have multiple timelines
|
||||
Object.defineProperty(this, "timeline", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new ThreadTimeline(this)
|
||||
});
|
||||
const latestRaw = threadRel.latest_event;
|
||||
const latestCached = this.room.events.get(latestRaw.event_id);
|
||||
const latestEvent = latestCached ?? new Event(this.room, latestRaw);
|
||||
if (!latestCached)
|
||||
this.room.events.set(latestEvent.id, latestEvent);
|
||||
this.latestEvent = latestEvent;
|
||||
this.messageCount = threadRel.count;
|
||||
}
|
||||
// // TODO: local echo(?), return event
|
||||
// async sendEvent(type: string, content: any) {
|
||||
|
|
2
dist/src/thread.js.map
vendored
2
dist/src/thread.js.map
vendored
|
@ -1 +1 @@
|
|||
{"version":3,"file":"thread.js","sourceRoot":"","sources":["../../src/thread.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAKlC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAU/C,MAAM,OAAO,MAAO,SAAS,YAAgE;IAK3F,YAAmB,SAAgB;QACjC,KAAK,EAAE,CAAC;QADE;;;;mBAAO,SAAS;WAAO;QAJ5B;;;;mBAAa,IAAI,CAAC,SAAS,CAAC,IAAI;WAAC;QACjC;;;;mBAA2B,IAAI,cAAc,CAAC,IAAI,CAAC;WAAC;QACpD;;;;mBAAK,IAAI,CAAC,SAAS,CAAC,EAAE;WAAC;IAI9B,CAAC;IAED,uCAAuC;IACvC,gDAAgD;IAChD,uEAAuE;IACvE,IAAI;IAEJ,sDAAsD;IACtD,sDAAsD;IACtD,IAAI;IAEJ,KAAK,CAAC,GAAG,CAAC,OAAiB;QACzB,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAC7B,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;SACnF,CAAC,CAAC;IACL,CAAC;CACF"}
|
||||
{"version":3,"file":"thread.js","sourceRoot":"","sources":["../../src/thread.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAIlC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAU/C,MAAM,OAAO,MAAO,SAAS,YAAgE;IAW3F,YAAmB,SAAgB;QACjC,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QAClE,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QAErF,KAAK,EAAE,CAAC;QAJE;;;;mBAAO,SAAS;WAAO;QAV5B;;;;mBAAa,IAAI,CAAC,SAAS,CAAC,IAAI;WAAC;QACjC;;;;mBAAK,IAAI,CAAC,SAAS,CAAC,EAAE;WAAC;QAEvB;;;;mBAAgB,eAAe;WAAC;QAChC;;;;;WAAqB;QACrB;;;;;WAAmB;QAE1B,oDAAoD;QAC7C;;;;mBAA2B,IAAI,cAAc,CAAC,IAAI,CAAC;WAAC;QAQzD,MAAM,SAAS,GAAG,SAAS,CAAC,YAAY,CAAC;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,YAAY,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACpE,IAAI,CAAC,YAAY;YAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QACrE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC;IACtC,CAAC;IAED,uCAAuC;IACvC,gDAAgD;IAChD,uEAAuE;IACvE,IAAI;IAEJ,sDAAsD;IACtD,sDAAsD;IACtD,IAAI;IAEJ,KAAK,CAAC,GAAG,CAAC,OAAiB;QACzB,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAC7B,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;SACnF,CAAC,CAAC;IACL,CAAC;CACF"}
|
25
dist/src/timeline.d.ts
vendored
25
dist/src/timeline.d.ts
vendored
|
@ -1,34 +1,44 @@
|
|||
import { EventId } from "./api.js";
|
||||
import { ApiEphemeralEvent, EventId } from "./api.js";
|
||||
import { Room } from "./room.js";
|
||||
import { Event } from "./event.js";
|
||||
import { Thread } from "./thread.js";
|
||||
export interface Timeline {
|
||||
import TypedEmitter from "typed-emitter";
|
||||
type TimelineEvents = {
|
||||
timelineUpdate: (batch: Array<Event>, toBeginning: boolean) => void;
|
||||
timelineAppend: (event: Event) => void;
|
||||
ephemeral: (event: ApiEphemeralEvent) => void;
|
||||
};
|
||||
export interface Timeline extends TypedEmitter<TimelineEvents> {
|
||||
isLive: boolean;
|
||||
isAtBeginning: boolean;
|
||||
isAtEnd: boolean;
|
||||
events: Array<Event>;
|
||||
getEvents(): Array<Event>;
|
||||
paginate(dir: "f" | "b", limit: number): Promise<boolean>;
|
||||
}
|
||||
export declare class RoomTimeline implements Timeline {
|
||||
declare const RoomTimeline_base: new () => TypedEmitter<TimelineEvents>;
|
||||
export declare class RoomTimeline extends RoomTimeline_base implements Timeline {
|
||||
room: Room;
|
||||
events: Array<Event>;
|
||||
isLive: boolean;
|
||||
isAtBeginning: boolean;
|
||||
isAtEnd: boolean;
|
||||
_events: Array<Event>;
|
||||
prevBatch: string | undefined;
|
||||
nextBatch: string | undefined;
|
||||
constructor(room: Room);
|
||||
getEvents(): Array<Event>;
|
||||
paginate(dir: "f" | "b", limit?: number): Promise<boolean>;
|
||||
}
|
||||
export declare class ThreadTimeline implements Timeline {
|
||||
declare const ThreadTimeline_base: new () => TypedEmitter<TimelineEvents>;
|
||||
export declare class ThreadTimeline extends ThreadTimeline_base implements Timeline {
|
||||
thread: Thread;
|
||||
events: Array<Event>;
|
||||
isLive: boolean;
|
||||
isAtBeginning: boolean;
|
||||
isAtEnd: boolean;
|
||||
_events: Array<Event>;
|
||||
prevBatch: string | undefined;
|
||||
nextBatch: string | undefined;
|
||||
constructor(thread: Thread);
|
||||
getEvents(): Array<Event>;
|
||||
paginate(dir: "f" | "b", limit?: number): Promise<boolean>;
|
||||
}
|
||||
export declare class TimelineSet {
|
||||
|
@ -39,3 +49,4 @@ export declare class TimelineSet {
|
|||
forEvent(eventId: EventId): Promise<RoomTimeline>;
|
||||
_appendEvents(events: Array<Event>): void;
|
||||
}
|
||||
export {};
|
||||
|
|
81
dist/src/timeline.js
vendored
81
dist/src/timeline.js
vendored
|
@ -1,19 +1,15 @@
|
|||
// Timelines are ordered sequences of events.
|
||||
import { Event } from "./event.js";
|
||||
export class RoomTimeline {
|
||||
import EventEmitter from "events";
|
||||
export class RoomTimeline extends EventEmitter {
|
||||
constructor(room) {
|
||||
super();
|
||||
Object.defineProperty(this, "room", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: room
|
||||
});
|
||||
Object.defineProperty(this, "events", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: []
|
||||
});
|
||||
Object.defineProperty(this, "isLive", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
|
@ -32,6 +28,13 @@ export class RoomTimeline {
|
|||
writable: true,
|
||||
value: false
|
||||
});
|
||||
// These should be private, but typescript doesn't have "private to module"
|
||||
Object.defineProperty(this, "_events", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: []
|
||||
});
|
||||
Object.defineProperty(this, "prevBatch", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
|
@ -45,6 +48,9 @@ export class RoomTimeline {
|
|||
value: void 0
|
||||
});
|
||||
}
|
||||
getEvents() {
|
||||
return this._events;
|
||||
}
|
||||
async paginate(dir, limit = 50) {
|
||||
if (dir === "b" && this.isAtBeginning)
|
||||
return false;
|
||||
|
@ -65,9 +71,10 @@ export class RoomTimeline {
|
|||
else {
|
||||
this.isAtEnd = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events)
|
||||
this.room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, false);
|
||||
}
|
||||
else {
|
||||
const events = data.chunk.reverse().map(raw => new Event(this.room, raw));
|
||||
|
@ -77,27 +84,23 @@ export class RoomTimeline {
|
|||
else {
|
||||
this.isAtBeginning = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events)
|
||||
this.room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export class ThreadTimeline {
|
||||
export class ThreadTimeline extends EventEmitter {
|
||||
constructor(thread) {
|
||||
super();
|
||||
Object.defineProperty(this, "thread", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: thread
|
||||
});
|
||||
Object.defineProperty(this, "events", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: []
|
||||
});
|
||||
Object.defineProperty(this, "isLive", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
|
@ -116,6 +119,13 @@ export class ThreadTimeline {
|
|||
writable: true,
|
||||
value: false
|
||||
});
|
||||
// These should be private, but typescript doesn't have "private to module"
|
||||
Object.defineProperty(this, "_events", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: []
|
||||
});
|
||||
Object.defineProperty(this, "prevBatch", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
|
@ -129,6 +139,9 @@ export class ThreadTimeline {
|
|||
value: void 0
|
||||
});
|
||||
}
|
||||
getEvents() {
|
||||
return this._events;
|
||||
}
|
||||
async paginate(dir, limit = 50) {
|
||||
if (dir === "b" && this.isAtBeginning)
|
||||
return false;
|
||||
|
@ -137,6 +150,7 @@ export class ThreadTimeline {
|
|||
// This is to prevent someone from trying to paginate forwards,
|
||||
// then paginate backwards. The timeline will end up with events from
|
||||
// the beginning and end!
|
||||
// NOTE: deprecated?
|
||||
// FIXME: implement /context in threads
|
||||
if (dir === "f")
|
||||
this.isAtBeginning = true;
|
||||
|
@ -150,30 +164,31 @@ export class ThreadTimeline {
|
|||
limit,
|
||||
});
|
||||
if (dir === "f") {
|
||||
const events = data.chunk.map(raw => new Event(room, raw));
|
||||
const events = data.chunk.reverse().map(raw => new Event(room, raw));
|
||||
if (data.next_batch) {
|
||||
this.nextBatch = data.next_batch;
|
||||
}
|
||||
else {
|
||||
this.isAtEnd = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events)
|
||||
room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, false);
|
||||
return !!data.next_batch;
|
||||
}
|
||||
else {
|
||||
// FIXME: conduit doesn't implement ?dir=b
|
||||
const events = data.chunk.map(raw => new Event(room, raw));
|
||||
const events = data.chunk.reverse().map(raw => new Event(room, raw));
|
||||
if (data.prev_batch) {
|
||||
this.prevBatch = data.prev_batch;
|
||||
}
|
||||
else {
|
||||
this.isAtBeginning = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events)
|
||||
room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, true);
|
||||
return !!data.prev_batch;
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +230,7 @@ export class TimelineSet {
|
|||
async forEvent(eventId) {
|
||||
const context = await this.room.client.net.fetchContext(this.room.id, eventId);
|
||||
const tl = new RoomTimeline(this.room);
|
||||
tl.events = context.events_before
|
||||
tl._events = context.events_before
|
||||
.reverse()
|
||||
.concat([context.event])
|
||||
.concat(context.events_after)
|
||||
|
@ -230,19 +245,21 @@ export class TimelineSet {
|
|||
// thread, they need to be merged together
|
||||
for (const event of events) {
|
||||
this.room.events.set(event.id, event);
|
||||
this.live._events.push(...events);
|
||||
for (const event of events)
|
||||
this.live.emit("timelineAppend", event);
|
||||
const threadId = event.content["m.relations"]?.find((rel) => rel.rel_type === "m.thread")?.event_id;
|
||||
if (threadId) {
|
||||
const tl = this.room.threads.get(threadId)?.timeline;
|
||||
if (tl?.isLive)
|
||||
tl.events.push(event);
|
||||
const thread = this.room.threads.get(threadId);
|
||||
if (thread) {
|
||||
thread.messageCount++;
|
||||
thread.latestEvent = event;
|
||||
const tl = thread.timeline;
|
||||
if (tl?.isLive) {
|
||||
tl._events.push(event);
|
||||
tl.emit("timelineAppend", event);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const timeline of this.timelines) {
|
||||
// if (timeline.isLive) timeline.events.push(...events);
|
||||
if (timeline.isLive && timeline instanceof RoomTimeline)
|
||||
timeline.events.push(...events);
|
||||
// this.room.threads.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=timeline.js.map
|
2
dist/src/timeline.js.map
vendored
2
dist/src/timeline.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/tsconfig.tsbuildinfo
vendored
2
dist/tsconfig.tsbuildinfo
vendored
File diff suppressed because one or more lines are too long
32
docs/bot.ts
Normal file
32
docs/bot.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
// An example pong-pong bot
|
||||
// I might add a higher level bot sdk at some point, since this is relatively low level
|
||||
|
||||
import { Client, Event } from "../dist/src/index.js";
|
||||
|
||||
// Create the client
|
||||
const client = new Client({
|
||||
// baseUrl: "https://homeserver.tld",
|
||||
// deviceId: "something",
|
||||
// token: "supersecrettoken",
|
||||
// userId: "@userid:homeserver.tld",
|
||||
baseUrl: "http://localhost:6167",
|
||||
deviceId: "something",
|
||||
token: "9SWeOqc5g42O0fS3JesE43s1JujCDD8S",
|
||||
userId: "@asdf:localhost",
|
||||
});
|
||||
|
||||
function handleEvent(event: Event) {
|
||||
console.log("received event from " + event.sender);
|
||||
}
|
||||
|
||||
client.on("roomInit", (room) => room.timelines.live.on("timelineAppend", handleEvent));
|
||||
client.on("roomDeinit", (room) => room.timelines.live.on("timelineAppend", handleEvent));
|
||||
|
||||
client.lists.subscribe("allrooms", {
|
||||
ranges: [[0, 9999999]], // fetch all rooms
|
||||
required_state: [["m.room.name", ""]], // get their names
|
||||
timeline_limit: 1, // only listen to the last event (this will not trigger timelineAppend)
|
||||
});
|
||||
|
||||
// Start syncing and receiving events
|
||||
client.start();
|
|
@ -188,7 +188,7 @@ export interface MessagesResponse {
|
|||
}
|
||||
|
||||
export interface RelationsResponse {
|
||||
chunk: Array<ApiEvent>,
|
||||
chunk: Array<ApiEvent>, // always in reverse chronological order! (later relations are always first)
|
||||
next_batch: string,
|
||||
prev_batch: string,
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ type RoomList = {
|
|||
|
||||
interface CreateRoom {
|
||||
creationContent?: Record<string, any>,
|
||||
initialState?: Array<{ type: string, content: any, stateKey: string }>,
|
||||
initialState?: Array<{ type: string, content: any, stateKey?: string }>,
|
||||
version?: string,
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ class Rooms extends Map<string, Room> {
|
|||
initial_state: options.initialState?.map(ev => ({
|
||||
type: ev.type,
|
||||
content: ev.content,
|
||||
state_key: ev.stateKey,
|
||||
state_key: ev.stateKey ?? "",
|
||||
})),
|
||||
creation_content: options.creationContent,
|
||||
});
|
||||
|
@ -135,6 +135,7 @@ export class Client extends (EventEmitter as unknown as new () => TypedEmitter<C
|
|||
try {
|
||||
await this.conn.sync();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.setState({ state: "error", reason: err });
|
||||
}
|
||||
}
|
||||
|
|
10
src/room.ts
10
src/room.ts
|
@ -9,9 +9,11 @@ import { Thread } from "./thread.js";
|
|||
|
||||
type RoomEvents = {
|
||||
// an event is appended to this room's live timeline
|
||||
// @deprecated: use timelines.live
|
||||
timeline: (event: Event) => void,
|
||||
|
||||
// an ephemeral event was received
|
||||
// @deprecated: use timelines.live
|
||||
ephemeral: (event: ApiEphemeralEvent) => void,
|
||||
|
||||
// this room's state updated
|
||||
|
@ -31,9 +33,9 @@ export class Room extends (EventEmitter as unknown as new () => TypedEmitter<Roo
|
|||
// The (possibly incomplete) state of this room
|
||||
private state: Map<string, Map<string, StateEvent>> = new Map();
|
||||
|
||||
public timelines: TimelineSet;
|
||||
public timelines = new TimelineSet(this);
|
||||
public events: Map<EventId, Event> = new Map();
|
||||
public threads: Map<EventId, Thread> = new Map();
|
||||
public threads = new RoomThreads(this);
|
||||
// public members: Members;
|
||||
|
||||
/*
|
||||
|
@ -56,9 +58,7 @@ room.unban(userid)
|
|||
data: SyncResponseRoom,
|
||||
) {
|
||||
super();
|
||||
this.timelines = new TimelineSet(this);
|
||||
this.timelines.live.prevBatch = data.prev_batch;
|
||||
this.threads = new RoomThreads(this);
|
||||
this._merge(data);
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ class RoomThreads extends Map<EventId, Thread> {
|
|||
return thread;
|
||||
}
|
||||
|
||||
async paginate(opts: { from?: string, limit?: number, watching?: boolean, include?: Array<IncludeThreads> }) {
|
||||
async paginate(opts?: { from?: string, limit?: number, watching?: boolean, include?: Array<IncludeThreads> }) {
|
||||
const data = await this.room.client.net.fetchThreads({ ...opts, roomIds: [this.room.id] });
|
||||
const threads = data.chunk?.map(raw => new Thread(new Event(this.room, raw))) || [];
|
||||
for (const th of threads) this.set(th.id, th);
|
||||
|
|
|
@ -15,11 +15,27 @@ type ThreadEvents = {
|
|||
|
||||
export class Thread extends (EventEmitter as unknown as new () => TypedEmitter<ThreadEvents>) {
|
||||
public room: Room = this.baseEvent.room;
|
||||
public timeline: ThreadTimeline = new ThreadTimeline(this);
|
||||
public id = this.baseEvent.id;
|
||||
|
||||
public participation = "participating";
|
||||
public messageCount: number;
|
||||
public latestEvent: Event;
|
||||
|
||||
// @deprecated: Threads will have multiple timelines
|
||||
public timeline: ThreadTimeline = new ThreadTimeline(this);
|
||||
|
||||
constructor(public baseEvent: Event) {
|
||||
const threadRel = baseEvent.unsigned["m.relations"]?.["m.thread"];
|
||||
if (!threadRel) throw new Error("Tried to create a thread from a non-thread event!");
|
||||
|
||||
super();
|
||||
|
||||
const latestRaw = threadRel.latest_event;
|
||||
const latestCached = this.room.events.get(latestRaw.event_id);
|
||||
const latestEvent = latestCached ?? new Event(this.room, latestRaw);
|
||||
if (!latestCached) this.room.events.set(latestEvent.id, latestEvent);
|
||||
this.latestEvent = latestEvent;
|
||||
this.messageCount = threadRel.count;
|
||||
}
|
||||
|
||||
// // TODO: local echo(?), return event
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
// Timelines are ordered sequences of events.
|
||||
|
||||
// import TypedEventEmitter from "typed-emitter";
|
||||
import { EventId } from "./api.js";
|
||||
import { ApiEphemeralEvent, EventId } from "./api.js";
|
||||
import { Room } from "./room.js";
|
||||
import { Event } from "./event.js";
|
||||
import { Thread } from "./thread.js";
|
||||
import TypedEmitter from "typed-emitter";
|
||||
import EventEmitter from "events";
|
||||
|
||||
export interface Timeline {
|
||||
type TimelineEvents = {
|
||||
// This room's live timeline is updated, usually via pagination.
|
||||
timelineUpdate: (batch: Array<Event>, toBeginning: boolean) => void,
|
||||
|
||||
// An event is appended to this timeline.
|
||||
// Only fires if this timeline is live.
|
||||
timelineAppend: (event: Event) => void,
|
||||
|
||||
// An ephemeral event was received
|
||||
ephemeral: (event: ApiEphemeralEvent) => void,
|
||||
}
|
||||
|
||||
export interface Timeline extends TypedEmitter<TimelineEvents> {
|
||||
// if this timeline is actively receiving new events
|
||||
isLive: boolean,
|
||||
|
||||
|
@ -18,8 +32,8 @@ export interface Timeline {
|
|||
|
||||
// isPaginating: boolean,
|
||||
|
||||
// the events in this timeline
|
||||
events: Array<Event>,
|
||||
// Get the events in this timeline
|
||||
getEvents(): Array<Event>,
|
||||
|
||||
// Paginate a timeline for more events
|
||||
// TODO: fuse two neighboring timelines together
|
||||
|
@ -27,16 +41,23 @@ export interface Timeline {
|
|||
paginate(dir: "f" | "b", limit: number): Promise<boolean>;
|
||||
}
|
||||
|
||||
export class RoomTimeline implements Timeline {
|
||||
public events: Array<Event> = [];
|
||||
export class RoomTimeline extends (EventEmitter as unknown as new () => TypedEmitter<TimelineEvents>) implements Timeline {
|
||||
public isLive: boolean = false;
|
||||
public isAtBeginning: boolean = false;
|
||||
public isAtEnd: boolean = false;
|
||||
|
||||
// These should be private, but typescript doesn't have "private to module"
|
||||
_events: Array<Event> = [];
|
||||
prevBatch: string | undefined;
|
||||
nextBatch: string | undefined;
|
||||
|
||||
constructor(public room: Room) {}
|
||||
constructor(public room: Room) {
|
||||
super();
|
||||
}
|
||||
|
||||
public getEvents(): Array<Event> {
|
||||
return this._events;
|
||||
}
|
||||
|
||||
public async paginate(dir: "f" | "b", limit: number = 50): Promise<boolean> {
|
||||
if (dir === "b" && this.isAtBeginning) return false;
|
||||
|
@ -56,8 +77,9 @@ export class RoomTimeline implements Timeline {
|
|||
} else {
|
||||
this.isAtEnd = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events) this.room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, false);
|
||||
} else {
|
||||
const events = data.chunk.reverse().map(raw => new Event(this.room, raw));
|
||||
if (data.end) {
|
||||
|
@ -65,8 +87,9 @@ export class RoomTimeline implements Timeline {
|
|||
} else {
|
||||
this.isAtBeginning = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events) this.room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -79,16 +102,23 @@ export class RoomTimeline implements Timeline {
|
|||
// }
|
||||
}
|
||||
|
||||
export class ThreadTimeline implements Timeline {
|
||||
public events: Array<Event> = [];
|
||||
export class ThreadTimeline extends (EventEmitter as unknown as new () => TypedEmitter<TimelineEvents>) implements Timeline {
|
||||
public isLive: boolean = true; // FIXME: live threads
|
||||
public isAtBeginning: boolean = false;
|
||||
public isAtEnd: boolean = false;
|
||||
|
||||
// These should be private, but typescript doesn't have "private to module"
|
||||
_events: Array<Event> = [];
|
||||
prevBatch: string | undefined;
|
||||
nextBatch: string | undefined;
|
||||
|
||||
constructor(public thread: Thread) {}
|
||||
constructor(public thread: Thread) {
|
||||
super();
|
||||
}
|
||||
|
||||
public getEvents(): Array<Event> {
|
||||
return this._events;
|
||||
}
|
||||
|
||||
public async paginate(dir: "f" | "b", limit: number = 50): Promise<boolean> {
|
||||
if (dir === "b" && this.isAtBeginning) return false;
|
||||
|
@ -97,6 +127,7 @@ export class ThreadTimeline implements Timeline {
|
|||
// This is to prevent someone from trying to paginate forwards,
|
||||
// then paginate backwards. The timeline will end up with events from
|
||||
// the beginning and end!
|
||||
// NOTE: deprecated?
|
||||
// FIXME: implement /context in threads
|
||||
if (dir === "f") this.isAtBeginning = true;
|
||||
if (dir === "b") this.isAtEnd = true;
|
||||
|
@ -109,25 +140,26 @@ export class ThreadTimeline implements Timeline {
|
|||
limit,
|
||||
});
|
||||
if (dir === "f") {
|
||||
const events = data.chunk.map(raw => new Event(room, raw));
|
||||
const events = data.chunk.reverse().map(raw => new Event(room, raw));
|
||||
if (data.next_batch) {
|
||||
this.nextBatch = data.next_batch;
|
||||
} else {
|
||||
this.isAtEnd = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events) room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, false);
|
||||
return !!data.next_batch;
|
||||
} else {
|
||||
// FIXME: conduit doesn't implement ?dir=b
|
||||
const events = data.chunk.map(raw => new Event(room, raw));
|
||||
const events = data.chunk.reverse().map(raw => new Event(room, raw));
|
||||
if (data.prev_batch) {
|
||||
this.prevBatch = data.prev_batch;
|
||||
} else {
|
||||
this.isAtBeginning = true;
|
||||
}
|
||||
this.events.push(...events);
|
||||
this._events.push(...events);
|
||||
for (const event of events) room.events.set(event.id, event);
|
||||
this.emit("timelineUpdate", events, true);
|
||||
return !!data.prev_batch;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +189,7 @@ export class TimelineSet {
|
|||
public async forEvent(eventId: EventId): Promise<RoomTimeline> {
|
||||
const context = await this.room.client.net.fetchContext(this.room.id, eventId);
|
||||
const tl = new RoomTimeline(this.room);
|
||||
tl.events = context.events_before
|
||||
tl._events = context.events_before
|
||||
.reverse()
|
||||
.concat([context.event])
|
||||
.concat(context.events_after)
|
||||
|
@ -173,17 +205,22 @@ export class TimelineSet {
|
|||
// thread, they need to be merged together
|
||||
for (const event of events) {
|
||||
this.room.events.set(event.id, event);
|
||||
const threadId = event.content["m.relations"]?.find((rel: any) => rel.rel_type === "m.thread")?.event_id;
|
||||
if (threadId) {
|
||||
const tl = this.room.threads.get(threadId)?.timeline;
|
||||
if (tl?.isLive) tl.events.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
for (const timeline of this.timelines) {
|
||||
// if (timeline.isLive) timeline.events.push(...events);
|
||||
if (timeline.isLive && timeline instanceof RoomTimeline) timeline.events.push(...events);
|
||||
// this.room.threads.get()
|
||||
this.live._events.push(...events);
|
||||
for (const event of events) this.live.emit("timelineAppend", event);
|
||||
|
||||
const threadId = event.content["m.relations"]?.find((rel: any) => rel.rel_type === "m.thread")?.event_id;
|
||||
const thread = this.room.threads.get(threadId);
|
||||
if (thread) {
|
||||
thread.messageCount++;
|
||||
thread.latestEvent = event;
|
||||
|
||||
const tl = thread.timeline;
|
||||
if (tl?.isLive) {
|
||||
tl._events.push(event);
|
||||
tl.emit("timelineAppend", event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue