0

I am implementing logic that receives real-time stock prices from an external websocket (KIS WebSocket) and sends this information to the front end.

The structure is: React (frontend) - Nest.js (backend) - KIS (external WebSocket)

However, the connection to KIS Websocket works well, and the real-time price of the item to be viewed is communicated well, but only pingpong data is received.

like this: terminal image

I am curious why the real-time prices of subscribed items are not received from KIS WebSocket. When I tested it with KIS WebSocket using the WebSocket test tool, the real-time price was received well, so it seems to be an internal problem in the server I implemented.

thank you in advance.


React Code :

import React, { useEffect, useState } from "react";
import io from "socket.io-client";

interface ChartRealTimePriceProps {
    stockCode: string;
}

const ChartRealTimePrice: React.FC<ChartRealTimePriceProps> = ({ stockCode }) => {
    const [price, setPrice] = useState<string>("");

    useEffect(() => {
        const fetchCurrentPrice = async () => {
            try {
                const response = await fetch(`${process.env.REACT_APP_API_SERVER_URI}/company/current-price/${stockCode}`);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                const data = await response.json();
                setPrice(data.result);
            } catch (error) {
                console.error("Error fetching data:", error);
            }
        };

        fetchCurrentPrice();
    }, [stockCode]);

    useEffect(() => {
        const webSocket = io(`${process.env.REACT_APP_WEBSOCKET_SERVER_WS_URI}`, {
            withCredentials: true,
            transports: ["websocket"],
        });

        webSocket.on("connect", () => {
            console.log("Connected to WebSocket server");
            webSocket.emit("messageToServer", { stockCode });
        });

        webSocket.on("disconnect", () => {
            console.log("Disconnected from WebSocket server");
        });

        webSocket.on("connect_error", (error) => {
            console.error("WebSocket connect error:", error);
        });

        webSocket.on("error", (error) => {
            console.error("WebSocket error:", error);
        });

        webSocket.on("message", (message) => {
            console.log("WebSocket message:", message);
            if (message.event === "messageFromKSI" && message.data.stockCode === stockCode) {
                setPrice(message.data.price);
            }
        });

        return () => {
            if (webSocket.connected) {
                webSocket.close();
            }
        };
    }, [stockCode]);

    if (price === "") {
        return <div>Loading...</div>;
    }

    return <div>{price}</div>;
};

export default ChartRealTimePrice;


Nest Code : ws.gateway.ts :

import {
    WebSocketGateway,
    WebSocketServer,
    SubscribeMessage,
    OnGatewayConnection,
    OnGatewayDisconnect,
    OnGatewayInit,
} from "@nestjs/websockets";
import { Server, Socket } from "socket.io";
import { ExternalWsService } from "./external-ws.service";
import { Injectable, Logger } from "@nestjs/common";

@Injectable()
@WebSocketGateway({
    cors: {
        origin: "ws://localhost:3000",
        methods: "GET,POST",
        credentials: true,
    },
})
export class WsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
    @WebSocketServer() server: Server;
    private clients: Map<string, Socket> = new Map();
    private readonly logger = new Logger(WsGateway.name);

    afterInit() {
        this.logger.log("WebSocket Server Initialized ✅");
    }

    constructor(private externalWsService: ExternalWsService) {
        // KSI WebSocket Message to Clients
        this.externalWsService.onMessage((data) => {
            try {
                const parsedMessage = JSON.parse(data.toString());
                this.logger.log(` message from KSI WebSocket: ${JSON.stringify(parsedMessage)}`);
            } catch (error) {
                this.logger.error(`Error parsing KSI message: ${error}`);
            }

            this.broadcastToClients("messageFromKSI", data);
        });
    }

    @SubscribeMessage("messageToServer")
    handleMessage(client: Socket, payload: any): void {
        this.logger.log(`Received message from ${client.id}: ${payload}`);

        // Message to KSI Websocket Server
        this.externalWsService.sendMessage(payload.stockCode);
    }

    broadcastToClients(event: string, message: any) {
        this.server.emit(event, message);
    }

    handleConnection(client: Socket) {
        this.logger.log(`Client connected: ${client.id}`);
        this.clients.set(client.id, client);
    }

    handleDisconnect(client: Socket) {
        this.logger.log(`Client disconnected: ${client.id}`);
        this.clients.delete(client.id);
    }
}

external-ws.service.ts :

import { Injectable, Logger } from "@nestjs/common";
import WebSocket from "ws";
import * as dotenv from "dotenv";

dotenv.config({ path: `.env.${process.env.NODE_ENV}` });

@Injectable()
export class ExternalWsService {
    private externalWebSocket: WebSocket;
    private connectedKSIWebSocket = false;
    private readonly logger = new Logger(ExternalWsService.name);

    constructor() {
        this.connectKSIWebSocket();
    }

    private connectKSIWebSocket() {
        if (this.connectedKSIWebSocket) {
            this.logger.log("Already connected to KSI WebSocket server");
            return;
        }

        try {
            this.externalWebSocket = new WebSocket(`${process.env.KIS_WEBSOCKET_SERVER_URL}`);

            this.externalWebSocket.on("open", () => {
                this.logger.log("Connected to KSI WebSocket server");
                this.connectedKSIWebSocket = true;
            });

            this.externalWebSocket.on("close", () => {
                this.logger.log("Disconnected from KSI WebSocket server");
                this.connectedKSIWebSocket = false;
                setTimeout(() => this.connectKSIWebSocket(), 5000);
            });

            this.externalWebSocket.on("error", (error) => {
                this.logger.error("Error with KSI WebSocket connection:", error);
            });
        } catch (error) {
            this.logger.error(`Failed to connect to KSI WebSocket server: ${error.message}`);
        }
    }

    sendMessage(message: any) {
        if (this.externalWebSocket && this.externalWebSocket.readyState === WebSocket.OPEN) {
            const header = {
                approval_key: "fb73e061-2c57-48e7-96b5-80f65b7dd5a1",
                custtype: "P",
                tr_type: "1",
                "content-type": "utf-8",
            };
            const body = {
                input: {
                    tr_id: "H0IFCNT0",
                    tr_key: message,
                },
            };

            this.externalWebSocket.send(JSON.stringify({ header, body }));
        } else {
            this.logger.warn("Cannot send message, WebSocket is not open");
        }
    }

    onMessage(callback: (data: any) => void) {
        if (this.externalWebSocket) {
            this.externalWebSocket.on("message", callback);
        } else {
            this.logger.error("WebSocket is not initialized");
        }
    }
}

0

Browse other questions tagged or ask your own question.