Supra_App/src/lib/core/handlers/messageHandler.ts

275 lines
6.6 KiB
TypeScript
Raw Normal View History

2026-02-17 14:30:02 +07:00
import { get, writable } from 'svelte/store';
import { addNotification, notiStore } from '../stores/noti';
import {
currentRecipeVersionsSelector,
materialFromServerQuery,
priceRecipeData,
2026-02-17 14:30:02 +07:00
recipeData,
recipeDataError,
recipeLoading,
recipeOverviewData,
recipeStreamMeta,
toppingGroupFromServerQuery,
toppingListFromServerQuery
2026-02-17 14:30:02 +07:00
} from '../stores/recipeStore';
import { buildOverviewFromServer } from '$lib/data/recipeService';
import { auth } from '../client/firebase';
import { type RecipeVersion } from '$lib/models/recipe_version.model';
import { goto } from '$app/navigation';
import { socketAlreadySendHeartbeat, socketConnectionOfflineCount } from '../stores/websocketStore';
import type { RecipePrice } from '$lib/models/price.model';
import { sendMessage } from './ws_messageSender';
import { auth as authStore } from '../stores/auth';
2026-02-17 14:30:02 +07:00
export const messages = writable<string[]>([]);
type WSMessage = { type: string; payload: any };
const handlers: Record<string, (payload: any) => 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;
let data_meta = p.metadata;
2026-02-17 14:30:02 +07:00
if (stream_id) {
addNotification('INFO:Start streaming data');
let meta_list = data_meta?.split(',');
let version = meta_list[0]?.split('=')[1] ?? '';
let country = meta_list[1]?.split('=')[1] ?? '';
// recipeLoading.set(true);
2026-02-17 14:30:02 +07:00
recipeStreamMeta.set({
id: stream_id,
total_size: total_size,
chunk_size: chunk_size,
progress: 0,
version,
country
2026-02-17 14:30:02 +07:00
});
recipeData.set([]);
recipeOverviewData.set([]);
materialFromServerQuery.set([]);
toppingListFromServerQuery.set([]);
toppingGroupFromServerQuery.set([]);
2026-02-17 14:30:02 +07:00
}
},
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);
// console.log('current meta', current_meta);
2026-02-17 14:30:02 +07:00
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}%`);
}
buildOverviewFromServer();
2026-02-17 14:30:02 +07:00
}
}
},
stream_data_end: (p) => {
recipeLoading.set(false);
// build overview for recipe from server
//
// console.log('ending stream');
buildOverviewFromServer();
let current_meta = get(recipeStreamMeta);
let curr_user = get(authStore);
let user_info: any;
if (curr_user) {
user_info = {
displayName: curr_user.displayName,
email: curr_user.email,
uid: curr_user.uid
};
}
// send next chain message
sendMessage({
type: 'price',
payload: {
action: {
View: 'sa=all'
},
country: current_meta?.country ?? '',
parameters: '',
user_info
}
});
},
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) ?? [];
if (!curr_mat_query) {
curr_mat_query = [];
}
// ex_payload has chunks of material setting
for (let m of ex_payload) {
let mid = m.id;
// curr_mat_query[mid] = m;
curr_mat_query.push(m);
}
// // console.log('current materials: ', JSON.stringify(curr_mat_query));
materialFromServerQuery.set(curr_mat_query);
break;
case 'topplist':
let curr_topping_list_query = get(toppingListFromServerQuery) ?? [];
if (!curr_topping_list_query) {
curr_topping_list_query = [];
}
for (let t of ex_payload) {
curr_topping_list_query.push(t);
}
toppingListFromServerQuery.set(curr_topping_list_query);
break;
case 'toppgrp':
let curr_topping_group_query = get(toppingGroupFromServerQuery) ?? [];
if (!curr_topping_group_query) {
curr_topping_group_query = [];
}
for (let t of ex_payload) {
curr_topping_group_query.push(t);
}
toppingGroupFromServerQuery.set(curr_topping_group_query);
break;
}
}
2026-02-17 14:30:02 +07:00
},
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}`);
}
},
ui_action: (p) => {
if (p.action == 'refreshNow' && p.from == 'brew') {
goto('/tools/brew');
}
},
version_selectors: (p) => {
if (p.versions.length > 0) {
currentRecipeVersionsSelector.set([]);
let result: RecipeVersion[] = [];
for (let vstr of p.versions) {
let pure_version = vstr.split('_')[0];
result.push({
display_version: pure_version,
actual_version_name: vstr
});
}
currentRecipeVersionsSelector.set(result);
}
},
price: (p) => {
let req_action = p.req_action;
let status = p.status;
let to = p.to;
let content: RecipePrice[] = p.content ?? [];
console.log('get price length: ', content.length);
let current_price = get(priceRecipeData);
for (const c of content) {
current_price[c.ProductCode] = c.NewPrice + (c.StringParam ? `,${c.StringParam}` : '');
}
priceRecipeData.set(current_price);
},
heartbeat: (p) => {
socketConnectionOfflineCount.set(0);
socketAlreadySendHeartbeat.set(0);
console.log('heartbeat reset offline count');
}
2026-02-17 14:30:02 +07:00
};
export function handleIncomingMessages(raw: string) {
const msg: WSMessage = JSON.parse(raw);
// console.log(`${new Date().toLocaleTimeString()}:ws msg`, msg);
2026-02-17 14:30:02 +07:00
if (msg == null) {
// error response
addNotification('ERR:No response from server');
return;
}
handlers[msg.type]?.(msg.payload);
}