// BULC Client - TCP Socket communication with Java application
import * as net from "net";
const DEFAULT_PORT = 19840;
const DEFAULT_HOST = "localhost";
const CONNECTION_TIMEOUT = 5000;
const RESPONSE_TIMEOUT = 30000;
export class BulcClient {
port;
host;
constructor(port = DEFAULT_PORT, host = DEFAULT_HOST) {
this.port = port;
this.host = host;
}
async sendCommand(cmd) {
return new Promise((resolve, reject) => {
const socket = new net.Socket();
let responseData = "";
let resolved = false;
// Connection timeout
const connectionTimer = setTimeout(() => {
if (!resolved) {
resolved = true;
socket.destroy();
reject(new Error(`BULC 연결 실패: ${this.host}:${this.port}에 연결할 수 없습니다. ` +
`BULC 애플리케이션이 실행 중인지 확인하세요.`));
}
}, CONNECTION_TIMEOUT);
// Response timeout
let responseTimer = null;
socket.on("connect", () => {
clearTimeout(connectionTimer);
// Set response timeout after connection
responseTimer = setTimeout(() => {
if (!resolved) {
resolved = true;
socket.destroy();
reject(new Error("BULC 응답 타임아웃: 30초 내에 응답이 없습니다."));
}
}, RESPONSE_TIMEOUT);
// Send command as JSON line
const json = JSON.stringify(cmd) + "\n";
socket.write(json);
});
socket.on("data", (data) => {
responseData += data.toString();
// Check for complete JSON response (ends with newline)
if (responseData.includes("\n")) {
if (responseTimer)
clearTimeout(responseTimer);
if (!resolved) {
resolved = true;
socket.end();
try {
const lines = responseData.trim().split("\n");
const lastLine = lines[lines.length - 1];
const result = JSON.parse(lastLine);
resolve(result);
}
catch (e) {
reject(new Error(`Invalid JSON response: ${responseData}`));
}
}
}
});
socket.on("error", (err) => {
clearTimeout(connectionTimer);
if (responseTimer)
clearTimeout(responseTimer);
if (!resolved) {
resolved = true;
reject(new Error(`BULC 연결 에러: ${err.message}. ` +
`BULC 애플리케이션이 실행 중인지 확인하세요.`));
}
});
socket.on("close", () => {
clearTimeout(connectionTimer);
if (responseTimer)
clearTimeout(responseTimer);
if (!resolved) {
resolved = true;
reject(new Error("BULC 연결이 닫혔습니다."));
}
});
// Connect
socket.connect(this.port, this.host);
});
}
async isConnected() {
try {
const result = await this.sendCommand({ action: "ping", params: {} });
return result.success === true;
}
catch {
return false;
}
}
}
// Singleton instance
let clientInstance = null;
export function getBulcClient() {
if (!clientInstance) {
const port = process.env.BULC_PORT ? parseInt(process.env.BULC_PORT) : DEFAULT_PORT;
clientInstance = new BulcClient(port);
}
return clientInstance;
}