Skip to content

Commit 8276aab

Browse files
author
Daniele Briggi
committed
chore: update libs
1 parent 9568309 commit 8276aab

27 files changed

+3618
-0
lines changed

lib/drivers/connection-tls.d.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* connection-tls.ts - connection via tls socket and sqlitecloud protocol
3+
*/
4+
import { SQLiteCloudConnection } from './connection';
5+
import { type ErrorCallback, type ResultsCallback, SQLiteCloudCommand, type SQLiteCloudConfig } from './types';
6+
/**
7+
* Implementation of SQLiteCloudConnection that connects to the database using specific tls APIs
8+
* that connect to native sockets or tls sockets and communicates via raw, binary protocol.
9+
*/
10+
export declare class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
11+
/** Currently opened bun socket used to communicated with SQLiteCloud server */
12+
private socket?;
13+
/** True if connection is open */
14+
get connected(): boolean;
15+
connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
16+
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
17+
transportCommands(commands: string | SQLiteCloudCommand, callback?: ResultsCallback): this;
18+
private buffer;
19+
private startedOn;
20+
private executingCommands?;
21+
private processCallback?;
22+
private pendingChunks;
23+
/** Handles data received in response to an outbound command sent by processCommands */
24+
private processCommandsData;
25+
/** Completes a transaction initiated by processCommands */
26+
private processCommandsFinish;
27+
/** Disconnect immediately, release connection, no events. */
28+
close(): this;
29+
}
30+
export default SQLiteCloudTlsConnection;

