| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- const DEFAULT_DEBUG_LOG_URL = 'wss://gs.gotomars.xyz/debug-log'
- const MAX_QUEUED_LOGS = 80
- export type MockSimulatorDebugLogLevel = 'info' | 'warn' | 'error'
- export interface MockSimulatorDebugLoggerState {
- enabled: boolean
- connected: boolean
- connecting: boolean
- url: string
- statusText: string
- }
- export interface MockSimulatorDebugLogEntry {
- type: 'debug-log'
- timestamp: number
- channelId?: string
- scope: string
- level: MockSimulatorDebugLogLevel
- message: string
- payload?: Record<string, unknown>
- }
- function normalizeMockSimulatorChannelId(rawChannelId: string | null | undefined): string {
- const trimmed = String(rawChannelId || '').trim()
- return trimmed || 'default'
- }
- function normalizeMockSimulatorLogUrl(rawUrl: string): string {
- const trimmed = String(rawUrl || '').trim()
- if (!trimmed) {
- return DEFAULT_DEBUG_LOG_URL
- }
- let normalized = trimmed
- if (!/^wss?:\/\//i.test(normalized)) {
- normalized = `ws://${normalized.replace(/^\/+/, '')}`
- }
- if (!/\/debug-log(?:\?.*)?$/i.test(normalized)) {
- normalized = normalized.replace(/\/+$/, '')
- normalized = `${normalized}/debug-log`
- }
- return normalized
- }
- export class MockSimulatorDebugLogger {
- socketTask: WechatMiniprogram.SocketTask | null
- enabled: boolean
- connected: boolean
- connecting: boolean
- url: string
- channelId: string
- queue: MockSimulatorDebugLogEntry[]
- onStateChange?: (state: MockSimulatorDebugLoggerState) => void
- constructor(onStateChange?: (state: MockSimulatorDebugLoggerState) => void) {
- this.socketTask = null
- this.enabled = false
- this.connected = false
- this.connecting = false
- this.url = DEFAULT_DEBUG_LOG_URL
- this.channelId = 'default'
- this.queue = []
- this.onStateChange = onStateChange
- }
- getState(): MockSimulatorDebugLoggerState {
- return {
- enabled: this.enabled,
- connected: this.connected,
- connecting: this.connecting,
- url: this.url,
- statusText: !this.enabled
- ? `已关闭 (${this.url})`
- : this.connected
- ? `已连接 (${this.url})`
- : this.connecting
- ? `连接中 (${this.url})`
- : `未连接 (${this.url})`,
- }
- }
- emitState(): void {
- if (this.onStateChange) {
- this.onStateChange(this.getState())
- }
- }
- setEnabled(enabled: boolean): void {
- if (this.enabled === enabled) {
- return
- }
- this.enabled = enabled
- if (!enabled) {
- this.disconnect()
- this.queue = []
- this.emitState()
- return
- }
- this.emitState()
- this.connect()
- }
- setUrl(url: string): void {
- const nextUrl = normalizeMockSimulatorLogUrl(url)
- if (this.url === nextUrl) {
- return
- }
- this.url = nextUrl
- if (!this.enabled) {
- this.emitState()
- return
- }
- this.disconnect()
- this.emitState()
- this.connect()
- }
- setChannelId(channelId: string): void {
- this.channelId = normalizeMockSimulatorChannelId(channelId)
- }
- log(
- scope: string,
- level: MockSimulatorDebugLogLevel,
- message: string,
- payload?: Record<string, unknown>,
- ): void {
- if (!this.enabled) {
- return
- }
- const entry: MockSimulatorDebugLogEntry = {
- type: 'debug-log',
- timestamp: Date.now(),
- channelId: this.channelId,
- scope,
- level,
- message,
- ...(payload ? { payload } : {}),
- }
- if (this.connected && this.socketTask) {
- this.send(entry)
- return
- }
- this.queue.push(entry)
- if (this.queue.length > MAX_QUEUED_LOGS) {
- this.queue.splice(0, this.queue.length - MAX_QUEUED_LOGS)
- }
- this.connect()
- }
- disconnect(): void {
- const socketTask = this.socketTask
- this.socketTask = null
- this.connected = false
- this.connecting = false
- if (socketTask) {
- try {
- socketTask.close({})
- } catch (_error) {
- // noop
- }
- }
- this.emitState()
- }
- destroy(): void {
- this.disconnect()
- this.queue = []
- }
- connect(): void {
- if (!this.enabled || this.connected || this.connecting) {
- return
- }
- this.connecting = true
- this.emitState()
- try {
- const socketTask = wx.connectSocket({
- url: this.url,
- })
- this.socketTask = socketTask
- socketTask.onOpen(() => {
- this.connected = true
- this.connecting = false
- this.emitState()
- this.send({
- type: 'debug-log',
- timestamp: Date.now(),
- channelId: this.channelId,
- scope: 'logger',
- level: 'info',
- message: 'logger channel connected',
- payload: {
- url: this.url,
- channelId: this.channelId,
- },
- })
- this.flush()
- })
- socketTask.onClose(() => {
- this.connected = false
- this.connecting = false
- this.socketTask = null
- this.emitState()
- })
- socketTask.onError(() => {
- this.connected = false
- this.connecting = false
- this.socketTask = null
- this.emitState()
- })
- socketTask.onMessage(() => {
- // 模拟器会广播所有消息,debug logger 不消费回包。
- })
- } catch (_error) {
- this.connected = false
- this.connecting = false
- this.socketTask = null
- this.emitState()
- }
- }
- flush(): void {
- if (!this.connected || !this.socketTask || !this.queue.length) {
- return
- }
- const pending = this.queue.splice(0, this.queue.length)
- pending.forEach((entry) => {
- this.send(entry)
- })
- }
- send(entry: MockSimulatorDebugLogEntry): void {
- if (!this.socketTask || !this.connected) {
- return
- }
- try {
- this.socketTask.send({
- data: JSON.stringify(entry),
- })
- } catch (_error) {
- this.connected = false
- this.connecting = false
- this.socketTask = null
- this.emitState()
- }
- }
- }
|