<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>디자인원엑스 &amp;gt; 서비스 &amp;gt; 메시지 브릿지</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge</link>
<language>ko</language>
<description>메시지 브릿지 (2025-12-09 08:37:25)</description>

<item>
<title>메시지 브릿지 1.4.1 보안 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=24</link>
<description><![CDATA[<p>메시지 브릿지 1.4.1 — 서버 보안 패치 설명</p><p><br /></p><p><strong style="font-size:16px;">1. 중복 그룹(duplicate group) 공격 차단</strong></p><p>그룹 ID 별 중복 등록 방지 장치를 서버 측에서 추가</p><p>동일 그룹 ID가 이미 활성 상태라면 서버가 별도 처리 없이 즉시 차단 및 경고 메시지 전송</p><p>악성 혹은 오작동하는 클라이언트가 반복 요청을 보내도 서버 자원 사용량이 증가하지 않도록 무부하 처리(bypass) 방식 적용</p><p><br /></p><p><strong style="font-size:16px;">2. 무한 전송 요청(Loop Request)로부터 보호</strong></p><p>서버가 비정상적인 짧은 주기의 반복 요청을 감지하면, 자동으로 IP 기반 단기 쿨다운을 적용하여 서버 보호</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-12-09T08:37:25+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.4.0 기능 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=22</link>
<description><![CDATA[<p>클라이언트 개발자님께 힘이 되고자 다음의 기능을 추가했습니다. 감사합니다.</p><p><br /></p><p><span style="font-size:16px;"><strong></strong></span></p><p><span style="font-size:16px;"><strong>1) 유령 처리 방식 개선 (삼세판 적용)</strong></span></p><p><br /></p><p>Ping 실패 1번 = 무시</p><p>3번 연속 실패할 때만 유령(끊긴 사용자)로 판단해 제거</p><p>→ 정상적인 모바일 백그라운드/일시적인 끊김은 절대 문제 없음.</p><p><br /></p><p><strong style="font-size:16px;">2) 자동 재접속 안정화</strong></p><p><br /></p><p>클라이언트에서 연결 끊기면 0.5초 간격으로 자동 재접속</p><p>서버는 동일 사용자가 다시 들어오면 기존 유령 세션 자동 정리</p><p>→ 중복 접속 표시 사라지고 부드러운 재접속 가능.</p><p><br /></p><p><strong style="font-size:16px;">3) 유령 세션 자동 청소기 강화</strong></p><p><br /></p><p>닫힌 소켓, 응답 없는 소켓, ping 3회 실패한 소켓 자동 삭제</p><p>→ 접속자 수가 실제와 다르게 올라가는 문제를 해결.</p><p><br /></p><p><strong style="font-size:16px;">4) 원본 구조 유지 + 안정성만 보강</strong></p><p><br /></p><p>기존 handler / broadcast / log 시스템 그대로 유지</p><p>메인은 그대로, 추가된 건 ‘유령 정리 정확도’와 ‘재접속 안정성’ 뿐</p><p><br /></p><p><strong style="font-size:16px;">5) 모바일 친화도 크게 향상</strong></p><p><br /></p><p>화면 꺼짐 / 앱 전환 / 네트워크 전환 시 끊긴 것으로 처리 안 함</p><p>돌아오면 그대로 재접속 가능</p><p><br /></p><p><strong style="font-size:16px;">적용된 기능의 클라이언트 최적화 소스</strong></p><pre><code class="language-javascript hljs">&lt;script&gt;
<span class="hljs-comment">/* -------------------------------------------
   설정
 ------------------------------------------- */</span>
<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">WS_URL</span> = <span class="hljs-string">"wss://designonex.com:14147?group=mygroup"</span>;
<span class="hljs-keyword">let</span> userInfo = {
    <span class="hljs-attr">user</span>: <span class="hljs-string">"UserA"</span>,      <span class="hljs-comment">// 재접속 시 다시 보냄</span>
    <span class="hljs-attr">role</span>: <span class="hljs-string">"viewer"</span>
};

<span class="hljs-comment">/* -------------------------------------------
   WebSocket 관리 변수
 ------------------------------------------- */</span>
<span class="hljs-keyword">let</span> ws = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> reconnectTimer = <span class="hljs-literal">null</span>;
<span class="hljs-keyword">let</span> retryDelay = <span class="hljs-number">1000</span>;  <span class="hljs-comment">// 재접속 시작 딜레이</span>
<span class="hljs-keyword">const</span> maxDelay = <span class="hljs-number">10000</span>; <span class="hljs-comment">// 최대 10초</span>

<span class="hljs-comment">/* -------------------------------------------
   WebSocket 연결 함수
 ------------------------------------------- */</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">connectWS</span>(<span class="hljs-params"></span>) {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"%c[WS] Connecting..."</span>, <span class="hljs-string">"color: cyan"</span>);

    ws = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WebSocket</span>(<span class="hljs-variable constant_">WS_URL</span>);

    ws.<span class="hljs-property">onopen</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"%c[WS] Connected"</span>, <span class="hljs-string">"color: lime"</span>);

        <span class="hljs-comment">// 재접속 딜레이 초기화</span>
        retryDelay = <span class="hljs-number">1000</span>;

        <span class="hljs-comment">// 재접속 시 반드시 다시 이름/상태 보내기</span>
        ws.<span class="hljs-title function_">send</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({
            <span class="hljs-attr">type</span>: <span class="hljs-string">"join"</span>,
            ...userInfo
        }));
    };

    ws.<span class="hljs-property">onmessage</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> msg = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(e.<span class="hljs-property">data</span>);
            <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"[WS] Recv:"</span>, msg);

            <span class="hljs-comment">// 필요 시 메시지 처리 추가</span>
        } <span class="hljs-keyword">catch</span> (err) {
            <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">"[WS] JSON Error:"</span>, err);
        }
    };

    ws.<span class="hljs-property">onerror</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) {
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">"%c[WS] ERROR"</span>, <span class="hljs-string">"color: red"</span>);
    };

    ws.<span class="hljs-property">onclose</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) {
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">"%c[WS] CLOSED"</span>, <span class="hljs-string">"color: orange"</span>);
        <span class="hljs-title function_">scheduleReconnect</span>();
    };
}

<span class="hljs-comment">/* -------------------------------------------
   자동 재접속 스케줄링
 ------------------------------------------- */</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">scheduleReconnect</span>(<span class="hljs-params"></span>) {
    <span class="hljs-keyword">if</span> (reconnectTimer) <span class="hljs-keyword">return</span>;

    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(
        <span class="hljs-string">`%c[WS] Reconnecting in <span class="hljs-subst">${retryDelay / <span class="hljs-number">1000</span>}</span>s`</span>,
        <span class="hljs-string">"color: yellow"</span>
    );

    reconnectTimer = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
        reconnectTimer = <span class="hljs-literal">null</span>;

        <span class="hljs-comment">// 딜레이 증가 (최대 10초)</span>
        retryDelay = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">min</span>(maxDelay, retryDelay + <span class="hljs-number">1000</span>);

        <span class="hljs-title function_">connectWS</span>();
    }, retryDelay);
}

