node-firebird 1.1.9 → 2.0.0
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/.github/workflows/node.js.yml +45 -10
- package/ENCRYPTION_CALLBACK.md +152 -0
- package/PR_SUMMARY.md +139 -0
- package/README.md +80 -17
- package/Roadmap.md +80 -0
- package/lib/index.d.ts +16 -2
- package/lib/index.js +1 -1
- package/lib/pool.js +83 -82
- package/lib/srp.js +3 -0
- package/lib/wire/connection.js +1639 -1295
- package/lib/wire/const.js +16 -10
- package/lib/wire/database.js +224 -118
- package/lib/wire/eventConnection.js +94 -92
- package/lib/wire/fbEventManager.js +107 -72
- package/lib/wire/serialize.js +434 -408
- package/lib/wire/service.js +935 -931
- package/lib/wire/socket.js +175 -0
- package/lib/wire/statement.js +32 -31
- package/lib/wire/transaction.js +135 -107
- package/lib/wire/xsqlvar.js +339 -330
- package/package.json +5 -5
- package/srp.js +94 -0
- package/vitest.config.js +13 -0
- package/.travis.yml +0 -23
|
@@ -3,111 +3,113 @@ const { XdrReader } = require('./serialize');
|
|
|
3
3
|
const DEFAULT_ENCODING = 'utf8';
|
|
4
4
|
const Const = require('./const');
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
class EventConnection {
|
|
7
|
+
constructor(host, port, callback, db) {
|
|
8
|
+
var self = this;
|
|
9
|
+
this.db = db;
|
|
10
|
+
this.emgr = null;
|
|
11
|
+
this._isClosed = false;
|
|
12
|
+
this._isOpened = false;
|
|
13
|
+
this._socket = net.createConnection(port, host);
|
|
14
|
+
this._bind_events(host, port, callback);
|
|
15
|
+
this.error;
|
|
16
|
+
this.eventcallback;
|
|
17
|
+
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
_bind_events(host, port, callback) {
|
|
20
|
+
var self = this;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
self._socket.on('close', function () {
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
self._isClosed = true;
|
|
25
|
+
})
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
self._socket.on('error', function (e) {
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
self.error = e;
|
|
30
|
+
})
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
self._socket.on('connect', function () {
|
|
33
|
+
self._isClosed = false;
|
|
34
|
+
self._isOpened = true;
|
|
35
|
+
if (callback)
|
|
36
|
+
callback();
|
|
37
|
+
});
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
self._socket.on('data', function (data) {
|
|
40
|
+
var xdr, buf;
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
if (!self._xdr) {
|
|
43
|
+
xdr = new XdrReader(data);
|
|
44
|
+
} else {
|
|
45
|
+
xdr = self._xdr;
|
|
46
|
+
delete (self._xdr);
|
|
47
|
+
buf = Buffer.from(data.length + xdr.buffer.length);
|
|
48
|
+
xdr.buffer.copy(buf);
|
|
49
|
+
data.copy(buf, xdr.buffer.length);
|
|
50
|
+
xdr.buffer = buf;
|
|
51
|
+
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
try {
|
|
54
|
+
var item, op;
|
|
55
|
+
var op_pos = xdr.pos;
|
|
56
|
+
var tmp_event;
|
|
57
|
+
while (xdr.pos < xdr.buffer.length) {
|
|
58
|
+
do {
|
|
59
|
+
var r = xdr.readInt();
|
|
60
|
+
} while (r === Const.op_dummy);
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
62
|
+
switch (r) {
|
|
63
|
+
case Const.op_event:
|
|
64
|
+
xdr.readInt(); // db handle
|
|
65
|
+
var buf = xdr.readArray();
|
|
66
|
+
// first byte is always set to 1
|
|
67
|
+
tmp_event = {};
|
|
68
|
+
var lst_event = [];
|
|
69
|
+
var eventname = '';
|
|
70
|
+
var eventcount = 0;
|
|
71
|
+
var pos = 1;
|
|
72
|
+
while (pos < buf.length) {
|
|
73
|
+
var len = buf.readInt8(pos++);
|
|
74
|
+
eventname = buf.toString(DEFAULT_ENCODING, pos, pos + len);
|
|
75
|
+
var prevcount = self.emgr.events[eventname] || 0;
|
|
76
|
+
pos += len;
|
|
77
|
+
eventcount = buf.readInt32LE(pos);
|
|
78
|
+
tmp_event[eventname] = eventcount;
|
|
79
|
+
pos += 4;
|
|
80
|
+
if (prevcount !== eventcount)
|
|
81
|
+
lst_event.push({ name: eventname, count: eventcount });
|
|
82
|
+
}
|
|
83
|
+
xdr.readInt64(); // ignore AST INFO
|
|
84
|
+
var event_id = xdr.readInt();
|
|
85
|
+
// set the new count in global event hash
|
|
86
|
+
for (var evt in tmp_event) {
|
|
87
|
+
self.emgr.events[evt] = tmp_event[evt];
|
|
88
|
+
}
|
|
89
|
+
if (self.eventcallback)
|
|
90
|
+
return self.eventcallback(null, { eventid: event_id, events: lst_event });
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
default:
|
|
93
|
+
return cb(new Error('Unexpected:' + r));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (err instanceof RangeError) { // incomplete packet case
|
|
98
|
+
xdr.buffer = xdr.buffer = xdr.buffer.slice(op_pos);
|
|
99
|
+
xdr.pos = 0;
|
|
100
|
+
self._xdr = xdr;
|
|
93
101
|
}
|
|
94
102
|
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
xdr.buffer = xdr.buffer = xdr.buffer.slice(op_pos);
|
|
98
|
-
xdr.pos = 0;
|
|
99
|
-
self._xdr = xdr;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
}
|
|
103
|
+
})
|
|
104
|
+
}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
106
|
+
throwClosed(callback) {
|
|
107
|
+
var err = new Error('Event Connection is closed.');
|
|
108
|
+
this.db.emit('error', err);
|
|
109
|
+
if (callback)
|
|
110
|
+
callback(err);
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
112
114
|
|
|
113
115
|
module.exports = EventConnection;
|
|
@@ -1,98 +1,133 @@
|
|
|
1
1
|
const Events = require('events');
|
|
2
2
|
const { doError } = require('../callback');
|
|
3
3
|
|
|
4
|
+
class FbEventManager extends Events.EventEmitter {
|
|
5
|
+
constructor(db, eventconnection, eventid, callback) {
|
|
6
|
+
super();
|
|
7
|
+
this.db = db;
|
|
8
|
+
this.eventconnection = eventconnection;
|
|
9
|
+
this.events = {};
|
|
10
|
+
this.eventid = eventid;
|
|
11
|
+
this._createEventLoop(callback);
|
|
12
|
+
}
|
|
4
13
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
_createEventLoop(callback) {
|
|
15
|
+
var self = this;
|
|
16
|
+
var cnx = this.db.connection;
|
|
17
|
+
this.eventconnection.emgr = this;
|
|
18
|
+
console.log('[EventManager] Creating event loop, eventid:', this.eventid);
|
|
19
|
+
// create the loop
|
|
20
|
+
function loop(first) {
|
|
21
|
+
console.log('[EventManager] Calling queEvents, first:', first, 'events:', Object.keys(self.events));
|
|
22
|
+
cnx.queEvents(self.events, self.eventid, function (err, ret) {
|
|
23
|
+
console.log('[EventManager] queEvents callback, err:', err, 'ret:', ret, 'first:', first);
|
|
24
|
+
if (err) {
|
|
25
|
+
console.log('[EventManager] queEvents error:', err);
|
|
26
|
+
doError(err, callback);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (first) {
|
|
30
|
+
console.log('[EventManager] First loop complete, calling callback');
|
|
31
|
+
callback(null);
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
}
|
|
12
35
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
FbEventManager.prototype._createEventLoop = function (callback) {
|
|
21
|
-
var self = this;
|
|
22
|
-
var cnx = this.db.connection;
|
|
23
|
-
this.eventconnection.emgr = this;
|
|
24
|
-
// create the loop
|
|
25
|
-
function loop(first) {
|
|
26
|
-
cnx.queEvents(self.events, self.eventid, function (err, ret) {
|
|
27
|
-
if (err) {
|
|
28
|
-
doError(err, callback);
|
|
36
|
+
this.eventconnection.eventcallback = function (err, ret) {
|
|
37
|
+
console.log('[EventManager] eventcallback invoked, err:', err, 'eventid match:', self.eventid === ret?.eventid);
|
|
38
|
+
if (err || (self.eventid !== ret.eventid)) {
|
|
39
|
+
doError(err || new Error('Bad eventid'), callback);
|
|
29
40
|
return;
|
|
30
41
|
}
|
|
31
|
-
if (first)
|
|
32
|
-
callback();
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
43
|
+
ret.events.forEach(function (event) {
|
|
44
|
+
self.emit('post_event', event.name, event.count)
|
|
45
|
+
})
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})
|
|
47
|
+
loop(false);
|
|
48
|
+
}
|
|
45
49
|
|
|
46
|
-
loop(
|
|
50
|
+
loop(true);
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
_changeEvent(callback) {
|
|
54
|
+
var self = this;
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
console.log('[EventManager] _changeEvent called, eventid:', this.eventid, 'events:', Object.keys(self.events));
|
|
57
|
+
// Temporarily suppress the event loop to prevent stale op_event
|
|
58
|
+
// notifications from pushing spurious queEvents onto the main
|
|
59
|
+
// connection queue while closeEvents + queEvents are in flight
|
|
60
|
+
var savedCallback = self.eventconnection.eventcallback;
|
|
61
|
+
self.eventconnection.eventcallback = null;
|
|
62
|
+
console.log('[EventManager] Suppressed event callback, calling closeEvents');
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
self.db.connection.closeEvents(this.eventid, function (err) {
|
|
65
|
+
console.log('[EventManager] closeEvents callback, err:', err);
|
|
66
|
+
if (err) {
|
|
67
|
+
self.eventconnection.eventcallback = savedCallback;
|
|
68
|
+
doError(err, callback);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log('[EventManager] closeEvents success, calling queEvents');
|
|
73
|
+
self.db.connection.queEvents(self.events, self.eventid, function (err, ret) {
|
|
74
|
+
console.log('[EventManager] queEvents callback in _changeEvent, err:', err, 'ret:', ret);
|
|
75
|
+
// Restore the event loop now that our queEvents is safely queued
|
|
76
|
+
self.eventconnection.eventcallback = savedCallback;
|
|
77
|
+
console.log('[EventManager] Restored event callback');
|
|
78
|
+
if (err) {
|
|
79
|
+
console.log('[EventManager] queEvents error in _changeEvent:', err);
|
|
80
|
+
doError(err, callback);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log('[EventManager] _changeEvent complete, calling final callback');
|
|
84
|
+
callback(null, ret);
|
|
85
|
+
});
|
|
86
|
+
})
|
|
87
|
+
}
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
|
|
89
|
+
registerEvent(events, callback) {
|
|
90
|
+
var self = this;
|
|
67
91
|
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
console.log('[EventManager] registerEvent called with events:', events);
|
|
93
|
+
console.log('[EventManager] Connection closed?', self.db.connection._isClosed, 'Event connection closed?', self.eventconnection._isClosed);
|
|
94
|
+
|
|
95
|
+
if (self.db.connection._isClosed || self.eventconnection._isClosed)
|
|
96
|
+
return self.eventconnection.throwClosed(callback);
|
|
70
97
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
events.forEach((event) => self.events[event] = self.events[event] || 0);
|
|
99
|
+
console.log('[EventManager] Events registered, current events:', Object.keys(self.events));
|
|
100
|
+
self._changeEvent(callback);
|
|
101
|
+
}
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
|
|
103
|
+
unregisterEvent(events, callback) {
|
|
104
|
+
var self = this;
|
|
77
105
|
|
|
78
|
-
|
|
79
|
-
|
|
106
|
+
if (self.db.connection._isClosed || self.eventconnection._isClosed)
|
|
107
|
+
return self.eventconnection.throwClosed(callback);
|
|
80
108
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
109
|
+
events.forEach(function (event) { delete self.events[event] });
|
|
110
|
+
self._changeEvent(callback);
|
|
111
|
+
}
|
|
84
112
|
|
|
85
|
-
|
|
86
|
-
|
|
113
|
+
close(callback) {
|
|
114
|
+
var self = this;
|
|
87
115
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
116
|
+
// Prevent the event loop from re-queuing on stale op_event notifications
|
|
117
|
+
// that may arrive between closeEvents and socket.end()
|
|
118
|
+
self.eventconnection.eventcallback = null;
|
|
119
|
+
|
|
120
|
+
self.db.connection.closeEvents(this.eventid, function (err) {
|
|
121
|
+
if (err) {
|
|
122
|
+
doError(err, callback);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
93
125
|
|
|
94
|
-
|
|
95
|
-
|
|
126
|
+
self.eventconnection._socket.end();
|
|
127
|
+
if (callback)
|
|
128
|
+
callback();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
96
131
|
}
|
|
97
132
|
|
|
98
133
|
module.exports = FbEventManager;
|