- ipc-channels.ts SSOT에 9개 그룹/키 추가: INSTRUCTION, SYSTEM_AUDIO, POPUP_RESULT/HISTORY/COMMAND/CAPTION, VOICE_PARTIAL, CLIPBOARD, APP, VOICE_CONVERSATION.FINISH_LISTENING - WindowManager/handlers/bootstrap 하드코딩 채널 -> IPC_CHANNELS 교체. 불일치 4건(result:* vs window:tip*)은 preload 재검증 후 SSOT로 통일. notifyRenderer channel: string -> IPCChannel 타입 좁힘. - AppConfig에 7개 누락 키 추가(customInstructions, llmChains, voiceCommandRules, voiceCommandsEnabled, activeInstructionId, activeChainId, captionAudioSource) -> as never 16건 제거. - ChainService/CustomInstructionService/WindowManager dynamic require -> static import. - services/index.ts 데드 레지스트리 제거 (import 0건). SKIP: ipcSuccess/ipcError 헬퍼 통일, catch 패턴(별도) 정책: docs/REFACTOR_POLICY.md DP2, DP9
114 lines
3.1 KiB
TypeScript
114 lines
3.1 KiB
TypeScript
// src/main/ipc/cloud-sync-handlers.ts
|
|
// Phase V2-4: CloudSync IPC 핸들러
|
|
|
|
import { ipcMain, BrowserWindow } from 'electron'
|
|
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
|
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
|
import type { IPCResult } from '@d3ro/core/errors'
|
|
import { getCloudSyncService } from '../services/CloudSyncService'
|
|
import { getLogger } from '../services/LoggerService'
|
|
import { configSet } from '../services/ConfigService'
|
|
|
|
const logger = getLogger('cloud-sync-handlers')
|
|
|
|
interface SignInParams {
|
|
provider: 'google' | 'github'
|
|
}
|
|
|
|
function ok<T>(data: T): IPCResult<T> {
|
|
return { success: true, data }
|
|
}
|
|
|
|
function fail(error: unknown): IPCResult<never> {
|
|
if (error instanceof D3ROError) {
|
|
return { success: false, error: { code: error.code, message: error.message } }
|
|
}
|
|
const message = error instanceof Error ? error.message : String(error)
|
|
return {
|
|
success: false,
|
|
error: { code: ErrorCode.LLMProcessingFailed, message }
|
|
}
|
|
}
|
|
|
|
export function registerCloudSyncHandlers(): void {
|
|
const sync = getCloudSyncService()
|
|
|
|
ipcMain.handle(IPC_CHANNELS.CLOUD_SYNC.GET_STATE, () => {
|
|
try {
|
|
return ok(sync.getState())
|
|
} catch (e) {
|
|
return fail(e)
|
|
}
|
|
})
|
|
|
|
ipcMain.handle(IPC_CHANNELS.CLOUD_SYNC.SIGN_IN, async (_e, params: SignInParams) => {
|
|
try {
|
|
await sync.startSignIn(params.provider)
|
|
return ok({ started: true })
|
|
} catch (e) {
|
|
return fail(e)
|
|
}
|
|
})
|
|
|
|
ipcMain.handle(IPC_CHANNELS.CLOUD_SYNC.HANDLE_CALLBACK, async (_e, params: { code: string }) => {
|
|
try {
|
|
await sync.handleAuthCallback(params.code)
|
|
return ok(sync.getState())
|
|
} catch (e) {
|
|
return fail(e)
|
|
}
|
|
})
|
|
|
|
ipcMain.handle(IPC_CHANNELS.CLOUD_SYNC.SIGN_OUT, async () => {
|
|
try {
|
|
await sync.signOut()
|
|
return ok(sync.getState())
|
|
} catch (e) {
|
|
return fail(e)
|
|
}
|
|
})
|
|
|
|
ipcMain.handle(IPC_CHANNELS.CLOUD_SYNC.PUSH_ALL, async () => {
|
|
try {
|
|
const result = await sync.pushAll()
|
|
configSet('cloudSyncLastAt', Date.now())
|
|
return ok(result)
|
|
} catch (e) {
|
|
return fail(e)
|
|
}
|
|
})
|
|
|
|
ipcMain.handle(IPC_CHANNELS.CLOUD_SYNC.PULL_ALL, async () => {
|
|
try {
|
|
const result = await sync.pullAll()
|
|
configSet('cloudSyncLastAt', Date.now())
|
|
return ok(result)
|
|
} catch (e) {
|
|
return fail(e)
|
|
}
|
|
})
|
|
|
|
// 이벤트 → renderer 브로드캐스트
|
|
function broadcast(channel: string, payload: unknown): void {
|
|
BrowserWindow.getAllWindows().forEach((win) => {
|
|
if (!win.isDestroyed()) {
|
|
win.webContents.send(channel, payload)
|
|
}
|
|
})
|
|
}
|
|
|
|
sync.on('auth-changed', (payload) => {
|
|
broadcast(IPC_CHANNELS.CLOUD_SYNC.AUTH_CHANGED, payload)
|
|
})
|
|
sync.on('sync-progress', (payload) => {
|
|
broadcast(IPC_CHANNELS.CLOUD_SYNC.SYNC_PROGRESS, payload)
|
|
})
|
|
sync.on('sync-complete', (payload) => {
|
|
broadcast(IPC_CHANNELS.CLOUD_SYNC.SYNC_COMPLETE, payload)
|
|
})
|
|
sync.on('sync-error', (payload) => {
|
|
broadcast(IPC_CHANNELS.CLOUD_SYNC.SYNC_ERROR, payload)
|
|
})
|
|
|
|
logger.info('Cloud Sync IPC handlers registered')
|
|
}
|