<span class="hljs-comment">/* -------------------------------------------
   네트워크 꺼졌다 켜질 때 즉시 재접속
 ------------------------------------------- */</span>
<span class="hljs-variable language_">window</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"online"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"%c[WS] ONLINE → immediate reconnect"</span>, <span class="hljs-string">"color: #4FC3F7"</span>);
    <span class="hljs-keyword">if</span> (!ws || ws.<span class="hljs-property">readyState</span> !== <span class="hljs-title class_">WebSocket</span>.<span class="hljs-property">OPEN</span>) {
        retryDelay = <span class="hljs-number">1000</span>;
        <span class="hljs-title function_">connectWS</span>();
    }
});

<span class="hljs-comment">/* -------------------------------------------
   모바일 백그라운드 복귀 시 재접속
 ------------------------------------------- */</span>
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"visibilitychange"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">document</span>.<span class="hljs-property">visibilityState</span> === <span class="hljs-string">"visible"</span>) {
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"%c[WS] TAB ACTIVE"</span>, <span class="hljs-string">"color: #FFD740"</span>);

        <span class="hljs-keyword">if</span> (!ws || ws.<span class="hljs-property">readyState</span> !== <span class="hljs-title class_">WebSocket</span>.<span class="hljs-property">OPEN</span>) {
            <span class="hljs-title function_">connectWS</span>();
        }
    }
});

<span class="hljs-comment">/* -------------------------------------------
   수동 메시지 전송 함수 (필요 시 UI에 연결)
 ------------------------------------------- */</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">sendMessage</span>(<span class="hljs-params">type, data = {}</span>) {
    <span class="hljs-keyword">if</span> (ws &amp;&amp; ws.<span class="hljs-property">readyState</span> === <span class="hljs-title class_">WebSocket</span>.<span class="hljs-property">OPEN</span>) {
        ws.<span class="hljs-title function_">send</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({ type, ...data }));
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">"WS not connected – message dropped:"</span>, type);
    }
}

<span class="hljs-comment">/* -------------------------------------------
   최초 실행
 ------------------------------------------- */</span>
<span class="hljs-title function_">connectWS</span>();
&lt;/script&gt;
</code></pre><p><br /></p><p>* 이 소스는 직접 개발을 진행하시는 개발자에게 도움이 되는 소스입니다.</p><p>* 디자인원엑스에서는 웹 엔진 소스를 가공해서 제공합니다. 매뉴얼을 참고해주세요.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-12-05T15:42:49+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.3.2 버그 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=21</link>
<description><![CDATA[<p>동작이 안되었던 테이블 최적화 기능 버그를 처리하였습니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-12-03T08:49:25+09:00</dc:date>
</item>


<item>
<title>[웹] 기본 서버에서 받은 소스 설명</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=20</link>
<description><![CDATA[<p><span style="font-size:18px;"><strong>updateDisplay() 내 postData의 역할 &amp; 활용 설명</strong></span></p><p><br /></p><p>updateDisplay() 안에서 만들어지는 postData는<br />서버(WebSocket)에서 받은 메시지를 프론트에서 활용하기 좋은 ‘가공용 데이터 꾸러미’로 만들어둔 것입니다.</p><p><br /></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">const</span> postData = {
    <span class="hljs-attr">type</span>: lastMessage.<span class="hljs-property">type</span>,
    auth : lastMessage.<span class="hljs-property">auth</span>,
    <span class="hljs-attr">mb_id</span>: <span class="hljs-variable constant_">MB_ID</span>,
    write_id : lastMessage.<span class="hljs-property">write_id</span>,
    <span class="hljs-attr">ip</span>: <span class="hljs-variable constant_">USER_IP</span>,
    <span class="hljs-attr">noti_type</span>: lastMessage.<span class="hljs-property">noti_type</span>,
    <span class="hljs-attr">mb_name</span>: lastMessage.<span class="hljs-property">mb_name</span>,
    <span class="hljs-attr">bo_table</span>: lastMessage.<span class="hljs-property">bo_table</span>,
    <span class="hljs-attr">bo_subject</span>: lastMessage.<span class="hljs-property">bo_subject</span>,
    <span class="hljs-attr">wr_subject</span>: lastMessage.<span class="hljs-property">wr_subject</span>,
    <span class="hljs-attr">wr_id</span>: lastMessage.<span class="hljs-property">wr_id</span>,
    <span class="hljs-attr">skin_url</span>: lastMessage.<span class="hljs-property">skin_url</span>
};</code></pre><p><br /></p><p>여기까지는 ‘준비’ 단계입니다.<br />이후에는 원하는 대로 가공해서 무엇이든 할 수 있어요.</p><p><br /></p><p>postData로 할 수 있는 일</p><p>이 postData는 말 그대로 만능 재료입니다.<br />필요한 요리를 자유롭게 선택하면 됩니다.</p><p><br /></p><p><strong style="font-size:16px;">1) alert()으로 바로 출력</strong></p><pre><code class="language-javascript hljs"><span class="hljs-title function_">alert</span>(postData.<span class="hljs-property">wr_subject</span>);
<span class="hljs-title function_">alert</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(postData, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));</code></pre><p><br /></p><p>바로 경고창에 띄워 확인하거나 디버깅용으로 사용할 수 있습니다.</p><p><br /></p><p><span style="font-size:16px;"><strong>2) AJAX로 서버에 다시 전송</strong></span></p><p><br /></p><p><strong>jQuery 예시</strong></p><pre><code class="language-javascript hljs">$.<span class="hljs-title function_">ajax</span>({
    <span class="hljs-attr">url</span>: <span class="hljs-string">"/notification/save.php"</span>,
    <span class="hljs-attr">type</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">data</span>: postData,
    <span class="hljs-attr">success</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">res</span>){
        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"저장 완료:"</span>, res);
    }
});</code></pre><p> <br /></p><p><strong>fetch 예시</strong></p><pre><code class="language-javascript hljs"><span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/notification/save.php'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
    <span class="hljs-attr">body</span>: <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(postData)
});</code></pre><p><br /></p><p>데이터베이스에 저장하거나 로그 파일로 기록할 때 사용합니다.</p><p><br /></p><p><span style="font-size:16px;"><strong>3) 폼 POST 전송</strong></span></p><p><br /></p><p>만약 서버가 form 방식만 받는다면:</p><pre><code class="language-javascript hljs"><span class="hljs-keyword">const</span> form = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">"form"</span>);
form.<span class="hljs-property">method</span> = <span class="hljs-string">"POST"</span>;
form.<span class="hljs-property">action</span> = <span class="hljs-string">"/noti"</span>;

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">in</span> postData) {
    <span class="hljs-keyword">const</span> input = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">"input"</span>);
    input.<span class="hljs-property">type</span> = <span class="hljs-string">"hidden"</span>;
    input.<span class="hljs-property">name</span> = key;
    input.<span class="hljs-property">value</span> = postData[key];
    form.<span class="hljs-title function_">appendChild</span>(input);
}

