diff --git a/matrix_puppeteer_line/rpc/client.py b/matrix_puppeteer_line/rpc/client.py index 94129fa..2762bff 100644 --- a/matrix_puppeteer_line/rpc/client.py +++ b/matrix_puppeteer_line/rpc/client.py @@ -98,6 +98,12 @@ class Client(RPCClient): self.add_event_handler("receipt", wrapper) + async def on_logged_out(self, func: Callable[[], Awaitable[None]]) -> None: + async def wrapper(data: Dict[str, Any]) -> None: + await func() + + self.add_event_handler("logged_out", wrapper) + # TODO Type hint for sender async def login(self, sender, **login_data) -> AsyncGenerator[Tuple[str, str], None]: login_data["login_type"] = sender.command_status["login_type"] diff --git a/matrix_puppeteer_line/user.py b/matrix_puppeteer_line/user.py index d464063..c7344ca 100644 --- a/matrix_puppeteer_line/user.py +++ b/matrix_puppeteer_line/user.py @@ -101,6 +101,7 @@ class User(DBUser, BaseUser): state = await self.client.start() await self.client.on_message(self.handle_message) await self.client.on_receipt(self.handle_receipt) + await self.client.on_logged_out(self.handle_logged_out) if state.is_connected: self._track_metric(METRIC_CONNECTED, True) if state.is_logged_in: @@ -176,6 +177,12 @@ class User(DBUser, BaseUser): await portal.create_matrix_room(self, chat_info) 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.") + if self._connection_check_task: + self._connection_check_task.cancel() + self._connection_check_task = None + def _add_to_cache(self) -> None: self.by_mxid[self.mxid] = self diff --git a/puppet/src/client.js b/puppet/src/client.js index 2c5e623..9fbd4cc 100644 --- a/puppet/src/client.js +++ b/puppet/src/client.js @@ -144,6 +144,14 @@ export default class Client { }) } + sendLoggedOut() { + this.log("Sending logout notice to client") + return this._write({ + id: --this.notificationID, + command: "logged_out", + }) + } + handleStart = async (req) => { let started = false if (this.puppet === null) { diff --git a/puppet/src/contentscript.js b/puppet/src/contentscript.js index 2fcefdf..570caae 100644 --- a/puppet/src/contentscript.js +++ b/puppet/src/contentscript.js @@ -69,6 +69,10 @@ window.__mautrixExpiry = function (button) {} * @return {Promise} */ window.__mautrixReceiveMessageID = function(id) {} +/** + * @return {void} + */ +window.__mautrixLoggedOut = function() {} /** * typedef ChatTypeEnum @@ -1287,3 +1291,16 @@ new MutationObserver(() => { attributeFilter: ["class"], childList: true, }) + +/** + * Watch for being logged out. + */ +const mainApp = document.querySelector("#mainApp") +new MutationObserver(() => { + if (mainApp.classList.contains("MdNonDisp")) { + window.__mautrixLoggedOut() + } +}).observe(mainApp, { + attributes: true, + attributeFilter: ["class"], +}) diff --git a/puppet/src/puppet.js b/puppet/src/puppet.js index b63a38a..805f1f8 100644 --- a/puppet/src/puppet.js +++ b/puppet/src/puppet.js @@ -107,6 +107,8 @@ export default class MessagesPuppeteer { this._receiveReceiptDirectLatest.bind(this)) await this.page.exposeFunction("__mautrixReceiveReceiptMulti", this._receiveReceiptMulti.bind(this)) + await this.page.exposeFunction("__mautrixLoggedOut", + this._onLoggedOut.bind(this)) await this.page.exposeFunction("__chronoParseDate", chrono.parseDate) // NOTE Must *always* re-login on a browser session, so no need to check if already logged in @@ -302,7 +304,17 @@ export default class MessagesPuppeteer { * @return {Promise} - Whether or not the session is logged in. */ async isLoggedIn() { - return await this.page.$("#wrap_message_sync") !== null + const selectors = [ + "#mainApp:not(.MdNonDisp)", + "#wrap_message_sync", + "#_chat_list_body", + ] + for (const selector of selectors) { + if (await this.page.$(selector) == null) { + return false + } + } + return true } async isPermanentlyDisconnected() { @@ -752,4 +764,15 @@ export default class MessagesPuppeteer { this.log("No client connected, not sending failure reason") } } + + _onLoggedOut() { + this.log("Got logged out!") + this.stopObserving() + if (this.client) { + this.client.sendLoggedOut().catch(err => + this.error("Failed to send logout notice to client:", err)) + } else { + this.log("No client connected, not sending logout notice") + } + } }