From c5eea7b50b830fd7b488d254650d3b9e72662b9a Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Tue, 8 Jun 2021 00:24:00 -0400 Subject: [PATCH] Fix crash when logging in after a forced logout Also tidy up bridge notices during the login flow --- matrix_puppeteer_line/commands/auth.py | 13 ++++++++---- matrix_puppeteer_line/rpc/client.py | 12 ++++++++--- matrix_puppeteer_line/user.py | 2 +- puppet/src/client.js | 14 ++++++++++--- puppet/src/puppet.js | 28 +++++++++++++++++--------- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/matrix_puppeteer_line/commands/auth.py b/matrix_puppeteer_line/commands/auth.py index 6cf44a9..afd5331 100644 --- a/matrix_puppeteer_line/commands/auth.py +++ b/matrix_puppeteer_line/commands/auth.py @@ -55,6 +55,11 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None] failure = False async for item in gen: if item[0] == "qr": + message = "Open LINE on your primary device and scan this QR code:" + content = TextMessageEventContent(body=message, msgtype=MessageType.NOTICE) + content.set_reply(evt.event_id) + await evt.az.intent.send_message(evt.room_id, content) + url = item[1] buffer = io.BytesIO() image = qrcode.make(url) @@ -69,7 +74,6 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None] content.set_edit(qr_event_id) await evt.az.intent.send_message(evt.room_id, content) else: - content.set_reply(evt.event_id) qr_event_id = await evt.az.intent.send_message(evt.room_id, content) elif item[0] == "pin": pin = item[1] @@ -79,9 +83,10 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None] content.set_edit(pin_event_id) await evt.az.intent.send_message(evt.room_id, content) else: - content.set_reply(evt.event_id) pin_event_id = await evt.az.intent.send_message(evt.room_id, content) - elif item[0] in ("failure", "error"): + elif item[0] == "login_success": + await evt.reply("Successfully logged in, waiting for LINE to load...") + elif item[0] in ("login_failure", "error"): # TODO Handle errors differently? failure = True reason = item[1] @@ -91,7 +96,7 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None] # else: pass if not failure and evt.sender.command_status: - await evt.reply("Successfully logged in") + await evt.reply("LINE loading complete") await evt.sender.sync() # else command was cancelled or failed. Don't post message about it, "cancel" command or failure did already evt.sender.command_status = None diff --git a/matrix_puppeteer_line/rpc/client.py b/matrix_puppeteer_line/rpc/client.py index 2762bff..3e68865 100644 --- a/matrix_puppeteer_line/rpc/client.py +++ b/matrix_puppeteer_line/rpc/client.py @@ -119,8 +119,12 @@ class Client(RPCClient): data.append(("pin", req["pin"])) event.set() + async def success_handler(req: LoginCommand) -> None: + data.append(("login_success", None)) + event.set() + async def failure_handler(req: LoginCommand) -> None: - data.append(("failure", req.get("reason"))) + data.append(("login_failure", req.get("reason"))) event.set() async def cancel_watcher() -> None: @@ -145,7 +149,8 @@ class Client(RPCClient): self.add_event_handler("qr", qr_handler) self.add_event_handler("pin", pin_handler) - self.add_event_handler("failure", failure_handler) + self.add_event_handler("login_success", success_handler) + self.add_event_handler("login_failure", failure_handler) try: while True: await event.wait() @@ -158,4 +163,5 @@ class Client(RPCClient): finally: self.remove_event_handler("qr", qr_handler) self.remove_event_handler("pin", pin_handler) - self.remove_event_handler("failure", failure_handler) + self.remove_event_handler("login_success", success_handler) + self.remove_event_handler("login_failure", failure_handler) diff --git a/matrix_puppeteer_line/user.py b/matrix_puppeteer_line/user.py index daa21a6..1372ac1 100644 --- a/matrix_puppeteer_line/user.py +++ b/matrix_puppeteer_line/user.py @@ -177,7 +177,7 @@ class User(DBUser, BaseUser): await portal.handle_remote_receipt(receipt) async def handle_logged_out(self) -> None: - await self.send_bridge_notice("Logged out of LINE. Please run the \"login\" command to log back in.") + await self.send_bridge_notice("Logged out of LINE. Please run either \"login-qr\" or \"login-email\" to log back in.") if self._connection_check_task: self._connection_check_task.cancel() self._connection_check_task = None diff --git a/puppet/src/client.js b/puppet/src/client.js index 9fbd4cc..636d695 100644 --- a/puppet/src/client.js +++ b/puppet/src/client.js @@ -135,11 +135,19 @@ export default class Client { }) } - sendFailure(reason) { - this.log(`Sending failure to client${reason ? `: "${reason}"` : ""}`) + sendLoginSuccess() { + this.log("Sending login success to client") return this._write({ id: --this.notificationID, - command: "failure", + command: "login_success", + }) + } + + sendLoginFailure(reason) { + this.log(`Sending login failure to client${reason ? `: "${reason}"` : ""}`) + return this._write({ + id: --this.notificationID, + command: "login_failure", reason, }) } diff --git a/puppet/src/puppet.js b/puppet/src/puppet.js index 5ae78be..caf0d32 100644 --- a/puppet/src/puppet.js +++ b/puppet/src/puppet.js @@ -207,7 +207,7 @@ export default class MessagesPuppeteer { } const result = await Promise.race([ - () => this.page.waitForSelector("#wrap_message_sync", {timeout: 2000}) + () => this.page.waitForSelector("#mainApp:not(.MdNonDisp)", {timeout: 2000}) .then(value => { loginSuccess = true return value @@ -227,11 +227,13 @@ export default class MessagesPuppeteer { delete this.login_email delete this.login_password - if (!loginSuccess) { + const messageSyncElement = loginSuccess ? await this.page.waitForSelector("#wrap_message_sync") : null + if (!loginSuccess || !messageSyncElement) { this._sendLoginFailure(result) return } + this._sendLoginSuccess() this.log("Waiting for sync") try { await this.page.waitForFunction( @@ -242,14 +244,12 @@ export default class MessagesPuppeteer { // TODO Sometimes it gets stuck at 99%...?? }, {timeout: 10000}, // Assume 10 seconds is long enough - result) + messageSyncElement) } catch (err) { //this._sendLoginFailure(`Failed to sync: ${err}`) this.log("LINE's sync took too long, assume it's fine and carry on...") } finally { - const syncText = await this.page.evaluate( - messageSyncElement => messageSyncElement.innerText, - result) + const syncText = await messageSyncElement.evaluate(e => e.innerText) this.log(`Final sync text is: "${syncText}"`) } @@ -758,14 +758,24 @@ export default class MessagesPuppeteer { } } + _sendLoginSuccess() { + this.error("Login success") + if (this.client) { + this.client.sendLoginSuccess().catch(err => + this.error("Failed to send login success to client:", err)) + } else { + this.log("No client connected, not sending login success") + } + } + _sendLoginFailure(reason) { this.loginRunning = false this.error(`Login failure: ${reason ? reason : "cancelled"}`) if (this.client) { - this.client.sendFailure(reason).catch(err => - this.error("Failed to send failure reason to client:", err)) + this.client.sendLoginFailure(reason).catch(err => + this.error("Failed to send login failure to client:", err)) } else { - this.log("No client connected, not sending failure reason") + this.log("No client connected, not sending login failure") } }