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.
@@ -3,111 +3,113 @@ const { XdrReader } = require('./serialize');
3
3
  const DEFAULT_ENCODING = 'utf8';
4
4
  const Const = require('./const');
5
5
 
6
- var EventConnection = function (host, port, callback, db) {
7
- var self = this;
8
- this.db = db;
9
- this.emgr = null;
10
- this._isClosed = false;
11
- this._isOpened = false;
12
- this._socket = net.createConnection(port, host);
13
- this._bind_events(host, port, callback);
14
- this.error;
15
- this.eventcallback;
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
- EventConnection.prototype._bind_events = function (host, port, callback) {
19
- var self = this;
19
+ _bind_events(host, port, callback) {
20
+ var self = this;
20
21
 
21
- self._socket.on('close', function () {
22
+ self._socket.on('close', function () {
22
23
 
23
- self._isClosed = true;
24
- })
24
+ self._isClosed = true;
25
+ })
25
26
 
26
- self._socket.on('error', function (e) {
27
+ self._socket.on('error', function (e) {
27
28
 
28
- self.error = e;
29
- })
29
+ self.error = e;
30
+ })
30
31
 
31
- self._socket.on('connect', function () {
32
- self._isClosed = false;
33
- self._isOpened = true;
34
- if (callback)
35
- callback();
36
- });
32
+ self._socket.on('connect', function () {
33
+ self._isClosed = false;
34
+ self._isOpened = true;
35
+ if (callback)
36
+ callback();
37
+ });
37
38
 
38
- self._socket.on('data', function (data) {
39
- var xdr, buf;
39
+ self._socket.on('data', function (data) {
40
+ var xdr, buf;
40
41
 
41
- if (!self._xdr) {
42
- xdr = new XdrReader(data);
43
- } else {
44
- xdr = self._xdr;
45
- delete (self._xdr);
46
- buf = Buffer.from(data.length + xdr.buffer.length);
47
- xdr.buffer.copy(buf);
48
- data.copy(buf, xdr.buffer.length);
49
- xdr.buffer = buf;
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
- try {
53
- var item, op;
54
- var op_pos = xdr.pos;
55
- var tmp_event;
56
- while (xdr.pos < xdr.buffer.length) {
57
- do {
58
- var r = xdr.readInt();
59
- } while (r === Const.op_dummy);
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
- switch (r) {
62
- case Const.op_event:
63
- xdr.readInt(); // db handle
64
- var buf = xdr.readArray();
65
- // first byte is always set to 1
66
- tmp_event = {};
67
- var lst_event = [];
68
- var eventname = '';
69
- var eventcount = 0;
70
- var pos = 1;
71
- while (pos < buf.length) {
72
- var len = buf.readInt8(pos++);
73
- eventname = buf.toString(DEFAULT_ENCODING, pos, pos + len);
74
- var prevcount = self.emgr.events[eventname] || 0;
75
- pos += len;
76
- eventcount = buf.readInt32LE(pos);
77
- tmp_event[eventname] = eventcount;
78
- pos += 4;
79
- if (prevcount !== eventcount)
80
- lst_event.push({ name: eventname, count: eventcount });
81
- }
82
- xdr.readInt64(); // ignore AST INFO
83
- var event_id = xdr.readInt();
84
- // set the new count in global event hash
85
- for (var evt in tmp_event) {
86
- self.emgr.events[evt] = tmp_event[evt];
87
- }
88
- if (self.eventcallback)
89
- return self.eventcallback(null, { eventid: event_id, events: lst_event });
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
- default:
92
- return cb(new Error('Unexpected:' + r));
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
- } catch (err) {
96
- if (err instanceof RangeError) { // incomplete packet case
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
- EventConnection.prototype.throwClosed = function (callback) {
106
- var err = new Error('Event Connection is closed.');
107
- this.db.emit('error', err);
108
- if (callback)
109
- callback(err);
110
- return this;
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
- function FbEventManager(db, eventconnection, eventid, callback) {
6
- this.db = db;
7
- this.eventconnection = eventconnection;
8
- this.events = {};
9
- this.eventid = eventid;
10
- this._createEventLoop(callback);
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
- FbEventManager.prototype.__proto__ = Object.create(Events.EventEmitter.prototype, {
14
- constructor: {
15
- value: FbEventManager,
16
- enumberable: false
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
- this.eventconnection.eventcallback = function (err, ret) {
37
- if (err || (self.eventid !== ret.eventid)) {
38
- doError(err || new Error('Bad eventid'), callback);
39
- return;
40
- }
43
+ ret.events.forEach(function (event) {
44
+ self.emit('post_event', event.name, event.count)
45
+ })
41
46
 
42
- ret.events.forEach(function (event) {
43
- self.emit('post_event', event.name, event.count)
44
- })
47
+ loop(false);
48
+ }
45
49
 
46
- loop(false);
50
+ loop(true);
47
51
  }
48
52
 
49
- loop(true);
50
- }
53
+ _changeEvent(callback) {
54
+ var self = this;
51
55
 
52
- FbEventManager.prototype._changeEvent = function (callback) {
53
- var self = this;
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
- self.db.connection.closeEvents(this.eventid, function (err) {
56
- if (err) {
57
- doError(err, callback);
58
- return;
59
- }
60
-
61
- self.db.connection.queEvents(self.events, self.eventid, callback);
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
- FbEventManager.prototype.registerEvent = function (events, callback) {
66
- var self = this;
89
+ registerEvent(events, callback) {
90
+ var self = this;
67
91
 
68
- if (self.db.connection._isClosed || self.eventconnection._isClosed)
69
- return self.eventconnection.throwClosed(callback);
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
- events.forEach((event) => self.events[event] = self.events[event] || 0);
72
- self._changeEvent(callback);
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
- FbEventManager.prototype.unregisterEvent = function (events, callback) {
76
- var self = this;
103
+ unregisterEvent(events, callback) {
104
+ var self = this;
77
105
 
78
- if (self.db.connection._isClosed || self.eventconnection._isClosed)
79
- return self.eventconnection.throwClosed(callback);
106
+ if (self.db.connection._isClosed || self.eventconnection._isClosed)
107
+ return self.eventconnection.throwClosed(callback);
80
108
 
81
- events.forEach(function (event) { delete self.events[event] });
82
- self._changeEvent(callback);
83
- }
109
+ events.forEach(function (event) { delete self.events[event] });
110
+ self._changeEvent(callback);
111
+ }
84
112
 
85
- FbEventManager.prototype.close = function (callback) {
86
- var self = this;
113
+ close(callback) {
114
+ var self = this;
87
115
 
88
- self.db.connection.closeEvents(this.eventid, function (err) {
89
- if (err) {
90
- doError(err, callback);
91
- return;
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
- self.eventconnection._socket.end();
95
- });
126
+ self.eventconnection._socket.end();
127
+ if (callback)
128
+ callback();
129
+ });
130
+ }
96
131
  }
97
132
 
98
133
  module.exports = FbEventManager;