@mp-assistant/core
Advanced tools
| import { BrowserContext, LaunchOptions } from "playwright"; | ||
| import { BaseTask } from "./BaseTask.js"; | ||
| import { BaseWorkerOptions, BaseWorkInfo, WorkerType } from "@mp-assistant/common/dist/work/index.js"; | ||
| import { BaseWorkerOptions, BaseWorkInfo, WorkerStatus, WorkerType } from "@mp-assistant/common/dist/work/index.js"; | ||
| import { WSMessage } from "@mp-assistant/common/dist/ws/message.js"; | ||
@@ -11,2 +11,3 @@ export declare abstract class BaseWorker { | ||
| private __taskList; | ||
| private __status; | ||
| private __currentRunningTaskKey; | ||
@@ -20,2 +21,4 @@ private __wsMessageEventHandler; | ||
| get browserContent(): BrowserContext | null; | ||
| set status(status: WorkerStatus); | ||
| get status(): WorkerStatus; | ||
| get taskList(): BaseTask[]; | ||
@@ -38,3 +41,4 @@ get currentRunningTask(): BaseTask | undefined; | ||
| removeTask(taskKey: string): Promise<void>; | ||
| destroy(): void; | ||
| pauseAndRecover(): void; | ||
| destroy(): Promise<void>; | ||
| private __taskCycle; | ||
@@ -41,0 +45,0 @@ protected _feedTasks(): Promise<void>; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"BaseWorker.d.ts","sourceRoot":"","sources":["../../src/worker/BaseWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAY,aAAa,EAAE,MAAM,YAAY,CAAC;AAIrE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AACtG,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGnE,8BAAsB,UAAU;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAE3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,OAAO,CAAC,MAAM,CAAc;IAE5B,OAAO,CAAC,gBAAgB,CAA+B;IAEvD,OAAO,CAAC,UAAU,CAAkB;IAEpC,OAAO,CAAC,uBAAuB,CAAM;IAErC,OAAO,CAAC,uBAAuB,CAAkB;IAEjD,WAAW;IACX,OAAO,CAAC,UAAU,CAAgB;IAElC,IAAI,GAAG,WAEN;IAED,IAAI,IAAI,IAIO,MAAM,CAFpB;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAEpB;IAED,IAAI,cAAc,0BAEjB;IAED,IAAI,QAAQ,eAEX;IAED,IAAI,kBAAkB,yBAErB;IACD,IAAI,qBAAqB,IAGM,MAAM,CADpC;IACD,IAAI,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAEpC;gBAEW,OAAO,EAAE,iBAAiB;IAQtC,IAAI,IAAI,YAAY;IAUd,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,gBAAgB,GAAG,UAAU,CAAC;IAWtE;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,QAAQ;IAOtB;;;OAGG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM;IAehC,OAAO;YAIO,WAAW;cAYT,UAAU;IAyB1B,UAAU,CAAC,IAAI,EAAE,MAAM;IAQvB,UAAU,CAAC,IAAI,EAAE,MAAM;IAMvB,SAAS,CAAC,IAAI,EAAE,MAAM;IAItB,WAAW,CAAC,CAAC,SAAS,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAIpF,OAAO,CAAC,4BAA4B,CAA8C;IAClF;;;OAGG;IACH,qBAAqB;IASrB,SAAS,CAAC,QAAQ,CAAC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;CACvD"} | ||
| {"version":3,"file":"BaseWorker.d.ts","sourceRoot":"","sources":["../../src/worker/BaseWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAY,aAAa,EAAE,MAAM,YAAY,CAAC;AAIrE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAa,MAAM,yCAAyC,CAAC;AAC/H,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAInE,8BAAsB,UAAU;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAE3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,OAAO,CAAC,MAAM,CAAc;IAE5B,OAAO,CAAC,gBAAgB,CAA+B;IAEvD,OAAO,CAAC,UAAU,CAAkB;IAEpC,OAAO,CAAC,QAAQ,CAAsC;IAEtD,OAAO,CAAC,uBAAuB,CAAM;IAErC,OAAO,CAAC,uBAAuB,CAAkB;IAEjD,WAAW;IACX,OAAO,CAAC,UAAU,CAAgB;IAElC,IAAI,GAAG,WAEN;IAED,IAAI,IAAI,IAIO,MAAM,CAFpB;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAEpB;IAED,IAAI,cAAc,0BAEjB;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,EAM9B;IAED,IAAI,MAAM,IARS,YAAY,CAU9B;IAED,IAAI,QAAQ,eAEX;IAED,IAAI,kBAAkB,yBAErB;IACD,IAAI,qBAAqB,IAGM,MAAM,CADpC;IACD,IAAI,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAEpC;gBAEW,OAAO,EAAE,iBAAiB;IAQtC,IAAI,IAAI,YAAY;IAWd,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,gBAAgB,GAAG,UAAU,CAAC;IAWtE;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,QAAQ;IAOtB;;;OAGG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM;IAehC,eAAe;IAQT,OAAO;YAyBC,WAAW;cAcT,UAAU;IAyB1B,UAAU,CAAC,IAAI,EAAE,MAAM;IAQvB,UAAU,CAAC,IAAI,EAAE,MAAM;IAMvB,SAAS,CAAC,IAAI,EAAE,MAAM;IAItB,WAAW,CAAC,CAAC,SAAS,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAIpF,OAAO,CAAC,4BAA4B,CAA8C;IAClF;;;OAGG;IACH,qBAAqB;IASrB,SAAS,CAAC,QAAQ,CAAC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;CACvD"} |
@@ -6,4 +6,6 @@ import { chromium } from "playwright"; | ||
| import { TaskStatus } from "@mp-assistant/common/dist/work/task/index.js"; | ||
| import { WorkerStatus, WXWorkerN } from "@mp-assistant/common/dist/work/index.js"; | ||
| import { WSMessage } from "@mp-assistant/common/dist/ws/message.js"; | ||
| import { getChromeUserDataDir } from "@mp-assistant/common/dist/pathManage.js"; | ||
| import fs from "fs"; | ||
| export class BaseWorker { | ||
@@ -15,2 +17,3 @@ type; | ||
| __taskList = []; | ||
| __status = WorkerStatus.RUNNING; | ||
| __currentRunningTaskKey = ''; | ||
@@ -32,2 +35,12 @@ __wsMessageEventHandler; | ||
| } | ||
| set status(status) { | ||
| if (this.__status === status) { | ||
| return; | ||
| } | ||
| this.__status = status; | ||
| this.emitDetailChangeEvent(); | ||
| } | ||
| get status() { | ||
| return this.__status; | ||
| } | ||
| get taskList() { | ||
@@ -58,2 +71,3 @@ return [...this.__taskList]; | ||
| loadings: [...this.__loadings], | ||
| status: this.status, | ||
| }; | ||
@@ -95,8 +109,36 @@ } | ||
| } | ||
| destroy() { | ||
| this.__browserContent?.close(); | ||
| pauseAndRecover() { | ||
| if (this.status === WorkerStatus.PAUSED) { | ||
| this.status = WorkerStatus.RUNNING; | ||
| return; | ||
| } | ||
| this.status = WorkerStatus.PAUSED; | ||
| } | ||
| async destroy() { | ||
| if (this.isLoading(WXWorkerN.LoadingType.deleteUserDataDir)) { | ||
| return; | ||
| } | ||
| this.setLoading(WXWorkerN.LoadingType.deleteUserDataDir); | ||
| this.status = WorkerStatus.DELETED; | ||
| try { | ||
| await this.__browserContent?.close(); | ||
| const userDataDir = path.join(getChromeUserDataDir(), this.key); | ||
| const stats = fs.statSync(userDataDir, { throwIfNoEntry: false }); | ||
| if (stats && stats.isDirectory()) { | ||
| // 持久化目录下可能存在缓存文件,需强制递归删除避免 ENOTEMPTY | ||
| fs.rmSync(userDataDir, { recursive: true, force: true }); | ||
| } | ||
| } | ||
| catch (error) { | ||
| console.log('删除用户数据目录失败', error); | ||
| } | ||
| finally { | ||
| this.offLoading(WXWorkerN.LoadingType.deleteUserDataDir); | ||
| } | ||
| } | ||
| async __taskCycle() { | ||
| try { | ||
| await this._taskCycleExecutor(); | ||
| if (this.status === WorkerStatus.RUNNING) { | ||
| await this._taskCycleExecutor(); | ||
| } | ||
| } | ||
@@ -103,0 +145,0 @@ catch (error) { |
@@ -78,3 +78,3 @@ import { BaseTask } from "../../BaseTask.js"; | ||
| this._addRunningReport({ | ||
| title: '切换小程序', | ||
| title: '切换小程序成功', | ||
| description: `切换小程序: ${this.options.app_name} - ${this.options.username}`, | ||
@@ -81,0 +81,0 @@ timestamp: Date.now(), |
@@ -12,2 +12,4 @@ import { BrowserContext, Page } from "playwright"; | ||
| private __countdown; | ||
| private __currentPage; | ||
| private __refreshLoading; | ||
| readonly options: WXTaskN.ReleaseTaskOptions; | ||
@@ -17,4 +19,10 @@ constructor(options: WXTaskN.ReleaseTaskOptions); | ||
| protected _waitForQrcodeScan(page: Page, timeout?: number): Promise<void>; | ||
| /** | ||
| * 获取二维码路径 | ||
| * @param ct - 容器 | ||
| * @returns 二维码路径 | ||
| */ | ||
| getQrcodePath(): Promise<boolean>; | ||
| protected _executor(browserContent: BrowserContext): Promise<TaskExecResult>; | ||
| } | ||
| //# sourceMappingURL=ReleaseTask.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ReleaseTask.d.ts","sourceRoot":"","sources":["../../../../src/worker/wx/task/ReleaseTask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAc,QAAQ,EAAE,OAAO,EAAE,MAAM,8CAA8C,CAAC;AAM7G;;;GAGG;AACH,qBAAa,WAAY,SAAQ,UAAU;IACvC,QAAQ,CAAC,IAAI,uBAAuB;IAEpC,OAAO,CAAC,uBAAuB,CAAc;IAC7C,OAAO,CAAC,WAAW,CAAa;IAEhC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC;gBAGjC,OAAO,EAAE,OAAO,CAAC,kBAAkB;IAK/C,IAAI,IAAI,OAAO,CAAC,WAAW;cAQX,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,MAAc,GAAG,OAAO,CAAC,IAAI,CAAC;cAsBtE,SAAS,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;CA2JrF"} | ||
| {"version":3,"file":"ReleaseTask.d.ts","sourceRoot":"","sources":["../../../../src/worker/wx/task/ReleaseTask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAW,IAAI,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAc,QAAQ,EAAE,OAAO,EAAE,MAAM,8CAA8C,CAAC;AAM7G;;;GAGG;AACH,qBAAa,WAAY,SAAQ,UAAU;IACvC,QAAQ,CAAC,IAAI,uBAAuB;IAEpC,OAAO,CAAC,uBAAuB,CAAc;IAC7C,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,gBAAgB,CAAkB;IAE1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC;gBAGjC,OAAO,EAAE,OAAO,CAAC,kBAAkB;IAK/C,IAAI,IAAI,OAAO,CAAC,WAAW;cASX,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,MAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCvF;;;;OAIG;IACG,aAAa;cAuCH,SAAS,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;CAyIrF"} |
@@ -15,2 +15,4 @@ import { BaseWXTask } from "./BaseWXTask.js"; | ||
| __countdown = 0; | ||
| __currentPage = null; | ||
| __refreshLoading = false; | ||
| options; | ||
@@ -26,15 +28,31 @@ constructor(options) { | ||
| countdown: this.__countdown, | ||
| refreshLoading: this.__refreshLoading, | ||
| }; | ||
| } | ||
| async _waitForQrcodeScan(page, timeout = 60000) { | ||
| async _waitForQrcodeScan(page, timeout = 180000) { | ||
| const startDate = Date.now(); | ||
| while ((Date.now() - startDate) < timeout) { | ||
| const openDialog = page.locator(".weui-desktop-dialog").filter({ hasText: "发布版本" }); | ||
| // 二维码过期 | ||
| const refreshBtn = openDialog.getByRole("link", { name: "刷新" }); | ||
| // 同步倒计时 | ||
| this.__countdown = Math.max(0, (timeout - (Date.now() - startDate)) / 1000); | ||
| this.emitDetailChangeEvent(); | ||
| const onlineVersion = (await this._getVersionList(page))[WXTaskN.VersionType.ONLINE] || {}; | ||
| const flag = versionSatisfy(onlineVersion, this?.options?.positioner || []); | ||
| if (flag) { | ||
| return; | ||
| const refreshBtnVisible = await refreshBtn.isVisible(); | ||
| // 二维码过期时,主动刷新并重新截取二维码,避免一直等待到超时 | ||
| if (refreshBtnVisible) { | ||
| await refreshBtn.click(); | ||
| await page.waitForTimeout(1000); | ||
| await this.getQrcodePath(); | ||
| this.emitDetailChangeEvent(); | ||
| await new Promise((resolve) => setTimeout(resolve, 200)); | ||
| continue; | ||
| } | ||
| if (!refreshBtnVisible) { | ||
| const onlineVersion = (await this._getVersionList(page))[WXTaskN.VersionType.ONLINE] || {}; | ||
| const flag = versionSatisfy(onlineVersion, this?.options?.positioner || []); | ||
| if (flag) { | ||
| return; | ||
| } | ||
| } | ||
| await new Promise((resolve) => setTimeout(resolve, 200)); | ||
@@ -44,5 +62,47 @@ } | ||
| } | ||
| /** | ||
| * 获取二维码路径 | ||
| * @param ct - 容器 | ||
| * @returns 二维码路径 | ||
| */ | ||
| async getQrcodePath() { | ||
| try { | ||
| const openDialog = this.__currentPage?.locator(".weui-desktop-dialog").filter({ hasText: "发布版本" }); | ||
| if (!openDialog) | ||
| return false; | ||
| const qrCodeLocator = openDialog.locator(".weui-desktop-qrcheck__img"); | ||
| const publishQRCodeURL = await qrCodeLocator.getAttribute('src') || ''; | ||
| if (!publishQRCodeURL) | ||
| return false; | ||
| // 检查图片资源加载情况 | ||
| await qrCodeLocator.evaluate((img) => { | ||
| return new Promise((resolve, reject) => { | ||
| // 如果图片已经加载完成 (Already loaded) | ||
| if (img.complete && img.naturalWidth > 0) { | ||
| resolve(); | ||
| } | ||
| else { | ||
| // 否则监听 load 和 error 事件 | ||
| img.onload = () => resolve(); | ||
| img.onerror = () => reject(new Error('Image load failed')); | ||
| } | ||
| }); | ||
| }); | ||
| const qrCodeBuffer = await qrCodeLocator.screenshot(); | ||
| const publishQRCodeFilePath = await saveScreenshotBufferToFile(qrCodeBuffer); | ||
| this.__publishQRCodeFilePath = publishQRCodeFilePath; | ||
| return true; | ||
| } | ||
| catch (error) { | ||
| console.log(error); | ||
| return false; | ||
| } | ||
| finally { | ||
| this.__refreshLoading = false; | ||
| } | ||
| } | ||
| async _executor(browserContent) { | ||
| const page = await this._switchMP(browserContent); | ||
| await page.goto(`${WXMP_VERSION_MANAGEMENT_URL}${new URL(page.url()).search}`); | ||
| this.__currentPage = page; | ||
| try { | ||
@@ -121,41 +181,6 @@ const currentVersionData = await this._getVersionList(page); | ||
| await page.waitForTimeout(1000); | ||
| const openDialog = page.locator(".weui-desktop-dialog").filter({ hasText: "发布版本" }); | ||
| const qrCodeLocator = openDialog.locator(".weui-desktop-qrcheck__img"); | ||
| const publishQRCodeURL = await qrCodeLocator.getAttribute('src') || ''; | ||
| if (publishQRCodeURL) { | ||
| // 检查图片资源加载情况 | ||
| await qrCodeLocator.evaluate((img) => { | ||
| return new Promise((resolve, reject) => { | ||
| // 如果图片已经加载完成 (Already loaded) | ||
| if (img.complete && img.naturalWidth > 0) { | ||
| resolve(); | ||
| } | ||
| else { | ||
| // 否则监听 load 和 error 事件 | ||
| img.onload = () => resolve(); | ||
| img.onerror = () => reject(new Error('Image load failed')); | ||
| } | ||
| }); | ||
| }); | ||
| const qrCodeBuffer = await qrCodeLocator.screenshot(); | ||
| const publishQRCodeFilePath = await saveScreenshotBufferToFile(qrCodeBuffer); | ||
| this.__publishQRCodeFilePath = publishQRCodeFilePath; | ||
| this._addRunningReport({ | ||
| title: "等待扫码发布", | ||
| timestamp: Date.now(), | ||
| description: `当前版本: ${testVersionData?.version}`, | ||
| }); | ||
| //判断发布成功 | ||
| await this._waitForQrcodeScan(page); | ||
| this._addRunningReport({ | ||
| title: "发布成功", | ||
| timestamp: Date.now(), | ||
| }); | ||
| // 检查图片资源加载情况 | ||
| const qrCodeLoadingStatus = await this.getQrcodePath(); | ||
| if (!qrCodeLoadingStatus) { | ||
| return { | ||
| status: TaskStatus.COMPLETED, | ||
| endTimestamp: Date.now(), | ||
| }; | ||
| } | ||
| else { | ||
| return { | ||
| status: TaskStatus.FAILED, | ||
@@ -167,2 +192,17 @@ data: null, | ||
| } | ||
| this._addRunningReport({ | ||
| title: "等待扫码发布", | ||
| timestamp: Date.now(), | ||
| description: `当前版本: ${testVersionData?.version}`, | ||
| }); | ||
| //判断是否扫码发布 | ||
| await this._waitForQrcodeScan(page); | ||
| this._addRunningReport({ | ||
| title: "发布成功", | ||
| timestamp: Date.now(), | ||
| }); | ||
| return { | ||
| status: TaskStatus.COMPLETED, | ||
| endTimestamp: Date.now(), | ||
| }; | ||
| } | ||
@@ -169,0 +209,0 @@ catch (error) { |
+4
-4
| { | ||
| "name": "@mp-assistant/core", | ||
| "version": "0.1.3", | ||
| "version": "0.1.4", | ||
| "description": "", | ||
@@ -11,4 +11,4 @@ "main": "index.js", | ||
| "devDependencies": { | ||
| "@mp-assistant/scripts": "0.1.3", | ||
| "@mp-assistant/configuration": "0.1.3" | ||
| "@mp-assistant/configuration": "0.1.4", | ||
| "@mp-assistant/scripts": "0.1.4" | ||
| }, | ||
@@ -23,3 +23,3 @@ "repository": { | ||
| "playwright": "^1.58.2", | ||
| "@mp-assistant/common": "0.1.3" | ||
| "@mp-assistant/common": "0.1.4" | ||
| }, | ||
@@ -26,0 +26,0 @@ "scripts": { |
69570
5.22%1521
6.59%4
33.33%+ Added
- Removed
Updated