lib/drivers/connection-tls.js

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
"use strict";
2+
/**
3+
* connection-tls.ts - connection via tls socket and sqlitecloud protocol
4+
*/
5+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6+
if (k2 === undefined) k2 = k;
7+
var desc = Object.getOwnPropertyDescriptor(m, k);
8+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9+
desc = { enumerable: true, get: function() { return m[k]; } };
10+
}
11+
Object.defineProperty(o, k2, desc);
12+
}) : (function(o, m, k, k2) {
13+
if (k2 === undefined) k2 = k;
14+
o[k2] = m[k];
15+
}));
16+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17+
Object.defineProperty(o, "default", { enumerable: true, value: v });
18+
}) : function(o, v) {
19+
o["default"] = v;
20+
});
21+
var __importStar = (this && this.__importStar) || (function () {
22+
var ownKeys = function(o) {
23+
ownKeys = Object.getOwnPropertyNames || function (o) {
24+
var ar = [];
25+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26+
return ar;
27+
};
28+
return ownKeys(o);
29+
};
30+
return function (mod) {
31+
if (mod && mod.__esModule) return mod;
32+
var result = {};
33+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34+
__setModuleDefault(result, mod);
35+
return result;
36+
};
37+
})();
38+
Object.defineProperty(exports, "__esModule", { value: true });
39+
exports.SQLiteCloudTlsConnection = void 0;
40+
const connection_1 = require("./connection");
41+
const protocol_1 = require("./protocol");
42+
const types_1 = require("./types");
43+
const utilities_1 = require("./utilities");
44+
// explicitly importing buffer library to allow cross-platform support by replacing it
45+
const buffer_1 = require("buffer");
46+
const tls = __importStar(require("tls"));
47+
/**
48+
* Implementation of SQLiteCloudConnection that connects to the database using specific tls APIs
49+
* that connect to native sockets or tls sockets and communicates via raw, binary protocol.
50+
*/
51+
class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
52+
constructor() {
53+
super(...arguments);
54+
// processCommands sets up empty buffers, results callback then send the command to the server via socket.write
55+
// onData is called when data is received, it will process the data until all data is retrieved for a response
56+
// when response is complete or there's an error, finish is called to call the results callback set by processCommands...
57+
// buffer to accumulate incoming data until an whole command is received and can be parsed
58+
this.buffer = buffer_1.Buffer.alloc(0);
59+
this.startedOn = new Date();
60+
this.pendingChunks = [];
61+
}
62+
/** True if connection is open */
63+
get connected() {
64+
return !!this.socket;
65+
}
66+
/* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
67+
connectTransport(config, callback) {
68+
console.assert(!this.connected, 'SQLiteCloudTlsConnection.connect - connection already established');
69+
if (this.config.verbose) {
70+
console.debug(`-> connecting ${config === null || config === void 0 ? void 0 : config.host}:${config === null || config === void 0 ? void 0 : config.port}`);
71+
}
72+
this.config = config;
73+
const initializationCommands = (0, utilities_1.getInitializationCommands)(config);
74+
// connect to plain socket, without encryption, only if insecure parameter specified
75+
// this option is mainly for testing purposes and is not available on production nodes
76+
// which would need to connect using tls and proper certificates as per code below
77+
const connectionOptions = {
78+
host: config.host,
79+
port: config.port,
80+
rejectUnauthorized: config.host != 'localhost',
81+
// Server name for the SNI (Server Name Indication) TLS extension.
82+
// https://r2.nodejs.org/docs/v6.11.4/api/tls.html#tls_class_tls_tlssocket
83+
servername: config.host
84+
};
85+
// tls.connect in the react-native-tcp-socket library is tls.connectTLS
86+
let connector = tls.connect;
87+
// @ts-ignore
88+
if (typeof tls.connectTLS !== 'undefined') {
89+
// @ts-ignore
90+
connector = tls.connectTLS;
91+
}
92+
this.socket = connector(connectionOptions, () => {
93+
var _a;
94+
if (this.config.verbose) {
95+
console.debug(`SQLiteCloudTlsConnection - connected to ${this.config.host}, authorized: ${(_a = this.socket) === null || _a === void 0 ? void 0 : _a.authorized}`);
96+
}
97+
this.transportCommands(initializationCommands, error => {
98+
if (this.config.verbose) {
99+
console.debug(`SQLiteCloudTlsConnection - initialized connection`);
100+
}
101+
callback === null || callback === void 0 ? void 0 : callback.call(this, error);
102+
});
103+
});
104+
this.socket.setKeepAlive(true);
105+
// disable Nagle algorithm because we want our writes to be sent ASAP
106+
// https://brooker.co.za/blog/2024/05/09/nagle.html
107+
this.socket.setNoDelay(true);
108+
this.socket.on('data', data => {
109+
this.processCommandsData(data);
110+
});
111+
this.socket.on('error', error => {
112+
this.close();
113+
this.processCommandsFinish(new types_1.SQLiteCloudError('Connection error', { errorCode: 'ERR_CONNECTION_ERROR', cause: error }));
114+
});
115+
this.socket.on('end', () => {
116+
this.close();
117+
if (this.processCallback)
118+
this.processCommandsFinish(new types_1.SQLiteCloudError('Server ended the connection', { errorCode: 'ERR_CONNECTION_ENDED' }));
119+
});
120+
this.socket.on('close', () => {
121+
this.close();
122+
this.processCommandsFinish(new types_1.SQLiteCloudError('Connection closed', { errorCode: 'ERR_CONNECTION_CLOSED' }));
123+
});
124+
this.socket.on('timeout', () => {
125+
this.close();
126+
this.processCommandsFinish(new types_1.SQLiteCloudError('Connection ened due to timeout', { errorCode: 'ERR_CONNECTION_TIMEOUT' }));
127+
});
128+
return this;
129+
}
130+
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
131+
transportCommands(commands, callback) {
132+
var _a, _b, _c, _d, _e;
133+
// connection needs to be established?
134+
if (!this.socket) {
135+
callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));
136+
return this;
137+
}
138+
if (typeof commands === 'string') {
139+
commands = { query: commands };
140+
}
141+
// reset buffer and rowset chunks, define response callback
142+
this.buffer = buffer_1.Buffer.alloc(0);
143+
this.startedOn = new Date();
144+
this.processCallback = callback;
145+
this.executingCommands = commands;
146+
// compose commands following SCPC protocol
147+
const formattedCommands = (0, protocol_1.formatCommand)(commands);
148+
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.verbose) {
149+
console.debug(`-> ${formattedCommands}`);
150+
}
151+
const timeoutMs = (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : 0;
152+
if (timeoutMs > 0) {
153+
const timeout = setTimeout(() => {
154+
var _a;
155+
callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection timeout out', { errorCode: 'ERR_CONNECTION_TIMEOUT' }));
156+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.destroy();
157+
this.socket = undefined;
158+
}, timeoutMs);
159+
(_d = this.socket) === null || _d === void 0 ? void 0 : _d.write(formattedCommands, () => {
160+
clearTimeout(timeout); // Clear the timeout on successful write
161+
});
162+
}
163+
else {
164+
(_e = this.socket) === null || _e === void 0 ? void 0 : _e.write(formattedCommands);
165+
}
166+
return this;
167+
}
168+
/** Handles data received in response to an outbound command sent by processCommands */
169+
processCommandsData(data) {
170+
var _a, _b, _c, _d, _e, _f, _g;
171+
try {
172+
// append data to buffer as it arrives
173+
if (data.length && data.length > 0) {
174+
// console.debug(`processCommandsData - received ${data.length} bytes`)
175+
this.buffer = buffer_1.Buffer.concat([this.buffer, data]);
176+
}
177+
let dataType = (_a = this.buffer) === null || _a === void 0 ? void 0 : _a.subarray(0, 1).toString();
178+
if ((0, protocol_1.hasCommandLength)(dataType)) {
179+
const commandLength = (0, protocol_1.parseCommandLength)(this.buffer);
180+
const hasReceivedEntireCommand = this.buffer.length - this.buffer.indexOf(' ') - 1 >= commandLength ? true : false;
181+
if (hasReceivedEntireCommand) {
182+
if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.verbose) {
183+
let bufferString = this.buffer.toString('utf8');
184+
if (bufferString.length > 1000) {
185+
bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40);
186+
}
187+
const elapsedMs = new Date().getTime() - this.startedOn.getTime();
188+
console.debug(`<- ${bufferString} (${bufferString.length} bytes, ${elapsedMs}ms)`);
189+
}
190+
// need to decompress this buffer before decoding?
191+
if (dataType === protocol_1.CMD_COMPRESSED) {
192+
const decompressResults = (0, protocol_1.decompressBuffer)(this.buffer);
193+
if (decompressResults.dataType === protocol_1.CMD_ROWSET_CHUNK) {
194+
this.pendingChunks.push(decompressResults.buffer);
195+
this.buffer = decompressResults.remainingBuffer;
196+
this.processCommandsData(buffer_1.Buffer.alloc(0));
197+
return;
198+
}
199+
else {
200+
const { data } = (0, protocol_1.popData)(decompressResults.buffer);
201+
(_c = this.processCommandsFinish) === null || _c === void 0 ? void 0 : _c.call(this, null, data);
202+
}
203+
}
204+
else {
205+
if (dataType !== protocol_1.CMD_ROWSET_CHUNK) {
206+
const { data } = (0, protocol_1.popData)(this.buffer);
207+
(_d = this.processCommandsFinish) === null || _d === void 0 ? void 0 : _d.call(this, null, data);
208+
}
209+
else {
210+
const completeChunk = (0, protocol_1.bufferEndsWith)(this.buffer, protocol_1.ROWSET_CHUNKS_END);
211+
if (completeChunk) {
212+
const parsedData = (0, protocol_1.parseRowsetChunks)([...this.pendingChunks, this.buffer]);
213+
(_e = this.processCommandsFinish) === null || _e === void 0 ? void 0 : _e.call(this, null, parsedData);
214+
}
215+
}
216+
}
217+
}
218+
}
219+
else {
220+
// command with no explicit len so make sure that the final character is a space
221+
const lastChar = this.buffer.subarray(this.buffer.length - 1, this.buffer.length).toString('utf8');
222+
if (lastChar == ' ') {
223+
const { data } = (0, protocol_1.popData)(this.buffer);
224+
(_f = this.processCommandsFinish) === null || _f === void 0 ? void 0 : _f.call(this, null, data);
225+
}
226+
}
227+
}
228+
catch (error) {
229+
console.error(`processCommandsData - error: ${error}`);
230+
console.assert(error instanceof Error, 'An error occoured while processing data');
231+
if (error instanceof Error) {
232+
(_g = this.processCommandsFinish) === null || _g === void 0 ? void 0 : _g.call(this, error);
233+
}
234+
}
235+
}
236+
/** Completes a transaction initiated by processCommands */
237+
processCommandsFinish(error, result) {
238+
if (error) {
239+
if (this.processCallback) {
240+
console.error('processCommandsFinish - error', error);
241+
}
242+
else {
243+
console.warn('processCommandsFinish - error with no registered callback', error);
244+
}
245+
}
246+
if (this.processCallback) {
247+
this.processCallback(error, result);
248+
}
249+
this.buffer = buffer_1.Buffer.alloc(0);
250+
this.pendingChunks = [];
251+
}
252+
/** Disconnect immediately, release connection, no events. */
253+
close() {
254+
if (this.socket) {
255+
this.socket.removeAllListeners();
256+
this.socket.destroy();
257+
this.socket = undefined;
258+
}
259+
this.operations.clear();
260+
return this;
261+
}
262+
}
263+
exports.SQLiteCloudTlsConnection = SQLiteCloudTlsConnection;
264+
exports.default = SQLiteCloudTlsConnection;

lib/drivers/connection-ws.d.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket
3+
*/
4+
import { SQLiteCloudConnection } from './connection';
5+
import { ErrorCallback, ResultsCallback, SQLiteCloudCommand, SQLiteCloudConfig } from './types';
6+
/**
7+
* Implementation of TransportConnection that connects to the database indirectly
8+
* via SQLite Cloud Gateway, a socket.io based deamon that responds to sql query
9+
* requests by returning results and rowsets in json format. The gateway handles
10+
* connect, disconnect, retries, order of operations, timeouts, etc.
11+
*/
12+
export declare class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection {
13+
/** Socket.io used to communicated with SQLiteCloud server */
14+
private socket?;
15+
/** True if connection is open */
16+
get connected(): boolean;
17+
connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
18+
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
19+
transportCommands(commands: string | SQLiteCloudCommand, callback?: ResultsCallback): this;
20+
/** Disconnect socket.io from server */
21+
close(): this;
22+
}
23+
export default SQLiteCloudWebsocketConnection;

0 commit comments

Comments
 (0)