148 lines
5.3 KiB
TypeScript
148 lines
5.3 KiB
TypeScript
import { useCallback, useEffect } from 'react'
|
|
import { LMS_API_BASE_URL } from '../../config/appConfig'
|
|
import type { CurriculumWeek } from '../curriculum/types'
|
|
import type { ModulePrebuiltArtifact, ModuleRow, RuntimeImageArtifact } from './types'
|
|
|
|
type UseRemoteWorkspaceRuntimeOptions = {
|
|
availableModules: ModuleRow[]
|
|
curriculumModules: CurriculumWeek['modules']
|
|
courseKey: string
|
|
weekNumber: number
|
|
clonePathPreview: string
|
|
remoteWorkspace: boolean
|
|
remoteWorkspaceTargetKey: string
|
|
activeRuntimeImages: RuntimeImageArtifact[]
|
|
getFreshAccessToken: () => Promise<string>
|
|
getRemoteWorkspaceTarget: () => RemoteWorkspaceTarget
|
|
saveDirtyFilesForModule: (module: ModuleRow) => Promise<void>
|
|
onRegisterStopRunningModules?: (handler: (() => Promise<void>) | null) => void
|
|
}
|
|
|
|
type UseRemoteWorkspaceRuntimeResult = {
|
|
prepareRemoteRuntimeModule: (module: ModuleRow) => Promise<void>
|
|
}
|
|
|
|
export function useRemoteWorkspaceRuntime({
|
|
availableModules,
|
|
curriculumModules,
|
|
courseKey,
|
|
weekNumber,
|
|
clonePathPreview,
|
|
remoteWorkspace,
|
|
remoteWorkspaceTargetKey,
|
|
activeRuntimeImages,
|
|
getFreshAccessToken,
|
|
getRemoteWorkspaceTarget,
|
|
saveDirtyFilesForModule,
|
|
onRegisterStopRunningModules
|
|
}: UseRemoteWorkspaceRuntimeOptions): UseRemoteWorkspaceRuntimeResult {
|
|
const prepareRemoteRuntimeModule = useCallback(async (module: ModuleRow): Promise<void> => {
|
|
const requestAccessToken = await getFreshAccessToken()
|
|
await saveDirtyFilesForModule(module)
|
|
|
|
const response = await fetch(`${LMS_API_BASE_URL}/studio/repositories/prepare`, {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `Bearer ${requestAccessToken}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
courseId: courseKey,
|
|
week: weekNumber,
|
|
moduleName: module.name,
|
|
folderName: module.folderName,
|
|
templateRepositoryUrl: module.templateRepositoryUrl
|
|
})
|
|
})
|
|
if (!response.ok) throw new Error(await response.text())
|
|
const prepared = await response.json() as {
|
|
repositoryUrlWithToken?: string
|
|
templateRepositoryUrlWithToken?: string
|
|
templateRepositoryUrl?: string
|
|
prebuiltArtifacts?: ModulePrebuiltArtifact[] | null
|
|
}
|
|
|
|
const templateRepositoryUrl = prepared.templateRepositoryUrlWithToken ?? prepared.templateRepositoryUrl ?? module.templateRepositoryUrl
|
|
await window.remoteWorkspace.modules.install(
|
|
getRemoteWorkspaceTarget(),
|
|
module.name,
|
|
module.folderName,
|
|
templateRepositoryUrl,
|
|
prepared.repositoryUrlWithToken,
|
|
{
|
|
prebuiltArtifacts: prepared.prebuiltArtifacts ?? module.prebuiltArtifacts ?? null,
|
|
runtimeImages: activeRuntimeImages
|
|
}
|
|
)
|
|
|
|
const submitResult = remoteWorkspace
|
|
? await window.remoteWorkspace.git.submit(
|
|
getRemoteWorkspaceTarget(),
|
|
module.name,
|
|
module.folderName,
|
|
`Run: ${weekNumber}주차 ${module.name}`,
|
|
)
|
|
: await window.localWorkspace.git.submit(
|
|
module.name,
|
|
clonePathPreview,
|
|
module.folderName,
|
|
`Run: ${weekNumber}주차 ${module.name}`,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
)
|
|
if (!submitResult.ok && !submitResult.message.includes('제출할 변경사항이 없습니다')) {
|
|
throw new Error(`[${module.name}] ${submitResult.message}`)
|
|
}
|
|
}, [
|
|
activeRuntimeImages,
|
|
clonePathPreview,
|
|
courseKey,
|
|
getFreshAccessToken,
|
|
getRemoteWorkspaceTarget,
|
|
remoteWorkspace,
|
|
saveDirtyFilesForModule,
|
|
weekNumber
|
|
])
|
|
|
|
const stopRunningWorkspaceModules = useCallback(async (): Promise<void> => {
|
|
if (remoteWorkspace) {
|
|
const moduleMap = new Map<string, { moduleName: string; folderName?: string | null; templateRepositoryUrl?: string | null; sortOrder?: number | null }>()
|
|
for (const module of availableModules) {
|
|
moduleMap.set(module.name, {
|
|
moduleName: module.name,
|
|
folderName: module.folderName,
|
|
templateRepositoryUrl: module.templateRepositoryUrl,
|
|
sortOrder: module.sortOrder
|
|
})
|
|
}
|
|
for (const module of curriculumModules ?? []) {
|
|
if (!moduleMap.has(module.name)) {
|
|
moduleMap.set(module.name, {
|
|
moduleName: module.name,
|
|
folderName: module.folderName,
|
|
templateRepositoryUrl: module.templateRepositoryUrl,
|
|
sortOrder: module.sortOrder
|
|
})
|
|
}
|
|
}
|
|
const modules = Array.from(moduleMap.values())
|
|
.sort((left, right) => (right.sortOrder ?? 0) - (left.sortOrder ?? 0))
|
|
.map(({ moduleName, folderName }) => ({ moduleName, folderName }))
|
|
if (!modules.length) return
|
|
await window.remoteWorkspace.modules.resetSession(getRemoteWorkspaceTarget(), modules).catch(() => ({ ok: false, message: '플랫폼 초기화 실패' }))
|
|
return
|
|
}
|
|
await window.localWorkspace.modules.stopRunning().catch(() => ({ ok: false, message: '모듈 중지 실패' }))
|
|
}, [availableModules, curriculumModules, getRemoteWorkspaceTarget, remoteWorkspace, remoteWorkspaceTargetKey])
|
|
|
|
useEffect(() => {
|
|
onRegisterStopRunningModules?.(stopRunningWorkspaceModules)
|
|
return () => onRegisterStopRunningModules?.(null)
|
|
}, [onRegisterStopRunningModules, stopRunningWorkspaceModules])
|
|
|
|
return {
|
|
prepareRemoteRuntimeModule
|
|
}
|
|
}
|