<span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>.<span class="hljs-title function_">appendChild</span>(form);
form.<span class="hljs-title function_">submit</span>();</code></pre><p><br /></p><p>전통적인 POST 방식도 문제없이 지원합니다.</p><p><br /></p><p><span style="font-size:16px;"><strong>4) HTML UI에 표시</strong></span></p><pre><code class="language-javascript hljs"><span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">"#notiTitle"</span>).<span class="hljs-property">textContent</span> = postData.<span class="hljs-property">wr_subject</span>;
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">"#notiWriter"</span>).<span class="hljs-property">textContent</span> = postData.<span class="hljs-property">mb_name</span>;
<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">"#notiBoard"</span>).<span class="hljs-property">textContent</span> = postData.<span class="hljs-property">bo_subject</span>;</code></pre><p><br /></p><p>알림 팝업 / 모달 / UI 카드 등 원하는 곳에 값을 끼워 넣기만 하면 됩니다.</p><p><br /></p><p><strong style="font-size:16px;">5) 다른 JS 함수에 전달해서 처리</strong></p><pre><code class="language-javascript hljs"><span class="hljs-title function_">sendToPopup</span>(postData);
<span class="hljs-title function_">logNotification</span>(postData);
<span class="hljs-title function_">updateCounter</span>(postData);</code></pre><p><br /></p><p>정리된 JSON 데이터를 다른 기능으로 넘겨 확장할 수도 있습니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-12-02T17:53:38+09:00</dc:date>
</item>


<item>
<title>[웹] 기본 서버 전송 소스 설명</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=19</link>
<description><![CDATA[<p>아래 코드는 실시간 알림 게시판에 적용되는 예제 소스입니다.<br />WebSocket 연결 상태를 자동으로 확인하여, 알림 데이터를 서버에 안전하게 전송하는 역할을 합니다.<br /><br />이 코드를 정상적으로 동작시키기 위해서는 <strong style="color:rgb(255,0,0);">반드시 페이지 상단에 WebSocket 엔진 소스(WS 초기화, sendEvent, connectWebSocket 등)가 포함</strong>되어 있어야 합니다.<br />엔진 로직 없이 이 함수만 사용하면 전송이 이루어지지 않습니다.</p><p><br /></p><p><strong style="font-size:18px;">1) 보낼 데이터(JSON) 준비</strong><br /><br />먼저 서버로 전달할 알림 패킷을 구성합니다.</p><pre><code class="language-javascript hljs"><span class="hljs-keyword">const</span> jsonData = {
    <span class="hljs-attr">type</span>: <span class="hljs-string">"notification"</span>,    <span class="hljs-comment">// 데이터 타입 정의</span>
    <span class="hljs-attr">auth</span>: <span class="hljs-string">"admin"</span>,           <span class="hljs-comment">// 인증/권한(옵션)</span>
    <span class="hljs-attr">mb_id</span>: <span class="hljs-variable constant_">MB_ID</span>,            <span class="hljs-comment">// 회원 아이디</span>
    <span class="hljs-attr">write_id</span>: <span class="hljs-string">"글쓴이 아이디"</span>,
    <span class="hljs-attr">ip</span>: <span class="hljs-variable constant_">USER_IP</span>,             <span class="hljs-comment">// 클라이언트 IP</span>
    <span class="hljs-attr">noti_type</span>: <span class="hljs-string">"글쓴위치"</span>,
    <span class="hljs-attr">mb_name</span>: <span class="hljs-string">"글쓴이 이름 또는 닉네임"</span>,
    <span class="hljs-attr">bo_table</span>: <span class="hljs-string">"게시판 테이블명"</span>,
    <span class="hljs-attr">bo_subject</span>: <span class="hljs-string">"게시판 제목"</span>,
    <span class="hljs-attr">wr_subject</span>: <span class="hljs-string">"게시글 제목"</span>,
    <span class="hljs-attr">wr_id</span>: <span class="hljs-string">"게시글 고유 ID"</span>,
    <span class="hljs-attr">skin_url</span>: <span class="hljs-string">"게시글 주소"</span>
};</code></pre><p><br /></p><p>위의 데이터는 실시간 알림 게시판을 만들었을 때 작업했던 값들입니다.</p><p><strong style="font-size:18px;"><br /></strong></p><p><strong style="font-size:18px;">2) WebSocket이 열렸는지 확인</strong></p><p><br /></p><p>아래 조건문이 핵심입니다.</p><pre><code class="language-javascript hljs"><span class="hljs-keyword">if</span> (ws &amp;&amp; ws.<span class="hljs-property">readyState</span> === <span class="hljs-title class_">WebSocket</span>.<span class="hljs-property">OPEN</span>) {
    <span class="hljs-title function_">sendEvent</span>(jsonData);  <span class="hljs-comment">// 즉시 전송</span>
}</code></pre><p><br /></p><p>연결 존재(ws), 열림 상태(OPEN) 두 조건이 모두 충족돼야 바로 전송합니다.</p><p><br /></p><p><strong style="font-size:18px;">3) 아직 열리지 않았다면 → 자동 대기 후 전송</strong></p><p><br /></p><p>웹소켓이 아직 연결중이라면 OPEN 이벤트를 기다립니다.</p><pre><code class="language-javascript hljs"><span class="hljs-keyword">else</span> {
    ws.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"open"</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-title function_">sendEvent</span>(jsonData), { <span class="hljs-attr">once</span>: <span class="hljs-literal">true</span> });
}</code></pre><p><br /></p><p>{ once: true } 옵션 덕분에 딱 한 번만 실행되고 사라집니다. 깔끔하고 안전한 전송 구조죠.</p><p>즉, WebSocket이 “자, 연결 완료!”라고 외치는 순간 → sendEvent(jsonData)가 전달됩니다.</p><p><br /></p><p><strong style="font-size:18px;">4) 사용 방법</strong></p><pre><code class="language-javascript hljs"><span class="hljs-title function_">sendChatMessageSafe</span>(<span class="hljs-string">"notification 메시지"</span>);</code></pre><p><br /></p><p>여기서 "notification 메시지"는 사실 jsonData 안에 직접 쓰지 않으셨으므로<br />단순 호출 트리거 역할만 합니다.<br />실제 메시지는 jsonData 객체 안에서 완성되어 서버로 갑니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-12-02T08:31:07+09:00</dc:date>
</item>


