From 31b293fa0374ca31003e4bad970f4744a1d04389 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 6 Dec 2021 23:09:30 +0100 Subject: [PATCH] lib/client: use Error objects for error events --- components/app.js | 17 +++++++++++++++-- lib/client.js | 38 ++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/components/app.js b/components/app.js index 5451bf3..6cbfbdc 100644 --- a/components/app.js +++ b/components/app.js @@ -317,8 +317,21 @@ export default class App extends Component { } } - showError(msg) { - this.setState({ error: String(msg) }); + showError(err) { + console.error("App error: ", err); + + let text; + if (err instanceof Error) { + let l = []; + while (err) { + l.push(err.message); + err = err.cause; + } + text = l.join(": "); + } else { + text = String(err); + } + this.setState({ error: text }); lastErrorID++; return lastErrorID; } diff --git a/lib/client.js b/lib/client.js index c4dac01..9c39ce7 100644 --- a/lib/client.js +++ b/lib/client.js @@ -126,7 +126,7 @@ export default class Client extends EventTarget { } catch (err) { console.error("Failed to create connection:", err); setTimeout(() => { - this.dispatchEvent(new CustomEvent("error", { detail: "Failed to create connection: " + err })); + this.dispatchError(new Error("Failed to create connection", { cause: err })); this.setStatus(Client.Status.DISCONNECTED); }, 0); return; @@ -137,7 +137,7 @@ export default class Client extends EventTarget { try { this.handleMessage(event); } catch (err) { - this.dispatchEvent(new CustomEvent("error", { detail: err })); + this.dispatchError(err); this.disconnect(); } }); @@ -146,7 +146,7 @@ export default class Client extends EventTarget { console.log("Connection closed (code: " + event.code + ")"); if (event.code !== NORMAL_CLOSURE && event.code !== GOING_AWAY) { - this.dispatchEvent(new CustomEvent("error", { detail: "Connection error" })); + this.dispatchError(new Error("Connection error")); } this.ws = null; @@ -202,6 +202,10 @@ export default class Client extends EventTarget { this.dispatchEvent(new CustomEvent("status")); } + dispatchError(err) { + this.dispatchEvent(new CustomEvent("error", { detail: err })); + } + handleOpen() { console.log("Connection opened"); this.setStatus(Client.Status.REGISTERING); @@ -264,7 +268,7 @@ export default class Client extends EventTarget { switch (msg.command) { case irc.RPL_WELCOME: if (this.params.saslPlain && !this.supportsCap) { - this.dispatchEvent(new CustomEvent("error", { detail: "Server doesn't support SASL PLAIN" })); + this.dispatchError(new Error("Server doesn't support SASL PLAIN")); this.disconnect(); return; } @@ -303,7 +307,7 @@ export default class Client extends EventTarget { // Both PLAIN and EXTERNAL expect an empty challenge let challengeStr = msg.params[0]; if (challengeStr != "+") { - this.dispatchEvent(new CustomEvent("error", { detail: "Expected an empty challenge, got: " + challengeStr })); + this.dispatchError(new Error("Expected an empty challenge, got: " + challengeStr)); this.send({ command: "AUTHENTICATE", params: ["*"] }); } break; @@ -362,9 +366,7 @@ export default class Client extends EventTarget { } break; case "ERROR": - this.dispatchEvent(new CustomEvent("error", { - detail: "Fatal IRC error: " + msg.params[0], - })); + this.dispatchError(new IRCError(msg)); this.disconnect(); break; case irc.ERR_PASSWDMISMATCH: @@ -374,9 +376,7 @@ export default class Client extends EventTarget { case irc.ERR_UNAVAILRESOURCE: case irc.ERR_NOPERMFORHOST: case irc.ERR_YOUREBANNEDCREEP: - this.dispatchEvent(new CustomEvent("error", { - detail: "Error (" + msg.command + "): " + msg.params[msg.params.length - 1], - })); + this.dispatchError(new IRCError(msg)); if (this.status != Client.Status.REGISTERED) { this.disconnect(); } @@ -387,15 +387,13 @@ export default class Client extends EventTarget { } let reason = msg.params[msg.params.length - 1]; if (msg.params[0] === "BOUNCER" && msg.params[2] === "BIND") { - this.dispatchEvent(new CustomEvent("error", { - detail: "Failed to bind to bouncer network: " + reason, + this.dispatchError(new Error("Failed to bind to bouncer network", { + cause: new IRCError(msg), })); this.disconnect(); } if (msg.params[1] === "ACCOUNT_REQUIRED") { - this.dispatchEvent(new CustomEvent("error", { - detail: reason, - })); + this.dispatchError(new IRCError(msg)); this.disconnect(); } break; @@ -635,12 +633,8 @@ export default class Client extends EventTarget { } else if (this.params.saslExternal) { promise = this.authenticate("EXTERNAL"); } - (promise || Promise.resolve()).catch((msg) => { - if (msg.command) { - this.dispatchEvent(new CustomEvent("error", { - detail: "Authentication error (SASL " + msg.command + "): " + msg.params[1], - })); - } + (promise || Promise.resolve()).catch((err) => { + this.dispatchError(err); this.disconnect(); }); }