Browse Source

🐞 fix: 修复登录失效不更新状态的问题

Pchen. 1 month ago
parent
commit
197f984c87

+ 19 - 2
apis/Lepao/Account/UpdateSelfAccount.js

@@ -18,6 +18,7 @@ class UpdateSelfAccount extends API {
 
 
     async onRequest(req, res) {
     async onRequest(req, res) {
         const { uuid, session, student_num } = req.body
         const { uuid, session, student_num } = req.body
+        const loginExpiredMsg = '乐跑账号登录失效,请重新使用乐跑登录器进行登录'
 
 
         if ([uuid, session, student_num].some((v) => v === '' || v === null || v === undefined)) {
         if ([uuid, session, student_num].some((v) => v === '' || v === null || v === undefined)) {
             return res.json({
             return res.json({
@@ -54,8 +55,24 @@ class UpdateSelfAccount extends API {
             const now = new Date()
             const now = new Date()
             const y = now.getFullYear()
             const y = now.getFullYear()
             const m = now.getMonth() + 1
             const m = now.getMonth() + 1
-            const monthKm = await fetchJkesMonthKm(account.token, y, m)
-            const totalKm = await fetchJkesTotalKm(account.token)
+            let monthKm
+            let totalKm
+            try {
+                monthKm = await fetchJkesMonthKm(account.token, y, m)
+                totalKm = await fetchJkesTotalKm(account.token)
+            } catch (error) {
+                if (error?.loginExpired) {
+                    await db.query(
+                        'UPDATE lepao_account SET state = 0, update_time = ? WHERE student_num = ? AND create_user = ?',
+                        [Date.now(), student_num, uuid]
+                    )
+                    return res.json({
+                        ...BaseStdResponse.ERR,
+                        msg: loginExpiredMsg
+                    })
+                }
+                throw error
+            }
 
 
             const updateTime = Date.now()
             const updateTime = Date.now()
             const updateRows = await db.query(
             const updateRows = await db.query(

+ 6 - 1
lib/Lepao/Worker.js

@@ -54,7 +54,7 @@ class Worker {
             } catch (e) {
             } catch (e) {
                 this.logger.warn(`${account} 清理 jkes_runner 标记失败:${e.message || e}`)
                 this.logger.warn(`${account} 清理 jkes_runner 标记失败:${e.message || e}`)
             }
             }
-            this.logger.warn(`${account} 登录状态已失效,已自动更新为未登录`)
+            this.logger.warn(`${account} 登录状态已失效,已自动更新账号状态`)
         } catch (error) {
         } catch (error) {
             this.logger.error(`更新账号登录状态失败:${error.stack || error}`)
             this.logger.error(`更新账号登录状态失败:${error.stack || error}`)
         }
         }
@@ -953,6 +953,11 @@ class Worker {
                 } catch (err) {
                 } catch (err) {
                     this.logErr(traceId, `任务失败 ${type}`, err)
                     this.logErr(traceId, `任务失败 ${type}`, err)
 
 
+                    if (err?.loginExpired) {
+                        const account = data?.account || data?.student_num || data?.studentNum
+                        await this.markLoginExpired(account)
+                    }
+
                     if (retry < this.maxRetry && this.isRetryableTaskError(err)) {
                     if (retry < this.maxRetry && this.isRetryableTaskError(err)) {
                         await channel.sendToQueue(
                         await channel.sendToQueue(
                             this.taskQueue,
                             this.taskQueue,

+ 27 - 0
plugin/jkes/request.js

@@ -31,6 +31,26 @@ function buildJkesHeaders(token) {
     }
     }
 }
 }
 
 
+function isJkesLoginExpiredPayload(payload) {
+    if (!payload || typeof payload !== 'object') return false
+    const code = Number(payload.code)
+    const msg = String(payload.message ?? payload.msg ?? '').trim()
+    return (
+        (code === 500 && msg.includes('无效用户')) ||
+        (code === 401 && msg.includes('您的认证已经失效'))
+    )
+}
+
+function makeJkesLoginExpiredError(payload) {
+    const msg = '乐跑账号登录失效,请重新使用乐跑登录器进行登录'
+    const err = new Error(msg)
+    err.code = 'JKES_AUTH_EXPIRED'
+    err.loginExpired = true
+    err.retryable = false
+    err.payload = payload
+    return err
+}
+
 /**
 /**
  * @param {string} url 如 /sys/user/getMyInfo
  * @param {string} url 如 /sys/user/getMyInfo
  * @param {object} [data] POST body
  * @param {object} [data] POST body
@@ -86,6 +106,10 @@ async function jkesRequest(url, data, token) {
                 ? JSON.stringify(payload)
                 ? JSON.stringify(payload)
                 : String(payload ?? '')
                 : String(payload ?? '')
 
 
+        if (isJkesLoginExpiredPayload(payload)) {
+            throw makeJkesLoginExpiredError(payload)
+        }
+
         if (res.status !== 200) {
         if (res.status !== 200) {
             logger.error(
             logger.error(
                 `[JKES] HTTP ${res.status} ${pathPart} 响应: ${payloadPreview.slice(0, 1000)}`
                 `[JKES] HTTP ${res.status} ${pathPart} 响应: ${payloadPreview.slice(0, 1000)}`
@@ -98,6 +122,7 @@ async function jkesRequest(url, data, token) {
 
 
         return payload
         return payload
     } catch (error) {
     } catch (error) {
+        if (error?.loginExpired) throw error
         const st = error.response?.status
         const st = error.response?.status
         const dataErr = error.response?.data
         const dataErr = error.response?.data
         const errStr =
         const errStr =
@@ -113,6 +138,8 @@ async function jkesRequest(url, data, token) {
 
 
 module.exports = {
 module.exports = {
     jkesRequest,
     jkesRequest,
+    isJkesLoginExpiredPayload,
+    makeJkesLoginExpiredError,
     get BASE_URL() {
     get BASE_URL() {
         return normalizeApiBase(getJkesSettings().apiBase)
         return normalizeApiBase(getJkesSettings().apiBase)
     }
     }

+ 7 - 0
plugin/jkes/runRecord.js

@@ -7,6 +7,10 @@ const axios = require('axios')
 const https = require('https')
 const https = require('https')
 
 
 const { getJkesSettings, normalizeApiBase } = require('./jkesSettings')
 const { getJkesSettings, normalizeApiBase } = require('./jkesSettings')
+const {
+    isJkesLoginExpiredPayload,
+    makeJkesLoginExpiredError
+} = require('./request')
 
 
 const CALC_INTERVAL_MS = 50000
 const CALC_INTERVAL_MS = 50000
 
 
@@ -318,6 +322,9 @@ async function runJkesRecord(opts) {
                 throw new Error(`JKES 非 JSON 响应 ${res.status}: ${String(text).slice(0, 200)}`)
                 throw new Error(`JKES 非 JSON 响应 ${res.status}: ${String(text).slice(0, 200)}`)
             }
             }
         }
         }
+        if (isJkesLoginExpiredPayload(json)) {
+            throw makeJkesLoginExpiredError(json)
+        }
         if (res.status !== 200 || json.code !== 0) {
         if (res.status !== 200 || json.code !== 0) {
             const err = new Error(`JKES 请求失败 ${res.status} ${pathSuffix}: ${String(text).slice(0, 500)}`)
             const err = new Error(`JKES 请求失败 ${res.status} ${pathSuffix}: ${String(text).slice(0, 500)}`)
             err.retryable = res.status >= 500 || res.status === 0
             err.retryable = res.status >= 500 || res.status === 0

+ 21 - 2
plugin/jkes/syncLepaoAccountFromToken.js

@@ -6,6 +6,13 @@ const { jkesRequest } = require('./request.js')
 
 
 const DEFAULT_AVATAR =
 const DEFAULT_AVATAR =
     'https://lepao-cloud.xxoo365.top/view.php/25aa126dc406974ff3579a99a2c6501a.png'
     'https://lepao-cloud.xxoo365.top/view.php/25aa126dc406974ff3579a99a2c6501a.png'
+const LOGIN_EXPIRED_MSG = '乐跑账号登录失效,请重新使用乐跑登录器进行登录'
+
+async function markLoginExpiredByToken(token) {
+    const tokenClean = String(token ?? '').trim()
+    if (!tokenClean) return
+    await db.query('UPDATE lepao_account SET state = 0 WHERE token = ?', [tokenClean])
+}
 
 
 /**
 /**
  * @param {string} token
  * @param {string} token
@@ -28,8 +35,20 @@ const DEFAULT_AVATAR =
  * >}
  * >}
  */
  */
 async function syncLepaoAccountFromToken(token, device = {}) {
 async function syncLepaoAccountFromToken(token, device = {}) {
-    const jkesRes = await jkesRequest('/sys/user/getMyInfo', {}, token)
-    console.log(jkesRes)
+    let jkesRes
+    try {
+        jkesRes = await jkesRequest('/sys/user/getMyInfo', {}, token)
+    } catch (error) {
+        if (error?.loginExpired) {
+            await markLoginExpiredByToken(token)
+            return {
+                ok: false,
+                msg: LOGIN_EXPIRED_MSG
+            }
+        }
+        throw error
+    }
+
     if (!jkesRes || jkesRes.code !== 0 || !jkesRes.data || !jkesRes.data.info) {
     if (!jkesRes || jkesRes.code !== 0 || !jkesRes.data || !jkesRes.data.info) {
         return {
         return {
             ok: false,
             ok: false,