/**
* 카운터 스트림 워커 (HTML 예제용)
*/
// 메시지 타입 상수 정의
const MESSAGE_TYPES = {
INIT: "STREAM_INIT",
READY: "STREAM_READY",
MESSAGE: "STREAM_MESSAGE",
CLOSE: "STREAM_CLOSE",
ERROR: "STREAM_ERROR",
} as const;
// 명령 타입 상수 정의
const COMMAND_ACTIONS = {
INCREMENT: "increment",
DECREMENT: "decrement",
RESET: "reset",
GET: "get",
} as const;
// 스트림 메시지 타입 정의
interface StreamMessage {
type: string;
streamId: string;
data?: any;
timestamp: number;
}
// 명령 데이터 타입 정의
interface CommandData {
action: (typeof COMMAND_ACTIONS)[keyof typeof COMMAND_ACTIONS];
value?: number;
}
// 응답 데이터 타입 정의
interface ResponseData {
counter: number;
action: string;
error?: string;
timestamp?: number;
}
// 액티브 스트림 관리
const activeStreams = new Set();
// 카운터 상태
let counter = 0;
/**
* 초기화 메시지 처리 함수
*/
function handleInit(message: StreamMessage): void {
if (activeStreams.has(message.streamId)) {
sendError(
message.streamId,
`스트림 ${message.streamId}이(가) 이미 존재합니다`
);
return;
}
// 스트림 등록
activeStreams.add(message.streamId);
console.log(`스트림 ${message.streamId} 초기화됨`);
// 시작 값 설정
if (message.data && typeof message.data.startValue === "number") {
counter = message.data.startValue;
} else {
counter = 0;
}
// 준비 완료 응답
sendReady(message.streamId);
// 초기 카운터 값 전송
sendResponse(message.streamId, "init");
}
/**
* 스트림 메시지 처리 함수
*/
function handleMessage(message: StreamMessage): void {
if (!activeStreams.has(message.streamId)) {
sendError(
message.streamId,
`스트림 ${message.streamId}을(를) 찾을 수 없습니다`
);
return;
}
// 명령 처리
const data = message.data as CommandData;
processCommand(message.streamId, data);
}
/**
* 스트림 종료 처리 함수
*/
function handleClose(message: StreamMessage): void {
if (!activeStreams.has(message.streamId)) {
console.warn(`종료할 스트림 ${message.streamId}을(를) 찾을 수 없습니다`);
return;
}
try {
// 스트림 제거
activeStreams.delete(message.streamId);
console.log(`스트림 ${message.streamId} 종료됨`);
// 모든 스트림이 종료되었는지 확인
if (activeStreams.size === 0) {
console.log("모든 스트림이 종료되었습니다");
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`스트림 ${message.streamId} 종료 중 오류 발생:`, error);
sendError(message.streamId, `스트림 종료 중 오류 발생: ${errorMessage}`);
}
}
/**
* 명령 처리 함수
*/
function processCommand(streamId: string, data: CommandData): void {
if (!data || !data.action) {
sendError(streamId, "유효하지 않은 명령입니다");
return;
}
// 기본값 처리
const value = data.value ?? 1;
// 명령 실행
switch (data.action) {
case COMMAND_ACTIONS.INCREMENT:
counter += value;
break;
case COMMAND_ACTIONS.DECREMENT:
counter -= value;
break;
case COMMAND_ACTIONS.RESET:
counter = data.value ?? 0;
break;
case COMMAND_ACTIONS.GET:
// 값 조회만 수행
break;
default:
console.warn(`알 수 없는 명령: ${data.action}`);
sendError(streamId, `지원하지 않는 명령: ${data.action}`);
return;
}
// 응답 전송
sendResponse(streamId, data.action);
}
/**
* 준비 완료 메시지 전송 함수
*/
function sendReady(streamId: string): void {
self.postMessage({
type: MESSAGE_TYPES.READY,
streamId,
timestamp: Date.now(),
});
}
/**
* 응답 메시지 전송 함수
*/
function sendResponse(streamId: string, action: string): void {
self.postMessage({
type: MESSAGE_TYPES.MESSAGE,
streamId,
data: {
counter,
action,
timestamp: Date.now(),
} as ResponseData,
timestamp: Date.now(),
});
}
/**
* 오류 메시지 전송 함수
*/
function sendError(streamId: string, errorMessage: string): void {
console.error(errorMessage);
self.postMessage({
type: MESSAGE_TYPES.ERROR,
streamId,
data: {
error: errorMessage,
counter,
action: "error",
timestamp: Date.now(),
} as ResponseData,
timestamp: Date.now(),
});
}
// 메시지 리스너 등록
self.addEventListener("message", (event: MessageEvent) => {
const message = event.data;
try {
if (!message || !message.type) {
console.error("유효하지 않은 메시지 형식입니다");
return;
}
// 메시지 타입에 따른 처리
switch (message.type) {
case MESSAGE_TYPES.INIT:
handleInit(message);
break;
case MESSAGE_TYPES.MESSAGE:
handleMessage(message);
break;
case MESSAGE_TYPES.CLOSE:
handleClose(message);
break;
default:
console.warn(`지원하지 않는 메시지 타입: ${message.type}`);
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error("메시지 처리 중 오류 발생:", error);
if (message) {
sendError(message.streamId, `메시지 처리 중 오류 발생: ${errorMessage}`);
}
}
});
// 워커 종료 시 정리
self.addEventListener("unload", () => {
try {
// 남아있는 스트림 정리
for (const streamId of activeStreams) {
console.log(`워커 종료 전 스트림 ${streamId} 정리`);
activeStreams.delete(streamId);
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error("워커 종료 중 오류 발생:", errorMessage);
}
});
// 파일을 모듈로 만들기 위한 빈 export 구문
export {};