后端迁移会话活动信息模块
This commit is contained in:
+94
-17
@@ -1,9 +1,83 @@
|
|||||||
// @ts-nocheck
|
/// <reference lib="dom" />
|
||||||
|
|
||||||
import { extractHostState, reloadActivityPageForPresentation } from './session-page.js'
|
import { extractHostState, reloadActivityPageForPresentation } from './session-page.js'
|
||||||
import { shouldRefreshLoggedInPresentation } from './session-state.js'
|
import { shouldRefreshLoggedInPresentation } from './session-state.js'
|
||||||
|
|
||||||
export function createEmptyActivityInfo() {
|
type BrowserPageLike = {
|
||||||
|
evaluate: <T = any>(callback: any) => Promise<T>
|
||||||
|
waitForTimeout: (milliseconds: number) => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostState = {
|
||||||
|
loginText?: string
|
||||||
|
unloginVisible?: boolean
|
||||||
|
loginedVisible?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ActivityInfo = {
|
||||||
|
nickname: string
|
||||||
|
role: {
|
||||||
|
ready: boolean
|
||||||
|
roleName: string
|
||||||
|
roleId: string
|
||||||
|
area: string
|
||||||
|
partition: string
|
||||||
|
platId: string
|
||||||
|
md5str: string
|
||||||
|
checkparam: string
|
||||||
|
}
|
||||||
|
form: {
|
||||||
|
cdkeyInputId: string
|
||||||
|
cdkeyValue: string
|
||||||
|
verifyInputId: string
|
||||||
|
verifyValue: string
|
||||||
|
verifyImgId: string
|
||||||
|
submitId: string
|
||||||
|
}
|
||||||
|
verify: {
|
||||||
|
visible: boolean
|
||||||
|
src: string
|
||||||
|
naturalWidth: number
|
||||||
|
naturalHeight: number
|
||||||
|
}
|
||||||
|
popup: {
|
||||||
|
visible: boolean
|
||||||
|
text: string
|
||||||
|
detail: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionForPresentation = {
|
||||||
|
page: BrowserPageLike
|
||||||
|
presentationSyncAttempts: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnsureLoggedInPresentationOptions = {
|
||||||
|
hostState?: HostState | null
|
||||||
|
credentialReady?: boolean
|
||||||
|
activityUrl?: string
|
||||||
|
extractHostState?: (page: BrowserPageLike) => Promise<HostState>
|
||||||
|
reloadActivityPageForPresentation?: (page: BrowserPageLike, activityUrl: string) => Promise<unknown>
|
||||||
|
shouldRefreshLoggedInPresentation?: (hostState: HostState) => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnsureActivityInfoReadyOptions = {
|
||||||
|
triggerRender?: boolean
|
||||||
|
timeoutMs?: number
|
||||||
|
extractActivityInfo?: (page: BrowserPageLike) => Promise<ActivityInfo>
|
||||||
|
triggerActivityRoleRender?: (page: BrowserPageLike) => Promise<unknown>
|
||||||
|
now?: () => number
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
renderCdkey?: () => void
|
||||||
|
roleData?: Record<string, unknown>
|
||||||
|
isRole?: unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createEmptyActivityInfo(): ActivityInfo {
|
||||||
return {
|
return {
|
||||||
nickname: '',
|
nickname: '',
|
||||||
role: {
|
role: {
|
||||||
@@ -39,7 +113,7 @@ export function createEmptyActivityInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function ensureLoggedInPresentation(
|
export async function ensureLoggedInPresentation(
|
||||||
session,
|
session: SessionForPresentation,
|
||||||
{
|
{
|
||||||
hostState = null,
|
hostState = null,
|
||||||
credentialReady = false,
|
credentialReady = false,
|
||||||
@@ -47,8 +121,8 @@ export async function ensureLoggedInPresentation(
|
|||||||
extractHostState: extractHostStateImpl = extractHostState,
|
extractHostState: extractHostStateImpl = extractHostState,
|
||||||
reloadActivityPageForPresentation: reloadActivityPageForPresentationImpl = reloadActivityPageForPresentation,
|
reloadActivityPageForPresentation: reloadActivityPageForPresentationImpl = reloadActivityPageForPresentation,
|
||||||
shouldRefreshLoggedInPresentation: shouldRefreshLoggedInPresentationImpl = shouldRefreshLoggedInPresentation,
|
shouldRefreshLoggedInPresentation: shouldRefreshLoggedInPresentationImpl = shouldRefreshLoggedInPresentation,
|
||||||
} = {},
|
}: EnsureLoggedInPresentationOptions = {},
|
||||||
) {
|
): Promise<{ reloaded: boolean; hostState: HostState }> {
|
||||||
let nextHostState = hostState || (await extractHostStateImpl(session.page))
|
let nextHostState = hostState || (await extractHostStateImpl(session.page))
|
||||||
|
|
||||||
if (!credentialReady || !shouldRefreshLoggedInPresentationImpl(nextHostState)) {
|
if (!credentialReady || !shouldRefreshLoggedInPresentationImpl(nextHostState)) {
|
||||||
@@ -76,15 +150,15 @@ export async function ensureLoggedInPresentation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function ensureActivityInfoReady(
|
export async function ensureActivityInfoReady(
|
||||||
page,
|
page: BrowserPageLike,
|
||||||
{
|
{
|
||||||
triggerRender = false,
|
triggerRender = false,
|
||||||
timeoutMs = 8_000,
|
timeoutMs = 8_000,
|
||||||
extractActivityInfo: extractActivityInfoImpl = extractActivityInfo,
|
extractActivityInfo: extractActivityInfoImpl = extractActivityInfo,
|
||||||
triggerActivityRoleRender: triggerActivityRoleRenderImpl = triggerActivityRoleRender,
|
triggerActivityRoleRender: triggerActivityRoleRenderImpl = triggerActivityRoleRender,
|
||||||
now = () => Date.now(),
|
now = () => Date.now(),
|
||||||
} = {},
|
}: EnsureActivityInfoReadyOptions = {},
|
||||||
) {
|
): Promise<ActivityInfo> {
|
||||||
if (triggerRender) {
|
if (triggerRender) {
|
||||||
await triggerActivityRoleRenderImpl(page)
|
await triggerActivityRoleRenderImpl(page)
|
||||||
}
|
}
|
||||||
@@ -104,7 +178,7 @@ export async function ensureActivityInfoReady(
|
|||||||
return lastInfo
|
return lastInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function triggerActivityRoleRender(page) {
|
export async function triggerActivityRoleRender(page: BrowserPageLike): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
const maybeRender = window.renderCdkey
|
const maybeRender = window.renderCdkey
|
||||||
@@ -118,11 +192,11 @@ export async function triggerActivityRoleRender(page) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function extractActivityInfo(page) {
|
export async function extractActivityInfo(page: BrowserPageLike): Promise<ActivityInfo> {
|
||||||
try {
|
try {
|
||||||
return await page.evaluate(() => {
|
return await page.evaluate(() => {
|
||||||
const asString = (value) => (typeof value === 'string' ? value.trim() : '')
|
const asString = (value: unknown) => (typeof value === 'string' ? value.trim() : '')
|
||||||
const isVisible = (element) => {
|
const isVisible = (element: Element | null) => {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -131,8 +205,11 @@ export async function extractActivityInfo(page) {
|
|||||||
return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'
|
return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
const pick = (selector) => document.querySelector(selector)
|
const pick = (selector: string) => document.querySelector(selector)
|
||||||
const pickBest = (selector, predicate = null) => {
|
const pickBest = (
|
||||||
|
selector: string,
|
||||||
|
predicate: ((element: Element) => boolean) | null = null,
|
||||||
|
): Element | null => {
|
||||||
const matches = [...document.querySelectorAll(selector)]
|
const matches = [...document.querySelectorAll(selector)]
|
||||||
const preferred = matches.find((element) => {
|
const preferred = matches.find((element) => {
|
||||||
if (predicate && !predicate(element)) {
|
if (predicate && !predicate(element)) {
|
||||||
@@ -170,7 +247,7 @@ export async function extractActivityInfo(page) {
|
|||||||
const roleSelector = pick('[id^="milo_role_selector_"]')
|
const roleSelector = pick('[id^="milo_role_selector_"]')
|
||||||
const roleNameText =
|
const roleNameText =
|
||||||
textOf('#role_name') ||
|
textOf('#role_name') ||
|
||||||
asString(roleSelector?.selectedOptions?.[0]?.textContent || '')
|
asString(roleSelector instanceof HTMLSelectElement ? roleSelector.selectedOptions?.[0]?.textContent || '' : '')
|
||||||
const verifyImg = pickBest('[id^="milo_verifyImg_"]', (node) => node instanceof HTMLImageElement)
|
const verifyImg = pickBest('[id^="milo_verifyImg_"]', (node) => node instanceof HTMLImageElement)
|
||||||
const popup = pick('#pop2')
|
const popup = pick('#pop2')
|
||||||
const cdkeyInput = pickBest(
|
const cdkeyInput = pickBest(
|
||||||
@@ -215,8 +292,8 @@ export async function extractActivityInfo(page) {
|
|||||||
verify: {
|
verify: {
|
||||||
visible: isVisible(verifyImg),
|
visible: isVisible(verifyImg),
|
||||||
src: asString(verifyImg?.getAttribute('src')),
|
src: asString(verifyImg?.getAttribute('src')),
|
||||||
naturalWidth: Number(verifyImg?.naturalWidth || 0),
|
naturalWidth: verifyImg instanceof HTMLImageElement ? Number(verifyImg.naturalWidth || 0) : 0,
|
||||||
naturalHeight: Number(verifyImg?.naturalHeight || 0),
|
naturalHeight: verifyImg instanceof HTMLImageElement ? Number(verifyImg.naturalHeight || 0) : 0,
|
||||||
},
|
},
|
||||||
popup: {
|
popup: {
|
||||||
visible: isVisible(popup),
|
visible: isVisible(popup),
|
||||||
@@ -488,6 +488,14 @@
|
|||||||
- `npm run typecheck`
|
- `npm run typecheck`
|
||||||
- `npm run build`
|
- `npm run build`
|
||||||
- `npm test` 共 139 个用例通过
|
- `npm test` 共 139 个用例通过
|
||||||
|
104. 腾讯浏览器会话 activity 信息模块迁移到 `.ts`:
|
||||||
|
- `src/services/session/session-activity.ts`
|
||||||
|
105. 活动角色 / 表单 / 验证码 / 弹窗信息结构、登录态 presentation 同步、角色渲染触发与轮询已显式类型化
|
||||||
|
106. Docker 内验证通过:
|
||||||
|
- `src/services/session/session.test.js` 共 14 个用例通过
|
||||||
|
- `npm run typecheck`
|
||||||
|
- `npm run build`
|
||||||
|
- `npm test` 共 139 个用例通过
|
||||||
|
|
||||||
## 下一步建议
|
## 下一步建议
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user