diff --git a/src/Channel.ts b/src/Channel.ts index 1e9c02c..758737b 100644 --- a/src/Channel.ts +++ b/src/Channel.ts @@ -1,15 +1,21 @@ +import axios from "axios"; +import { IRCUser } from "./IRCUser.js"; import { MatrixUser } from "./MatrixUser.js"; export class Channel { public name: string + // public matrixUsers: Map + // public powerLevels: Map public topic: Map; public eventIDsSeen: Set; public historyVisibility: string public guestAccess: string public joinRules: string - constructor(public roomId: string, initialMatrixUser: MatrixUser) { + private syncLocks: Set + private initialSyncID: NodeJS.Timeout; + constructor(public roomId: string, initialMatrixUser: MatrixUser, private ircUser: IRCUser) { this.name = roomId; this.matrixUsers = new Map(); this.matrixUsers.set(initialMatrixUser.nick, initialMatrixUser); @@ -19,6 +25,58 @@ export class Channel { this.historyVisibility = ""; this.guestAccess = ""; this.joinRules = ""; + this.syncLocks = new Set(); + this.doInitialSync(); + this.initialSyncID = setInterval(this.checkChannelSync.bind(this), 2000); + } + + doInitialSync() { + this.syncLocks.add("m.room.canonical_alias"); + axios.get(`https://${this.ircUser.homeserver}/_matrix/client/v3/rooms/${this.roomId}/event/m.room.canonical_alias?access_token=${this.ircUser.accessToken}`).then(response => { + const canonical_alias = response.data["content"]?.["alias"]; + if (canonical_alias) { + this.name = canonical_alias; + } + this.syncLocks.delete("m.room.canonical_alias") + }).catch(e => { + this.syncLocks.delete("m.room.canonical_alias") + }) + this.syncLocks.add("m.room.topic"); + axios.get(`https://${this.ircUser.homeserver}/_matrix/client/v3/rooms/${this.roomId}/event/m.room.topic?access_token=${this.ircUser.accessToken}`).then(response => { + const topicText = response.data["content"]?.["topic"]; + if (!topicText) + return; + const topicSetter = this.ircUser.getOrCreateMatrixUser(response.data["sender"]); + const topicTS: string = response.data["origin_server_ts"].toString(); + this.topic.set("text", topicText); + this.topic.set("timestamp", topicTS.substring(0,10)) + this.topic.set('setter', topicSetter.nick); + this.syncLocks.delete("m.room.topic") + }).catch(e => { + this.syncLocks.delete("m.room.topic") + }) + this.syncLocks.add("m.room.members"); + axios.get(`https://${this.ircUser.homeserver}/_matrix/client/v3/rooms/${this.roomId}/joined_members?access_token=${this.ircUser.accessToken}`).then(response => { + const allMembers = response.data["joined"]; + for (const member of Object.keys(allMembers)) { + const nextMatrixUser = this.ircUser.getOrCreateMatrixUser(member); + this.matrixUsers.set(nextMatrixUser.nick, nextMatrixUser); + } + this.syncLocks.delete("m.room.members") + }).catch(e => { + this.syncLocks.delete("m.room.members") + }) + } + + checkChannelSync() { + if (this.syncLocks.size === 0) { + if (this.matrixUsers.size === 2 && this.name === this.roomId) { + const otherUser = [...this.matrixUsers.values()].filter(m => m.nick !== this.ircUser.nick); + this.name = `&${otherUser[0].mxid.substring(1)}` + } + this.ircUser.finishChannelSync(this); + clearInterval(this.initialSyncID); + } } getNickPowerLevelMapping(nick: string): string { diff --git a/src/Client.ts b/src/Client.ts index fdc80c1..f8bafd6 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -198,24 +198,15 @@ export class Client { if (this.user === null) return; if (rooms['join']) { - const joinedRooms: Set = new Set(); for (const roomId of Object.keys(rooms.join)) { const targetChannel = this.user.getOrCreateIRCChannel(roomId); - joinedRooms.add(targetChannel); //@ts-ignore rooms.join[roomId].state.events.forEach((nextEvent: any) => this.user.routeMatrixEvent(nextEvent, targetChannel)); } - joinedRooms.forEach(c => { - if (this.user !== null) { - this.user.channels.set(c.name, c); - this.user.roomIdToChannel.set(c.roomId, c); - } - }); } if (this.user === null) return; this.user.nextBatch = data.next_batch; - this.sendMessage(this.server.name, 'NOTICE', [this.user.nick, 'You are now synced to the network!']); this.user.addClient(this); }).catch(function (error) { console.log(error); diff --git a/src/IRCUser.ts b/src/IRCUser.ts index eadae37..f76c3dd 100644 --- a/src/IRCUser.ts +++ b/src/IRCUser.ts @@ -8,6 +8,7 @@ export class IRCUser { private clients: Set public channels: Map public roomIdToChannel: Map + private syncLocks: Set public matrixUsers: Map public nickToMatrixUser: Map public nick: string @@ -18,6 +19,7 @@ export class IRCUser { public ourMatrixUser: MatrixUser public txnIdStore: Map public nextBatch: string + private initialSync: boolean private isSyncing: boolean private currentSyncTime: number private syncIntervalID: NodeJS.Timeout; @@ -25,6 +27,7 @@ export class IRCUser { this.clients = new Set(); this.channels = new Map(); this.roomIdToChannel = new Map(); + this.syncLocks = new Set(); this.matrixUsers = new Map(); this.nickToMatrixUser = new Map(); const mxidSplit = mxid.split(':') @@ -38,6 +41,7 @@ export class IRCUser { this.nickToMatrixUser.set(this.nick, this.ourMatrixUser); this.txnIdStore = new Map(); this.nextBatch = ""; + this.initialSync = false; this.isSyncing = false; this.currentSyncTime = 0; this.syncIntervalID = setInterval(this.doSync.bind(this), 2000); @@ -69,7 +73,8 @@ export class IRCUser { if (maybeChannel) return maybeChannel; - const newChannel = new Channel(roomId, this.ourMatrixUser); + const newChannel = new Channel(roomId, this.ourMatrixUser, this); + this.syncLocks.add(newChannel); this.roomIdToChannel.set(roomId, newChannel); this.channels.set(roomId, newChannel); return newChannel; @@ -79,6 +84,17 @@ export class IRCUser { return this.nextBatch !== ""; } + finishChannelSync(targetChannel: Channel) { + this.syncLocks.delete(targetChannel); + this.channels.set(targetChannel.name, targetChannel); + this.roomIdToChannel.set(targetChannel.roomId, targetChannel); + this.clients.forEach(c => this.joinNewIRCClient(c, targetChannel)); + if (this.initialSync === false && this.syncLocks.size === 0) { + this.initialSync = true; + this.sendToAll(this.server.name, 'NOTICE', [this.nick, 'You are now synced to the network!']); + } + } + getVerification() { return axios.get(`https://${this.homeserver}/_matrix/client/v3/account/whoami?access_token=${this.accessToken}`, { validateStatus: function (status) { @@ -107,7 +123,7 @@ export class IRCUser { addClient(client: Client) { this.clients.add(client); - if (this.nextBatch !== "") { + if (this.initialSync) { for (const channel of this.channels.values()) { this.joinNewIRCClient(client, channel); } diff --git a/src/MatrixUser.ts b/src/MatrixUser.ts index 5c583bb..f3b1979 100644 --- a/src/MatrixUser.ts +++ b/src/MatrixUser.ts @@ -8,7 +8,7 @@ export class MatrixUser { public channels: Set constructor(public mxid: string, public nick: string) { const mxidSplit = this.mxid.split(':') - this.ident = mxidSplit[0].substr(1); + this.ident = mxidSplit[0].substring(1); this.hostname = mxidSplit[1]; this.realname = this.mxid; this.accountName = this.mxid.slice(1);