From eefab888a7388e36e1a18e521a093ec0726301d5 Mon Sep 17 00:00:00 2001 From: JoshADC <71401649+JoshADC@users.noreply.github.com> Date: Mon, 23 Mar 2026 11:23:11 -0400 Subject: [PATCH] reolink: logout expired token sessions before renewing (#1979) The ReolinkCameraClient never called the Logout API before requesting a new token, causing stale sessions to accumulate on the camera. When the camera's session limit was reached (~68 min cycle), it would close the RTMP/RTSP connection, dropping the stream. Add a logout() method that releases the old token session before login() requests a new one, matching the pattern already used by ReolinkNvrClient. This prevents session buildup and eliminates periodic stream drops. Fixes #1873 Co-authored-by: Josh Casada Co-authored-by: Claude Opus 4.6 --- plugins/reolink/src/reolink-api.ts | 36 ++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/plugins/reolink/src/reolink-api.ts b/plugins/reolink/src/reolink-api.ts index ee01fad08..d5b8b6253 100644 --- a/plugins/reolink/src/reolink-api.ts +++ b/plugins/reolink/src/reolink-api.ts @@ -126,13 +126,45 @@ export class ReolinkCameraClient { return; } - this.console.log(`token expired at ${this.tokenLease}, renewing...`); + if (this.parameters?.token) { + this.console.log(`token expired at ${this.tokenLease}, logging out before renewing...`); + await this.logout(); + } else if (this.tokenLease !== undefined) { + this.console.log(`token expired at ${this.tokenLease}, renewing...`); + } else { + this.console.log('performing initial login...'); + } const { parameters, leaseTimeSeconds } = await getLoginParameters(this.host, this.username, this.password, this.forceToken); - this.parameters = parameters + this.parameters = parameters; this.tokenLease = Date.now() + 1000 * leaseTimeSeconds; } + async logout() { + if (!this.parameters?.token) { + return; + } + try { + const url = new URL(`http://${this.host}/api.cgi`); + const params = url.searchParams; + params.set('cmd', 'Logout'); + params.set('token', this.parameters.token); + + await this.request({ + url, + method: 'POST', + responseType: 'json', + }, this.createReadable([{ + cmd: "Logout", + action: 0, + param: {}, + }])); + this.console.log('successfully logged out previous session'); + } catch (e) { + this.console.warn('failed to logout previous session:', e.message); + } + } + async requestWithLogin(options: HttpFetchOptions, body?: Readable) { await this.login(); const url = options.url as URL;