<item>
<title>[웹] 기본 엔진 소스 설명</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=18</link>
<description><![CDATA[<p><span style="font-size:18px;"><strong>WebSocket 엔진(상단 핵심 로직) 설명서</strong></span></p><br /><p>※ 이 영역은 전체 시스템의 핵심 엔진이므로 <strong><u>가능한 수정 없이 그대로 사용하는 것을 권장</u></strong>합니다.</p><p>※ 필요한 기능 확장은 하단 UI 영역 또는 별도 함수에서 처리하는 것을 권장합니다.</p><p><br /></p><p><strong style="font-size:16px;">1. 기본 정보 설정</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">const</span> domain = <span class="hljs-variable language_">window</span>.<span class="hljs-property">location</span>.<span class="hljs-property">hostname</span>;
<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">MB_ID</span> = <span class="hljs-string">"아이디"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">USER_IP</span> = <span class="hljs-string">"ip주소(해당 언어 참고)"</span>
<span class="hljs-keyword">const</span> myKey = <span class="hljs-variable constant_">MB_ID</span> || <span class="hljs-variable constant_">USER_IP</span>;</code></pre><p><strong><br /></strong></p><p><strong>domain</strong><br />현재 접속한 웹사이트의 도메인 이름.<br />WebSocket 서버로 전송되는 group 파라미터로 사용되며, 같은 도메인끼리만 접속자 그룹을 분리하여 관리하는 역할을 한다.</p><p><br /><strong>MB_ID</strong><br />로그인된 사용자의 회원 ID.<br />비회원이라면 빈 문자("") 또는 null.<br /><br /><strong>USER_IP</strong><br />비회원 사용자를 구분하기 위한 식별자.<br /><br /><strong>myKey</strong><br />현재 사용자를 대표하는 고유 키.<br />우선순위: 회원 → MB_ID<br />비회원 → USER_IP<br /><br />이 값은 이후 접속자 Map에서 Key로 사용되며, 접속자 중복 여부 판단 등에 매우 중요하므로 수정하지 않을 것을 권장.</p><p><br /></p><p><strong style="font-size:16px;">2. 접속 사용자 목록 저장소</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">let</span> ws;
<span class="hljs-keyword">let</span> activeUsers = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Map</span>(); <span class="hljs-comment">// {key: data}</span>
<span class="hljs-keyword">let</span> userListString = <span class="hljs-string">""</span>;</code></pre><p><br /></p><p><strong>ws</strong><br />WebSocket 인스턴스를 저장하는 변수.<br />재연결 또는 종료 시 동일 객체에 접근하기 위해 전역으로 선언.<br /><br /><strong>activeUsers (Map 구조)</strong><br />현재 WebSocket 그룹에 접속 중인 사용자 목록을 저장하는 저장소.<br /><strong>key:</strong> 사용자 식별자(MB_ID 또는 IP)<br /><strong>value:</strong> 사용자 정보 객체(접속시간, id, ip 등 서버에서 내려주는 데이터)<br /><br /><strong>userListString</strong><br />화면에 보여주기 좋은 문자열 형태(“아이디1 | 아이디2 | …”)로 만든 접속자 목록.<br />activeUsers와 userListString은 실시간 UI 업데이트에 활용되므로 구조 변경은 권장하지 않음.</p><p><br /></p><p><strong style="font-size:16px;">3. WebSocket 연결 함수</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">function</span> <span class="hljs-title function_">connectWebSocket</span>() {
    ws = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WebSocket</span>(<span class="hljs-string">'wss://designonex.com:14147/?group='</span> + <span class="hljs-built_in">encodeURIComponent</span>(domain));</code></pre><p><br /></p><p><strong>WebSocket 서버에 연결하는 엔트리 포인트.</strong><br />접속 시 group=도메인 값을 전달하여 도메인 단위의 접속자 방(그룹)을 자동으로 형성한다.<br /><strong style="color:rgb(255,0,0);">이 그룹 구조는 서버 설계에 맞춰져 있으므로 반드시 수정 없이 유지</strong>해야 한다.</p><p><br /></p><p><strong style="font-size:16px;">4. WebSocket 이벤트 처리</strong></p><p><strong><br /></strong></p><p><strong>4-1. 접속 성공 (onopen)</strong></p><pre><code class="language-javascript hljs">ws.<span class="hljs-property">onopen</span> = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-title function_">sendEvent</span>({<span class="hljs-attr">type</span>: <span class="hljs-string">"join"</span>, <span class="hljs-attr">mb_id</span>: <span class="hljs-variable constant_">MB_ID</span>, <span class="hljs-attr">ip</span>: <span class="hljs-variable constant_">USER_IP</span>});
};</code></pre><p><br /></p><p>서버에 “현재 사용자가 접속했다”는 정보를 전송. </p><p>서버는 이를 기반으로 전체 접속자 목록을 갱신한다.</p><p><br /></p><p><strong>4-2. 서버 메시지 수신 (onmessage)</strong></p><pre><code class="language-javascript hljs">ws.<span class="hljs-property">onmessage</span> = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> data;
    <span class="hljs-keyword">try</span> { data = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(event.<span class="hljs-property">data</span>); } <span class="hljs-keyword">catch</span> { <span class="hljs-keyword">return</span>; }</code></pre><p><br /></p><p>서버에서 받은 데이터를 JSON 형태로 변환한다.<br />이후 메시지 타입에 따라 다른 동작을 수행한다.</p><p><br /></p><p><strong style="font-size:16px;">메시지 타입별 처리</strong><br /><strong>① init — 전체 접속자 목록을 최초로 받는 경우</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">if</span> (data.<span class="hljs-property">type</span> === <span class="hljs-string">"init"</span>) {
    activeUsers.<span class="hljs-title function_">clear</span>();
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> u <span class="hljs-keyword">of</span> data.<span class="hljs-property">users</span>) {
        <span class="hljs-keyword">const</span> key = u.<span class="hljs-property">mb_id</span> || u.<span class="hljs-property">ip</span> || <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>();
        activeUsers.<span class="hljs-title function_">set</span>(key, u);
    }
}</code></pre><p><br /></p><p>서버가 현재 유지하고 있는 전체 접속 사용자 목록을 배열로 전달함.<br />Map을 초기화한 뒤 새 목록을 모두 다시 저장.</p><p><br /></p><p><strong>② join / update — 누군가 접속했거나 정보가 갱신된 경우</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (data.<span class="hljs-property">type</span> === <span class="hljs-string">"join"</span> || data.<span class="hljs-property">type</span> === <span class="hljs-string">"update"</span>) {
    <span class="hljs-keyword">const</span> key = data.<span class="hljs-property">mb_id</span> || data.<span class="hljs-property">ip</span> || <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>();
    activeUsers.<span class="hljs-title function_">set</span>(key, data);
}</code></pre><p> <br /></p><p>새 사용자가 들어온 경우(join)<br />닉네임‧멤버 정보가 바뀐 경우(update)<br />activeUsers에 새로운 정보로 갱신함.</p><p><br /></p><p><strong>③ leave — 특정 사용자가 나간 경우</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (data.<span class="hljs-property">type</span> === <span class="hljs-string">"leave"</span>) {
    <span class="hljs-keyword">const</span> key = data.<span class="hljs-property">mb_id</span> || data.<span class="hljs-property">ip</span>;
    activeUsers.<span class="hljs-title function_">delete</span>(key);
}</code></pre><p><br /></p><p><strong>후처리</strong></p><pre><code class="language-javascript hljs"><span class="hljs-title function_">rebuildUserString</span>();

