IPC 와이어 포맷
Suji의 모든 IPC는 JSON 문자열을 단일 payload로 주고받음. V8 hidden context나 바이너리 프레임 없음 → 크로스-언어에서 같은 메시지가 그대로 흐름.
메시지 흐름
섹션 제목: “메시지 흐름”[Renderer] ──invoke──▶ [Core (Zig)] ──dispatch──▶ [Backend (Zig/Rust/Go/Node)] │ │ │ ◀────response JSON────────◀──────response JSON───────────◀- Renderer → Core: CEF
CefProcessMessage채널로 JSON 문자열 전달 - Core → Backend:
- Zig 백엔드: 같은 프로세스, 함수 호출 (
Request.raw) - Rust/Go 백엔드:
dlopencdylib,char*JSON - Node 백엔드: 같은 프로세스, libnode V8 스레드 재진입
- Zig 백엔드: 같은 프로세스, 함수 호출 (
Request JSON 기본 구조
섹션 제목: “Request JSON 기본 구조”{ "cmd": "save", // 핸들러 채널명 (필수) "content": "...", // 사용자 payload 필드 (자유) "filename": "out.txt",
"__window": 2, // (자동 주입) sender 창의 WM id "__window_name": "settings" // (자동 주입, 조건부) sender 창의 이름}예약 필드 (__ 접두사)
섹션 제목: “예약 필드 (__ 접두사)”코어가 wire에 자동 주입하는 메타데이터. 사용자 코드는 읽기만 하고 쓰지 않음.
| 필드 | 타입 | 조건 | 의미 |
|---|---|---|---|
__window | number | 항상 (renderer invoke) | sender 창의 WindowManager id |
__window_name | string | create_window에서 name 지정된 경우만 | 창의 논리적 이름 |
__window 자동 태깅 규칙
섹션 제목: “__window 자동 태깅 규칙”주입 위치
섹션 제목: “주입 위치”코어가 CEF BrowserId → WM id 변환 후 request JSON의 루트 객체에 필드를 삽입한다.
멱등성 (cross-hop 보존)
섹션 제목: “멱등성 (cross-hop 보존)”이미 "__window"가 포함된 request는 재주입 안 함. 이유:
renderer(id=2) → core → backendA → core.invoke("backendB", req) └─ 여기서 재주입하면 원 sender 정보 손실backend → backend 재호출 시 원 sender 창 id를 그대로 전파할 수 있음.
JSON-unsafe name skip
섹션 제목: “JSON-unsafe name skip”name에 ", \, 또는 control char (< 0x20)가 포함되면 __window_name 주입만
생략 (id는 정상 주입). 이유: 이스케이프 없이 직접 삽입 → JSON 파서가 깨질 수 있음.
수명 짧은 필드의 안전한 쪽 기본값.
fn isJsonSafe(s: []const u8) bool { for (s) |c| { if (c == '"' or c == '\\' or c < 0x20) return false; } return true;}빈 객체 / 공백 처리
섹션 제목: “빈 객체 / 공백 처리”{} → {"__window":2}{ } → { ,"__window":2} ❌ 아님{"cmd":"save"} → {"cmd":"save","__window":2}공백은 trim 후 } 직전에 삽입. 빈 객체는 separator 생략.
Response JSON 구조
섹션 제목: “Response JSON 구조”모든 핸들러는 JSON 객체 반환.
{ "ok": true, "msg": "pong" }
{ "error": "invalid filename" }명시적 포맷 강제는 없지만 SDK 관례:
- 성공:
{ "ok": true, ... }또는 결과 필드 직접 - 실패:
{ "error": "..." }
Zig SDK의 req.ok(.{...}) / req.err("...")가 자동으로 이 관례 적용.
크로스-백엔드 invoke
섹션 제목: “크로스-백엔드 invoke”Backend A: suji.invoke("rust", "{\"cmd\":\"ping\"}") → Core: registry lookup ("rust" 등록된 dylib) → Rust cdylib 진입점 호출 → Rust handler 실행 → response JSON 문자열 반환 → A가 결과 파싱- target 이름은 backend lang 문자열 (
"zig","rust","go","node") - 프론트엔드
suji.invoke(channel, ...)는 채널명 기준 자동 라우팅 — target 생략 가능
이벤트 발신 (send)
섹션 제목: “이벤트 발신 (send)”// core → 모든 렌더러 브로드캐스트{ "channel": "data-updated", "data": { "items": [...] }}현재 타겟 지정 불가 (모든 창에 브로드). 특정 창 지정({to: winId})은 추후 지원 예정이다.
크기 & 인코딩
섹션 제목: “크기 & 인코딩”- UTF-8 JSON (BOM 없음)
- Zig / CEF / libnode 모두 UTF-8 native
- 현재 명시적 크기 제한 없음 — 단일 payload가 수 MB를 넘으면 CEF IPC가 파편화될 수 있으므로 실무에선 청킹 권장
디버깅
섹션 제목: “디버깅”SUJI_TRACE_IPC=1 환경변수로 Zig 백엔드 핸들러가 원 JSON 덤프:
SUJI_TRACE_IPC=1 suji dev# [zig/ping] window.id=2 name=settings raw={"cmd":"ping","__window":2,"__window_name":"settings"}CEF DevTools (--remote-debugging-port=9222)에서 console.log(await suji.invoke(...))로
직접 확인 가능.
__core__ 채널 — window 조작 cmd
섹션 제목: “__core__ 채널 — window 조작 cmd”__suji__.core(JSON.stringify({cmd, ...})) 호출 시 코어가 직접 처리한다. 백엔드 SDK도
invoke("__core__", req) 경유로 같은 cmd를 사용한다.
| 카테고리 | cmd |
|---|---|
| 창/네비/JS | create_window / set_title / set_bounds / load_url / reload / execute_javascript / get_url / is_loading |
| 줌 | set_zoom_level / set_zoom_factor / get_zoom_level / get_zoom_factor |
| DevTools | open_dev_tools / close_dev_tools / is_dev_tools_opened / toggle_dev_tools |
| 편집/검색 | undo / redo / cut / copy / paste / select_all / find_in_page / stop_find_in_page |
| 인쇄 | print_to_pdf (async — 결과는 window:pdf-print-finished 이벤트) |
| Native | clipboard_read_text / clipboard_write_text / clipboard_clear / shell_open_external / shell_show_item_in_folder / shell_beep / dialog_show_message_box / dialog_show_error_box / dialog_show_open_dialog / dialog_show_save_dialog |
| Tray | tray_create / tray_set_title / tray_set_tooltip / tray_set_menu / tray_destroy |
| Notification | notification_is_supported / notification_request_permission / notification_show / notification_close |
| Menu | menu_set_application_menu / menu_reset_application_menu / menu_popup |
| Global shortcut | global_shortcut_register / global_shortcut_unregister / global_shortcut_unregister_all / global_shortcut_is_registered |
| File system | fs_read_file / fs_write_file / fs_stat / fs_mkdir / fs_readdir / fs_rm |
| 배포 | auto_updater_check_update / auto_updater_verify_file / auto_updater_download_artifact / auto_updater_prepare_install / auto_updater_quit_and_install |
window 계열 응답은 { from: "zig-core", cmd, windowId, ok, ... }, Native API 계열은
각 API별 {success} / {trayId} / {notificationId} 등 응답을 반환한다. cmd 매치는 정확 비교.