앱 실시간 갱신 수정

This commit is contained in:
Macbook
2026-06-14 19:41:49 +09:00
parent c105ae209b
commit ad6347f2a2
9 changed files with 71 additions and 39 deletions
+5 -8
View File
@@ -1,21 +1,18 @@
import { useEffect, useState } from 'react';
import { isDesktop } from '../utils/platform';
import { getDesktopAppVersion, syncDesktopMainWindowTitle } from '../utils/desktopBridge';
import { readBakedDesktopAppVersion } from '../utils/desktopAppVersion';
/** Desktop — 네이티브 창 타이틀·document.title을 GoldenChart (vX.Y.Z) 로 맞춤 */
/** Desktop — Tauri getVersion() 기준 (설치된 앱 버전). baked 0.1.4 등 git 고정값 사용 안 함 */
export function useDesktopAppTitle(): string | null {
const [version, setVersion] = useState<string | null>(() =>
isDesktop() ? readBakedDesktopAppVersion() : null,
);
const [version, setVersion] = useState<string | null>(null);
useEffect(() => {
if (!isDesktop()) return;
let cancelled = false;
void (async () => {
const v = (await getDesktopAppVersion()) ?? readBakedDesktopAppVersion();
if (cancelled || !v) return;
setVersion(v);
const v = await getDesktopAppVersion();
if (cancelled || !v?.trim()) return;
setVersion(v.trim());
await syncDesktopMainWindowTitle();
})();
return () => { cancelled = true; };
+7
View File
@@ -61,6 +61,13 @@ export function getStompSockJsUrl(): string {
return path;
}
/** Desktop — 순수 WebSocket STOMP (SockJS 미사용) */
export function getStompNativeWebSocketUrl(): string {
const secureOrigin = getSecureApiOrigin().replace(/^http:\/\//i, 'https://');
const wsOrigin = secureOrigin.replace(/^https:\/\//i, 'wss://');
return `${wsOrigin}/api/ws/trading/ws`;
}
// UUID 생성 — HTTPS/localhost: crypto.randomUUID() 사용, HTTP: 폴리필
function generateUUID(): string {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
+28 -11
View File
@@ -1,10 +1,11 @@
/**
* 차트·실시간 전략용 STOMP 단일 연결 (SockJS 1회).
* 훅마다 StompClient 를 만들면 "closed before connection is established" 가 반복된다.
* 차트·실시간 전략용 STOMP 단일 연결.
* 웹: SockJS 1회 / Desktop: 순수 WebSocket (cross-origin SockJS 세션 불가)
*/
import { Client as StompClient, IMessage, StompSubscription } from '@stomp/stompjs';
import SockJS from 'sockjs-client';
import { getStompSockJsUrl } from './backendApi';
import { getStompNativeWebSocketUrl, getStompSockJsUrl } from './backendApi';
import { isDesktop } from './platform';
type MessageHandler = (msg: IMessage) => void;
type ConnectionListener = (connected: boolean) => void;
@@ -49,11 +50,12 @@ function resubscribeAll(): void {
}
}
function getOrCreateClient(): StompClient {
if (client) return client;
function stompConnectLabel(): string {
return isDesktop() ? getStompNativeWebSocketUrl() : getStompSockJsUrl();
}
client = new StompClient({
webSocketFactory: () => new SockJS(getStompSockJsUrl()),
function createStompClient(): StompClient {
const shared = {
reconnectDelay: 5000,
heartbeatIncoming: 10_000,
heartbeatOutgoing: 10_000,
@@ -68,11 +70,11 @@ function getOrCreateClient(): StompClient {
entry.stompSub = undefined;
}
},
onStompError: frame => {
onStompError: (frame: { headers?: { message?: string } }) => {
console.warn('[stompChartBroker] STOMP error', frame.headers?.message ?? frame);
},
onWebSocketError: ev => {
console.warn('[stompChartBroker] WebSocket error', getStompSockJsUrl(), ev);
onWebSocketError: (ev: Event) => {
console.warn('[stompChartBroker] WebSocket error', stompConnectLabel(), ev);
},
onWebSocketClose: () => {
notifyConnection(false);
@@ -80,7 +82,23 @@ function getOrCreateClient(): StompClient {
entry.stompSub = undefined;
}
},
};
if (isDesktop()) {
const brokerURL = getStompNativeWebSocketUrl();
return new StompClient({ ...shared, brokerURL });
}
const sockJsUrl = getStompSockJsUrl();
return new StompClient({
...shared,
webSocketFactory: () => new SockJS(sockJsUrl),
});
}
function getOrCreateClient(): StompClient {
if (client) return client;
client = createStompClient();
return client;
}
@@ -96,7 +114,6 @@ function scheduleDisconnect(): void {
disconnectTimer = null;
if (handlerCount() > 0) return;
if (!client?.active) return;
// 연결 수립 중 deactivate 하면 "closed before connection is established" 발생
if (!connected) {
scheduleDisconnect();
return;