connectbase-client 3.6.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +260 -118
- package/dist/connect-base.umd.js +3 -3
- package/dist/index.d.mts +46 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +85 -0
- package/dist/index.mjs +85 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1431,10 +1431,36 @@ function createWsPongFrame() {
|
|
|
1431
1431
|
header[1] = 128 | 0;
|
|
1432
1432
|
return Buffer.concat([header, maskKey]);
|
|
1433
1433
|
}
|
|
1434
|
+
function createWsBinaryFrame(payload) {
|
|
1435
|
+
const len = payload.length;
|
|
1436
|
+
const maskKey = crypto.randomBytes(4);
|
|
1437
|
+
let header;
|
|
1438
|
+
if (len < 126) {
|
|
1439
|
+
header = Buffer.alloc(2);
|
|
1440
|
+
header[0] = 130;
|
|
1441
|
+
header[1] = 128 | len;
|
|
1442
|
+
} else if (len < 65536) {
|
|
1443
|
+
header = Buffer.alloc(4);
|
|
1444
|
+
header[0] = 130;
|
|
1445
|
+
header[1] = 128 | 126;
|
|
1446
|
+
header.writeUInt16BE(len, 2);
|
|
1447
|
+
} else {
|
|
1448
|
+
header = Buffer.alloc(10);
|
|
1449
|
+
header[0] = 130;
|
|
1450
|
+
header[1] = 128 | 127;
|
|
1451
|
+
header.writeBigUInt64BE(BigInt(len), 2);
|
|
1452
|
+
}
|
|
1453
|
+
const masked = Buffer.alloc(len);
|
|
1454
|
+
for (let i = 0; i < len; i++) {
|
|
1455
|
+
masked[i] = payload[i] ^ maskKey[i % 4];
|
|
1456
|
+
}
|
|
1457
|
+
return Buffer.concat([header, maskKey, masked]);
|
|
1458
|
+
}
|
|
1434
1459
|
var WsFrameParser = class {
|
|
1435
1460
|
constructor(handlers) {
|
|
1436
1461
|
this.buffer = Buffer.alloc(0);
|
|
1437
1462
|
this.onMessage = handlers.onMessage;
|
|
1463
|
+
this.onBinary = handlers.onBinary;
|
|
1438
1464
|
this.onClose = handlers.onClose;
|
|
1439
1465
|
this.onPing = handlers.onPing;
|
|
1440
1466
|
}
|
|
@@ -1479,6 +1505,13 @@ var WsFrameParser = class {
|
|
|
1479
1505
|
case 1:
|
|
1480
1506
|
this.onMessage(payload.toString("utf-8"));
|
|
1481
1507
|
break;
|
|
1508
|
+
case 2:
|
|
1509
|
+
if (this.onBinary) {
|
|
1510
|
+
const copy = Buffer.alloc(payload.length);
|
|
1511
|
+
payload.copy(copy);
|
|
1512
|
+
this.onBinary(copy);
|
|
1513
|
+
}
|
|
1514
|
+
break;
|
|
1482
1515
|
case 8:
|
|
1483
1516
|
this.onClose();
|
|
1484
1517
|
break;
|
|
@@ -1664,7 +1697,7 @@ async function startTunnel(port, config, tunnelOpts) {
|
|
|
1664
1697
|
const tunnelServerUrl = getTunnelServerUrl(config.baseUrl);
|
|
1665
1698
|
const parsedUrl = new URL(tunnelServerUrl);
|
|
1666
1699
|
const isHttps = parsedUrl.protocol === "https:";
|
|
1667
|
-
let wsPath = `/
|
|
1700
|
+
let wsPath = `/v2/tunnel/connect?app_id=${encodeURIComponent(appId)}&local_port=${port}`;
|
|
1668
1701
|
if (tunnelOpts?.timeout) {
|
|
1669
1702
|
wsPath += `&timeout=${tunnelOpts.timeout}`;
|
|
1670
1703
|
}
|
|
@@ -1741,6 +1774,15 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
1741
1774
|
warn(`\uBA54\uC2DC\uC9C0 \uD30C\uC2F1 \uC2E4\uD328: ${e}`);
|
|
1742
1775
|
}
|
|
1743
1776
|
},
|
|
1777
|
+
onBinary: (data) => {
|
|
1778
|
+
if (data.length < 8) {
|
|
1779
|
+
warn(`v2 binary frame too short (${data.length} bytes)`);
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
const streamId = data.readBigUInt64BE(0).toString();
|
|
1783
|
+
const payload = data.subarray(8);
|
|
1784
|
+
routeStreamData(streamId, payload);
|
|
1785
|
+
},
|
|
1744
1786
|
onClose: () => {
|
|
1745
1787
|
info("\uC11C\uBC84\uAC00 \uC5F0\uACB0\uC744 \uC885\uB8CC\uD588\uC2B5\uB2C8\uB2E4");
|
|
1746
1788
|
sock.destroy();
|
|
@@ -1804,6 +1846,192 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
1804
1846
|
info(`${(delay / 1e3).toFixed(0)}\uCD08 \uD6C4 \uC7AC\uC5F0\uACB0 \uC2DC\uB3C4... (${reconnectAttempts}/${maxReconnectAttempts})`);
|
|
1805
1847
|
setTimeout(connect, delay);
|
|
1806
1848
|
}
|
|
1849
|
+
const streams = /* @__PURE__ */ new Map();
|
|
1850
|
+
function routeStreamData(streamId, payload) {
|
|
1851
|
+
const f = streams.get(streamId);
|
|
1852
|
+
if (!f) return;
|
|
1853
|
+
f.feedBody(payload);
|
|
1854
|
+
}
|
|
1855
|
+
function sendControl(sock, msg) {
|
|
1856
|
+
try {
|
|
1857
|
+
sock.write(createWsTextFrame(JSON.stringify(msg)));
|
|
1858
|
+
} catch {
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
function sendBinary(sock, streamIdStr, payload) {
|
|
1862
|
+
try {
|
|
1863
|
+
const header = Buffer.alloc(8);
|
|
1864
|
+
header.writeBigUInt64BE(BigInt(streamIdStr), 0);
|
|
1865
|
+
sock.write(createWsBinaryFrame(Buffer.concat([header, payload])));
|
|
1866
|
+
} catch {
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
function startHTTPStream(sock, streamId, open, localPort) {
|
|
1870
|
+
const method = open.method || "GET";
|
|
1871
|
+
const reqPath = open.path || "/";
|
|
1872
|
+
const query = open.query || "";
|
|
1873
|
+
const headers = open.headers || {};
|
|
1874
|
+
const fullPath = query ? `${reqPath}?${query}` : reqPath;
|
|
1875
|
+
const localHeaders = {};
|
|
1876
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
1877
|
+
if (k.toLowerCase() !== "host") localHeaders[k] = v;
|
|
1878
|
+
}
|
|
1879
|
+
localHeaders["host"] = `localhost:${localPort}`;
|
|
1880
|
+
let started = false;
|
|
1881
|
+
let cancelled = false;
|
|
1882
|
+
const localReq = http.request(
|
|
1883
|
+
{ hostname: "127.0.0.1", port: localPort, path: fullPath, method, headers: localHeaders },
|
|
1884
|
+
(res) => {
|
|
1885
|
+
const respHeaders = {};
|
|
1886
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
1887
|
+
if (v == null) continue;
|
|
1888
|
+
respHeaders[k] = Array.isArray(v) ? v.join(", ") : v;
|
|
1889
|
+
}
|
|
1890
|
+
started = true;
|
|
1891
|
+
sendControl(sock, {
|
|
1892
|
+
type: "stream_response",
|
|
1893
|
+
stream_id: streamId,
|
|
1894
|
+
status: res.statusCode || 502,
|
|
1895
|
+
headers: respHeaders
|
|
1896
|
+
});
|
|
1897
|
+
const methodColor = method === "GET" ? colors.green : method === "POST" ? colors.blue : colors.yellow;
|
|
1898
|
+
log(`${colors.dim}${(/* @__PURE__ */ new Date()).toLocaleTimeString()}${colors.reset} ${methodColor}${method}${colors.reset} ${reqPath} \u2192 ${res.statusCode}`);
|
|
1899
|
+
res.on("data", (chunk) => {
|
|
1900
|
+
if (cancelled) return;
|
|
1901
|
+
sendBinary(sock, streamId, chunk);
|
|
1902
|
+
});
|
|
1903
|
+
res.on("end", () => {
|
|
1904
|
+
if (cancelled) return;
|
|
1905
|
+
sendControl(sock, { type: "stream_eof", stream_id: streamId, side: "upstream" });
|
|
1906
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId });
|
|
1907
|
+
streams.delete(streamId);
|
|
1908
|
+
});
|
|
1909
|
+
res.on("error", (err) => {
|
|
1910
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId, error: `upstream_error: ${err.message}` });
|
|
1911
|
+
streams.delete(streamId);
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
);
|
|
1915
|
+
localReq.on("error", (err) => {
|
|
1916
|
+
warn(`\uB85C\uCEEC \uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328 (${method} ${reqPath}): ${err.message}`);
|
|
1917
|
+
if (!started) {
|
|
1918
|
+
sendControl(sock, {
|
|
1919
|
+
type: "stream_response",
|
|
1920
|
+
stream_id: streamId,
|
|
1921
|
+
status: 502,
|
|
1922
|
+
headers: { "content-type": "application/json" }
|
|
1923
|
+
});
|
|
1924
|
+
sendBinary(sock, streamId, Buffer.from(JSON.stringify({ error: `Local server error: ${err.message}` })));
|
|
1925
|
+
}
|
|
1926
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId, error: `upstream_error: ${err.message}` });
|
|
1927
|
+
streams.delete(streamId);
|
|
1928
|
+
});
|
|
1929
|
+
const forwarder = {
|
|
1930
|
+
kind: "http",
|
|
1931
|
+
feedBody: (chunk) => {
|
|
1932
|
+
if (!cancelled) localReq.write(chunk);
|
|
1933
|
+
},
|
|
1934
|
+
endBody: () => {
|
|
1935
|
+
if (!cancelled) localReq.end();
|
|
1936
|
+
},
|
|
1937
|
+
cancel: () => {
|
|
1938
|
+
cancelled = true;
|
|
1939
|
+
try {
|
|
1940
|
+
localReq.destroy();
|
|
1941
|
+
} catch {
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
streams.set(streamId, forwarder);
|
|
1946
|
+
}
|
|
1947
|
+
function startWSStream(sock, streamId, open, localPort) {
|
|
1948
|
+
const reqPath = open.path || "/";
|
|
1949
|
+
const query = open.query || "";
|
|
1950
|
+
const headers = open.headers || {};
|
|
1951
|
+
const fullPath = query ? `${reqPath}?${query}` : reqPath;
|
|
1952
|
+
const localHeaders = {};
|
|
1953
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
1954
|
+
if (k.toLowerCase() !== "host") localHeaders[k] = v;
|
|
1955
|
+
}
|
|
1956
|
+
localHeaders["host"] = `localhost:${localPort}`;
|
|
1957
|
+
localHeaders["connection"] = "Upgrade";
|
|
1958
|
+
localHeaders["upgrade"] = "websocket";
|
|
1959
|
+
let cancelled = false;
|
|
1960
|
+
let upstream = null;
|
|
1961
|
+
const req = http.request({
|
|
1962
|
+
hostname: "127.0.0.1",
|
|
1963
|
+
port: localPort,
|
|
1964
|
+
path: fullPath,
|
|
1965
|
+
method: "GET",
|
|
1966
|
+
headers: localHeaders
|
|
1967
|
+
});
|
|
1968
|
+
req.on("upgrade", (res, sk) => {
|
|
1969
|
+
upstream = sk;
|
|
1970
|
+
const respHeaders = {};
|
|
1971
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
1972
|
+
if (v == null) continue;
|
|
1973
|
+
respHeaders[k] = Array.isArray(v) ? v.join(", ") : v;
|
|
1974
|
+
}
|
|
1975
|
+
sendControl(sock, {
|
|
1976
|
+
type: "stream_response",
|
|
1977
|
+
stream_id: streamId,
|
|
1978
|
+
status: res.statusCode || 101,
|
|
1979
|
+
headers: respHeaders,
|
|
1980
|
+
websocket: true
|
|
1981
|
+
});
|
|
1982
|
+
log(`${colors.dim}${(/* @__PURE__ */ new Date()).toLocaleTimeString()}${colors.reset} ${colors.cyan}WS${colors.reset} ${reqPath} \u2192 101`);
|
|
1983
|
+
sk.on("data", (chunk) => {
|
|
1984
|
+
if (cancelled) return;
|
|
1985
|
+
sendBinary(sock, streamId, chunk);
|
|
1986
|
+
});
|
|
1987
|
+
sk.on("close", () => {
|
|
1988
|
+
if (cancelled) return;
|
|
1989
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId });
|
|
1990
|
+
streams.delete(streamId);
|
|
1991
|
+
});
|
|
1992
|
+
sk.on("error", (err) => {
|
|
1993
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId, error: `upstream_error: ${err.message}` });
|
|
1994
|
+
streams.delete(streamId);
|
|
1995
|
+
});
|
|
1996
|
+
});
|
|
1997
|
+
req.on("response", (res) => {
|
|
1998
|
+
const respHeaders = {};
|
|
1999
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
2000
|
+
if (v == null) continue;
|
|
2001
|
+
respHeaders[k] = Array.isArray(v) ? v.join(", ") : v;
|
|
2002
|
+
}
|
|
2003
|
+
sendControl(sock, {
|
|
2004
|
+
type: "stream_response",
|
|
2005
|
+
stream_id: streamId,
|
|
2006
|
+
status: res.statusCode || 502,
|
|
2007
|
+
headers: respHeaders,
|
|
2008
|
+
websocket: false
|
|
2009
|
+
});
|
|
2010
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId });
|
|
2011
|
+
streams.delete(streamId);
|
|
2012
|
+
});
|
|
2013
|
+
req.on("error", (err) => {
|
|
2014
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId, error: `upstream_error: ${err.message}` });
|
|
2015
|
+
streams.delete(streamId);
|
|
2016
|
+
});
|
|
2017
|
+
req.end();
|
|
2018
|
+
const forwarder = {
|
|
2019
|
+
kind: "ws",
|
|
2020
|
+
feedBody: (chunk) => {
|
|
2021
|
+
if (!cancelled && upstream) upstream.write(chunk);
|
|
2022
|
+
},
|
|
2023
|
+
endBody: () => {
|
|
2024
|
+
},
|
|
2025
|
+
cancel: () => {
|
|
2026
|
+
cancelled = true;
|
|
2027
|
+
try {
|
|
2028
|
+
upstream?.destroy();
|
|
2029
|
+
} catch {
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
streams.set(streamId, forwarder);
|
|
2034
|
+
}
|
|
1807
2035
|
async function handleMessage(msg, sock, localPort) {
|
|
1808
2036
|
switch (msg.type) {
|
|
1809
2037
|
case "tunnel_ready": {
|
|
@@ -1851,9 +2079,38 @@ ${colors.dim}Ctrl+C\uB85C \uC885\uB8CC${colors.reset}
|
|
|
1851
2079
|
`);
|
|
1852
2080
|
break;
|
|
1853
2081
|
}
|
|
1854
|
-
case "
|
|
1855
|
-
|
|
2082
|
+
case "stream_open": {
|
|
2083
|
+
const sid = String(msg.stream_id ?? "");
|
|
2084
|
+
if (!sid) {
|
|
2085
|
+
warn("stream_open with empty stream_id");
|
|
2086
|
+
break;
|
|
2087
|
+
}
|
|
2088
|
+
const kind = msg.kind || "http";
|
|
2089
|
+
if (kind === "ws") {
|
|
2090
|
+
startWSStream(sock, sid, msg, localPort);
|
|
2091
|
+
} else {
|
|
2092
|
+
startHTTPStream(sock, sid, msg, localPort);
|
|
2093
|
+
}
|
|
1856
2094
|
break;
|
|
2095
|
+
}
|
|
2096
|
+
case "stream_eof": {
|
|
2097
|
+
const sid = String(msg.stream_id ?? "");
|
|
2098
|
+
const side = msg.side;
|
|
2099
|
+
if (side === "client") {
|
|
2100
|
+
const f = streams.get(sid);
|
|
2101
|
+
f?.endBody();
|
|
2102
|
+
}
|
|
2103
|
+
break;
|
|
2104
|
+
}
|
|
2105
|
+
case "stream_close": {
|
|
2106
|
+
const sid = String(msg.stream_id ?? "");
|
|
2107
|
+
const f = streams.get(sid);
|
|
2108
|
+
if (f) {
|
|
2109
|
+
f.cancel();
|
|
2110
|
+
streams.delete(sid);
|
|
2111
|
+
}
|
|
2112
|
+
break;
|
|
2113
|
+
}
|
|
1857
2114
|
case "tunnel_error": {
|
|
1858
2115
|
const result = handleTunnelError(msg, appId, localPort);
|
|
1859
2116
|
error(result.message);
|
|
@@ -1868,121 +2125,6 @@ ${colors.dim}Ctrl+C\uB85C \uC885\uB8CC${colors.reset}
|
|
|
1868
2125
|
break;
|
|
1869
2126
|
}
|
|
1870
2127
|
}
|
|
1871
|
-
function forwardRequest(msg, sock, localPort) {
|
|
1872
|
-
const requestId = msg.request_id;
|
|
1873
|
-
const method = msg.method;
|
|
1874
|
-
const reqPath = msg.path;
|
|
1875
|
-
const query = msg.query || "";
|
|
1876
|
-
const headers = msg.headers || {};
|
|
1877
|
-
const bodyBase64 = msg.body;
|
|
1878
|
-
const fullPath = query ? `${reqPath}?${query}` : reqPath;
|
|
1879
|
-
const localHeaders = {};
|
|
1880
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
1881
|
-
if (key.toLowerCase() !== "host") {
|
|
1882
|
-
localHeaders[key] = value;
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
localHeaders["host"] = `localhost:${localPort}`;
|
|
1886
|
-
const reqOptions = {
|
|
1887
|
-
hostname: "127.0.0.1",
|
|
1888
|
-
port: localPort,
|
|
1889
|
-
path: fullPath,
|
|
1890
|
-
method,
|
|
1891
|
-
headers: localHeaders
|
|
1892
|
-
};
|
|
1893
|
-
const localReq = http.request(reqOptions, (res) => {
|
|
1894
|
-
const responseHeaders = {};
|
|
1895
|
-
for (const [key, value] of Object.entries(res.headers)) {
|
|
1896
|
-
if (value) responseHeaders[key] = Array.isArray(value) ? value.join(", ") : value;
|
|
1897
|
-
}
|
|
1898
|
-
const contentType = (responseHeaders["content-type"] || "").toLowerCase();
|
|
1899
|
-
const transferEncoding = (responseHeaders["transfer-encoding"] || "").toLowerCase();
|
|
1900
|
-
const isStreaming = contentType.includes("text/event-stream") || transferEncoding.includes("chunked");
|
|
1901
|
-
if (isStreaming) {
|
|
1902
|
-
try {
|
|
1903
|
-
sock.write(createWsTextFrame(JSON.stringify({
|
|
1904
|
-
type: "http_response_start",
|
|
1905
|
-
request_id: requestId,
|
|
1906
|
-
status: res.statusCode || 200,
|
|
1907
|
-
headers: responseHeaders
|
|
1908
|
-
})));
|
|
1909
|
-
} catch {
|
|
1910
|
-
warn(`\uC2A4\uD2B8\uB9AC\uBC0D \uC2DC\uC791 \uC804\uC1A1 \uC2E4\uD328: ${requestId}`);
|
|
1911
|
-
return;
|
|
1912
|
-
}
|
|
1913
|
-
const methodColor = method === "GET" ? colors.green : method === "POST" ? colors.blue : colors.yellow;
|
|
1914
|
-
log(`${colors.dim}${(/* @__PURE__ */ new Date()).toLocaleTimeString()}${colors.reset} ${methodColor}${method}${colors.reset} ${reqPath} \u2192 ${res.statusCode} ${colors.cyan}[stream]${colors.reset}`);
|
|
1915
|
-
res.on("data", (chunk) => {
|
|
1916
|
-
try {
|
|
1917
|
-
sock.write(createWsTextFrame(JSON.stringify({
|
|
1918
|
-
type: "http_response_chunk",
|
|
1919
|
-
request_id: requestId,
|
|
1920
|
-
data: chunk.toString("base64")
|
|
1921
|
-
})));
|
|
1922
|
-
} catch {
|
|
1923
|
-
warn(`\uC2A4\uD2B8\uB9AC\uBC0D \uCCAD\uD06C \uC804\uC1A1 \uC2E4\uD328: ${requestId}`);
|
|
1924
|
-
}
|
|
1925
|
-
});
|
|
1926
|
-
res.on("end", () => {
|
|
1927
|
-
try {
|
|
1928
|
-
sock.write(createWsTextFrame(JSON.stringify({
|
|
1929
|
-
type: "http_response_end",
|
|
1930
|
-
request_id: requestId
|
|
1931
|
-
})));
|
|
1932
|
-
} catch {
|
|
1933
|
-
}
|
|
1934
|
-
});
|
|
1935
|
-
res.on("error", (err) => {
|
|
1936
|
-
try {
|
|
1937
|
-
sock.write(createWsTextFrame(JSON.stringify({
|
|
1938
|
-
type: "http_response_error",
|
|
1939
|
-
request_id: requestId,
|
|
1940
|
-
error: err.message
|
|
1941
|
-
})));
|
|
1942
|
-
} catch {
|
|
1943
|
-
}
|
|
1944
|
-
});
|
|
1945
|
-
} else {
|
|
1946
|
-
const chunks = [];
|
|
1947
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
1948
|
-
res.on("end", () => {
|
|
1949
|
-
const body = Buffer.concat(chunks);
|
|
1950
|
-
const response = {
|
|
1951
|
-
type: "http_response",
|
|
1952
|
-
request_id: requestId,
|
|
1953
|
-
status: res.statusCode || 200,
|
|
1954
|
-
headers: responseHeaders,
|
|
1955
|
-
body: body.length > 0 ? body.toString("base64") : ""
|
|
1956
|
-
};
|
|
1957
|
-
try {
|
|
1958
|
-
sock.write(createWsTextFrame(JSON.stringify(response)));
|
|
1959
|
-
const methodColor = method === "GET" ? colors.green : method === "POST" ? colors.blue : colors.yellow;
|
|
1960
|
-
log(`${colors.dim}${(/* @__PURE__ */ new Date()).toLocaleTimeString()}${colors.reset} ${methodColor}${method}${colors.reset} ${reqPath} \u2192 ${res.statusCode}`);
|
|
1961
|
-
} catch {
|
|
1962
|
-
warn(`\uC751\uB2F5 \uC804\uC1A1 \uC2E4\uD328: ${requestId}`);
|
|
1963
|
-
}
|
|
1964
|
-
});
|
|
1965
|
-
}
|
|
1966
|
-
});
|
|
1967
|
-
localReq.on("error", (err) => {
|
|
1968
|
-
const response = {
|
|
1969
|
-
type: "http_response",
|
|
1970
|
-
request_id: requestId,
|
|
1971
|
-
status: 502,
|
|
1972
|
-
headers: { "content-type": "application/json" },
|
|
1973
|
-
body: Buffer.from(JSON.stringify({ error: `Local server error: ${err.message}` })).toString("base64")
|
|
1974
|
-
};
|
|
1975
|
-
try {
|
|
1976
|
-
sock.write(createWsTextFrame(JSON.stringify(response)));
|
|
1977
|
-
} catch {
|
|
1978
|
-
}
|
|
1979
|
-
warn(`\uB85C\uCEEC \uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328 (${method} ${reqPath}): ${err.message}`);
|
|
1980
|
-
});
|
|
1981
|
-
if (bodyBase64) {
|
|
1982
|
-
localReq.write(Buffer.from(bodyBase64, "base64"));
|
|
1983
|
-
}
|
|
1984
|
-
localReq.end();
|
|
1985
|
-
}
|
|
1986
2128
|
connect();
|
|
1987
2129
|
await new Promise(() => {
|
|
1988
2130
|
});
|