diff --git a/commands.js b/commands.js index 0fa4e46..d881ec2 100644 --- a/commands.js +++ b/commands.js @@ -25,21 +25,20 @@ function getActiveChannel(app) { return activeBuffer.name; } -function setUserHostMode(app, args, mode) { +async function setUserHostMode(app, args, mode) { let nick = args[0]; if (!nick) { throw new Error("Missing nick"); } let activeChannel = getActiveChannel(app); let client = getActiveClient(app); - client.whois(nick).then((whois) => { - const info = whois[irc.RPL_WHOISUSER].params; - const user = info[2]; - const host = info[3]; - client.send({ - command: "MODE", - params: [activeChannel, mode, `*!${user}@${host}`], - }); + let whois = await client.whois(nick); + const info = whois[irc.RPL_WHOISUSER].params; + const user = info[2]; + const host = info[3]; + client.send({ + command: "MODE", + params: [activeChannel, mode, `*!${user}@${host}`], }); } diff --git a/components/app.js b/components/app.js index 2e1503e..2384c33 100644 --- a/components/app.js +++ b/components/app.js @@ -1209,7 +1209,7 @@ export default class App extends Component { }); } - fetchBacklog(serverID) { + async fetchBacklog(serverID) { let client = this.clients.get(serverID); if (!client.caps.enabled.has("draft/chathistory")) { return; @@ -1224,45 +1224,48 @@ export default class App extends Component { } let now = irc.formatDate(new Date()); - client.fetchHistoryTargets(now, lastReceipt.time).then((targets) => { - targets.forEach((target) => { - let from = lastReceipt; - let to = { time: now }; + let targets = await client.fetchHistoryTargets(now, lastReceipt.time); + targets.forEach(async (target) => { + let from = lastReceipt; + let to = { time: now }; - // Maybe we've just received a READ update from the - // server, avoid over-fetching history - let stored = this.bufferStore.get({ name: target.name, server: client.params }); - let readReceipt = getReceipt(stored, ReceiptType.READ); - if (isReceiptBefore(from, readReceipt)) { - from = readReceipt; + // Maybe we've just received a READ update from the + // server, avoid over-fetching history + let stored = this.bufferStore.get({ name: target.name, server: client.params }); + let readReceipt = getReceipt(stored, ReceiptType.READ); + if (isReceiptBefore(from, readReceipt)) { + from = readReceipt; + } + + // If we already have messages stored for the target, + // fetch all messages we've missed + let buf = State.getBuffer(this.state, { server: serverID, name: target.name }); + if (buf && buf.messages.length > 0) { + let lastMsg = buf.messages[buf.messages.length - 1]; + from = receiptFromMessage(lastMsg); + } + + // Query read marker if this is a user (ie, we haven't received + // the read marker as part of a JOIN burst) + if (client.supportsReadMarker() && client.isNick(target.name)) { + client.fetchReadMarker(target.name); + } + + let result; + try { + result = await client.fetchHistoryBetween(target.name, from, to, CHATHISTORY_MAX_SIZE); + } catch (err) { + console.error("Failed to fetch backlog for '" + target.name + "': ", err); + this.showError("Failed to fetch backlog for '" + target.name + "'"); + return; + } + + for (let msg of result.messages) { + let destBuffers = this.routeMessage(serverID, msg); + for (let bufName of destBuffers) { + this.handleChatMessage(serverID, bufName, msg); } - - // If we already have messages stored for the target, - // fetch all messages we've missed - let buf = State.getBuffer(this.state, { server: serverID, name: target.name }); - if (buf && buf.messages.length > 0) { - let lastMsg = buf.messages[buf.messages.length - 1]; - from = receiptFromMessage(lastMsg); - } - - // Query read marker if this is a user (ie, we haven't received - // the read marker as part of a JOIN burst) - if (client.supportsReadMarker() && client.isNick(target.name)) { - client.fetchReadMarker(target.name); - } - - client.fetchHistoryBetween(target.name, from, to, CHATHISTORY_MAX_SIZE).then((result) => { - for (let msg of result.messages) { - let destBuffers = this.routeMessage(serverID, msg); - for (let bufName of destBuffers) { - this.handleChatMessage(serverID, bufName, msg); - } - } - }).catch((err) => { - console.error("Failed to fetch backlog for '" + target.name + "': ", err); - this.showError("Failed to fetch backlog for '" + target.name + "'"); - }); - }); + } }); } @@ -1367,14 +1370,13 @@ export default class App extends Component { } } - whoChannelBuffer(target, serverID) { + async whoChannelBuffer(target, serverID) { let client = this.clients.get(serverID); - client.who(target, { + await client.who(target, { fields: ["flags", "hostname", "nick", "realname", "username", "account"], - }).then(() => { - this.setBufferState({ name: target, server: serverID }, { hasInitialWho: true }); }); + this.setBufferState({ name: target, server: serverID }, { hasInitialWho: true }); } open(target, serverID, password) { @@ -1646,7 +1648,7 @@ export default class App extends Component { this.openDialog("help"); } - handleBufferScrollTop() { + async handleBufferScrollTop() { let buf = this.state.buffers.get(this.state.activeBuffer); if (!buf || buf.type == BufferType.SERVER) { return; @@ -1676,35 +1678,34 @@ export default class App extends Component { limit = 200; } - client.fetchHistoryBefore(buf.name, before, limit).then((result) => { - this.endOfHistory.set(buf.id, !result.more); + let result = await client.fetchHistoryBefore(buf.name, before, limit); + this.endOfHistory.set(buf.id, !result.more); - if (result.messages.length > 0) { - let msg = result.messages[result.messages.length - 1]; - let receipts = { [ReceiptType.DELIVERED]: receiptFromMessage(msg) }; - if (this.state.activeBuffer === buf.id) { - receipts[ReceiptType.READ] = receiptFromMessage(msg); - } - let stored = { - name: buf.name, - server: client.params, - receipts, - }; - if (this.bufferStore.put(stored)) { - this.sendReadReceipt(client, stored); - } - this.setBufferState(buf, ({ prevReadReceipt }) => { - if (!isMessageBeforeReceipt(msg, prevReadReceipt)) { - prevReadReceipt = receiptFromMessage(msg); - } - return { prevReadReceipt }; - }); + if (result.messages.length > 0) { + let msg = result.messages[result.messages.length - 1]; + let receipts = { [ReceiptType.DELIVERED]: receiptFromMessage(msg) }; + if (this.state.activeBuffer === buf.id) { + receipts[ReceiptType.READ] = receiptFromMessage(msg); } + let stored = { + name: buf.name, + server: client.params, + receipts, + }; + if (this.bufferStore.put(stored)) { + this.sendReadReceipt(client, stored); + } + this.setBufferState(buf, ({ prevReadReceipt }) => { + if (!isMessageBeforeReceipt(msg, prevReadReceipt)) { + prevReadReceipt = receiptFromMessage(msg); + } + return { prevReadReceipt }; + }); + } - for (let msg of result.messages) { - this.addChatMessage(buf.server, buf.name, msg); - } - }); + for (let msg of result.messages) { + this.addChatMessage(buf.server, buf.name, msg); + } } openDialog(name, data) { @@ -1822,12 +1823,13 @@ export default class App extends Component { }); } - handleNetworkSubmit(attrs, autojoin) { + async handleNetworkSubmit(attrs, autojoin) { let client = this.clients.values().next().value; + this.dismissDialog(); + if (this.state.dialogData && this.state.dialogData.id) { if (Object.keys(attrs).length == 0) { - this.dismissDialog(); return; } @@ -1837,22 +1839,19 @@ export default class App extends Component { }); } else { attrs = { ...attrs, tls: "1" }; - client.createBouncerNetwork(attrs).then((id) => { - if (!autojoin) { - return; - } + let id = await client.createBouncerNetwork(attrs); + if (!autojoin) { + return; + } - // By this point, bouncer-networks-notify should've advertised - // the new network - let serverID = this.serverFromBouncerNetwork(id); - let client = this.clients.get(serverID); - client.params.autojoin = [autojoin]; + // By this point, bouncer-networks-notify should've advertised + // the new network + let serverID = this.serverFromBouncerNetwork(id); + let client = this.clients.get(serverID); + client.params.autojoin = [autojoin]; - this.switchToChannel = autojoin; - }); + this.switchToChannel = autojoin; } - - this.dismissDialog(); } handleNetworkRemove() { diff --git a/lib/client.js b/lib/client.js index 73223dc..383af81 100644 --- a/lib/client.js +++ b/lib/client.js @@ -902,62 +902,56 @@ export default class Client extends EventTarget { } /* Fetch one page of history before the given date. */ - fetchHistoryBefore(target, before, limit) { + async fetchHistoryBefore(target, before, limit) { let max = Math.min(limit, this.isupport.chatHistory()); let params = ["BEFORE", target, "timestamp=" + before, max]; - return this.roundtripChatHistory(params).then((messages) => { - return { messages, more: messages.length >= max }; - }); + let messages = await this.roundtripChatHistory(params); + return { messages, more: messages.length >= max }; } /* Fetch history in ascending order. */ - fetchHistoryBetween(target, after, before, limit) { + async fetchHistoryBetween(target, after, before, limit) { let max = Math.min(limit, this.isupport.chatHistory()); let params = ["AFTER", target, "timestamp=" + after.time, max]; - return this.roundtripChatHistory(params).then((messages) => { - limit -= messages.length; - if (limit <= 0) { - throw new Error("Cannot fetch all chat history: too many messages"); - } - if (messages.length >= max) { - // There are still more messages to fetch - after.time = messages[messages.length - 1].tags.time; - return this.fetchHistoryBetween(target, after, before, limit); - } - return { messages }; - }); + let messages = await this.roundtripChatHistory(params); + limit -= messages.length; + if (limit <= 0) { + throw new Error("Cannot fetch all chat history: too many messages"); + } + if (messages.length >= max) { + // There are still more messages to fetch + after.time = messages[messages.length - 1].tags.time; + return await this.fetchHistoryBetween(target, after, before, limit); + } + return { messages }; } - fetchHistoryTargets(t1, t2) { + async fetchHistoryTargets(t1, t2) { let msg = { command: "CHATHISTORY", params: ["TARGETS", "timestamp=" + t1, "timestamp=" + t2, 1000], }; - return this.fetchBatch(msg, "draft/chathistory-targets").then((batch) => { - return batch.messages.map((msg) => { - if (msg.command != "CHATHISTORY" || msg.params[0] != "TARGETS") { - throw new Error("Cannot fetch chat history targets: unexpected message " + msg); - } - return { - name: msg.params[1], - latestMessage: msg.params[2], - }; - }); + let batch = await this.fetchBatch(msg, "draft/chathistory-targets"); + return batch.messages.map((msg) => { + console.assert(msg.command === "CHATHISTORY" && msg.params[0] === "TARGETS"); + return { + name: msg.params[1], + latestMessage: msg.params[2], + }; }); } - listBouncerNetworks() { + async listBouncerNetworks() { let req = { command: "BOUNCER", params: ["LISTNETWORKS"] }; - return this.fetchBatch(req, "soju.im/bouncer-networks").then((batch) => { - let networks = new Map(); - for (let msg of batch.messages) { - console.assert(msg.command === "BOUNCER" && msg.params[0] === "NETWORK"); - let id = msg.params[1]; - let params = irc.parseTags(msg.params[2]); - networks.set(id, params); - } - return networks; - }); + let batch = await this.fetchBatch(req, "soju.im/bouncer-networks"); + let networks = new Map(); + for (let msg of batch.messages) { + console.assert(msg.command === "BOUNCER" && msg.params[0] === "NETWORK"); + let id = msg.params[1]; + let params = irc.parseTags(msg.params[2]); + networks.set(id, params); + } + return networks; } monitor(target) {