import { get, writable } from 'svelte/store'; import { addNotification, notiStore } from '../stores/noti'; import { materialFromServerQuery, recipeData, recipeDataError, recipeLoading, recipeOverviewData, recipeStreamMeta } from '../stores/recipeStore'; import { buildOverviewFromServer } from '$lib/data/recipeService'; import { auth } from '../client/firebase'; export const messages = writable([]); type WSMessage = { type: string; payload: any }; const handlers: Record void> = { chat: (p) => messages.update((m) => [...m, p]), ping: (p) => console.log('ping from server'), recipeResponse: (p) => { let recipe_result = p.result; let recipe_request = p.request; if (recipe_result) { addNotification('INFO:Start fetch recipe!'); } }, stream_data_start: (p) => { let stream_id = p.stream_id; let total_size = p.total_size; let chunk_size = p.chunk_size; if (stream_id) { addNotification('INFO:Start streaming data'); recipeLoading.set(true); recipeStreamMeta.set({ id: stream_id, total_size: total_size, chunk_size: chunk_size, progress: 0 }); recipeData.set([]); recipeOverviewData.set([]); } }, stream_data_error: (p) => { recipeLoading.set(false); recipeDataError.set(p); setTimeout(() => { addNotification(`ERROR:${p.error}`); }, 2000); }, stream_data_chunk: (p) => { let current_meta = get(recipeStreamMeta); if (current_meta) { let stream_id = current_meta.id; let progress_response_id = p.stream_id; if (stream_id === progress_response_id) { let current_response_end = p.start_idx + current_meta.chunk_size; let percent = (current_response_end / current_meta.total_size) * 100; if (percent > 100) { percent = 100; } let data = p.data; let currentData = get(recipeData); for (let rp of data) { currentData.push(rp); } recipeData.set(currentData); recipeStreamMeta.set({ ...current_meta, progress: percent }); // build overview if (percent == 100) { addNotification(`INFO:Current progress ${percent}%`); } } } }, stream_data_end: (p) => { recipeLoading.set(false); // build overview for recipe from server // buildOverviewFromServer(); }, stream_data_extra: (p) => { // extended data from server, may be extra infos // // expected last stream_id + count let exid = p.exid; let extp = p.extp; let ex_payload = p.payload; if (extp) { // know type switch (extp) { case 'matset': let curr_mat_query = get(materialFromServerQuery); // ex_payload has chunks of material setting for (let m of ex_payload) { let mid = m.id; curr_mat_query[mid] = m; } materialFromServerQuery.set(curr_mat_query); break; case 'topplist': break; case 'toppgrp': break; } } }, stream_patch_update: (p) => {}, notify: (p) => { let noti_level = p.level ?? 'INFO'; let msg = p.msg ?? `Notify from ${p.from}`; let target = p.to; if (target) { // let currentUsername = auth.currentUser?.displayName; if (currentUsername && currentUsername === target) { addNotification(`${noti_level}:${msg}`); } } else { // broadcast to all addNotification(`${noti_level}:${msg}`); } } }; export function handleIncomingMessages(raw: string) { const msg: WSMessage = JSON.parse(raw); console.log(`${new Date().toLocaleTimeString()}:ws msg`, msg); if (msg == null) { // error response addNotification('ERR:No response from server'); return; } handlers[msg.type]?.(msg.payload); }