@dbcube/core 3.0.6 → 3.0.8

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/index.cjs CHANGED
@@ -767,6 +767,7 @@ var import_module2 = require("module");
767
767
  var net = __toESM(require("net"));
768
768
  var import_child_process2 = require("child_process");
769
769
  var globalTcpServers = /* @__PURE__ */ new Map();
770
+ var globalTcpConnections = /* @__PURE__ */ new Map();
770
771
  var QueryEngine = class {
771
772
  name;
772
773
  config;
@@ -784,13 +785,27 @@ var QueryEngine = class {
784
785
  this.tcpPort = this.generatePort();
785
786
  }
786
787
  generatePort() {
787
- let hash = 0;
788
- for (let i = 0; i < this.connectionId.length; i++) {
789
- const char = this.connectionId.charCodeAt(i);
790
- hash = (hash << 5) - hash + char;
791
- hash = hash & hash;
788
+ return 9944;
789
+ }
790
+ async findAvailablePort(startPort) {
791
+ for (let port = startPort; port >= 9900; port--) {
792
+ if (await this.isPortAvailable(port)) {
793
+ return port;
794
+ }
792
795
  }
793
- return 8100 + Math.abs(hash % 900);
796
+ throw new Error("No available ports found in range 9900-9944");
797
+ }
798
+ isPortAvailable(port) {
799
+ return new Promise((resolve5) => {
800
+ const net2 = require("net");
801
+ const tester = net2.createServer();
802
+ tester.once("error", () => resolve5(false));
803
+ tester.once("listening", () => {
804
+ tester.close();
805
+ resolve5(true);
806
+ });
807
+ tester.listen(port, "127.0.0.1");
808
+ });
794
809
  }
795
810
  async initializeBinary() {
796
811
  if (!this.binary) {
@@ -871,15 +886,51 @@ var QueryEngine = class {
871
886
  if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
872
887
  console.log("\u{1F680} Starting TCP server for ultra-fast queries...");
873
888
  await this.startTcpServer();
889
+ await this.waitForServerReady();
874
890
  }
875
891
  console.log("\u26A1 Using TCP server (ultra-fast)");
876
- return this.sendTcpRequest(args);
892
+ return this.sendTcpRequestFast(args);
893
+ }
894
+ async waitForServerReady() {
895
+ const maxRetries = 10;
896
+ const retryDelay = 500;
897
+ for (let i = 0; i < maxRetries; i++) {
898
+ if (await this.isServerResponding()) {
899
+ return;
900
+ }
901
+ console.log(`\u23F3 Waiting for TCP server to be ready... (${i + 1}/${maxRetries})`);
902
+ await this.sleep(retryDelay);
903
+ }
904
+ throw new Error("TCP server failed to become ready within timeout");
905
+ }
906
+ async isServerResponding() {
907
+ return new Promise((resolve5) => {
908
+ const client = new net.Socket();
909
+ const timeout = setTimeout(() => {
910
+ client.destroy();
911
+ resolve5(false);
912
+ }, 1e3);
913
+ client.connect(this.tcpPort, "127.0.0.1", () => {
914
+ clearTimeout(timeout);
915
+ client.destroy();
916
+ resolve5(true);
917
+ });
918
+ client.on("error", () => {
919
+ clearTimeout(timeout);
920
+ resolve5(false);
921
+ });
922
+ });
923
+ }
924
+ sleep(ms) {
925
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
877
926
  }
878
927
  async startTcpServer() {
879
928
  await this.initializeBinary();
880
929
  if (!this.binary) {
881
930
  throw new Error("Binary not initialized");
882
931
  }
932
+ this.tcpPort = await this.findAvailablePort(this.tcpPort);
933
+ console.log(`\u{1F310} Using port ${this.tcpPort} for TCP server`);
883
934
  return new Promise((resolve5, reject) => {
884
935
  const serverArgs = [...this.arguments, "--action", "server", "--port", this.tcpPort.toString()];
885
936
  const serverProcess = (0, import_child_process2.spawn)(this.binary["query_engine"], serverArgs);
@@ -889,7 +940,7 @@ var QueryEngine = class {
889
940
  serverProcess.kill();
890
941
  reject(new Error("TCP server startup timeout"));
891
942
  }
892
- }, 1e4);
943
+ }, 15e3);
893
944
  serverProcess.stdout.on("data", (data) => {
894
945
  const output = data.toString();
895
946
  console.log(`[TCP Server] ${output.trim()}`);
@@ -924,16 +975,24 @@ var QueryEngine = class {
924
975
  return new Promise((resolve5, reject) => {
925
976
  const client = new net.Socket();
926
977
  let responseBuffer = "";
978
+ let isResolved = false;
927
979
  const timeout = setTimeout(() => {
928
- client.destroy();
929
- reject(new Error("TCP request timeout"));
930
- }, this.timeout);
980
+ if (!isResolved) {
981
+ isResolved = true;
982
+ client.destroy();
983
+ reject(new Error("TCP request timeout"));
984
+ }
985
+ }, this.timeout * 2);
931
986
  client.connect(this.tcpPort, "127.0.0.1", () => {
932
987
  const dmlIndex = args.findIndex((arg) => arg === "--dml");
933
988
  const dmlJson = dmlIndex !== -1 ? args[dmlIndex + 1] : null;
934
989
  if (!dmlJson) {
935
- client.destroy();
936
- reject(new Error("No DML found in arguments"));
990
+ if (!isResolved) {
991
+ isResolved = true;
992
+ clearTimeout(timeout);
993
+ client.destroy();
994
+ reject(new Error("No DML found in arguments"));
995
+ }
937
996
  return;
938
997
  }
939
998
  const command = {
@@ -945,7 +1004,8 @@ var QueryEngine = class {
945
1004
  client.on("data", (data) => {
946
1005
  responseBuffer += data.toString();
947
1006
  const match = responseBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
948
- if (match) {
1007
+ if (match && !isResolved) {
1008
+ isResolved = true;
949
1009
  clearTimeout(timeout);
950
1010
  client.destroy();
951
1011
  try {
@@ -961,13 +1021,149 @@ var QueryEngine = class {
961
1021
  }
962
1022
  });
963
1023
  client.on("error", (error) => {
964
- clearTimeout(timeout);
965
- reject(error);
1024
+ if (!isResolved) {
1025
+ isResolved = true;
1026
+ clearTimeout(timeout);
1027
+ reject(error);
1028
+ }
966
1029
  });
967
1030
  client.on("close", () => {
1031
+ if (!isResolved) {
1032
+ clearTimeout(timeout);
1033
+ if (!responseBuffer.includes("PROCESS_RESPONSE:")) {
1034
+ reject(new Error("Connection closed without valid response"));
1035
+ }
1036
+ }
1037
+ });
1038
+ });
1039
+ }
1040
+ async sendTcpRequestFast(args) {
1041
+ const existingConnection = globalTcpConnections.get(this.connectionId);
1042
+ if (existingConnection && existingConnection.readyState === "open") {
1043
+ try {
1044
+ return await this.sendOnExistingConnection(existingConnection, args);
1045
+ } catch (error) {
1046
+ globalTcpConnections.delete(this.connectionId);
1047
+ existingConnection.destroy();
1048
+ }
1049
+ }
1050
+ return await this.createPersistentConnection(args);
1051
+ }
1052
+ async sendOnExistingConnection(connection, args) {
1053
+ return new Promise((resolve5, reject) => {
1054
+ const dmlIndex = args.findIndex((arg) => arg === "--dml");
1055
+ const dmlJson = dmlIndex !== -1 ? args[dmlIndex + 1] : null;
1056
+ if (!dmlJson) {
1057
+ reject(new Error("No DML found in arguments"));
1058
+ return;
1059
+ }
1060
+ let responseBuffer = "";
1061
+ let isResolved = false;
1062
+ const timeout = setTimeout(() => {
1063
+ if (!isResolved) {
1064
+ isResolved = true;
1065
+ reject(new Error("TCP request timeout"));
1066
+ }
1067
+ }, 5e3);
1068
+ const onData = (data) => {
1069
+ responseBuffer += data.toString();
1070
+ const match = responseBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
1071
+ if (match && !isResolved) {
1072
+ isResolved = true;
1073
+ clearTimeout(timeout);
1074
+ connection.off("data", onData);
1075
+ connection.off("error", onError);
1076
+ try {
1077
+ const response = JSON.parse(match[1]);
1078
+ resolve5({
1079
+ status: response.status,
1080
+ message: response.message,
1081
+ data: response.data
1082
+ });
1083
+ } catch (error) {
1084
+ reject(new Error("Failed to parse TCP response"));
1085
+ }
1086
+ }
1087
+ };
1088
+ const onError = (error) => {
1089
+ if (!isResolved) {
1090
+ isResolved = true;
1091
+ clearTimeout(timeout);
1092
+ connection.off("data", onData);
1093
+ connection.off("error", onError);
1094
+ reject(error);
1095
+ }
1096
+ };
1097
+ connection.on("data", onData);
1098
+ connection.on("error", onError);
1099
+ const command = {
1100
+ action: "execute",
1101
+ dml: dmlJson
1102
+ };
1103
+ connection.write(JSON.stringify(command));
1104
+ });
1105
+ }
1106
+ async createPersistentConnection(args) {
1107
+ return new Promise((resolve5, reject) => {
1108
+ const client = new net.Socket();
1109
+ let responseBuffer = "";
1110
+ let isResolved = false;
1111
+ client.setNoDelay(true);
1112
+ client.setKeepAlive(true, 6e4);
1113
+ const timeout = setTimeout(() => {
1114
+ if (!isResolved) {
1115
+ isResolved = true;
1116
+ client.destroy();
1117
+ reject(new Error("TCP connection timeout"));
1118
+ }
1119
+ }, 5e3);
1120
+ client.connect(this.tcpPort, "127.0.0.1", () => {
968
1121
  clearTimeout(timeout);
969
- if (responseBuffer && !responseBuffer.includes("\n")) {
970
- reject(new Error("Incomplete TCP response"));
1122
+ const dmlIndex = args.findIndex((arg) => arg === "--dml");
1123
+ const dmlJson = dmlIndex !== -1 ? args[dmlIndex + 1] : null;
1124
+ if (!dmlJson) {
1125
+ if (!isResolved) {
1126
+ isResolved = true;
1127
+ client.destroy();
1128
+ reject(new Error("No DML found in arguments"));
1129
+ }
1130
+ return;
1131
+ }
1132
+ globalTcpConnections.set(this.connectionId, client);
1133
+ const command = {
1134
+ action: "execute",
1135
+ dml: dmlJson
1136
+ };
1137
+ client.write(JSON.stringify(command));
1138
+ });
1139
+ client.on("data", (data) => {
1140
+ responseBuffer += data.toString();
1141
+ const match = responseBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
1142
+ if (match && !isResolved) {
1143
+ isResolved = true;
1144
+ try {
1145
+ const response = JSON.parse(match[1]);
1146
+ resolve5({
1147
+ status: response.status,
1148
+ message: response.message,
1149
+ data: response.data
1150
+ });
1151
+ } catch (error) {
1152
+ reject(new Error("Failed to parse TCP response"));
1153
+ }
1154
+ }
1155
+ });
1156
+ client.on("error", (error) => {
1157
+ if (!isResolved) {
1158
+ isResolved = true;
1159
+ globalTcpConnections.delete(this.connectionId);
1160
+ reject(error);
1161
+ }
1162
+ });
1163
+ client.on("close", () => {
1164
+ globalTcpConnections.delete(this.connectionId);
1165
+ if (!isResolved && !responseBuffer.includes("PROCESS_RESPONSE:")) {
1166
+ reject(new Error("Connection closed without valid response"));
971
1167
  }
972
1168
  });
973
1169
  });
@@ -1060,6 +1256,12 @@ var QueryEngine = class {
1060
1256
  });
1061
1257
  }
1062
1258
  async disconnect() {
1259
+ const connection = globalTcpConnections.get(this.connectionId);
1260
+ if (connection && connection.readyState === "open") {
1261
+ connection.write(JSON.stringify({ action: "disconnect" }));
1262
+ connection.destroy();
1263
+ globalTcpConnections.delete(this.connectionId);
1264
+ }
1063
1265
  const serverInfo = globalTcpServers.get(this.connectionId);
1064
1266
  if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
1065
1267
  console.log("\u{1F50C} Stopping TCP server...");
@@ -1067,7 +1269,7 @@ var QueryEngine = class {
1067
1269
  globalTcpServers.delete(this.connectionId);
1068
1270
  return {
1069
1271
  status: 200,
1070
- message: "TCP server stopped",
1272
+ message: "TCP server and connections stopped",
1071
1273
  data: null
1072
1274
  };
1073
1275
  }