<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> updateDisplay === <span class="hljs-string">"function"</span>) {
    <span class="hljs-title function_">updateDisplay</span>(activeUsers, data); 
}</code></pre><p><br /></p><p><strong>userListString을 다시 구성</strong><br />UI가 필요할 경우 개발자가 직접 만든 updateDisplay()에 데이터를 전달<br />updateDisplay는 “하단 사용 UI 로직”에서 작성하는 것을 권장.<br />상단 엔진은 건드리지 않고 UI만 교체할 수 있는 구조로 설계됨.</p><p><br /></p><p><strong>4-3. 연결 종료 (onclose)</strong></p><pre><code class="language-javascript hljs">ws.<span class="hljs-property">onclose</span> = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">setTimeout</span>(connectWebSocket, <span class="hljs-number">2000</span>); <span class="hljs-comment">// 자동 재연결</span>
};</code></pre><p><br /></p><p>WebSocket이 끊기면 2초 후 자동 재연결을 시도.<br />서버 재부팅·네트워크 불안정 상황에서도 지속 접속을 보장.</p><p><br /></p><p><strong>4-4. 오류 발생 (onerror)</strong></p><pre><code class="language-javascript hljs">ws.<span class="hljs-property">onerror</span> = <span class="hljs-function">() =&gt;</span> {
    ws.<span class="hljs-title function_">close</span>();
};</code></pre><p><br /></p><p>오류 발생 시 즉시 연결을 닫고, onclose → 자동 재연결 동작이 이어짐.</p><p><br /></p><p><strong style="font-size:16px;">5. 메시지 전송 함수</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">function</span> <span class="hljs-title function_">sendEvent</span>(<span class="hljs-params">jsonData</span>) {
    <span class="hljs-keyword">if</span> (ws &amp;&amp; ws.<span class="hljs-property">readyState</span> === <span class="hljs-title class_">WebSocket</span>.<span class="hljs-property">OPEN</span>) {
        ws.<span class="hljs-title function_">send</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(jsonData));
    }
}</code></pre><p><br /></p><p>WebSocket이 정상적으로 열려 있는 경우에만 JSON 데이터 전송.<br />서버로 join/update/chat 등 다양한 이벤트 메시지를 보낼 때 사용한다.<br />엔진에서 사용하는 기본 전송 구조이므로 변경하지 않는 것을 권장한다.</p><p><strong style="font-size:16px;"><br /></strong></p><p><strong style="font-size:16px;">6. 안전한 종료 처리 (gracefulDisconnect)</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">function</span> <span class="hljs-title function_">gracefulDisconnect</span>() {
    <span class="hljs-keyword">const</span> leaveData = {<span class="hljs-attr">type</span>: <span class="hljs-string">"leave"</span>, <span class="hljs-attr">mb_id</span>: <span class="hljs-variable constant_">MB_ID</span>, <span class="hljs-attr">ip</span>: <span class="hljs-variable constant_">USER_IP</span>};</code></pre><p><br /></p><p><strong>6-1. WebSocket으로 정상 종료 신호 보내기</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">if</span> (ws &amp;&amp; ws.<span class="hljs-property">readyState</span> === <span class="hljs-title class_">WebSocket</span>.<span class="hljs-property">OPEN</span>) {
    <span class="hljs-keyword">try</span> {
        ws.<span class="hljs-title function_">send</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(leaveData));
        ws.<span class="hljs-title function_">close</span>();
    } <span class="hljs-keyword">catch</span>(e) {}
}</code></pre><p><br /></p><p><strong>6-2. 모바일 대비 sendBeacon 보조 전송</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> blob = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Blob</span>([<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(leaveData)], {<span class="hljs-attr">type</span>: <span class="hljs-string">"application/json"</span>});
    navigator.<span class="hljs-title function_">sendBeacon</span>(<span class="hljs-string">"/ws-leave"</span>, blob);
} <span class="hljs-keyword">catch</span>(e) {}</code></pre><p><br /></p><p>모바일 브라우저는 탭 닫힘 시 WS 전송이 실패하는 문제가 빈번하기 때문에 sendBeacon으로 백엔드에 안전하게 한 번 더 전송하여 접속자 정보가 꼬이지 않도록 보완한다.</p><p>이 종료 처리 구조는 필수 요소이며, 엔진의 안정성을 위해 그대로 유지하는 것을 강력 권장.</p><p><br /></p><p><strong style="font-size:16px;">7. 브라우저 종료·백그라운드 이동 감지</strong></p><pre><code class="language-javascript hljs"><span class="hljs-variable language_">window</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"beforeunload"</span>, gracefulDisconnect);
<span class="hljs-variable language_">window</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"pagehide"</span>, gracefulDisconnect);

<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">"visibilitychange"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">document</span>.<span class="hljs-property">visibilityState</span> === <span class="hljs-string">"hidden"</span>) {
        <span class="hljs-title function_">gracefulDisconnect</span>();
    }
});</code></pre><p><br /></p><p>PC와 모바일에서 브라우저가 페이지를 떠나는 다양한 상황을 모두 감지하여, 접속 종료 정보가 빠짐없이 서버에 전달되도록 설계됨.</p><p><br /></p><p><strong style="font-size:16px;">8. 접속자 문자열 생성</strong></p><pre><code class="language-javascript hljs"><span class="hljs-keyword">function</span> <span class="hljs-title function_">rebuildUserString</span>() {
    userListString = <span class="hljs-title class_">Array</span>.<span class="hljs-title function_">from</span>(activeUsers.<span class="hljs-title function_">values</span>())
        .<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">u</span> =&gt;</span> u.<span class="hljs-property">mb_id</span> || u.<span class="hljs-property">ip</span>)
        .<span class="hljs-title function_">join</span>(<span class="hljs-string">" | "</span>);
}</code></pre><p><br /></p><p>activeUsers(Map)을 기반으로 “아이디 | 아이디 | IP…” 형태의 문자열을 구성.<br />UI에서 접속자 리스트를 간단히 표현할 때 활용.</p><p><br /></p><p><strong style="font-size:16px;">9. 최초 실행</strong></p><pre><code class="language-javascript hljs"><span class="hljs-title function_">connectWebSocket</span>();</code></pre><p><br /></p><p>페이지 로드와 동시에 WebSocket 연결을 시작함.</p><p><br /></p><p><br /></p><p>기본엔진 전체소스</p><pre><code class="language-javascript">const domain = window.location.hostname;
<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">MB_ID</span> = <span class="hljs-string">"아이디"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">USER_IP</span> = <span class="hljs-string">"ip주소(해당 언어 참고)"</span>
const myKey = MB_ID || USER_IP;

