클라이언트 API와 이벤트
기준 소스: IOCore. 브라우저와 Node.js는 같은 핵심 API를 사용하지만 import 경로가 다릅니다.
| 환경 | 가져오기 |
|---|---|
| Node.js | import { IO } from 'iosignal' |
| 브라우저 번들러 | import IO from 'iosignal/io' |
new IO('ws://localhost:7777')처럼 서버의 WebSocket 주소로 생성합니다.
| 메서드 | 용도 |
|---|---|
listen(tag, handler) | 일반 태그는 핸들러 등록과 자동 구독을 설정합니다. @ 또는 @topic은 구독 없이 직접 수신 핸들러만 등록합니다. |
subscribe(tag) / unsubscribe(tag) | 구독 시점과 해제를 직접 제어합니다. 수동 구독은 ready 이후에 호출하고 재접속 시 다시 등록합니다. |
signal(tag, ...args) / publish(tag, ...args) | 태그로 메시지를 전송합니다. |
auth(id, key) / login(id, key) | 인증 정보를 설정하거나 현재 연결에서 로그인합니다. 인증 참조. |
call(target, topic, ...args) | 서버 서비스 요청을 전송하고 응답 Promise를 받습니다. |
open(url?) | 연결을 열거나 다시 엽니다. |
stop() | 자동 재연결을 끄고 연결을 종료합니다. 나중에 다시 열 수 있습니다. |
destroy() | 리스너와 자원을 정리합니다. 인스턴스를 다시 사용하지 않습니다. |
| 이벤트 | 사용 시점 |
|---|---|
ready | CID를 받고 통신 가능한 상태가 되었을 때. io.cid를 읽거나 직접 subscribe합니다. |
change | 상태 이름이 바뀌었을 때. UI의 연결 상태를 갱신합니다. |
message | 채널 구독 및 CID 발행 구독으로 받은 시그널을 (tag, ...args)로 공통 처리합니다. 직접 시그널은 전달되지 않습니다. |
@ | 자신에게 온 모든 직접 시그널을 (tag, ...args)로 처리합니다. tag는 수신자 CID가 제거된 @topic 또는 @입니다. 구독은 필요하지 않습니다. |
@topic | 정확히 일치하는 직접 수신 토픽을 (tag, ...args)로 처리합니다. @ 이벤트 다음에 발생하며 구독은 필요하지 않습니다. |
error | 연결 또는 처리 오류를 표시할 때. |
auth_fail | 인증이 거부되었을 때. 잘못된 인증 정보이거나 keepOld 서버의 중복 로그인입니다. |
auth_clear | 서버가 인증을 해제했을 때. 예: keepNew 서버에서 같은 ID의 새 연결로 교체됨. 인증 정보가 지워지고 자동 재연결이 꺼집니다. |
| 구독 태그 이름 | 구독 수신을 정확한 태그 이름으로 처리합니다. 예: room#chat, A@status. on(tag, handler)는 핸들러만 등록하므로 서버 구독은 별도로 필요합니다. |
두 가지 구독 방식과 용도
실행 예제는 연결 수명주기와 구독에 모았습니다. listen() 자동 구독은 ready 핸들러 이후에 전송됩니다. 구독 직후 송신할 때는 ready에서 subscribe()를 먼저 호출하세요.
태그 길이와 구독 목록
- 시그널 태그는 UTF-8 기준 최대 255바이트입니다. JS의 문자열
.length와 다릅니다. 예를 들어가85개는 255바이트이고, 86개는 초과합니다. - 송신 메서드(
signal(),publish(),getSignalPack(),signal_e2e())는 초과 태그를TypeError로 거부하고,listen()/link()/unlink()도 길이를 검사하며 빈 태그를 허용하지 않습니다. subscribe('a,b')·unsubscribe('a,b')는 쉼표를 포함한 전체가 255바이트 이내여야 하므로 긴 목록은 나눠 호출합니다.listen()으로 저장한 자동 구독 목록은 라이브러리가 태그 경계에서 255바이트 이하로 나눠 보냅니다.- CID 발행
@topic은 서버가 붙이는 송신자 CID까지 포함해 255바이트 이내여야 하며, 초과하면 서버가 전달·보관하지 않습니다.
구독 수신과 직접 수신 구분
직접 시그널은 on()·listen()으로 '@'(모든 직접 시그널) 또는 '@topic'(정확한 토픽)에 등록해 받으며 서버 구독이 필요 없습니다. message로는 오지 않고, 같은 처리를 '@'와 '@topic' 양쪽에 등록하면 두 번 실행됩니다.
// 연결 전에 핸들러를 등록합니다.
io.on('message', (tag, ...args) => {
// room#chat 같은 채널 구독 또는 A@status 같은 CID 발행 구독 수신
console.log('구독 수신', tag, args);
});
io.on('@', (tag, ...args) => {
// 상대가 <내 CID>@set으로 송신하면 tag는 @set입니다.
if (tag === '@set') {
console.log('직접 명령', args);
}
});
io.on('ready', () => {
io.subscribe('room#chat,A@status'); // A는 구독할 발행자의 실제 CID로 변경
});
직접 시그널은 '@' 다음에 정확한 태그 이벤트(예: '@set')가 동기적으로 발생하며, 태그가 '@'이면 한 번만 발생합니다. A@status 구독으로 받은 시그널은 'A@status'와 'message'로 전달됩니다.
// 특정 직접 수신 토픽만 처리: subscribe() 불필요
io.listen('@set', (tag, value) => {
console.log(tag, value);
});
'@' 핸들러에서 emit(tag, ...)로 수동 전달하던 코드가 남아 있으면 중복 실행됩니다. 핸들러의 return false는 다음 이벤트를 취소하지 않으며 async 핸들러의 완료를 기다리지 않습니다. 객체와 바이너리 인자는 공유되므로 앞선 핸들러의 변경이 뒤의 핸들러에 보일 수 있습니다. 동기 예외는 현재 수신 처리의 catch에서 기록되고 남은 전달을 중단합니다.
Arduino는 onMessage를 한 번 호출합니다. 태그와 라이브러리 이벤트는 같은 이름 공간을 쓰므로 message, ready, error 같은 이름은 채널명으로 피하세요.
IO 인스턴스를 단독 소유하는 컴포넌트가 사라질 때는 destroy()를 호출하세요. 여러 컴포넌트가 IO를 공유한다면 해당 컴포넌트의 unlinkAll(component)로 연결만 해제하세요. 실행 예제는 Vanilla와 React를 참고하세요.
컴포넌트 단위 link / unlink
공유 클라이언트의 수명주기와 link/unlink 예제를 참고하세요.