stuff/matrix.js
2022-05-20 12:42:24 -07:00

189 lines
3.6 KiB
JavaScript

// wrapper around matrix-js-sdk for easier bot development
// inspired by discord.js
const EventEmitter = require("events");
const sdk = require("matrix-js-sdk");
class User {
constructor(client, id) {
this._client = client;
this.id = id;
}
get avatar() {
return this._client.getUser(this.id).avatarUrl;
}
get name() {
return this._client.getUser(this.id).displayName;
}
}
class Member extends User {
constructor(client, id, room) {
super(client, id);
this._room = room;
}
get room() {
return new Room(this._client, this._room);
}
get membership() {
return this.room._state.members[this.id].membership;
}
kick(reason) {
return this._client.kick(this._room, this.id, reason);
}
ban(reason) {
return this._client.ban(this._room, this.id, reason);
}
unban() {
return this._client.unban(this._room, this.id);
}
getPower() {
return this.room._state.members[this.id].powerLevel;
}
setPower(level) {
const event = this.room._state.getStateEvents('m.room.power_levels')[0];
return this._client.setPowerLevel(this.room.id, this.id, level, event);
}
}
class Room {
constructor(client, id) {
this._client = client;
this.id = id;
}
get _state() {
return this._client.getRoom(this.id).currentState;
}
get name() {
return this._client.getRoom(this.id).name;
}
send(content) {
return this._client.sendMessage(this.id, null, {
body: content,
});
}
invite(who) {
return this._client.invite(this.id, who instanceof User ? who.id : who);
}
join() {
return this._client.joinRoom(this.id);
}
setName(name) {
return this._client.setRoomName(this.id, name);
}
}
class Event {
constructor(client, event) {
this._client = client;
this._event = event;
}
get id() {
return this._event.getId();
}
get room() {
return new Room(this._client, this._event.getRoomId());
}
get author() {
return new Member(this._client, this._event.getSender(), this._event.getRoomId());
}
}
class Message extends Event {
constructor(client, event) {
super(client, event);
}
get content() {
return this._event.getContent().body;
}
redact() {
return this._client.redactEvent(this.room.id, this.id);
}
reply(content) {
return this._client.sendMessage(this.room.id, null, {
body: content,
"m.relates_to": { "m.in_reply_to": { event_id: this.id } },
});
}
relations() {
return this._client.fetchRelations(this.room.id, this.id);
}
}
class Bot extends EventEmitter {
constructor(options) {
super();
this._client = sdk.createClient(options);
this._ready = false;
this._client.on("Room.timeline", (event, room, toStartOfTimeline) => {
if (!this._ready) return;
if (toStartOfTimeline) return;
switch (event.getType()) {
case "m.room.message":
return this.emit("message", new Message(this._client, event));
};
});
this._client.on("Room.redaction", (event) => {
if (!this._ready) return;
return this.emit("redact", new Message(this._client, event));
});
this._client.on("RoomMember.membership", (event, member) => {
if (!this._ready) return;
return this.emit(member.membership, new Member(this._client, member.userId, member.roomId), new Room(this._client, member.roomId));
});
}
get id() {
return this._client.getUserId();
}
getRooms() {
return this._client
.getRooms()
.map(room => new Room(this._client, room.roomId));
}
getRoom(id) {
return new Room(this._client, id));
}
async start() {
this._client.once("sync", (state) => {
if(state === 'PREPARED') {
this._ready = true;
this.emit("ready");
} else {
throw "failed to start: " + state;
}
});
this._client.startClient({ initialSyncLimit: 0 });
}
}
module.exports = Bot;