let ws;
let activeUsers = new Map(); // {key: data}
let userListString = "";

// ---------------------------
// 웹소켓 연결
// ---------------------------
function connectWebSocket() {
    ws = new WebSocket('wss://designonex.com:14147/?group=' + encodeURIComponent(domain));

    ws.onopen = () =&gt; {
        sendEvent({type: "join", mb_id: MB_ID, ip: USER_IP});
    };

    ws.onmessage = (event) =&gt; {
        let data;
        try { data = JSON.parse(event.data); } catch { return; }

        // 초기 접속자 목록
        if (data.type === "init") {
            activeUsers.clear();
            for (const u of data.users) {
                const key = u.mb_id || u.ip || Math.random();
                activeUsers.set(key, u);
            }
        }
        // 접속 또는 업데이트
        else if (data.type === "join" || data.type === "update") {
            const key = data.mb_id || data.ip || Math.random();
            activeUsers.set(key, data);
        }
        // 접속 종료
        else if (data.type === "leave") {
            const key = data.mb_id || data.ip;
            activeUsers.delete(key);
        }

        rebuildUserString();

		if (typeof updateDisplay === "function") {
			updateDisplay(activeUsers, data); 
		}
    };

    ws.onclose = () =&gt; {
        setTimeout(connectWebSocket, 2000); // 자동 재연결
    };

    ws.onerror = () =&gt; {
        ws.close();
    };
}

// ---------------------------
// 메시지 전송
// ---------------------------
function sendEvent(jsonData) {
    if (ws &amp;&amp; ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify(jsonData));
    }
}

// ---------------------------
// 안전한 종료 처리
// ---------------------------
function gracefulDisconnect() {
    const leaveData = {type: "leave", mb_id: MB_ID, ip: USER_IP};

    // 1️⃣ WebSocket으로 전송 (가능하면)
    if (ws &amp;&amp; ws.readyState === WebSocket.OPEN) {
        try {
            ws.send(JSON.stringify(leaveData));
            ws.close();
        } catch(e) {}
    }

    // 2️⃣ 모바일 대비 — sendBeacon으로 보조 전송
    try {
        const blob = new Blob([JSON.stringify(leaveData)], {type: "application/json"});
        navigator.sendBeacon("/ws-leave", blob);
    } catch(e) {}
}

// ---------------------------
// 브라우저 이벤트 감지
// ---------------------------

// PC 및 일부 모바일 브라우저
window.addEventListener("beforeunload", gracefulDisconnect);

// iOS / Android에서 동작 안정적인 이벤트
window.addEventListener("pagehide", gracefulDisconnect);

// 탭 비활성화 시 (백그라운드 이동 등)
document.addEventListener("visibilitychange", () =&gt; {
    if (document.visibilityState === "hidden") {
        gracefulDisconnect();
    }
});

// ---------------------------
// 문자열 갱신
// ---------------------------
function rebuildUserString() {
    userListString = Array.from(activeUsers.values())
        .map(u =&gt; u.mb_id || u.ip)
        .join(" | ");
}


// ---------------------------
// 최초 실행
// ---------------------------
connectWebSocket();

&lt;/script&gt;


