Compare commits
123 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
80f2e7e50f | ||
|
9bbc961d52 | ||
|
3a2e30281f | ||
|
a48e4fa386 | ||
|
c422057f5f | ||
6159cd56b8 | |||
cbf3c7bb5e | |||
|
b17ab0c77a | ||
|
c67d0d25a2 | ||
|
5bc2aaa093 | ||
|
401f6c3190 | ||
|
40736d9da3 | ||
|
853ae875b8 | ||
|
da6d059547 | ||
|
e9834daa31 | ||
|
f79a0444f6 | ||
|
eb56e077f9 | ||
|
11f882501f | ||
|
7b7ccc2eef | ||
|
6b75d241fc | ||
|
7da398eae8 | ||
195a6d40ce | |||
55b9ddd856 | |||
fe82aebfec | |||
|
3f7798d46e | ||
|
6ad2d34114 | ||
|
67dab18d53 | ||
|
78677ba53e | ||
|
bbf25ee8b5 | ||
|
732b691e40 | ||
|
941f671ed2 | ||
|
343eaa85df | ||
|
e0fcf9a72d | ||
|
02642c5cfb | ||
|
d64f181dbb | ||
|
9e31b17c44 | ||
|
4ae4c1e010 | ||
76a405ace2 | |||
|
930b900426 | ||
|
934251d7fa | ||
|
1449b43b8d | ||
|
2f4850680f | ||
|
8f68923008 | ||
|
8e54a22cd2 | ||
|
6663b42903 | ||
|
ad8d16d112 | ||
|
bebd04a398 | ||
|
4d981596eb | ||
|
7ccced45aa | ||
|
88df807508 | ||
|
35f720f94f | ||
|
6d49f51e7d | ||
|
d8baed4c5d | ||
|
7e5327c278 | ||
|
bb53c01fe8 | ||
|
20818869f1 | ||
|
16f172c6f2 | ||
|
7db060af6e | ||
|
2c272a19f5 | ||
|
7dc4658719 | ||
|
811368c1af | ||
|
fcf27fba20 | ||
|
e9d86a3c4d | ||
|
0db2b93b79 | ||
|
ef26ed636f | ||
2893454e8a | |||
a0642ab081 | |||
760d31cc31 | |||
c1f17a7d99 | |||
96145fbe49 | |||
|
5ac4a206ad | ||
|
e1f99cecbc | ||
|
0a64b37b6f | ||
|
3421d41068 | ||
215708014c | |||
|
c3a63ff8b7 | ||
|
d8c0bfb03a | ||
34e8262dc8 | |||
bc2fbe14e3 | |||
9fc5d64ceb | |||
|
2bdd74e041 | ||
|
fde6ad2e77 | ||
4a2065c0a7 | |||
67dd275b5d | |||
8997a8c398 | |||
a5807483a2 | |||
e79ad8f9c4 | |||
|
bf89354564 | ||
|
254ddda8a2 | ||
|
16c081020a | ||
|
4584517ede | ||
|
e6af223f0d | ||
|
990351738c | ||
18e35c56f9 | |||
20de4c3715 | |||
60d2a1e5ee | |||
a8081a280a | |||
7c94e26055 | |||
|
0b968c40e8 | ||
|
21ab49845f | ||
|
6634dee5f3 | ||
1d21facd2c | |||
|
8735b23bf9 | ||
|
f66decdfb3 | ||
|
121e248dd8 | ||
|
917b89cf3d | ||
|
a1b9d6db9b | ||
|
83b88fc015 | ||
|
4130ab646c | ||
83cfa8fe1c | |||
e0446cfb3e | |||
0302099a16 | |||
f7c13634cc | |||
56c2dee6d6 | |||
|
85814ed03f | ||
|
361330629d | ||
|
883e89abfe | ||
|
e39280a2dc | ||
|
05b36f22bc | ||
|
217c1c6bb8 | ||
|
eaec15fe74 | ||
|
d71d565197 | ||
9e29e60cfa |
1
.gitignore
vendored
1
.gitignore
vendored
@ -34,6 +34,7 @@ node_modules
|
|||||||
|
|
||||||
# InteliJ
|
# InteliJ
|
||||||
.idea/workspace.xml
|
.idea/workspace.xml
|
||||||
|
.idea/shelf
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
lib/
|
lib/
|
||||||
|
11
.idea/codeStyles/Project.xml
generated
Normal file
11
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<codeStyleSettings language="JavaScript">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
92
README.md
92
README.md
@ -1,11 +1,14 @@
|
|||||||
# eventstore-node
|
# node-eventstore-client
|
||||||
A port of the EventStore .Net ClientAPI to Node.js
|
A port of the EventStore .Net ClientAPI to Node.js
|
||||||
|
|
||||||
|
## Learning
|
||||||
|
|
||||||
|
If you want to learn more about EventSourcing/EventModeling, you can join one of the monthly virtual workshops offered by my employer Adaptech Group, see info at [https://adaptechgroup.com/#workshop](https://adaptechgroup.com/#workshop).
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
### Missing features:
|
### Missing features:
|
||||||
|
|
||||||
- Ssl connection
|
|
||||||
- Set system settings
|
- Set system settings
|
||||||
|
|
||||||
### Areas to improve
|
### Areas to improve
|
||||||
@ -19,33 +22,44 @@ A port of the EventStore .Net ClientAPI to Node.js
|
|||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
Install using `npm install eventstore-node`
|
Install using `npm install node-eventstore-client`
|
||||||
|
|
||||||
|
Versions to install to match EventStore versions:
|
||||||
|
|
||||||
|
- 0.1.x for ES prior to 3.9.4
|
||||||
|
- 0.2.x for ES from 3.9.4 to 5.x
|
||||||
|
- 20.10.x for ES 20.10 LTS
|
||||||
|
- 21.10.x for ES 21.10 LTS
|
||||||
|
- 22.10.x for ES 22.10 LTS
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
- Node.js >= 0.12
|
- Node.js >= 14
|
||||||
- Modules: [long](https://www.npmjs.org/package/long), [protobufjs](https://www.npmjs.org/package/protobufjs), [uuid](https://www.npmjs.org/package/uuid) (installed via `npm install`)
|
- Modules: [long](https://www.npmjs.org/package/long), [protobufjs](https://www.npmjs.org/package/protobufjs), [uuid](https://www.npmjs.org/package/uuid), [strict-event-emitter-types](https://www.npmjs.com/package/strict-event-emitter-types) (installed via `npm install`)
|
||||||
|
|
||||||
|
### Install and run an Eventstore on localhost
|
||||||
|
|
||||||
|
See https://eventstore.com
|
||||||
|
|
||||||
|
*Note: If you are using a version of EventStore prior to 3.9.4, you need to use version 0.1.x of this package `npm install node-eventstore-client@^0.1`.*
|
||||||
|
|
||||||
|
|
||||||
### API Documentation
|
### API Documentation
|
||||||
|
|
||||||
#### Offline
|
#### Offline
|
||||||
|
|
||||||
The offline documentation can be found in the module folder `./node_modules/eventstore-node/docs`.
|
The offline documentation can be found in the module folder `./node_modules/node-eventstore-client/docs`.
|
||||||
|
|
||||||
#### Online
|
#### Online
|
||||||
|
|
||||||
The online documentation can be found at [https://dev.nicdex.com/eventstore-node/docs/](https://dev.nicdex.com/eventstore-node/docs/)
|
The online documentation can be found at [https://dev.nicdex.com/node-eventstore-client/docs/](https://dev.nicdex.com/node-eventstore-client/docs/)
|
||||||
|
|
||||||
### Install & run an Eventstore on localhost
|
|
||||||
|
|
||||||
See http://docs.geteventstore.com/introduction/3.9.0/ .
|
|
||||||
|
|
||||||
### Example: Storing an event
|
### Example: Storing an event
|
||||||
|
|
||||||
Save to ```app.js:```
|
Save to ```app.js:```
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var esClient = require('eventstore-node');
|
var esClient = require('node-eventstore-client');
|
||||||
var uuid = require('uuid');
|
var uuid = require('uuid');
|
||||||
|
|
||||||
var streamName = "testStream";
|
var streamName = "testStream";
|
||||||
@ -88,7 +102,7 @@ Run:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
npm install uuid
|
npm install uuid
|
||||||
npm install eventstore-node
|
npm install node-eventstore-client
|
||||||
node app.js
|
node app.js
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -110,14 +124,60 @@ To generate a test event, open a separate console and run:
|
|||||||
|
|
||||||
## Running the tests
|
## Running the tests
|
||||||
|
|
||||||
|
### Local testing
|
||||||
|
|
||||||
To run the tests it is recommended that you use an in-memory instance of the eventstore so you don't pollute your dev instance.
|
To run the tests it is recommended that you use an in-memory instance of the eventstore so you don't pollute your dev instance.
|
||||||
|
|
||||||
EventStore.ClusterNode.exe --memdb
|
EventStore.ClusterNode.exe --run-projections=all --memdb –certificate-file=yourcert.pfx
|
||||||
|
or
|
||||||
|
./run-node.sh --run-projections=all --memdb –certificate-file=yourcert.p12
|
||||||
|
|
||||||
|
You can also use docker-compose :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# start the single node cluster
|
||||||
|
npm run compose:single:start
|
||||||
|
# if you want to wait for the cluster to be available
|
||||||
|
npm run compose:wait
|
||||||
|
# run the tests
|
||||||
|
npm run test
|
||||||
|
# to cleanup (stop containres, delete volumes)
|
||||||
|
npm run compose:single:stop
|
||||||
|
```
|
||||||
|
|
||||||
|
For SSL setup see:
|
||||||
|
|
||||||
|
https://eventstore.org/docs/server/setting_up_ssl/
|
||||||
|
or
|
||||||
|
https://eventstore.org/docs/server/setting_up_ssl_linux/
|
||||||
|
|
||||||
To execute the tests suites simply run
|
To execute the tests suites simply run
|
||||||
|
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
|
### Isolated environment
|
||||||
|
|
||||||
|
To be able to run the tests for different connection types (tcp, gossip, cluster) docker-compose files are available to setup the environment and run the tests.
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
|
||||||
|
* docker
|
||||||
|
* docker-compose
|
||||||
|
|
||||||
|
#### Run
|
||||||
|
|
||||||
|
To execute the tests suites for single node cluster (tcp connection) simply run
|
||||||
|
|
||||||
|
npm run test:single
|
||||||
|
|
||||||
|
To execute the tests suites for multiple nodes cluster (gossip connection) simply run
|
||||||
|
|
||||||
|
npm run test:gossip
|
||||||
|
|
||||||
|
To execute the tests suites for multiple nodes cluster (dns discovery connection) simply run
|
||||||
|
|
||||||
|
npm run test:cluster
|
||||||
|
|
||||||
## Porting .Net Task to Node.js
|
## Porting .Net Task to Node.js
|
||||||
|
|
||||||
Any async commands returns a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) object in replacement of .Net Task.
|
Any async commands returns a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) object in replacement of .Net Task.
|
||||||
@ -125,6 +185,6 @@ Any async commands returns a [Promise](https://developer.mozilla.org/en/docs/Web
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Ported code is released under the MIT license, see [LICENSE](https://github.com/nicdex/eventstore-node/blob/master/LICENSE).
|
Ported code is released under the MIT license, see [LICENSE](https://github.com/nicdex/node-eventstore-client/blob/master/LICENSE).
|
||||||
|
|
||||||
Original code is released under the EventStore license and can be found at https://github.com/eventstore/eventstore.
|
Original code is released under the EventStore license and can be found at https://github.com/eventstore/eventstore.
|
||||||
|
11
build-and-test.sh
Executable file
11
build-and-test.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ -d /var/code/src ]]; then
|
||||||
|
cp -R /var/code/{src,test,*.js,*.json} .
|
||||||
|
fi
|
||||||
|
|
||||||
|
npm i
|
||||||
|
npm run build
|
||||||
|
npm run test-debug
|
23
certs/ca/ca.crt
Normal file
23
certs/ca/ca.crt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDzTCCArWgAwIBAgIRAJD0c8z8ITssbEkzjx4ZmRowDQYJKoZIhvcNAQELBQAw
|
||||||
|
YjELMAkGA1UEBhMCVUsxGDAWBgNVBAoTD0V2ZW50IFN0b3JlIEx0ZDE5MDcGA1UE
|
||||||
|
AxMwRXZlbnRTdG9yZURCIENBIDkwZjQ3M2NjZmMyMTNiMmM2YzQ5MzM4ZjFlMTk5
|
||||||
|
OTFhMB4XDTIyMTAyMjEzNTA1N1oXDTI3MTAyMjEzNTA1N1owYjELMAkGA1UEBhMC
|
||||||
|
VUsxGDAWBgNVBAoTD0V2ZW50IFN0b3JlIEx0ZDE5MDcGA1UEAxMwRXZlbnRTdG9y
|
||||||
|
ZURCIENBIDkwZjQ3M2NjZmMyMTNiMmM2YzQ5MzM4ZjFlMTk5OTFhMIIBIjANBgkq
|
||||||
|
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA17JM4jAG4fM4dtA6mpatLVkYhS42wwHC
|
||||||
|
RbG7dQINSE9wMKpoy2u4sDvZQrsudOvdeclPkIL1JgUtk7lDlqRMXZ6HnP7zTCKn
|
||||||
|
SQCXzvc3IIU0cGlkffuIS/kuAGBePvmmTwFE3ByDneydlHpSUGEvQY1KEAKwpgSO
|
||||||
|
LX1NtthP3kKT+bq0NdQlgOjm9dEkSYWwfCM7Of9cJdh8bCO4zJ1taGqchxluWlpo
|
||||||
|
DJL6TTHsZDvDjhfzBxhjuRax4S8B8xLaq6LirTFEFGpqFBhqzGGhRl42ZylKqVo9
|
||||||
|
fKhhywwq81ItROmB14OGKa8gyJi7pWGSKRI4M6Ngn89D50Q49K1QdQIDAQABo34w
|
||||||
|
fDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjApBgNVHQ4EIgQg
|
||||||
|
/3vmZ5JvcSlcqyaNXgrQZ5FOXlZ9HvYr9x+Tbrs3Mx4wKwYDVR0jBCQwIoAg/3vm
|
||||||
|
Z5JvcSlcqyaNXgrQZ5FOXlZ9HvYr9x+Tbrs3Mx4wDQYJKoZIhvcNAQELBQADggEB
|
||||||
|
AIMQR/3BHnVYAuG6DSdDPVYkPR9Fvwi9G9U1nybMHY9uSnEOp6yASrRc/cD7pIbP
|
||||||
|
Ax7cvD5f0829fAUFupXtp2T/yNOA7/eis7l6Y0ZZf+QEk9XhZXHVTFLFDb9Fyc6r
|
||||||
|
+i/lXnatGsYwOns0RFSG6tzxi2lxUPwlXauacwTBW4jrphtn0vC3q/n85JOEi2ib
|
||||||
|
aIlXaXUTREJFiFnS22/SX4dSRaeimL34rrd9AjX53Ne6pUiVBGgd2aSUkBh65EYk
|
||||||
|
VCIZwuWLx0jgcT8NI/EeId7FN4CWq73dze5eY2QU00rXidyYDeC2aZcU5e2RTQqn
|
||||||
|
5dGqFGAd/xCopGYdWfusqKM=
|
||||||
|
-----END CERTIFICATE-----
|
27
certs/ca/ca.key
Normal file
27
certs/ca/ca.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEA17JM4jAG4fM4dtA6mpatLVkYhS42wwHCRbG7dQINSE9wMKpo
|
||||||
|
y2u4sDvZQrsudOvdeclPkIL1JgUtk7lDlqRMXZ6HnP7zTCKnSQCXzvc3IIU0cGlk
|
||||||
|
ffuIS/kuAGBePvmmTwFE3ByDneydlHpSUGEvQY1KEAKwpgSOLX1NtthP3kKT+bq0
|
||||||
|
NdQlgOjm9dEkSYWwfCM7Of9cJdh8bCO4zJ1taGqchxluWlpoDJL6TTHsZDvDjhfz
|
||||||
|
BxhjuRax4S8B8xLaq6LirTFEFGpqFBhqzGGhRl42ZylKqVo9fKhhywwq81ItROmB
|
||||||
|
14OGKa8gyJi7pWGSKRI4M6Ngn89D50Q49K1QdQIDAQABAoIBAQCbeiKBSC0t4avp
|
||||||
|
uN8FX2clMPvDxDQlDLeElUCSbxAz907fRXaUaumN3xYUS+iIzxuuFbYMbNlYtpLL
|
||||||
|
0NcvVu7U7NjECeJGFxSOQqcqwHg0MNBD1zRgu1bbrJnEG7LTohCHElsYblVRGKXd
|
||||||
|
yO5ckjEGB1pDgCzk/pOdppzGF9Y6Vl/6WfZQgdGV6B1Qh9Vxs+1CGbK/6YqMM3av
|
||||||
|
9AJTEXgXbHOPyqNwixjxihpz79hXx0lOznL/CeosHKj7+ZY/knWZcDBmNq3ZA3Nz
|
||||||
|
w3p0fDkBtY7zQglh5nTSYoLtpcJvzkAI8uD6eJ4ThwIGUbLlvq0c3yaHZwIqrmEq
|
||||||
|
py09FA8BAoGBAPnuy+ehTBXV5k8icPZjI50Bjr5Alres01OjHxAA5bZJACwVbjMQ
|
||||||
|
a2464yb6DMA6NDrUevfHvKn3rw8OoceNrlaEua0qE5IweRpROf+ENqW9Yhcg4O1G
|
||||||
|
bSUPf5M1JusCSznAJu+gKsqHq0pTtdssh8Xb655xgd3gNMi0lLPlw5+tAoGBANzu
|
||||||
|
vidC8LRH+4JRrb+7PUZi1AR8vtCpabkLuVe7AZJl1wXFvYJTyFcW/e0WTvETcclf
|
||||||
|
9dhy1c0lH44571L4kpKRRKF4U3lcESbiLPDwjvfnls1rYzfzjY1YWoERwGYxL54H
|
||||||
|
2BBYPjKocnHZOnyiBxYn4ysK2O3dYlFxgJy/1GzpAoGBAM4HzW1HqRoC91Va1fY2
|
||||||
|
aaA/LXWmdtg5DwhOWwftRXAMI6kzjWFo8rauspxp2uMH2BB7Ildp/xu6A0SNUk3X
|
||||||
|
fNTzmsCmA/YqIVrRhNcfHZFpWhgo0WKoAMdhTFCEq21lua+EuFQnG79TMaAW+74O
|
||||||
|
qmovzb8SYPUPo1OkkUTvbmENAoGAODTg2Zo1JJhfiyL+ghW/nAWOjOmzneBLzlEG
|
||||||
|
QSSJXNZd4tEQynRINqfZyBRx1vEsdJ/eKsfkTsGQCp4AneoxV+pvPGkhS3G5x1up
|
||||||
|
NU7uAHHBstcMMfLbY0dEFywN97GxvJGgTWA1yquCGia6s3SBOwjAyXWEBNfaqH+o
|
||||||
|
ybgf8ekCgYEA3/Vx/CZ/VB0Fr47cpZGckJWH6lDWkzBEcaAT22VYlhL4CZ0CRDWj
|
||||||
|
6+LSiQDuI3+JwEhZlIkTvfZSo5bhNeUHoEL+15yg2RvsWFzorDxBfvZ//29BQg/Q
|
||||||
|
bN+vlKHpn7V7T9LQg/Tp107mfW6Z/TG4UYIVJyxY/JUjXjQLcFPvTVE=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
20
certs/eventstore-local.crt
Normal file
20
certs/eventstore-local.crt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSzCCAjMCFAxEesn/oIrU2T7DOU9cWCyoCCqfMA0GCSqGSIb3DQEBCwUAMGIx
|
||||||
|
CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRcw
|
||||||
|
FQYDVQQKDA5BZGFwdGVjaCBHcm91cDEZMBcGA1UEAwwQZXZlbnRzdG9yZS5sb2Nh
|
||||||
|
bDAeFw0yMTA1MDYyMDAyMzZaFw0zMTA1MDQyMDAyMzZaMGIxCzAJBgNVBAYTAkNB
|
||||||
|
MQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRcwFQYDVQQKDA5BZGFw
|
||||||
|
dGVjaCBHcm91cDEZMBcGA1UEAwwQZXZlbnRzdG9yZS5sb2NhbDCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBANbNrVQ91TFVsrfFV39/1MjxM/UIP78FaX+S
|
||||||
|
kxAzcpAJKP9PbHLwFXxkl0Bam+3ekE6+hc3qT8o4ksOdzwz+dJbdZF8gblLda7vq
|
||||||
|
JnPjkAZuhojRLPfXvaJZbManEkB30+JIvb/XWhMf34+kvyZaOnKqidzNAuLAFQ+6
|
||||||
|
KCCXYnTUFimumr6AsrZvA9UzN3edrk1pqxMYNT+8MBOUnNfkdHX78aTzdWvq4+Ro
|
||||||
|
+58MT3NpqdI+1cY423JlG2qj8PAqPsgdE4XvmtqDtLndH+VflR1M1Rkn41cofgSh
|
||||||
|
lo7PE2SNn4hSv8m+1HJMfcegJEXKE3LIGHJtV6qT6S+pRtJd9mcCAwEAATANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCAQEAlhKziHmYm81vrx+EHqIZXvmoUp3I1A9STvFqUdHrv9sa
|
||||||
|
8tKD7wW0owTVaxXBW3380ZFRpG3JVJFUgOyFIhi4IccWoqVsBCE0BBR96tlRXrKT
|
||||||
|
UZTAHLEk/SdLL+qfhKgY7F7+M9Wtf5HldiRfNoTqYn6YVXMJMgcwehhHho/fCHzj
|
||||||
|
tzOMfKFjGAq+n8cScLrTaW92JbbxjFPJJ7uQDH4OjAHx6pT885+RJf0rNqboAErA
|
||||||
|
lRLcEjtihslWKD7nelOlJE1egkum/m7MLVFpZPqEBp+x1zXdwacENwIhiRrQQhKi
|
||||||
|
8Qw36BuSCZ3CZK18kGyhtxl/uUP/wx7XXc1U0W2Wtw==
|
||||||
|
-----END CERTIFICATE-----
|
BIN
certs/eventstore.p12
Normal file
BIN
certs/eventstore.p12
Normal file
Binary file not shown.
24
certs/node1/node1.crt
Normal file
24
certs/node1/node1.crt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIECDCCAvCgAwIBAgIQI83qjs8Vn2iLbeUZbTPRcTANBgkqhkiG9w0BAQsFADBi
|
||||||
|
MQswCQYDVQQGEwJVSzEYMBYGA1UEChMPRXZlbnQgU3RvcmUgTHRkMTkwNwYDVQQD
|
||||||
|
EzBFdmVudFN0b3JlREIgQ0EgOTBmNDczY2NmYzIxM2IyYzZjNDkzMzhmMWUxOTk5
|
||||||
|
MWEwHhcNMjMwMTMwMTUyMzM0WhcNMjQwMTMwMTUyMzM0WjAcMRowGAYDVQQDExFl
|
||||||
|
dmVudHN0b3JlZGItbm9kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AL3CBeNLxZDvUA4WMRACrM+kxvrlD8ahs9MOFfAJHCNLoNR4mWAvh+BUDHsG7E56
|
||||||
|
4I5Y7XbC0cCIIER3/QB6Jz80kcJ4y745d9RCbYSqTeUnptrLdcXDNiwbI3bAjyuJ
|
||||||
|
tEqg+iPjrz2E6bSlZ4GSxKSTC95Dm80UUU/CG6+H1FesN8JP+ruYey4S5bYASy6o
|
||||||
|
z1NtYaPDGqSqDGvLhuWQNKoJAAc4g1R/UcVFbuI2asnCkFGjDF7gcRKkHpw0DNhN
|
||||||
|
TMQWMdQ2+I8it5UwNzYpsCZj/le5a54mNZqNYj52nEpURDsdJy4BXJy5dUwADZHz
|
||||||
|
ffN+ciWEToQz2hZmnliIG98CAwEAAaOB/zCB/DAOBgNVHQ8BAf8EBAMCBaAwHQYD
|
||||||
|
VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwKQYDVR0O
|
||||||
|
BCIEIFRmt7SsPXFStSAcZDS9OCP03JyevPMV6/1R0Utg8UA3MCsGA1UdIwQkMCKA
|
||||||
|
IP975meSb3EpXKsmjV4K0GeRTl5WfR72K/cfk267NzMeMGUGA1UdEQReMFyCKmNs
|
||||||
|
dXN0ZXIudGVzdHMubm9kZS1ldmVudHN0b3JlLWNsaWVudC5sb2NhbIIobm9kZTEu
|
||||||
|
dGVzdHMubm9kZS1ldmVudHN0b3JlLWNsaWVudC5sb2NhbIcEwKghCjANBgkqhkiG
|
||||||
|
9w0BAQsFAAOCAQEATHxhyf27pPFJRegPB9ozm4P06MkvZMm4syxmoR1jJohm+7Xp
|
||||||
|
7jd9ENATFApZNxV+/MYGgryML9Y+Md/Bd1fttP8j0MUR5euJX8zehrnCufaIw2If
|
||||||
|
/a9YalJ2/a+WElAgTHM1sCpdvL+WwsQ6IjWPVfGIu7VIotQXIqllZUjMd3rFI4Ip
|
||||||
|
9CkMgXbZzls8OhWH1FnPkFFjolqITwcgSmn3NWbQkl6qFYFjAZ8pFcjhdNay7yZx
|
||||||
|
+Pe9gEPbi6iyP50xb0LQtJXQQvFhwmDQbR5v0xiBI6ONK8mha3fQkxmV1wMPJdvQ
|
||||||
|
TOva/iFP4qmjyewyzOd752DN6r4qFlpb39Hpmw==
|
||||||
|
-----END CERTIFICATE-----
|
27
certs/node1/node1.key
Normal file
27
certs/node1/node1.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAvcIF40vFkO9QDhYxEAKsz6TG+uUPxqGz0w4V8AkcI0ug1HiZ
|
||||||
|
YC+H4FQMewbsTnrgjljtdsLRwIggRHf9AHonPzSRwnjLvjl31EJthKpN5Sem2st1
|
||||||
|
xcM2LBsjdsCPK4m0SqD6I+OvPYTptKVngZLEpJML3kObzRRRT8Ibr4fUV6w3wk/6
|
||||||
|
u5h7LhLltgBLLqjPU21ho8MapKoMa8uG5ZA0qgkABziDVH9RxUVu4jZqycKQUaMM
|
||||||
|
XuBxEqQenDQM2E1MxBYx1Db4jyK3lTA3NimwJmP+V7lrniY1mo1iPnacSlREOx0n
|
||||||
|
LgFcnLl1TAANkfN9835yJYROhDPaFmaeWIgb3wIDAQABAoIBAFO5a8eiAwWz0Wql
|
||||||
|
t/gMdhsX5QOGVbOaXTFeIafLHTMlh0y3+VRLJHSCIQ+XOmRWKwYjjoK76rg8V6Be
|
||||||
|
IK85Nl/Y3gckLSE9UfXBaXkDe2MEX8ZhxxD+1MQZJUicJY9cLsROyo9TQlqubj9a
|
||||||
|
S5UMIN9MUgw7YF7X/Bho2LZWBAa6Hz3LSyndwArvqZeUf8ovmJnWEUvJB8amVhwB
|
||||||
|
DoYqyNjiqIEJYWRfCeGfLEOmotmwCfYeJFyr84r3wfS6qmaesKM8Nbz8eSSNg7n3
|
||||||
|
5LcAL2Bv3hvsMmUEZQl3J41AtBVsU5DgbTf6/seuKvfVOcqVp9AtZp2rg3xY4pNI
|
||||||
|
7gN4wiECgYEA1lBh13LdjM0rOg9096ee2hQKjFvwVki0xzZigmf94CXoAJ19qwOe
|
||||||
|
J0WXfk1g5GP1bg5pdVhKdS+LEIqet9ipaall5hWotaYJdyOtWiQan9wRRa3sk6pl
|
||||||
|
K29LBF+XzZWAKE7C2371rVyMXViHzv056wasw0RSgxd6HBi1mOpcveMCgYEA4qrj
|
||||||
|
Ha24Qh+/b883FaMphYrl8H8nMgAdGmi7HiLnJx6jzPzalsBI5+qnDY8/oqeAie66
|
||||||
|
k8c6uRKOsEFrsbK/w3+21rGuZb9t9PupDONFOW9D94744HDFu0Clnr5S2ABKM9D6
|
||||||
|
hUL2qQedAqZx5CNWbpM/wdV0OBKhveIb9OyjytUCgYA21jCC0ThRK7owy/2w1Kn3
|
||||||
|
wQMF8Qxo94eSJZ9FINi7/tcDOUkLdgyEnfDqd2AgcFc/Rt7DEMlUfMrHe8Cq5/xJ
|
||||||
|
NfgFzGrzt71aR722f+B0IPomax9KlWH3oC2Au/j6uJMnPSfsw+qW5kRgKiPt2at1
|
||||||
|
MKsJ97RpKJutDsGAlA8Q4wKBgQCUyjBD7yEg5s43iwJRxcUf0EmYUR9dhw2TpGQQ
|
||||||
|
KEEsQMStbt3eT2KMOlBmaj4Pe3y5DmiTURiPHEtmD8ut3fRbVJ6k2AXu7HY1dm1F
|
||||||
|
9HogdZVcEBH24pAplwog5jZja+1Jjkik6YwY8NJ0RuZEJ544/5e+mWus0y4xAxfu
|
||||||
|
8teh8QKBgQDQm6vKAsldQStgj9gwRiTAUrMPTriVQTUd4/8lof+RoIJWM7CARLos
|
||||||
|
9MYkAefv4MgjvwWNn8RbFjN91NBX4qpCjgm62P25npFSKQAK+JQlvj7MbSw54jyx
|
||||||
|
2/uj4JEMM1rOocJr9tvYAeC2nnZMOuhesLVy+SHF9TJ2WtalDOTZ1A==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
24
certs/node2/node2.crt
Normal file
24
certs/node2/node2.crt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIECDCCAvCgAwIBAgIQdipz5iGZgwtJYjBK4mjFijANBgkqhkiG9w0BAQsFADBi
|
||||||
|
MQswCQYDVQQGEwJVSzEYMBYGA1UEChMPRXZlbnQgU3RvcmUgTHRkMTkwNwYDVQQD
|
||||||
|
EzBFdmVudFN0b3JlREIgQ0EgOTBmNDczY2NmYzIxM2IyYzZjNDkzMzhmMWUxOTk5
|
||||||
|
MWEwHhcNMjMwMTMwMTUyMzQwWhcNMjQwMTMwMTUyMzQwWjAcMRowGAYDVQQDExFl
|
||||||
|
dmVudHN0b3JlZGItbm9kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AOJZaF5skFJeNOgkqG8B38lV6lhKwvrmspxZvw7tP8dhzV7R+EUdTXYS86ximW4c
|
||||||
|
cdK5zqXRgZG6WaaFFN4BeCLqum+602l9Bw88K5Ww68v5R9VP8sgt7w4UsqvVjTJ4
|
||||||
|
60R59PvfrwkIL1DFkKBM4B7CmdLR20VZiJQ9YghR03TBbjjvIhaDyprmxu0vDsF7
|
||||||
|
f3zNmcnBF+14Z0b/exevtiVbyvNQ6nQENSo7Whz/kDV1a2i/BsVlsbFc43ywmsHL
|
||||||
|
Ks1z2rSctTgfYmK/yUFaR4B1mkzhQf9/CfJxJQLekC9Zv85ah9tMGwl/pbDfZh7q
|
||||||
|
NUJQHjJMm4I/HeeTQPd1CXcCAwEAAaOB/zCB/DAOBgNVHQ8BAf8EBAMCBaAwHQYD
|
||||||
|
VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwKQYDVR0O
|
||||||
|
BCIEIDlz3IFnAja157ly4cFxgZTfYrwlqAhgtbEu4TVhO/yPMCsGA1UdIwQkMCKA
|
||||||
|
IP975meSb3EpXKsmjV4K0GeRTl5WfR72K/cfk267NzMeMGUGA1UdEQReMFyCKmNs
|
||||||
|
dXN0ZXIudGVzdHMubm9kZS1ldmVudHN0b3JlLWNsaWVudC5sb2NhbIIobm9kZTIu
|
||||||
|
dGVzdHMubm9kZS1ldmVudHN0b3JlLWNsaWVudC5sb2NhbIcEwKghCzANBgkqhkiG
|
||||||
|
9w0BAQsFAAOCAQEAvj0ZjZkKdqwVdfXJAhMPGZwMf8gfZRpSCJe95FL0yePUk/jm
|
||||||
|
di2qk2sb2+W9prPR1Nbs1hfLnHHBw32yrxekvFSUC6Qc23X8S9QU01FOO7uEVtnM
|
||||||
|
fdEzyuZcdPBK2SAL/CxN0WH/yUxNWkWnqQKegZxkvpMVxMAsA0l3twWwfkEQtjhA
|
||||||
|
V/dcS5WwZxyyvCQ0qAVZ4+Zd/huvmsNIaXplvCs/P8yU6SR0TUdahJpfxJeKkKIf
|
||||||
|
k2h2/G36i26lTTm2TyxO4A2v8PotRO0xhjJkVKVEs4ZuY+lK6JUoTaM9Z8FubDqE
|
||||||
|
K2KH+YCBdER5jQK2YbmZDRh58aKMpCXtCx8RqQ==
|
||||||
|
-----END CERTIFICATE-----
|
27
certs/node2/node2.key
Normal file
27
certs/node2/node2.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEA4lloXmyQUl406CSobwHfyVXqWErC+uaynFm/Du0/x2HNXtH4
|
||||||
|
RR1NdhLzrGKZbhxx0rnOpdGBkbpZpoUU3gF4Iuq6b7rTaX0HDzwrlbDry/lH1U/y
|
||||||
|
yC3vDhSyq9WNMnjrRHn0+9+vCQgvUMWQoEzgHsKZ0tHbRVmIlD1iCFHTdMFuOO8i
|
||||||
|
FoPKmubG7S8OwXt/fM2ZycEX7XhnRv97F6+2JVvK81DqdAQ1KjtaHP+QNXVraL8G
|
||||||
|
xWWxsVzjfLCawcsqzXPatJy1OB9iYr/JQVpHgHWaTOFB/38J8nElAt6QL1m/zlqH
|
||||||
|
20wbCX+lsN9mHuo1QlAeMkybgj8d55NA93UJdwIDAQABAoIBAQDR3UvjoIz/kdFE
|
||||||
|
HBj/M6GmLz6ktkyqDRQ12xBGarrjxk6AR/YFPvH/M/syLglMCpuOYjCzldiooTtW
|
||||||
|
JbX/USVuWmyaA4LZH89X1NYkaHF4IZz0rrfP2qb3S0GOCOZtkaexSdJXZkIIAcq8
|
||||||
|
/TDnL9/tJUkyKtk/J5B2waMPS67fZGoZ6wx3sHZ7/CCcvdtHSvCT5+taVoHGUDPi
|
||||||
|
kToGcJAIDKAOakZfv1bfzYFyln18NA55V+133tGfZYJrILmEwLcU2Y7BAaoD+yme
|
||||||
|
+BWU3eKgYRCsvA+HzdgDetEaqp78Ax/G29OUK9NWdXk2hwhmkpZgSLV3g7OlfNve
|
||||||
|
6pmuEpcBAoGBAOPIMM+uYQJmRIapXZADQOc7VkF55sSjh3h25tjS8iHIEGQ9gb8n
|
||||||
|
h4iNUDC73NN9Yfw6/vKrwcpIq5nQKRRUQ+NJFxurtN6XBBlYNf336tg6S/65oe3W
|
||||||
|
R3m35/w72qcct1aOASDafuxdoEV/kbflpao57PxRZAXGdMPJANDckujXAoGBAP5j
|
||||||
|
x4NZvYI73oL2OI/2CJytA5uksfsh0ymusNKRaBhqLwFIE1Ud/CHj5eG1Bo9ox8Yl
|
||||||
|
e5AdkMmSSYFIe3B/P1apFI22/GKc1on2mFXKRY8zAMVLGbsLJarQz4xIX36bafUh
|
||||||
|
1O9JM1d6PWDITAzoptIJDF7U41jxbbGMic6gIbBhAoGAMOUkNTCFenJhe1aX0vYf
|
||||||
|
1IMUPPHh64v+5IkBfMGrYD0F576cP2BI47MR56Qr/uoHQpGXcJgV/UokK9xXNRnx
|
||||||
|
iLSD1VjCdpWMN7SLwnyZWNkKvx8x90/r/+DOV4KxqPWtFVNeQqMkY7ClWsXLjeIp
|
||||||
|
8aSFjpQaGHNFVVGsbykqD/kCgYEA3BZ/eoidiJs7e5qCfSqjcMnPIU1wHpG5G4rj
|
||||||
|
uInMwbK8UCOHdlCm3rtJG+l+b3x7ulabfKfXqE1EAvIuubmdluBZw/HYkYiXpG0Q
|
||||||
|
hsilPasms4qyDD0srYhSyE+lLuhO16IZk5yFKt27VIx2H4T5LyZc6X7N4xmdicrJ
|
||||||
|
P1cTToECgYEAlW2xWDl90suSAw1Tv23BVEX6ol/UColtGY8VDIHsXPDBYImtGiFt
|
||||||
|
MibOuyzWsvPw0HZDzWw9otU0735clhK34v+E1WyPFvOAo18orcCS4A6Fi42tp5oG
|
||||||
|
sNVxiYJFFUn+nnHUoGZNuKlB5PZR1Wxus6wXY2rZdoQ6QsBD0XjquCE=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
24
certs/node3/node3.crt
Normal file
24
certs/node3/node3.crt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIECDCCAvCgAwIBAgIQecOoexYVeIUtLwNQp179vzANBgkqhkiG9w0BAQsFADBi
|
||||||
|
MQswCQYDVQQGEwJVSzEYMBYGA1UEChMPRXZlbnQgU3RvcmUgTHRkMTkwNwYDVQQD
|
||||||
|
EzBFdmVudFN0b3JlREIgQ0EgOTBmNDczY2NmYzIxM2IyYzZjNDkzMzhmMWUxOTk5
|
||||||
|
MWEwHhcNMjMwMTMwMTUyMzQ2WhcNMjQwMTMwMTUyMzQ2WjAcMRowGAYDVQQDExFl
|
||||||
|
dmVudHN0b3JlZGItbm9kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AN8iXoWZjjxOqJJLTHmHOy89lbk2pBo/ca7qPZ/WC+I52A4Lgw58/O7tV/RHFyao
|
||||||
|
X8lS2hAVMlRfToUqj7ILAVBeF3t827W0qttbv+wdnxvIWqpq1HdtV5xgLIUXbyiQ
|
||||||
|
SI97Tgn7zDJOvm41sHV0xsPWKlritliDByXlGMOabzV53yxa1c0cU2bP5n7nc9wW
|
||||||
|
KOH03OU64qCj6MJTdi35peKDhaAcRtGmr5ZggUCP4n9GUzJ1FATAkcrLMOjoh1v1
|
||||||
|
K6auqOQZ8f+ns+3bQ4G96rZxwwrSzI/leUFY4u/lzjLUlEuLALJquPrB6RiwzTwb
|
||||||
|
BOaTYG6mgWORWPBupjpj67cCAwEAAaOB/zCB/DAOBgNVHQ8BAf8EBAMCBaAwHQYD
|
||||||
|
VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwKQYDVR0O
|
||||||
|
BCIEIMdKDLFiWvROUmnmDVing8S3lLisBr+vfrrM+A0t3yycMCsGA1UdIwQkMCKA
|
||||||
|
IP975meSb3EpXKsmjV4K0GeRTl5WfR72K/cfk267NzMeMGUGA1UdEQReMFyCKmNs
|
||||||
|
dXN0ZXIudGVzdHMubm9kZS1ldmVudHN0b3JlLWNsaWVudC5sb2NhbIIobm9kZTMu
|
||||||
|
dGVzdHMubm9kZS1ldmVudHN0b3JlLWNsaWVudC5sb2NhbIcEwKghDDANBgkqhkiG
|
||||||
|
9w0BAQsFAAOCAQEAEJmQloXSfxqWGIdGFi7UFDNr3oTxuQsEJRztKzA1rRPbvFhp
|
||||||
|
jJ1uPZKRv0SBnmaQa6+PW1zphP+kklmMq9XqiFqq7D7FmYgr2err08DbQfMxyEhG
|
||||||
|
yHmaBFzEyI/rm8jRn3K5DMV6cDCB3jTn5eud3oVVAZwTsLcR3mB2UpSJ7lAJgRFs
|
||||||
|
5pfFFgHKCQ4YQcFIkNtMeda7KpVv4YxoltJMSISDGvo4fcNhCH62H6/PDJFBi/e9
|
||||||
|
L4vB7eZHaO//8UQQxV24VSDLDBP1MQ4ucLZEVam9HQj4qK+DiwDlH6WmQs22FqqE
|
||||||
|
i7aLjEEu9Ko2zG7hzTp1jxDfyPw5iByax1JdXw==
|
||||||
|
-----END CERTIFICATE-----
|
27
certs/node3/node3.key
Normal file
27
certs/node3/node3.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA3yJehZmOPE6okktMeYc7Lz2VuTakGj9xruo9n9YL4jnYDguD
|
||||||
|
Dnz87u1X9EcXJqhfyVLaEBUyVF9OhSqPsgsBUF4Xe3zbtbSq21u/7B2fG8haqmrU
|
||||||
|
d21XnGAshRdvKJBIj3tOCfvMMk6+bjWwdXTGw9YqWuK2WIMHJeUYw5pvNXnfLFrV
|
||||||
|
zRxTZs/mfudz3BYo4fTc5TrioKPowlN2Lfml4oOFoBxG0aavlmCBQI/if0ZTMnUU
|
||||||
|
BMCRyssw6OiHW/Urpq6o5Bnx/6ez7dtDgb3qtnHDCtLMj+V5QVji7+XOMtSUS4sA
|
||||||
|
smq4+sHpGLDNPBsE5pNgbqaBY5FY8G6mOmPrtwIDAQABAoIBADk571QEVd5RrhoX
|
||||||
|
Bb4FWMB84vFleiDhNJ7PpI5hrxqOC0NO4IXOuG/unygfM2jOtgJEJXkKdqX8635r
|
||||||
|
s/7No8Cg4RTiqNapR0iK92XvEudlMxuR2nvmpxmL8N8Ra4jTuEhUL2eQFIaye1R4
|
||||||
|
oJD/Khr/yk0U5/87W5H0d61y5iKobF87QbI9xxkBGGQygsvoEni4sHchN1se/Ha8
|
||||||
|
y9nb6B/9sYU8lfSSaRhS/sqpH/ppnptWr1hwxj6jxI21uMB+cWN+rs8j1F0Zizex
|
||||||
|
+TTDqhyuYoqh1x2J9UFCjipiKVnA1563eFmtQZk2nrNdjvN6K9qWa0iF8IgTGvdh
|
||||||
|
m+9NNEECgYEA6sYqugSzeVCqBqHKAQKESsO6XOQjwkDZQhgeDG8Sal5RArlNsup6
|
||||||
|
hh/ZONPCL/6zxz5oKEyxzsTg4tJI9F3uqkpF5rcM1UGCc3maywXmLUd70NuTWM2G
|
||||||
|
hz+R4IhKyuQsFhWzFRBh10rorSvjIflkKiviZp+lNiDp1UnY0pOhxWUCgYEA807M
|
||||||
|
i60fuTTZsvGKhExORHUOnfs3USst1zHODDAaQYyjUYJP7ix/azf1ciHeeNCZ9rzF
|
||||||
|
9xBlDKChRSvKPnU0K07C49a+WI4rdgw8zS+8dqKdvaczPas0InPzXs+oW/O6I86I
|
||||||
|
ANEanw9fgrAPEL4/8TLMLhjTV3msdrJ04KzVWOsCgYEAtc9Ax01cr1YIVZp1FNMe
|
||||||
|
H8fzSnxiNMyDcuu6WWaqnDTuB234/dUXjUacsaVLfF+CWYm6n3rFN5q/jOfMF3Gm
|
||||||
|
obli6IhZJ8zTeRlzBkZLOkVhXRytvtdqltJj5b2mLfkFKxUi2e0V1+PqzDBwdJ7t
|
||||||
|
MrtJWK/JAWH7s3C8uFYbsQECgYEAsxD2d4H1zA/6fLlKEa47GCTymhCumJ1nwm4U
|
||||||
|
UGICoOWJuU5n10mGiXmIufP1UQNtnOs342p8hDugFVFyKl+GAq2Xv6lnM7OGhv3g
|
||||||
|
rb6JPOLXpyHsE2HyH70oi0nXhb0t7HZvH/LFXfUpfPxoShFK7BBPt0lsGYAiDsWu
|
||||||
|
QUDST/sCgYAVljJlvlEx8C8HmBrSeeh+Zec9t9HDjl04jNAwenY4x5hD1l1u2ij5
|
||||||
|
OJqVodZd1s/To7Dm9Xc6w7r6c9x8xsok4Kc3izc/KQXlxPvRnxF76J4KsMw8kEU1
|
||||||
|
LnQN+igffijohdln2Q8cQnEZylM1N4e+sNat5ufEzTk7MBn1676aHA==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
134
docker-compose-cluster.yaml
Normal file
134
docker-compose-cluster.yaml
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
version: '3.7'
|
||||||
|
|
||||||
|
services:
|
||||||
|
eventstore1:
|
||||||
|
image: eventstore/eventstore:22.10.0-buster-slim
|
||||||
|
environment:
|
||||||
|
- EVENTSTORE_CLUSTER_SIZE=3
|
||||||
|
- EVENTSTORE_CLUSTER_DNS=cluster.tests.node-eventstore-client.local
|
||||||
|
- EVENTSTORE_ADVERTISE_HOST_TO_CLIENT_AS=node1.tests.node-eventstore-client.local
|
||||||
|
- EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2113
|
||||||
|
- EVENTSTORE_ADVERTISE_TCP_PORT_TO_CLIENT_AS=1113
|
||||||
|
# - EVENTSTORE_DISCOVER_VIA_DNS=False
|
||||||
|
# - EVENTSTORE_GOSSIP_SEED=192.168.33.10:2113,192.168.33.11:2113,192.168.33.12:2113
|
||||||
|
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||||
|
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
|
||||||
|
- EVENTSTORE_ENABLE_EXTERNAL_TCP=true
|
||||||
|
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||||
|
- EVENTSTORE_HTTP_PORT=2113
|
||||||
|
- EVENTSTORE_INT_IP=192.168.33.10
|
||||||
|
- EVENTSTORE_EXT_IP=192.168.33.10
|
||||||
|
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node1/node1.crt
|
||||||
|
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node1/node1.key
|
||||||
|
- EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/etc/eventstore/certs/ca
|
||||||
|
expose:
|
||||||
|
- "1112"
|
||||||
|
- "1113"
|
||||||
|
- "2113"
|
||||||
|
ports:
|
||||||
|
- "1112:1112"
|
||||||
|
- "1113:1113"
|
||||||
|
- "2113:2113"
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
aliases:
|
||||||
|
- cluster.tests.node-eventstore-client.local
|
||||||
|
- node1.tests.node-eventstore-client.local
|
||||||
|
ipv4_address: 192.168.33.10
|
||||||
|
volumes:
|
||||||
|
- eventstore1-data:/var/lib/eventstore
|
||||||
|
- ./certs:/etc/eventstore/certs:ro
|
||||||
|
|
||||||
|
eventstore2:
|
||||||
|
image: eventstore/eventstore:22.10.0-buster-slim
|
||||||
|
environment:
|
||||||
|
- EVENTSTORE_CLUSTER_SIZE=3
|
||||||
|
- EVENTSTORE_CLUSTER_DNS=cluster.tests.node-eventstore-client.local
|
||||||
|
- EVENTSTORE_ADVERTISE_HOST_TO_CLIENT_AS=node2.tests.node-eventstore-client.local
|
||||||
|
- EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2113
|
||||||
|
- EVENTSTORE_ADVERTISE_TCP_PORT_TO_CLIENT_AS=1113
|
||||||
|
# - EVENTSTORE_DISCOVER_VIA_DNS=False
|
||||||
|
# - EVENTSTORE_GOSSIP_SEED=192.168.33.10:2113,192.168.33.11:2113,192.168.33.12:2113
|
||||||
|
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||||
|
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
|
||||||
|
- EVENTSTORE_ENABLE_EXTERNAL_TCP=true
|
||||||
|
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||||
|
- EVENTSTORE_HTTP_PORT=2113
|
||||||
|
- EVENTSTORE_INT_IP=192.168.33.11
|
||||||
|
- EVENTSTORE_EXT_IP=192.168.33.11
|
||||||
|
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node2/node2.crt
|
||||||
|
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node2/node2.key
|
||||||
|
- EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/etc/eventstore/certs/ca
|
||||||
|
expose:
|
||||||
|
- "1113"
|
||||||
|
- "1112"
|
||||||
|
- "2113"
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
aliases:
|
||||||
|
- cluster.tests.node-eventstore-client.local
|
||||||
|
- node2.tests.node-eventstore-client.local
|
||||||
|
ipv4_address: 192.168.33.11
|
||||||
|
volumes:
|
||||||
|
- eventstore2-data:/var/lib/eventstore
|
||||||
|
- ./certs:/etc/eventstore/certs:ro
|
||||||
|
|
||||||
|
eventstore3:
|
||||||
|
image: eventstore/eventstore:22.10.0-buster-slim
|
||||||
|
environment:
|
||||||
|
- EVENTSTORE_CLUSTER_SIZE=3
|
||||||
|
- EVENTSTORE_CLUSTER_DNS=cluster.tests.node-eventstore-client.local
|
||||||
|
- EVENTSTORE_ADVERTISE_HOST_TO_CLIENT_AS=node3.tests.node-eventstore-client.local
|
||||||
|
- EVENTSTORE_ADVERTISE_HTTP_PORT_TO_CLIENT_AS=2113
|
||||||
|
- EVENTSTORE_ADVERTISE_TCP_PORT_TO_CLIENT_AS=1113
|
||||||
|
# - EVENTSTORE_DISCOVER_VIA_DNS=False
|
||||||
|
# - EVENTSTORE_GOSSIP_SEED=192.168.33.10:2113,192.168.33.11:2113,192.168.33.12:2113
|
||||||
|
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||||
|
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
|
||||||
|
- EVENTSTORE_ENABLE_EXTERNAL_TCP=true
|
||||||
|
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||||
|
- EVENTSTORE_HTTP_PORT=2113
|
||||||
|
- EVENTSTORE_INT_IP=192.168.33.12
|
||||||
|
- EVENTSTORE_EXT_IP=192.168.33.12
|
||||||
|
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node3/node3.crt
|
||||||
|
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node3/node3.key
|
||||||
|
- EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/etc/eventstore/certs/ca
|
||||||
|
expose:
|
||||||
|
- "1113"
|
||||||
|
- "1112"
|
||||||
|
- "2113"
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
aliases:
|
||||||
|
- cluster.tests.node-eventstore-client.local
|
||||||
|
- node3.tests.node-eventstore-client.local
|
||||||
|
ipv4_address: 192.168.33.12
|
||||||
|
volumes:
|
||||||
|
- eventstore3-data:/var/lib/eventstore-data
|
||||||
|
- ./certs:/etc/eventstore/certs:ro
|
||||||
|
|
||||||
|
nodejs:
|
||||||
|
image: node:14
|
||||||
|
working_dir: /var/build
|
||||||
|
volumes:
|
||||||
|
- ./:/var/code:ro
|
||||||
|
- ./build-and-test.sh:/var/build/build-and-test.sh:ro
|
||||||
|
- ./certs:/var/certs:ro
|
||||||
|
environment:
|
||||||
|
- NODE_EXTRA_CA_CERTS=/var/certs/ca/ca.crt
|
||||||
|
command: bash -c "tail -f /dev/null"
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
ipv4_address: 192.168.33.5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
eventstore1-data:
|
||||||
|
eventstore2-data:
|
||||||
|
eventstore3-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: "192.168.33.0/24"
|
54
docker-compose-single.yaml
Normal file
54
docker-compose-single.yaml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
version: '3.4'
|
||||||
|
|
||||||
|
services:
|
||||||
|
eventstore:
|
||||||
|
image: eventstore/eventstore:22.10.0-buster-slim
|
||||||
|
environment:
|
||||||
|
- EVENTSTORE_CLUSTER_SIZE=1
|
||||||
|
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||||
|
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
|
||||||
|
- EVENTSTORE_ENABLE_EXTERNAL_TCP=true
|
||||||
|
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||||
|
- EVENTSTORE_HTTP_PORT=2113
|
||||||
|
- EVENTSTORE_INT_IP=192.168.33.10
|
||||||
|
- EVENTSTORE_EXT_IP=192.168.33.10
|
||||||
|
- EVENTSTORE_CERTIFICATE_FILE=/etc/eventstore/certs/node1/node1.crt
|
||||||
|
- EVENTSTORE_CERTIFICATE_PRIVATE_KEY_FILE=/etc/eventstore/certs/node1/node1.key
|
||||||
|
- EVENTSTORE_TRUSTED_ROOT_CERTIFICATES_PATH=/etc/eventstore/certs/ca
|
||||||
|
ports:
|
||||||
|
- "1113:1113"
|
||||||
|
- "2113:2113"
|
||||||
|
tmpfs:
|
||||||
|
- /var/log/eventstore
|
||||||
|
volumes:
|
||||||
|
- eventstore-data:/var/lib/eventstore
|
||||||
|
- ./certs:/etc/eventstore/certs:ro
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
aliases:
|
||||||
|
- node1.tests.node-eventstore-client.local
|
||||||
|
ipv4_address: 192.168.33.10
|
||||||
|
|
||||||
|
nodejs:
|
||||||
|
image: node:14
|
||||||
|
working_dir: /var/build
|
||||||
|
volumes:
|
||||||
|
- ./:/var/code:ro
|
||||||
|
- ./build-and-test.sh:/var/build/build-and-test.sh:ro
|
||||||
|
- ./certs:/var/certs:ro
|
||||||
|
environment:
|
||||||
|
- NODE_EXTRA_CA_CERTS=/var/certs/ca/ca.crt
|
||||||
|
command: bash -c "tail -f /dev/null"
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
ipv4_address: 192.168.33.5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
eventstore-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app_net:
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: "192.168.33.0/24"
|
186
index.d.ts
vendored
186
index.d.ts
vendored
@ -1,14 +1,18 @@
|
|||||||
/// <reference types="node" />
|
/// <reference types="node" />
|
||||||
/// <reference types="Long" />
|
/// <reference types="Long" />
|
||||||
|
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
import { StrictEventEmitter } from 'strict-event-emitter-types';
|
||||||
|
|
||||||
|
// Expose classes
|
||||||
export class Position {
|
export class Position {
|
||||||
constructor(commitPosition: number|Long, preparePosition: number|Long);
|
constructor(commitPosition: number|Long, preparePosition: number|Long);
|
||||||
readonly commitPosition: Long;
|
readonly commitPosition: Long;
|
||||||
readonly preparePosition: Long;
|
readonly preparePosition: Long;
|
||||||
|
static readonly start: number;
|
||||||
|
static readonly end: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose classes
|
|
||||||
|
|
||||||
export class UserCredentials {
|
export class UserCredentials {
|
||||||
constructor(username: string, password: string);
|
constructor(username: string, password: string);
|
||||||
readonly username: string;
|
readonly username: string;
|
||||||
@ -16,17 +20,17 @@ export class UserCredentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PersistentSubscriptionSettings {
|
export class PersistentSubscriptionSettings {
|
||||||
constructor(resolveLinkTos: boolean, startFrom: number, extraStatistics: boolean, messageTimeout: number,
|
constructor(resolveLinkTos: boolean, startFrom: Long|number, extraStatistics: boolean, messageTimeout: number,
|
||||||
maxRetryCount: number, liveBufferSize: number, readBatchSize: number, historyBufferSize: number,
|
maxRetryCount: number, liveBufferSize: number, readBatchSize: number, historyBufferSize: number,
|
||||||
checkPointAfter: number, minCheckPointCount: number, maxCheckPointCount: number,
|
checkPointAfter: number, minCheckPointCount: number, maxCheckPointCount: number,
|
||||||
maxSubscriberCount: number, namedConsumerStrategy: string)
|
maxSubscriberCount: number, namedConsumerStrategy: string)
|
||||||
static create();
|
static create(): PersistentSubscriptionSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace SystemConsumerStrategies {
|
export namespace SystemConsumerStrategies {
|
||||||
const DispatchToSingle: string;
|
const DispatchToSingle: string;
|
||||||
const RoundRobin: string;
|
const RoundRobin: string;
|
||||||
const Pinned: string
|
const Pinned: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GossipSeed {
|
export class GossipSeed {
|
||||||
@ -35,13 +39,65 @@ export class GossipSeed {
|
|||||||
readonly hostHeader: string;
|
readonly hostHeader: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProjectionDetails {
|
||||||
|
readonly coreProcessingTime: number,
|
||||||
|
readonly version: number,
|
||||||
|
readonly epoch: number,
|
||||||
|
readonly effectiveName: string,
|
||||||
|
readonly writesInProgress: number,
|
||||||
|
readonly readsInProgress: number,
|
||||||
|
readonly partitionsCached: number,
|
||||||
|
readonly status: string,
|
||||||
|
readonly stateReason: string,
|
||||||
|
readonly name: string,
|
||||||
|
readonly mode: string,
|
||||||
|
readonly position: string,
|
||||||
|
readonly progress: number,
|
||||||
|
readonly lastCheckpoint: string,
|
||||||
|
readonly eventsProcessedAfterRestart: number,
|
||||||
|
readonly statusUrl: string,
|
||||||
|
readonly stateUrl: string,
|
||||||
|
readonly resultUrl: string,
|
||||||
|
readonly queryUrl: string,
|
||||||
|
readonly enableCommandUrl: string,
|
||||||
|
readonly disableCommandUrl: string,
|
||||||
|
readonly checkpointStatus: string,
|
||||||
|
readonly bufferedEvents: number,
|
||||||
|
readonly writePendingEventsBeforeCheckpoint: number,
|
||||||
|
readonly writePendingEventsAfterCheckpoint: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProjectionsManager {
|
||||||
|
constructor(log: Logger, httpEndPoint: string, operationTimeout: number);
|
||||||
|
enable(name: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
disable(name: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
abort(name: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
reset(name: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
createOneTime(query: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
createTransient(name: string, query: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
createContinuous(name: string, query: string, trackEmittedStreams: boolean, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
listAll(userCredentials: UserCredentials): Promise<ProjectionDetails[]>;
|
||||||
|
listOneTime(userCredentials: UserCredentials): Promise<ProjectionDetails[]>;
|
||||||
|
listContinuous(userCredentials: UserCredentials): Promise<ProjectionDetails[]>;
|
||||||
|
getStatus(name: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getState(name: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getPartitionState(name: string, partitionId: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getResult(name: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getPartitionResult(name: string, partitionId: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getStatistics(name: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getQuery(name: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
getState(name: string, userCredentials: UserCredentials): Promise<string>;
|
||||||
|
updateQuery(name: string, query: string, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
delete(name: string, deleteEmittedStreams: boolean, deleteStateStream: boolean, deleteCheckpointStream: boolean, userCredentials: UserCredentials): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
// Expose errors
|
// Expose errors
|
||||||
export class WrongExpectedVersionError {
|
export class WrongExpectedVersionError {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly action: string;
|
readonly action: string;
|
||||||
readonly message: string;
|
readonly message: string;
|
||||||
readonly stream?: string;
|
readonly stream?: string;
|
||||||
readonly expectedVersion?: number;
|
readonly expectedVersion?: Long;
|
||||||
readonly transactionId?: Long;
|
readonly transactionId?: Long;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,12 +115,17 @@ export class AccessDeniedError {
|
|||||||
readonly transactionId?: Long;
|
readonly transactionId?: Long;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose enums/constants
|
export class ProjectionCommandFailedError {
|
||||||
|
readonly httpStatusCode: number;
|
||||||
|
readonly message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose enums/constants
|
||||||
export namespace expectedVersion {
|
export namespace expectedVersion {
|
||||||
const any: number;
|
const any: number;
|
||||||
const noStream: number;
|
const noStream: number;
|
||||||
const emptyStream: number;
|
const emptyStream: number;
|
||||||
|
const streamExists: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace positions {
|
export namespace positions {
|
||||||
@ -72,19 +133,24 @@ export namespace positions {
|
|||||||
const end: Position;
|
const end: Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace streamPosition {
|
||||||
|
const start: number;
|
||||||
|
const end: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
// systemMetadata
|
// systemMetadata
|
||||||
// eventReadStatus
|
// eventReadStatus
|
||||||
// sliceReadStatus
|
// sliceReadStatus
|
||||||
|
|
||||||
// Expose loggers
|
// Expose loggers
|
||||||
|
|
||||||
export interface Logger {
|
export interface Logger {
|
||||||
debug(fmt: string, ...args: any[]): void;
|
debug(fmt: string, ...args: any[]): void;
|
||||||
info(fmt: string, ...args: any[]): void;
|
info(fmt: string, ...args: any[]): void;
|
||||||
error(fmt: string, ...args: any[]): void;
|
error(fmt: string, ...args: any[]): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NoOpLogger implements Logger {
|
export class NoopLogger implements Logger {
|
||||||
constructor()
|
constructor()
|
||||||
debug(fmt: string, ...args: any[]): void;
|
debug(fmt: string, ...args: any[]): void;
|
||||||
info(fmt: string, ...args: any[]): void;
|
info(fmt: string, ...args: any[]): void;
|
||||||
@ -98,18 +164,18 @@ export class FileLogger implements Logger {
|
|||||||
error(fmt: string, ...args: any[]): void;
|
error(fmt: string, ...args: any[]): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Expose results
|
||||||
|
|
||||||
export interface WriteResult {
|
export interface WriteResult {
|
||||||
readonly nextExpectedVersion: number;
|
readonly nextExpectedVersion: Long;
|
||||||
readonly logPosition: Position;
|
readonly logPosition: Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RecordedEvent {
|
export interface RecordedEvent {
|
||||||
readonly eventStreamId: string;
|
readonly eventStreamId: string;
|
||||||
readonly eventId: string;
|
readonly eventId: string;
|
||||||
readonly eventNumber: number;
|
readonly eventNumber: Long;
|
||||||
readonly eventType: string;
|
readonly eventType: string;
|
||||||
|
readonly created: Date;
|
||||||
readonly createdEpoch: number;
|
readonly createdEpoch: number;
|
||||||
readonly data?: Buffer;
|
readonly data?: Buffer;
|
||||||
readonly metadata?: Buffer;
|
readonly metadata?: Buffer;
|
||||||
@ -123,17 +189,17 @@ export interface ResolvedEvent {
|
|||||||
readonly isResolved: boolean;
|
readonly isResolved: boolean;
|
||||||
readonly originalPosition?: Position;
|
readonly originalPosition?: Position;
|
||||||
readonly originalStreamId: string;
|
readonly originalStreamId: string;
|
||||||
readonly originalEventNumber: number;
|
readonly originalEventNumber: Long;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StreamEventsSlice {
|
export interface StreamEventsSlice {
|
||||||
readonly status: string; // TODO: enum
|
readonly status: string; // TODO: enum
|
||||||
readonly stream: string;
|
readonly stream: string;
|
||||||
readonly fromEventNumber: number;
|
readonly fromEventNumber: Long;
|
||||||
readonly readDirection: string; // TODO: enum
|
readonly readDirection: string; // TODO: enum
|
||||||
readonly events: ResolvedEvent[];
|
readonly events: ResolvedEvent[];
|
||||||
readonly nextEventNumber: number;
|
readonly nextEventNumber: Long;
|
||||||
readonly lastEventNumber: number;
|
readonly lastEventNumber: Long;
|
||||||
readonly isEndOfStream: boolean;
|
readonly isEndOfStream: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +225,7 @@ export interface EventStoreTransaction {
|
|||||||
export interface EventReadResult {
|
export interface EventReadResult {
|
||||||
readonly status: string;
|
readonly status: string;
|
||||||
readonly stream: string;
|
readonly stream: string;
|
||||||
readonly eventNumber: number;
|
readonly eventNumber: Long;
|
||||||
readonly event: ResolvedEvent | null;
|
readonly event: ResolvedEvent | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,27 +233,52 @@ export interface EventStoreSubscription {
|
|||||||
readonly isSubscribedToAll: boolean;
|
readonly isSubscribedToAll: boolean;
|
||||||
readonly streamId: string;
|
readonly streamId: string;
|
||||||
readonly lastCommitPosition: Position;
|
readonly lastCommitPosition: Position;
|
||||||
readonly lastEventNumber: number;
|
readonly lastEventNumber: Long;
|
||||||
|
|
||||||
close(): void;
|
close(): void;
|
||||||
unsubscribe(): void;
|
unsubscribe(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventStoreCatchUpSubscription {
|
export interface EventStoreCatchUpSubscription {
|
||||||
start(): void;
|
stop(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PersistentSubscriptionNakEventAction {
|
||||||
|
Unknown = 0,
|
||||||
|
Park = 1,
|
||||||
|
Retry = 2,
|
||||||
|
Skip = 3,
|
||||||
|
Stop = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventStorePersistentSubscription {
|
||||||
|
acknowledge(events: ResolvedEvent | ResolvedEvent[]): void;
|
||||||
|
fail(events: ResolvedEvent | ResolvedEvent[], action: PersistentSubscriptionNakEventAction, reason: string): void;
|
||||||
stop(): void;
|
stop(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RawStreamMetadataResult {
|
export interface RawStreamMetadataResult {
|
||||||
readonly stream: string;
|
readonly stream: string;
|
||||||
readonly isStreamDeleted: boolean;
|
readonly isStreamDeleted: boolean;
|
||||||
readonly metastreamVersion: number;
|
readonly metastreamVersion: Long;
|
||||||
readonly streamMetadata: any;
|
readonly streamMetadata: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PersistentSubscriptionCreateResult {
|
||||||
|
readonly status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PersistentSubscriptionUpdateResult {
|
||||||
|
readonly status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PersistentSubscriptionDeleteResult {
|
||||||
|
readonly status: string;
|
||||||
|
}
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
export interface EventAppearedCallback<TSubscription> {
|
export interface EventAppearedCallback<TSubscription> {
|
||||||
(subscription: TSubscription, event: ResolvedEvent): void;
|
(subscription: TSubscription, event: ResolvedEvent): void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LiveProcessingStartedCallback {
|
export interface LiveProcessingStartedCallback {
|
||||||
@ -203,6 +294,15 @@ export interface TcpEndPoint {
|
|||||||
host: string;
|
host: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HeartbeatInfo {
|
||||||
|
readonly connectionId: string;
|
||||||
|
readonly remoteEndPoint: TcpEndPoint;
|
||||||
|
readonly requestSentAt: number;
|
||||||
|
readonly requestPkgNumber: number;
|
||||||
|
readonly responseReceivedAt: number;
|
||||||
|
readonly responsePkgNumber: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EventData {
|
export interface EventData {
|
||||||
readonly eventId: string;
|
readonly eventId: string;
|
||||||
readonly type: string;
|
readonly type: string;
|
||||||
@ -211,35 +311,47 @@ export interface EventData {
|
|||||||
readonly metadata: Buffer;
|
readonly metadata: Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventStoreNodeConnection {
|
interface EventStoreNodeConnectionEvents {
|
||||||
|
connected: TcpEndPoint;
|
||||||
|
disconnected: TcpEndPoint;
|
||||||
|
reconnecting: void;
|
||||||
|
closed:string;
|
||||||
|
error: Error;
|
||||||
|
heartbeatInfo: HeartbeatInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventStoreNodeConnectionEventEmitter = StrictEventEmitter<EventEmitter, EventStoreNodeConnectionEvents>;
|
||||||
|
|
||||||
|
export class EventStoreNodeConnection extends (EventEmitter as { new(): EventStoreNodeConnectionEventEmitter }) {
|
||||||
connect(): Promise<void>;
|
connect(): Promise<void>;
|
||||||
close(): void;
|
close(): void;
|
||||||
// write actions
|
// write actions
|
||||||
deleteStream(stream: string, expectedVersion: number, hardDelete?: boolean, userCredentials?: UserCredentials): Promise<DeleteResult>;
|
deleteStream(stream: string, expectedVersion: Long|number, hardDelete?: boolean, userCredentials?: UserCredentials): Promise<DeleteResult>;
|
||||||
appendToStream(stream: string, expectedVersion: number, eventOrEvents: EventData | EventData[], userCredentials?: UserCredentials): Promise<WriteResult>;
|
appendToStream(stream: string, expectedVersion: Long|number, eventOrEvents: EventData | EventData[], userCredentials?: UserCredentials): Promise<WriteResult>;
|
||||||
startTransaction(stream: string, expectedVersion: number, userCredentials?: UserCredentials): Promise<EventStoreTransaction>;
|
startTransaction(stream: string, expectedVersion: Long|number, userCredentials?: UserCredentials): Promise<EventStoreTransaction>;
|
||||||
continueTransaction(transactionId: number, userCredentials?: UserCredentials): EventStoreTransaction;
|
continueTransaction(transactionId: number, userCredentials?: UserCredentials): EventStoreTransaction;
|
||||||
// read actions
|
// read actions
|
||||||
readEvent(stream: string, eventNumber: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<EventReadResult>;
|
readEvent(stream: string, eventNumber: Long|number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<EventReadResult>;
|
||||||
readStreamEventsForward(stream: string, start: number, count: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<StreamEventsSlice>;
|
readStreamEventsForward(stream: string, start: Long|number, count: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<StreamEventsSlice>;
|
||||||
readStreamEventsBackward(stream: string, start: number, count: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<StreamEventsSlice>;
|
readStreamEventsBackward(stream: string, start: Long|number, count: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<StreamEventsSlice>;
|
||||||
readAllEventsForward(position: Position, maxCount: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<AllEventsSlice>;
|
readAllEventsForward(position: Position, maxCount: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<AllEventsSlice>;
|
||||||
readAllEventsBackward(position: Position, maxCount: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<AllEventsSlice>;
|
readAllEventsBackward(position: Position, maxCount: number, resolveLinkTos?: boolean, userCredentials?: UserCredentials): Promise<AllEventsSlice>;
|
||||||
// subscription actions
|
// subscription actions
|
||||||
subscribeToStream(stream: string, resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreSubscription>, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreSubscription>, userCredentials?: UserCredentials): Promise<EventStoreSubscription>;
|
subscribeToStream(stream: string, resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreSubscription>, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreSubscription>, userCredentials?: UserCredentials): Promise<EventStoreSubscription>;
|
||||||
subscribeToStreamFrom(stream: string, lastCheckpoint: number | null, resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreCatchUpSubscription>, liveProcessingStarted?: LiveProcessingStartedCallback, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreCatchUpSubscription>, userCredentials?: UserCredentials, readBatchSize?: number): EventStoreCatchUpSubscription;
|
subscribeToStreamFrom(stream: string, lastCheckpoint: Long|number|null, resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreCatchUpSubscription>, liveProcessingStarted?: LiveProcessingStartedCallback, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreCatchUpSubscription>, userCredentials?: UserCredentials, readBatchSize?: number): EventStoreCatchUpSubscription;
|
||||||
subscribeToAll(resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreSubscription>, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreSubscription>, userCredentials?: UserCredentials): Promise<EventStoreSubscription>;
|
subscribeToAll(resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreSubscription>, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreSubscription>, userCredentials?: UserCredentials): Promise<EventStoreSubscription>;
|
||||||
subscribeToAllFrom(lastCheckpoint: Position | null, resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreCatchUpSubscription>, liveProcessingStarted?: LiveProcessingStartedCallback, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreCatchUpSubscription>, userCredentials?: UserCredentials, readBatchSize?: number): EventStoreCatchUpSubscription;
|
subscribeToAllFrom(lastCheckpoint: Position|null, resolveLinkTos: boolean, eventAppeared: EventAppearedCallback<EventStoreCatchUpSubscription>, liveProcessingStarted?: LiveProcessingStartedCallback, subscriptionDropped?: SubscriptionDroppedCallback<EventStoreCatchUpSubscription>, userCredentials?: UserCredentials, readBatchSize?: number): EventStoreCatchUpSubscription;
|
||||||
|
// persistent subscriptions
|
||||||
|
createPersistentSubscription(stream: string, groupName: string, settings: PersistentSubscriptionSettings, userCredentials?: UserCredentials): Promise<PersistentSubscriptionCreateResult>;
|
||||||
|
updatePersistentSubscription(stream: string, groupName: string, settings: PersistentSubscriptionSettings, userCredentials?: UserCredentials): Promise<PersistentSubscriptionUpdateResult>;
|
||||||
|
deletePersistentSubscription(stream: string, groupName: string, userCredentials?: UserCredentials): Promise<PersistentSubscriptionDeleteResult>
|
||||||
|
connectToPersistentSubscription(stream: string, groupName: string, eventAppeared: EventAppearedCallback<EventStorePersistentSubscription>, subscriptionDropped?: SubscriptionDroppedCallback<EventStorePersistentSubscription>, userCredentials?: UserCredentials, bufferSize?: number, autoAck?: boolean): Promise<EventStorePersistentSubscription>;
|
||||||
// metadata actions
|
// metadata actions
|
||||||
setStreamMetadataRaw(stream: string, expectedMetastreamVersion: number, metadata: any, userCredentials?: UserCredentials): Promise<WriteResult>;
|
setStreamMetadataRaw(stream: string, expectedMetastreamVersion: Long|number, metadata: any, userCredentials?: UserCredentials): Promise<WriteResult>;
|
||||||
getStreamMetadataRaw(stream: string, userCredentials?: UserCredentials): Promise<RawStreamMetadataResult>;
|
getStreamMetadataRaw(stream: string, userCredentials?: UserCredentials): Promise<RawStreamMetadataResult>;
|
||||||
|
|
||||||
on(event: "connected" | "disconnected" | "reconnecting" | "closed" | "error", listener: (arg: Error | string | TcpEndPoint) => void): this;
|
|
||||||
once(event: "connected" | "disconnected" | "reconnecting" | "closed" | "error", listener: (arg: Error | string | TcpEndPoint) => void): this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose helper functions
|
// Expose helper functions
|
||||||
|
|
||||||
export interface ConnectionSettings {
|
export interface ConnectionSettings {
|
||||||
log?: Logger,
|
log?: Logger,
|
||||||
verboseLogging?: boolean,
|
verboseLogging?: boolean,
|
||||||
@ -268,10 +380,12 @@ export interface ConnectionSettings {
|
|||||||
// Cluster Settings
|
// Cluster Settings
|
||||||
clusterDns?: string,
|
clusterDns?: string,
|
||||||
maxDiscoverAttempts?: number,
|
maxDiscoverAttempts?: number,
|
||||||
|
discoverDelay?: number,
|
||||||
externalGossipPort?: number,
|
externalGossipPort?: number,
|
||||||
gossipTimeout?: number
|
gossipTimeout?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expose Helper functions
|
||||||
export function createConnection(settings: ConnectionSettings, endPointOrGossipSeed: string | TcpEndPoint | GossipSeed[], connectionName?: string): EventStoreNodeConnection;
|
export function createConnection(settings: ConnectionSettings, endPointOrGossipSeed: string | TcpEndPoint | GossipSeed[], connectionName?: string): EventStoreNodeConnection;
|
||||||
export function createJsonEventData(eventId: string, event: any, metadata?: any, type?: string): EventData;
|
export function createJsonEventData(eventId: string, event: any, metadata?: any, type?: string): EventData;
|
||||||
export function createEventData(eventId: string, type: string, isJson: boolean, data: Buffer, metadata?: Buffer): EventData;
|
export function createEventData(eventId: string, type: string, isJson: boolean, data: Buffer, metadata?: Buffer): EventData;
|
||||||
|
2
index.js
2
index.js
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* eventstore-node A port of EventStore .Net ClientAPI to Node.js
|
* node-eventstore-client A port of EventStore .Net ClientAPI to Node.js
|
||||||
* see README.md for more details
|
* see README.md for more details
|
||||||
* see LICENSE for license info
|
* see LICENSE for license info
|
||||||
*/
|
*/
|
||||||
|
6891
package-lock.json
generated
Normal file
6891
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@ -1,16 +1,34 @@
|
|||||||
{
|
{
|
||||||
"name": "eventstore-node",
|
"name": "node-eventstore-client",
|
||||||
"version": "0.0.28",
|
"version": "22.10.0",
|
||||||
"description": "A port of the EventStore .Net ClientAPI to Node.js",
|
"description": "A port of the EventStore .Net ClientAPI to Node.js",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14",
|
||||||
|
"npm": ">=6"
|
||||||
|
},
|
||||||
|
"engineStrict": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm lib/dist.js",
|
"clean": "rm -f lib/dist.js",
|
||||||
|
"prebuild": "npm run clean",
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"pretest": "npm run build",
|
"pretest": "npm run build",
|
||||||
"test": "nodeunit",
|
"test": "nodeunit",
|
||||||
"test-debug": "TESTS_VERBOSE_LOGGING=1 nodeunit",
|
"test-debug": "TESTS_VERBOSE_LOGGING=1 nodeunit",
|
||||||
"prepublish": "npm run build && npm run gendocs",
|
"test:jest:watch": "jest --watch --coverage",
|
||||||
|
"test:single": "npm run compose:single:start && npm run compose:wait && npm run compose:single:test ; npm run compose:single:stop",
|
||||||
|
"test:gossip": "npm run compose:cluster:start && npm run compose:wait && npm run compose:gossip:test ; npm run compose:cluster:stop",
|
||||||
|
"test:cluster": "npm run compose:cluster:start && npm run compose:wait && npm run compose:cluster:test ; npm run compose:cluster:stop",
|
||||||
|
"compose:single:start": "docker-compose -f docker-compose-single.yaml up --build -d",
|
||||||
|
"compose:cluster:start": "docker-compose -f docker-compose-cluster.yaml up --build -d",
|
||||||
|
"compose:single:stop": "docker-compose -f docker-compose-single.yaml down -v --remove-orphans",
|
||||||
|
"compose:cluster:stop": "docker-compose -f docker-compose-cluster.yaml down -v --remove-orphans",
|
||||||
|
"compose:wait": "while [ \"$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:2113/ping)\" != \"200\" ]; do sleep 5; done",
|
||||||
|
"compose:single:test": "docker-compose -f docker-compose-single.yaml exec nodejs bash -c \"EVENTSTORE_CONNECTION_TYPE=tcp EVENTSTORE_HOST=192.168.33.10 ./build-and-test.sh\"",
|
||||||
|
"compose:gossip:test": "docker-compose -f docker-compose-cluster.yaml exec nodejs bash -c \"EVENTSTORE_CONNECTION_TYPE=gossip EVENTSTORE_HOST=192.168.33.10 EVENTSTORE_HOST_1=192.168.33.10 EVENTSTORE_HOST_2=192.168.33.11 EVENTSTORE_HOST_3=192.168.33.12 ./build-and-test.sh\"",
|
||||||
|
"compose:cluster:test": "docker-compose -f docker-compose-cluster.yaml exec nodejs bash -c \"EVENTSTORE_CONNECTION_TYPE=dns EVENTSTORE_HOST=cluster.tests.node-eventstore-client.local ./build-and-test.sh\"",
|
||||||
|
"prepublishOnly": "npm run build && npm run gendocs",
|
||||||
"gendocs": "rm -rf docs && jsdoc src -r -d docs"
|
"gendocs": "rm -rf docs && jsdoc src -r -d docs"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@ -27,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/nicdex/eventstore-node.git"
|
"url": "git+https://github.com/nicdex/node-eventstore-client.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"eventstore",
|
"eventstore",
|
||||||
@ -37,19 +55,22 @@
|
|||||||
"author": "Nicolas Dextraze",
|
"author": "Nicolas Dextraze",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/nicdex/eventstore-node/issues"
|
"url": "https://github.com/nicdex/node-eventstore-client/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/nicdex/eventstore-node#readme",
|
"homepage": "https://github.com/nicdex/node-eventstore-client#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/long": "^3.0.31",
|
"@types/node": ">=14",
|
||||||
"@types/node": "^6.0.47",
|
"long": "^5.2.0",
|
||||||
"long": "^3.2",
|
"strict-event-emitter-types": "^1.2.0",
|
||||||
"protobufjs": "^5.0",
|
"uuid": "^9.0.0"
|
||||||
"uuid": "^2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jsdoc": "^3.4.2",
|
"jest": "^29.4.1",
|
||||||
"nodeunit": "^0.10.2",
|
"jsdoc": "^4.0.0",
|
||||||
"webpack": "^1.13.2"
|
"nodeunit": "^0.11.3",
|
||||||
|
"protobufjs": "^7.2.0",
|
||||||
|
"protobufjs-cli": "^1.1.0",
|
||||||
|
"webpack": "^5.75.0",
|
||||||
|
"webpack-cli": "^3.3.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
62
samples/issue-60.js
Normal file
62
samples/issue-60.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
const client = require('../src/client'); // RWM: Import from npm installed package rather than from src
|
||||||
|
//const client = require("node-eventstore-client");
|
||||||
|
|
||||||
|
const resolveLinkTos = true;
|
||||||
|
|
||||||
|
function resumeEvent(event) {
|
||||||
|
return [
|
||||||
|
event.originalEvent.eventType,
|
||||||
|
[event.originalEventNumber.toNumber(), event.originalStreamId].join('@'),
|
||||||
|
event.originalPosition
|
||||||
|
].join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventAppeared = (subscription, event) => console.log("Event received", resumeEvent(event));
|
||||||
|
|
||||||
|
const subscriptionDropped = (subscription, reason, error) => console.log("Subscription dropped", reason, error);
|
||||||
|
|
||||||
|
const libeProcessingStarted = () => console.log("Live processing started.");
|
||||||
|
|
||||||
|
const credentials = new client.UserCredentials("admin", "changeit");
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
maxReconnections: 10,
|
||||||
|
reconnectionDelay: 1000, // RWM: slow down the reconnection attempts. 10 seconds to restore connection.
|
||||||
|
};
|
||||||
|
if (process.env.ENABLE_LOGGING) settings.log = console;
|
||||||
|
if (process.env.VERBOSE) settings.verboseLogging = true;
|
||||||
|
const endpoint = "tcp://localhost:1113";
|
||||||
|
const connection = client.createConnection(settings, endpoint);
|
||||||
|
|
||||||
|
connection.connect().catch(err => console.log("Connection failed", err));
|
||||||
|
|
||||||
|
connection.on('heartbeatInfo', heartbeatInfo =>
|
||||||
|
console.log('Heartbeat latency', heartbeatInfo.responseReceivedAt - heartbeatInfo.requestSentAt, 'ms')
|
||||||
|
);
|
||||||
|
|
||||||
|
connection.once("connected", tcpEndPoint => {
|
||||||
|
console.log(`Connected to eventstore at ${tcpEndPoint.host}:${tcpEndPoint.port}`);
|
||||||
|
// RWM: subscribe Stream instead of All
|
||||||
|
connection.subscribeToStreamFrom(
|
||||||
|
"test", // RWM: Stream to subscribe to
|
||||||
|
null,
|
||||||
|
resolveLinkTos,
|
||||||
|
eventAppeared,
|
||||||
|
libeProcessingStarted,
|
||||||
|
subscriptionDropped,
|
||||||
|
credentials
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on("error", error =>
|
||||||
|
console.log(`Error occurred on connection: ${error}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.on("closed", reason =>
|
||||||
|
console.log(`Connection closed, reason: ${reason}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// RWM: Handle the reconnecting event, for better awareness of what's happening
|
||||||
|
connection.on("reconnecting", msg =>
|
||||||
|
console.log(`Reconnecting, msg: ${JSON.stringify(msg, null, 4)}`)
|
||||||
|
)
|
@ -1,39 +1,55 @@
|
|||||||
var client = require('../src/client');
|
const client = require('../src/client')
|
||||||
var uuid = require('uuid');
|
// const client = require("node-eventstore-client")
|
||||||
|
const uuid = require("uuid")
|
||||||
|
|
||||||
var settings = {
|
const settings = {
|
||||||
verboseLogging: true,
|
verboseLogging: true,
|
||||||
log: new client.FileLogger('./simple-verbose.log')
|
log: new client.FileLogger("./simple-verbose.log")
|
||||||
};
|
}
|
||||||
var gossipSeeds = [
|
/*
|
||||||
new client.GossipSeed({host: '192.168.33.10', port: 2113}),
|
// connecting to Cluster using hard-coded gossip seeds
|
||||||
new client.GossipSeed({host: '192.168.33.11', port: 2113}),
|
const gossipSeeds = [
|
||||||
new client.GossipSeed({host: '192.168.33.12', port: 2113})
|
new client.GossipSeed({host: "192.168.33.10", port: 2113}),
|
||||||
];
|
new client.GossipSeed({host: "192.168.33.11", port: 2113}),
|
||||||
var conn = client.createConnection(settings, gossipSeeds);
|
new client.GossipSeed({host: "192.168.33.12", port: 2113})
|
||||||
conn.connect()
|
]
|
||||||
.catch(function (err) {
|
const connection = client.createConnection(settings, gossipSeeds)
|
||||||
console.log(err);
|
*/
|
||||||
//process.exit(-1);
|
/*
|
||||||
});
|
// connecting to Cluster using dns discovery, note that cluster gossip over external http port not tcp port
|
||||||
conn.on('connected', function (endPoint) {
|
const connection = client.createConnection(settings, 'discover://my.dns:2113')
|
||||||
console.log('connected to endPoint', endPoint);
|
*/
|
||||||
//Start some work
|
const connection = client.createConnection(settings, 'tcp://localhost:1113')
|
||||||
setInterval(function () {
|
|
||||||
conn.appendToStream('test-' + uuid.v4(), client.expectedVersion.noStream, [
|
connection.connect().catch(err => console.log(err))
|
||||||
client.createJsonEventData(uuid.v4(), {abc: 123}, null, 'MyEvent')
|
|
||||||
]).then(function (writeResult) {
|
connection.on("connected", tcpEndPoint => {
|
||||||
console.log(writeResult);
|
console.log(`connected to endPoint ${tcpEndPoint.host}:${tcpEndPoint.port}`)
|
||||||
});
|
|
||||||
}, 1000);
|
setInterval(() => {
|
||||||
});
|
connection.appendToStream(
|
||||||
conn.on('error', function (err) {
|
`test-${uuid.v4()}`,
|
||||||
console.log('Error occurred on connection:', err);
|
client.expectedVersion.noStream,
|
||||||
});
|
[
|
||||||
conn.on('closed', function (reason) {
|
client.createJsonEventData(
|
||||||
console.log('Connection closed, reason:', reason);
|
uuid.v4(),
|
||||||
//process.exit(-1);
|
{ abc: 123 },
|
||||||
});
|
null,
|
||||||
process.stdin.setRawMode(true);
|
"MyEvent"
|
||||||
process.stdin.resume();
|
)
|
||||||
process.stdin.on('data', process.exit.bind(process, 0));
|
]
|
||||||
|
).then(writeResult => console.log(writeResult))
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.on("error", error =>
|
||||||
|
console.log(`Error occurred on connection: ${error}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.on("closed", reason =>
|
||||||
|
console.log(`Connection closed, reason: ${reason}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
process.stdin.setRawMode(true)
|
||||||
|
process.stdin.resume()
|
||||||
|
process.stdin.on("data", process.exit.bind(process, 0))
|
||||||
|
108
samples/speed-tests.js
Normal file
108
samples/speed-tests.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//NOTE: this script require node.js v8+ to run (native async/await)
|
||||||
|
var uuid = require('uuid');
|
||||||
|
var client = require('../src/client');
|
||||||
|
var conn = client.createConnection({}, 'tcp://localhost:1113');
|
||||||
|
conn.on('connected', onConnected);
|
||||||
|
|
||||||
|
var batchSize = parseInt(process.argv[2], 10) || 500;
|
||||||
|
const MB = 1024*1024;
|
||||||
|
const adminCreds = new client.UserCredentials("admin", "changeit");
|
||||||
|
const nbEvents = 50000;
|
||||||
|
const events = [];
|
||||||
|
const streams = [];
|
||||||
|
const writeOneStream = 'testWrite-' + uuid.v4();
|
||||||
|
for(var i = 0; i < nbEvents; i++) {
|
||||||
|
streams.push('testWrite-' + uuid.v4());
|
||||||
|
events.push(client.createJsonEventData(uuid.v4(), {a:i, b:i+1, c:i+2}, null, 'myEvent'))
|
||||||
|
}
|
||||||
|
conn.connect();
|
||||||
|
|
||||||
|
function rssMB() {
|
||||||
|
return (process.memoryUsage().rss / MB).toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reportResult(action, nbEvents, elapsedMs) {
|
||||||
|
console.log(action, nbEvents, 'events took', elapsedMs, 'ms, avg', (nbEvents/(elapsedMs/1000)).toFixed(2), '/s');
|
||||||
|
console.log('Memory usage:', rssMB(), 'MB\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testWriteOneStreamAnyVersion(batchSize) {
|
||||||
|
console.log(`Test Write One Stream Any Version (batchSize = ${batchSize})...`);
|
||||||
|
const start = Date.now();
|
||||||
|
const promises = [];
|
||||||
|
for(let i = 0; i < nbEvents; i += batchSize) {
|
||||||
|
promises.push(conn.appendToStream(writeOneStream, client.expectedVersion.any, events.slice(i, i + batchSize)))
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
var diff = Date.now() - start;
|
||||||
|
reportResult("Writing", nbEvents, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testWriteOneStreamWithVersion(batchSize) {
|
||||||
|
console.log(`Test Write One Stream With Version (batchSize = ${batchSize})...`);
|
||||||
|
const writeStream = 'testWrite-' + uuid.v4();
|
||||||
|
const start = Date.now();
|
||||||
|
const promises = [];
|
||||||
|
for(let i = 0; i < nbEvents; i += batchSize) {
|
||||||
|
promises.push(conn.appendToStream(writeStream, i-1, events.slice(i, i + batchSize)))
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
var diff = Date.now() - start;
|
||||||
|
reportResult("Writing", nbEvents, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testWriteMultipleStream() {
|
||||||
|
console.log('Test Write Multiple Streams...');
|
||||||
|
var start = Date.now();
|
||||||
|
var promises = [];
|
||||||
|
for(var i = 0; i < nbEvents; i++) {
|
||||||
|
promises.push(conn.appendToStream(streams[i], client.expectedVersion.emptyStream, events[i]))
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
const diff = Date.now() - start;
|
||||||
|
reportResult("Writing", nbEvents, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testRead(batchSize) {
|
||||||
|
console.log(`Test Read One Stream (batchSize = ${batchSize})...`);
|
||||||
|
const start = Date.now();
|
||||||
|
const promises = [];
|
||||||
|
for(let i = 0; i < nbEvents; i += batchSize) {
|
||||||
|
promises.push(conn.readStreamEventsForward(writeOneStream, i, batchSize, false));
|
||||||
|
}
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
const diff = Date.now() - start;
|
||||||
|
const readEvents = results.reduce((x,y) => x + y.events.length, 0);
|
||||||
|
reportResult("Reading", readEvents, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testReadAll(batchSize) {
|
||||||
|
console.log(`Test Read from $all (batchSize = ${batchSize})...`);
|
||||||
|
const start = Date.now();
|
||||||
|
let pos = client.positions.start;
|
||||||
|
let eventsCount = 0;
|
||||||
|
for(;;) {
|
||||||
|
var result = await conn.readAllEventsForward(pos, batchSize, false, adminCreds);
|
||||||
|
pos = result.nextPosition;
|
||||||
|
eventsCount += result.events.length;
|
||||||
|
if (result.isEndOfStream) break;
|
||||||
|
}
|
||||||
|
const diff = Date.now() - start;
|
||||||
|
reportResult("Reading", eventsCount, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onConnected() {
|
||||||
|
try {
|
||||||
|
await testWriteOneStreamAnyVersion(1);
|
||||||
|
await testWriteOneStreamAnyVersion(batchSize);
|
||||||
|
await testWriteOneStreamWithVersion(1);
|
||||||
|
await testWriteOneStreamWithVersion(batchSize);
|
||||||
|
await testWriteMultipleStream();
|
||||||
|
await testRead(1);
|
||||||
|
await testRead(batchSize);
|
||||||
|
await testReadAll(batchSize);
|
||||||
|
conn.close();
|
||||||
|
} catch (e) {
|
||||||
|
console.log('ERROR', e);
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +1,53 @@
|
|||||||
var esClient = require('../src/client'); // When running in 'eventstore-node/samples' folder.
|
const client = require('../src/client')
|
||||||
// var esClient = require('eventstore-node'); // Otherwise
|
// const client = require("node-eventstore-client")
|
||||||
var uuid = require('uuid');
|
const uuid = require("uuid")
|
||||||
|
|
||||||
var esConnection = esClient.createConnection({}, {"hostname": "localhost", "port": 1113});
|
const settings = {}
|
||||||
esConnection.connect();
|
const endpoint = "tcp://localhost:1113"
|
||||||
esConnection.once('connected', function (tcpEndPoint) {
|
const connection = client.createConnection(settings, endpoint)
|
||||||
console.log('Connected to eventstore at ' + tcpEndPoint.host + ":" + tcpEndPoint.port);
|
|
||||||
var userId = uuid.v4();
|
|
||||||
// This event could happen as a result of (e.g.) a 'CreateUser(id, username, password)' command.
|
|
||||||
var userCreatedEvent = {
|
|
||||||
id: userId,
|
|
||||||
username: "user" + uuid.v4().substring(0,6), // Hard-to-spell exotic username.
|
|
||||||
password: Math.random().toString() // Hard-to-guess password.
|
|
||||||
};
|
|
||||||
var eventId = uuid.v4();
|
|
||||||
var event = esClient.createJsonEventData(eventId, userCreatedEvent, null, "UserCreated");
|
|
||||||
// Every user has her/his own stream of events:
|
|
||||||
var streamName = "user-" + userId;
|
|
||||||
console.log("Storing event. Look for it at http://localhost:2113/web/index.html#/streams/user-" + userId);
|
|
||||||
esConnection.appendToStream(streamName, esClient.expectedVersion.any, event)
|
|
||||||
.then(function(result) {
|
|
||||||
console.log("Event stored.");
|
|
||||||
process.exit(0);
|
|
||||||
})
|
|
||||||
.catch(function(err) {
|
|
||||||
console.log(err);
|
|
||||||
process.exit(-1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
esConnection.on('error', function (err) {
|
connection.connect().catch(err => console.log(err))
|
||||||
console.log('Error occurred on connection:', err);
|
|
||||||
process.exit(-1);
|
|
||||||
});
|
|
||||||
|
|
||||||
esConnection.on('closed', function (reason) {
|
connection.once("connected", tcpEndPoint => {
|
||||||
console.log('Connection closed, reason:', reason);
|
const userId = uuid.v4()
|
||||||
process.exit(-1);
|
|
||||||
});
|
const userCreatedEvent = {
|
||||||
|
id: userId,
|
||||||
|
username: `user${uuid.v4().substring(0,6)}`,
|
||||||
|
password: Math.random().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventId = uuid.v4();
|
||||||
|
const event = client.createJsonEventData(
|
||||||
|
eventId,
|
||||||
|
userCreatedEvent,
|
||||||
|
null,
|
||||||
|
"UserCreated"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Every user has their own stream of events:
|
||||||
|
const streamName = `user-${userId}`
|
||||||
|
|
||||||
|
console.log(`Connected to eventstore at ${tcpEndPoint.host}:${tcpEndPoint.port}`)
|
||||||
|
console.log(`Storing event ${eventId}. Look for it at http://localhost:2113/web/index.html#/streams/user-${userId}`)
|
||||||
|
|
||||||
|
connection.appendToStream(streamName, client.expectedVersion.any, event)
|
||||||
|
.then(result => {
|
||||||
|
console.log("Event stored.")
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
process.exit(-1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.on("error", error => {
|
||||||
|
console.log(`Error occurred on connection: ${error}`)
|
||||||
|
process.exit(-1)
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.on("closed", reason => {
|
||||||
|
console.log(`Connection closed, reason: ${reason}`)
|
||||||
|
process.exit(-1)
|
||||||
|
})
|
||||||
|
@ -1,48 +1,56 @@
|
|||||||
// Subscribe to all new events on the $all stream. Filter out any which aren't about "user" aggregates.
|
// Subscribe to all new events on the $all stream. Filter out any which aren"t about "user" aggregates.
|
||||||
|
|
||||||
var esClient = require('../src/client'); // When running in 'eventstore-node/samples' folder.
|
const client = require('../src/client')
|
||||||
// var esClient = require('eventstore-node'); // Otherwise
|
// const client = require("node-eventstore-client")
|
||||||
|
|
||||||
const credentialsForAllEventsStream = new esClient.UserCredentials("admin", "changeit");
|
const resolveLinkTos = false
|
||||||
const resolveLinkTos = false;
|
|
||||||
|
|
||||||
var esConnection = esClient.createConnection({}, {"hostname": "localhost", "port": 1113});
|
const belongsToAUserAggregate = event =>
|
||||||
esConnection.connect();
|
event.originalEvent.eventStreamId.startsWith("user-")
|
||||||
esConnection.once('connected', function (tcpEndPoint) {
|
|
||||||
console.log('Connected to eventstore at ' + tcpEndPoint.host + ":" + tcpEndPoint.port);
|
|
||||||
esConnection.subscribeToAll(resolveLinkTos, eventAppeared, subscriptionDropped, credentialsForAllEventsStream)
|
|
||||||
.then(function(subscription) {
|
|
||||||
console.log("subscription.isSubscribedToAll: " + subscription.isSubscribedToAll);
|
|
||||||
console.log("(To generate a test event, try running 'node store-event.js' in a separate console.)")
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function belongsToAUserAggregate(event) {
|
const eventAppeared = (subscription, event) => {
|
||||||
return event.originalEvent.eventStreamId.startsWith("user-")
|
if (belongsToAUserAggregate(event)) {
|
||||||
|
const aggregateId = event.originalEvent.eventStreamId
|
||||||
|
const eventId = event.originalEvent.eventId
|
||||||
|
const eventType = event.originalEvent.eventType
|
||||||
|
console.log(aggregateId, eventType, eventId)
|
||||||
|
console.log(event.originalEvent.data.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventAppeared(subscription, event) {
|
const subscriptionDropped = (subscription, reason, error) =>
|
||||||
// Ignore all events which aren't about users:
|
console.log(error ? error : "Subscription dropped.")
|
||||||
if(belongsToAUserAggregate(event)) {
|
|
||||||
var aggregateId = event.originalEvent.eventStreamId;
|
|
||||||
var eventId = event.originalEvent.eventId;
|
|
||||||
var eventType = event.originalEvent.eventType;
|
|
||||||
console.log(aggregateId, eventType, eventId);
|
|
||||||
console.log(event.originalEvent.data.toString() + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function subscriptionDropped(subscription, reason, error) {
|
const credentials = new client.UserCredentials("admin", "changeit")
|
||||||
if (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
console.log('Subscription dropped.');
|
|
||||||
}
|
|
||||||
|
|
||||||
esConnection.on('error', function (err) {
|
const settings = {}
|
||||||
console.log('Error occurred on connection:', err);
|
const endpoint = "tcp://localhost:1113"
|
||||||
});
|
const connection = client.createConnection(settings, endpoint)
|
||||||
|
|
||||||
esConnection.on('closed', function (reason) {
|
connection.connect().catch(err => console.log(err))
|
||||||
console.log('Connection closed, reason:', reason);
|
|
||||||
});
|
connection.on('heartbeatInfo', heartbeatInfo => {
|
||||||
|
console.log('Connected to endpoint', heartbeatInfo.remoteEndPoint)
|
||||||
|
console.log('Heartbeat latency', heartbeatInfo.responseReceivedAt - heartbeatInfo.requestSentAt)
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.once("connected", tcpEndPoint => {
|
||||||
|
console.log(`Connected to eventstore at ${tcpEndPoint.host}:${tcpEndPoint.port}`)
|
||||||
|
connection.subscribeToAll(
|
||||||
|
resolveLinkTos,
|
||||||
|
eventAppeared,
|
||||||
|
subscriptionDropped,
|
||||||
|
credentials
|
||||||
|
).then(subscription => {
|
||||||
|
console.log(`subscription.isSubscribedToAll: ${subscription.isSubscribedToAll}`),
|
||||||
|
console.log("(To generate a test event, try running 'node store-event.js' in a separate console.)")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.on("error", error =>
|
||||||
|
console.log(`Error occurred on connection: ${error}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.on("closed", reason =>
|
||||||
|
console.log(`Connection closed, reason: ${reason}`)
|
||||||
|
)
|
||||||
|
50
samples/subscribe-all-from-events.js
Normal file
50
samples/subscribe-all-from-events.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
const client = require('../src/client');
|
||||||
|
//const client = require("node-eventstore-client");
|
||||||
|
|
||||||
|
const resolveLinkTos = true;
|
||||||
|
|
||||||
|
function resumeEvent(event) {
|
||||||
|
return [
|
||||||
|
event.originalEvent.eventType,
|
||||||
|
[event.originalEventNumber.toNumber(), event.originalStreamId].join('@'),
|
||||||
|
event.originalPosition
|
||||||
|
].join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventAppeared = (subscription, event) => console.log("Event received", resumeEvent(event));
|
||||||
|
|
||||||
|
const subscriptionDropped = (subscription, reason, error) => console.log("Subscription dropped", reason, error);
|
||||||
|
|
||||||
|
const libeProcessingStarted = () => console.log("Live processing started.");
|
||||||
|
|
||||||
|
const credentials = new client.UserCredentials("admin", "changeit");
|
||||||
|
|
||||||
|
const settings = {};
|
||||||
|
const endpoint = "tcp://localhost:1113";
|
||||||
|
const connection = client.createConnection(settings, endpoint);
|
||||||
|
|
||||||
|
connection.connect().catch(err => console.log("Connection failed", err));
|
||||||
|
|
||||||
|
connection.on('heartbeatInfo', heartbeatInfo =>
|
||||||
|
console.log('Heartbeat latency', heartbeatInfo.responseReceivedAt - heartbeatInfo.requestSentAt, 'ms')
|
||||||
|
);
|
||||||
|
|
||||||
|
connection.once("connected", tcpEndPoint => {
|
||||||
|
console.log(`Connected to eventstore at ${tcpEndPoint.host}:${tcpEndPoint.port}`);
|
||||||
|
connection.subscribeToAllFrom(
|
||||||
|
null,
|
||||||
|
resolveLinkTos,
|
||||||
|
eventAppeared,
|
||||||
|
libeProcessingStarted,
|
||||||
|
subscriptionDropped,
|
||||||
|
credentials
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on("error", error =>
|
||||||
|
console.log(`Error occurred on connection: ${error}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.on("closed", reason =>
|
||||||
|
console.log(`Connection closed, reason: ${reason}`)
|
||||||
|
)
|
@ -1,51 +1,49 @@
|
|||||||
// Subscribe to all events on the $all stream. Catch up from the beginning, then listen for any new events as they occur.
|
// Subscribe to all events on the $all stream. Catch up from the beginning, then listen for any new events as they occur.
|
||||||
// This can be used (e.g.) for subscribers which populate read models.
|
// This could be used for subscribers which populate read models.
|
||||||
|
|
||||||
var esClient = require('../src/client'); // When running in 'eventstore-node/samples' folder.
|
const client = require('../src/client')
|
||||||
// var esClient = require('eventstore-node'); // Otherwise
|
// const client = require("node-eventstore-client")
|
||||||
|
|
||||||
const credentialsForAllEventsStream = new esClient.UserCredentials("admin", "changeit");
|
const eventAppeared = (stream, event) =>
|
||||||
|
console.log(
|
||||||
|
event.originalEvent.eventStreamId,
|
||||||
|
event.originalEvent.eventId,
|
||||||
|
event.originalEvent.eventType
|
||||||
|
)
|
||||||
|
|
||||||
var esConnection = esClient.createConnection({}, {"hostname": "localhost", "port": 1113});
|
const liveProcessingStarted = () => {
|
||||||
esConnection.connect();
|
console.log("Caught up with previously stored events. Listening for new events.")
|
||||||
esConnection.once('connected', function (tcpEndPoint) {
|
console.log("(To generate a test event, try running 'node store-event.js' in a separate console.)")
|
||||||
console.log('Connected to eventstore at ' + tcpEndPoint.host + ":" + tcpEndPoint.port);
|
|
||||||
var subscription = esConnection.subscribeToAllFrom(null, true, eventAppeared, liveProcessingStarted, subscriptionDropped, credentialsForAllEventsStream);
|
|
||||||
console.log("subscription.isSubscribedToAll: " + subscription.isSubscribedToAll);
|
|
||||||
});
|
|
||||||
|
|
||||||
function eventAppeared(subscription, event) {
|
|
||||||
// This is where to filter out events which the subscriber isn't interested in.
|
|
||||||
// For an example, see 'subscribe-all-events.js'.
|
|
||||||
console.log(event.originalEvent.eventStreamId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function subscriptionDropped(subscription, reason, error) {
|
const subscriptionDropped = (subscription, reason, error) =>
|
||||||
if (error) {
|
console.log(error ? error : "Subscription dropped.")
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
console.log('Subscription dropped.');
|
|
||||||
}
|
|
||||||
|
|
||||||
function liveProcessingStarted() {
|
const credentials = new client.UserCredentials("admin", "changeit")
|
||||||
console.log("Caught up with previously stored events. Listening for new events.");
|
|
||||||
console.log("(To generate a test event, try running 'node store-event.js' in a separate console.)")
|
|
||||||
}
|
|
||||||
|
|
||||||
function eventAppeared(stream, event) {
|
const settings = {}
|
||||||
console.log(event.originalEvent.eventStreamId, event.originalEvent.eventId, event.originalEvent.eventType);
|
const endpoint = "tcp://localhost:1113"
|
||||||
// Data:
|
const connection = client.createConnection(settings, endpoint)
|
||||||
// console.log(event.originalEvent.data.toString());
|
|
||||||
|
|
||||||
// Position in the event stream. Can be persisted and used to catch up with missed events when re-starting subscribers instead of re-reading
|
connection.connect().catch(err => console.log(err))
|
||||||
// all events from the beginning.
|
|
||||||
// console.log(event.originalPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
esConnection.on('error', function (err) {
|
connection.once("connected", tcpEndPoint => {
|
||||||
console.log('Error occurred on connection:', err);
|
const subscription = connection.subscribeToAllFrom(
|
||||||
});
|
null,
|
||||||
|
true,
|
||||||
|
eventAppeared,
|
||||||
|
liveProcessingStarted,
|
||||||
|
subscriptionDropped,
|
||||||
|
credentials
|
||||||
|
)
|
||||||
|
console.log(`Connected to eventstore at ${tcpEndPoint.host}:${tcpEndPoint.port}`)
|
||||||
|
console.log(`subscription.isSubscribedToAll: ${subscription.isSubscribedToAll}`)
|
||||||
|
})
|
||||||
|
|
||||||
esConnection.on('closed', function (reason) {
|
connection.on("error", err =>
|
||||||
console.log('Connection closed, reason:', reason);
|
console.log(`Error occurred on connection: ${err}`)
|
||||||
});
|
)
|
||||||
|
|
||||||
|
connection.on("closed", reason =>
|
||||||
|
console.log(`Connection closed, reason: ${reason}`)
|
||||||
|
)
|
||||||
|
@ -4,12 +4,22 @@ var results = require('./results');
|
|||||||
const expectedVersion = {
|
const expectedVersion = {
|
||||||
any: -2,
|
any: -2,
|
||||||
noStream: -1,
|
noStream: -1,
|
||||||
emptyStream: -1
|
emptyStream: -1,
|
||||||
|
streamExists: -4
|
||||||
};
|
};
|
||||||
|
Object.freeze(expectedVersion);
|
||||||
|
|
||||||
const positions = {
|
const positions = {
|
||||||
start: new results.Position(0, 0),
|
start: new results.Position(0, 0),
|
||||||
end: new results.Position(-1, -1)
|
end: new results.Position(-1, -1)
|
||||||
};
|
};
|
||||||
|
Object.freeze(positions);
|
||||||
|
|
||||||
|
const streamPosition = {
|
||||||
|
start: 0,
|
||||||
|
end: -1
|
||||||
|
};
|
||||||
|
Object.freeze(streamPosition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an EventData object from JavaScript event/metadata that will be serialized as json
|
* Create an EventData object from JavaScript event/metadata that will be serialized as json
|
||||||
@ -23,8 +33,8 @@ const positions = {
|
|||||||
function createJsonEventData(eventId, event, metadata, type) {
|
function createJsonEventData(eventId, event, metadata, type) {
|
||||||
if (!event || typeof event !== 'object') throw new TypeError("data must be an object.");
|
if (!event || typeof event !== 'object') throw new TypeError("data must be an object.");
|
||||||
|
|
||||||
var eventBuf = new Buffer(JSON.stringify(event));
|
var eventBuf = Buffer.from(JSON.stringify(event));
|
||||||
var metaBuf = metadata ? new Buffer(JSON.stringify(metadata)) : null;
|
var metaBuf = metadata ? Buffer.from(JSON.stringify(metadata)) : null;
|
||||||
return new EventData(eventId, type || event.constructor.name, true, eventBuf, metaBuf);
|
return new EventData(eventId, type || event.constructor.name, true, eventBuf, metaBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,26 +53,31 @@ function createEventData(eventId, type, isJson, data, metadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Expose classes
|
// Expose classes
|
||||||
module.exports.Position = results.Position;
|
exports.Position = results.Position;
|
||||||
module.exports.UserCredentials = require('./systemData/userCredentials');
|
exports.UserCredentials = require('./systemData/userCredentials');
|
||||||
module.exports.PersistentSubscriptionSettings = require('./persistentSubscriptionSettings');
|
exports.PersistentSubscriptionSettings = require('./persistentSubscriptionSettings');
|
||||||
module.exports.SystemConsumerStrategies = require('./systemConsumerStrategies');
|
exports.SystemConsumerStrategies = require('./systemConsumerStrategies');
|
||||||
module.exports.GossipSeed = require('./gossipSeed');
|
exports.GossipSeed = require('./gossipSeed');
|
||||||
module.exports.EventStoreConnection = require('./eventStoreConnection');
|
exports.EventStoreConnection = require('./eventStoreConnection');
|
||||||
|
exports.ProjectionsManager = require('./projections/projectionsManager');
|
||||||
// Expose errors
|
// Expose errors
|
||||||
module.exports.WrongExpectedVersionError = require('./errors/wrongExpectedVersionError');
|
exports.WrongExpectedVersionError = require('./errors/wrongExpectedVersionError');
|
||||||
module.exports.StreamDeletedError = require('./errors/streamDeletedError');
|
exports.StreamDeletedError = require('./errors/streamDeletedError');
|
||||||
module.exports.AccessDeniedError = require('./errors/accessDeniedError');
|
exports.AccessDeniedError = require('./errors/accessDeniedError');
|
||||||
|
exports.ProjectionCommandFailedError = require('./errors/projectionCommandFailedError');
|
||||||
// Expose enums/constants
|
// Expose enums/constants
|
||||||
module.exports.expectedVersion = expectedVersion;
|
exports.expectedVersion = expectedVersion;
|
||||||
module.exports.positions = positions;
|
exports.positions = positions;
|
||||||
module.exports.systemMetadata = require('./common/systemMetadata');
|
exports.streamPosition = streamPosition;
|
||||||
module.exports.eventReadStatus = results.EventReadStatus;
|
exports.systemMetadata = require('./common/systemMetadata');
|
||||||
module.exports.sliceReadStatus = require('./sliceReadStatus');
|
exports.eventReadStatus = results.EventReadStatus;
|
||||||
|
exports.sliceReadStatus = require('./sliceReadStatus');
|
||||||
|
exports.persistentSubscriptionNakEventAction =
|
||||||
|
exports.PersistentSubscriptionNakEventAction = require('./persistentSubscriptionNakEventAction');
|
||||||
// Expose loggers
|
// Expose loggers
|
||||||
module.exports.NoopLogger = require('./common/log/noopLogger');
|
exports.NoopLogger = require('./common/log/noopLogger');
|
||||||
module.exports.FileLogger = require('./common/log/fileLogger');
|
exports.FileLogger = require('./common/log/fileLogger');
|
||||||
// Expose Helper functions
|
// Expose Helper functions
|
||||||
module.exports.createConnection = require('./eventStoreConnection').create;
|
exports.createConnection = require('./eventStoreConnection').create;
|
||||||
module.exports.createJsonEventData = createJsonEventData;
|
exports.createJsonEventData = createJsonEventData;
|
||||||
module.exports.createEventData = createEventData;
|
exports.createEventData = createEventData;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
var guidParse = require('../common/guid-parse');
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||||
@ -26,25 +26,25 @@ util.inherits(AppendToStreamOperation, OperationBase);
|
|||||||
|
|
||||||
AppendToStreamOperation.prototype._createRequestDto = function() {
|
AppendToStreamOperation.prototype._createRequestDto = function() {
|
||||||
var dtos = this._events.map(function(ev) {
|
var dtos = this._events.map(function(ev) {
|
||||||
var eventId = new Buffer(uuid.parse(ev.eventId));
|
var eventId = guidParse.parse(ev.eventId);
|
||||||
return new ClientMessage.NewEvent({
|
return {
|
||||||
event_id: eventId, event_type: ev.type,
|
eventId: eventId, eventType: ev.type,
|
||||||
data_content_type: ev.isJson ? 1 : 0, metadata_content_type: 0,
|
dataContentType: ev.isJson ? 1 : 0, metadataContentType: 0,
|
||||||
data: ev.data, metadata: ev.metadata});
|
data: ev.data, metadata: ev.metadata
|
||||||
|
};
|
||||||
});
|
});
|
||||||
return new ClientMessage.WriteEvents({
|
return new ClientMessage.WriteEvents({
|
||||||
event_stream_id: this._stream,
|
eventStreamId: this._stream,
|
||||||
expected_version: this._expectedVersion,
|
expectedVersion: this._expectedVersion,
|
||||||
events: dtos,
|
events: dtos,
|
||||||
require_master: this._requireMaster});
|
requireLeader: this._requireMaster});
|
||||||
};
|
};
|
||||||
|
|
||||||
AppendToStreamOperation.prototype._inspectResponse = function(response) {
|
AppendToStreamOperation.prototype._inspectResponse = function(response) {
|
||||||
switch (response.result)
|
switch (response.result)
|
||||||
{
|
{
|
||||||
case ClientMessage.OperationResult.Success:
|
case ClientMessage.OperationResult.Success:
|
||||||
if (this._wasCommitTimeout)
|
if (this._wasCommitTimeout) this.log.debug("IDEMPOTENT WRITE SUCCEEDED FOR %s.", this);
|
||||||
this.log.debug("IDEMPOTENT WRITE SUCCEEDED FOR %s.", this);
|
|
||||||
this._succeed();
|
this._succeed();
|
||||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||||
case ClientMessage.OperationResult.PrepareTimeout:
|
case ClientMessage.OperationResult.PrepareTimeout:
|
||||||
@ -72,7 +72,7 @@ AppendToStreamOperation.prototype._inspectResponse = function(response) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AppendToStreamOperation.prototype._transformResponse = function(response) {
|
AppendToStreamOperation.prototype._transformResponse = function(response) {
|
||||||
return new WriteResult(response.last_event_number, new Position(response.prepare_position || -1, response.commit_position || -1));
|
return new WriteResult(response.lastEventNumber, new Position(response.preparePosition || -1, response.commitPosition || -1));
|
||||||
};
|
};
|
||||||
|
|
||||||
AppendToStreamOperation.prototype.toString = function() {
|
AppendToStreamOperation.prototype.toString = function() {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||||
@ -23,7 +22,10 @@ function CommitTransactionOperation(log, cb, requireMaster, transactionId, userC
|
|||||||
util.inherits(CommitTransactionOperation, OperationBase);
|
util.inherits(CommitTransactionOperation, OperationBase);
|
||||||
|
|
||||||
CommitTransactionOperation.prototype._createRequestDto = function() {
|
CommitTransactionOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.TransactionCommit(this._transactionId, this._requireMaster);
|
return new ClientMessage.TransactionCommit({
|
||||||
|
transactionId: this._transactionId,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
CommitTransactionOperation.prototype._inspectResponse = function(response) {
|
CommitTransactionOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -56,12 +58,12 @@ CommitTransactionOperation.prototype._inspectResponse = function(response) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CommitTransactionOperation.prototype._transformResponse = function(response) {
|
CommitTransactionOperation.prototype._transformResponse = function(response) {
|
||||||
var logPosition = new results.Position(response.prepare_position || -1, response.commit_position || -1);
|
var logPosition = new results.Position(response.preparePosition || -1, response.commitPosition || -1);
|
||||||
return new results.WriteResult(response.last_event_number, logPosition);
|
return new results.WriteResult(response.lastEventNumber, logPosition);
|
||||||
};
|
};
|
||||||
|
|
||||||
CommitTransactionOperation.prototype.toString = function() {
|
CommitTransactionOperation.prototype.toString = function() {
|
||||||
return util.format("TransactionId: %s", this._transactionId);
|
return util.format("TransactionId: %s", this._transactionId);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = CommitTransactionOperation;
|
module.exports = CommitTransactionOperation;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
var guidParse = require('../common/guid-parse');
|
||||||
|
|
||||||
var SubscriptionOperation = require('./subscriptionOperation');
|
var SubscriptionOperation = require('./subscriptionOperation');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
@ -27,21 +27,25 @@ function ConnectToPersistentSubscriptionOperation(
|
|||||||
util.inherits(ConnectToPersistentSubscriptionOperation, SubscriptionOperation);
|
util.inherits(ConnectToPersistentSubscriptionOperation, SubscriptionOperation);
|
||||||
|
|
||||||
ConnectToPersistentSubscriptionOperation.prototype._createSubscriptionPackage = function() {
|
ConnectToPersistentSubscriptionOperation.prototype._createSubscriptionPackage = function() {
|
||||||
var dto = new ClientMessage.ConnectToPersistentSubscription(this._groupName, this._streamId, this._bufferSize);
|
var dto = new ClientMessage.ConnectToPersistentSubscription({
|
||||||
|
subscriptionId: this._groupName,
|
||||||
|
eventStreamId: this._streamId,
|
||||||
|
allowedInFlightMessages: this._bufferSize
|
||||||
|
});
|
||||||
return new TcpPackage(TcpCommand.ConnectToPersistentSubscription,
|
return new TcpPackage(TcpCommand.ConnectToPersistentSubscription,
|
||||||
this._userCredentials !== null ? TcpFlags.Authenticated : TcpFlags.None,
|
this._userCredentials !== null ? TcpFlags.Authenticated : TcpFlags.None,
|
||||||
this._correlationId,
|
this._correlationId,
|
||||||
this._userCredentials !== null ? this._userCredentials.username : null,
|
this._userCredentials !== null ? this._userCredentials.username : null,
|
||||||
this._userCredentials !== null ? this._userCredentials.password : null,
|
this._userCredentials !== null ? this._userCredentials.password : null,
|
||||||
createBufferSegment(dto.toBuffer()));
|
createBufferSegment(ClientMessage.ConnectToPersistentSubscription.encode(dto).finish()));
|
||||||
};
|
};
|
||||||
|
|
||||||
ConnectToPersistentSubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
ConnectToPersistentSubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
||||||
if (pkg.command === TcpCommand.PersistentSubscriptionConfirmation)
|
if (pkg.command === TcpCommand.PersistentSubscriptionConfirmation)
|
||||||
{
|
{
|
||||||
var dto = ClientMessage.PersistentSubscriptionConfirmation.decode(pkg.data.toBuffer());
|
var dto = ClientMessage.PersistentSubscriptionConfirmation.decode(pkg.data.toBuffer());
|
||||||
this._confirmSubscription(dto.last_commit_position, dto.last_event_number);
|
this._confirmSubscription(dto.lastCommitPosition, dto.lastEventNumber);
|
||||||
this._subscriptionId = dto.subscription_id;
|
this._subscriptionId = dto.subscriptionId;
|
||||||
return new InspectionResult(InspectionDecision.Subscribed, "SubscriptionConfirmation");
|
return new InspectionResult(InspectionDecision.Subscribed, "SubscriptionConfirmation");
|
||||||
}
|
}
|
||||||
if (pkg.command === TcpCommand.PersistentSubscriptionStreamEventAppeared)
|
if (pkg.command === TcpCommand.PersistentSubscriptionStreamEventAppeared)
|
||||||
@ -86,9 +90,9 @@ ConnectToPersistentSubscriptionOperation.prototype._createSubscriptionObject = f
|
|||||||
ConnectToPersistentSubscriptionOperation.prototype.notifyEventsProcessed = function(processedEvents) {
|
ConnectToPersistentSubscriptionOperation.prototype.notifyEventsProcessed = function(processedEvents) {
|
||||||
ensure.notNull(processedEvents, "processedEvents");
|
ensure.notNull(processedEvents, "processedEvents");
|
||||||
var dto = new ClientMessage.PersistentSubscriptionAckEvents({
|
var dto = new ClientMessage.PersistentSubscriptionAckEvents({
|
||||||
subscription_id: this._subscriptionId,
|
subscriptionId: this._subscriptionId,
|
||||||
processed_event_ids: processedEvents.map(function (x) {
|
processedEventIds: processedEvents.map(function (x) {
|
||||||
return new Buffer(uuid.parse(x));
|
return guidParse.parse(x);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -97,26 +101,27 @@ ConnectToPersistentSubscriptionOperation.prototype.notifyEventsProcessed = funct
|
|||||||
this._correlationId,
|
this._correlationId,
|
||||||
this._userCredentials !== null ? this._userCredentials.username : null,
|
this._userCredentials !== null ? this._userCredentials.username : null,
|
||||||
this._userCredentials !== null ? this._userCredentials.password : null,
|
this._userCredentials !== null ? this._userCredentials.password : null,
|
||||||
createBufferSegment(dto.encode().toBuffer()));
|
createBufferSegment(ClientMessage.PersistentSubscriptionAckEvents.encode(dto).finish()));
|
||||||
this._enqueueSend(pkg);
|
this._enqueueSend(pkg);
|
||||||
};
|
};
|
||||||
|
|
||||||
ConnectToPersistentSubscriptionOperation.prototype.notifyEventsFailed = function(processedEvents, action, reason) {
|
ConnectToPersistentSubscriptionOperation.prototype.notifyEventsFailed = function(processedEvents, action, reason) {
|
||||||
ensure.notNull(processedEvents, "processedEvents");
|
ensure.notNull(processedEvents, "processedEvents");
|
||||||
ensure.notNull(reason, "reason");
|
ensure.notNull(reason, "reason");
|
||||||
var dto = new ClientMessage.PersistentSubscriptionNakEvents(
|
var dto = new ClientMessage.PersistentSubscriptionNakEvents({
|
||||||
this._subscriptionId,
|
subscriptionId: this._subscriptionId,
|
||||||
processedEvents.map(function(x) { return new Buffer(uuid.parse(x)); }),
|
processedEventIds: processedEvents.map(function(x) { return guidParse.parse(x); }),
|
||||||
reason,
|
message: reason,
|
||||||
action);
|
action: action
|
||||||
|
});
|
||||||
|
|
||||||
var pkg = new TcpPackage(TcpCommand.PersistentSubscriptionNakEvents,
|
var pkg = new TcpPackage(TcpCommand.PersistentSubscriptionNakEvents,
|
||||||
this._userCredentials !== null ? TcpFlags.Authenticated : TcpFlags.None,
|
this._userCredentials !== null ? TcpFlags.Authenticated : TcpFlags.None,
|
||||||
this._correlationId,
|
this._correlationId,
|
||||||
this._userCredentials !== null ? this._userCredentials.username : null,
|
this._userCredentials !== null ? this._userCredentials.username : null,
|
||||||
this._userCredentials !== null ? this._userCredentials.password : null,
|
this._userCredentials !== null ? this._userCredentials.password : null,
|
||||||
createBufferSegment(dto.toBuffer()));
|
createBufferSegment(ClientMessage.PersistentSubscriptionNakEvents.encode(dto).finish()));
|
||||||
this._enqueueSend(pkg);
|
this._enqueueSend(pkg);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ConnectToPersistentSubscriptionOperation;
|
module.exports = ConnectToPersistentSubscriptionOperation;
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var ensure = require('../common/utils/ensure');
|
var ensure = require('../common/utils/ensure');
|
||||||
var OperationBase = require('../clientOperations/operationBase');
|
var OperationBase = require('../clientOperations/operationBase');
|
||||||
@ -36,11 +35,24 @@ function CreatePersistentSubscriptionOperation(log, cb, stream, groupName, setti
|
|||||||
util.inherits(CreatePersistentSubscriptionOperation, OperationBase);
|
util.inherits(CreatePersistentSubscriptionOperation, OperationBase);
|
||||||
|
|
||||||
CreatePersistentSubscriptionOperation.prototype._createRequestDto = function() {
|
CreatePersistentSubscriptionOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.CreatePersistentSubscription(this._groupName, this._stream, this._resolveLinkTos,
|
return new ClientMessage.CreatePersistentSubscription({
|
||||||
this._startFromBeginning, this._messageTimeoutMilliseconds, this._recordStatistics, this._liveBufferSize,
|
subscriptionGroupName: this._groupName,
|
||||||
this._readBatchSize, this._bufferSize, this._maxRetryCount,
|
eventStreamId: this._stream,
|
||||||
this._namedConsumerStrategy === SystemConsumerStrategies.RoundRobin, this._checkPointAfter,
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
this._maxCheckPointCount, this._minCheckPointCount, this._maxSubscriberCount, this._namedConsumerStrategy);
|
startFrom: this._startFromBeginning,
|
||||||
|
messageTimeoutMilliseconds: this._messageTimeoutMilliseconds,
|
||||||
|
recordStatistics: this._recordStatistics,
|
||||||
|
liveBufferSize: this._liveBufferSize,
|
||||||
|
readBatchSize: this._readBatchSize,
|
||||||
|
bufferSize: this._bufferSize,
|
||||||
|
maxRetryCount: this._maxRetryCount,
|
||||||
|
preferRoundRobin: this._namedConsumerStrategy === SystemConsumerStrategies.RoundRobin,
|
||||||
|
checkpointAfterTime: this._checkPointAfter,
|
||||||
|
checkpointMaxCount: this._maxCheckPointCount,
|
||||||
|
checkpointMinCount: this._minCheckPointCount,
|
||||||
|
subscriberMaxCount: this._maxSubscriberCount,
|
||||||
|
namedConsumerStrategy: this._namedConsumerStrategy
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
CreatePersistentSubscriptionOperation.prototype._inspectResponse = function(response) {
|
CreatePersistentSubscriptionOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -71,4 +83,4 @@ CreatePersistentSubscriptionOperation.prototype.toString = function() {
|
|||||||
return util.format("Stream: %s, Group Name: %s", this._stream, this._groupName);
|
return util.format("Stream: %s, Group Name: %s", this._stream, this._groupName);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = CreatePersistentSubscriptionOperation;
|
module.exports = CreatePersistentSubscriptionOperation;
|
@ -1,7 +1,5 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var ensure = require('../common/utils/ensure');
|
|
||||||
var OperationBase = require('../clientOperations/operationBase');
|
var OperationBase = require('../clientOperations/operationBase');
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
@ -21,7 +19,10 @@ function DeletePersistentSubscriptionOperation(log, cb, stream, groupName, userC
|
|||||||
util.inherits(DeletePersistentSubscriptionOperation, OperationBase);
|
util.inherits(DeletePersistentSubscriptionOperation, OperationBase);
|
||||||
|
|
||||||
DeletePersistentSubscriptionOperation.prototype._createRequestDto = function() {
|
DeletePersistentSubscriptionOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.DeletePersistentSubscription(this._groupName, this._stream);
|
return new ClientMessage.DeletePersistentSubscription({
|
||||||
|
subscriptionGroupName: this._groupName,
|
||||||
|
eventStreamId: this._stream
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
DeletePersistentSubscriptionOperation.prototype._inspectResponse = function(response) {
|
DeletePersistentSubscriptionOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -52,4 +53,4 @@ DeletePersistentSubscriptionOperation.prototype.toString = function() {
|
|||||||
return util.format("Stream: %s, Group Name: %s", this._stream, this._groupName);
|
return util.format("Stream: %s, Group Name: %s", this._stream, this._groupName);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = DeletePersistentSubscriptionOperation;
|
module.exports = DeletePersistentSubscriptionOperation;
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||||
@ -25,7 +24,12 @@ function DeleteStreamOperation(log, cb, requireMaster, stream, expectedVersion,
|
|||||||
util.inherits(DeleteStreamOperation, OperationBase);
|
util.inherits(DeleteStreamOperation, OperationBase);
|
||||||
|
|
||||||
DeleteStreamOperation.prototype._createRequestDto = function() {
|
DeleteStreamOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.DeleteStream(this._stream, this._expectedVersion, this._requireMaster, this._hardDelete);
|
return new ClientMessage.DeleteStream({
|
||||||
|
eventStreamId: this._stream,
|
||||||
|
expectedVersion: this._expectedVersion,
|
||||||
|
requireLeader: this._requireMaster,
|
||||||
|
hardDelete: this._hardDelete
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
DeleteStreamOperation.prototype._inspectResponse = function(response) {
|
DeleteStreamOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -58,11 +62,11 @@ DeleteStreamOperation.prototype._inspectResponse = function(response) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
DeleteStreamOperation.prototype._transformResponse = function(response) {
|
DeleteStreamOperation.prototype._transformResponse = function(response) {
|
||||||
return new results.DeleteResult(new results.Position(response.prepare_position || -1, response.commit_position || -1));
|
return new results.DeleteResult(new results.Position(response.preparePosition || -1, response.commitPosition || -1));
|
||||||
};
|
};
|
||||||
|
|
||||||
DeleteStreamOperation.prototype.toString = function() {
|
DeleteStreamOperation.prototype.toString = function() {
|
||||||
return util.format("Stream: %s, ExpectedVersion: %s.", this._stream, this._expectedVersion);
|
return util.format("Stream: %s, ExpectedVersion: %s.", this._stream, this._expectedVersion);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = DeleteStreamOperation;
|
module.exports = DeleteStreamOperation;
|
||||||
|
@ -42,16 +42,17 @@ OperationBase.prototype._succeed = function() {
|
|||||||
if (!this._completed) {
|
if (!this._completed) {
|
||||||
this._completed = true;
|
this._completed = true;
|
||||||
|
|
||||||
if (this._response)
|
if (this._response) {
|
||||||
this._cb(null, this._transformResponse(this._response));
|
this._cb(null, this._transformResponse(this._response));
|
||||||
else
|
} else {
|
||||||
this._cb(new Error("No result."))
|
this._cb(new Error("No result."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
OperationBase.prototype.createNetworkPackage = function(correlationId) {
|
OperationBase.prototype.createNetworkPackage = function(correlationId) {
|
||||||
var dto = this._createRequestDto();
|
var dto = this._createRequestDto();
|
||||||
var buf = dto.toBuffer();
|
var buf = dto.constructor.encode(dto).finish();
|
||||||
return new TcpPackage(
|
return new TcpPackage(
|
||||||
this._requestCommand,
|
this._requestCommand,
|
||||||
this.userCredentials ? TcpFlags.Authenticated : TcpFlags.None,
|
this.userCredentials ? TcpFlags.Authenticated : TcpFlags.None,
|
||||||
@ -116,11 +117,11 @@ OperationBase.prototype._inspectNotHandled = function(pkg)
|
|||||||
case ClientMessage.NotHandled.NotHandledReason.TooBusy:
|
case ClientMessage.NotHandled.NotHandledReason.TooBusy:
|
||||||
return new InspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy");
|
return new InspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy");
|
||||||
|
|
||||||
case ClientMessage.NotHandled.NotHandledReason.NotMaster:
|
case ClientMessage.NotHandled.NotHandledReason.NotLeader:
|
||||||
var masterInfo = ClientMessage.NotHandled.MasterInfo.decode(message.additional_info);
|
var masterInfo = ClientMessage.NotHandled.LeaderInfo.decode(message.additionalInfo);
|
||||||
return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotMaster",
|
return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotLeader",
|
||||||
{host: masterInfo.external_tcp_address, port: masterInfo.external_tcp_port},
|
{host: masterInfo.externalTcpAddress, port: masterInfo.externalTcpPort},
|
||||||
{host: masterInfo.external_secure_tcp_address, port: masterInfo.external_secure_tcp_port});
|
{host: masterInfo.externalSecureTcpAddress, port: masterInfo.externalSecureTcpPort});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.log.error("Unknown NotHandledReason: %s.", message.reason);
|
this.log.error("Unknown NotHandledReason: %s.", message.reason);
|
||||||
@ -130,8 +131,7 @@ OperationBase.prototype._inspectNotHandled = function(pkg)
|
|||||||
|
|
||||||
OperationBase.prototype._inspectUnexpectedCommand = function(pkg, expectedCommand)
|
OperationBase.prototype._inspectUnexpectedCommand = function(pkg, expectedCommand)
|
||||||
{
|
{
|
||||||
if (pkg.command === expectedCommand)
|
if (pkg.command === expectedCommand) throw new Error("Command shouldn't be " + TcpCommand.getName(pkg.command));
|
||||||
throw new Error("Command shouldn't be " + TcpCommand.getName(pkg.command));
|
|
||||||
|
|
||||||
this.log.error("Unexpected TcpCommand received.\n"
|
this.log.error("Unexpected TcpCommand received.\n"
|
||||||
+ "Expected: %s, Actual: %s, Flags: %s, CorrelationId: %s\n"
|
+ "Expected: %s, Actual: %s, Flags: %s, CorrelationId: %s\n"
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
@ -25,7 +24,13 @@ function ReadAllEventsBackwardOperation(
|
|||||||
util.inherits(ReadAllEventsBackwardOperation, OperationBase);
|
util.inherits(ReadAllEventsBackwardOperation, OperationBase);
|
||||||
|
|
||||||
ReadAllEventsBackwardOperation.prototype._createRequestDto = function() {
|
ReadAllEventsBackwardOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.ReadAllEvents(this._position.commitPosition, this._position.preparePosition, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
return new ClientMessage.ReadAllEvents({
|
||||||
|
commitPosition: this._position.commitPosition,
|
||||||
|
preparePosition: this._position.preparePosition,
|
||||||
|
maxCount: this._maxCount,
|
||||||
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadAllEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
ReadAllEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -48,8 +53,8 @@ ReadAllEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
|||||||
ReadAllEventsBackwardOperation.prototype._transformResponse = function(response) {
|
ReadAllEventsBackwardOperation.prototype._transformResponse = function(response) {
|
||||||
return new results.AllEventsSlice(
|
return new results.AllEventsSlice(
|
||||||
ReadDirection.Backward,
|
ReadDirection.Backward,
|
||||||
new results.Position(response.commit_position, response.prepare_position),
|
new results.Position(response.commitPosition, response.preparePosition),
|
||||||
new results.Position(response.next_commit_position, response.next_prepare_position),
|
new results.Position(response.nextCommitPosition, response.nextPreparePosition),
|
||||||
response.events
|
response.events
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
@ -25,7 +24,13 @@ function ReadAllEventsForwardOperation(
|
|||||||
util.inherits(ReadAllEventsForwardOperation, OperationBase);
|
util.inherits(ReadAllEventsForwardOperation, OperationBase);
|
||||||
|
|
||||||
ReadAllEventsForwardOperation.prototype._createRequestDto = function() {
|
ReadAllEventsForwardOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.ReadAllEvents(this._position.commitPosition, this._position.preparePosition, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
return new ClientMessage.ReadAllEvents({
|
||||||
|
commitPosition: this._position.commitPosition,
|
||||||
|
preparePosition: this._position.preparePosition,
|
||||||
|
maxCount: this._maxCount,
|
||||||
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadAllEventsForwardOperation.prototype._inspectResponse = function(response) {
|
ReadAllEventsForwardOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -48,8 +53,8 @@ ReadAllEventsForwardOperation.prototype._inspectResponse = function(response) {
|
|||||||
ReadAllEventsForwardOperation.prototype._transformResponse = function(response) {
|
ReadAllEventsForwardOperation.prototype._transformResponse = function(response) {
|
||||||
return new results.AllEventsSlice(
|
return new results.AllEventsSlice(
|
||||||
ReadDirection.Forward,
|
ReadDirection.Forward,
|
||||||
new results.Position(response.commit_position, response.prepare_position),
|
new results.Position(response.commitPosition, response.preparePosition),
|
||||||
new results.Position(response.next_commit_position, response.next_prepare_position),
|
new results.Position(response.nextCommitPosition, response.nextPreparePosition),
|
||||||
response.events
|
response.events
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,12 @@ function ReadEventOperation(log, cb, stream, eventNumber, resolveLinkTos, requir
|
|||||||
util.inherits(ReadEventOperation, OperationBase);
|
util.inherits(ReadEventOperation, OperationBase);
|
||||||
|
|
||||||
ReadEventOperation.prototype._createRequestDto = function() {
|
ReadEventOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.ReadEvent(this._stream, this._eventNumber, this._resolveLinkTos, this._requireMaster);
|
return new ClientMessage.ReadEvent({
|
||||||
|
eventStreamId: this._stream,
|
||||||
|
eventNumber: this._eventNumber,
|
||||||
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadEventOperation.prototype._inspectResponse = function(response) {
|
ReadEventOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -54,7 +59,6 @@ ReadEventOperation.prototype._transformResponse = function(response) {
|
|||||||
return new results.EventReadResult(convert(response.result), this._stream, this._eventNumber, response.event);
|
return new results.EventReadResult(convert(response.result), this._stream, this._eventNumber, response.event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function convert(result)
|
function convert(result)
|
||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
@ -27,7 +26,13 @@ function ReadStreamEventsBackwardOperation(
|
|||||||
util.inherits(ReadStreamEventsBackwardOperation, OperationBase);
|
util.inherits(ReadStreamEventsBackwardOperation, OperationBase);
|
||||||
|
|
||||||
ReadStreamEventsBackwardOperation.prototype._createRequestDto = function() {
|
ReadStreamEventsBackwardOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.ReadStreamEvents(this._stream, this._fromEventNumber, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
return new ClientMessage.ReadStreamEvents({
|
||||||
|
eventStreamId: this._stream,
|
||||||
|
fromEventNumber: this._fromEventNumber,
|
||||||
|
maxCount: this._maxCount,
|
||||||
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadStreamEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
ReadStreamEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -60,9 +65,9 @@ ReadStreamEventsBackwardOperation.prototype._transformResponse = function(respon
|
|||||||
this._fromEventNumber,
|
this._fromEventNumber,
|
||||||
ReadDirection.Backward,
|
ReadDirection.Backward,
|
||||||
response.events,
|
response.events,
|
||||||
response.next_event_number,
|
response.nextEventNumber,
|
||||||
response.last_event_number,
|
response.lastEventNumber,
|
||||||
response.is_end_of_stream
|
response.isEndOfStream
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
@ -27,7 +26,13 @@ function ReadStreamEventsForwardOperation(
|
|||||||
util.inherits(ReadStreamEventsForwardOperation, OperationBase);
|
util.inherits(ReadStreamEventsForwardOperation, OperationBase);
|
||||||
|
|
||||||
ReadStreamEventsForwardOperation.prototype._createRequestDto = function() {
|
ReadStreamEventsForwardOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.ReadStreamEvents(this._stream, this._fromEventNumber, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
return new ClientMessage.ReadStreamEvents({
|
||||||
|
eventStreamId: this._stream,
|
||||||
|
fromEventNumber: this._fromEventNumber,
|
||||||
|
maxCount: this._maxCount,
|
||||||
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ReadStreamEventsForwardOperation.prototype._inspectResponse = function(response) {
|
ReadStreamEventsForwardOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -60,9 +65,9 @@ ReadStreamEventsForwardOperation.prototype._transformResponse = function(respons
|
|||||||
this._fromEventNumber,
|
this._fromEventNumber,
|
||||||
ReadDirection.Forward,
|
ReadDirection.Forward,
|
||||||
response.events,
|
response.events,
|
||||||
response.next_event_number,
|
response.nextEventNumber,
|
||||||
response.last_event_number,
|
response.lastEventNumber,
|
||||||
response.is_end_of_stream
|
response.isEndOfStream
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||||
var InspectionResult = require('./../systemData/inspectionResult');
|
var InspectionResult = require('./../systemData/inspectionResult');
|
||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
var EventStoreTransaction = require('../eventStoreTransaction');
|
var EventStoreTransaction = require('../eventStoreTransaction');
|
||||||
var results = require('../results');
|
|
||||||
var AccessDeniedError = require('../errors/accessDeniedError');
|
var AccessDeniedError = require('../errors/accessDeniedError');
|
||||||
var WrongExpectedVersionError = require('../errors/wrongExpectedVersionError');
|
var WrongExpectedVersionError = require('../errors/wrongExpectedVersionError');
|
||||||
var StreamDeletedError = require('../errors/streamDeletedError');
|
var StreamDeletedError = require('../errors/streamDeletedError');
|
||||||
@ -24,7 +22,11 @@ function StartTransactionOperation(log, cb, requireMaster, stream, expectedVersi
|
|||||||
util.inherits(StartTransactionOperation, OperationBase);
|
util.inherits(StartTransactionOperation, OperationBase);
|
||||||
|
|
||||||
StartTransactionOperation.prototype._createRequestDto = function() {
|
StartTransactionOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.TransactionStart(this._stream, this._expectedVersion, this._requireMaster);
|
return new ClientMessage.TransactionStart({
|
||||||
|
eventStreamId: this._stream,
|
||||||
|
expectedVersion: this._expectedVersion,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
StartTransactionOperation.prototype._inspectResponse = function(response) {
|
StartTransactionOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -57,7 +59,7 @@ StartTransactionOperation.prototype._inspectResponse = function(response) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
StartTransactionOperation.prototype._transformResponse = function(response) {
|
StartTransactionOperation.prototype._transformResponse = function(response) {
|
||||||
return new EventStoreTransaction(response.transaction_id, this.userCredentials, this._parentConnection);
|
return new EventStoreTransaction(response.transactionId, this.userCredentials, this._parentConnection);
|
||||||
};
|
};
|
||||||
|
|
||||||
StartTransactionOperation.prototype.toString = function() {
|
StartTransactionOperation.prototype.toString = function() {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var TcpFlags = require('../systemData/tcpFlags');
|
var TcpFlags = require('../systemData/tcpFlags');
|
||||||
@ -46,8 +45,7 @@ SubscriptionOperation.prototype._enqueueSend = function(pkg) {
|
|||||||
SubscriptionOperation.prototype.subscribe = function(correlationId, connection) {
|
SubscriptionOperation.prototype.subscribe = function(correlationId, connection) {
|
||||||
if (connection === null) throw new TypeError("connection is null.");
|
if (connection === null) throw new TypeError("connection is null.");
|
||||||
|
|
||||||
if (this._subscription !== null || this._unsubscribed)
|
if (this._subscription !== null || this._unsubscribed) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
this._correlationId = correlationId;
|
this._correlationId = correlationId;
|
||||||
connection.enqueueSend(this._createSubscriptionPackage());
|
connection.enqueueSend(this._createSubscriptionPackage());
|
||||||
@ -64,7 +62,7 @@ SubscriptionOperation.prototype.unsubscribe = function() {
|
|||||||
|
|
||||||
SubscriptionOperation.prototype._createUnsubscriptionPackage = function() {
|
SubscriptionOperation.prototype._createUnsubscriptionPackage = function() {
|
||||||
var msg = new ClientMessage.UnsubscribeFromStream();
|
var msg = new ClientMessage.UnsubscribeFromStream();
|
||||||
var data = new BufferSegment(msg.toBuffer());
|
var data = new BufferSegment(ClientMessage.UnsubscribeFromStream.encode(msg).finish());
|
||||||
return new TcpPackage(TcpCommand.UnsubscribeFromStream, TcpFlags.None, this._correlationId, null, null, data);
|
return new TcpPackage(TcpCommand.UnsubscribeFromStream, TcpFlags.None, this._correlationId, null, null, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,9 +74,7 @@ SubscriptionOperation.prototype.inspectPackage = function(pkg) {
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = this._inspectPackage(pkg);
|
var result = this._inspectPackage(pkg);
|
||||||
if (result !== null) {
|
if (result !== null) return result;
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pkg.command)
|
switch (pkg.command)
|
||||||
{
|
{
|
||||||
@ -128,8 +124,9 @@ SubscriptionOperation.prototype.inspectPackage = function(pkg) {
|
|||||||
|
|
||||||
case TcpCommand.NotHandled:
|
case TcpCommand.NotHandled:
|
||||||
{
|
{
|
||||||
if (this._subscription !== null)
|
if (this._subscription !== null) {
|
||||||
throw new Error("NotHandled command appeared while we already subscribed.");
|
throw new Error("NotHandled command appeared while we already subscribed.");
|
||||||
|
}
|
||||||
|
|
||||||
var message = ClientMessage.NotHandled.decode(pkg.data.toBuffer());
|
var message = ClientMessage.NotHandled.decode(pkg.data.toBuffer());
|
||||||
switch (message.reason)
|
switch (message.reason)
|
||||||
@ -140,11 +137,11 @@ SubscriptionOperation.prototype.inspectPackage = function(pkg) {
|
|||||||
case ClientMessage.NotHandled.NotHandledReason.TooBusy:
|
case ClientMessage.NotHandled.NotHandledReason.TooBusy:
|
||||||
return new InspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy");
|
return new InspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy");
|
||||||
|
|
||||||
case ClientMessage.NotHandled.NotHandledReason.NotMaster:
|
case ClientMessage.NotHandled.NotHandledReason.NotLeader:
|
||||||
var masterInfo = ClientMessage.NotHandled.MasterInfo.decode(message.additional_info);
|
var masterInfo = ClientMessage.NotHandled.LeaderInfo.decode(message.additionalInfo);
|
||||||
return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotMaster",
|
return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotLeader",
|
||||||
{host: masterInfo.external_tcp_address, port: masterInfo.external_tcp_port},
|
{host: masterInfo.externalTcpAddress, port: masterInfo.externalTcpPort},
|
||||||
{host: masterInfo.external_secure_tcp_address, port: masterInfo.external_secure_tcp_port});
|
{host: masterInfo.externalSecureTcpAddress, port: masterInfo.externalSecureTcpPort});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this._log.error("Unknown NotHandledReason: %s.", message.reason);
|
this._log.error("Unknown NotHandledReason: %s.", message.reason);
|
||||||
@ -172,8 +169,7 @@ SubscriptionOperation.prototype.connectionClosed = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SubscriptionOperation.prototype.timeOutSubscription = function() {
|
SubscriptionOperation.prototype.timeOutSubscription = function() {
|
||||||
if (this._subscription !== null)
|
if (this._subscription !== null) return false;
|
||||||
return false;
|
|
||||||
this.dropSubscription(SubscriptionDropReason.SubscribingError, null);
|
this.dropSubscription(SubscriptionDropReason.SubscribingError, null);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -182,9 +178,10 @@ SubscriptionOperation.prototype.dropSubscription = function(reason, err, connect
|
|||||||
if (!this._unsubscribed)
|
if (!this._unsubscribed)
|
||||||
{
|
{
|
||||||
this._unsubscribed = true;
|
this._unsubscribed = true;
|
||||||
if (this._verboseLogging)
|
if (this._verboseLogging) {
|
||||||
this._log.debug("Subscription %s to %s: closing subscription, reason: %s, exception: %s...",
|
this._log.debug("Subscription %s to %s: closing subscription, reason: %s, exception: %s...",
|
||||||
this._correlationId, this._streamId || "<all>", reason, err);
|
this._correlationId, this._streamId || "<all>", reason, err);
|
||||||
|
}
|
||||||
|
|
||||||
if (reason !== SubscriptionDropReason.UserInitiated && this._subscription === null)
|
if (reason !== SubscriptionDropReason.UserInitiated && this._subscription === null)
|
||||||
{
|
{
|
||||||
@ -193,24 +190,31 @@ SubscriptionOperation.prototype.dropSubscription = function(reason, err, connect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason === SubscriptionDropReason.UserInitiated && this._subscription !== null && connection !== null)
|
if (reason === SubscriptionDropReason.UserInitiated && this._subscription !== null && connection !== null) {
|
||||||
connection.enqueueSend(this._createUnsubscriptionPackage());
|
connection.enqueueSend(this._createUnsubscriptionPackage());
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if (this._subscription !== null)
|
if (this._subscription !== null) {
|
||||||
this._executeAction(function() { self._subscriptionDropped(self._subscription, reason, err); });
|
this._executeAction(function () {
|
||||||
|
self._subscriptionDropped(self._subscription, reason, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SubscriptionOperation.prototype._confirmSubscription = function(lastCommitPosition, lastEventNumber) {
|
SubscriptionOperation.prototype._confirmSubscription = function(lastCommitPosition, lastEventNumber) {
|
||||||
if (lastCommitPosition < -1)
|
if (lastCommitPosition < -1) {
|
||||||
throw new Error(util.format("Invalid lastCommitPosition %s on subscription confirmation.", lastCommitPosition));
|
throw new Error(util.format("Invalid lastCommitPosition %s on subscription confirmation.", lastCommitPosition));
|
||||||
if (this._subscription !== null)
|
}
|
||||||
|
if (this._subscription !== null) {
|
||||||
throw new Error("Double confirmation of subscription.");
|
throw new Error("Double confirmation of subscription.");
|
||||||
|
}
|
||||||
|
|
||||||
if (this._verboseLogging)
|
if (this._verboseLogging) {
|
||||||
this._log.debug("Subscription %s to %s: subscribed at CommitPosition: %d, EventNumber: %d.",
|
this._log.debug("Subscription %s to %s: subscribed at CommitPosition: %d, EventNumber: %d.",
|
||||||
this._correlationId, this._streamId || "<all>", lastCommitPosition, lastEventNumber);
|
this._correlationId, this._streamId || "<all>", lastCommitPosition, lastEventNumber);
|
||||||
|
}
|
||||||
|
|
||||||
this._subscription = this._createSubscriptionObject(lastCommitPosition, lastEventNumber);
|
this._subscription = this._createSubscriptionObject(lastCommitPosition, lastEventNumber);
|
||||||
this._cb(null, this._subscription);
|
this._cb(null, this._subscription);
|
||||||
@ -221,18 +225,18 @@ SubscriptionOperation.prototype._createSubscriptionObject = function(lastCommitP
|
|||||||
};
|
};
|
||||||
|
|
||||||
SubscriptionOperation.prototype._onEventAppeared = function(e) {
|
SubscriptionOperation.prototype._onEventAppeared = function(e) {
|
||||||
if (this._unsubscribed)
|
if (this._unsubscribed) return;
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._subscription === null) throw new Error("Subscription not confirmed, but event appeared!");
|
if (this._subscription === null) throw new Error("Subscription not confirmed, but event appeared!");
|
||||||
|
|
||||||
if (this._verboseLogging)
|
if (this._verboseLogging) {
|
||||||
this._log.debug("Subscription %s to %s: event appeared (%s, %d, %s @ %s).",
|
this._log.debug("Subscription %s to %s: event appeared (%s, %d, %s @ %s).",
|
||||||
this._correlationId, this._streamId || "<all>",
|
this._correlationId, this._streamId || "<all>",
|
||||||
e.originalStreamId, e.originalEventNumber, e.originalEvent.eventType, e.originalPosition);
|
e.originalStreamId, e.originalEventNumber, e.originalEvent.eventType, e.originalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this._executeAction(function() { self._eventAppeared(self._subscription, e); });
|
this._executeAction(function() { return self._eventAppeared(self._subscription, e); });
|
||||||
};
|
};
|
||||||
|
|
||||||
SubscriptionOperation.prototype._executeAction = function(action) {
|
SubscriptionOperation.prototype._executeAction = function(action) {
|
||||||
@ -244,21 +248,30 @@ SubscriptionOperation.prototype._executeAction = function(action) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SubscriptionOperation.prototype._executeActions = function() {
|
SubscriptionOperation.prototype._executeActions = function() {
|
||||||
//TODO: possible blocking loop for node.js
|
|
||||||
var action = this._actionQueue.shift();
|
var action = this._actionQueue.shift();
|
||||||
while (action)
|
if (!action) {
|
||||||
{
|
this._actionExecuting = false;
|
||||||
try
|
return;
|
||||||
{
|
}
|
||||||
action();
|
var promise;
|
||||||
}
|
try
|
||||||
catch (err)
|
{
|
||||||
{
|
promise = action();
|
||||||
this._log.error(err, "Exception during executing user callback: %s.", err.message);
|
}
|
||||||
}
|
catch (err)
|
||||||
action = this._actionQueue.shift();
|
{
|
||||||
|
this._log.error(err, "Exception during executing user callback: %s.", err.message);
|
||||||
|
}
|
||||||
|
if (promise && promise.then) {
|
||||||
|
var self = this;
|
||||||
|
promise
|
||||||
|
.catch(function (err) {
|
||||||
|
self._log.error(err, "Exception during executing user callback: %s.", err.message);
|
||||||
|
})
|
||||||
|
.then(this._executeActions.bind(this));
|
||||||
|
} else {
|
||||||
|
setImmediate(this._executeActions.bind(this));
|
||||||
}
|
}
|
||||||
this._actionExecuting = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SubscriptionOperation.prototype.toString = function() {
|
SubscriptionOperation.prototype.toString = function() {
|
||||||
@ -266,4 +279,4 @@ SubscriptionOperation.prototype.toString = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = SubscriptionOperation;
|
module.exports = SubscriptionOperation;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
var guidParse = require('../common/guid-parse');
|
||||||
|
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||||
@ -22,13 +22,18 @@ util.inherits(TransactionalWriteOperation, OperationBase);
|
|||||||
|
|
||||||
TransactionalWriteOperation.prototype._createRequestDto = function() {
|
TransactionalWriteOperation.prototype._createRequestDto = function() {
|
||||||
var dtos = this._events.map(function(ev) {
|
var dtos = this._events.map(function(ev) {
|
||||||
var eventId = new Buffer(uuid.parse(ev.eventId));
|
var eventId = guidParse.parse(ev.eventId);
|
||||||
return new ClientMessage.NewEvent({
|
return {
|
||||||
event_id: eventId, event_type: ev.type,
|
eventId: eventId, eventType: ev.type,
|
||||||
data_content_type: ev.isJson ? 1 : 0, metadata_content_type: 0,
|
dataContentType: ev.isJson ? 1 : 0, metadataContentType: 0,
|
||||||
data: ev.data, metadata: ev.metadata});
|
data: ev.data, metadata: ev.metadata
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return new ClientMessage.TransactionWrite({
|
||||||
|
transactionId: this._transactionId,
|
||||||
|
events: dtos,
|
||||||
|
requireLeader: this._requireMaster
|
||||||
});
|
});
|
||||||
return new ClientMessage.TransactionWrite(this._transactionId, dtos, this._requireMaster);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionalWriteOperation.prototype._inspectResponse = function(response) {
|
TransactionalWriteOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -60,4 +65,3 @@ TransactionalWriteOperation.prototype.toString = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
module.exports = TransactionalWriteOperation;
|
module.exports = TransactionalWriteOperation;
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
|
||||||
|
|
||||||
var ensure = require('../common/utils/ensure');
|
var ensure = require('../common/utils/ensure');
|
||||||
var OperationBase = require('../clientOperations/operationBase');
|
var OperationBase = require('../clientOperations/operationBase');
|
||||||
@ -36,11 +35,24 @@ function UpdatePersistentSubscriptionOperation(log, cb, stream, groupName, setti
|
|||||||
util.inherits(UpdatePersistentSubscriptionOperation, OperationBase);
|
util.inherits(UpdatePersistentSubscriptionOperation, OperationBase);
|
||||||
|
|
||||||
UpdatePersistentSubscriptionOperation.prototype._createRequestDto = function() {
|
UpdatePersistentSubscriptionOperation.prototype._createRequestDto = function() {
|
||||||
return new ClientMessage.UpdatePersistentSubscription(this._groupName, this._stream, this._resolveLinkTos,
|
return new ClientMessage.UpdatePersistentSubscription({
|
||||||
this._startFromBeginning, this._messageTimeoutMilliseconds, this._recordStatistics, this._liveBufferSize,
|
subscriptionGroupName: this._groupName,
|
||||||
this._readBatchSize, this._bufferSize, this._maxRetryCount,
|
eventStreamId: this._stream,
|
||||||
this._namedConsumerStrategy === SystemConsumerStrategies.RoundRobin, this._checkPointAfter,
|
resolveLinkTos: this._resolveLinkTos,
|
||||||
this._maxCheckPointCount, this._minCheckPointCount, this._maxSubscriberCount, this._namedConsumerStrategy);
|
startFrom: this._startFromBeginning,
|
||||||
|
messageTimeoutMilliseconds: this._messageTimeoutMilliseconds,
|
||||||
|
recordStatistics: this._recordStatistics,
|
||||||
|
liveBufferSize: this._liveBufferSize,
|
||||||
|
readBatchSize: this._readBatchSize,
|
||||||
|
bufferSize: this._bufferSize,
|
||||||
|
maxRetryCount: this._maxRetryCount,
|
||||||
|
preferRoundRobin: this._namedConsumerStrategy === SystemConsumerStrategies.RoundRobin,
|
||||||
|
checkpointAfterTime: this._checkPointAfter,
|
||||||
|
checkpointMaxCount: this._maxCheckPointCount,
|
||||||
|
checkpointMinCount: this._minCheckPointCount,
|
||||||
|
subscriberMaxCount: this._maxSubscriberCount,
|
||||||
|
namedConsumerStrategy: this._namedConsumerStrategy
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UpdatePersistentSubscriptionOperation.prototype._inspectResponse = function(response) {
|
UpdatePersistentSubscriptionOperation.prototype._inspectResponse = function(response) {
|
||||||
@ -71,4 +83,4 @@ UpdatePersistentSubscriptionOperation.prototype.toString = function() {
|
|||||||
return util.format("Stream: %s, Group Name: %s", this._stream, this._groupName);
|
return util.format("Stream: %s, Group Name: %s", this._stream, this._groupName);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = UpdatePersistentSubscriptionOperation;
|
module.exports = UpdatePersistentSubscriptionOperation;
|
@ -20,20 +20,23 @@ function VolatileSubscriptionOperation(
|
|||||||
util.inherits(VolatileSubscriptionOperation, SubscriptionOperation);
|
util.inherits(VolatileSubscriptionOperation, SubscriptionOperation);
|
||||||
|
|
||||||
VolatileSubscriptionOperation.prototype._createSubscriptionPackage = function() {
|
VolatileSubscriptionOperation.prototype._createSubscriptionPackage = function() {
|
||||||
var dto = new ClientMessage.SubscribeToStream(this._streamId, this._resolveLinkTos);
|
var dto = new ClientMessage.SubscribeToStream({
|
||||||
|
eventStreamId: this._streamId,
|
||||||
|
resolveLinkTos: this._resolveLinkTos
|
||||||
|
});
|
||||||
return new TcpPackage(TcpCommand.SubscribeToStream,
|
return new TcpPackage(TcpCommand.SubscribeToStream,
|
||||||
this._userCredentials !== null ? TcpFlags.Authenticated : TcpFlags.None,
|
this._userCredentials !== null ? TcpFlags.Authenticated : TcpFlags.None,
|
||||||
this._correlationId,
|
this._correlationId,
|
||||||
this._userCredentials !== null ? this._userCredentials.username : null,
|
this._userCredentials !== null ? this._userCredentials.username : null,
|
||||||
this._userCredentials !== null ? this._userCredentials.password : null,
|
this._userCredentials !== null ? this._userCredentials.password : null,
|
||||||
new BufferSegment(dto.toBuffer()));
|
new BufferSegment(ClientMessage.SubscribeToStream.encode(dto).finish()));
|
||||||
};
|
};
|
||||||
|
|
||||||
VolatileSubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
VolatileSubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
||||||
try {
|
try {
|
||||||
if (pkg.command === TcpCommand.SubscriptionConfirmation) {
|
if (pkg.command === TcpCommand.SubscriptionConfirmation) {
|
||||||
var dto = ClientMessage.SubscriptionConfirmation.decode(pkg.data.toBuffer());
|
var dto = ClientMessage.SubscriptionConfirmation.decode(pkg.data.toBuffer());
|
||||||
this._confirmSubscription(dto.last_commit_position, dto.last_event_number);
|
this._confirmSubscription(dto.lastCommitPosition, dto.lastEventNumber);
|
||||||
return new InspectionResult(InspectionDecision.Subscribed, "SubscriptionConfirmation");
|
return new InspectionResult(InspectionDecision.Subscribed, "SubscriptionConfirmation");
|
||||||
}
|
}
|
||||||
if (pkg.command === TcpCommand.StreamEventAppeared) {
|
if (pkg.command === TcpCommand.StreamEventAppeared) {
|
||||||
@ -43,7 +46,7 @@ VolatileSubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(e.stack);
|
this._log.warn(e.stack);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -52,4 +55,4 @@ VolatileSubscriptionOperation.prototype._createSubscriptionObject = function(las
|
|||||||
return new VolatileEventStoreSubscription(this, this._streamId, lastCommitPosition, lastEventNumber);
|
return new VolatileEventStoreSubscription(this, this._streamId, lastCommitPosition, lastEventNumber);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = VolatileSubscriptionOperation;
|
module.exports = VolatileSubscriptionOperation;
|
||||||
|
@ -19,8 +19,7 @@ BufferSegment.prototype.toString = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
BufferSegment.prototype.toBuffer = function() {
|
BufferSegment.prototype.toBuffer = function() {
|
||||||
if (this.offset === 0 && this.count === this.buffer.length)
|
if (this.offset === 0 && this.count === this.buffer.length) return this.buffer;
|
||||||
return this.buffer;
|
|
||||||
return this.buffer.slice(this.offset, this.offset + this.count);
|
return this.buffer.slice(this.offset, this.offset + this.count);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
47
src/common/guid-parse.js
Normal file
47
src/common/guid-parse.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Maps for number <-> hex string conversion
|
||||||
|
var _byteToHex = [];
|
||||||
|
var _hexToByte = {};
|
||||||
|
for (var i = 0; i < 256; i++) {
|
||||||
|
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
||||||
|
_hexToByte[_byteToHex[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// **`parse()` - Parse a UUID into it's component bytes**
|
||||||
|
function parse(s, buf, offset) {
|
||||||
|
const i = (buf && offset) || 0;
|
||||||
|
var ii = 0;
|
||||||
|
|
||||||
|
if (buf) buf.fill(0, i, i + 16);
|
||||||
|
buf = buf || Buffer.alloc(16);
|
||||||
|
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
|
||||||
|
if (ii < 16) { // Don't overflow!
|
||||||
|
buf[i + ii++] = _hexToByte[oct];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var buf2 = Buffer.from(buf.slice(i, i + 16));
|
||||||
|
buf[i + 0] = buf2[3];
|
||||||
|
buf[i + 1] = buf2[2];
|
||||||
|
buf[i + 2] = buf2[1];
|
||||||
|
buf[i + 3] = buf2[0];
|
||||||
|
buf[i + 4] = buf2[5];
|
||||||
|
buf[i + 5] = buf2[4];
|
||||||
|
buf[i + 6] = buf2[7];
|
||||||
|
buf[i + 7] = buf2[6];
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
|
||||||
|
function unparse(buf, offset) {
|
||||||
|
var i = offset || 0;
|
||||||
|
return '03020100-0504-0706-0809-101112131415'.replace(/\d{2}/g, function (num) {
|
||||||
|
var j = parseInt(num, 10);
|
||||||
|
return _byteToHex[buf[i+j]];
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.parse = parse;
|
||||||
|
exports.unparse = unparse;
|
@ -39,4 +39,4 @@ Hash.prototype.remove = function(key) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = Hash;
|
module.exports = Hash;
|
@ -26,6 +26,11 @@ FileLogger.prototype.info = function() {
|
|||||||
fs.appendFileSync(this._filePath, line);
|
fs.appendFileSync(this._filePath, line);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FileLogger.prototype.warn = function() {
|
||||||
|
var line = createLine('WARN', arguments, 0);
|
||||||
|
fs.appendFileSync(this._filePath, line);
|
||||||
|
};
|
||||||
|
|
||||||
FileLogger.prototype.error = function(e) {
|
FileLogger.prototype.error = function(e) {
|
||||||
var hasError = e instanceof Error;
|
var hasError = e instanceof Error;
|
||||||
var line = createLine('ERROR', arguments, hasError ? 1 : 0);
|
var line = createLine('ERROR', arguments, hasError ? 1 : 0);
|
||||||
@ -36,4 +41,4 @@ FileLogger.prototype.error = function(e) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = FileLogger;
|
module.exports = FileLogger;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
function NoopLogger() {
|
function NoopLogger() {
|
||||||
}
|
}
|
||||||
NoopLogger.prototype.error = function() {};
|
|
||||||
NoopLogger.prototype.debug = function() {};
|
NoopLogger.prototype.debug = function() {};
|
||||||
NoopLogger.prototype.info = function() {};
|
NoopLogger.prototype.info = function() {};
|
||||||
|
NoopLogger.prototype.warn = function() {};
|
||||||
|
NoopLogger.prototype.error = function() {};
|
||||||
|
|
||||||
module.exports = NoopLogger;
|
module.exports = NoopLogger;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const SystemEventTypes = {
|
const SystemEventTypes = Object.freeze({
|
||||||
StreamMetadata: '$metadata'
|
StreamMetadata: '$metadata'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = SystemEventTypes;
|
module.exports = SystemEventTypes;
|
@ -1,4 +1,4 @@
|
|||||||
const SystemMetadata = {
|
const SystemMetadata = Object.freeze({
|
||||||
maxAge: '$maxAge',
|
maxAge: '$maxAge',
|
||||||
maxCount: '$maxCount',
|
maxCount: '$maxCount',
|
||||||
truncateBefore: '$tb',
|
truncateBefore: '$tb',
|
||||||
@ -11,6 +11,6 @@ const SystemMetadata = {
|
|||||||
aclMetaWrite: '$mw',
|
aclMetaWrite: '$mw',
|
||||||
userStreamAcl: '$userStreamAcl',
|
userStreamAcl: '$userStreamAcl',
|
||||||
systemStreamAcl: '$systemStreamAcl'
|
systemStreamAcl: '$systemStreamAcl'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = SystemMetadata;
|
module.exports = SystemMetadata;
|
@ -1,6 +1,6 @@
|
|||||||
module.exports.metastreamOf = function(stream) {
|
exports.metastreamOf = function(stream) {
|
||||||
return '$$' + stream;
|
return '$$' + stream;
|
||||||
};
|
};
|
||||||
module.exports.isMetastream = function(stream) {
|
exports.isMetastream = function(stream) {
|
||||||
return stream.indexOf('$$') === 0;
|
return stream.indexOf('$$') === 0;
|
||||||
};
|
};
|
@ -1,39 +1,45 @@
|
|||||||
|
var Long = require('long');
|
||||||
|
|
||||||
module.exports.notNullOrEmpty = function(value, name) {
|
module.exports.notNullOrEmpty = function(value, name) {
|
||||||
if (value === null)
|
if (value === null) throw new TypeError(name + " should not be null.");
|
||||||
throw new TypeError(name + " should not be null.");
|
if (value === '') throw new Error(name + " should not be empty.");
|
||||||
if (value === '')
|
|
||||||
throw new Error(name + " should not be empty.");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.notNull = function(value, name) {
|
module.exports.notNull = function(value, name) {
|
||||||
if (value === null)
|
if (value === null) throw new TypeError(name + " should not be null.");
|
||||||
throw new TypeError(name + " should not be null.");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.isInteger = function(value, name) {
|
function isInteger(value, name) {
|
||||||
if (typeof value !== 'number' || value % 1 !== 0)
|
if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError(name + " should be an integer.");
|
||||||
throw new TypeError(name + " should be an integer.");
|
}
|
||||||
|
module.exports.isInteger = isInteger;
|
||||||
|
|
||||||
|
module.exports.isLongOrInteger = function(value, name) {
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return isInteger(value, name);
|
||||||
|
} else if (!Long.isLong(value)) {
|
||||||
|
throw new TypeError(name + " should be a Long|number.");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.isArrayOf = function(expectedType, value, name) {
|
module.exports.isArrayOf = function(expectedType, value, name) {
|
||||||
if (!Array.isArray(value))
|
if (!Array.isArray(value)) throw new TypeError(name + " should be an array.");
|
||||||
throw new TypeError(name + " should be an array.");
|
if (!value.every(function(x) { return x instanceof expectedType; })) {
|
||||||
if (!value.every(function(x) { return x instanceof expectedType; }))
|
|
||||||
throw new TypeError([name, " should be an array of ", expectedType.name, "."].join(""));
|
throw new TypeError([name, " should be an array of ", expectedType.name, "."].join(""));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.isTypeOf = function(expectedType, value, name, nullAllowed) {
|
module.exports.isTypeOf = function(expectedType, value, name, nullAllowed) {
|
||||||
if (nullAllowed && value === null) return;
|
if (nullAllowed && value === null) return;
|
||||||
if (!(value instanceof expectedType))
|
if (!(value instanceof expectedType)) {
|
||||||
throw new TypeError([name, " should be of type '", expectedType.name, "'", nullAllowed ? " or null": "", "."].join(""));
|
throw new TypeError([name, " should be of type '", expectedType.name, "'", nullAllowed ? " or null" : "", "."].join(""));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.positive = function(value, name) {
|
module.exports.positive = function(value, name) {
|
||||||
if (value <= 0)
|
if (value <= 0) throw new Error(name + " should be positive.");
|
||||||
throw new Error(name + " should be positive.");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.nonNegative = function(value, name) {
|
module.exports.nonNegative = function(value, name) {
|
||||||
if (value < 0)
|
if (value < 0) throw new Error(name + " should be non-negative.");
|
||||||
throw new Error(name + " should be non-negative.");
|
|
||||||
};
|
};
|
28
src/common/utils/shuffle.js
Normal file
28
src/common/utils/shuffle.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
function rndNext(min, max) {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(Math.random() * (max - min)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shuffle (arr, from, to) {
|
||||||
|
if (arr.length <= 1){
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
if (!from) {
|
||||||
|
from = 0;
|
||||||
|
}
|
||||||
|
if (!to) {
|
||||||
|
to = arr.length - 1;
|
||||||
|
}
|
||||||
|
const newArr = [...arr];
|
||||||
|
if (from >= to) return;
|
||||||
|
for (var current = from; current <= to; ++current) {
|
||||||
|
var index = rndNext(current, to + 1);
|
||||||
|
var tmp = newArr[index];
|
||||||
|
newArr[index] = newArr[current];
|
||||||
|
newArr[current] = tmp;
|
||||||
|
}
|
||||||
|
return newArr;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = shuffle;
|
165
src/core/cluster/clusterDiscoverer.js
Normal file
165
src/core/cluster/clusterDiscoverer.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
const ClusterInfo = require('./clusterInfo');
|
||||||
|
const GossipSeed = require('../../gossipSeed');
|
||||||
|
const NodeEndPoints = require('./nodeEndpoints');
|
||||||
|
const shuffle = require('../../common/utils/shuffle');
|
||||||
|
|
||||||
|
function wait(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClusterDiscoverer
|
||||||
|
* @constructor
|
||||||
|
* @class
|
||||||
|
* @param {Logger} log - Logger instance
|
||||||
|
* @param {Object} settings - Settings object
|
||||||
|
* @param {Object} dnsService - DNS service to perform DNS lookup
|
||||||
|
* @param {Object} httpService - HTTP service to perform http requests
|
||||||
|
*/
|
||||||
|
function ClusterDiscoverer(log, settings, dnsService, httpService) {
|
||||||
|
if (!settings.clusterDns && (!settings.seeds || settings.seeds.length === 0))
|
||||||
|
throw new Error('Both clusterDns and seeds are null/empty.');
|
||||||
|
this._log = log;
|
||||||
|
|
||||||
|
this._settings = settings;
|
||||||
|
this._dnsService = dnsService;
|
||||||
|
this._httpService = httpService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover Cluster endpoints
|
||||||
|
* @param {Object} failedTcpEndPoint - The failed TCP endpoint which were used by the handler
|
||||||
|
* @returns {Promise.<NodeEndPoints>}
|
||||||
|
*/
|
||||||
|
ClusterDiscoverer.prototype.discover = async function (failedTcpEndPoint) {
|
||||||
|
let attempts = 0;
|
||||||
|
while (attempts++ < this._settings.maxDiscoverAttempts) {
|
||||||
|
try {
|
||||||
|
const candidates = await this._getGossipCandidates(this._settings.managerExternalHttpPort);
|
||||||
|
const gossipSeeds = candidates.filter(
|
||||||
|
(candidate) =>
|
||||||
|
!failedTcpEndPoint ||
|
||||||
|
!(candidate.endPoint.host === failedTcpEndPoint.host && candidate.endPoint.port === failedTcpEndPoint.port)
|
||||||
|
);
|
||||||
|
let gossipSeedsIndex = 0;
|
||||||
|
let clusterInfo;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
clusterInfo = await this._clusterInfo(gossipSeeds[gossipSeedsIndex], this._settings.gossipTimeout);
|
||||||
|
if (!clusterInfo.bestNode) {
|
||||||
|
this._log.info(
|
||||||
|
`Discovering attempt ${attempts}/${this._settings.maxDiscoverAttempts} failed: no candidate found.`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
} while (++gossipSeedsIndex < gossipSeeds.length);
|
||||||
|
if (clusterInfo) {
|
||||||
|
return NodeEndPoints.createFromGossipMember(clusterInfo.bestNode);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this._log.info(
|
||||||
|
`Discovering attempt ${attempts}/${this._settings.maxDiscoverAttempts} failed with error: ${err}.\n${err.stack}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await wait(this._settings.discoverDelay);
|
||||||
|
}
|
||||||
|
throw new Error(`Failed to discover candidate in ${this._settings.maxDiscoverAttempts} attempts.`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get gossip candidates either from DNS or from gossipSeeds settings
|
||||||
|
* @private
|
||||||
|
* @param {Number} managerExternalHttpPort - Http port of the manager (or the http port of the node for OSS clusters)
|
||||||
|
* @returns {Promise.<GossipSeed[]>}
|
||||||
|
*/
|
||||||
|
ClusterDiscoverer.prototype._getGossipCandidates = async function (managerExternalHttpPort) {
|
||||||
|
const gossipSeeds =
|
||||||
|
this._settings.seeds && this._settings.seeds.length > 0
|
||||||
|
? this._settings.seeds
|
||||||
|
: (await this._resolveDns(this._settings.clusterDns)).map(
|
||||||
|
(address) => new GossipSeed({ host: address, port: managerExternalHttpPort }, address, this._settings.clusterDns)
|
||||||
|
);
|
||||||
|
return shuffle(gossipSeeds);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the cluster DNS discovery address to retrieve belonging ip addresses
|
||||||
|
* @private
|
||||||
|
* @param {String} clusterDns - Cluster DNS discovery address
|
||||||
|
* @returns {Promise.<String[]>}
|
||||||
|
*/
|
||||||
|
ClusterDiscoverer.prototype._resolveDns = async function (clusterDns) {
|
||||||
|
const dnsOptions = {
|
||||||
|
family: 4,
|
||||||
|
hints: this._dnsService.ADDRCONFIG | this._dnsService.V4MAPPED,
|
||||||
|
all: true,
|
||||||
|
};
|
||||||
|
const result = await this._dnsService.lookup(clusterDns, dnsOptions);
|
||||||
|
if (!result || result.length === 0) {
|
||||||
|
throw new Error(`No result from dns lookup for ${clusterDns}`);
|
||||||
|
}
|
||||||
|
return result.map((address) => address.address);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cluster informations (gossip members)
|
||||||
|
* @param {GossipSeed} candidate - candidate to get informations from
|
||||||
|
* @param {Number} timeout - timeout for the http request
|
||||||
|
* @returns {Promise.<ClusterInfo>}
|
||||||
|
*/
|
||||||
|
ClusterDiscoverer.prototype._clusterInfo = async function (candidate, timeout) {
|
||||||
|
var self = this;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const options = {
|
||||||
|
host: candidate.endPoint.host,
|
||||||
|
port: candidate.endPoint.port,
|
||||||
|
path: '/gossip?format=json',
|
||||||
|
timeout: timeout,
|
||||||
|
rejectUnauthorized: self._settings.rejectUnauthorized
|
||||||
|
};
|
||||||
|
if (candidate.hostHeader) {
|
||||||
|
options.headers = {
|
||||||
|
Host: candidate.hostHeader,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = this._httpService.request(options, (res) => {
|
||||||
|
if (res.statusCode !== 200) {
|
||||||
|
this._log.info('Trying to get gossip from', candidate, 'failed with status code:', res.statusCode);
|
||||||
|
reject(new Error(`Gossip candidate returns a ${res.statusCode} error`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let result = '';
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
result += chunk.toString();
|
||||||
|
});
|
||||||
|
res.on('end', function () {
|
||||||
|
try {
|
||||||
|
result = JSON.parse(result);
|
||||||
|
} catch (e) {
|
||||||
|
reject(new Error('Unable to parse gossip response'));
|
||||||
|
}
|
||||||
|
resolve(new ClusterInfo(result.members));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
request.setTimeout(timeout);
|
||||||
|
|
||||||
|
request.on('timeout', () => {
|
||||||
|
this._log.info('Trying to get gossip from', candidate, 'timed out.');
|
||||||
|
request.destroy();
|
||||||
|
reject(new Error('Connection to gossip timed out'));
|
||||||
|
});
|
||||||
|
|
||||||
|
request.on('error', (error) => {
|
||||||
|
this._log.info('Trying to get gossip from', candidate, 'errored', error);
|
||||||
|
request.destroy();
|
||||||
|
reject(new Error('Connection to gossip errored'));
|
||||||
|
});
|
||||||
|
|
||||||
|
request.end();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ClusterDiscoverer;
|
41
src/core/cluster/clusterInfo.js
Normal file
41
src/core/cluster/clusterInfo.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const MemberInfo = require('./memberInfo.js');
|
||||||
|
|
||||||
|
const VNodeStates = Object.freeze({
|
||||||
|
Initializing: 0,
|
||||||
|
DiscoverLeader: 1,
|
||||||
|
Unknown: 2,
|
||||||
|
PreReplica: 3,
|
||||||
|
CatchingUp: 4,
|
||||||
|
Clone: 5,
|
||||||
|
Follower: 6,
|
||||||
|
PreLeader: 7,
|
||||||
|
Leader: 8,
|
||||||
|
Manager: 9,
|
||||||
|
ShuttingDown: 10,
|
||||||
|
Shutdown: 11,
|
||||||
|
ReadOnlyLeaderless: 12,
|
||||||
|
PreReadOnlyReplica: 13,
|
||||||
|
ReadOnlyReplica: 14,
|
||||||
|
ResigningLeader: 15,
|
||||||
|
});
|
||||||
|
|
||||||
|
function ClusterInfo(members) {
|
||||||
|
this._members = members.map(member => new MemberInfo(member));
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'bestNode', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._getBestNode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ClusterInfo.prototype._getBestNode = function () {
|
||||||
|
return this._members
|
||||||
|
.filter(member => member.isAlive && member.isAllowedToConnect)
|
||||||
|
.sort(function (a, b) {
|
||||||
|
return VNodeStates[b.state] - VNodeStates[a.state];
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ClusterInfo;
|
73
src/core/cluster/memberInfo.js
Normal file
73
src/core/cluster/memberInfo.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
const NOT_ALLOWED_STATES = [
|
||||||
|
'Manager',
|
||||||
|
'ShuttingDown',
|
||||||
|
'Shutdown'
|
||||||
|
];
|
||||||
|
|
||||||
|
function MemberInfo(informations) {
|
||||||
|
this._instanceId = informations.instanceId;
|
||||||
|
this._timeStamp = informations.timeStamp;
|
||||||
|
this._state = informations.state;
|
||||||
|
this._isAlive = informations.isAlive;
|
||||||
|
this._internalTcpIp = informations.internalTcpIp;
|
||||||
|
this._internalTcpPort = informations.internalTcpPort;
|
||||||
|
this._internalSecureTcpPort = informations.internalSecureTcpPort;
|
||||||
|
this._externalTcpIp = informations.externalTcpIp;
|
||||||
|
this._externalTcpPort = informations.externalTcpPort;
|
||||||
|
this._externalSecureTcpPort = informations.externalSecureTcpPort;
|
||||||
|
this._internalHttpIp = informations.internalHttpIp;
|
||||||
|
this._internalHttpPort = informations.internalHttpPort;
|
||||||
|
this._externalHttpIp = informations.externalHttpIp;
|
||||||
|
this._externalHttpPort = informations.externalHttpPort;
|
||||||
|
this._lastCommitPosition = informations.lastCommitPosition;
|
||||||
|
this._writerCheckpoint = informations.writerCheckpoint;
|
||||||
|
this._chaserCheckpoint = informations.chaserCheckpoint;
|
||||||
|
this._epochPosition = informations.epochPosition;
|
||||||
|
this._epochNumber = informations.epochNumber;
|
||||||
|
this._epochId = informations.epochId;
|
||||||
|
this._nodePriority = informations.nodePriority;
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'state', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'isAllowedToConnect', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return !NOT_ALLOWED_STATES.includes(this._state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'isAlive', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._isAlive;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'externalTcpIp', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._externalTcpIp;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'externalTcpPort', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._externalTcpPort;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'externalSecureTcpPort', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._externalSecureTcpPort;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MemberInfo;
|
23
src/core/cluster/nodeEndpoints.js
Normal file
23
src/core/cluster/nodeEndpoints.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
function NodeEndPoints(tcpEndPoint, secureTcpEndPoint) {
|
||||||
|
if (tcpEndPoint === null && secureTcpEndPoint === null) throw new Error('Both endpoints are null.');
|
||||||
|
Object.defineProperties(this, {
|
||||||
|
tcpEndPoint: {
|
||||||
|
enumerable: true,
|
||||||
|
value: tcpEndPoint
|
||||||
|
},
|
||||||
|
secureTcpEndPoint: {
|
||||||
|
enumerable: true,
|
||||||
|
value: secureTcpEndPoint
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEndPoints.createFromGossipMember = function (member) {
|
||||||
|
const normTcp = { host: member.externalTcpIp, port: member.externalTcpPort };
|
||||||
|
const secTcp = member.externalSecureTcpPort > 0
|
||||||
|
? { host: member.externalTcpIp, port: member.externalSecureTcpPort }
|
||||||
|
: null;
|
||||||
|
return new NodeEndPoints(normTcp, secTcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = NodeEndPoints
|
@ -1,254 +0,0 @@
|
|||||||
var http = require('http');
|
|
||||||
var util = require('util');
|
|
||||||
var dns = require('dns');
|
|
||||||
var GossipSeed = require('../gossipSeed');
|
|
||||||
|
|
||||||
function NodeEndPoints(tcpEndPoint, secureTcpEndPoint) {
|
|
||||||
if (tcpEndPoint === null && secureTcpEndPoint === null) throw new Error('Both endpoints are null.');
|
|
||||||
Object.defineProperties(this, {
|
|
||||||
tcpEndPoint: {
|
|
||||||
enumerable: true,
|
|
||||||
value: tcpEndPoint
|
|
||||||
},
|
|
||||||
secureTcpEndPoint: {
|
|
||||||
enumerable: true,
|
|
||||||
value: secureTcpEndPoint
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function ClusterDnsEndPointDiscoverer(log, clusterDns, maxDiscoverAttempts, managerExternalHttpPort, gossipSeeds, gossipTimeout) {
|
|
||||||
if (!clusterDns && (!gossipSeeds || gossipSeeds.length === 0)) throw new Error('Both clusterDns and gossipSeeds are null/empty.');
|
|
||||||
this._log = log;
|
|
||||||
this._clusterDns = clusterDns;
|
|
||||||
this._maxDiscoverAttempts = maxDiscoverAttempts;
|
|
||||||
this._managerExternalHttpPort = managerExternalHttpPort;
|
|
||||||
this._gossipSeeds = gossipSeeds;
|
|
||||||
this._gossipTimeout = gossipTimeout;
|
|
||||||
this._oldGossip = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype.discover = function(failedTcpEndPoint) {
|
|
||||||
var attempt = 1;
|
|
||||||
var self = this;
|
|
||||||
function discover(resolve, reject) {
|
|
||||||
self._discoverEndPoint(failedTcpEndPoint)
|
|
||||||
.then(function (endPoints) {
|
|
||||||
if (!endPoints)
|
|
||||||
self._log.info(util.format("Discovering attempt %d/%d failed: no candidate found.", attempt, self._maxDiscoverAttempts));
|
|
||||||
return endPoints;
|
|
||||||
})
|
|
||||||
.catch(function (exc) {
|
|
||||||
self._log.info(util.format("Discovering attempt %d/%d failed with error: %s.\n%s", attempt, self._maxDiscoverAttempts, exc, exc.stack));
|
|
||||||
})
|
|
||||||
.then(function (endPoints) {
|
|
||||||
if (endPoints)
|
|
||||||
return resolve(endPoints);
|
|
||||||
if (attempt++ === self._maxDiscoverAttempts)
|
|
||||||
return reject(new Error('Failed to discover candidate in ' + self._maxDiscoverAttempts + ' attempts.'));
|
|
||||||
setTimeout(discover, 500, resolve, reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
discover(resolve, reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discover Cluster endpoints
|
|
||||||
* @param {Object} failedTcpEndPoint
|
|
||||||
* @returns {Promise.<NodeEndPoints>}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._discoverEndPoint = function (failedTcpEndPoint) {
|
|
||||||
try {
|
|
||||||
var mainPromise = this._oldGossip
|
|
||||||
? Promise.resolve(this._getGossipCandidatesFromOldGossip(this._oldGossip, failedTcpEndPoint))
|
|
||||||
: this._getGossipCandidatesFromDns();
|
|
||||||
var self = this;
|
|
||||||
var j = 0;
|
|
||||||
return mainPromise.then(function (gossipCandidates) {
|
|
||||||
var loopPromise = Promise.resolve();
|
|
||||||
for (var i = 0; i < gossipCandidates.length; i++) {
|
|
||||||
loopPromise = loopPromise.then(function (endPoints) {
|
|
||||||
if (endPoints) return endPoints;
|
|
||||||
return self._tryGetGossipFrom(gossipCandidates[j++])
|
|
||||||
.then(function (gossip) {
|
|
||||||
if (!gossip || !gossip.members || gossip.members.length === 0)
|
|
||||||
return;
|
|
||||||
var bestNode = self._tryDetermineBestNode(gossip.members);
|
|
||||||
if (bestNode) {
|
|
||||||
self._oldGossip = gossip.members;
|
|
||||||
return bestNode;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return loopPromise;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._getGossipCandidatesFromOldGossip = function (oldGossip, failedTcpEndPoint) {
|
|
||||||
if (!failedTcpEndPoint) return this._arrangeGossipCandidates(oldGossip);
|
|
||||||
var gossipCandidates = oldGossip.filter(function(x) {
|
|
||||||
return !(x.externalTcpPort === failedTcpEndPoint.port && x.externalTcpIp === failedTcpEndPoint.host);
|
|
||||||
});
|
|
||||||
return this._arrangeGossipCandidates(gossipCandidates);
|
|
||||||
};
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._arrangeGossipCandidates = function (members) {
|
|
||||||
var result = new Array(members.length);
|
|
||||||
var i = -1;
|
|
||||||
var j = members.length;
|
|
||||||
for (var k = 0; k < members.length; ++k)
|
|
||||||
{
|
|
||||||
if (members[k].state === 'Manager')
|
|
||||||
result[--j] = new GossipSeed({host: members[k].externalHttpIp, port: members[k].externalHttpPort});
|
|
||||||
else
|
|
||||||
result[++i] = new GossipSeed({host: members[k].externalHttpIp, port: members[k].externalHttpPort});
|
|
||||||
}
|
|
||||||
this._randomShuffle(result, 0, i); // shuffle nodes
|
|
||||||
this._randomShuffle(result, j, members.length - 1); // shuffle managers
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._getGossipCandidatesFromDns = function () {
|
|
||||||
var self = this;
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
if (self._gossipSeeds && self._gossipSeeds.length > 0) {
|
|
||||||
var endpoints = self._gossipSeeds;
|
|
||||||
self._randomShuffle(endpoints, 0, endpoints.length - 1);
|
|
||||||
resolve(endpoints);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const dnsOptions = {
|
|
||||||
family: 4,
|
|
||||||
hints: dns.ADDRCONFIG | dns.V4MAPPED,
|
|
||||||
all: true
|
|
||||||
};
|
|
||||||
dns.lookup(self._clusterDns, dnsOptions, function (err, addresses) {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
if (!addresses || addresses.length === 0) {
|
|
||||||
return reject(new Error('No result from dns lookup for ' + self._clusterDns));
|
|
||||||
}
|
|
||||||
var endpoints = addresses.map(function (x) {
|
|
||||||
return new GossipSeed({host: x.address, port: self._managerExternalHttpPort});
|
|
||||||
});
|
|
||||||
resolve(endpoints);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._tryGetGossipFrom = function (endPoint) {
|
|
||||||
var options = {
|
|
||||||
host: endPoint.endPoint.host,
|
|
||||||
port: endPoint.endPoint.port,
|
|
||||||
path: '/gossip?format=json'
|
|
||||||
};
|
|
||||||
if (endPoint.hostHeader) {
|
|
||||||
options.headers = {'Host': endPoint.hostHeader};
|
|
||||||
}
|
|
||||||
this._log.info('Try get gossip from', endPoint);
|
|
||||||
var self = this;
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
var timedout = false;
|
|
||||||
http.request(options, function (res) {
|
|
||||||
if (timedout) return;
|
|
||||||
var result = '';
|
|
||||||
if (res.statusCode !== 200) {
|
|
||||||
self._log.info('Trying to get gossip from', endPoint, 'failed with status code:', res.statusCode);
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.on('data', function (chunk) {
|
|
||||||
result += chunk.toString();
|
|
||||||
});
|
|
||||||
res.on('end', function () {
|
|
||||||
try {
|
|
||||||
result = JSON.parse(result);
|
|
||||||
} catch (e) {
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.setTimeout(self._gossipTimeout, function () {
|
|
||||||
self._log.info('Trying to get gossip from', endPoint, 'timed out.');
|
|
||||||
timedout = true;
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', function (e) {
|
|
||||||
if (timedout) return;
|
|
||||||
self._log.info('Trying to get gossip from', endPoint, 'failed with error:', e);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.end();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const VNodeStates = {
|
|
||||||
'Initializing': 0,
|
|
||||||
'Unknown': 1,
|
|
||||||
'PreReplica': 2,
|
|
||||||
'CatchingUp': 3,
|
|
||||||
'Clone': 4,
|
|
||||||
'Slave': 5,
|
|
||||||
'PreMaster': 6,
|
|
||||||
'Master': 7,
|
|
||||||
'Manager': 8,
|
|
||||||
'ShuttingDown': 9,
|
|
||||||
'Shutdown': 10
|
|
||||||
};
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._tryDetermineBestNode = function (members) {
|
|
||||||
var notAllowedStates = [
|
|
||||||
'Manager',
|
|
||||||
'ShuttingDown',
|
|
||||||
'Shutdown'
|
|
||||||
];
|
|
||||||
var node = members
|
|
||||||
.filter(function (x) {
|
|
||||||
return (x.isAlive && notAllowedStates.indexOf(x.state) === -1);
|
|
||||||
})
|
|
||||||
.sort(function (a, b) {
|
|
||||||
return VNodeStates[b.state] - VNodeStates[a.state];
|
|
||||||
})[0];
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
//_log.Info("Unable to locate suitable node. Gossip info:\n{0}.", string.Join("\n", members.Select(x => x.ToString())));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var normTcp = {host: node.externalTcpIp, port: node.externalTcpPort};
|
|
||||||
var secTcp = node.externalSecureTcpPort > 0
|
|
||||||
? {host: externalTcpIp, port: node.externalSecureTcpPort}
|
|
||||||
: null;
|
|
||||||
this._log.info(util.format("Discovering: found best choice [%j,%j] (%s).", normTcp, secTcp === null ? "n/a" : secTcp, node.state));
|
|
||||||
return new NodeEndPoints(normTcp, secTcp);
|
|
||||||
};
|
|
||||||
|
|
||||||
function rndNext(min, max) {
|
|
||||||
min = Math.ceil(min);
|
|
||||||
max = Math.floor(max);
|
|
||||||
return Math.floor(Math.random() * (max - min)) + min;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClusterDnsEndPointDiscoverer.prototype._randomShuffle = function (arr, i, j) {
|
|
||||||
if (i >= j)
|
|
||||||
return;
|
|
||||||
for (var k = i; k <= j; ++k)
|
|
||||||
{
|
|
||||||
var index = rndNext(k, j + 1);
|
|
||||||
var tmp = arr[index];
|
|
||||||
arr[index] = arr[k];
|
|
||||||
arr[k] = tmp;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = ClusterDnsEndPointDiscoverer;
|
|
@ -9,31 +9,35 @@ var SubscriptionsManager = require('./subscriptionsManager');
|
|||||||
var VolatileSubscriptionOperation = require('../clientOperations/volatileSubscriptionOperation');
|
var VolatileSubscriptionOperation = require('../clientOperations/volatileSubscriptionOperation');
|
||||||
var ConnectToPersistentSubscriptionOperation = require('../clientOperations/connectToPersistentSubscriptionOperation');
|
var ConnectToPersistentSubscriptionOperation = require('../clientOperations/connectToPersistentSubscriptionOperation');
|
||||||
var messages = require('./messages');
|
var messages = require('./messages');
|
||||||
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
|
var createBufferSegment = require('../common/bufferSegment');
|
||||||
|
|
||||||
var TcpPackage = require('../systemData/tcpPackage');
|
var TcpPackage = require('../systemData/tcpPackage');
|
||||||
var TcpCommand = require('../systemData/tcpCommand');
|
var TcpCommand = require('../systemData/tcpCommand');
|
||||||
var TcpFlags = require('../systemData/tcpFlags');
|
var TcpFlags = require('../systemData/tcpFlags');
|
||||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||||
|
|
||||||
const ConnectionState = {
|
const ConnectionState = Object.freeze({
|
||||||
Init: 'init',
|
Init: 'init',
|
||||||
Connecting: 'connecting',
|
Connecting: 'connecting',
|
||||||
Connected: 'connected',
|
Connected: 'connected',
|
||||||
Closed: 'closed'
|
Closed: 'closed'
|
||||||
};
|
});
|
||||||
|
|
||||||
const ConnectingPhase = {
|
const ConnectingPhase = Object.freeze({
|
||||||
Invalid: 'invalid',
|
Invalid: 'invalid',
|
||||||
Reconnecting: 'reconnecting',
|
Reconnecting: 'reconnecting',
|
||||||
EndPointDiscovery: 'endpointDiscovery',
|
EndPointDiscovery: 'endpointDiscovery',
|
||||||
ConnectionEstablishing: 'connectionEstablishing',
|
ConnectionEstablishing: 'connectionEstablishing',
|
||||||
Authentication: 'authentication',
|
Authentication: 'authentication',
|
||||||
|
Identification: 'identification',
|
||||||
Connected: 'connected'
|
Connected: 'connected'
|
||||||
};
|
});
|
||||||
|
|
||||||
const TimerPeriod = 200;
|
const TimerPeriod = 200;
|
||||||
const TimerTickMessage = new messages.TimerTickMessage();
|
const TimerTickMessage = new messages.TimerTickMessage();
|
||||||
const EmptyGuid = '00000000-0000-0000-0000-000000000000';
|
const EmptyGuid = '00000000-0000-0000-0000-000000000000';
|
||||||
|
const ClientVersion = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -43,9 +47,10 @@ const EmptyGuid = '00000000-0000-0000-0000-000000000000';
|
|||||||
* @property {Number} totalOperationCount
|
* @property {Number} totalOperationCount
|
||||||
*/
|
*/
|
||||||
function EventStoreConnectionLogicHandler(esConnection, settings) {
|
function EventStoreConnectionLogicHandler(esConnection, settings) {
|
||||||
|
EventEmitter.call(this);
|
||||||
this._esConnection = esConnection;
|
this._esConnection = esConnection;
|
||||||
this._settings = settings;
|
this._settings = settings;
|
||||||
this._queue = new SimpleQueuedHandler();
|
this._queue = new SimpleQueuedHandler(this._settings.log);
|
||||||
this._state = ConnectionState.Init;
|
this._state = ConnectionState.Init;
|
||||||
this._connectingPhase = ConnectingPhase.Invalid;
|
this._connectingPhase = ConnectingPhase.Invalid;
|
||||||
this._endpointDiscoverer = null;
|
this._endpointDiscoverer = null;
|
||||||
@ -182,8 +187,7 @@ EventStoreConnectionLogicHandler.prototype._closeConnection = function(reason, e
|
|||||||
|
|
||||||
this._logInfo("Closed. Reason: %s", reason);
|
this._logInfo("Closed. Reason: %s", reason);
|
||||||
|
|
||||||
if (error)
|
if (error) this.emit('error', error);
|
||||||
this.emit('error', error);
|
|
||||||
|
|
||||||
this.emit('closed', reason);
|
this.emit('closed', reason);
|
||||||
};
|
};
|
||||||
@ -200,7 +204,7 @@ EventStoreConnectionLogicHandler.prototype._closeTcpConnection = function(reason
|
|||||||
this._connection = null;
|
this._connection = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
var _nextSeqNo = -1;
|
var _nextSeqNo = 0;
|
||||||
function createOperationItem(operation, maxRetries, timeout) {
|
function createOperationItem(operation, maxRetries, timeout) {
|
||||||
var operationItem = {
|
var operationItem = {
|
||||||
seqNo: _nextSeqNo++,
|
seqNo: _nextSeqNo++,
|
||||||
@ -278,10 +282,11 @@ EventStoreConnectionLogicHandler.prototype._startSubscription = function(msg) {
|
|||||||
this._state === ConnectionState.Connected ? "fire" : "enqueue",
|
this._state === ConnectionState.Connected ? "fire" : "enqueue",
|
||||||
operation.constructor.name, operation, msg.maxRetries, msg.timeout);
|
operation.constructor.name, operation, msg.maxRetries, msg.timeout);
|
||||||
var subscription = createSubscriptionItem(operation, msg.maxRetries, msg.timeout);
|
var subscription = createSubscriptionItem(operation, msg.maxRetries, msg.timeout);
|
||||||
if (this._state === ConnectionState.Connecting)
|
if (this._state === ConnectionState.Connecting) {
|
||||||
this._subscriptions.enqueueSubscription(subscription);
|
this._subscriptions.enqueueSubscription(subscription);
|
||||||
else
|
} else {
|
||||||
this._subscriptions.startSubscription(subscription, this._connection);
|
this._subscriptions.startSubscription(subscription, this._connection);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ConnectionState.Closed:
|
case ConnectionState.Closed:
|
||||||
msg.cb(new Error("Connection closed. Connection: " + this._esConnection.connectionName));
|
msg.cb(new Error("Connection closed. Connection: " + this._esConnection.connectionName));
|
||||||
@ -307,10 +312,11 @@ EventStoreConnectionLogicHandler.prototype._startPersistentSubscription = functi
|
|||||||
this._state === ConnectionState.Connected ? "fire" : "enqueue",
|
this._state === ConnectionState.Connected ? "fire" : "enqueue",
|
||||||
operation.constructor.name, operation, msg.maxRetries, msg.timeout);
|
operation.constructor.name, operation, msg.maxRetries, msg.timeout);
|
||||||
var subscription = createSubscriptionItem(operation, msg.maxRetries, msg.timeout);
|
var subscription = createSubscriptionItem(operation, msg.maxRetries, msg.timeout);
|
||||||
if (this._state === ConnectionState.Connecting)
|
if (this._state === ConnectionState.Connecting) {
|
||||||
this._subscriptions.enqueueSubscription(subscription);
|
this._subscriptions.enqueueSubscription(subscription);
|
||||||
else
|
} else {
|
||||||
this._subscriptions.startSubscription(subscription, this._connection);
|
this._subscriptions.startSubscription(subscription, this._connection);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ConnectionState.Closed:
|
case ConnectionState.Closed:
|
||||||
msg.cb(new Error("Connection closed. " + this._esConnection.connectionName));
|
msg.cb(new Error("Connection closed. " + this._esConnection.connectionName));
|
||||||
@ -391,10 +397,21 @@ EventStoreConnectionLogicHandler.prototype._tcpConnectionEstablished = function(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this._goToConnectedState();
|
this._goToIdentifiedState();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EventStoreConnectionLogicHandler.prototype._goToIdentifiedState = function() {
|
||||||
|
this._connectingPhase = ConnectingPhase.Identification;
|
||||||
|
this._identityInfo = {
|
||||||
|
correlationId: uuid.v4(),
|
||||||
|
timeStamp: Date.now()
|
||||||
|
};
|
||||||
|
var dto = new ClientMessage.IdentifyClient({version: ClientVersion, connectionName: this._esConnection.connectionName});
|
||||||
|
var buf = dto.constructor.encode(dto).finish();
|
||||||
|
this._connection.enqueueSend(new TcpPackage(TcpCommand.IdentifyClient, TcpFlags.None, this._identityInfo.correlationId, null, null, createBufferSegment(buf)))
|
||||||
|
};
|
||||||
|
|
||||||
EventStoreConnectionLogicHandler.prototype._goToConnectedState = function() {
|
EventStoreConnectionLogicHandler.prototype._goToConnectedState = function() {
|
||||||
this._state = ConnectionState.Connected;
|
this._state = ConnectionState.Connected;
|
||||||
this._connectingPhase = ConnectingPhase.Connected;
|
this._connectingPhase = ConnectingPhase.Connected;
|
||||||
@ -460,7 +477,26 @@ EventStoreConnectionLogicHandler.prototype._handleTcpPackage = function(connecti
|
|||||||
this._packageNumber += 1;
|
this._packageNumber += 1;
|
||||||
|
|
||||||
if (pkg.command === TcpCommand.HeartbeatResponseCommand)
|
if (pkg.command === TcpCommand.HeartbeatResponseCommand)
|
||||||
|
{
|
||||||
|
if (pkg.correlationId === this._heartbeatInfo.correlationId)
|
||||||
|
{
|
||||||
|
var now = Date.now();
|
||||||
|
var heartbeatEvent = {
|
||||||
|
connectionId: this._connection.connectionId,
|
||||||
|
remoteEndPoint: this._connection.remoteEndPoint,
|
||||||
|
requestSentAt: this._heartbeatInfo.timeStamp,
|
||||||
|
requestPkgNumber: this._heartbeatInfo.lastPackageNumber,
|
||||||
|
responseReceivedAt: now,
|
||||||
|
responsePkgNumber: this._packageNumber
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
this.emit('heartbeatInfo', heartbeatEvent);
|
||||||
|
} catch(e) {
|
||||||
|
this._logDebug("IGNORED: emit heartbeat event failed.\n%s", e.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (pkg.command === TcpCommand.HeartbeatRequestCommand)
|
if (pkg.command === TcpCommand.HeartbeatRequestCommand)
|
||||||
{
|
{
|
||||||
this._connection.enqueueSend(new TcpPackage(
|
this._connection.enqueueSend(new TcpPackage(
|
||||||
@ -479,6 +515,16 @@ EventStoreConnectionLogicHandler.prototype._handleTcpPackage = function(connecti
|
|||||||
if (pkg.command === TcpCommand.NotAuthenticated)
|
if (pkg.command === TcpCommand.NotAuthenticated)
|
||||||
this.emit('authenticationFailed', "Not authenticated");
|
this.emit('authenticationFailed', "Not authenticated");
|
||||||
|
|
||||||
|
this._goToIdentifiedState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg.command === TcpCommand.ClientIdentified)
|
||||||
|
{
|
||||||
|
if (this._state === ConnectionState.Connecting
|
||||||
|
&& this._identityInfo.correlationId === pkg.correlationId)
|
||||||
|
{
|
||||||
this._goToConnectedState();
|
this._goToConnectedState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -516,8 +562,9 @@ EventStoreConnectionLogicHandler.prototype._handleTcpPackage = function(connecti
|
|||||||
default:
|
default:
|
||||||
throw new Error("Unknown InspectionDecision: " + result.decision);
|
throw new Error("Unknown InspectionDecision: " + result.decision);
|
||||||
}
|
}
|
||||||
if (this._state === ConnectionState.Connected)
|
if (this._state === ConnectionState.Connected) {
|
||||||
this._operations.scheduleWaitingOperations(connection);
|
this._operations.scheduleWaitingOperations(connection);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -564,8 +611,7 @@ EventStoreConnectionLogicHandler.prototype._reconnectTo = function(endPoints) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._state !== ConnectionState.Connected || this._connection.remoteEndPoint === endPoint)
|
if (this._state !== ConnectionState.Connected || this._connection.remoteEndPoint === endPoint) return;
|
||||||
return;
|
|
||||||
|
|
||||||
var msg = util.format("EventStoreConnection '%s': going to reconnect to [%j]. Current endpoint: [%j, L%j].",
|
var msg = util.format("EventStoreConnection '%s': going to reconnect to [%j]. Current endpoint: [%j, L%j].",
|
||||||
this._esConnection.connectionName, endPoint, this._connection.remoteEndPoint, this._connection.localEndPoint);
|
this._esConnection.connectionName, endPoint, this._connection.remoteEndPoint, this._connection.localEndPoint);
|
||||||
@ -582,26 +628,26 @@ EventStoreConnectionLogicHandler.prototype._timerTick = function() {
|
|||||||
{
|
{
|
||||||
case ConnectionState.Init: break;
|
case ConnectionState.Init: break;
|
||||||
case ConnectionState.Connecting:
|
case ConnectionState.Connecting:
|
||||||
if (this._connectingPhase === ConnectingPhase.Reconnecting && (Date.now() - this._reconnInfo.timeStamp) >= this._settings.reconnectionDelay)
|
if (this._connectingPhase === ConnectingPhase.Reconnecting && (Date.now() - this._reconnInfo.timeStamp) >= this._settings.reconnectionDelay) {
|
||||||
{
|
|
||||||
this._logDebug("TimerTick checking reconnection...");
|
this._logDebug("TimerTick checking reconnection...");
|
||||||
|
|
||||||
this._reconnInfo = {reconnectionAttempt: this._reconnInfo.reconnectionAttempt + 1, timeStamp: Date.now()};
|
this._reconnInfo = {reconnectionAttempt: this._reconnInfo.reconnectionAttempt + 1, timeStamp: Date.now()};
|
||||||
if (this._settings.maxReconnections >= 0 && this._reconnInfo.reconnectionAttempt > this._settings.maxReconnections)
|
if (this._settings.maxReconnections >= 0 && this._reconnInfo.reconnectionAttempt > this._settings.maxReconnections) {
|
||||||
this._closeConnection("Reconnection limit reached.");
|
this._closeConnection("Reconnection limit reached.");
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
this.emit('reconnecting', {});
|
this.emit('reconnecting', {});
|
||||||
this._discoverEndpoint(null);
|
this._discoverEndpoint(null);
|
||||||
}
|
}
|
||||||
}
|
} else if (this._connectingPhase === ConnectingPhase.Authentication && (Date.now() - this._authInfo.timeStamp) >= this._settings.operationTimeout) {
|
||||||
else if (this._connectingPhase === ConnectingPhase.Authentication && (Date.now() - this._authInfo.timeStamp) >= this._settings.operationTimeout)
|
|
||||||
{
|
|
||||||
this.emit('authenticationFailed', "Authentication timed out.");
|
this.emit('authenticationFailed', "Authentication timed out.");
|
||||||
this._goToConnectedState();
|
if (this._clientVersion === 1) {
|
||||||
}
|
this._goToIdentifiedState();
|
||||||
else if (this._connectingPhase === ConnectingPhase.Authentication || this._connectingPhase === ConnectingPhase.Connected)
|
} else {
|
||||||
|
this._goToConnectedState();
|
||||||
|
}
|
||||||
|
} else if (this._connectingPhase === ConnectingPhase.Authentication || this._connectingPhase === ConnectingPhase.Connected) {
|
||||||
this._manageHeartbeats();
|
this._manageHeartbeats();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ConnectionState.Connected:
|
case ConnectionState.Connected:
|
||||||
// operations timeouts are checked only if connection is established and check period time passed
|
// operations timeouts are checked only if connection is established and check period time passed
|
||||||
@ -628,8 +674,7 @@ EventStoreConnectionLogicHandler.prototype._manageHeartbeats = function() {
|
|||||||
if (this._connection === null) return;
|
if (this._connection === null) return;
|
||||||
|
|
||||||
var timeout = this._heartbeatInfo.isIntervalStage ? this._settings.heartbeatInterval : this._settings.heartbeatTimeout;
|
var timeout = this._heartbeatInfo.isIntervalStage ? this._settings.heartbeatInterval : this._settings.heartbeatTimeout;
|
||||||
if ((Date.now() - this._heartbeatInfo.timeStamp) < timeout)
|
if ((Date.now() - this._heartbeatInfo.timeStamp) < timeout) return;
|
||||||
return;
|
|
||||||
|
|
||||||
var packageNumber = this._packageNumber;
|
var packageNumber = this._packageNumber;
|
||||||
if (this._heartbeatInfo.lastPackageNumber !== packageNumber)
|
if (this._heartbeatInfo.lastPackageNumber !== packageNumber)
|
||||||
@ -640,12 +685,13 @@ EventStoreConnectionLogicHandler.prototype._manageHeartbeats = function() {
|
|||||||
|
|
||||||
if (this._heartbeatInfo.isIntervalStage)
|
if (this._heartbeatInfo.isIntervalStage)
|
||||||
{
|
{
|
||||||
|
var correlationId = uuid.v4();
|
||||||
// TcpMessage.Heartbeat analog
|
// TcpMessage.Heartbeat analog
|
||||||
this._connection.enqueueSend(new TcpPackage(
|
this._connection.enqueueSend(new TcpPackage(
|
||||||
TcpCommand.HeartbeatRequestCommand,
|
TcpCommand.HeartbeatRequestCommand,
|
||||||
TcpFlags.None,
|
TcpFlags.None,
|
||||||
uuid.v4()));
|
correlationId));
|
||||||
this._heartbeatInfo = {lastPackageNumber: this._heartbeatInfo.lastPackageNumber, isIntervalStage: false, timeStamp: Date.now()};
|
this._heartbeatInfo = {correlationId: correlationId, lastPackageNumber: this._heartbeatInfo.lastPackageNumber, isIntervalStage: false, timeStamp: Date.now()};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -661,17 +707,19 @@ EventStoreConnectionLogicHandler.prototype._manageHeartbeats = function() {
|
|||||||
EventStoreConnectionLogicHandler.prototype._logDebug = function(message) {
|
EventStoreConnectionLogicHandler.prototype._logDebug = function(message) {
|
||||||
if (!this._settings.verboseLogging) return;
|
if (!this._settings.verboseLogging) return;
|
||||||
|
|
||||||
if (arguments.length > 1)
|
if (arguments.length > 1) {
|
||||||
message = util.format.apply(util, Array.prototype.slice.call(arguments));
|
message = util.format.apply(util, Array.prototype.slice.call(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
this._settings.log.debug("EventStoreConnection '%s': %s", this._esConnection.connectionName, message);
|
this._settings.log.debug("EventStoreConnection '%s': %s", this._esConnection.connectionName, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventStoreConnectionLogicHandler.prototype._logInfo = function(message){
|
EventStoreConnectionLogicHandler.prototype._logInfo = function(message){
|
||||||
if (arguments.length > 1)
|
if (arguments.length > 1) {
|
||||||
message = util.format.apply(util, Array.prototype.slice.call(arguments));
|
message = util.format.apply(util, Array.prototype.slice.call(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
this._settings.log.info("EventStoreConnection '%s': %s", this._esConnection.connectionName, message);
|
this._settings.log.info("EventStoreConnection '%s': %s", this._esConnection.connectionName, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = EventStoreConnectionLogicHandler;
|
module.exports = EventStoreConnectionLogicHandler;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var ensure = require('../common/utils/ensure');
|
|
||||||
|
|
||||||
function Message() {
|
function Message() {
|
||||||
}
|
}
|
||||||
|
@ -110,8 +110,7 @@ OperationsManager.prototype.checkTimeoutsAndRetry = function(connection) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
OperationsManager.prototype.scheduleOperationRetry = function(operation) {
|
OperationsManager.prototype.scheduleOperationRetry = function(operation) {
|
||||||
if (!this.removeOperation(operation))
|
if (!this.removeOperation(operation)) return;
|
||||||
return;
|
|
||||||
|
|
||||||
this._logDebug("ScheduleOperationRetry for %s.", operation);
|
this._logDebug("ScheduleOperationRetry for %s.", operation);
|
||||||
if (operation.maxRetries >= 0 && operation.retryCount >= operation.maxRetries)
|
if (operation.maxRetries >= 0 && operation.retryCount >= operation.maxRetries)
|
||||||
@ -166,10 +165,11 @@ OperationsManager.prototype.scheduleOperation = function(operation, connection)
|
|||||||
OperationsManager.prototype._logDebug = function(message) {
|
OperationsManager.prototype._logDebug = function(message) {
|
||||||
if (!this._settings.verboseLogging) return;
|
if (!this._settings.verboseLogging) return;
|
||||||
|
|
||||||
if (arguments.length > 1)
|
if (arguments.length > 1) {
|
||||||
message = util.format.apply(util, Array.prototype.slice.call(arguments));
|
message = util.format.apply(util, Array.prototype.slice.call(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
this._settings.log.debug("EventStoreConnection '%s': %s.", this._connectionName, message);
|
this._settings.log.debug("EventStoreConnection '%s': %s.", this._connectionName, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = OperationsManager;
|
module.exports = OperationsManager;
|
@ -1,24 +1,24 @@
|
|||||||
function typeName(t) {
|
function typeName(t) {
|
||||||
if (typeof t === 'function')
|
if (typeof t === 'function') return t.name;
|
||||||
return t.name;
|
if (typeof t === 'object') return t.constructor.name;
|
||||||
if (typeof t === 'object')
|
|
||||||
return t.constructor.name;
|
|
||||||
throw new TypeError('type must be a function or object, not ' + typeof t);
|
throw new TypeError('type must be a function or object, not ' + typeof t);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SimpleQueuedHandler() {
|
function SimpleQueuedHandler(log) {
|
||||||
this._handlers = {};
|
this._handlers = {};
|
||||||
this._messages = [];
|
this._messages = [];
|
||||||
this._isProcessing = false;
|
this._isProcessing = false;
|
||||||
|
this._log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleQueuedHandler.prototype.registerHandler = function(type, handler) {
|
SimpleQueuedHandler.prototype.registerHandler = function(type, handler) {
|
||||||
var typeId = typeName(type);
|
var typeId = typeName(type);
|
||||||
|
var log = this._log;
|
||||||
this._handlers[typeId] = function (msg) {
|
this._handlers[typeId] = function (msg) {
|
||||||
try {
|
try {
|
||||||
handler(msg);
|
handler(msg);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log('ERROR: ', e.stack);
|
log.error('handle for', type, 'failed:', e.stack);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -36,12 +36,11 @@ SimpleQueuedHandler.prototype._processQueue = function() {
|
|||||||
while(message) {
|
while(message) {
|
||||||
var typeId = typeName(message);
|
var typeId = typeName(message);
|
||||||
var handler = this._handlers[typeId];
|
var handler = this._handlers[typeId];
|
||||||
if (!handler)
|
if (!handler) throw new Error("No handler registered for message " + typeId);
|
||||||
throw new Error("No handler registered for message " + typeId);
|
|
||||||
setImmediate(handler, message);
|
setImmediate(handler, message);
|
||||||
message = this._messages.shift();
|
message = this._messages.shift();
|
||||||
}
|
}
|
||||||
this._isProcessing = false;
|
this._isProcessing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = SimpleQueuedHandler;
|
module.exports = SimpleQueuedHandler;
|
||||||
|
@ -8,11 +8,13 @@ function AccessDeniedError(action, streamOrTransactionId) {
|
|||||||
if (typeof streamOrTransactionId === 'string') {
|
if (typeof streamOrTransactionId === 'string') {
|
||||||
this.message = util.format("%s access denied for stream '%s'.", action, streamOrTransactionId);
|
this.message = util.format("%s access denied for stream '%s'.", action, streamOrTransactionId);
|
||||||
this.stream = streamOrTransactionId;
|
this.stream = streamOrTransactionId;
|
||||||
|
Object.freeze(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Long.isLong(streamOrTransactionId)) {
|
if (Long.isLong(streamOrTransactionId)) {
|
||||||
this.message = util.format("%s access denied for transaction %s.", action, streamOrTransactionId);
|
this.message = util.format("%s access denied for transaction %s.", action, streamOrTransactionId);
|
||||||
this.transactionId = streamOrTransactionId;
|
this.transactionId = streamOrTransactionId;
|
||||||
|
Object.freeze(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new TypeError("second argument must be a stream name or transaction Id.");
|
throw new TypeError("second argument must be a stream name or transaction Id.");
|
||||||
|
10
src/errors/projectionCommandFailedError.js
Normal file
10
src/errors/projectionCommandFailedError.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const util = require('util');
|
||||||
|
|
||||||
|
function ProjectionCommandFailedError(httpStatusCode, message) {
|
||||||
|
Error.captureStackTrace(this, this.constructor);
|
||||||
|
this.httpStatusCode = httpStatusCode;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
util.inherits(ProjectionCommandFailedError, Error);
|
||||||
|
|
||||||
|
module.exports = ProjectionCommandFailedError;
|
@ -7,11 +7,13 @@ function StreamDeletedError(streamOrTransactionId) {
|
|||||||
if (typeof streamOrTransactionId === 'string') {
|
if (typeof streamOrTransactionId === 'string') {
|
||||||
this.message = util.format("Event stream '%s' is deleted.", streamOrTransactionId);
|
this.message = util.format("Event stream '%s' is deleted.", streamOrTransactionId);
|
||||||
this.stream = streamOrTransactionId;
|
this.stream = streamOrTransactionId;
|
||||||
|
Object.freeze(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Long.isLong(streamOrTransactionId)) {
|
if (Long.isLong(streamOrTransactionId)) {
|
||||||
this.message = util.format("Stream is deleted for transaction %s.", streamOrTransactionId);
|
this.message = util.format("Stream is deleted for transaction %s.", streamOrTransactionId);
|
||||||
this.transactionId = streamOrTransactionId;
|
this.transactionId = streamOrTransactionId;
|
||||||
|
Object.freeze(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new TypeError("second argument must be a stream name or transaction Id.");
|
throw new TypeError("second argument must be a stream name or transaction Id.");
|
||||||
|
@ -9,11 +9,13 @@ function WrongExpectedVersionError(action, streamOrTransactionId, expectedVersio
|
|||||||
this.message = util.format("%s failed due to WrongExpectedVersion. Stream: %s Expected version: %d.", action, streamOrTransactionId, expectedVersion);
|
this.message = util.format("%s failed due to WrongExpectedVersion. Stream: %s Expected version: %d.", action, streamOrTransactionId, expectedVersion);
|
||||||
this.stream = streamOrTransactionId;
|
this.stream = streamOrTransactionId;
|
||||||
this.expectedVersion = expectedVersion;
|
this.expectedVersion = expectedVersion;
|
||||||
|
Object.freeze(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Long.isLong(streamOrTransactionId)) {
|
if (Long.isLong(streamOrTransactionId)) {
|
||||||
this.message = util.format("%s transaction failed due to WrongExpectedVersion. Transaction Id: %s.", action, streamOrTransactionId);
|
this.message = util.format("%s transaction failed due to WrongExpectedVersion. Transaction Id: %s.", action, streamOrTransactionId);
|
||||||
this.transactionId = streamOrTransactionId;
|
this.transactionId = streamOrTransactionId;
|
||||||
|
Object.freeze(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new TypeError("second argument must be a stream name or a transaction Id.");
|
throw new TypeError("second argument must be a stream name or a transaction Id.");
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
var uuid = require('uuid');
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||||
|
|
||||||
function isValidId(id) {
|
function isValidId(id) {
|
||||||
if (typeof id !== 'string') return false;
|
if (typeof id !== 'string') return false;
|
||||||
var buf = uuid.parse(id);
|
return uuidRegex.test(id);
|
||||||
var valid = false;
|
|
||||||
for(var i=0;i<buf.length;i++)
|
|
||||||
if (buf[i] !== 0)
|
|
||||||
valid = true;
|
|
||||||
return valid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,8 +24,9 @@ function EventData(eventId, type, isJson, data, metadata) {
|
|||||||
this.eventId = eventId;
|
this.eventId = eventId;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.isJson = isJson || false;
|
this.isJson = isJson || false;
|
||||||
this.data = data || new Buffer(0);
|
this.data = data || Buffer.alloc(0);
|
||||||
this.metadata = metadata || new Buffer(0);
|
this.metadata = metadata || Buffer.alloc(0);
|
||||||
|
Object.freeze(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = EventData;
|
module.exports = EventData;
|
||||||
|
@ -24,14 +24,10 @@ EventStoreAllCatchUpSubscription.prototype._readEventsTill = function(
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function processEvents(events, index) {
|
function processEvents(events, index) {
|
||||||
index = index || 0;
|
|
||||||
if (index >= events.length) return Promise.resolve();
|
if (index >= events.length) return Promise.resolve();
|
||||||
if (events[index].originalPosition === null) throw new Error("Subscription event came up with no OriginalPosition.");
|
if (events[index].originalPosition === null) throw new Error("Subscription event came up with no OriginalPosition.");
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return self._tryProcess(events[index])
|
||||||
self._tryProcess(events[index]);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return processEvents(events, index + 1);
|
return processEvents(events, index + 1);
|
||||||
});
|
});
|
||||||
@ -40,18 +36,16 @@ EventStoreAllCatchUpSubscription.prototype._readEventsTill = function(
|
|||||||
function readNext() {
|
function readNext() {
|
||||||
return connection.readAllEventsForward(self._nextReadPosition, self.readBatchSize, resolveLinkTos, userCredentials)
|
return connection.readAllEventsForward(self._nextReadPosition, self.readBatchSize, resolveLinkTos, userCredentials)
|
||||||
.then(function(slice) {
|
.then(function(slice) {
|
||||||
return processEvents(slice.events)
|
return processEvents(slice.events, 0)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
self._nextReadPosition = slice.nextPosition;
|
self._nextReadPosition = slice.nextPosition;
|
||||||
var done = lastCommitPosition === null
|
return (lastCommitPosition === null)
|
||||||
? slice.isEndOfStream
|
? slice.isEndOfStream
|
||||||
: slice.nextPosition.compareTo(new results.Position(lastCommitPosition, lastCommitPosition)) >= 0;
|
: slice.nextPosition.compareTo(new results.Position(lastCommitPosition, lastCommitPosition)) >= 0;
|
||||||
return Promise.resolve(done);
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function(done) {
|
.then(function(done) {
|
||||||
if (done || self._shouldStop)
|
if (done || self._shouldStop) return;
|
||||||
return;
|
|
||||||
return readNext();
|
return readNext();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -67,16 +61,19 @@ EventStoreAllCatchUpSubscription.prototype._readEventsTill = function(
|
|||||||
|
|
||||||
EventStoreAllCatchUpSubscription.prototype._tryProcess = function(e) {
|
EventStoreAllCatchUpSubscription.prototype._tryProcess = function(e) {
|
||||||
var processed = false;
|
var processed = false;
|
||||||
|
var promise;
|
||||||
if (e.originalPosition.compareTo(this._lastProcessedPosition) > 0)
|
if (e.originalPosition.compareTo(this._lastProcessedPosition) > 0)
|
||||||
{
|
{
|
||||||
this._eventAppeared(this, e);
|
promise = this._eventAppeared(this, e);
|
||||||
this._lastProcessedPosition = e.originalPosition;
|
this._lastProcessedPosition = e.originalPosition;
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
if (this._verbose)
|
if (this._verbose) {
|
||||||
this._log.debug("Catch-up Subscription to %s: %s event (%s, %d, %s @ %s).",
|
this._log.debug("Catch-up Subscription to %s: %s event (%s, %d, %s @ %s).",
|
||||||
this.streamId || '<all>', processed ? "processed" : "skipping",
|
this.streamId || '<all>', processed ? "processed" : "skipping",
|
||||||
e.originalEvent.eventStreamId, e.originalEvent.eventNumber, e.originalEvent.eventType, e.originalPosition);
|
e.originalEvent.eventStreamId, e.originalEvent.eventNumber, e.originalEvent.eventType, e.originalPosition);
|
||||||
|
}
|
||||||
|
return (promise && promise.then) ? promise : Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = EventStoreAllCatchUpSubscription;
|
module.exports = EventStoreAllCatchUpSubscription;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
var SubscriptionDropReason = require('./subscriptionDropReason');
|
var SubscriptionDropReason = require('./subscriptionDropReason');
|
||||||
var results = require('./results');
|
|
||||||
|
|
||||||
const DefaultReadBatchSize = 500;
|
const DefaultReadBatchSize = 500;
|
||||||
const DefaultMaxPushQueueSize = 10000;
|
const DefaultMaxPushQueueSize = 10000;
|
||||||
@ -68,9 +67,9 @@ function EventStoreCatchUpSubscription(
|
|||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this._onReconnect = function() {
|
this._onReconnect = function() {
|
||||||
if (self._verbose) self._log.debug("Catch-up Subscription to %s: recovering after reconnection.", self._streamId || '<all>');
|
|
||||||
if (self._verbose) self._log.debug("Catch-up Subscription to %s: unhooking from connection.Connected.", self._streamId || '<all>');
|
if (self._verbose) self._log.debug("Catch-up Subscription to %s: unhooking from connection.Connected.", self._streamId || '<all>');
|
||||||
self._connection.removeListener('connected', self._onReconnect);
|
self._connection.removeListener('connected', self._onReconnect);
|
||||||
|
if (self._verbose) self._log.debug("Catch-up Subscription to %s: recovering after reconnection.", self._streamId || '<all>');
|
||||||
self._runSubscription();
|
self._runSubscription();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,15 +127,18 @@ EventStoreCatchUpSubscription.prototype._runSubscription = function() {
|
|||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this._stopped = false;
|
this._stopped = false;
|
||||||
|
this._isDropped = false;
|
||||||
|
this._dropData = null;
|
||||||
if (this._verbose) this._log.debug("Catch-up Subscription to %s: pulling events...", logStreamName);
|
if (this._verbose) this._log.debug("Catch-up Subscription to %s: pulling events...", logStreamName);
|
||||||
this._readEventsTill(this._connection, this._resolveLinkTos, this._userCredentials, null, null)
|
this._readEventsTill(this._connection, this._resolveLinkTos, this._userCredentials, null, null)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (self._shouldStop) return;
|
if (self._shouldStop) return;
|
||||||
if (self._verbose) self._log.debug("Catch-up Subscription to %s: subscribing...", logStreamName);
|
if (self._verbose) self._log.debug("Catch-up Subscription to %s: subscribing...", logStreamName);
|
||||||
if (self._streamId === '')
|
if (self._streamId === '') {
|
||||||
return self._connection.subscribeToAll(self._resolveLinkTos, self._enqueuePushedEvent.bind(self), self._serverSubscriptionDropped.bind(self), self._userCredentials);
|
return self._connection.subscribeToAll(self._resolveLinkTos, self._enqueuePushedEvent.bind(self), self._serverSubscriptionDropped.bind(self), self._userCredentials);
|
||||||
else
|
} else {
|
||||||
return self._connection.subscribeToStream(self._streamId, self._resolveLinkTos, self._enqueuePushedEvent.bind(self), self._serverSubscriptionDropped.bind(self), self._userCredentials);
|
return self._connection.subscribeToStream(self._streamId, self._resolveLinkTos, self._enqueuePushedEvent.bind(self), self._serverSubscriptionDropped.bind(self), self._userCredentials);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.then(function(subscription) {
|
.then(function(subscription) {
|
||||||
if (subscription === undefined) return;
|
if (subscription === undefined) return;
|
||||||
@ -155,12 +157,13 @@ EventStoreCatchUpSubscription.prototype._runSubscription = function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (self._verbose) self._log.debug("Catch-up Subscription to %s: processing live events...", logStreamName);
|
if (self._verbose) self._log.debug("Catch-up Subscription to %s: processing live events...", logStreamName);
|
||||||
if (self._liveProcessingStarted)
|
if (self._liveProcessingStarted) {
|
||||||
try {
|
try {
|
||||||
self._liveProcessingStarted(self);
|
self._liveProcessingStarted(self);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
self._log.error(e, "Catch-up Subscription to %s: liveProcessingStarted callback failed.", logStreamName);
|
self._log.error(e, "Catch-up Subscription to %s: liveProcessingStarted callback failed.", logStreamName);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (self._verbose) self._log.debug("Catch-up Subscription to %s: hooking to connection.Connected", logStreamName);
|
if (self._verbose) self._log.debug("Catch-up Subscription to %s: hooking to connection.Connected", logStreamName);
|
||||||
self._connection.on('connected', self._onReconnect);
|
self._connection.on('connected', self._onReconnect);
|
||||||
self._allowProcessing = true;
|
self._allowProcessing = true;
|
||||||
@ -169,10 +172,11 @@ EventStoreCatchUpSubscription.prototype._runSubscription = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
EventStoreCatchUpSubscription.prototype._enqueuePushedEvent = function(subscription, e) {
|
EventStoreCatchUpSubscription.prototype._enqueuePushedEvent = function(subscription, e) {
|
||||||
if (this._verbose)
|
if (this._verbose) {
|
||||||
this._log.debug("Catch-up Subscription to %s: event appeared (%s, %d, %s @ %s).",
|
this._log.debug("Catch-up Subscription to %s: event appeared (%s, %d, %s @ %s).",
|
||||||
this._streamId || '<all>',
|
this._streamId || '<all>',
|
||||||
e.originalStreamId, e.originalEventNumber, e.originalEvent.eventType, e.originalPosition);
|
e.originalStreamId, e.originalEventNumber, e.originalEvent.eventType, e.originalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._liveQueue.length >= this.maxPushQueueSize)
|
if (this._liveQueue.length >= this.maxPushQueueSize)
|
||||||
{
|
{
|
||||||
@ -183,8 +187,7 @@ EventStoreCatchUpSubscription.prototype._enqueuePushedEvent = function(subscript
|
|||||||
|
|
||||||
this._liveQueue.push(e);
|
this._liveQueue.push(e);
|
||||||
|
|
||||||
if (this._allowProcessing)
|
if (this._allowProcessing) this._ensureProcessingPushQueue();
|
||||||
this._ensureProcessingPushQueue();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EventStoreCatchUpSubscription.prototype._serverSubscriptionDropped = function(subscription, reason, err) {
|
EventStoreCatchUpSubscription.prototype._serverSubscriptionDropped = function(subscription, reason, err) {
|
||||||
@ -196,8 +199,7 @@ EventStoreCatchUpSubscription.prototype._enqueueSubscriptionDropNotification = f
|
|||||||
if (this._dropData) return;
|
if (this._dropData) return;
|
||||||
this._dropData = {reason: reason, error: error};
|
this._dropData = {reason: reason, error: error};
|
||||||
this._liveQueue.push(new DropSubscriptionEvent());
|
this._liveQueue.push(new DropSubscriptionEvent());
|
||||||
if (this._allowProcessing)
|
if (this._allowProcessing) this._ensureProcessingPushQueue();
|
||||||
this._ensureProcessingPushQueue();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EventStoreCatchUpSubscription.prototype._ensureProcessingPushQueue = function() {
|
EventStoreCatchUpSubscription.prototype._ensureProcessingPushQueue = function() {
|
||||||
@ -209,44 +211,54 @@ EventStoreCatchUpSubscription.prototype._ensureProcessingPushQueue = function()
|
|||||||
|
|
||||||
EventStoreCatchUpSubscription.prototype._processLiveQueue = function() {
|
EventStoreCatchUpSubscription.prototype._processLiveQueue = function() {
|
||||||
var ev = this._liveQueue.shift();
|
var ev = this._liveQueue.shift();
|
||||||
//TODO: possible blocking while, use when
|
if (!ev) {
|
||||||
while(ev) {
|
this._isProcessing = false;
|
||||||
if (ev instanceof DropSubscriptionEvent) {
|
return;
|
||||||
if (!this._dropData) this._dropData = {reason: SubscriptionDropReason.Unknown, error: new Error("Drop reason not specified.")};
|
}
|
||||||
this._dropSubscription(this._dropData.reason, this._dropData.error);
|
if (ev instanceof DropSubscriptionEvent) {
|
||||||
this._isProcessing = false;
|
if (!this._dropData) this._dropData = {reason: SubscriptionDropReason.Unknown, error: new Error("Drop reason not specified.")};
|
||||||
return;
|
this._dropSubscription(this._dropData.reason, this._dropData.error);
|
||||||
}
|
this._isProcessing = false;
|
||||||
|
return;
|
||||||
try {
|
}
|
||||||
this._tryProcess(ev);
|
var promise;
|
||||||
}
|
try {
|
||||||
catch(err) {
|
promise = this._tryProcess(ev);
|
||||||
this._dropSubscription(SubscriptionDropReason.EventHandlerException, err);
|
}
|
||||||
return;
|
catch(err) {
|
||||||
}
|
this._dropSubscription(SubscriptionDropReason.EventHandlerException, err);
|
||||||
ev = this._liveQueue.shift();
|
this._isProcessing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (promise && promise.then) {
|
||||||
|
var self = this;
|
||||||
|
promise
|
||||||
|
.then(this._processLiveQueue.bind(this), function(err) {
|
||||||
|
self._dropSubscription(SubscriptionDropReason.EventHandlerException, err);
|
||||||
|
self._isProcessing = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setImmediate(this._processLiveQueue.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isProcessing = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EventStoreCatchUpSubscription.prototype._dropSubscription = function(reason, error) {
|
EventStoreCatchUpSubscription.prototype._dropSubscription = function(reason, error) {
|
||||||
if (this._isDropped) return;
|
if (this._isDropped) return;
|
||||||
|
|
||||||
this._isDropped = true;
|
this._isDropped = true;
|
||||||
if (this._verbose)
|
if (this._verbose) {
|
||||||
this._log.debug("Catch-up Subscription to %s: dropping subscription, reason: %s %s.",
|
this._log.debug("Catch-up Subscription to %s: dropping subscription, reason: %s %s.",
|
||||||
this._streamId || '<all>', reason, error);
|
this._streamId || '<all>', reason, error);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._subscription)
|
if (this._subscription) this._subscription.unsubscribe();
|
||||||
this._subscription.unsubscribe();
|
if (this._subscriptionDropped) {
|
||||||
if (this._subscriptionDropped)
|
|
||||||
try {
|
try {
|
||||||
this._subscriptionDropped(this, reason, error);
|
this._subscriptionDropped(this, reason, error);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
this._log.error(e, "Catch-up Subscription to %s: subscriptionDropped callback failed.", this._streamId || '<all>');
|
this._log.error(e, "Catch-up Subscription to %s: subscriptionDropped callback failed.", this._streamId || '<all>');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this._stopped = true;
|
this._stopped = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
var EventStoreNodeConnection = require('./eventStoreNodeConnection');
|
var EventStoreNodeConnection = require('./eventStoreNodeConnection');
|
||||||
var StaticEndpointDiscoverer = require('./core/staticEndpointDiscoverer');
|
var StaticEndpointDiscoverer = require('./core/staticEndpointDiscoverer');
|
||||||
var ClusterDnsEndPointDiscoverer = require('./core/clusterDnsEndPointDiscoverer');
|
var ClusterDiscoverer = require('./core/cluster/clusterDiscoverer');
|
||||||
var NoopLogger = require('./common/log/noopLogger');
|
var NoopLogger = require('./common/log/noopLogger');
|
||||||
var ensure = require('./common/utils/ensure');
|
var ensure = require('./common/utils/ensure');
|
||||||
|
|
||||||
var defaultConnectionSettings = {
|
const util = require('util');
|
||||||
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
|
const dns = require('dns');
|
||||||
|
|
||||||
|
const dnsService = {
|
||||||
|
lookup : util.promisify(dns.lookup),
|
||||||
|
ADDRCONFIG: dns.ADDRCONFIG,
|
||||||
|
V4MAPPED: dns.V4MAPPED
|
||||||
|
};
|
||||||
|
|
||||||
|
var defaultConnectionSettings = Object.freeze({
|
||||||
log: new NoopLogger(),
|
log: new NoopLogger(),
|
||||||
verboseLogging: false,
|
verboseLogging: false,
|
||||||
|
|
||||||
@ -32,9 +43,10 @@ var defaultConnectionSettings = {
|
|||||||
// Cluster Settings
|
// Cluster Settings
|
||||||
clusterDns: '',
|
clusterDns: '',
|
||||||
maxDiscoverAttempts: 10,
|
maxDiscoverAttempts: 10,
|
||||||
|
discoverDelay: 500,
|
||||||
externalGossipPort: 0,
|
externalGossipPort: 0,
|
||||||
gossipTimeout: 1000
|
gossipTimeout: 1000
|
||||||
};
|
});
|
||||||
|
|
||||||
|
|
||||||
function merge(a,b) {
|
function merge(a,b) {
|
||||||
@ -80,17 +92,18 @@ function createFromClusterDns(connectionSettings, clusterDns, externalGossipPort
|
|||||||
var mergedSettings = merge(defaultConnectionSettings, connectionSettings || {});
|
var mergedSettings = merge(defaultConnectionSettings, connectionSettings || {});
|
||||||
var clusterSettings = {
|
var clusterSettings = {
|
||||||
clusterDns: clusterDns,
|
clusterDns: clusterDns,
|
||||||
gossipSeeds: null,
|
seeds: null,
|
||||||
externalGossipPort: externalGossipPort,
|
managerExternalHttpPort: externalGossipPort,
|
||||||
maxDiscoverAttempts: mergedSettings.maxDiscoverAttempts,
|
maxDiscoverAttempts: mergedSettings.maxDiscoverAttempts,
|
||||||
gossipTimeout: mergedSettings.gossipTimeout
|
discoverDelay: mergedSettings.discoverDelay,
|
||||||
|
gossipTimeout: mergedSettings.gossipTimeout,
|
||||||
|
rejectUnauthorized: connectionSettings.useSslConnection ? connectionSettings.validateServer : undefined
|
||||||
};
|
};
|
||||||
var endPointDiscoverer = new ClusterDnsEndPointDiscoverer(mergedSettings.log,
|
var endPointDiscoverer = new ClusterDiscoverer(
|
||||||
clusterSettings.clusterDns,
|
mergedSettings.log,
|
||||||
clusterSettings.maxDiscoverAttempts,
|
clusterSettings,
|
||||||
clusterSettings.externalGossipPort,
|
dnsService,
|
||||||
clusterSettings.gossipSeeds,
|
connectionSettings.useSslConnection ? https : http
|
||||||
clusterSettings.gossipTimeout
|
|
||||||
);
|
);
|
||||||
return new EventStoreNodeConnection(mergedSettings, clusterSettings, endPointDiscoverer, connectionName);
|
return new EventStoreNodeConnection(mergedSettings, clusterSettings, endPointDiscoverer, connectionName);
|
||||||
}
|
}
|
||||||
@ -101,17 +114,18 @@ function createFromGossipSeeds(connectionSettings, gossipSeeds, connectionName)
|
|||||||
var mergedSettings = merge(defaultConnectionSettings, connectionSettings || {});
|
var mergedSettings = merge(defaultConnectionSettings, connectionSettings || {});
|
||||||
var clusterSettings = {
|
var clusterSettings = {
|
||||||
clusterDns: '',
|
clusterDns: '',
|
||||||
gossipSeeds: gossipSeeds,
|
seeds: gossipSeeds,
|
||||||
externalGossipPort: 0,
|
externalGossipPort: 0,
|
||||||
maxDiscoverAttempts: mergedSettings.maxDiscoverAttempts,
|
maxDiscoverAttempts: mergedSettings.maxDiscoverAttempts,
|
||||||
gossipTimeout: mergedSettings.gossipTimeout
|
discoverDelay: mergedSettings.discoverDelay,
|
||||||
|
gossipTimeout: mergedSettings.gossipTimeout,
|
||||||
|
rejectUnauthorized: connectionSettings.useSslConnection ? connectionSettings.validateServer : undefined
|
||||||
};
|
};
|
||||||
var endPointDiscoverer = new ClusterDnsEndPointDiscoverer(mergedSettings.log,
|
var endPointDiscoverer = new ClusterDiscoverer(
|
||||||
clusterSettings.clusterDns,
|
mergedSettings.log,
|
||||||
clusterSettings.maxDiscoverAttempts,
|
clusterSettings,
|
||||||
clusterSettings.externalGossipPort,
|
dnsService,
|
||||||
clusterSettings.gossipSeeds,
|
connectionSettings.useSslConnection ? https : http
|
||||||
clusterSettings.gossipTimeout
|
|
||||||
);
|
);
|
||||||
return new EventStoreNodeConnection(mergedSettings, clusterSettings, endPointDiscoverer, connectionName);
|
return new EventStoreNodeConnection(mergedSettings, clusterSettings, endPointDiscoverer, connectionName);
|
||||||
}
|
}
|
||||||
@ -121,6 +135,27 @@ function createFromGossipSeeds(connectionSettings, gossipSeeds, connectionName)
|
|||||||
* @public
|
* @public
|
||||||
* @alias createConnection
|
* @alias createConnection
|
||||||
* @param {object} settings
|
* @param {object} settings
|
||||||
|
* @param {boolean} [settings.verboseLogging=false]
|
||||||
|
* @param {number} [settings.maxQueueSize=5000]
|
||||||
|
* @param {number} [settings.maxConcurrentItems=5000]
|
||||||
|
* @param {number} [settings.maxRetries=10]
|
||||||
|
* @param {number} [settings.maxReconnections=10]
|
||||||
|
* @param {boolean} [settings.requireMaster=true]
|
||||||
|
* @param {number} [settings.reconnectionDelay=100]
|
||||||
|
* @param {number} [settings.operationTimeout=7000]
|
||||||
|
* @param {number} [settings.operationTimeoutCheckPeriod=1000]
|
||||||
|
* @param {object} [settings.defaultUserCredentials=null] - The default user credentials to use for requests
|
||||||
|
* @param {boolean} [settings.useSslConnection=false] - Whether to use SSL or not
|
||||||
|
* @param {object} [settings.targetHost=null]
|
||||||
|
* @param {boolean} [settings.validateServer=false]
|
||||||
|
* @param {boolean} [settings.failOnNoServerResponse=false]
|
||||||
|
* @param {number} [settings.heartbeatInterval=750]
|
||||||
|
* @param {number} [settings.heartbeatTimeout=1500]
|
||||||
|
* @param {number} [settings.clientConnectionTimeout=1000]
|
||||||
|
* @param {string} [settings.clusterDns='']
|
||||||
|
* @param {number} [settings.maxDiscoverAttempts=10]
|
||||||
|
* @param {number} [settings.externalGossipPort=0]
|
||||||
|
* @param {number} [settings.gossipTimeout=1000]
|
||||||
* @param {string|object|array} endPointOrGossipSeeds
|
* @param {string|object|array} endPointOrGossipSeeds
|
||||||
* @param {string} [connectionName]
|
* @param {string} [connectionName]
|
||||||
* @returns {EventStoreNodeConnection}
|
* @returns {EventStoreNodeConnection}
|
||||||
@ -130,4 +165,4 @@ module.exports.create = function(settings, endPointOrGossipSeeds, connectionName
|
|||||||
if (typeof endPointOrGossipSeeds === 'object') return createFromTcpEndpoint(settings, endPointOrGossipSeeds, connectionName);
|
if (typeof endPointOrGossipSeeds === 'object') return createFromTcpEndpoint(settings, endPointOrGossipSeeds, connectionName);
|
||||||
if (typeof endPointOrGossipSeeds === 'string') return createFromStringEndpoint(settings, endPointOrGossipSeeds, connectionName);
|
if (typeof endPointOrGossipSeeds === 'string') return createFromStringEndpoint(settings, endPointOrGossipSeeds, connectionName);
|
||||||
throw new TypeError('endPointOrGossipSeeds must be an object, a string or an array.');
|
throw new TypeError('endPointOrGossipSeeds must be an object, a string or an array.');
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var uuid = require('uuid');
|
var uuid = require('uuid');
|
||||||
|
var Long = require('long');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var ensure = require('./common/utils/ensure');
|
var ensure = require('./common/utils/ensure');
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ const MaxReadSize = 4096;
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EventStoreNodeConnection(settings, clusterSettings, endpointDiscoverer, connectionName) {
|
function EventStoreNodeConnection(settings, clusterSettings, endpointDiscoverer, connectionName) {
|
||||||
|
EventEmitter.call(this);
|
||||||
this._connectionName = connectionName || ['ES-', uuid.v4()].join('');
|
this._connectionName = connectionName || ['ES-', uuid.v4()].join('');
|
||||||
this._settings = settings;
|
this._settings = settings;
|
||||||
this._clusterSettings = clusterSettings;
|
this._clusterSettings = clusterSettings;
|
||||||
@ -59,6 +61,9 @@ function EventStoreNodeConnection(settings, clusterSettings, endpointDiscoverer,
|
|||||||
this._handler.on('error', function(e) {
|
this._handler.on('error', function(e) {
|
||||||
self.emit('error', e);
|
self.emit('error', e);
|
||||||
});
|
});
|
||||||
|
this._handler.on('heartbeatInfo', function(e) {
|
||||||
|
self.emit('heartbeatInfo', e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
util.inherits(EventStoreNodeConnection, EventEmitter);
|
util.inherits(EventStoreNodeConnection, EventEmitter);
|
||||||
|
|
||||||
@ -97,15 +102,16 @@ EventStoreNodeConnection.prototype.close = function() {
|
|||||||
* Delete a stream (async)
|
* Delete a stream (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} expectedVersion
|
* @param {Long|number} expectedVersion
|
||||||
* @param {boolean} [hardDelete]
|
* @param {boolean} [hardDelete]
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
* @returns {Promise.<DeleteResult>}
|
* @returns {Promise.<DeleteResult>}
|
||||||
*/
|
*/
|
||||||
EventStoreNodeConnection.prototype.deleteStream = function(stream, expectedVersion, hardDelete, userCredentials) {
|
EventStoreNodeConnection.prototype.deleteStream = function(stream, expectedVersion, hardDelete, userCredentials) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isInteger(expectedVersion, "expectedVersion");
|
ensure.isLongOrInteger(expectedVersion, "expectedVersion");
|
||||||
hardDelete = !!hardDelete;
|
expectedVersion = Long.fromValue(expectedVersion);
|
||||||
|
hardDelete = Boolean(hardDelete);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -125,16 +131,16 @@ EventStoreNodeConnection.prototype.deleteStream = function(stream, expectedVersi
|
|||||||
* Append events to a stream (async)
|
* Append events to a stream (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream The name of the stream to which to append.
|
* @param {string} stream The name of the stream to which to append.
|
||||||
* @param {number} expectedVersion The version at which we currently expect the stream to be in order that an optimistic concurrency check can be performed.
|
* @param {Long|number} expectedVersion The version at which we currently expect the stream to be in order that an optimistic concurrency check can be performed.
|
||||||
* @param {EventData[]|EventData} events The event(s) to append.
|
* @param {EventData[]|EventData} events The event(s) to append.
|
||||||
* @param {UserCredentials} [userCredentials] User credentials
|
* @param {UserCredentials} [userCredentials] User credentials
|
||||||
* @returns {Promise.<WriteResult>}
|
* @returns {Promise.<WriteResult>}
|
||||||
*/
|
*/
|
||||||
EventStoreNodeConnection.prototype.appendToStream = function(stream, expectedVersion, events, userCredentials) {
|
EventStoreNodeConnection.prototype.appendToStream = function(stream, expectedVersion, events, userCredentials) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isInteger(expectedVersion, "expectedVersion");
|
ensure.isLongOrInteger(expectedVersion, "expectedVersion");
|
||||||
if (!Array.isArray(events))
|
expectedVersion = Long.fromValue(expectedVersion);
|
||||||
events = [events];
|
if (!Array.isArray(events)) events = [events];
|
||||||
ensure.isArrayOf(EventData, events, "events");
|
ensure.isArrayOf(EventData, events, "events");
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
@ -154,13 +160,14 @@ EventStoreNodeConnection.prototype.appendToStream = function(stream, expectedVer
|
|||||||
* Start a transaction (async)
|
* Start a transaction (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} expectedVersion
|
* @param {Long|number} expectedVersion
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
* @returns {Promise.<EventStoreTransaction>}
|
* @returns {Promise.<EventStoreTransaction>}
|
||||||
*/
|
*/
|
||||||
EventStoreNodeConnection.prototype.startTransaction = function(stream, expectedVersion, userCredentials) {
|
EventStoreNodeConnection.prototype.startTransaction = function(stream, expectedVersion, userCredentials) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isInteger(expectedVersion, "expectedVersion");
|
ensure.isLongOrInteger(expectedVersion, "expectedVersion");
|
||||||
|
expectedVersion = Long.fromValue(expectedVersion);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -231,21 +238,20 @@ EventStoreNodeConnection.prototype.commitTransaction = function(transaction, use
|
|||||||
* Read a single event (async)
|
* Read a single event (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} eventNumber
|
* @param {Long|number} eventNumber
|
||||||
* @param {boolean} [resolveLinkTos]
|
* @param {boolean} [resolveLinkTos]
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
* @returns {Promise.<EventReadResult>}
|
* @returns {Promise.<EventReadResult>}
|
||||||
*/
|
*/
|
||||||
EventStoreNodeConnection.prototype.readEvent = function(stream, eventNumber, resolveLinkTos, userCredentials) {
|
EventStoreNodeConnection.prototype.readEvent = function(stream, eventNumber, resolveLinkTos, userCredentials) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isInteger(eventNumber, "eventNumber");
|
ensure.isLongOrInteger(eventNumber, "eventNumber");
|
||||||
if (eventNumber < -1) throw new Error("eventNumber out of range.");
|
eventNumber = Long.fromValue(eventNumber);
|
||||||
resolveLinkTos = !!resolveLinkTos;
|
resolveLinkTos = Boolean(resolveLinkTos);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
if (typeof stream !== 'string' || stream === '') throw new TypeError("stream must be an non-empty string.");
|
if (typeof stream !== 'string' || stream === '') throw new TypeError("stream must be an non-empty string.");
|
||||||
if (typeof eventNumber !== 'number' || eventNumber % 1 !== 0) throw new TypeError("eventNumber must be an integer.");
|
if (eventNumber.compare(-1) < 0) throw new Error("eventNumber out of range.");
|
||||||
if (eventNumber < -1) throw new Error("eventNumber out of range.");
|
|
||||||
if (resolveLinkTos && typeof resolveLinkTos !== 'boolean') throw new TypeError("resolveLinkTos must be a boolean.");
|
if (resolveLinkTos && typeof resolveLinkTos !== 'boolean') throw new TypeError("resolveLinkTos must be a boolean.");
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -264,7 +270,7 @@ EventStoreNodeConnection.prototype.readEvent = function(stream, eventNumber, res
|
|||||||
* Reading a specific stream forwards (async)
|
* Reading a specific stream forwards (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} start
|
* @param {Long|number} start
|
||||||
* @param {number} count
|
* @param {number} count
|
||||||
* @param {boolean} [resolveLinkTos]
|
* @param {boolean} [resolveLinkTos]
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
@ -274,12 +280,13 @@ EventStoreNodeConnection.prototype.readStreamEventsForward = function(
|
|||||||
stream, start, count, resolveLinkTos, userCredentials
|
stream, start, count, resolveLinkTos, userCredentials
|
||||||
) {
|
) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isInteger(start, "start");
|
ensure.isLongOrInteger(start, "start");
|
||||||
|
start = Long.fromValue(start);
|
||||||
ensure.nonNegative(start, "start");
|
ensure.nonNegative(start, "start");
|
||||||
ensure.isInteger(count, "count");
|
ensure.isInteger(count, "count");
|
||||||
ensure.positive(count, "count");
|
ensure.positive(count, "count");
|
||||||
if (count > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
if (count > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
||||||
resolveLinkTos = !!resolveLinkTos;
|
resolveLinkTos = Boolean(resolveLinkTos);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -298,7 +305,7 @@ EventStoreNodeConnection.prototype.readStreamEventsForward = function(
|
|||||||
* Reading a specific stream backwards (async)
|
* Reading a specific stream backwards (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} start
|
* @param {Long|number} start
|
||||||
* @param {number} count
|
* @param {number} count
|
||||||
* @param {boolean} [resolveLinkTos]
|
* @param {boolean} [resolveLinkTos]
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
@ -308,11 +315,12 @@ EventStoreNodeConnection.prototype.readStreamEventsBackward = function(
|
|||||||
stream, start, count, resolveLinkTos, userCredentials
|
stream, start, count, resolveLinkTos, userCredentials
|
||||||
) {
|
) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isInteger(start, "start");
|
ensure.isLongOrInteger(start, "start");
|
||||||
|
start = Long.fromValue(start);
|
||||||
ensure.isInteger(count, "count");
|
ensure.isInteger(count, "count");
|
||||||
ensure.positive(count, "count");
|
ensure.positive(count, "count");
|
||||||
if (count > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
if (count > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
||||||
resolveLinkTos = !!resolveLinkTos;
|
resolveLinkTos = Boolean(resolveLinkTos);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -343,7 +351,7 @@ EventStoreNodeConnection.prototype.readAllEventsForward = function(
|
|||||||
ensure.isInteger(maxCount, "maxCount");
|
ensure.isInteger(maxCount, "maxCount");
|
||||||
ensure.positive(maxCount, "maxCount");
|
ensure.positive(maxCount, "maxCount");
|
||||||
if (maxCount > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
if (maxCount > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
||||||
resolveLinkTos = !!resolveLinkTos;
|
resolveLinkTos = Boolean(resolveLinkTos);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -374,7 +382,7 @@ EventStoreNodeConnection.prototype.readAllEventsBackward = function(
|
|||||||
ensure.isInteger(maxCount, "maxCount");
|
ensure.isInteger(maxCount, "maxCount");
|
||||||
ensure.positive(maxCount, "maxCount");
|
ensure.positive(maxCount, "maxCount");
|
||||||
if (maxCount > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
if (maxCount > MaxReadSize) throw new Error(util.format("Count should be less than %d. For larger reads you should page.", MaxReadSize));
|
||||||
resolveLinkTos = !!resolveLinkTos;
|
resolveLinkTos = Boolean(resolveLinkTos);
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -404,8 +412,7 @@ EventStoreNodeConnection.prototype.subscribeToStream = function(
|
|||||||
) {
|
) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
ensure.isTypeOf(Function, eventAppeared, "eventAppeared");
|
ensure.isTypeOf(Function, eventAppeared, "eventAppeared");
|
||||||
if (subscriptionDropped)
|
if (subscriptionDropped) ensure.isTypeOf(Function, subscriptionDropped, "subscriptionDropped");
|
||||||
ensure.isTypeOf(Function, subscriptionDropped, "subscriptionDropped");
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
return new Promise(function(resolve,reject) {
|
return new Promise(function(resolve,reject) {
|
||||||
@ -424,7 +431,7 @@ EventStoreNodeConnection.prototype.subscribeToStream = function(
|
|||||||
* Subscribe to a stream from position
|
* Subscribe to a stream from position
|
||||||
* @public
|
* @public
|
||||||
* @param {!string} stream
|
* @param {!string} stream
|
||||||
* @param {?number} lastCheckpoint
|
* @param {?number|Position} lastCheckpoint
|
||||||
* @param {!boolean} resolveLinkTos
|
* @param {!boolean} resolveLinkTos
|
||||||
* @param {!function} eventAppeared
|
* @param {!function} eventAppeared
|
||||||
* @param {function} [liveProcessingStarted]
|
* @param {function} [liveProcessingStarted]
|
||||||
@ -438,6 +445,10 @@ EventStoreNodeConnection.prototype.subscribeToStreamFrom = function(
|
|||||||
userCredentials, readBatchSize
|
userCredentials, readBatchSize
|
||||||
) {
|
) {
|
||||||
if (typeof stream !== 'string' || stream === '') throw new TypeError("stream must be a non-empty string.");
|
if (typeof stream !== 'string' || stream === '') throw new TypeError("stream must be a non-empty string.");
|
||||||
|
if (lastCheckpoint !== null) {
|
||||||
|
ensure.isLongOrInteger(lastCheckpoint);
|
||||||
|
lastCheckpoint = Long.fromValue(lastCheckpoint);
|
||||||
|
}
|
||||||
if (typeof eventAppeared !== 'function') throw new TypeError("eventAppeared must be a function.");
|
if (typeof eventAppeared !== 'function') throw new TypeError("eventAppeared must be a function.");
|
||||||
|
|
||||||
var catchUpSubscription =
|
var catchUpSubscription =
|
||||||
@ -515,7 +526,7 @@ EventStoreNodeConnection.prototype.subscribeToAllFrom = function(
|
|||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
* @param {number} [bufferSize]
|
* @param {number} [bufferSize]
|
||||||
* @param {boolean} [autoAck]
|
* @param {boolean} [autoAck]
|
||||||
* @return {EventStorePersistentSubscription}
|
* @return {Promise<EventStorePersistentSubscription>}
|
||||||
*/
|
*/
|
||||||
EventStoreNodeConnection.prototype.connectToPersistentSubscription = function(
|
EventStoreNodeConnection.prototype.connectToPersistentSubscription = function(
|
||||||
stream, groupName, eventAppeared, subscriptionDropped, userCredentials, bufferSize, autoAck
|
stream, groupName, eventAppeared, subscriptionDropped, userCredentials, bufferSize, autoAck
|
||||||
@ -527,14 +538,12 @@ EventStoreNodeConnection.prototype.connectToPersistentSubscription = function(
|
|||||||
subscriptionDropped = subscriptionDropped || null;
|
subscriptionDropped = subscriptionDropped || null;
|
||||||
userCredentials = userCredentials || null;
|
userCredentials = userCredentials || null;
|
||||||
bufferSize = bufferSize === undefined ? 10 : bufferSize;
|
bufferSize = bufferSize === undefined ? 10 : bufferSize;
|
||||||
autoAck = autoAck === undefined ? true : !!autoAck;
|
autoAck = autoAck === undefined ? true : Boolean(autoAck);
|
||||||
|
|
||||||
var subscription = new EventStorePersistentSubscription(
|
var subscription = new EventStorePersistentSubscription(
|
||||||
groupName, stream, eventAppeared, subscriptionDropped, userCredentials, this._settings.log,
|
groupName, stream, eventAppeared, subscriptionDropped, userCredentials, this._settings.log,
|
||||||
this._settings.verboseLogging, this._settings, this._handler, bufferSize, autoAck);
|
this._settings.verboseLogging, this._settings, this._handler, bufferSize, autoAck);
|
||||||
subscription.start();
|
return subscription.start();
|
||||||
|
|
||||||
return subscription;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -567,7 +576,7 @@ EventStoreNodeConnection.prototype.createPersistentSubscription = function(strea
|
|||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {string} groupName
|
* @param {string} groupName
|
||||||
* @param {string} settings
|
* @param {PersistentSubscriptionSettings} settings
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
* @returns {Promise.<PersistentSubscriptionUpdateResult>}
|
* @returns {Promise.<PersistentSubscriptionUpdateResult>}
|
||||||
*/
|
*/
|
||||||
@ -621,7 +630,7 @@ EventStoreNodeConnection.prototype.setStreamMetadata = function() {
|
|||||||
* Set stream metadata with raw object (async)
|
* Set stream metadata with raw object (async)
|
||||||
* @public
|
* @public
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} expectedMetastreamVersion
|
* @param {Long|number} expectedMetastreamVersion
|
||||||
* @param {object} metadata
|
* @param {object} metadata
|
||||||
* @param {UserCredentials} [userCredentials]
|
* @param {UserCredentials} [userCredentials]
|
||||||
* @returns {Promise.<WriteResult>}
|
* @returns {Promise.<WriteResult>}
|
||||||
@ -630,15 +639,18 @@ EventStoreNodeConnection.prototype.setStreamMetadataRaw = function(
|
|||||||
stream, expectedMetastreamVersion, metadata, userCredentials
|
stream, expectedMetastreamVersion, metadata, userCredentials
|
||||||
) {
|
) {
|
||||||
ensure.notNullOrEmpty(stream, "stream");
|
ensure.notNullOrEmpty(stream, "stream");
|
||||||
if (systemStreams.isMetastream(stream))
|
if (systemStreams.isMetastream(stream)) {
|
||||||
throw new Error(util.format("Setting metadata for metastream '%s' is not supported.", stream));
|
throw new Error(util.format("Setting metadata for metastream '%s' is not supported.", stream));
|
||||||
|
}
|
||||||
|
ensure.isLongOrInteger(expectedMetastreamVersion, "expectedMetastreamVersion");
|
||||||
|
expectedMetastreamVersion = Long.fromValue(expectedMetastreamVersion);
|
||||||
var self = this;
|
var self = this;
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
function cb(err, result) {
|
function cb(err, result) {
|
||||||
if (err) return reject(err);
|
if (err) return reject(err);
|
||||||
resolve(result);
|
resolve(result);
|
||||||
}
|
}
|
||||||
var data = metadata ? new Buffer(JSON.stringify(metadata)) : null;
|
var data = metadata ? Buffer.from(JSON.stringify(metadata)) : null;
|
||||||
var metaevent = new EventData(uuid.v4(), systemEventTypes.StreamMetadata, true, data, null);
|
var metaevent = new EventData(uuid.v4(), systemEventTypes.StreamMetadata, true, data, null);
|
||||||
self._enqueueOperation(
|
self._enqueueOperation(
|
||||||
new AppendToStreamOperation(self._settings.log, cb, self._settings.requireMaster,
|
new AppendToStreamOperation(self._settings.log, cb, self._settings.requireMaster,
|
||||||
@ -674,12 +686,12 @@ EventStoreNodeConnection.prototype.getStreamMetadataRaw = function(stream, userC
|
|||||||
var evnt = res.event.originalEvent;
|
var evnt = res.event.originalEvent;
|
||||||
var version = evnt ? evnt.eventNumber : -1;
|
var version = evnt ? evnt.eventNumber : -1;
|
||||||
var data = evnt ? JSON.parse(evnt.data.toString()) : null;
|
var data = evnt ? JSON.parse(evnt.data.toString()) : null;
|
||||||
return new results.RawStreamMetadataResult(stream, false, version, data);
|
return new results.RawStreamMetadataResult(stream, false, Long.fromValue(version), data);
|
||||||
case results.EventReadStatus.NotFound:
|
case results.EventReadStatus.NotFound:
|
||||||
case results.EventReadStatus.NoStream:
|
case results.EventReadStatus.NoStream:
|
||||||
return new results.RawStreamMetadataResult(stream, false, -1, null);
|
return new results.RawStreamMetadataResult(stream, false, Long.fromValue(-1), null);
|
||||||
case results.EventReadStatus.StreamDeleted:
|
case results.EventReadStatus.StreamDeleted:
|
||||||
return new results.RawStreamMetadataResult(stream, true, 0x7fffffff, null);
|
return new results.RawStreamMetadataResult(stream, true, Long.fromValue(0x7fffffff), null);
|
||||||
default:
|
default:
|
||||||
throw new Error(util.format("Unexpected ReadEventResult: %s.", res.status));
|
throw new Error(util.format("Unexpected ReadEventResult: %s.", res.status));
|
||||||
}
|
}
|
||||||
@ -700,7 +712,7 @@ EventStoreNodeConnection.prototype._enqueueOperation = function(operation) {
|
|||||||
var message = new messages.StartOperationMessage(operation, self._settings.maxRetries, self._settings.operationTimeout);
|
var message = new messages.StartOperationMessage(operation, self._settings.maxRetries, self._settings.operationTimeout);
|
||||||
function tryEnqueue() {
|
function tryEnqueue() {
|
||||||
if (self._handler.totalOperationCount >= self._settings.maxQueueSize) {
|
if (self._handler.totalOperationCount >= self._settings.maxQueueSize) {
|
||||||
setImmediate(tryEnqueue);
|
setTimeout(tryEnqueue, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self._handler.enqueueMessage(message);
|
self._handler.enqueueMessage(message);
|
||||||
|
@ -35,11 +35,12 @@ EventStorePersistentSubscriptionBase.prototype.start = function() {
|
|||||||
this._stopped = false;
|
this._stopped = false;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this._startSubscription(this._subscriptionId, this._streamId, this._bufferSize, this._userCredentials,
|
return this._startSubscription(this._subscriptionId, this._streamId, this._bufferSize, this._userCredentials,
|
||||||
this._onEventAppeared.bind(this), this._onSubscriptionDropped.bind(this), this._settings)
|
this._onEventAppeared.bind(this), this._onSubscriptionDropped.bind(this), this._settings)
|
||||||
.then(function(subscription) {
|
.then(function(subscription) {
|
||||||
console.log('Subscription started.');
|
self._log.debug('Subscription started.');
|
||||||
self._subscription = subscription;
|
self._subscription = subscription;
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,8 +56,7 @@ EventStorePersistentSubscriptionBase.prototype.acknowledge = function(events) {
|
|||||||
ensure.notNull(events, "events");
|
ensure.notNull(events, "events");
|
||||||
|
|
||||||
if (this._subscription === null) throw new Error("Invalid operation. Subscription is not active yet.");
|
if (this._subscription === null) throw new Error("Invalid operation. Subscription is not active yet.");
|
||||||
if (!Array.isArray(events))
|
if (!Array.isArray(events)) events = [events];
|
||||||
events = [events];
|
|
||||||
var ids = events.map(function(x) { return x.originalEvent.eventId; });
|
var ids = events.map(function(x) { return x.originalEvent.eventId; });
|
||||||
this._subscription.notifyEventsProcessed(ids);
|
this._subscription.notifyEventsProcessed(ids);
|
||||||
};
|
};
|
||||||
@ -72,12 +72,12 @@ EventStorePersistentSubscriptionBase.prototype.fail = function(events, action, r
|
|||||||
ensure.notNull(reason, "reason");
|
ensure.notNull(reason, "reason");
|
||||||
|
|
||||||
if (this._subscription === null) throw new Error("Invalid operation. Subscription is not active yet.");
|
if (this._subscription === null) throw new Error("Invalid operation. Subscription is not active yet.");
|
||||||
if (!Array.isArray(events))
|
if (!Array.isArray(events)) events = [events];
|
||||||
events = [events];
|
|
||||||
var ids = events.map(function(x) { return x.originalEvent.eventId; });
|
var ids = events.map(function(x) { return x.originalEvent.eventId; });
|
||||||
this._subscription.notifyEventsFailed(ids, action, reason);
|
this._subscription.notifyEventsFailed(ids, action, reason);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//TODO: this should return a promise
|
||||||
EventStorePersistentSubscriptionBase.prototype.stop = function() {
|
EventStorePersistentSubscriptionBase.prototype.stop = function() {
|
||||||
if (this._verbose) this._log.debug("Persistent Subscription to %s: requesting stop...", this._streamId);
|
if (this._verbose) this._log.debug("Persistent Subscription to %s: requesting stop...", this._streamId);
|
||||||
this._enqueueSubscriptionDropNotification(SubscriptionDropReason.UserInitiated, null);
|
this._enqueueSubscriptionDropNotification(SubscriptionDropReason.UserInitiated, null);
|
||||||
@ -110,57 +110,75 @@ EventStorePersistentSubscriptionBase.prototype._enqueue = function(resolvedEvent
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function runAsync(fn) {
|
||||||
|
try {
|
||||||
|
return Promise.resolve(fn());
|
||||||
|
} catch(e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EventStorePersistentSubscriptionBase.prototype._processQueue = function() {
|
EventStorePersistentSubscriptionBase.prototype._processQueue = function() {
|
||||||
//do
|
var ev = this._queue.shift();
|
||||||
//{
|
if (!ev) {
|
||||||
var e = this._queue.shift();
|
|
||||||
while (e)
|
|
||||||
{
|
|
||||||
if (e instanceof DropSubscriptionEvent) // drop subscription artificial ResolvedEvent
|
|
||||||
{
|
|
||||||
if (this._dropData === null) throw new Error("Drop reason not specified.");
|
|
||||||
this._dropSubscription(this._dropData.reason, this._dropData.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this._dropData !== null)
|
|
||||||
{
|
|
||||||
this._dropSubscription(this._dropData.reason, this._dropData.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this._eventAppeared(this, e);
|
|
||||||
if(this._autoAck)
|
|
||||||
this._subscription.notifyEventsProcessed([e.originalEvent.eventId]);
|
|
||||||
if (this._verbose)
|
|
||||||
this._log.debug("Persistent Subscription to %s: processed event (%s, %d, %s @ %d).",
|
|
||||||
this._streamId, e.originalEvent.eventStreamId, e.originalEvent.eventNumber, e.originalEvent.eventType,
|
|
||||||
e.originalEventNumber);
|
|
||||||
}
|
|
||||||
catch (err)
|
|
||||||
{
|
|
||||||
//TODO GFY should we autonak here?
|
|
||||||
this._dropSubscription(SubscriptionDropReason.EventHandlerException, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e = this._queue.shift();
|
|
||||||
}
|
|
||||||
this._isProcessing = false;
|
this._isProcessing = false;
|
||||||
//} while (_queue.Count > 0 && Interlocked.CompareExchange(ref _isProcessing, 1, 0) === 0);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev instanceof DropSubscriptionEvent) // drop subscription artificial ResolvedEvent
|
||||||
|
{
|
||||||
|
if (this._dropData === null) throw new Error("Drop reason not specified.");
|
||||||
|
this._dropSubscription(this._dropData.reason, this._dropData.error);
|
||||||
|
this._isProcessing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._dropData !== null)
|
||||||
|
{
|
||||||
|
this._dropSubscription(this._dropData.reason, this._dropData.error);
|
||||||
|
this._isProcessing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
runAsync(function() {
|
||||||
|
return self._eventAppeared(self, ev);
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
if(self._autoAck) self._subscription.notifyEventsProcessed([ev.originalEvent.eventId]);
|
||||||
|
if (self._verbose) {
|
||||||
|
self._log.debug("Persistent Subscription to %s: processed event (%s, %d, %s @ %d).",
|
||||||
|
self._streamId, ev.originalEvent.eventStreamId, ev.originalEvent.eventNumber, ev.originalEvent.eventType,
|
||||||
|
ev.originalEventNumber);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}, function(err) {
|
||||||
|
//TODO GFY should we autonak here?
|
||||||
|
self._dropSubscription(SubscriptionDropReason.EventHandlerException, err);
|
||||||
|
self._isProcessing = false;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.then(function (faulted) {
|
||||||
|
if (faulted) return;
|
||||||
|
self._processQueue();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
EventStorePersistentSubscriptionBase.prototype._dropSubscription = function(reason, error) {
|
EventStorePersistentSubscriptionBase.prototype._dropSubscription = function(reason, error) {
|
||||||
if (!this._isDropped)
|
if (!this._isDropped)
|
||||||
{
|
{
|
||||||
this._isDropped = true;
|
this._isDropped = true;
|
||||||
if (this._verbose)
|
if (this._verbose) {
|
||||||
this._log.debug("Persistent Subscription to %s: dropping subscription, reason: %s %s.",
|
this._log.debug("Persistent Subscription to %s: dropping subscription, reason: %s %s.",
|
||||||
this._streamId, reason, error);
|
this._streamId, reason, error);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._subscription !== null)
|
if (this._subscription !== null) this._subscription.unsubscribe();
|
||||||
this._subscription.unsubscribe();
|
if (this._subscriptionDropped !== null) {
|
||||||
if (this._subscriptionDropped !== null)
|
try {
|
||||||
this._subscriptionDropped(this, reason, error);
|
this._subscriptionDropped(this, reason, error);
|
||||||
|
} catch (e) {
|
||||||
|
this._log.error(e, "Persistent Subscription to %s: subscriptionDropped callback failed.", this._streamId);
|
||||||
|
}
|
||||||
|
}
|
||||||
this._stopped = true;
|
this._stopped = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
var Long = require('long');
|
||||||
|
|
||||||
var EventStoreCatchUpSubscription = require('./eventStoreCatchUpSubscription');
|
var EventStoreCatchUpSubscription = require('./eventStoreCatchUpSubscription');
|
||||||
var SliceReadStatus = require('./sliceReadStatus');
|
var SliceReadStatus = require('./sliceReadStatus');
|
||||||
@ -14,24 +15,26 @@ function EventStoreStreamCatchUpSubscription(
|
|||||||
|
|
||||||
//Ensure.NotNullOrEmpty(streamId, "streamId");
|
//Ensure.NotNullOrEmpty(streamId, "streamId");
|
||||||
|
|
||||||
this._lastProcessedEventNumber = fromEventNumberExclusive || -1;
|
this._lastProcessedEventNumber = fromEventNumberExclusive === null ? Long.fromNumber(-1) : fromEventNumberExclusive;
|
||||||
this._nextReadEventNumber = fromEventNumberExclusive || 0;
|
this._nextReadEventNumber = fromEventNumberExclusive === null ? Long.fromNumber(0) : fromEventNumberExclusive.add(1);
|
||||||
}
|
}
|
||||||
util.inherits(EventStoreStreamCatchUpSubscription, EventStoreCatchUpSubscription);
|
util.inherits(EventStoreStreamCatchUpSubscription, EventStoreCatchUpSubscription);
|
||||||
|
|
||||||
|
function delay(ms, result) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
setTimeout(resolve, ms, result);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
EventStoreStreamCatchUpSubscription.prototype._readEventsTill = function(
|
EventStoreStreamCatchUpSubscription.prototype._readEventsTill = function(
|
||||||
connection, resolveLinkTos, userCredentials, lastCommitPosition, lastEventNumber
|
connection, resolveLinkTos, userCredentials, lastCommitPosition, lastEventNumber
|
||||||
) {
|
) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function processEvents(events, index) {
|
function processEvents(events, index) {
|
||||||
index = index || 0;
|
|
||||||
if (index >= events.length) return Promise.resolve();
|
if (index >= events.length) return Promise.resolve();
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return self._tryProcess(events[index])
|
||||||
self._tryProcess(events[index]);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return processEvents(events, index + 1);
|
return processEvents(events, index + 1);
|
||||||
});
|
});
|
||||||
@ -42,23 +45,22 @@ EventStoreStreamCatchUpSubscription.prototype._readEventsTill = function(
|
|||||||
.then(function(slice) {
|
.then(function(slice) {
|
||||||
switch(slice.status) {
|
switch(slice.status) {
|
||||||
case SliceReadStatus.Success:
|
case SliceReadStatus.Success:
|
||||||
return processEvents(slice.events)
|
return processEvents(slice.events, 0)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
self._nextReadEventNumber = slice.nextEventNumber;
|
self._nextReadEventNumber = slice.nextEventNumber;
|
||||||
var done = Promise.resolve(lastEventNumber === null ? slice.isEndOfStream : slice.nextEventNumber > lastEventNumber);
|
var done = Promise.resolve(lastEventNumber === null ? slice.isEndOfStream : slice.nextEventNumber.compare(lastEventNumber) > 0);
|
||||||
if (!done && slice.isEndOfStream)
|
if (!done && slice.isEndOfStream) return delay(100, false);
|
||||||
return done.delay(10);
|
|
||||||
return done;
|
return done;
|
||||||
});
|
});
|
||||||
break;
|
|
||||||
case SliceReadStatus.StreamNotFound:
|
case SliceReadStatus.StreamNotFound:
|
||||||
if (lastEventNumber && lastEventNumber !== -1)
|
if (lastEventNumber && lastEventNumber.compare(-1) !== 0) {
|
||||||
throw new Error(util.format("Impossible: stream %s disappeared in the middle of catching up subscription.", self.streamId));
|
throw new Error(util.format("Impossible: stream %s disappeared in the middle of catching up subscription.", self.streamId));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case SliceReadStatus.StreamDeleted:
|
case SliceReadStatus.StreamDeleted:
|
||||||
throw new Error("Stream deleted: " + self.streamId);
|
throw new Error("Stream deleted: " + self.streamId);
|
||||||
default:
|
default:
|
||||||
throw new Error("Unexpected StreamEventsSlice.Status: %s.", slice.status);
|
throw new Error(util.format("Unexpected StreamEventsSlice.Status: %s.", slice.status));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function(done) {
|
.then(function(done) {
|
||||||
@ -69,24 +71,28 @@ EventStoreStreamCatchUpSubscription.prototype._readEventsTill = function(
|
|||||||
}
|
}
|
||||||
return readNext()
|
return readNext()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (self._verbose)
|
if (self._verbose) {
|
||||||
self._log.debug("Catch-up Subscription to %s: finished reading events, nextReadEventNumber = %d.",
|
self._log.debug("Catch-up Subscription to %s: finished reading events, nextReadEventNumber = %d.",
|
||||||
self.isSubscribedToAll ? '<all>' : self.streamId, self._nextReadEventNumber);
|
self.isSubscribedToAll ? '<all>' : self.streamId, self._nextReadEventNumber);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
EventStoreStreamCatchUpSubscription.prototype._tryProcess = function(e) {
|
EventStoreStreamCatchUpSubscription.prototype._tryProcess = function(e) {
|
||||||
var processed = false;
|
var processed = false;
|
||||||
if (e.originalEventNumber > this._lastProcessedEventNumber) {
|
var promise;
|
||||||
this._eventAppeared(this, e);
|
if (e.originalEventNumber.compare(this._lastProcessedEventNumber) > 0) {
|
||||||
|
promise = this._eventAppeared(this, e);
|
||||||
this._lastProcessedEventNumber = e.originalEventNumber;
|
this._lastProcessedEventNumber = e.originalEventNumber;
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
if (this._verbose)
|
if (this._verbose) {
|
||||||
this._log.debug("Catch-up Subscription to %s: %s event (%s, %d, %s @ %d).",
|
this._log.debug("Catch-up Subscription to %s: %s event (%s, %d, %s @ %d).",
|
||||||
this.isSubscribedToAll ? '<all>' : this.streamId, processed ? "processed" : "skipping",
|
this.isSubscribedToAll ? '<all>' : this.streamId, processed ? "processed" : "skipping",
|
||||||
e.originalEvent.eventStreamId, e.originalEvent.eventNumber, e.originalEvent.eventType, e.originalEventNumber)
|
e.originalEvent.eventStreamId, e.originalEvent.eventNumber, e.originalEvent.eventType, e.originalEventNumber);
|
||||||
|
}
|
||||||
|
return (promise && promise.then) ? promise : Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = EventStoreStreamCatchUpSubscription;
|
module.exports = EventStoreStreamCatchUpSubscription;
|
@ -41,4 +41,4 @@ EventStoreSubscription.prototype.unsubscribe = function() {
|
|||||||
throw new Error("EventStoreSubscription.unsubscribe abstract method called." + this.constructor.name);
|
throw new Error("EventStoreSubscription.unsubscribe abstract method called." + this.constructor.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = EventStoreSubscription;
|
module.exports = EventStoreSubscription;
|
@ -1,13 +1,9 @@
|
|||||||
module.exports = function GossipSeed(endPoint, hostName) {
|
function GossipSeed(endPoint, hostName, hostHeader) {
|
||||||
if (typeof endPoint !== 'object' || !endPoint.host || !endPoint.port) throw new TypeError('endPoint must be have host and port properties.');
|
if (typeof endPoint !== 'object' || !endPoint.host || !endPoint.port) throw new TypeError('endPoint must be have host and port properties.');
|
||||||
Object.defineProperties(this, {
|
this.endPoint = endPoint;
|
||||||
endPoint: {
|
this.hostName = hostName;
|
||||||
enumerable: true,
|
this.hostHeader = hostHeader;
|
||||||
value: endPoint
|
Object.freeze(this);
|
||||||
},
|
}
|
||||||
hostName: {
|
|
||||||
enumerable: true,
|
module.exports = GossipSeed;
|
||||||
value: hostName
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
16223
src/messages/messages.js
16223
src/messages/messages.js
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
package EventStore.Client.Messages;
|
package EventStore.Client.Messages;
|
||||||
|
|
||||||
enum OperationResult
|
enum OperationResult
|
||||||
@ -13,113 +15,115 @@ enum OperationResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
message NewEvent {
|
message NewEvent {
|
||||||
required bytes event_id = 1;
|
bytes event_id = 1;
|
||||||
required string event_type = 2;
|
string event_type = 2;
|
||||||
required int32 data_content_type = 3;
|
int32 data_content_type = 3;
|
||||||
required int32 metadata_content_type = 4;
|
int32 metadata_content_type = 4;
|
||||||
required bytes data = 5;
|
bytes data = 5;
|
||||||
optional bytes metadata = 6;
|
bytes metadata = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EventRecord {
|
message EventRecord {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required int32 event_number = 2;
|
int64 event_number = 2;
|
||||||
required bytes event_id = 3;
|
bytes event_id = 3;
|
||||||
required string event_type = 4;
|
string event_type = 4;
|
||||||
required int32 data_content_type = 5;
|
int32 data_content_type = 5;
|
||||||
required int32 metadata_content_type = 6;
|
int32 metadata_content_type = 6;
|
||||||
required bytes data = 7;
|
bytes data = 7;
|
||||||
optional bytes metadata = 8;
|
bytes metadata = 8;
|
||||||
optional int64 created = 9;
|
int64 created = 9;
|
||||||
optional int64 created_epoch = 10;
|
int64 created_epoch = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ResolvedIndexedEvent {
|
message ResolvedIndexedEvent {
|
||||||
required EventRecord event = 1;
|
EventRecord event = 1;
|
||||||
optional EventRecord link = 2;
|
EventRecord link = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ResolvedEvent {
|
message ResolvedEvent {
|
||||||
required EventRecord event = 1;
|
EventRecord event = 1;
|
||||||
optional EventRecord link = 2;
|
EventRecord link = 2;
|
||||||
required int64 commit_position = 3;
|
int64 commit_position = 3;
|
||||||
required int64 prepare_position = 4;
|
int64 prepare_position = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WriteEvents {
|
message WriteEvents {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required int32 expected_version = 2;
|
int64 expected_version = 2;
|
||||||
repeated NewEvent events = 3;
|
repeated NewEvent events = 3;
|
||||||
required bool require_master = 4;
|
bool require_leader = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WriteEventsCompleted {
|
message WriteEventsCompleted {
|
||||||
required OperationResult result = 1;
|
OperationResult result = 1;
|
||||||
optional string message = 2;
|
string message = 2;
|
||||||
required int32 first_event_number = 3;
|
int64 first_event_number = 3;
|
||||||
required int32 last_event_number = 4;
|
int64 last_event_number = 4;
|
||||||
optional int64 prepare_position = 5;
|
int64 prepare_position = 5;
|
||||||
optional int64 commit_position = 6;
|
int64 commit_position = 6;
|
||||||
|
int64 current_version = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteStream {
|
message DeleteStream {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required int32 expected_version = 2;
|
int64 expected_version = 2;
|
||||||
required bool require_master = 3;
|
bool require_leader = 3;
|
||||||
optional bool hard_delete = 4;
|
bool hard_delete = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteStreamCompleted {
|
message DeleteStreamCompleted {
|
||||||
required OperationResult result = 1;
|
OperationResult result = 1;
|
||||||
optional string message = 2;
|
string message = 2;
|
||||||
optional int64 prepare_position = 3;
|
int64 prepare_position = 3;
|
||||||
optional int64 commit_position = 4;
|
int64 commit_position = 4;
|
||||||
|
int64 current_version = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionStart {
|
message TransactionStart {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required int32 expected_version = 2;
|
int64 expected_version = 2;
|
||||||
required bool require_master = 3;
|
bool require_leader = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionStartCompleted {
|
message TransactionStartCompleted {
|
||||||
required int64 transaction_id = 1;
|
int64 transaction_id = 1;
|
||||||
required OperationResult result = 2;
|
OperationResult result = 2;
|
||||||
optional string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionWrite {
|
message TransactionWrite {
|
||||||
required int64 transaction_id = 1;
|
int64 transaction_id = 1;
|
||||||
repeated NewEvent events = 2;
|
repeated NewEvent events = 2;
|
||||||
required bool require_master = 3;
|
bool require_leader = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionWriteCompleted {
|
message TransactionWriteCompleted {
|
||||||
required int64 transaction_id = 1;
|
int64 transaction_id = 1;
|
||||||
required OperationResult result = 2;
|
OperationResult result = 2;
|
||||||
optional string message = 3;
|
string message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionCommit {
|
message TransactionCommit {
|
||||||
required int64 transaction_id = 1;
|
int64 transaction_id = 1;
|
||||||
required bool require_master = 2;
|
bool require_leader = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionCommitCompleted {
|
message TransactionCommitCompleted {
|
||||||
required int64 transaction_id = 1;
|
int64 transaction_id = 1;
|
||||||
required OperationResult result = 2;
|
OperationResult result = 2;
|
||||||
optional string message = 3;
|
string message = 3;
|
||||||
required int32 first_event_number = 4;
|
int64 first_event_number = 4;
|
||||||
required int32 last_event_number = 5;
|
int64 last_event_number = 5;
|
||||||
optional int64 prepare_position = 6;
|
int64 prepare_position = 6;
|
||||||
optional int64 commit_position = 7;
|
int64 commit_position = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReadEvent {
|
message ReadEvent {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required int32 event_number = 2;
|
int64 event_number = 2;
|
||||||
required bool resolve_link_tos = 3;
|
bool resolve_link_tos = 3;
|
||||||
required bool require_master = 4;
|
bool require_leader = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReadEventCompleted {
|
message ReadEventCompleted {
|
||||||
@ -133,18 +137,18 @@ message ReadEventCompleted {
|
|||||||
AccessDenied = 5;
|
AccessDenied = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
required ReadEventResult result = 1;
|
ReadEventResult result = 1;
|
||||||
required ResolvedIndexedEvent event = 2;
|
ResolvedIndexedEvent event = 2;
|
||||||
|
|
||||||
optional string error = 3;
|
string error = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReadStreamEvents {
|
message ReadStreamEvents {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required int32 from_event_number = 2;
|
int64 from_event_number = 2;
|
||||||
required int32 max_count = 3;
|
int32 max_count = 3;
|
||||||
required bool resolve_link_tos = 4;
|
bool resolve_link_tos = 4;
|
||||||
required bool require_master = 5;
|
bool require_leader = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReadStreamEventsCompleted {
|
message ReadStreamEventsCompleted {
|
||||||
@ -159,21 +163,21 @@ message ReadStreamEventsCompleted {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repeated ResolvedIndexedEvent events = 1;
|
repeated ResolvedIndexedEvent events = 1;
|
||||||
required ReadStreamResult result = 2;
|
ReadStreamResult result = 2;
|
||||||
required int32 next_event_number = 3;
|
int64 next_event_number = 3;
|
||||||
required int32 last_event_number = 4;
|
int64 last_event_number = 4;
|
||||||
required bool is_end_of_stream = 5;
|
bool is_end_of_stream = 5;
|
||||||
required int64 last_commit_position = 6;
|
int64 last_commit_position = 6;
|
||||||
|
|
||||||
optional string error = 7;
|
string error = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReadAllEvents {
|
message ReadAllEvents {
|
||||||
required int64 commit_position = 1;
|
int64 commit_position = 1;
|
||||||
required int64 prepare_position = 2;
|
int64 prepare_position = 2;
|
||||||
required int32 max_count = 3;
|
int32 max_count = 3;
|
||||||
required bool resolve_link_tos = 4;
|
bool resolve_link_tos = 4;
|
||||||
required bool require_master = 5;
|
bool require_leader = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReadAllEventsCompleted {
|
message ReadAllEventsCompleted {
|
||||||
@ -185,57 +189,105 @@ message ReadAllEventsCompleted {
|
|||||||
AccessDenied = 3;
|
AccessDenied = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
required int64 commit_position = 1;
|
int64 commit_position = 1;
|
||||||
required int64 prepare_position = 2;
|
int64 prepare_position = 2;
|
||||||
repeated ResolvedEvent events = 3;
|
repeated ResolvedEvent events = 3;
|
||||||
required int64 next_commit_position = 4;
|
int64 next_commit_position = 4;
|
||||||
required int64 next_prepare_position = 5;
|
int64 next_prepare_position = 5;
|
||||||
|
|
||||||
optional ReadAllResult result = 6 [default = Success];
|
ReadAllResult result = 6;
|
||||||
optional string error = 7;
|
string error = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Filter{
|
||||||
|
|
||||||
|
enum FilterContext {
|
||||||
|
StreamId = 0;
|
||||||
|
EventType = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FilterType {
|
||||||
|
Regex = 0;
|
||||||
|
Prefix = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterContext context = 1;
|
||||||
|
FilterType type = 2;
|
||||||
|
repeated string data = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FilteredReadAllEvents {
|
||||||
|
int64 commit_position = 1;
|
||||||
|
int64 prepare_position = 2;
|
||||||
|
int32 max_count = 3;
|
||||||
|
int32 max_search_window = 4;
|
||||||
|
bool resolve_link_tos = 5;
|
||||||
|
bool require_leader = 6;
|
||||||
|
Filter filter = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FilteredReadAllEventsCompleted {
|
||||||
|
|
||||||
|
enum FilteredReadAllResult {
|
||||||
|
Success = 0;
|
||||||
|
NotModified = 1;
|
||||||
|
Error = 2;
|
||||||
|
AccessDenied = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 commit_position = 1;
|
||||||
|
int64 prepare_position = 2;
|
||||||
|
repeated ResolvedEvent events = 3;
|
||||||
|
int64 next_commit_position = 4;
|
||||||
|
int64 next_prepare_position = 5;
|
||||||
|
bool is_end_of_stream = 6;
|
||||||
|
|
||||||
|
FilteredReadAllResult result = 7;
|
||||||
|
string error = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreatePersistentSubscription {
|
message CreatePersistentSubscription {
|
||||||
required string subscription_group_name = 1;
|
string subscription_group_name = 1;
|
||||||
required string event_stream_id = 2;
|
string event_stream_id = 2;
|
||||||
required bool resolve_link_tos = 3;
|
bool resolve_link_tos = 3;
|
||||||
required int32 start_from = 4;
|
int64 start_from = 4;
|
||||||
required int32 message_timeout_milliseconds = 5;
|
int32 message_timeout_milliseconds = 5;
|
||||||
required bool record_statistics = 6;
|
bool record_statistics = 6;
|
||||||
required int32 live_buffer_size = 7;
|
int32 live_buffer_size = 7;
|
||||||
required int32 read_batch_size = 8;
|
int32 read_batch_size = 8;
|
||||||
required int32 buffer_size = 9;
|
int32 buffer_size = 9;
|
||||||
required int32 max_retry_count = 10;
|
int32 max_retry_count = 10;
|
||||||
required bool prefer_round_robin = 11;
|
bool prefer_round_robin = 11;
|
||||||
required int32 checkpoint_after_time = 12;
|
int32 checkpoint_after_time = 12;
|
||||||
required int32 checkpoint_max_count = 13;
|
int32 checkpoint_max_count = 13;
|
||||||
required int32 checkpoint_min_count = 14;
|
int32 checkpoint_min_count = 14;
|
||||||
required int32 subscriber_max_count = 15;
|
int32 subscriber_max_count = 15;
|
||||||
optional string named_consumer_strategy = 16;
|
string named_consumer_strategy = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeletePersistentSubscription {
|
message DeletePersistentSubscription {
|
||||||
required string subscription_group_name = 1;
|
string subscription_group_name = 1;
|
||||||
required string event_stream_id = 2;
|
string event_stream_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdatePersistentSubscription {
|
message UpdatePersistentSubscription {
|
||||||
required string subscription_group_name = 1;
|
string subscription_group_name = 1;
|
||||||
required string event_stream_id = 2;
|
string event_stream_id = 2;
|
||||||
required bool resolve_link_tos = 3;
|
bool resolve_link_tos = 3;
|
||||||
required int32 start_from = 4;
|
int64 start_from = 4;
|
||||||
required int32 message_timeout_milliseconds = 5;
|
int32 message_timeout_milliseconds = 5;
|
||||||
required bool record_statistics = 6;
|
bool record_statistics = 6;
|
||||||
required int32 live_buffer_size = 7;
|
int32 live_buffer_size = 7;
|
||||||
required int32 read_batch_size = 8;
|
int32 read_batch_size = 8;
|
||||||
required int32 buffer_size = 9;
|
int32 buffer_size = 9;
|
||||||
required int32 max_retry_count = 10;
|
int32 max_retry_count = 10;
|
||||||
required bool prefer_round_robin = 11;
|
bool prefer_round_robin = 11;
|
||||||
required int32 checkpoint_after_time = 12;
|
int32 checkpoint_after_time = 12;
|
||||||
required int32 checkpoint_max_count = 13;
|
int32 checkpoint_max_count = 13;
|
||||||
required int32 checkpoint_min_count = 14;
|
int32 checkpoint_min_count = 14;
|
||||||
required int32 subscriber_max_count = 15;
|
int32 subscriber_max_count = 15;
|
||||||
optional string named_consumer_strategy = 16;
|
string named_consumer_strategy = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdatePersistentSubscriptionCompleted {
|
message UpdatePersistentSubscriptionCompleted {
|
||||||
@ -245,8 +297,8 @@ message UpdatePersistentSubscriptionCompleted {
|
|||||||
Fail = 2;
|
Fail = 2;
|
||||||
AccessDenied=3;
|
AccessDenied=3;
|
||||||
}
|
}
|
||||||
required UpdatePersistentSubscriptionResult result = 1 [default = Success];
|
UpdatePersistentSubscriptionResult result = 1;
|
||||||
optional string reason = 2;
|
string reason = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreatePersistentSubscriptionCompleted {
|
message CreatePersistentSubscriptionCompleted {
|
||||||
@ -256,8 +308,8 @@ message CreatePersistentSubscriptionCompleted {
|
|||||||
Fail = 2;
|
Fail = 2;
|
||||||
AccessDenied=3;
|
AccessDenied=3;
|
||||||
}
|
}
|
||||||
required CreatePersistentSubscriptionResult result = 1 [default = Success];
|
CreatePersistentSubscriptionResult result = 1;
|
||||||
optional string reason = 2;
|
string reason = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeletePersistentSubscriptionCompleted {
|
message DeletePersistentSubscriptionCompleted {
|
||||||
@ -267,19 +319,19 @@ message DeletePersistentSubscriptionCompleted {
|
|||||||
Fail = 2;
|
Fail = 2;
|
||||||
AccessDenied = 3;
|
AccessDenied = 3;
|
||||||
}
|
}
|
||||||
required DeletePersistentSubscriptionResult result = 1 [default = Success];
|
DeletePersistentSubscriptionResult result = 1;
|
||||||
optional string reason = 2;
|
string reason = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ConnectToPersistentSubscription {
|
message ConnectToPersistentSubscription {
|
||||||
required string subscription_id = 1;
|
string subscription_id = 1;
|
||||||
required string event_stream_id = 2;
|
string event_stream_id = 2;
|
||||||
required int32 allowed_in_flight_messages = 3;
|
int32 allowed_in_flight_messages = 3;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message PersistentSubscriptionAckEvents {
|
message PersistentSubscriptionAckEvents {
|
||||||
required string subscription_id = 1;
|
string subscription_id = 1;
|
||||||
repeated bytes processed_event_ids = 2;
|
repeated bytes processed_event_ids = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,34 +344,47 @@ message PersistentSubscriptionNakEvents {
|
|||||||
Stop = 4;
|
Stop = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
required string subscription_id = 1;
|
string subscription_id = 1;
|
||||||
repeated bytes processed_event_ids = 2;
|
repeated bytes processed_event_ids = 2;
|
||||||
optional string message = 3;
|
string message = 3;
|
||||||
required NakAction action = 4 [default = Unknown];
|
NakAction action = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PersistentSubscriptionConfirmation {
|
message PersistentSubscriptionConfirmation {
|
||||||
required int64 last_commit_position = 1;
|
int64 last_commit_position = 1;
|
||||||
required string subscription_id = 2;
|
string subscription_id = 2;
|
||||||
optional int32 last_event_number = 3;
|
int64 last_event_number = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PersistentSubscriptionStreamEventAppeared {
|
message PersistentSubscriptionStreamEventAppeared {
|
||||||
required ResolvedIndexedEvent event = 1;
|
ResolvedIndexedEvent event = 1;
|
||||||
|
int32 retryCount = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SubscribeToStream {
|
message SubscribeToStream {
|
||||||
required string event_stream_id = 1;
|
string event_stream_id = 1;
|
||||||
required bool resolve_link_tos = 2;
|
bool resolve_link_tos = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FilteredSubscribeToStream {
|
||||||
|
string event_stream_id = 1;
|
||||||
|
bool resolve_link_tos = 2;
|
||||||
|
Filter filter = 3;
|
||||||
|
int32 checkpoint_interval = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CheckpointReached {
|
||||||
|
int64 commit_position = 1;
|
||||||
|
int64 prepare_position = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SubscriptionConfirmation {
|
message SubscriptionConfirmation {
|
||||||
required int64 last_commit_position = 1;
|
int64 last_commit_position = 1;
|
||||||
optional int32 last_event_number = 2;
|
int64 last_event_number = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StreamEventAppeared {
|
message StreamEventAppeared {
|
||||||
required ResolvedEvent event = 1;
|
ResolvedEvent event = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UnsubscribeFromStream {
|
message UnsubscribeFromStream {
|
||||||
@ -334,44 +399,52 @@ message SubscriptionDropped {
|
|||||||
PersistentSubscriptionDeleted=3;
|
PersistentSubscriptionDeleted=3;
|
||||||
SubscriberMaxCountReached=4;
|
SubscriberMaxCountReached=4;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional SubscriptionDropReason reason = 1 [default = Unsubscribed];
|
SubscriptionDropReason reason = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message NotHandled {
|
message NotHandled {
|
||||||
|
|
||||||
enum NotHandledReason {
|
enum NotHandledReason {
|
||||||
NotReady = 0;
|
NotReady = 0;
|
||||||
TooBusy = 1;
|
TooBusy = 1;
|
||||||
NotMaster = 2;
|
NotLeader = 2;
|
||||||
|
IsReadOnly = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotHandledReason reason = 1;
|
||||||
|
bytes additional_info = 2;
|
||||||
|
|
||||||
required NotHandledReason reason = 1;
|
message LeaderInfo {
|
||||||
optional bytes additional_info = 2;
|
string external_tcp_address = 1;
|
||||||
|
int32 external_tcp_port = 2;
|
||||||
message MasterInfo {
|
string http_address = 3;
|
||||||
required string external_tcp_address = 1;
|
int32 http_port = 4;
|
||||||
required int32 external_tcp_port = 2;
|
string external_secure_tcp_address = 5;
|
||||||
required string external_http_address = 3;
|
int32 external_secure_tcp_port = 6;
|
||||||
required int32 external_http_port = 4;
|
|
||||||
optional string external_secure_tcp_address = 5;
|
|
||||||
optional int32 external_secure_tcp_port = 6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message ScavengeDatabase {
|
message ScavengeDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
message ScavengeDatabaseCompleted {
|
message ScavengeDatabaseResponse {
|
||||||
|
|
||||||
enum ScavengeResult {
|
enum ScavengeResult {
|
||||||
Success = 0;
|
Started = 0;
|
||||||
InProgress = 1;
|
InProgress = 1;
|
||||||
Failed = 2;
|
Unauthorized = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
required ScavengeResult result = 1;
|
ScavengeResult result = 1;
|
||||||
optional string error = 2;
|
string scavengeId = 2;
|
||||||
required int32 total_time_ms = 3;
|
|
||||||
required int64 total_space_saved = 4;
|
}
|
||||||
|
|
||||||
|
message IdentifyClient {
|
||||||
|
int32 version = 1;
|
||||||
|
string connection_name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientIdentified {
|
||||||
}
|
}
|
||||||
|
@ -22,4 +22,4 @@ PersistentEventStoreSubscription.prototype.notifyEventsFailed = function(process
|
|||||||
this._subscriptionOperation.notifyEventsFailed(processedEvents, action, reason);
|
this._subscriptionOperation.notifyEventsFailed(processedEvents, action, reason);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PersistentEventStoreSubscription;
|
module.exports = PersistentEventStoreSubscription;
|
@ -1,14 +1,15 @@
|
|||||||
const PersistentSubscriptionNakEventAction = {
|
const PersistentSubscriptionNakEventAction = Object.freeze({
|
||||||
Unknown: 0,
|
Unknown: 0,
|
||||||
Park: 1,
|
Park: 1,
|
||||||
Retry: 2,
|
Retry: 2,
|
||||||
Skip: 3,
|
Skip: 3,
|
||||||
Stop: 4
|
Stop: 4,
|
||||||
};
|
isValid: function(value) {
|
||||||
|
for(var k in PersistentSubscriptionNakEventAction) {
|
||||||
|
if (PersistentSubscriptionNakEventAction[k] === value) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = PersistentSubscriptionNakEventAction;
|
module.exports = PersistentSubscriptionNakEventAction;
|
||||||
module.exports.isValid = function(value) {
|
|
||||||
for(var k in PersistentSubscriptionNakEventAction)
|
|
||||||
if (PersistentSubscriptionNakEventAction[k] === value) return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
@ -1,4 +1,6 @@
|
|||||||
var SystemConsumerStrategies = require('./systemConsumerStrategies');
|
var SystemConsumerStrategies = require('./systemConsumerStrategies');
|
||||||
|
var ensure = require('./common/utils/ensure');
|
||||||
|
var Long = require('long');
|
||||||
|
|
||||||
function PersistentSubscriptionSettings(
|
function PersistentSubscriptionSettings(
|
||||||
resolveLinkTos, startFrom, extraStatistics, messageTimeout,
|
resolveLinkTos, startFrom, extraStatistics, messageTimeout,
|
||||||
@ -6,6 +8,9 @@ function PersistentSubscriptionSettings(
|
|||||||
checkPointAfter, minCheckPointCount, maxCheckPointCount,
|
checkPointAfter, minCheckPointCount, maxCheckPointCount,
|
||||||
maxSubscriberCount, namedConsumerStrategy
|
maxSubscriberCount, namedConsumerStrategy
|
||||||
) {
|
) {
|
||||||
|
ensure.isLongOrInteger(startFrom);
|
||||||
|
startFrom = Long.fromValue(startFrom);
|
||||||
|
|
||||||
this.resolveLinkTos = resolveLinkTos;
|
this.resolveLinkTos = resolveLinkTos;
|
||||||
this.startFrom = startFrom;
|
this.startFrom = startFrom;
|
||||||
this.extraStatistics = extraStatistics;
|
this.extraStatistics = extraStatistics;
|
||||||
|
56
src/projections/projectionDetails.js
Normal file
56
src/projections/projectionDetails.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
function ProjectionDetails(
|
||||||
|
coreProcessingTime,
|
||||||
|
version,
|
||||||
|
epoch,
|
||||||
|
effectiveName,
|
||||||
|
writesInProgress,
|
||||||
|
readsInProgress,
|
||||||
|
partitionsCached,
|
||||||
|
status,
|
||||||
|
stateReason,
|
||||||
|
name,
|
||||||
|
mode,
|
||||||
|
position,
|
||||||
|
progress,
|
||||||
|
lastCheckpoint,
|
||||||
|
eventsProcessedAfterRestart,
|
||||||
|
statusUrl,
|
||||||
|
stateUrl,
|
||||||
|
resultUrl,
|
||||||
|
queryUrl,
|
||||||
|
enableCommandUrl,
|
||||||
|
disableCommandUrl,
|
||||||
|
checkpointStatus,
|
||||||
|
bufferedEvents,
|
||||||
|
writePendingEventsBeforeCheckpoint,
|
||||||
|
writePendingEventsAfterCheckpoint
|
||||||
|
) {
|
||||||
|
this.coreProcessingTime = coreProcessingTime;
|
||||||
|
this.version = version;
|
||||||
|
this.epoch = epoch;
|
||||||
|
this.effectiveName = effectiveName;
|
||||||
|
this.writesInProgress = writesInProgress;
|
||||||
|
this.readsInProgress = readsInProgress;
|
||||||
|
this.partitionsCached = partitionsCached;
|
||||||
|
this.status = status;
|
||||||
|
this.stateReason = stateReason;
|
||||||
|
this.name = name;
|
||||||
|
this.mode = mode;
|
||||||
|
this.position = position;
|
||||||
|
this.progress = progress;
|
||||||
|
this.lastCheckpoint = lastCheckpoint;
|
||||||
|
this.eventsProcessedAfterRestart = eventsProcessedAfterRestart;
|
||||||
|
this.statusUrl = statusUrl;
|
||||||
|
this.stateUrl = stateUrl;
|
||||||
|
this.resultUrl = resultUrl;
|
||||||
|
this.queryUrl = queryUrl;
|
||||||
|
this.enableCommandUrl = enableCommandUrl;
|
||||||
|
this.disableCommandUrl = disableCommandUrl;
|
||||||
|
this.checkpointStatus = checkpointStatus;
|
||||||
|
this.bufferedEvents = bufferedEvents;
|
||||||
|
this.writePendingEventsBeforeCheckpoint = writePendingEventsBeforeCheckpoint;
|
||||||
|
this.writePendingEventsAfterCheckpoint = writePendingEventsAfterCheckpoint;
|
||||||
|
Object.freeze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ProjectionDetails;
|
181
src/projections/projectionsClient.js
Normal file
181
src/projections/projectionsClient.js
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
|
const url = require('url');
|
||||||
|
const util = require('util');
|
||||||
|
const ProjectionCommandFailedError = require('../errors/projectionCommandFailedError');
|
||||||
|
|
||||||
|
const HTTP_OK = 200;
|
||||||
|
const HTTP_CREATED = 201;
|
||||||
|
|
||||||
|
function safeParseJson(json) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(json);
|
||||||
|
} catch(e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProjectionsClient(log, operationTimeout, rejectUnauthorized) {
|
||||||
|
this._log = log;
|
||||||
|
this._operationTimeout = operationTimeout;
|
||||||
|
this._rejectUnauthorized = typeof rejectUnauthorized === 'undefined' ? true : !!rejectUnauthorized;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.enable = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projection/' + name + '/command/enable', '', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.disable = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projection/' + name + '/command/disable', '', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.abort = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projection/' + name + '/command/abort', '', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.reset = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projection/' + name + '/command/reset', '', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.createOneTime = function(httpEndPoint, query, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projections/onetime?type=JS', query, userCredentials, HTTP_CREATED);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.createTransient = function(httpEndPoint, name, query, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projections/transient?name=' + name + '&type=JS', query, userCredentials, HTTP_CREATED);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.createContinuous = function(httpEndPoint, name, query, trackEmittedStreams, userCredentials) {
|
||||||
|
return this.sendPost(httpEndPoint + '/projections/continuous?name=' + name + '&type=JS&emit=1&trackemittedstreams=' + trackEmittedStreams, query, userCredentials, HTTP_CREATED);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.listAll = function(httpEndPoint, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projections/any', userCredentials, HTTP_OK)
|
||||||
|
.then(function (json) {
|
||||||
|
var r = safeParseJson(json);
|
||||||
|
if (r && r.projections) return r.projections;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.listOneTime = function(httpEndPoint, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projections/onetime', userCredentials, HTTP_OK)
|
||||||
|
.then(function (json) {
|
||||||
|
var r = safeParseJson(json);
|
||||||
|
if (r && r.projections) return r.projections;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.listContinuous = function(httpEndPoint, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projections/continuous', userCredentials, HTTP_OK)
|
||||||
|
.then(function (json) {
|
||||||
|
var r = safeParseJson(json);
|
||||||
|
if (r && r.projections) return r.projections;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getStatus = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name, userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getState = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name + '/state', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getPartitionState = function(httpEndPoint, name, partitionId, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name + '/state?partition=' + partitionId, userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getResult = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name + '/result', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getPartitionResult = function(httpEndPoint, name, partitionId, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name + '/result?partition=' + partitionId, userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getStatistics = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name + '/statistics', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.getQuery = function(httpEndPoint, name, userCredentials) {
|
||||||
|
return this.sendGet(httpEndPoint + '/projection/' + name + '/query', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.updateQuery = function(httpEndPoint, name, query, userCredentials) {
|
||||||
|
return this.sendPut(httpEndPoint + '/projection/' + name + '/query?type=JS', query, userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.delete = function(httpEndPoint, name, deleteEmittedStreams, deleteStateStream, deleteCheckpointStream, userCredentials) {
|
||||||
|
return this.sendDelete(httpEndPoint + '/projection/' + name + '?deleteStateStream=' + deleteStateStream + '&deleteCheckpointStream=' + deleteCheckpointStream + '&deleteEmittedStreams=' + deleteEmittedStreams, '', userCredentials, HTTP_OK);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.request = function(method, _url, data, userCredentials, expectedCode) {
|
||||||
|
const options = url.parse(_url);
|
||||||
|
const httplib = options.protocol === 'https:' ? https : http;
|
||||||
|
options.method = method;
|
||||||
|
if (userCredentials) {
|
||||||
|
options.auth = [userCredentials.username, userCredentials.password].join(':');
|
||||||
|
}
|
||||||
|
if (!this._rejectUnauthorized) {
|
||||||
|
options.rejectUnauthorized = false;
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
const timeout = setTimeout(function () {
|
||||||
|
reject(new Error(util.format('Request timed out for %s on %s', method, _url)))
|
||||||
|
}, self._operationTimeout);
|
||||||
|
const req = httplib.request(options, function (res) {
|
||||||
|
const hasExpectedCode = res.statusCode === expectedCode;
|
||||||
|
var result = '';
|
||||||
|
res.setEncoding('utf8');
|
||||||
|
res.on('data', function (chunk) {
|
||||||
|
result += chunk;
|
||||||
|
});
|
||||||
|
res.on('end', function () {
|
||||||
|
if (hasExpectedCode) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
resolve(result);
|
||||||
|
} else {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
reject(new ProjectionCommandFailedError(
|
||||||
|
res.statusCode,
|
||||||
|
util.format('Server returned %d (%s) for %s on %s', res.statusCode, res.statusMessage, method, _url)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.on('error', reject);
|
||||||
|
if (data) {
|
||||||
|
req.setHeader('Content-Length', data.length);
|
||||||
|
req.setHeader('Content-Type', 'application/json');
|
||||||
|
req.write(data);
|
||||||
|
}
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function voidResult() {}
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.sendGet = function(_url, userCredentials, expectedCode) {
|
||||||
|
return this.request('GET', _url, null, userCredentials, expectedCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.sendPost = function(_url, data, userCredentials, expectedCode) {
|
||||||
|
return this.request('POST', _url, data, userCredentials, expectedCode)
|
||||||
|
.then(voidResult);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.sendPut = function(_url, data, userCredentials, expectedCode) {
|
||||||
|
return this.request('PUT', _url, data, userCredentials, expectedCode)
|
||||||
|
.then(voidResult);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionsClient.prototype.sendDelete = function(_url, data, userCredentials, expectedCode) {
|
||||||
|
return this.request('DELETE', _url, data, userCredentials, expectedCode)
|
||||||
|
.then(voidResult);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProjectionsClient;
|
215
src/projections/projectionsManager.js
Normal file
215
src/projections/projectionsManager.js
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
const ensure = require('../common/utils/ensure');
|
||||||
|
const ProjectionsClient = require('./projectionsClient');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of ProjectionsManager.
|
||||||
|
* @param {Logger} log Instance of Logger to use for logging.
|
||||||
|
* @param {string} httpEndPoint HTTP endpoint of an Event Store server.
|
||||||
|
* @param {number} operationTimeout Operation timeout in milliseconds.
|
||||||
|
* @param {boolean} [rejectUnauthorized] Reject authorized SSL certs (if using SSL) - set to false is using self-signed certs
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function ProjectionsManager(log, httpEndPoint, operationTimeout, rejectUnauthorized) {
|
||||||
|
ensure.notNull(log, "log");
|
||||||
|
ensure.notNull(httpEndPoint, "httpEndPoint");
|
||||||
|
this._client = new ProjectionsClient(log, operationTimeout, rejectUnauthorized);
|
||||||
|
this._httpEndPoint = httpEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables a projection.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for a user with permission to enable a projection.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.enable = function(name, userCredentials) {
|
||||||
|
return this._client.enable(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aborts and disables a projection without writing a checkpoint.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for a user with permission to disable a projection.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.disable = function(name, userCredentials) {
|
||||||
|
return this._client.disable(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables a projection.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for a user with permission to disable a projection.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.abort = function(name, userCredentials) {
|
||||||
|
return this._client.abort(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset a projection. (This will re-emit events, streams that are written to from the projection will also be soft deleted)
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for a user with permission to reset a projection.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.reset = function(name, userCredentials) {
|
||||||
|
return this._client.reset(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a one-time query.
|
||||||
|
* @param query The JavaScript source code for the query.
|
||||||
|
* @param userCredentials Credentials for a user with permission to create a query.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.createOneTime = function(query, userCredentials) {
|
||||||
|
return this._client.createOneTime(this._httpEndPoint, query, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a one-time query.
|
||||||
|
* @param name A name for the query.
|
||||||
|
* @param query The JavaScript source code for the query.
|
||||||
|
* @param userCredentials Credentials for a user with permission to create a query.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.createTransient = function(name, query, userCredentials) {
|
||||||
|
return this._client.createTransient(this._httpEndPoint, query, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a one-time query.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param query The JavaScript source code for the query.
|
||||||
|
* @param trackEmittedStreams Whether the streams emitted by this projection should be tracked.
|
||||||
|
* @param userCredentials Credentials for a user with permission to create a query.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.createContinuous = function(name, query, trackEmittedStreams, userCredentials) {
|
||||||
|
return this._client.createContinuous(this._httpEndPoint, name, query, trackEmittedStreams, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists the status of all projections.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<ProjectionDetails[]>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.listAll = function(userCredentials) {
|
||||||
|
return this._client.listAll(this._httpEndPoint, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists the status of all one-time projections.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<ProjectionDetails[]>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.listOneTime = function(userCredentials) {
|
||||||
|
return this._client.listOneTime(this._httpEndPoint, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists the status of all continuous projections.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<ProjectionDetails[]>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.listContinuous = function(userCredentials) {
|
||||||
|
return this._client.listContinuous(this._httpEndPoint, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status of a projection.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing projection status.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getStatus = function(name, userCredentials) {
|
||||||
|
return this._client.getStatus(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the state of a projection.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing projection state.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getState = function(name, userCredentials) {
|
||||||
|
return this._client.getState(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the state of a projection for a specified partition.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param partitionId The id of the partition.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing projection state.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getPartitionState = function(name, partitionId, userCredentials) {
|
||||||
|
return this._client.getPartitionState(this._httpEndPoint, name, partitionId, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the state of a projection.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing projection state.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getResult = function(name, userCredentials) {
|
||||||
|
return this._client.getResult(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the state of a projection for a specified partition.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param partitionId The id of the partition.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing projection state.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getPartitionResult = function(name, partitionId, userCredentials) {
|
||||||
|
return this._client.getPartitionResult(this._httpEndPoint, name, partitionId, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the statistics of a projection.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing projection statistics.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getStatistics = function(name, userCredentials) {
|
||||||
|
return this._client.getStatistics(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status of a query.
|
||||||
|
* @param name The name of the query.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<string>} String of JSON containing query status.
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.getQuery = function(name, userCredentials) {
|
||||||
|
return this._client.getQuery(this._httpEndPoint, name, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the definition of a query.
|
||||||
|
* @param name The name of the query.
|
||||||
|
* @param query The JavaScript source code for the query.
|
||||||
|
* @param userCredentials Credentials for the operation.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.updateQuery = function(name, query, userCredentials) {
|
||||||
|
return this._client.updateQuery(this._httpEndPoint, name, query, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the definition of a query.
|
||||||
|
* @param name The name of the projection.
|
||||||
|
* @param deleteEmittedStreams Whether to delete the streams that were emitted by this projection.
|
||||||
|
* @param deleteStateStream Where to delete the state stream for this projection
|
||||||
|
* @param deleteCheckpointStream Where to delete the checkpoint stream for this projection
|
||||||
|
* @param userCredentials Credentials for a user with permission to delete a projection.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
ProjectionsManager.prototype.delete = function(name, deleteEmittedStreams, deleteStateStream, deleteCheckpointStream, userCredentials) {
|
||||||
|
return this._client.delete(this._httpEndPoint, name, deleteEmittedStreams, deleteStateStream, deleteCheckpointStream, userCredentials);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProjectionsManager;
|
@ -1,6 +1,6 @@
|
|||||||
const ReadDirection = {
|
const ReadDirection = Object.freeze({
|
||||||
Forward: 'forward',
|
Forward: 'forward',
|
||||||
Backward: 'backward'
|
Backward: 'backward'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = ReadDirection;
|
module.exports = ReadDirection;
|
281
src/results.js
281
src/results.js
@ -1,5 +1,4 @@
|
|||||||
var util = require('util');
|
var guidParse = require('./common/guid-parse');
|
||||||
var uuid = require('uuid');
|
|
||||||
var Long = require('long');
|
var Long = require('long');
|
||||||
var ensure = require('./common/utils/ensure');
|
var ensure = require('./common/utils/ensure');
|
||||||
|
|
||||||
@ -14,24 +13,18 @@ var ensure = require('./common/utils/ensure');
|
|||||||
function Position(commitPosition, preparePosition) {
|
function Position(commitPosition, preparePosition) {
|
||||||
ensure.notNull(commitPosition, "commitPosition");
|
ensure.notNull(commitPosition, "commitPosition");
|
||||||
ensure.notNull(preparePosition, "preparePosition");
|
ensure.notNull(preparePosition, "preparePosition");
|
||||||
commitPosition = Long.fromValue(commitPosition);
|
this.commitPosition = Long.fromValue(commitPosition);
|
||||||
preparePosition = Long.fromValue(preparePosition);
|
this.preparePosition = Long.fromValue(preparePosition);
|
||||||
|
Object.freeze(this);
|
||||||
Object.defineProperties(this, {
|
|
||||||
commitPosition: {
|
|
||||||
enumerable: true, value: commitPosition
|
|
||||||
},
|
|
||||||
preparePosition: {
|
|
||||||
enumerable: true, value: preparePosition
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Position.prototype.compareTo = function(other) {
|
Position.prototype.compareTo = function(other) {
|
||||||
if (this.commitPosition.lt(other.commitPosition) || (this.commitPosition.eq(other.commitPosition)&& this.preparePosition.lt(other.preparePosition)))
|
if (this.commitPosition.lt(other.commitPosition) || (this.commitPosition.eq(other.commitPosition)&& this.preparePosition.lt(other.preparePosition))) {
|
||||||
return -1;
|
return -1;
|
||||||
if (this.commitPosition.gt(other.commitPosition) || (this.commitPosition.eq(other.commitPosition) && this.preparePosition.gt(other.preparePosition)))
|
}
|
||||||
|
if (this.commitPosition.gt(other.commitPosition) || (this.commitPosition.eq(other.commitPosition) && this.preparePosition.gt(other.preparePosition))) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,39 +32,40 @@ Position.prototype.toString = function() {
|
|||||||
return [this.commitPosition.toString(), this.preparePosition.toString()].join("/");
|
return [this.commitPosition.toString(), this.preparePosition.toString()].join("/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Position.start = new Position(0,0);
|
||||||
|
Position.end = new Position(-1,-1);
|
||||||
|
|
||||||
const EventReadStatus = {
|
const EventReadStatus = Object.freeze({
|
||||||
Success: 'success',
|
Success: 'success',
|
||||||
NotFound: 'notFound',
|
NotFound: 'notFound',
|
||||||
NoStream: 'noStream',
|
NoStream: 'noStream',
|
||||||
StreamDeleted: 'streamDeleted'
|
StreamDeleted: 'streamDeleted'
|
||||||
};
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} ev
|
* @param {object} ev
|
||||||
* @constructor
|
* @constructor
|
||||||
* @property {string} eventStreamId
|
* @property {string} eventStreamId
|
||||||
* @property {string} eventId
|
* @property {string} eventId
|
||||||
* @property {number} eventNumber
|
* @property {Long} eventNumber
|
||||||
* @property {string} eventType
|
* @property {string} eventType
|
||||||
|
* @property {Date} created
|
||||||
* @property {number} createdEpoch
|
* @property {number} createdEpoch
|
||||||
* @property {?Buffer} data
|
* @property {?Buffer} data
|
||||||
* @property {?Buffer} metadata
|
* @property {?Buffer} metadata
|
||||||
* @property {boolean} isJson
|
* @property {boolean} isJson
|
||||||
*/
|
*/
|
||||||
function RecordedEvent(ev) {
|
function RecordedEvent(ev) {
|
||||||
Object.defineProperties(this, {
|
this.eventStreamId = ev.eventStreamId;
|
||||||
eventStreamId: {enumerable: true, value: ev.event_stream_id},
|
this.eventId = guidParse.unparse(ev.eventId);
|
||||||
eventId: {enumerable: true, value: uuid.unparse(ev.event_id.buffer, ev.event_id.offset)},
|
this.eventNumber = ev.eventNumber;
|
||||||
eventNumber: {enumerable: true, value: ev.event_number},
|
this.eventType = ev.eventType;
|
||||||
eventType: {enumerable: true, value: ev.event_type},
|
this.created = new Date(ev.createdEpoch ? ev.createdEpoch.toNumber() : 0);
|
||||||
//Javascript doesn't have .Net precision for time, so we use created_epoch for created
|
this.createdEpoch = ev.createdEpoch ? ev.createdEpoch.toNumber() : 0;
|
||||||
created: {enumerable: true, value: new Date(ev.created_epoch ? ev.created_epoch.toNumber() : 0)},
|
this.data = ev.data ? ev.data : Buffer.alloc(0);
|
||||||
createdEpoch: {enumerable: true, value: ev.created_epoch ? ev.created_epoch.toNumber() : 0},
|
this.metadata = ev.metadata ? ev.metadata : Buffer.alloc(0);
|
||||||
data: {enumerable: true, value: ev.data ? ev.data.toBuffer() : new Buffer(0)},
|
this.isJson = ev.dataContentType === 1;
|
||||||
metadata: {enumerable: true, value: ev.metadata ? ev.metadata.toBuffer() : new Buffer(0)},
|
Object.freeze(this);
|
||||||
isJson: {enumerable: true, value: ev.data_content_type === 1}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,138 +77,83 @@ function RecordedEvent(ev) {
|
|||||||
* @property {boolean} isResolved
|
* @property {boolean} isResolved
|
||||||
* @property {?Position} originalPosition
|
* @property {?Position} originalPosition
|
||||||
* @property {string} originalStreamId
|
* @property {string} originalStreamId
|
||||||
* @property {number} originalEventNumber
|
* @property {Long} originalEventNumber
|
||||||
*/
|
*/
|
||||||
function ResolvedEvent(ev) {
|
function ResolvedEvent(ev) {
|
||||||
Object.defineProperties(this, {
|
this.event = ev.event === null ? null : new RecordedEvent(ev.event);
|
||||||
event: {
|
this.link = ev.link === null ? null : new RecordedEvent(ev.link);
|
||||||
enumerable: true,
|
this.originalEvent = this.link || this.event;
|
||||||
value: ev.event === null ? null : new RecordedEvent(ev.event)
|
this.isResolved = this.link !== null && this.event !== null;
|
||||||
},
|
this.originalPosition = (ev.commitPosition && ev.preparePosition) ? new Position(ev.commitPosition, ev.preparePosition) : null;
|
||||||
link: {
|
this.originalStreamId = this.originalEvent && this.originalEvent.eventStreamId;
|
||||||
enumerable: true,
|
this.originalEventNumber = this.originalEvent && this.originalEvent.eventNumber;
|
||||||
value: ev.link === null ? null : new RecordedEvent(ev.link)
|
Object.freeze(this);
|
||||||
},
|
|
||||||
originalEvent: {
|
|
||||||
enumerable: true,
|
|
||||||
get: function() {
|
|
||||||
return this.link || this.event;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isResolved: {
|
|
||||||
enumerable: true,
|
|
||||||
get: function() {
|
|
||||||
return this.link !== null && this.event !== null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
originalPosition: {
|
|
||||||
enumerable: true,
|
|
||||||
value: (ev.commit_position && ev.prepare_position) ? new Position(ev.commit_position, ev.prepare_position) : null
|
|
||||||
},
|
|
||||||
originalStreamId: {
|
|
||||||
enumerable: true,
|
|
||||||
get: function() {
|
|
||||||
return this.originalEvent.eventStreamId;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
originalEventNumber: {
|
|
||||||
enumerable: true,
|
|
||||||
get: function() {
|
|
||||||
return this.originalEvent.eventNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} status
|
* @param {string} status
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} eventNumber
|
* @param {Long} eventNumber
|
||||||
* @param {object} event
|
* @param {object} event
|
||||||
* @constructor
|
* @constructor
|
||||||
* @property {string} status
|
* @property {string} status
|
||||||
* @property {string} stream
|
* @property {string} stream
|
||||||
* @property {number} eventNumber
|
* @property {Long} eventNumber
|
||||||
* @property {ResolvedEvent} event
|
* @property {ResolvedEvent} event
|
||||||
*/
|
*/
|
||||||
function EventReadResult(status, stream, eventNumber, event) {
|
function EventReadResult(status, stream, eventNumber, event) {
|
||||||
Object.defineProperties(this, {
|
this.status = status;
|
||||||
status: {enumerable: true, value: status},
|
this.stream = stream;
|
||||||
stream: {enumerable: true, value: stream},
|
this.eventNumber = eventNumber;
|
||||||
eventNumber: {enumerable: true, value: eventNumber},
|
this.event = status === EventReadStatus.Success ? new ResolvedEvent(event) : null;
|
||||||
event: {
|
Object.freeze(this);
|
||||||
enumerable: true, value: status === EventReadStatus.Success ? new ResolvedEvent(event) : null
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} nextExpectedVersion
|
* @param {number} nextExpectedVersion
|
||||||
* @param {Position} logPosition
|
* @param {Position} logPosition
|
||||||
* @constructor
|
* @constructor
|
||||||
* @property {number} nextExpectedVersion
|
* @property {Long} nextExpectedVersion
|
||||||
* @property {Position} logPosition
|
* @property {Position} logPosition
|
||||||
*/
|
*/
|
||||||
function WriteResult(nextExpectedVersion, logPosition) {
|
function WriteResult(nextExpectedVersion, logPosition) {
|
||||||
Object.defineProperties(this, {
|
this.nextExpectedVersion = nextExpectedVersion;
|
||||||
nextExpectedVersion: {
|
this.logPosition = logPosition;
|
||||||
enumerable: true, value: nextExpectedVersion
|
Object.freeze(this);
|
||||||
},
|
|
||||||
logPosition: {
|
|
||||||
enumerable: true, value: logPosition
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} status
|
* @param {string} status
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {number} fromEventNumber
|
* @param {Long} fromEventNumber
|
||||||
* @param {string} readDirection
|
* @param {string} readDirection
|
||||||
* @param {object[]} events
|
* @param {object[]} events
|
||||||
* @param {number} nextEventNumber
|
* @param {Long} nextEventNumber
|
||||||
* @param {number} lastEventNumber
|
* @param {Long} lastEventNumber
|
||||||
* @param {boolean} isEndOfStream
|
* @param {boolean} isEndOfStream
|
||||||
* @constructor
|
* @constructor
|
||||||
* @property {string} status
|
* @property {string} status
|
||||||
* @property {string} stream
|
* @property {string} stream
|
||||||
* @property {number} fromEventNumber
|
* @property {Long} fromEventNumber
|
||||||
* @property {string} readDirection
|
* @property {string} readDirection
|
||||||
* @property {ResolvedEvent[]} events
|
* @property {ResolvedEvent[]} events
|
||||||
* @property {number} nextEventNumber
|
* @property {Long} nextEventNumber
|
||||||
* @property {number} lastEventNumber
|
* @property {Long} lastEventNumber
|
||||||
* @property {boolean} isEndOfStream
|
* @property {boolean} isEndOfStream
|
||||||
*/
|
*/
|
||||||
function StreamEventsSlice(
|
function StreamEventsSlice(
|
||||||
status, stream, fromEventNumber, readDirection, events, nextEventNumber, lastEventNumber, isEndOfStream
|
status, stream, fromEventNumber, readDirection, events, nextEventNumber, lastEventNumber, isEndOfStream
|
||||||
) {
|
) {
|
||||||
Object.defineProperties(this, {
|
this.status = status;
|
||||||
status: {
|
this.stream = stream;
|
||||||
enumerable: true, value: status
|
this.fromEventNumber = fromEventNumber;
|
||||||
},
|
this.readDirection = readDirection;
|
||||||
stream: {
|
this.events = events ? events.map(function(ev) { return new ResolvedEvent(ev); }) : [];
|
||||||
enumerable: true, value: stream
|
this.nextEventNumber = nextEventNumber;
|
||||||
},
|
this.lastEventNumber = lastEventNumber;
|
||||||
fromEventNumber: {
|
this.isEndOfStream = isEndOfStream;
|
||||||
enumerable: true, value: fromEventNumber
|
Object.freeze(this);
|
||||||
},
|
|
||||||
readDirection: {
|
|
||||||
enumerable: true, value: readDirection
|
|
||||||
},
|
|
||||||
events: {
|
|
||||||
enumerable: true, value: events ? events.map(function(ev) { return new ResolvedEvent(ev); }) : []
|
|
||||||
},
|
|
||||||
nextEventNumber: {
|
|
||||||
enumerable: true, value: nextEventNumber
|
|
||||||
},
|
|
||||||
lastEventNumber: {
|
|
||||||
enumerable: true, value: lastEventNumber
|
|
||||||
},
|
|
||||||
isEndOfStream: {
|
|
||||||
enumerable: true, value: isEndOfStream
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,23 +168,12 @@ function StreamEventsSlice(
|
|||||||
* @property {ResolvedEvent[]} events
|
* @property {ResolvedEvent[]} events
|
||||||
*/
|
*/
|
||||||
function AllEventsSlice(readDirection, fromPosition, nextPosition, events) {
|
function AllEventsSlice(readDirection, fromPosition, nextPosition, events) {
|
||||||
Object.defineProperties(this, {
|
this.readDirection = readDirection;
|
||||||
readDirection: {
|
this.fromPosition = fromPosition;
|
||||||
enumerable: true, value: readDirection
|
this.nextPosition = nextPosition;
|
||||||
},
|
this.events = events ? events.map(function(ev){ return new ResolvedEvent(ev); }) : [];
|
||||||
fromPosition: {
|
this.isEndOfStream = events === null || events.length === 0;
|
||||||
enumerable: true, value: fromPosition
|
Object.freeze(this);
|
||||||
},
|
|
||||||
nextPosition: {
|
|
||||||
enumerable: true, value: nextPosition
|
|
||||||
},
|
|
||||||
events: {
|
|
||||||
enumerable: true, value: events ? events.map(function(ev){ return new ResolvedEvent(ev); }) : []
|
|
||||||
},
|
|
||||||
isEndOfStream: {
|
|
||||||
enumerable: true, value: events === null || events.length === 0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -254,39 +182,35 @@ function AllEventsSlice(readDirection, fromPosition, nextPosition, events) {
|
|||||||
* @property {Position} logPosition
|
* @property {Position} logPosition
|
||||||
*/
|
*/
|
||||||
function DeleteResult(logPosition) {
|
function DeleteResult(logPosition) {
|
||||||
Object.defineProperties(this, {
|
this.logPosition = logPosition;
|
||||||
logPosition: {
|
Object.freeze(this);
|
||||||
enumerable: true, value: logPosition
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} stream
|
* @param {string} stream
|
||||||
* @param {boolean} isStreamDeleted
|
* @param {boolean} isStreamDeleted
|
||||||
* @param {number} metastreamVersion
|
* @param {Long} metastreamVersion
|
||||||
* @param {object} streamMetadata
|
* @param {object} streamMetadata
|
||||||
* @constructor
|
* @constructor
|
||||||
* @property {string} stream
|
* @property {string} stream
|
||||||
* @property {boolean} isStreamDeleted
|
* @property {boolean} isStreamDeleted
|
||||||
* @property {number} metastreamVersion
|
* @property {Long} metastreamVersion
|
||||||
* @property {object} streamMetadata
|
* @property {object} streamMetadata
|
||||||
*/
|
*/
|
||||||
function RawStreamMetadataResult(stream, isStreamDeleted, metastreamVersion, streamMetadata) {
|
function RawStreamMetadataResult(stream, isStreamDeleted, metastreamVersion, streamMetadata) {
|
||||||
ensure.notNullOrEmpty(stream);
|
ensure.notNullOrEmpty(stream);
|
||||||
Object.defineProperties(this, {
|
this.stream = stream;
|
||||||
stream: {enumerable: true, value: stream},
|
this.isStreamDeleted = isStreamDeleted;
|
||||||
isStreamDeleted: {enumerable: true, value: isStreamDeleted},
|
this.metastreamVersion = metastreamVersion;
|
||||||
metastreamVersion: {enumerable: true, value: metastreamVersion},
|
this.streamMetadata = streamMetadata;
|
||||||
streamMetadata: {enumerable: true, value: streamMetadata}
|
Object.freeze(this);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PersistentSubscriptionCreateStatus = {
|
const PersistentSubscriptionCreateStatus = Object.freeze({
|
||||||
Success: 'success',
|
Success: 'success',
|
||||||
NotFound: 'notFound',
|
NotFound: 'notFound',
|
||||||
Failure: 'failure'
|
Failure: 'failure'
|
||||||
};
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} status
|
* @param {string} status
|
||||||
@ -294,17 +218,16 @@ const PersistentSubscriptionCreateStatus = {
|
|||||||
* @property {string} status
|
* @property {string} status
|
||||||
*/
|
*/
|
||||||
function PersistentSubscriptionCreateResult(status) {
|
function PersistentSubscriptionCreateResult(status) {
|
||||||
Object.defineProperties(this, {
|
this.status = status;
|
||||||
status: {enumerable: true, value: status}
|
Object.freeze(this);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PersistentSubscriptionUpdateStatus = {
|
const PersistentSubscriptionUpdateStatus = Object.freeze({
|
||||||
Success: 'success',
|
Success: 'success',
|
||||||
NotFound: 'notFound',
|
NotFound: 'notFound',
|
||||||
Failure: 'failure',
|
Failure: 'failure',
|
||||||
AccessDenied: 'accessDenied'
|
AccessDenied: 'accessDenied'
|
||||||
};
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} status
|
* @param {string} status
|
||||||
@ -312,15 +235,14 @@ const PersistentSubscriptionUpdateStatus = {
|
|||||||
* @property {string} status
|
* @property {string} status
|
||||||
*/
|
*/
|
||||||
function PersistentSubscriptionUpdateResult(status) {
|
function PersistentSubscriptionUpdateResult(status) {
|
||||||
Object.defineProperties(this, {
|
this.status = status;
|
||||||
status: {enumerable: true, value: status}
|
Object.freeze(this);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PersistentSubscriptionDeleteStatus = {
|
const PersistentSubscriptionDeleteStatus = Object.freeze({
|
||||||
Success: 'success',
|
Success: 'success',
|
||||||
Failure: 'failure'
|
Failure: 'failure'
|
||||||
};
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} status
|
* @param {string} status
|
||||||
@ -328,24 +250,23 @@ const PersistentSubscriptionDeleteStatus = {
|
|||||||
* @property {string} status
|
* @property {string} status
|
||||||
*/
|
*/
|
||||||
function PersistentSubscriptionDeleteResult(status) {
|
function PersistentSubscriptionDeleteResult(status) {
|
||||||
Object.defineProperties(this, {
|
this.status = status;
|
||||||
status: {enumerable: true, value: status}
|
Object.freeze(this);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exports Constructors
|
// Exports Constructors
|
||||||
module.exports.Position = Position;
|
exports.Position = Position;
|
||||||
module.exports.ResolvedEvent = ResolvedEvent;
|
exports.ResolvedEvent = ResolvedEvent;
|
||||||
module.exports.EventReadStatus = EventReadStatus;
|
exports.EventReadStatus = EventReadStatus;
|
||||||
module.exports.EventReadResult = EventReadResult;
|
exports.EventReadResult = EventReadResult;
|
||||||
module.exports.WriteResult = WriteResult;
|
exports.WriteResult = WriteResult;
|
||||||
module.exports.StreamEventsSlice = StreamEventsSlice;
|
exports.StreamEventsSlice = StreamEventsSlice;
|
||||||
module.exports.AllEventsSlice = AllEventsSlice;
|
exports.AllEventsSlice = AllEventsSlice;
|
||||||
module.exports.DeleteResult = DeleteResult;
|
exports.DeleteResult = DeleteResult;
|
||||||
module.exports.RawStreamMetadataResult = RawStreamMetadataResult;
|
exports.RawStreamMetadataResult = RawStreamMetadataResult;
|
||||||
module.exports.PersistentSubscriptionCreateResult = PersistentSubscriptionCreateResult;
|
exports.PersistentSubscriptionCreateResult = PersistentSubscriptionCreateResult;
|
||||||
module.exports.PersistentSubscriptionCreateStatus = PersistentSubscriptionCreateStatus;
|
exports.PersistentSubscriptionCreateStatus = PersistentSubscriptionCreateStatus;
|
||||||
module.exports.PersistentSubscriptionUpdateResult = PersistentSubscriptionUpdateResult;
|
exports.PersistentSubscriptionUpdateResult = PersistentSubscriptionUpdateResult;
|
||||||
module.exports.PersistentSubscriptionUpdateStatus = PersistentSubscriptionUpdateStatus;
|
exports.PersistentSubscriptionUpdateStatus = PersistentSubscriptionUpdateStatus;
|
||||||
module.exports.PersistentSubscriptionDeleteResult = PersistentSubscriptionDeleteResult;
|
exports.PersistentSubscriptionDeleteResult = PersistentSubscriptionDeleteResult;
|
||||||
module.exports.PersistentSubscriptionDeleteStatus = PersistentSubscriptionDeleteStatus;
|
exports.PersistentSubscriptionDeleteStatus = PersistentSubscriptionDeleteStatus;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const SliceReadStatus = {
|
const SliceReadStatus = Object.freeze({
|
||||||
Success: 'success',
|
Success: 'success',
|
||||||
StreamNotFound: 'streamNotFound',
|
StreamNotFound: 'streamNotFound',
|
||||||
StreamDeleted: 'streamDeleted'
|
StreamDeleted: 'streamDeleted'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = SliceReadStatus;
|
module.exports = SliceReadStatus;
|
@ -1,4 +1,4 @@
|
|||||||
const SubscriptionDropReason = {
|
const SubscriptionDropReason = Object.freeze({
|
||||||
AccessDenied: 'accessDenied',
|
AccessDenied: 'accessDenied',
|
||||||
CatchUpError: 'catchUpError',
|
CatchUpError: 'catchUpError',
|
||||||
ConnectionClosed: 'connectionClosed',
|
ConnectionClosed: 'connectionClosed',
|
||||||
@ -11,6 +11,6 @@ const SubscriptionDropReason = {
|
|||||||
SubscribingError: 'subscribingError',
|
SubscribingError: 'subscribingError',
|
||||||
UserInitiated: 'userInitiated',
|
UserInitiated: 'userInitiated',
|
||||||
Unknown: 'unknown'
|
Unknown: 'unknown'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = SubscriptionDropReason;
|
module.exports = SubscriptionDropReason;
|
@ -1,7 +1,7 @@
|
|||||||
const SystemConsumerStrategies = {
|
const SystemConsumerStrategies = Object.freeze({
|
||||||
DispatchToSingle: 'DispatchToSingle',
|
DispatchToSingle: 'DispatchToSingle',
|
||||||
RoundRobin: 'RoundRobin',
|
RoundRobin: 'RoundRobin',
|
||||||
Pinned: 'Pinned'
|
Pinned: 'Pinned'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = SystemConsumerStrategies;
|
module.exports = SystemConsumerStrategies;
|
@ -1,9 +1,9 @@
|
|||||||
var InspectionDecision = {
|
var InspectionDecision = Object.freeze({
|
||||||
DoNothing: 'doNothing',
|
DoNothing: 'doNothing',
|
||||||
EndOperation: 'endOperation',
|
EndOperation: 'endOperation',
|
||||||
Retry: 'retry',
|
Retry: 'retry',
|
||||||
Reconnect: 'reconnect',
|
Reconnect: 'reconnect',
|
||||||
Subscribed: 'subscribed'
|
Subscribed: 'subscribed'
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = InspectionDecision;
|
module.exports = InspectionDecision;
|
@ -5,4 +5,4 @@ function InspectionResult(decision, description, tcpEndPoint, secureTcpEndPoint)
|
|||||||
this.secureTcpEndPoint = secureTcpEndPoint || null;
|
this.secureTcpEndPoint = secureTcpEndPoint || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = InspectionResult;
|
module.exports = InspectionResult;
|
@ -1,9 +1,7 @@
|
|||||||
var ClientMessage = require('../messages/clientMessage');
|
var ClientMessage = require('../messages/clientMessage');
|
||||||
var SliceReadStatus = require('../sliceReadStatus');
|
var SliceReadStatus = require('../sliceReadStatus');
|
||||||
|
|
||||||
module.exports = {};
|
exports.convert = function(code) {
|
||||||
|
|
||||||
module.exports.convert = function(code) {
|
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.Success:
|
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.Success:
|
||||||
return SliceReadStatus.Success;
|
return SliceReadStatus.Success;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const TcpCommand = {
|
const TcpCommand = Object.freeze({
|
||||||
HeartbeatRequestCommand: 0x01,
|
HeartbeatRequestCommand: 0x01,
|
||||||
HeartbeatResponseCommand: 0x02,
|
HeartbeatResponseCommand: 0x02,
|
||||||
|
|
||||||
@ -71,16 +71,20 @@ const TcpCommand = {
|
|||||||
NotHandled: 0xF1,
|
NotHandled: 0xF1,
|
||||||
Authenticate: 0xF2,
|
Authenticate: 0xF2,
|
||||||
Authenticated: 0xF3,
|
Authenticated: 0xF3,
|
||||||
NotAuthenticated: 0xF4
|
NotAuthenticated: 0xF4,
|
||||||
};
|
IdentifyClient: 0xF5,
|
||||||
|
ClientIdentified: 0xF6,
|
||||||
|
|
||||||
|
getName: function(v) {
|
||||||
|
return _reverseLookup[v];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var _reverseLookup = {};
|
var _reverseLookup = {};
|
||||||
for(var n in TcpCommand) {
|
for(var n in TcpCommand) {
|
||||||
|
if (n === 'getName') continue;
|
||||||
var v = TcpCommand[n];
|
var v = TcpCommand[n];
|
||||||
_reverseLookup[v] = n;
|
_reverseLookup[v] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TcpCommand;
|
module.exports = TcpCommand;
|
||||||
module.exports.getName = function(v) {
|
|
||||||
return _reverseLookup[v];
|
|
||||||
};
|
|
@ -1,6 +1,6 @@
|
|||||||
const TcpFlags = {
|
const TcpFlags = Object.freeze({
|
||||||
None: 0x0,
|
None: 0x0,
|
||||||
Authenticated: 0x01
|
Authenticated: 0x01
|
||||||
};
|
});
|
||||||
|
|
||||||
module.exports = TcpFlags;
|
module.exports = TcpFlags;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var uuid = require('uuid');
|
var guidParse = require('../common/guid-parse');
|
||||||
|
|
||||||
var createBufferSegment = require('../common/bufferSegment');
|
var createBufferSegment = require('../common/bufferSegment');
|
||||||
var TcpFlags = require('./tcpFlags');
|
var TcpFlags = require('./tcpFlags');
|
||||||
@ -19,26 +19,27 @@ function TcpPackage(command, flags, correlationId, login, password, data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TcpPackage.fromBufferSegment = function(data) {
|
TcpPackage.fromBufferSegment = function(data) {
|
||||||
if (data.length < MandatorySize)
|
if (data.length < MandatorySize) throw new Error("ArraySegment too short, length: " + data.length);
|
||||||
throw new Error("ArraySegment too short, length: " + data.length);
|
|
||||||
|
|
||||||
var command = data.buffer[data.offset + CommandOffset];
|
var command = data.buffer[data.offset + CommandOffset];
|
||||||
var flags = data.buffer[data.offset + FlagsOffset];
|
var flags = data.buffer[data.offset + FlagsOffset];
|
||||||
|
|
||||||
var correlationId = uuid.unparse(data.buffer, data.offset + CorrelationOffset);
|
var correlationId = guidParse.unparse(data.buffer, data.offset + CorrelationOffset);
|
||||||
|
|
||||||
var headerSize = MandatorySize;
|
var headerSize = MandatorySize;
|
||||||
var login = null, pass = null;
|
var login = null, pass = null;
|
||||||
if ((flags & TcpFlags.Authenticated) !== 0)
|
if ((flags & TcpFlags.Authenticated) !== 0)
|
||||||
{
|
{
|
||||||
var loginLen = data.buffer[data.offset + AuthOffset];
|
var loginLen = data.buffer[data.offset + AuthOffset];
|
||||||
if (AuthOffset + 1 + loginLen + 1 >= data.count)
|
if (AuthOffset + 1 + loginLen + 1 >= data.count) {
|
||||||
throw new Error("Login length is too big, it doesn't fit into TcpPackage.");
|
throw new Error("Login length is too big, it doesn't fit into TcpPackage.");
|
||||||
|
}
|
||||||
login = data.buffer.toString('utf8', data.offset + AuthOffset + 1, data.offset + AuthOffset + 1 + loginLen);
|
login = data.buffer.toString('utf8', data.offset + AuthOffset + 1, data.offset + AuthOffset + 1 + loginLen);
|
||||||
|
|
||||||
var passLen = data.buffer[data.offset + AuthOffset + 1 + loginLen];
|
var passLen = data.buffer[data.offset + AuthOffset + 1 + loginLen];
|
||||||
if (AuthOffset + 1 + loginLen + 1 + passLen > data.count)
|
if (AuthOffset + 1 + loginLen + 1 + passLen > data.count) {
|
||||||
throw new Error("Password length is too big, it doesn't fit into TcpPackage.");
|
throw new Error("Password length is too big, it doesn't fit into TcpPackage.");
|
||||||
|
}
|
||||||
headerSize += 1 + loginLen + 1 + passLen;
|
headerSize += 1 + loginLen + 1 + passLen;
|
||||||
pass = data.buffer.toString('utf8', data.offset + AuthOffset + 1 + loginLen + 1, data.offset + headerSize);
|
pass = data.buffer.toString('utf8', data.offset + AuthOffset + 1 + loginLen + 1, data.offset + headerSize);
|
||||||
}
|
}
|
||||||
@ -49,32 +50,30 @@ TcpPackage.fromBufferSegment = function(data) {
|
|||||||
|
|
||||||
TcpPackage.prototype.asBuffer = function() {
|
TcpPackage.prototype.asBuffer = function() {
|
||||||
if ((this.flags & TcpFlags.Authenticated) !== 0) {
|
if ((this.flags & TcpFlags.Authenticated) !== 0) {
|
||||||
var loginBytes = new Buffer(this.login);
|
var loginBytes = Buffer.from(this.login);
|
||||||
if (loginBytes.length > 255) throw new Error("Login serialized length should be less than 256 bytes.");
|
if (loginBytes.length > 255) throw new Error("Login serialized length should be less than 256 bytes.");
|
||||||
var passwordBytes = new Buffer(this.password);
|
var passwordBytes = Buffer.from(this.password);
|
||||||
if (passwordBytes.length > 255) throw new Error("Password serialized length should be less than 256 bytes.");
|
if (passwordBytes.length > 255) throw new Error("Password serialized length should be less than 256 bytes.");
|
||||||
|
|
||||||
var res = new Buffer(MandatorySize + 2 + loginBytes.length + passwordBytes.length + (this.data ? this.data.count : 0));
|
var res = Buffer.alloc(MandatorySize + 2 + loginBytes.length + passwordBytes.length + (this.data ? this.data.count : 0));
|
||||||
res[CommandOffset] = this.command;
|
res[CommandOffset] = this.command;
|
||||||
res[FlagsOffset] = this.flags;
|
res[FlagsOffset] = this.flags;
|
||||||
uuid.parse(this.correlationId, res, CorrelationOffset);
|
guidParse.parse(this.correlationId, res, CorrelationOffset);
|
||||||
|
|
||||||
res[AuthOffset] = loginBytes.length;
|
res[AuthOffset] = loginBytes.length;
|
||||||
loginBytes.copy(res, AuthOffset + 1);
|
loginBytes.copy(res, AuthOffset + 1);
|
||||||
res[AuthOffset + 1 + loginBytes.length] = passwordBytes.length;
|
res[AuthOffset + 1 + loginBytes.length] = passwordBytes.length;
|
||||||
passwordBytes.copy(res, AuthOffset + 2 + loginBytes.length);
|
passwordBytes.copy(res, AuthOffset + 2 + loginBytes.length);
|
||||||
|
|
||||||
if (this.data)
|
if (this.data) this.data.copyTo(res, res.length - this.data.count);
|
||||||
this.data.copyTo(res, res.length - this.data.count);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
var res = new Buffer(MandatorySize + (this.data ? this.data.count : 0));
|
var res = Buffer.alloc(MandatorySize + (this.data ? this.data.count : 0));
|
||||||
res[CommandOffset] = this.command;
|
res[CommandOffset] = this.command;
|
||||||
res[FlagsOffset] = this.flags;
|
res[FlagsOffset] = this.flags;
|
||||||
uuid.parse(this.correlationId, res, CorrelationOffset);
|
guidParse.parse(this.correlationId, res, CorrelationOffset);
|
||||||
if (this.data)
|
if (this.data) this.data.copyTo(res, AuthOffset);
|
||||||
this.data.copyTo(res, AuthOffset);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -83,4 +82,4 @@ TcpPackage.prototype.asBufferSegment = function() {
|
|||||||
return createBufferSegment(this.asBuffer());
|
return createBufferSegment(this.asBuffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = TcpPackage;
|
module.exports = TcpPackage;
|
||||||
|
@ -10,11 +10,9 @@ var ensure = require('../common/utils/ensure');
|
|||||||
function UserCredentials(username, password) {
|
function UserCredentials(username, password) {
|
||||||
ensure.notNullOrEmpty(username, 'username');
|
ensure.notNullOrEmpty(username, 'username');
|
||||||
ensure.notNullOrEmpty(password, 'password');
|
ensure.notNullOrEmpty(password, 'password');
|
||||||
|
this.username = username;
|
||||||
Object.defineProperties(this, {
|
this.password = password;
|
||||||
username: {enumerable: true, value: username},
|
Object.freeze(this);
|
||||||
password: {enumerable: true, value: password}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UserCredentials;
|
module.exports = UserCredentials;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user