@sqlitecloud/drivers 0.0.40 → 0.0.50
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/lib/{transport-tls.d.ts → drivers/connection-tls.d.ts} +7 -7
- package/lib/drivers/connection-tls.js +236 -0
- package/lib/{transport-ws.d.ts → drivers/connection-ws.d.ts} +5 -6
- package/lib/{transport-ws.js → drivers/connection-ws.js} +10 -7
- package/lib/drivers/connection.d.ts +32 -0
- package/lib/drivers/connection.js +73 -0
- package/lib/{database.js → drivers/database.js} +68 -19
- package/lib/drivers/protocol.d.ts +51 -0
- package/lib/drivers/protocol.js +291 -0
- package/lib/drivers/queue.d.ts +12 -0
- package/lib/drivers/queue.js +42 -0
- package/lib/{types.d.ts → drivers/types.d.ts} +2 -0
- package/lib/{utilities.d.ts → drivers/utilities.d.ts} +6 -0
- package/lib/{utilities.js → drivers/utilities.js} +51 -1
- package/lib/index.d.ts +6 -8
- package/lib/index.js +13 -13
- package/lib/sqlitecloud.drivers.dev.js +629 -0
- package/lib/sqlitecloud.drivers.js +1 -0
- package/package.json +12 -3
- package/lib/connection.d.ts +0 -59
- package/lib/connection.js +0 -230
- package/lib/sqlitecloud.v0.0.40.dev.js +0 -597
- package/lib/sqlitecloud.v0.0.40.js +0 -1
- package/lib/transport-tls.js +0 -465
- /package/lib/{database.d.ts → drivers/database.d.ts} +0 -0
- /package/lib/{rowset.d.ts → drivers/rowset.d.ts} +0 -0
- /package/lib/{rowset.js → drivers/rowset.js} +0 -0
- /package/lib/{statement.d.ts → drivers/statement.d.ts} +0 -0
- /package/lib/{statement.js → drivers/statement.js} +0 -0
- /package/lib/{types.js → drivers/types.js} +0 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* connection-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol
|
|
3
3
|
*/
|
|
4
4
|
import { SQLiteCloudConfig, ErrorCallback, ResultsCallback } from './types';
|
|
5
|
-
import {
|
|
5
|
+
import { SQLiteCloudConnection } from './connection';
|
|
6
6
|
/**
|
|
7
7
|
* Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol.
|
|
8
|
+
* Connects with plain socket with no encryption is the ?insecure=1 parameter is specified.
|
|
8
9
|
* SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc.
|
|
9
10
|
* A connection socket is established when the connection is created and closed when the connection is closed.
|
|
10
11
|
* All operations are serialized by waiting for any pending operations to complete. Once a connection is closed,
|
|
11
12
|
* it cannot be reopened and you must create a new connection.
|
|
12
13
|
*/
|
|
13
|
-
export declare class
|
|
14
|
-
/** Configuration passed to connect */
|
|
15
|
-
private config?;
|
|
14
|
+
export declare class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
|
|
16
15
|
/** Currently opened tls socket used to communicated with SQLiteCloud server */
|
|
17
16
|
private socket?;
|
|
18
17
|
/** True if connection is open */
|
|
19
18
|
get connected(): boolean;
|
|
20
|
-
|
|
19
|
+
connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
|
|
21
20
|
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
|
|
22
|
-
|
|
21
|
+
transportCommands(commands: string, callback?: ResultsCallback): this;
|
|
23
22
|
/** Disconnect from server, release connection. */
|
|
24
23
|
close(): this;
|
|
25
24
|
}
|
|
25
|
+
export default SQLiteCloudTlsConnection;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* connection-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SQLiteCloudTlsConnection = void 0;
|
|
10
|
+
const types_1 = require("./types");
|
|
11
|
+
const connection_1 = require("./connection");
|
|
12
|
+
const protocol_1 = require("./protocol");
|
|
13
|
+
const utilities_1 = require("./utilities");
|
|
14
|
+
const protocol_2 = require("./protocol");
|
|
15
|
+
const net_1 = __importDefault(require("net"));
|
|
16
|
+
const tls_1 = __importDefault(require("tls"));
|
|
17
|
+
/**
|
|
18
|
+
* Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol.
|
|
19
|
+
* Connects with plain socket with no encryption is the ?insecure=1 parameter is specified.
|
|
20
|
+
* SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc.
|
|
21
|
+
* A connection socket is established when the connection is created and closed when the connection is closed.
|
|
22
|
+
* All operations are serialized by waiting for any pending operations to complete. Once a connection is closed,
|
|
23
|
+
* it cannot be reopened and you must create a new connection.
|
|
24
|
+
*/
|
|
25
|
+
class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
|
|
26
|
+
/** True if connection is open */
|
|
27
|
+
get connected() {
|
|
28
|
+
return !!this.socket;
|
|
29
|
+
}
|
|
30
|
+
/* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
|
|
31
|
+
connectTransport(config, callback) {
|
|
32
|
+
// connection established while we were waiting in line?
|
|
33
|
+
console.assert(!this.connected, 'Connection already established');
|
|
34
|
+
// clear all listeners and call done in the operations queue
|
|
35
|
+
const finish = error => {
|
|
36
|
+
if (this.socket) {
|
|
37
|
+
this.socket.removeAllListeners('data');
|
|
38
|
+
this.socket.removeAllListeners('error');
|
|
39
|
+
this.socket.removeAllListeners('close');
|
|
40
|
+
if (error) {
|
|
41
|
+
this.close();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error);
|
|
45
|
+
};
|
|
46
|
+
this.config = config;
|
|
47
|
+
const initializationCommands = (0, utilities_1.getInitializationCommands)(config);
|
|
48
|
+
if (config.insecure) {
|
|
49
|
+
// connect to plain socket, without encryption, only if insecure parameter specified
|
|
50
|
+
// this option is mainly for testing purposes and is not available on production nodes
|
|
51
|
+
// which would need to connect using tls and proper certificates as per code below
|
|
52
|
+
const connectionOptions = {
|
|
53
|
+
host: config.host,
|
|
54
|
+
port: config.port
|
|
55
|
+
};
|
|
56
|
+
this.socket = net_1.default.connect(connectionOptions, () => {
|
|
57
|
+
console.warn(`TlsConnection.connectTransport - connected to ${config.host}:${config.port} using insecure protocol`);
|
|
58
|
+
// send initialization commands
|
|
59
|
+
console.assert(this.socket, 'Connection already closed');
|
|
60
|
+
this.transportCommands(initializationCommands, error => {
|
|
61
|
+
if (error && this.socket) {
|
|
62
|
+
this.close();
|
|
63
|
+
}
|
|
64
|
+
if (callback) {
|
|
65
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error);
|
|
66
|
+
callback = undefined;
|
|
67
|
+
}
|
|
68
|
+
finish(error);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// connect to tls socket, initialize connection, setup event handlers
|
|
74
|
+
this.socket = tls_1.default.connect(this.config.port, this.config.host, this.config.tlsOptions, () => {
|
|
75
|
+
const tlsSocket = this.socket;
|
|
76
|
+
if (!(tlsSocket === null || tlsSocket === void 0 ? void 0 : tlsSocket.authorized)) {
|
|
77
|
+
const anonimizedError = (0, utilities_1.anonimizeError)(tlsSocket.authorizationError);
|
|
78
|
+
console.error('Connection was not authorized', anonimizedError);
|
|
79
|
+
this.close();
|
|
80
|
+
finish(new types_1.SQLiteCloudError('Connection was not authorized', { cause: anonimizedError }));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// the connection was closed before it was even opened,
|
|
84
|
+
// eg. client closed the connection before the server accepted it
|
|
85
|
+
if (this.socket === null) {
|
|
86
|
+
finish(new types_1.SQLiteCloudError('Connection was closed before it was done opening'));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// send initialization commands
|
|
90
|
+
console.assert(this.socket, 'Connection already closed');
|
|
91
|
+
this.transportCommands(initializationCommands, error => {
|
|
92
|
+
if (error && this.socket) {
|
|
93
|
+
this.close();
|
|
94
|
+
}
|
|
95
|
+
if (callback) {
|
|
96
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error);
|
|
97
|
+
callback = undefined;
|
|
98
|
+
}
|
|
99
|
+
finish(error);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
this.socket.on('close', () => {
|
|
105
|
+
this.socket = null;
|
|
106
|
+
finish(new types_1.SQLiteCloudError('Connection was closed'));
|
|
107
|
+
});
|
|
108
|
+
this.socket.once('error', (error) => {
|
|
109
|
+
console.error('Connection error', error);
|
|
110
|
+
finish(new types_1.SQLiteCloudError('Connection error', { cause: error }));
|
|
111
|
+
});
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
|
|
115
|
+
transportCommands(commands, callback) {
|
|
116
|
+
var _a, _b, _c;
|
|
117
|
+
// connection needs to be established?
|
|
118
|
+
if (!this.socket) {
|
|
119
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
// compose commands following SCPC protocol
|
|
123
|
+
commands = (0, protocol_1.formatCommand)(commands);
|
|
124
|
+
let buffer = Buffer.alloc(0);
|
|
125
|
+
const rowsetChunks = [];
|
|
126
|
+
// const startedOn = new Date()
|
|
127
|
+
// define what to do if an answer does not arrive within the set timeout
|
|
128
|
+
let socketTimeout;
|
|
129
|
+
// clear all listeners and call done in the operations queue
|
|
130
|
+
const finish = (error, result) => {
|
|
131
|
+
clearTimeout(socketTimeout);
|
|
132
|
+
if (this.socket) {
|
|
133
|
+
this.socket.removeAllListeners('data');
|
|
134
|
+
this.socket.removeAllListeners('error');
|
|
135
|
+
this.socket.removeAllListeners('close');
|
|
136
|
+
}
|
|
137
|
+
if (callback) {
|
|
138
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);
|
|
139
|
+
callback = undefined;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
// define the Promise that waits for the server response
|
|
143
|
+
const readData = (data) => {
|
|
144
|
+
var _a, _b;
|
|
145
|
+
try {
|
|
146
|
+
// on first ondata event, dataType is read from data, on subsequent ondata event, is read from buffer that is the concatanations of data received on each ondata event
|
|
147
|
+
let dataType = buffer.length === 0 ? data.subarray(0, 1).toString() : buffer.subarray(0, 1).toString('utf8');
|
|
148
|
+
buffer = Buffer.concat([buffer, data]);
|
|
149
|
+
const commandLength = (0, protocol_1.hasCommandLength)(dataType);
|
|
150
|
+
if (commandLength) {
|
|
151
|
+
const commandLength = (0, protocol_1.parseCommandLength)(buffer);
|
|
152
|
+
const hasReceivedEntireCommand = buffer.length - buffer.indexOf(' ') - 1 >= commandLength ? true : false;
|
|
153
|
+
if (hasReceivedEntireCommand) {
|
|
154
|
+
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.verbose) {
|
|
155
|
+
let bufferString = buffer.toString('utf8');
|
|
156
|
+
if (bufferString.length > 1000) {
|
|
157
|
+
bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40);
|
|
158
|
+
}
|
|
159
|
+
// const elapsedMs = new Date().getTime() - startedOn.getTime()
|
|
160
|
+
// console.debug(`Receive: ${bufferString} - ${elapsedMs}ms`)
|
|
161
|
+
}
|
|
162
|
+
// need to decompress this buffer before decoding?
|
|
163
|
+
if (dataType === protocol_1.CMD_COMPRESSED) {
|
|
164
|
+
;
|
|
165
|
+
({ buffer, dataType } = (0, protocol_1.decompressBuffer)(buffer));
|
|
166
|
+
}
|
|
167
|
+
if (dataType !== protocol_1.CMD_ROWSET_CHUNK) {
|
|
168
|
+
(_b = this.socket) === null || _b === void 0 ? void 0 : _b.off('data', readData);
|
|
169
|
+
const { data } = (0, protocol_1.popData)(buffer);
|
|
170
|
+
finish(null, data);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// check if rowset received the ending chunk
|
|
174
|
+
if ((0, protocol_1.bufferEndsWith)(buffer, protocol_1.ROWSET_CHUNKS_END)) {
|
|
175
|
+
rowsetChunks.push(buffer);
|
|
176
|
+
const parsedData = (0, protocol_2.parseRowsetChunks)(rowsetChunks);
|
|
177
|
+
finish === null || finish === void 0 ? void 0 : finish.call(this, null, parsedData);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// no ending string? ask server for another chunk
|
|
181
|
+
rowsetChunks.push(buffer);
|
|
182
|
+
buffer = Buffer.alloc(0);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// command with no explicit len so make sure that the final character is a space
|
|
189
|
+
const lastChar = buffer.subarray(buffer.length - 1, buffer.length).toString('utf8');
|
|
190
|
+
if (lastChar == ' ') {
|
|
191
|
+
const { data } = (0, protocol_1.popData)(buffer);
|
|
192
|
+
finish(null, data);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.assert(error instanceof Error);
|
|
198
|
+
if (error instanceof Error) {
|
|
199
|
+
finish(error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.once('close', () => {
|
|
204
|
+
finish(new types_1.SQLiteCloudError('Connection was closed', { cause: (0, utilities_1.anonimizeCommand)(commands) }));
|
|
205
|
+
});
|
|
206
|
+
(_b = this.socket) === null || _b === void 0 ? void 0 : _b.write(commands, 'utf8', () => {
|
|
207
|
+
var _a, _b;
|
|
208
|
+
// @ts-ignore
|
|
209
|
+
socketTimeout = setTimeout(() => {
|
|
210
|
+
const timeoutError = new types_1.SQLiteCloudError('Request timed out', { cause: (0, utilities_1.anonimizeCommand)(commands) });
|
|
211
|
+
// console.debug(`Request timed out, config.timeout is ${this.config?.timeout as number}ms`, timeoutError)
|
|
212
|
+
finish(timeoutError);
|
|
213
|
+
}, (_a = this.config) === null || _a === void 0 ? void 0 : _a.timeout);
|
|
214
|
+
(_b = this.socket) === null || _b === void 0 ? void 0 : _b.on('data', readData);
|
|
215
|
+
});
|
|
216
|
+
(_c = this.socket) === null || _c === void 0 ? void 0 : _c.once('error', (error) => {
|
|
217
|
+
console.error('Socket error', error);
|
|
218
|
+
this.close();
|
|
219
|
+
finish(new types_1.SQLiteCloudError('Socket error', { cause: (0, utilities_1.anonimizeError)(error) }));
|
|
220
|
+
});
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
/** Disconnect from server, release connection. */
|
|
224
|
+
close() {
|
|
225
|
+
console.assert(this.socket !== null, 'TlsConnection.close - connection already closed');
|
|
226
|
+
this.operations.clear();
|
|
227
|
+
if (this.socket) {
|
|
228
|
+
this.socket.destroy();
|
|
229
|
+
this.socket = null;
|
|
230
|
+
}
|
|
231
|
+
this.socket = undefined;
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
exports.SQLiteCloudTlsConnection = SQLiteCloudTlsConnection;
|
|
236
|
+
exports.default = SQLiteCloudTlsConnection;
|
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
* transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket
|
|
3
3
|
*/
|
|
4
4
|
import { SQLiteCloudConfig, ErrorCallback, ResultsCallback } from './types';
|
|
5
|
-
import {
|
|
5
|
+
import { SQLiteCloudConnection } from './connection';
|
|
6
6
|
/**
|
|
7
7
|
* Implementation of TransportConnection that connects to the database indirectly
|
|
8
8
|
* via SQLite Cloud Gateway, a socket.io based deamon that responds to sql query
|
|
9
9
|
* requests by returning results and rowsets in json format. The gateway handles
|
|
10
10
|
* connect, disconnect, retries, order of operations, timeouts, etc.
|
|
11
11
|
*/
|
|
12
|
-
export declare class
|
|
13
|
-
/** Configuration passed to connect */
|
|
14
|
-
private config?;
|
|
12
|
+
export declare class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection {
|
|
15
13
|
/** Socket.io used to communicated with SQLiteCloud server */
|
|
16
14
|
private socket?;
|
|
17
15
|
/** True if connection is open */
|
|
18
16
|
get connected(): boolean;
|
|
19
|
-
|
|
17
|
+
connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
|
|
20
18
|
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
|
|
21
|
-
|
|
19
|
+
transportCommands(commands: string, callback?: ResultsCallback): this;
|
|
22
20
|
/** Disconnect socket.io from server */
|
|
23
21
|
close(): this;
|
|
24
22
|
}
|
|
23
|
+
export default SQLiteCloudWebsocketConnection;
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.SQLiteCloudWebsocketConnection = void 0;
|
|
7
7
|
const types_1 = require("./types");
|
|
8
8
|
const rowset_1 = require("./rowset");
|
|
9
|
+
const connection_1 = require("./connection");
|
|
9
10
|
const socket_io_client_1 = require("socket.io-client");
|
|
10
11
|
/**
|
|
11
12
|
* Implementation of TransportConnection that connects to the database indirectly
|
|
@@ -13,13 +14,13 @@ const socket_io_client_1 = require("socket.io-client");
|
|
|
13
14
|
* requests by returning results and rowsets in json format. The gateway handles
|
|
14
15
|
* connect, disconnect, retries, order of operations, timeouts, etc.
|
|
15
16
|
*/
|
|
16
|
-
class
|
|
17
|
+
class SQLiteCloudWebsocketConnection extends connection_1.SQLiteCloudConnection {
|
|
17
18
|
/** True if connection is open */
|
|
18
19
|
get connected() {
|
|
19
20
|
return !!this.socket;
|
|
20
21
|
}
|
|
21
22
|
/* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
|
|
22
|
-
|
|
23
|
+
connectTransport(config, callback) {
|
|
23
24
|
var _a;
|
|
24
25
|
try {
|
|
25
26
|
// connection established while we were waiting in line?
|
|
@@ -38,7 +39,7 @@ class WebSocketTransport {
|
|
|
38
39
|
return this;
|
|
39
40
|
}
|
|
40
41
|
/** Will send a command immediately (no queueing), return the rowset/result or throw an error */
|
|
41
|
-
|
|
42
|
+
transportCommands(commands, callback) {
|
|
42
43
|
// connection needs to be established?
|
|
43
44
|
if (!this.socket) {
|
|
44
45
|
callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));
|
|
@@ -53,7 +54,7 @@ class WebSocketTransport {
|
|
|
53
54
|
const { data, metadata } = response;
|
|
54
55
|
if (data && metadata) {
|
|
55
56
|
if (metadata.numberOfRows !== undefined && metadata.numberOfColumns !== undefined && metadata.columns !== undefined) {
|
|
56
|
-
console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.
|
|
57
|
+
console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.transportCommands - data is not an array');
|
|
57
58
|
// we can recreate a SQLiteCloudRowset from the response which we know to be an array of arrays
|
|
58
59
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
59
60
|
const rowset = new rowset_1.SQLiteCloudRowset(metadata, data.flat());
|
|
@@ -69,13 +70,15 @@ class WebSocketTransport {
|
|
|
69
70
|
/** Disconnect socket.io from server */
|
|
70
71
|
close() {
|
|
71
72
|
var _a;
|
|
72
|
-
console.assert(this.socket !== null, '
|
|
73
|
+
console.assert(this.socket !== null, 'SQLiteCloudWebsocketConnection.close - connection already closed');
|
|
73
74
|
if (this.socket) {
|
|
74
75
|
(_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();
|
|
75
76
|
this.socket = undefined;
|
|
76
77
|
}
|
|
78
|
+
this.operations.clear();
|
|
77
79
|
this.socket = undefined;
|
|
78
80
|
return this;
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
|
-
exports.
|
|
83
|
+
exports.SQLiteCloudWebsocketConnection = SQLiteCloudWebsocketConnection;
|
|
84
|
+
exports.default = SQLiteCloudWebsocketConnection;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* connection.ts - base abstract class for sqlitecloud server connections
|
|
3
|
+
*/
|
|
4
|
+
import { SQLiteCloudConfig, ErrorCallback, ResultsCallback } from './types';
|
|
5
|
+
import { OperationsQueue } from './queue';
|
|
6
|
+
/**
|
|
7
|
+
* Base class for SQLiteCloudConnection handles basics and defines methods.
|
|
8
|
+
* Actual connection management and communication with the server in concrete classes.
|
|
9
|
+
*/
|
|
10
|
+
export declare abstract class SQLiteCloudConnection {
|
|
11
|
+
/** Parse and validate provided connectionString or configuration */
|
|
12
|
+
constructor(config: SQLiteCloudConfig | string, callback?: ErrorCallback);
|
|
13
|
+
/** Configuration passed by client or extracted from connection string */
|
|
14
|
+
protected config: SQLiteCloudConfig;
|
|
15
|
+
/** Operations are serialized by waiting an any pending promises */
|
|
16
|
+
protected operations: OperationsQueue;
|
|
17
|
+
/** Connect will establish a tls or websocket transport to the server based on configuration and environment */
|
|
18
|
+
protected connect(callback?: ErrorCallback): this;
|
|
19
|
+
protected abstract connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
|
|
20
|
+
/** Send a command, return the rowset/result or throw an error */
|
|
21
|
+
protected abstract transportCommands(commands: string, callback?: ResultsCallback): this;
|
|
22
|
+
/** Will log to console if verbose mode is enabled */
|
|
23
|
+
protected log(message: string, ...optionalParams: any[]): void;
|
|
24
|
+
/** Returns true if connection is open */
|
|
25
|
+
abstract get connected(): boolean;
|
|
26
|
+
/** Enable verbose logging for debug purposes */
|
|
27
|
+
verbose(): void;
|
|
28
|
+
/** Will enquee a command to be executed and callback with the resulting rowset/result/error */
|
|
29
|
+
sendCommands(commands: string, callback?: ResultsCallback): this;
|
|
30
|
+
/** Disconnect from server, release transport. */
|
|
31
|
+
abstract close(): this;
|
|
32
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* connection.ts - base abstract class for sqlitecloud server connections
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SQLiteCloudConnection = void 0;
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
const utilities_1 = require("./utilities");
|
|
9
|
+
const queue_1 = require("./queue");
|
|
10
|
+
const utilities_2 = require("./utilities");
|
|
11
|
+
/**
|
|
12
|
+
* Base class for SQLiteCloudConnection handles basics and defines methods.
|
|
13
|
+
* Actual connection management and communication with the server in concrete classes.
|
|
14
|
+
*/
|
|
15
|
+
class SQLiteCloudConnection {
|
|
16
|
+
/** Parse and validate provided connectionString or configuration */
|
|
17
|
+
constructor(config, callback) {
|
|
18
|
+
/** Operations are serialized by waiting an any pending promises */
|
|
19
|
+
this.operations = new queue_1.OperationsQueue();
|
|
20
|
+
if (typeof config === 'string') {
|
|
21
|
+
this.config = (0, utilities_1.validateConfiguration)({ connectionString: config });
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.config = (0, utilities_1.validateConfiguration)(config);
|
|
25
|
+
}
|
|
26
|
+
// connect transport layer to server
|
|
27
|
+
this.connect(callback);
|
|
28
|
+
}
|
|
29
|
+
//
|
|
30
|
+
// internal methods (some are implemented in concrete classes using different transport layers)
|
|
31
|
+
//
|
|
32
|
+
/** Connect will establish a tls or websocket transport to the server based on configuration and environment */
|
|
33
|
+
connect(callback) {
|
|
34
|
+
this.operations.enqueue(done => {
|
|
35
|
+
this.connectTransport(this.config, error => {
|
|
36
|
+
if (error) {
|
|
37
|
+
console.error(`SQLiteCloudConnection.connect - error connecting ${this.config.host}:${this.config.port} ${error.toString()}`, error);
|
|
38
|
+
this.close();
|
|
39
|
+
}
|
|
40
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error || null);
|
|
41
|
+
done(error);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/** Will log to console if verbose mode is enabled */
|
|
47
|
+
log(message, ...optionalParams) {
|
|
48
|
+
if (this.config.verbose) {
|
|
49
|
+
message = (0, utilities_2.anonimizeCommand)(message);
|
|
50
|
+
console.log(`${new Date().toISOString()} ${this.config.clientId}: ${message}`, ...optionalParams);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Enable verbose logging for debug purposes */
|
|
54
|
+
verbose() {
|
|
55
|
+
this.config.verbose = true;
|
|
56
|
+
}
|
|
57
|
+
/** Will enquee a command to be executed and callback with the resulting rowset/result/error */
|
|
58
|
+
sendCommands(commands, callback) {
|
|
59
|
+
this.operations.enqueue(done => {
|
|
60
|
+
if (!this.connected) {
|
|
61
|
+
const error = new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' });
|
|
62
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error);
|
|
63
|
+
done(error);
|
|
64
|
+
}
|
|
65
|
+
this.transportCommands(commands, (error, result) => {
|
|
66
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);
|
|
67
|
+
done(error);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.SQLiteCloudConnection = SQLiteCloudConnection;
|
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
//
|
|
3
3
|
// database.ts - database driver api, implements and extends sqlite3
|
|
4
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 (mod) {
|
|
22
|
+
if (mod && mod.__esModule) return mod;
|
|
23
|
+
var result = {};
|
|
24
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
25
|
+
__setModuleDefault(result, mod);
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
5
28
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
29
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
30
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -16,18 +39,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
16
39
|
};
|
|
17
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
41
|
exports.Database = void 0;
|
|
19
|
-
// Trying as much as possible to be a drop-in replacement for SQLite3 API
|
|
20
|
-
// https://github.com/TryGhost/node-sqlite3/wiki/API
|
|
21
|
-
// https://github.com/TryGhost/node-sqlite3
|
|
22
|
-
// https://github.com/TryGhost/node-sqlite3/blob/master/lib/sqlite3.d.ts
|
|
23
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
24
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
25
|
-
const connection_1 = require("./connection");
|
|
26
42
|
const rowset_1 = require("./rowset");
|
|
27
43
|
const types_1 = require("./types");
|
|
28
44
|
const utilities_1 = require("./utilities");
|
|
29
45
|
const statement_1 = require("./statement");
|
|
30
46
|
const eventemitter3_1 = __importDefault(require("eventemitter3"));
|
|
47
|
+
const utilities_2 = require("./utilities");
|
|
31
48
|
// Uses eventemitter3 instead of node events for browser compatibility
|
|
32
49
|
// https://github.com/primus/eventemitter3
|
|
33
50
|
/**
|
|
@@ -50,29 +67,61 @@ class Database extends eventemitter3_1.default {
|
|
|
50
67
|
}
|
|
51
68
|
// mode is ignored for now
|
|
52
69
|
// opens first connection to the database automatically
|
|
53
|
-
this.getConnection(
|
|
70
|
+
this.getConnection((error, _connection) => {
|
|
71
|
+
if (callback) {
|
|
72
|
+
callback.call(this, error);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
54
75
|
}
|
|
55
76
|
//
|
|
56
77
|
// private methods
|
|
57
78
|
//
|
|
58
79
|
/** Returns first available connection from connection pool */
|
|
59
80
|
getConnection(callback) {
|
|
60
|
-
var _a;
|
|
81
|
+
var _a, _b, _c;
|
|
61
82
|
// TODO sqlitecloud-js / implement database connection pool #10
|
|
62
83
|
if (((_a = this.connections) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
63
84
|
callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
|
|
64
85
|
}
|
|
65
86
|
else {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
87
|
+
// connect using websocket if tls is not supported or if explicitly requested
|
|
88
|
+
const useWebsocket = utilities_2.isBrowser || ((_b = this.config) === null || _b === void 0 ? void 0 : _b.useWebsocket) || ((_c = this.config) === null || _c === void 0 ? void 0 : _c.gatewayUrl);
|
|
89
|
+
if (useWebsocket) {
|
|
90
|
+
// socket.io transport works in both node.js and browser environments and connects via SQLite Cloud Gateway
|
|
91
|
+
Promise.resolve().then(() => __importStar(require('./connection-ws'))).then(module => {
|
|
92
|
+
this.connections.push(new module.default(this.config, error => {
|
|
93
|
+
if (error) {
|
|
94
|
+
this.handleError(this.connections[0], error, callback);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.assert;
|
|
98
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
|
|
99
|
+
this.emitEvent('open');
|
|
100
|
+
}
|
|
101
|
+
}));
|
|
102
|
+
})
|
|
103
|
+
.catch(error => {
|
|
104
|
+
this.handleError(null, error, callback);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// tls sockets work only in node.js environments
|
|
109
|
+
Promise.resolve().then(() => __importStar(require('./connection-tls'))).then(module => {
|
|
110
|
+
this.connections.push(new module.default(this.config, error => {
|
|
111
|
+
if (error) {
|
|
112
|
+
this.handleError(this.connections[0], error, callback);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.assert;
|
|
116
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
|
|
117
|
+
this.emitEvent('open');
|
|
118
|
+
}
|
|
119
|
+
}));
|
|
120
|
+
})
|
|
121
|
+
.catch(error => {
|
|
122
|
+
this.handleError(null, error, callback);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
76
125
|
}
|
|
77
126
|
}
|
|
78
127
|
/** Handles an error by closing the connection, calling the callback and/or emitting an error event */
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { type SQLCloudRowsetMetadata, type SQLiteCloudDataTypes } from './types';
|
|
3
|
+
import { SQLiteCloudRowset } from './rowset';
|
|
4
|
+
export declare const CMD_STRING = "+";
|
|
5
|
+
export declare const CMD_ZEROSTRING = "!";
|
|
6
|
+
export declare const CMD_ERROR = "-";
|
|
7
|
+
export declare const CMD_INT = ":";
|
|
8
|
+
export declare const CMD_FLOAT = ",";
|
|
9
|
+
export declare const CMD_ROWSET = "*";
|
|
10
|
+
export declare const CMD_ROWSET_CHUNK = "/";
|
|
11
|
+
export declare const CMD_JSON = "#";
|
|
12
|
+
export declare const CMD_NULL = "_";
|
|
13
|
+
export declare const CMD_BLOB = "$";
|
|
14
|
+
export declare const CMD_COMPRESSED = "%";
|
|
15
|
+
export declare const CMD_COMMAND = "^";
|
|
16
|
+
export declare const CMD_ARRAY = "=";
|
|
17
|
+
export declare const ROWSET_CHUNKS_END = "/6 0 0 0 ";
|
|
18
|
+
/** Analyze first character to check if corresponding data type has LEN */
|
|
19
|
+
export declare function hasCommandLength(firstCharacter: string): boolean;
|
|
20
|
+
/** Analyze a command with explict LEN and extract it */
|
|
21
|
+
export declare function parseCommandLength(data: Buffer): number;
|
|
22
|
+
/** Receive a compressed buffer, decompress with lz4, return buffer and datatype */
|
|
23
|
+
export declare function decompressBuffer(buffer: Buffer): {
|
|
24
|
+
buffer: Buffer;
|
|
25
|
+
dataType: string;
|
|
26
|
+
};
|
|
27
|
+
/** Parse error message or extended error message */
|
|
28
|
+
export declare function parseError(buffer: Buffer, spaceIndex: number): never;
|
|
29
|
+
/** Parse an array of items (each of which will be parsed by type separately) */
|
|
30
|
+
export declare function parseArray(buffer: Buffer, spaceIndex: number): SQLiteCloudDataTypes[];
|
|
31
|
+
/** Parse header in a rowset or chunk of a chunked rowset */
|
|
32
|
+
export declare function parseRowsetHeader(buffer: Buffer): {
|
|
33
|
+
index: number;
|
|
34
|
+
metadata: SQLCloudRowsetMetadata;
|
|
35
|
+
fwdBuffer: Buffer;
|
|
36
|
+
};
|
|
37
|
+
export declare function bufferStartsWith(buffer: Buffer, prefix: string): boolean;
|
|
38
|
+
export declare function bufferEndsWith(buffer: Buffer, suffix: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Parse a chunk of a chunked rowset command, eg:
|
|
41
|
+
* *LEN 0:VERS NROWS NCOLS DATA
|
|
42
|
+
* @see https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseRowsetChunks(buffers: Buffer[]): SQLiteCloudRowset;
|
|
45
|
+
/** Parse command, extract its data, return the data and the buffer moved to the first byte after the command */
|
|
46
|
+
export declare function popData(buffer: Buffer): {
|
|
47
|
+
data: SQLiteCloudDataTypes | SQLiteCloudRowset;
|
|
48
|
+
fwdBuffer: Buffer;
|
|
49
|
+
};
|
|
50
|
+
/** Format a command to be sent via SCSP protocol */
|
|
51
|
+
export declare function formatCommand(command: string): string;
|