&lt;script&gt;
function updateDisplay(activeUsers, lastMessage) {
    // 접속자 수 표시
    $("#userConCount").text("(" + activeUsers.size + ")");

	// 사이드 패널에 접속자 리스트 표시
    const userListString = Array.from(activeUsers.values())
        .map(u =&gt; {
            // mb_id가 null, undefined, 빈 문자열이 아니면 mb_id 표시
            if (u.mb_id &amp;&amp; u.mb_id.trim() !== "") {
                return u.mb_id;
            }
            return u.ip; // 회원이 아니면 IP 표시
        })
        .join(" | ");
    $("#sidePanelContent").text(userListString);

}</code></pre><p> </p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-12-01T23:03:40+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.3.1 보안,성능 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=17</link>
<description><![CDATA[<p><strong>1) 메인 이벤트 루프의 차단 요인 제거</strong></p><p><br /></p><p>비동기 흐름을 방해하던 일부 연산이 별도 경로로 이관되었습니다.</p><p>그 결과, 메시지 처리 경로가 불필요하게 정지하거나 응답 지연이 발생하는 사례가 감소했습니다.</p><p><br /></p><p><strong>2) 안정성 확보</strong></p><p><br /></p><p>단시간에 대량 로그가 발생할 때 출력 루프가 굳어버리던 문제를 재구성했습니다.</p><p>출력 배치, 버퍼 관리, 스로틀링이 정비되어 장시간 운영 시 안정성이 개선되었습니다.</p><p><br /></p><p><strong>3) 비활성 클라이언트 세션 정리 최적화</strong></p><p><br /></p><p>전송 실패·ping 응답 지연·이탈 여부가 감지된 연결은 즉시 파기되며,</p><p>연결 객체가 메모리에 더 오래 남지 않도록 관리 루틴이 강화되었습니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-29T22:07:08+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.3.0 기능 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=16</link>
<description><![CDATA[<p>내부 “메시지 브릿지 보조 엔진”을 부착.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-29T18:11:30+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.2.1 보안 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=15</link>
<description><![CDATA[<p>1. 대용량 메시지 차단 기능 추가</p><p>2. 서버 안정성 강화</p><p><br /></p><p>대용량 파일과 동영상 업로드는 별도의 기술 구조를 통해 처리할 계획입니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-23T22:36:55+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.2.0 기능패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=14</link>
<description><![CDATA[<p><b><span style="font-size:14pt;">일회용 보안 토큰(One-Time Token) 기능 추가</span></b></p><p><br /></p><p>클라이언트가 서버에 연결할 때 요청할 수 있는 일회용 인증 토큰 기능이 새롭게 추가되었습니다.</p><ul><li>서버에서 직접 안전한 토큰을 생성하며, 일정 시간 후 자동으로 폐기됩니다.</li><li>특정 프레임워크나 언어에 종속되지 않아 웹, 앱, 서버 등 모든 환경에서 사용 가능합니다.</li><li>토큰은 서버 내부에서만 관리되므로, 외부 서비스가 민감한 인증정보를 공유할 필요가 없습니다.</li><li>이제 어떤 플랫폼에서도 동일한 방식으로 토큰을 발급받아 WebSocket 통신에 활용할 수 있습니다.</li></ul><div>테스트 주소 : <a href="https://designonex.com/token.php" target="_blank" rel="nofollow noreferrer noopener">https://designonex.com/token.php</a></div><div><br /></div><p><span style="font-size:14pt;"><b>클라이언트 사용법</b></span></p><pre><code class="language-javascript">ws.send(JSON.stringify({ type: "get_token" }));
</code></pre>
<pre><code class="language-javascript">
{
  "type": "token",
  "value": "aDif9Kf9S-z1rfxSOK3...",
  "expire": 10
}
</code></pre><p>{ "type": "token", "value": "랜덤값", "expire": 10 }</p><p>토큰은 서버 메모리에 저장되고 10초 후 자동 만료</p>

<pre><code class="language-javascript">
const group = "getToken";
const ws = new WebSocket('wss://designonex.com:14147/?group=' + group);

ws.addEventListener("open", () =&gt; {
    ws.send(JSON.stringify({ type: "get_token" }));
});

ws.addEventListener("message", (event) =&gt; {
    try {
        const data = JSON.parse(event.data);

        // type이 token인 경우만 따로 처리
        if (data.type === "token") {
            alert("TOKEN: " + data.value);  // 토큰 값만 출력
        } else {
            console.log("Other message:", data);
        }
    } catch (e) {
        console.error("Invalid JSON:", event.data);
    }
});
</code></pre>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-20T09:54:24+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.1.3 성능패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=13</link>
<description><![CDATA[<p><span style="font-size:14pt;"><b>메시지 처리 안정성 개선</b></span></p><p><br /></p><p>내부 메시지 흐름이 특정 구간에서 지연되지 않도록 구조를 조금 정리했습니다.</p><p>출력 처리도 병렬적으로 흘러가도록 방향을 바꿔, 전체 루프 부하를 줄이는 방식으로 보완했습니다.</p><p><br /></p><p><b><span style="font-size:14pt;">전송 지연 클라이언트의 영향 최소화</span></b></p><p><br /></p><p>일부 연결에서 응답이 늦어질 때 전체 전송 흐름이 끌려가지 않도록</p><p>전송 경로를 분리해주는 보호 장치가 들어갔습니다.</p><p><br /></p><p><b><span style="font-size:14pt;">그룹 단위 자원 접근 안정화</span></b></p><p><br /></p><p>그룹별 상태가 동시에 갱신될 때 충돌 가능성을 낮추기 위해</p><p>접근 제어 쪽을 조금 더 단단하게 묶어 두었습니다.</p><p><br /></p><p><b><span style="font-size:14pt;">주기 작업 분리로 메인 루프 부하 감소</span></b></p><p><br /></p><p>주기적으로 실행되는 관리 작업이 실시간 메시지 처리에 영향을 주지 않도록</p><p>백그라운드로 살짝 옮겨서 전체 반응성을 높였습니다.</p><p><br /></p><p><b><span style="font-size:14pt;">연결 유지 신뢰도 향상</span></b></p><p><br /></p><p>특정 환경에서 연결 상태 체크가 제때 이뤄지지 않는 문제가 있어</p><p>상태 검증과 정리 과정을 보다 안정적인 방식으로 재배치했습니다.</p><p><br /></p><p><b><span style="font-size:14pt;">환경 옵션 정리 및 확장성 강화</span></b></p><p><br /></p><p>운영 환경에 따라 조정 가능한 항목들을 조금 더 정돈했습니다.</p><p>특히 실시간 성능과 안정성 사이의 균형을 맞출 수 있게 선택지를 넓혀두었습니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-15T20:02:01+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.1.2 보안패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=11</link>
<description><![CDATA[<p>안녕하세요, 디자인원엑스입니다.</p><p><br /></p><p>메시지 브릿지(Message Bridge)가 보안 패치 되었습니다.</p><p>이번 업데이트의 핵심은 서비스 이전 과정에서 발생할 수 있는 잠재적 위험과 불법 접근을 방지하는 기능을 추가한 점입니다.</p><p><br /></p><p>이번 기능 개선으로,</p><ul><li>서비스 이전 과정에서 발생할 수 있는 무단 접근이나 데이터 손상 방지</li><li>사용자 연결 안정성 및 메시지 전달 신뢰성 향상</li><li>서비스 운영 중 발생할 수 있는 잠재적 보안 리스크 최소화 등을 확보하였습니다.</li></ul><p><br /></p><p>이번 버전 업은 서비스의 안정성과 신뢰성을 한층 강화하는 중요한 단계입니다.</p><p>사용자분들께서는 기존과 동일하게 편리하게 메시지 브릿지를 이용하실 수 있으며,</p><p>보다 안전하고 안정적인 환경에서 서비스를 경험하실 수 있습니다.</p><p><br /></p><p>앞으로도 디자인원엑스는</p><p>사용자 중심의 안정적이고 신뢰성 높은 서비스 제공을 위해</p><p>지속적으로 시스템을 개선하고, 필요한 보안 기능을 강화해 나가겠습니다.</p><p><br /></p><p>항상 관심과 응원 감사드립니다.</p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-14T10:28:40+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 무료 사용 약관</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=10</link>
<description><![CDATA[<p>시행일자: 2025.11.14 </p><p><br /></p><p>본 약관은 디자인원엑스(이하 “회사”)가 제공하는 메시지 브릿지(Message Bridge) 무료 서비스(이하 “서비스”)의 이용과 관련하여 회사와 이용자 간의 권리, 의무 및 책임사항을 규정함을 목적으로 합니다.</p><p><br /></p><p><b><span style="font-size:14pt;">제1조 (목적)</span></b></p><p><br /></p><p>본 약관은 회사가 제공하는 실시간 메시지 전송 및 데이터 중계 서비스인 메시지 브릿지의 무료 이용과 관련하여, 서비스 이용 조건 및 절차, 회사와 이용자의 권리·의무, 책임 및 기타 필요한 사항을 규정합니다.</p><p><br /></p><p><span style="font-size:14pt;"><b>제2조 (정의)</b></span></p><ol><li>“서비스”란 WebSocket 기반으로 제공되는 실시간 메시지 중계 및 접속 관리 기능을 말합니다.</li><li>“이용자”란 본 약관에 동의하고 서비스를 사용하는 개인 또는 기관을 의미합니다.</li><li>“콘텐츠”란 이용자가 서비스 이용 과정에서 전송, 저장, 공유하는 데이터 일체를 말합니다.</li><li>“서버”란 회사가 서비스 제공을 위해 운영하는 시스템 및 인프라를 의미합니다.</li></ol><p><br /></p><p><b><span style="font-size:14pt;">제3조 (약관의 효력 및 변경)</span></b></p><ol><li>본 약관은 서비스 페이지 또는 공지사항을 통해 게시함으로써 효력이 발생합니다.</li><li>회사는 필요 시 약관을 변경할 수 있으며, 변경된 약관은 동일한 방식으로 공지합니다.</li><li>이용자가 변경된 약관에 동의하지 않을 경우 서비스 이용을 중단해야 하며, 계속 사용 시 변경 사항에 동의한 것으로 간주합니다.</li></ol><p><br /></p><p><b><span style="font-size:14pt;">제4조 (서비스 제공)</span></b></p><ol><li>회사는 다음의 기능을 무료로 제공합니다.</li><li>실시간 메시지 전송 및 중계</li><li>그룹별 접속 관리</li><li>접속 사용자 수 조회</li><li>WebSocket 기반 통신 기능</li><li>무료 서비스는 운영 정책, 서버 상황, 개발 우선순위 등에 따라 기능 일부가 변경, 축소 또는 중단될 수 있습니다.</li><li>회사는 다음과 같은 경우 서비스 제공을 일시 중단할 수 있습니다.<br />- 서버 점검, 시스템 업그레이드 등 유지보수<br />- 정전, 네트워크 장애, 천재지변 등 불가항력<br />- 기타 서비스 운용상 필요한 경우</li><li>서비스 중단 시 회사는 사전에 공지하며, 긴급한 경우 사후 공지할 수 있습니다.</li></ol><p><br /></p><p><span style="font-size:14pt;"><b>제5조 (이용자의 의무)<br /></b></span></p><ol><li>이용자는 다음 행위를 하여서는 안 됩니다.</li><li>서버에 과도한 트래픽을 유발하는 행위</li><li>악성코드, 해킹 시도, 시스템 교란 행위</li><li>불법 콘텐츠 또는 타인에게 피해를 주는 데이터 전송</li><li>서비스 구조를 역분석(Reverse Engineering)·무단 수정하는 행위</li><li>이용자의 위반 행위로 인해 발생한 모든 책임은 이용자에게 있습니다.<br /> </li></ol><p><b><span style="font-size:14pt;">제6조 (데이터 및 보안)</span></b></p><ol><li>회사는 서비스 안정성과 데이터 보호를 위해 합리적인 기술적 조치를 제공합니다.</li><li>다만, 무료 서비스 특성상 지속적인 저장 보장이나 백업 의무는 제공되지 않습니다.</li><li>이용자는 자신의 인증키, 토큰, 시스템 설정을 안전하게 관리할 책임이 있습니다.</li></ol><p><br /></p><p><b><span style="font-size:14pt;">제7조 (지적재산권)</span></b></p><ol><li>서비스 및 관련 기술에 대한 모든 권리는 회사에 귀속됩니다.</li><li>이용자가 전송하는 콘텐츠의 소유권은 이용자에게 있으며, 회사는 서비스 제공을 위한 범위 내에서만 이를 처리합니다.</li></ol><p><br /></p><p><b><span style="font-size:14pt;">제8조 (책임 제한)</span></b></p><ol><li>회사는 무료 서비스 제공에 대한 특별한 보증을 제공하지 않습니다.</li><li>회사는 다음 사항에 대해 책임을 지지 않습니다.</li><li>이용자 간 메시지 오·남용 및 분쟁</li><li>데이터 유실, 전송 지연, 장애로 인한 손해</li><li>외부 서버/네트워크 문제로 인한 서비스 중단</li><li>서비스의 품질 및 특정 목적 적합성</li><li>이용자는 서비스 이용에 따른 위험을 스스로 감수합니다.</li></ol><p><br /></p><p><b><span style="font-size:14pt;">제9조 (서비스 중단 및 종료)</span></b></p><ol><li>회사는 무료 서비스의 전부 또는 일부를 종료할 수 있습니다.</li><li>서비스 종료 시 사전 공지하며, 서비스 종료로 인한 손해에 대한 책임은 부담하지 않습니다.</li></ol>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-14T06:49:26+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지는 무료 서비스입니다.</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=9</link>
<description><![CDATA[<p>안녕하세요. 디자인원엑스(Designonex) 입니다.</p><p><br /></p><p>저희 메시지 브릿지(Message Bridge) 서비스는</p><p>누구나 자유롭게 사용할 수 있는 무료 실시간 통신 플랫폼입니다.</p><p>웹사이트나 커뮤니티, 그리고 프로젝트 환경 내에서</p><p>사용자 간 메시지 전달, 알림, 접속 상태 공유 등</p><p>다양한 기능을 보다 쉽게 구현할 수 있도록 설계되었습니다.</p><p><br /></p><p>본 서비스는 무료로 제공되고 있으나,</p><p>안정적인 운영과 공정한 이용 환경을 위해</p><p>반드시 이용약관 및 정책을 숙지하신 후 사용해 주시기 바랍니다.</p><p>이용약관에는 서비스의 사용 목적, 기술적 제한, 데이터 관리,</p><p>운영자 및 이용자의 책임 범위 등이 포함되어 있습니다.</p><p><br /></p><p>디자인원엑스는 앞으로도</p><p>사용자분들이 보다 편리하고 안전하게 서비스를 이용할 수 있도록</p><p>지속적인 개선과 기술적 지원을 이어가겠습니다.</p><p><br /></p><p>서비스 이용 중 문의 사항이나 기술 지원이 필요하신 경우,</p><p>공식 문의 채널을 통해 연락 주시면 신속히 안내드리겠습니다.</p><p><br /></p><p>메시지 브릿지 무료 사용 약관 : <a href="https://designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;wr_id=10" rel="nofollow">https://designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;wr_id=10</a></p><p>메시지 브릿지 이용 약관 : <a href="https://designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;wr_id=5" rel="nofollow">https://designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;wr_id=5</a></p>]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-13T15:27:10+09:00</dc:date>
</item>


<item>
<title>메시지 브릿지 1.1.1 버그 및 성능 패치</title>
<link>https://re.designonex.com/bbs/board.php?bo_table=real_time_bridge&amp;amp;wr_id=8</link>
<description><![CDATA[<p>안녕하세요, 디자인원엑스입니다.</p>
<p>이번에 메시지 브릿지에서 발견된 버그를 수정하고, 안정성과 성능을 향상시키는 패치를 진행하였습니다. 이번 업데이트를 통해 보다 안정적이고 쾌적한 환경에서 서비스를 이용하실 수 있도록 개선하였습니다.</p>
<p>앞으로도 사용자 여러분께서 편리하고 안정적으로 서비스를 이용하실 수 있도록 지속적으로 모니터링하고, 필요 시 신속한 패치와 기능 개선을 진행할 예정입니다. 고객 여러분의 소중한 의견과 피드백은 저희 서비스 품질 향상의 중요한 밑거름이 됩니다.</p>
<p>디자인원엑스는 항상 최상의 사용자 경험을 제공하기 위해 최선을 다하겠습니다. 앞으로도 많은 관심과 격려 부탁드립니다.</p> ]]></description>
<dc:creator>관리자</dc:creator>
<dc:date>2025-11-12T21:38:04+09:00</dc:date>
</item>

</channel>
</rss>
