Add browser toolbar to auth windows
This commit is contained in:
@@ -2,8 +2,8 @@ import { createHash } from 'node:crypto'
|
|||||||
import {
|
import {
|
||||||
appendFileSync,
|
appendFileSync,
|
||||||
mkdirSync,
|
mkdirSync,
|
||||||
readFileSync,
|
|
||||||
readdirSync,
|
readdirSync,
|
||||||
|
readFileSync,
|
||||||
statSync,
|
statSync,
|
||||||
writeFileSync,
|
writeFileSync,
|
||||||
} from 'node:fs'
|
} from 'node:fs'
|
||||||
@@ -12,7 +12,7 @@ import { dirname, join } from 'node:path'
|
|||||||
import type { DesktopAccountInfo } from '@geo/shared-types'
|
import type { DesktopAccountInfo } from '@geo/shared-types'
|
||||||
import { aiPlatformCatalog } from '@geo/shared-types'
|
import { aiPlatformCatalog } from '@geo/shared-types'
|
||||||
import type { Cookie, Session, WebContents } from 'electron/main'
|
import type { Cookie, Session, WebContents } from 'electron/main'
|
||||||
import { BrowserWindow, app, session as electronSession, nativeTheme } from 'electron/main'
|
import { app, BrowserWindow, session as electronSession, nativeTheme } from 'electron/main'
|
||||||
|
|
||||||
import { normalizeAccountPlatformUid, sameAccountPlatformUid } from '../shared/account-identity'
|
import { normalizeAccountPlatformUid, sameAccountPlatformUid } from '../shared/account-identity'
|
||||||
import {
|
import {
|
||||||
@@ -72,7 +72,12 @@ import {
|
|||||||
} from './session-registry'
|
} from './session-registry'
|
||||||
import { upsertDesktopAccount } from './transport/api-client'
|
import { upsertDesktopAccount } from './transport/api-client'
|
||||||
import { STANDARD_USER_AGENT } from './user-agent'
|
import { STANDARD_USER_AGENT } from './user-agent'
|
||||||
import { openWorkbenchWindow } from './workbench-window'
|
import {
|
||||||
|
getWorkbenchWindowWebContents,
|
||||||
|
isWorkbenchWindowReadyForDetection,
|
||||||
|
loadWorkbenchWindowURL,
|
||||||
|
openWorkbenchWindow,
|
||||||
|
} from './workbench-window'
|
||||||
|
|
||||||
interface DetectedAccount {
|
interface DetectedAccount {
|
||||||
platformUid: string
|
platformUid: string
|
||||||
@@ -118,6 +123,11 @@ interface ActiveBindOperation {
|
|||||||
promise: Promise<DesktopAccountInfo>
|
promise: Promise<DesktopAccountInfo>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BoundWindowHandle {
|
||||||
|
window: BrowserWindow
|
||||||
|
webContents: WebContents
|
||||||
|
}
|
||||||
|
|
||||||
interface WeixinGzhConsoleState {
|
interface WeixinGzhConsoleState {
|
||||||
loggedOut: boolean
|
loggedOut: boolean
|
||||||
title: string
|
title: string
|
||||||
@@ -438,7 +448,11 @@ function appendAccountBindDiagnostic(event: Record<string, unknown>): void {
|
|||||||
const target = join(app.getPath('userData'), ACCOUNT_BIND_DIAGNOSTIC_FILE)
|
const target = join(app.getPath('userData'), ACCOUNT_BIND_DIAGNOSTIC_FILE)
|
||||||
try {
|
try {
|
||||||
mkdirSync(dirname(target), { recursive: true })
|
mkdirSync(dirname(target), { recursive: true })
|
||||||
appendFileSync(target, `${JSON.stringify({ at: new Date().toISOString(), ...event })}\n`, 'utf8')
|
appendFileSync(
|
||||||
|
target,
|
||||||
|
`${JSON.stringify({ at: new Date().toISOString(), ...event })}\n`,
|
||||||
|
'utf8',
|
||||||
|
)
|
||||||
} catch {
|
} catch {
|
||||||
// Best-effort diagnostics. Never block binding on local log writes.
|
// Best-effort diagnostics. Never block binding on local log writes.
|
||||||
}
|
}
|
||||||
@@ -447,7 +461,9 @@ function appendAccountBindDiagnostic(event: Record<string, unknown>): void {
|
|||||||
async function summarizeDoubaoAuthCookies(
|
async function summarizeDoubaoAuthCookies(
|
||||||
session: Session,
|
session: Session,
|
||||||
urls: Iterable<string>,
|
urls: Iterable<string>,
|
||||||
): Promise<Array<{ url: string | null; cookieCount: number; authCookieCount: number; authCookies: string[] }>> {
|
): Promise<
|
||||||
|
Array<{ url: string | null; cookieCount: number; authCookieCount: number; authCookies: string[] }>
|
||||||
|
> {
|
||||||
const summaries: Array<{
|
const summaries: Array<{
|
||||||
url: string | null
|
url: string | null
|
||||||
cookieCount: number
|
cookieCount: number
|
||||||
@@ -2498,14 +2514,16 @@ export async function probeAIAccountSession(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (definitionLooksLikeLoginRedirect(currentURL, {
|
if (
|
||||||
id: platformMeta.id,
|
definitionLooksLikeLoginRedirect(currentURL, {
|
||||||
label: platformMeta.label,
|
id: platformMeta.id,
|
||||||
loginUrl: platformMeta.loginUrl,
|
label: platformMeta.label,
|
||||||
consoleUrl: platformMeta.consoleUrl,
|
loginUrl: platformMeta.loginUrl,
|
||||||
detect: (context: DetectContext) =>
|
consoleUrl: platformMeta.consoleUrl,
|
||||||
detectAIPlatformAccount(platformMeta.id, platformMeta.label, context),
|
detect: (context: DetectContext) =>
|
||||||
})) {
|
detectAIPlatformAccount(platformMeta.id, platformMeta.label, context),
|
||||||
|
})
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
verdict: 'expired',
|
verdict: 'expired',
|
||||||
reason: 'login_redirect',
|
reason: 'login_redirect',
|
||||||
@@ -3082,13 +3100,13 @@ async function waitForWindowNavigationSettled(
|
|||||||
let stableSince = Date.now()
|
let stableSince = Date.now()
|
||||||
|
|
||||||
while (!window.isDestroyed() && Date.now() - startedAt < timeoutMs) {
|
while (!window.isDestroyed() && Date.now() - startedAt < timeoutMs) {
|
||||||
const currentURL = window.webContents.getURL()
|
const currentURL = getBoundWindowURL(window)
|
||||||
if (currentURL !== lastURL) {
|
if (currentURL !== lastURL) {
|
||||||
lastURL = currentURL
|
lastURL = currentURL
|
||||||
stableSince = Date.now()
|
stableSince = Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window.webContents.isLoading() && Date.now() - stableSince >= 450) {
|
if (!isBoundWindowLoading(window) && Date.now() - stableSince >= 450) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3130,14 +3148,18 @@ async function verifyToutiaoConsoleAccess(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
await loadWindowURLSafely(window, TOUTIAO_CONSOLE_HOME_URL, '头条号创作台校验')
|
await loadBoundWindowURLSafely(window, TOUTIAO_CONSOLE_HOME_URL, '头条号创作台校验')
|
||||||
await waitForWindowNavigationSettled(window)
|
await waitForWindowNavigationSettled(window)
|
||||||
|
|
||||||
if (window.isDestroyed()) {
|
if (window.isDestroyed()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentURL = window.webContents.getURL()
|
const webContents = getBoundWindowWebContents(window)
|
||||||
|
if (!webContents) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const currentURL = webContents.getURL()
|
||||||
if (isToutiaoLoginURL(currentURL)) {
|
if (isToutiaoLoginURL(currentURL)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -3147,7 +3169,7 @@ async function verifyToutiaoConsoleAccess(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pageResponse = await pageFetchJson<ToutiaoMediaInfoResponse>(
|
const pageResponse = await pageFetchJson<ToutiaoMediaInfoResponse>(
|
||||||
window.webContents,
|
webContents,
|
||||||
'https://mp.toutiao.com/mp/agw/media/get_media_info',
|
'https://mp.toutiao.com/mp/agw/media/get_media_info',
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -3228,7 +3250,11 @@ async function verifyWangyihaoConsoleAccess(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentURL = window.webContents.getURL()
|
const webContents = getBoundWindowWebContents(window)
|
||||||
|
if (!webContents) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const currentURL = webContents.getURL()
|
||||||
if (!currentURL || currentURL.startsWith('data:text/html')) {
|
if (!currentURL || currentURL.startsWith('data:text/html')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -3238,7 +3264,7 @@ async function verifyWangyihaoConsoleAccess(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageState = await readWangyihaoConsoleState(window.webContents)
|
const pageState = await readWangyihaoConsoleState(webContents)
|
||||||
if (pageState?.loggedOut) {
|
if (pageState?.loggedOut) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -3272,7 +3298,11 @@ async function verifyWangyihaoBindWindowReady(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentURL = window.webContents.getURL()
|
const webContents = getBoundWindowWebContents(window)
|
||||||
|
if (!webContents) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const currentURL = webContents.getURL()
|
||||||
const definition = platformBindingDefinitions.wangyihao
|
const definition = platformBindingDefinitions.wangyihao
|
||||||
if (!currentURL || currentURL.startsWith('data:text/html')) {
|
if (!currentURL || currentURL.startsWith('data:text/html')) {
|
||||||
return false
|
return false
|
||||||
@@ -3281,7 +3311,7 @@ async function verifyWangyihaoBindWindowReady(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageState = await readWangyihaoConsoleState(window.webContents)
|
const pageState = await readWangyihaoConsoleState(webContents)
|
||||||
if (pageState?.loggedOut) {
|
if (pageState?.loggedOut) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -3325,9 +3355,14 @@ async function verifyZolConsoleAccess(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const webContents = getBoundWindowWebContents(window)
|
||||||
|
if (!webContents) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const detected = await detectZol({
|
const detected = await detectZol({
|
||||||
session,
|
session,
|
||||||
webContents: window.webContents,
|
webContents,
|
||||||
}).catch(() => null)
|
}).catch(() => null)
|
||||||
return detected ? detectedAccountMatchesIdentity(detected, account) : false
|
return detected ? detectedAccountMatchesIdentity(detected, account) : false
|
||||||
}
|
}
|
||||||
@@ -4173,6 +4208,68 @@ function createBoundWindow(
|
|||||||
return window
|
return window
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createVisibleBoundWindow(
|
||||||
|
title: string,
|
||||||
|
targetURL: string,
|
||||||
|
sessionHandle: Session,
|
||||||
|
): Promise<BoundWindowHandle> {
|
||||||
|
const window = await openWorkbenchWindow({
|
||||||
|
title,
|
||||||
|
targetURL,
|
||||||
|
session: sessionHandle,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
window,
|
||||||
|
webContents: getWorkbenchWindowWebContents(window) ?? window.webContents,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBoundWindowWebContents(window: BrowserWindow): WebContents | null {
|
||||||
|
if (window.isDestroyed()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const contents = getWorkbenchWindowWebContents(window) ?? window.webContents
|
||||||
|
return contents && !contents.isDestroyed() ? contents : null
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBoundWindowURL(window: BrowserWindow): string {
|
||||||
|
return getBoundWindowWebContents(window)?.getURL() ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBoundWindowLoading(window: BrowserWindow): boolean {
|
||||||
|
return getBoundWindowWebContents(window)?.isLoading() ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBoundWindowReadyForDetection(window: BrowserWindow): boolean {
|
||||||
|
const contents = getBoundWindowWebContents(window)
|
||||||
|
if (!contents) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentURL = contents.getURL()
|
||||||
|
const fallbackReady =
|
||||||
|
/^https?:\/\//i.test(currentURL) &&
|
||||||
|
!currentURL.startsWith('data:text/html') &&
|
||||||
|
!contents.isLoading()
|
||||||
|
|
||||||
|
return (
|
||||||
|
isWorkbenchWindowReadyForDetection(window) || isWindowReadyForDetection(window) || fallbackReady
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadBoundWindowURLSafely(
|
||||||
|
window: BrowserWindow,
|
||||||
|
targetURL: string,
|
||||||
|
context: string,
|
||||||
|
): Promise<void> {
|
||||||
|
if (await loadWorkbenchWindowURL(window, targetURL)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await loadWindowURLSafely(window, targetURL, context)
|
||||||
|
}
|
||||||
|
|
||||||
function focusBindWindow(window: BrowserWindow): void {
|
function focusBindWindow(window: BrowserWindow): void {
|
||||||
if (window.isDestroyed()) {
|
if (window.isDestroyed()) {
|
||||||
return
|
return
|
||||||
@@ -4230,14 +4327,29 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
loginUrl: diagnosticUrl(definition.loginUrl),
|
loginUrl: diagnosticUrl(definition.loginUrl),
|
||||||
})
|
})
|
||||||
let window: BrowserWindow
|
let window: BrowserWindow
|
||||||
|
let bindWebContents: WebContents
|
||||||
|
|
||||||
try {
|
try {
|
||||||
window = createBoundWindow(`绑定 ${definition.label}`, definition.loginUrl, handle.session)
|
const boundWindow = await createVisibleBoundWindow(
|
||||||
|
`绑定 ${definition.label}`,
|
||||||
|
definition.loginUrl,
|
||||||
|
handle.session,
|
||||||
|
)
|
||||||
|
window = boundWindow.window
|
||||||
|
bindWebContents = boundWindow.webContents
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
forgetSessionHandle(handle.accountId)
|
forgetSessionHandle(handle.accountId)
|
||||||
throw error instanceof Error ? error : new Error('desktop_account_bind_failed')
|
throw error instanceof Error ? error : new Error('desktop_account_bind_failed')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentBindWebContents = (): WebContents | null => {
|
||||||
|
if (window.isDestroyed()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const contents = getWorkbenchWindowWebContents(window) ?? bindWebContents
|
||||||
|
return contents && !contents.isDestroyed() ? contents : null
|
||||||
|
}
|
||||||
|
|
||||||
const bindPromise = new Promise<DesktopAccountInfo>((resolve, reject) => {
|
const bindPromise = new Promise<DesktopAccountInfo>((resolve, reject) => {
|
||||||
let finished = false
|
let finished = false
|
||||||
let checking = false
|
let checking = false
|
||||||
@@ -4285,16 +4397,11 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
}
|
}
|
||||||
|
|
||||||
const syncDetectionState = () => {
|
const syncDetectionState = () => {
|
||||||
if (window.isDestroyed()) {
|
if (!currentBindWebContents()) {
|
||||||
detectReady = false
|
detectReady = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const currentURL = window.webContents.getURL()
|
detectReady = isBoundWindowReadyForDetection(window)
|
||||||
const fallbackReady =
|
|
||||||
/^https?:\/\//i.test(currentURL) &&
|
|
||||||
!currentURL.startsWith('data:text/html') &&
|
|
||||||
!window.webContents.isLoading()
|
|
||||||
detectReady = isWindowReadyForDetection(window) || fallbackReady
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const scheduleDetectAndBind = (delayMs = 120) => {
|
const scheduleDetectAndBind = (delayMs = 120) => {
|
||||||
@@ -4315,11 +4422,11 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
scheduleDetectAndBind()
|
scheduleDetectAndBind()
|
||||||
}
|
}
|
||||||
|
|
||||||
window.webContents.on('did-finish-load', handleNavigationReady)
|
bindWebContents.on('did-finish-load', handleNavigationReady)
|
||||||
window.webContents.on('did-navigate', handleNavigationReady)
|
bindWebContents.on('did-navigate', handleNavigationReady)
|
||||||
window.webContents.on('did-navigate-in-page', handleNavigationReady)
|
bindWebContents.on('did-navigate-in-page', handleNavigationReady)
|
||||||
window.webContents.on('page-title-updated', () => scheduleDetectAndBind(250))
|
bindWebContents.on('page-title-updated', () => scheduleDetectAndBind(250))
|
||||||
window.webContents.on(
|
bindWebContents.on(
|
||||||
'did-fail-load',
|
'did-fail-load',
|
||||||
(_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {
|
(_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {
|
||||||
if (isMainFrame && errorCode !== -3) {
|
if (isMainFrame && errorCode !== -3) {
|
||||||
@@ -4330,9 +4437,10 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
|
|
||||||
const detectAndBind = async () => {
|
const detectAndBind = async () => {
|
||||||
syncDetectionState()
|
syncDetectionState()
|
||||||
const currentURL = window.isDestroyed() ? '' : window.webContents.getURL()
|
const contents = currentBindWebContents()
|
||||||
const canProbe = detectReady || /^https?:\/\//i.test(currentURL)
|
const currentURL = contents?.getURL() ?? ''
|
||||||
if (finished || checking || !canProbe || window.isDestroyed()) {
|
const canProbe = Boolean(contents) && (detectReady || /^https?:\/\//i.test(currentURL))
|
||||||
|
if (finished || checking || !canProbe || !contents || window.isDestroyed()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
checking = true
|
checking = true
|
||||||
@@ -4342,7 +4450,7 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
platform: definition.id,
|
platform: definition.id,
|
||||||
detectReady,
|
detectReady,
|
||||||
canProbe,
|
canProbe,
|
||||||
loading: window.webContents.isLoading(),
|
loading: contents.isLoading(),
|
||||||
url: diagnosticUrl(currentURL),
|
url: diagnosticUrl(currentURL),
|
||||||
partition: handle.partition,
|
partition: handle.partition,
|
||||||
})
|
})
|
||||||
@@ -4350,11 +4458,11 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
platform: definition.id,
|
platform: definition.id,
|
||||||
detectReady,
|
detectReady,
|
||||||
canProbe,
|
canProbe,
|
||||||
loading: window.webContents.isLoading(),
|
loading: contents.isLoading(),
|
||||||
url: currentURL,
|
url: currentURL,
|
||||||
})
|
})
|
||||||
const detected = await definition
|
const detected = await definition
|
||||||
.detect({ session: handle.session, webContents: window.webContents })
|
.detect({ session: handle.session, webContents: contents })
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.warn(`[desktop-bind] ${definition.id} detect failed`, {
|
console.warn(`[desktop-bind] ${definition.id} detect failed`, {
|
||||||
message: error instanceof Error ? error.message : String(error),
|
message: error instanceof Error ? error.message : String(error),
|
||||||
@@ -4398,14 +4506,14 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
console.info('[desktop-bind] toutiao console verification', {
|
console.info('[desktop-bind] toutiao console verification', {
|
||||||
platform: definition.id,
|
platform: definition.id,
|
||||||
ready: consoleReady,
|
ready: consoleReady,
|
||||||
url: window.isDestroyed() ? '' : window.webContents.getURL(),
|
url: getBoundWindowURL(window),
|
||||||
})
|
})
|
||||||
if (!consoleReady) {
|
if (!consoleReady) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const detectedFromWorkbench = await definition
|
const detectedFromWorkbench = await definition
|
||||||
.detect({ session: handle.session, webContents: window.webContents })
|
.detect({ session: handle.session, webContents: contents })
|
||||||
.catch(() => null)
|
.catch(() => null)
|
||||||
if (detectedFromWorkbench) {
|
if (detectedFromWorkbench) {
|
||||||
normalizedDetected = sanitizeDetectedAccount(detectedFromWorkbench)
|
normalizedDetected = sanitizeDetectedAccount(detectedFromWorkbench)
|
||||||
@@ -4421,14 +4529,14 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
console.info('[desktop-bind] wangyihao console verification', {
|
console.info('[desktop-bind] wangyihao console verification', {
|
||||||
platform: definition.id,
|
platform: definition.id,
|
||||||
ready: consoleReady,
|
ready: consoleReady,
|
||||||
url: window.isDestroyed() ? '' : window.webContents.getURL(),
|
url: getBoundWindowURL(window),
|
||||||
})
|
})
|
||||||
if (!consoleReady) {
|
if (!consoleReady) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const detectedFromWorkbench = await definition
|
const detectedFromWorkbench = await definition
|
||||||
.detect({ session: handle.session, webContents: window.webContents })
|
.detect({ session: handle.session, webContents: contents })
|
||||||
.catch(() => null)
|
.catch(() => null)
|
||||||
if (detectedFromWorkbench) {
|
if (detectedFromWorkbench) {
|
||||||
normalizedDetected = sanitizeDetectedAccount(detectedFromWorkbench)
|
normalizedDetected = sanitizeDetectedAccount(detectedFromWorkbench)
|
||||||
@@ -4437,7 +4545,7 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
|
|||||||
|
|
||||||
normalizedDetected = await finalizeDetectedAccountForBind(
|
normalizedDetected = await finalizeDetectedAccountForBind(
|
||||||
definition,
|
definition,
|
||||||
{ session: handle.session, webContents: window.webContents },
|
{ session: handle.session, webContents: contents },
|
||||||
normalizedDetected,
|
normalizedDetected,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ function workbenchErrorDataURL(title: string, targetURL: string, message: string
|
|||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
<h1>${escapeHtml(title)}加载失败</h1>
|
<h1>${escapeHtml(title)}加载失败</h1>
|
||||||
<p>远程工作台暂时无法打开。可以使用窗口左上方的刷新按钮重试。</p>
|
<p>远程页面暂时无法打开。可以使用窗口左上方的刷新按钮重试。</p>
|
||||||
<code>${escapeHtml(host || targetURL)}
|
<code>${escapeHtml(host || targetURL)}
|
||||||
|
|
||||||
${escapeHtml(message)}</code>
|
${escapeHtml(message)}</code>
|
||||||
@@ -563,6 +563,19 @@ function getRecordForSender(sender: WebContents): WorkbenchWindowRecord | null {
|
|||||||
return record
|
return record
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRecordForWindow(window: BrowserWindow): WorkbenchWindowRecord | null {
|
||||||
|
const record = workbenchWindows.get(window.webContents.id)
|
||||||
|
if (
|
||||||
|
!record ||
|
||||||
|
record.window !== window ||
|
||||||
|
record.window.isDestroyed() ||
|
||||||
|
record.view.webContents.isDestroyed()
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
|
||||||
function defaultNavigationState(): WorkbenchNavigationState {
|
function defaultNavigationState(): WorkbenchNavigationState {
|
||||||
return {
|
return {
|
||||||
canGoBack: false,
|
canGoBack: false,
|
||||||
@@ -740,6 +753,38 @@ async function navigateWorkbenchRemote(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getWorkbenchWindowWebContents(window: BrowserWindow): WebContents | null {
|
||||||
|
return getRecordForWindow(window)?.view.webContents ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWorkbenchWindowReadyForDetection(window: BrowserWindow): boolean {
|
||||||
|
const record = getRecordForWindow(window)
|
||||||
|
if (!record) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentURL = record.view.webContents.getURL()
|
||||||
|
return (
|
||||||
|
isRemoteHTTPURL(currentURL) &&
|
||||||
|
!isLocalWorkbenchPage(currentURL) &&
|
||||||
|
!record.loading &&
|
||||||
|
!record.view.webContents.isLoading()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadWorkbenchWindowURL(
|
||||||
|
window: BrowserWindow,
|
||||||
|
targetURL: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const record = getRecordForWindow(window)
|
||||||
|
if (!record) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
await navigateWorkbenchRemote(record, targetURL)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
export async function openWorkbenchWindow(options: WorkbenchWindowOptions): Promise<BrowserWindow> {
|
export async function openWorkbenchWindow(options: WorkbenchWindowOptions): Promise<BrowserWindow> {
|
||||||
registerWorkbenchNavigationHandlers()
|
registerWorkbenchNavigationHandlers()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user