-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#58] 테스트 실행 중지 기능 추가하기 #89
The head ref may contain hidden characters: "58-\uD14C\uC2A4\uD2B8-\uC2E4\uD589-\uC911\uC9C0-\uAE30\uB2A5-\uCD94\uAC00\uD558\uAE30"
Changes from all commits
22b799a
e797bd1
02bb864
6c329eb
efd4154
cc0f398
3c1a60e
a30faf4
4e5c3a3
6236949
bb3cc38
5a7a688
659efdf
22fa677
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { css } from '@style/css'; | ||
|
||
import type { ChangeEvent, HTMLAttributes } from 'react'; | ||
|
||
import type { SimulationInput } from '@/hooks/simulation'; | ||
|
||
interface Props extends HTMLAttributes<HTMLUListElement> { | ||
inputList: SimulationInput[]; | ||
onChangeInput: (index: number, newInput: string) => void; | ||
} | ||
|
||
export function SimulationInputList(props: Props) { | ||
const { inputList, onChangeInput, ...rest } = props; | ||
|
||
const handleInputChange = (index: number, newInput: string) => { | ||
onChangeInput(index, newInput); | ||
}; | ||
|
||
return ( | ||
<ul {...rest}> | ||
{inputList.map(({ input, id }, index) => ( | ||
<li key={id} className={listStyle}> | ||
케이스 {index}: | ||
<SimulationInput | ||
value={input} | ||
onChange={(newInput) => handleInputChange(id, newInput)} | ||
></SimulationInput> | ||
</li> | ||
))} | ||
</ul> | ||
); | ||
} | ||
|
||
interface SimulationInputProps { | ||
value: string; | ||
onChange: (newInput: string) => void; | ||
} | ||
|
||
const SimulationInput = (props: SimulationInputProps) => { | ||
const { value, onChange } = props; | ||
|
||
const handleInput = (e: ChangeEvent<HTMLInputElement>) => { | ||
const newInput = e.target.value; | ||
if (onChange) { | ||
onChange(newInput); | ||
} | ||
}; | ||
|
||
return <input value={value} className={inputStyle} onChange={handleInput}></input>; | ||
}; | ||
|
||
const listStyle = css({ | ||
marginBottom: '0.25rem', | ||
}); | ||
|
||
const inputStyle = css({ | ||
color: 'black', | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { HTMLAttributes } from 'react'; | ||
|
||
import type { SimulationResult } from '@/hooks/simulation'; | ||
|
||
interface Props extends HTMLAttributes<HTMLUListElement> { | ||
resultList: SimulationResult[]; | ||
} | ||
|
||
export function SimulationResultList(props: Props) { | ||
const { resultList = [] } = props; | ||
|
||
return ( | ||
<ul> | ||
{resultList.map((result) => ( | ||
<li key={result.id}> | ||
<div> | ||
<p>입력: {result.input}</p> | ||
<p>결과: {String(result.output)}</p> | ||
<hr /> | ||
</div> | ||
</li> | ||
))} | ||
</ul> | ||
); | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './useSimulations'; | ||
export * from './types'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export type SimulationInput = { | ||
id: number; | ||
input: string; | ||
}; | ||
|
||
export type SimulationResult = { | ||
id: number; | ||
isDone: boolean; | ||
input: string; | ||
output: unknown; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { useEffect, useMemo, useState } from 'react'; | ||
|
||
import evaluator from '@/modules/evaluator'; | ||
|
||
import type { SimulationInput, SimulationResult } from './types'; | ||
|
||
export const useSimulations = () => { | ||
const [simulationInputs, setSimulationInputs] = useState<SimulationInput[]>([ | ||
{ id: 1, input: '' }, | ||
{ id: 2, input: '' }, | ||
{ id: 3, input: '' }, | ||
{ id: 4, input: '' }, | ||
{ id: 5, input: '' }, | ||
]); | ||
const [simulationResults, setSimulationResults] = useState<SimulationResult[]>([ | ||
{ id: 1, isDone: true, input: '', output: '' }, | ||
{ id: 2, isDone: true, input: '', output: '' }, | ||
{ id: 3, isDone: true, input: '', output: '' }, | ||
{ id: 4, isDone: true, input: '', output: '' }, | ||
{ id: 5, isDone: true, input: '', output: '' }, | ||
]); | ||
const isSimulating = useMemo(() => { | ||
return simulationResults.some((result) => !result.isDone); | ||
}, [simulationResults]); | ||
|
||
useEffect(() => { | ||
return evaluator.subscribe(({ result, error, task }) => { | ||
if (!task) return; | ||
|
||
setSimulationResults((simulations) => { | ||
return simulations.map((simul) => { | ||
if (simul.id !== task.clientId) return simul; | ||
|
||
if (error) { | ||
return { | ||
...simul, | ||
isDone: true, | ||
output: `${error.name}: ${error.message} \n${error.stack}`, | ||
}; | ||
} | ||
return { | ||
...simul, | ||
isDone: true, | ||
output: result, | ||
}; | ||
}); | ||
}); | ||
}); | ||
}, []); | ||
|
||
function runSimulation(code: string) { | ||
const tasks = simulationInputs.map(({ id, input }) => | ||
evaluator.createEvalMessage(id, code, input), | ||
); | ||
|
||
const isRequestSuccess = evaluator.evaluate(tasks); | ||
|
||
if (!isRequestSuccess) { | ||
return; | ||
} | ||
|
||
setSimulationResults((simulResults) => { | ||
return simulResults | ||
.map((simul, index) => ({ | ||
...simul, | ||
input: simulationInputs[index].input, | ||
})) | ||
.map(toEvaluatingState); | ||
}); | ||
} | ||
|
||
function changeInput(targetId: number, newParam: string) { | ||
const changedSimulation = simulationInputs.find(({ id }) => id === targetId); | ||
if (changedSimulation) { | ||
changedSimulation.input = newParam; | ||
} | ||
setSimulationInputs([...simulationInputs]); | ||
} | ||
|
||
function cancelSimulation() { | ||
evaluator.cancelEvaluation(); | ||
} | ||
|
||
return { | ||
simulationInputs, | ||
simulationResults, | ||
isSimulating, | ||
runSimulation, | ||
cancelSimulation, | ||
changeInput, | ||
}; | ||
}; | ||
|
||
const toEvaluatingState = (simulation: SimulationResult) => { | ||
return { | ||
...simulation, | ||
output: '계산중...', | ||
isDone: false, | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,16 @@ function evaluate(tasks: EvalMessage[]) { | |
|
||
evalManager.queueTasks(tasks); | ||
evalManager.deployTask(); | ||
|
||
return true; | ||
} | ||
|
||
function cancelEvaluation() { | ||
evalWorkers.forEach(({ worker }) => worker.terminate()); | ||
evalManager.cancelTasks(); | ||
|
||
const newEvalWorkers = range(0, TOTAL_WORKERS).map(createEvaluator); | ||
evalManager.setNewWorkers(newEvalWorkers); | ||
Comment on lines
+26
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네이밍을 잘 하니, 이 코드만 봐도 어떤 일들을 할 지 예상이 가네요. 진짜 좋습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네, while(true)로 한 스레드가 먹통이 되어버리면 그 스레드를 통째로 드러내야해서 cancel하면 워커를 종료시키고 새로 등록합니다. 좀 더 정밀하게 하자면 쉬고 있는 워커는 놔두고 일하고 있는 워커만 새로 만드는 방법도 있는데, 그건 그냥 귀찮아서... :) |
||
} | ||
|
||
function subscribe(listener: Listener<TaskEndMessage>) { | ||
|
@@ -27,6 +37,7 @@ function subscribe(listener: Listener<TaskEndMessage>) { | |
|
||
export default { | ||
evaluate, | ||
cancelEvaluation, | ||
subscribe, | ||
createEvalMessage, | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isXXX : boolean;
if(!isXXX) return ;
이렇게 하니 가독성 좋네요