Compare commits
11 Commits
v4_proto
...
release-0.
Author | SHA1 | Date | |
---|---|---|---|
bc2fbe14e3 | |||
9fc5d64ceb | |||
2bdd74e041 | |||
fde6ad2e77 | |||
4a2065c0a7 | |||
67dd275b5d | |||
8997a8c398 | |||
a5807483a2 | |||
bf89354564 | |||
254ddda8a2 | |||
16c081020a |
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="ES5" />
|
||||
</component>
|
||||
</project>
|
24
README.md
24
README.md
@ -5,7 +5,6 @@ A port of the EventStore .Net ClientAPI to Node.js
|
||||
|
||||
### Missing features:
|
||||
|
||||
- Ssl connection
|
||||
- Set system settings
|
||||
|
||||
### Areas to improve
|
||||
@ -23,9 +22,16 @@ Install using `npm install node-eventstore-client`
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Node.js >= 0.12
|
||||
- Node.js >= 4.0
|
||||
- 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`)
|
||||
|
||||
### Install and run an Eventstore on localhost
|
||||
|
||||
See https://eventstore.org/docs/introduction/4.1.0/
|
||||
|
||||
*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
|
||||
|
||||
#### Offline
|
||||
@ -36,10 +42,6 @@ The offline documentation can be found in the module folder `./node_modules/node
|
||||
|
||||
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
|
||||
|
||||
Save to ```app.js:```
|
||||
@ -112,7 +114,15 @@ To generate a test event, open a separate console and run:
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
87
index.d.ts
vendored
87
index.d.ts
vendored
@ -1,14 +1,15 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="Long" />
|
||||
|
||||
// Expose classes
|
||||
export class Position {
|
||||
constructor(commitPosition: number|Long, preparePosition: number|Long);
|
||||
readonly commitPosition: Long;
|
||||
readonly preparePosition: Long;
|
||||
static readonly start: number;
|
||||
static readonly end: number;
|
||||
}
|
||||
|
||||
// Expose classes
|
||||
|
||||
export class UserCredentials {
|
||||
constructor(username: string, password: string);
|
||||
readonly username: string;
|
||||
@ -26,7 +27,7 @@ export class PersistentSubscriptionSettings {
|
||||
export namespace SystemConsumerStrategies {
|
||||
const DispatchToSingle: string;
|
||||
const RoundRobin: string;
|
||||
const Pinned: string
|
||||
const Pinned: string;
|
||||
}
|
||||
|
||||
export class GossipSeed {
|
||||
@ -35,6 +36,57 @@ export class GossipSeed {
|
||||
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>;
|
||||
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>;
|
||||
deleteQuery(name: string, deleteEmittedStreams: boolean, userCredentials: UserCredentials): Promise<void>;
|
||||
}
|
||||
|
||||
// Expose errors
|
||||
export class WrongExpectedVersionError {
|
||||
readonly name: string;
|
||||
@ -59,8 +111,12 @@ export class AccessDeniedError {
|
||||
readonly transactionId?: Long;
|
||||
}
|
||||
|
||||
// Expose enums/constants
|
||||
export class ProjectionCommandFailedError {
|
||||
readonly httpStatusCode: number;
|
||||
readonly message: string;
|
||||
}
|
||||
|
||||
// Expose enums/constants
|
||||
export namespace expectedVersion {
|
||||
const any: number;
|
||||
const noStream: number;
|
||||
@ -72,19 +128,24 @@ export namespace positions {
|
||||
const end: Position;
|
||||
}
|
||||
|
||||
export namespace streamPosition {
|
||||
const start: number;
|
||||
const end: number;
|
||||
}
|
||||
|
||||
//TODO
|
||||
// systemMetadata
|
||||
// eventReadStatus
|
||||
// sliceReadStatus
|
||||
|
||||
// Expose loggers
|
||||
|
||||
export interface Logger {
|
||||
debug(fmt: string, ...args: any[]): void;
|
||||
info(fmt: string, ...args: any[]): void;
|
||||
error(fmt: string, ...args: any[]): void;
|
||||
}
|
||||
|
||||
export class NoOpLogger implements Logger {
|
||||
export class NoopLogger implements Logger {
|
||||
constructor()
|
||||
debug(fmt: string, ...args: any[]): void;
|
||||
info(fmt: string, ...args: any[]): void;
|
||||
@ -228,12 +289,12 @@ export interface TcpEndPoint {
|
||||
}
|
||||
|
||||
export interface HeartbeatInfo {
|
||||
connectionId: string;
|
||||
remoteEndPoint: TcpEndPoint;
|
||||
requestSentAt: number;
|
||||
requestPkgNumber: number;
|
||||
responseReceivedAt: number;
|
||||
responsePkgNumber: number;
|
||||
readonly connectionId: string;
|
||||
readonly remoteEndPoint: TcpEndPoint;
|
||||
readonly requestSentAt: number;
|
||||
readonly requestPkgNumber: number;
|
||||
readonly responseReceivedAt: number;
|
||||
readonly responsePkgNumber: number;
|
||||
}
|
||||
|
||||
export interface EventData {
|
||||
@ -277,7 +338,6 @@ export interface EventStoreNodeConnection {
|
||||
}
|
||||
|
||||
// Expose helper functions
|
||||
|
||||
export interface ConnectionSettings {
|
||||
log?: Logger,
|
||||
verboseLogging?: boolean,
|
||||
@ -310,6 +370,7 @@ export interface ConnectionSettings {
|
||||
gossipTimeout?: number
|
||||
}
|
||||
|
||||
// Expose Helper functions
|
||||
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 createEventData(eventId: string, type: string, isJson: boolean, data: Buffer, metadata?: Buffer): EventData;
|
||||
|
@ -1,9 +1,13 @@
|
||||
{
|
||||
"name": "node-eventstore-client",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.3",
|
||||
"description": "A port of the EventStore .Net ClientAPI to Node.js",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"scripts": {
|
||||
"clean": "rm lib/dist.js",
|
||||
"build": "webpack",
|
||||
@ -48,7 +52,7 @@
|
||||
"uuid": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsdoc": "^3.5.3",
|
||||
"jsdoc": "^3.5.5",
|
||||
"nodeunit": "^0.11.1",
|
||||
"webpack": "^3.3.0"
|
||||
}
|
||||
|
@ -4,15 +4,23 @@ var results = require('./results');
|
||||
const expectedVersion = {
|
||||
any: -2,
|
||||
noStream: -1,
|
||||
emptyStream: -1
|
||||
emptyStream: -1,
|
||||
streamExists: -4
|
||||
};
|
||||
Object.freeze(expectedVersion);
|
||||
|
||||
const positions = {
|
||||
start: new results.Position(0, 0),
|
||||
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
|
||||
* @public
|
||||
@ -51,13 +59,16 @@ module.exports.PersistentSubscriptionSettings = require('./persistentSubscriptio
|
||||
module.exports.SystemConsumerStrategies = require('./systemConsumerStrategies');
|
||||
module.exports.GossipSeed = require('./gossipSeed');
|
||||
module.exports.EventStoreConnection = require('./eventStoreConnection');
|
||||
module.exports.ProjectionsManager = require('./projections/projectionsManager');
|
||||
// Expose errors
|
||||
module.exports.WrongExpectedVersionError = require('./errors/wrongExpectedVersionError');
|
||||
module.exports.StreamDeletedError = require('./errors/streamDeletedError');
|
||||
module.exports.AccessDeniedError = require('./errors/accessDeniedError');
|
||||
module.exports.ProjectionCommandFailedError = require('./errors/projectionCommandFailedError');
|
||||
// Expose enums/constants
|
||||
module.exports.expectedVersion = expectedVersion;
|
||||
module.exports.positions = positions;
|
||||
module.exports.streamPosition = streamPosition;
|
||||
module.exports.systemMetadata = require('./common/systemMetadata');
|
||||
module.exports.eventReadStatus = results.EventReadStatus;
|
||||
module.exports.sliceReadStatus = require('./sliceReadStatus');
|
||||
|
@ -47,6 +47,7 @@ const ClientVersion = 1;
|
||||
* @property {Number} totalOperationCount
|
||||
*/
|
||||
function EventStoreConnectionLogicHandler(esConnection, settings) {
|
||||
EventEmitter.call(this);
|
||||
this._esConnection = esConnection;
|
||||
this._settings = settings;
|
||||
this._queue = new SimpleQueuedHandler();
|
||||
|
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;
|
@ -38,6 +38,7 @@ const MaxReadSize = 4096;
|
||||
* @constructor
|
||||
*/
|
||||
function EventStoreNodeConnection(settings, clusterSettings, endpointDiscoverer, connectionName) {
|
||||
EventEmitter.call(this);
|
||||
this._connectionName = connectionName || ['ES-', uuid.v4()].join('');
|
||||
this._settings = settings;
|
||||
this._clusterSettings = clusterSettings;
|
||||
|
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;
|
170
src/projections/projectionsClient.js
Normal file
170
src/projections/projectionsClient.js
Normal file
@ -0,0 +1,170 @@
|
||||
const http = require('http');
|
||||
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) {
|
||||
this._log = log;
|
||||
this._operationTimeout = operationTimeout;
|
||||
}
|
||||
|
||||
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.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, userCredentials) {
|
||||
return this.sendDelete(httpEndPoint + '/projection/' + name + '?deleteEmittedStreams=' + deleteEmittedStreams, userCredentials, HTTP_OK);
|
||||
};
|
||||
|
||||
ProjectionsClient.prototype.request = function(method, _url, data, userCredentials, expectedCode) {
|
||||
const options = url.parse(_url);
|
||||
options.method = method;
|
||||
if (userCredentials) {
|
||||
options.auth = [userCredentials.username, userCredentials.password].join(':');
|
||||
}
|
||||
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 = http.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-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;
|
202
src/projections/projectionsManager.js
Normal file
202
src/projections/projectionsManager.js
Normal file
@ -0,0 +1,202 @@
|
||||
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.
|
||||
* @constructor
|
||||
*/
|
||||
function ProjectionsManager(log, httpEndPoint, operationTimeout) {
|
||||
ensure.notNull(log, "log");
|
||||
ensure.notNull(httpEndPoint, "httpEndPoint");
|
||||
this._client = new ProjectionsClient(log, operationTimeout);
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 userCredentials Credentials for a user with permission to delete a projection.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
ProjectionsManager.prototype.delete = function(name, deleteEmittedStreams, userCredentials) {
|
||||
return this._client.delete(this._httpEndPoint, name, deleteEmittedStreams, userCredentials);
|
||||
};
|
||||
|
||||
module.exports = ProjectionsManager;
|
@ -30,6 +30,8 @@ Position.prototype.toString = function() {
|
||||
return [this.commitPosition.toString(), this.preparePosition.toString()].join("/");
|
||||
};
|
||||
|
||||
Position.start = new Position(0,0);
|
||||
Position.end = new Position(-1,-1);
|
||||
|
||||
const EventReadStatus = {
|
||||
Success: 'success',
|
||||
|
@ -1,4 +1,5 @@
|
||||
var net = require('net');
|
||||
var tls = require('tls');
|
||||
var createBufferSegment = require('../../common/bufferSegment');
|
||||
|
||||
const MaxSendPacketSize = 64 * 1024;
|
||||
@ -136,11 +137,16 @@ TcpConnection.prototype._closeInternal = function(err, reason) {
|
||||
};
|
||||
|
||||
TcpConnection.createConnectingConnection = function(
|
||||
log, connectionId, remoteEndPoint, connectionTimeout,
|
||||
onConnectionEstablished, onConnectionFailed, onConnectionClosed
|
||||
log, connectionId, remoteEndPoint, ssl, targetHost, validateServer,
|
||||
connectionTimeout, onConnectionEstablished, onConnectionFailed, onConnectionClosed
|
||||
) {
|
||||
var connection = new TcpConnection(log, connectionId, remoteEndPoint, onConnectionClosed);
|
||||
var socket = net.connect(remoteEndPoint.port, remoteEndPoint.host);
|
||||
var provider = ssl ? tls : net;
|
||||
var options = {
|
||||
servername: targetHost,
|
||||
rejectUnauthorized: validateServer
|
||||
};
|
||||
var socket = provider.connect(remoteEndPoint.port, remoteEndPoint.host, options);
|
||||
function onError(err) {
|
||||
if (onConnectionFailed)
|
||||
onConnectionFailed(connection, err);
|
||||
|
@ -38,15 +38,14 @@ function TcpPackageConnection(
|
||||
this._framer = new LengthPrefixMessageFramer();
|
||||
this._framer.registerMessageArrivedCallback(this._incomingMessageArrived.bind(this));
|
||||
|
||||
//TODO ssl
|
||||
var self = this;
|
||||
this._connection = TcpConnection.createConnectingConnection(
|
||||
log,
|
||||
connectionId,
|
||||
remoteEndPoint,
|
||||
//ssl,
|
||||
//targetHost,
|
||||
//validateServer,
|
||||
ssl,
|
||||
targetHost,
|
||||
validateServer,
|
||||
timeout,
|
||||
function(tcpConnection) {
|
||||
log.debug("TcpPackageConnection: connected to [%j, L%j, %s].", tcpConnection.remoteEndPoint, tcpConnection.localEndPoint, connectionId);
|
||||
|
@ -72,7 +72,24 @@ module.exports = {
|
||||
if (err) return test.done(err);
|
||||
test.done();
|
||||
}
|
||||
}*/
|
||||
}*/,
|
||||
'Connect to secure tcp endpoint': function(test) {
|
||||
var conn = client.createConnection({
|
||||
useSslConnection: true,
|
||||
targetHost: 'localhost',
|
||||
validateServer: false
|
||||
}, 'tcp://localhost:1115');
|
||||
conn.on('error', function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function () {
|
||||
test.done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
testBase.init(module.exports, false);
|
47
test/projections_test.js
Normal file
47
test/projections_test.js
Normal file
@ -0,0 +1,47 @@
|
||||
const client = require('../src/client');
|
||||
const userCredentials = new client.UserCredentials('admin', 'changeit');
|
||||
|
||||
const log = new client.NoopLogger();
|
||||
const httpEndpoint = 'http://127.0.0.1:2113';
|
||||
const operationTimeout = 5000;
|
||||
|
||||
const simpleProjection = "\
|
||||
fromStream('$stats-127.0.0.1:2113')\
|
||||
.when({\
|
||||
$init: function(){\
|
||||
return {\
|
||||
count: 0\
|
||||
}\
|
||||
},\
|
||||
$any: function(s,e){\
|
||||
s.count += 1;\
|
||||
}\
|
||||
})\
|
||||
";
|
||||
|
||||
module.exports = {
|
||||
setUp: function(cb) {
|
||||
this.projectionsManager = new client.ProjectionsManager(log, httpEndpoint, operationTimeout);
|
||||
cb();
|
||||
},
|
||||
'Create One Time Projection Happy Path': function(test) {
|
||||
test.expect(1);
|
||||
|
||||
this.projectionsManager.createOneTime(simpleProjection, userCredentials)
|
||||
.then(function (result) {
|
||||
test.equal(result, undefined);
|
||||
test.done();
|
||||
})
|
||||
.catch(test.done);
|
||||
},
|
||||
'List All Happy Path': function(test) {
|
||||
test.expect(1);
|
||||
this.projectionsManager.listAll(userCredentials)
|
||||
.then(function (projections) {
|
||||
test.ok(projections.length > 0, "no projections");
|
||||
test.done();
|
||||
})
|
||||
.catch(test.done);
|
||||
}
|
||||
//TODO: other tests
|
||||
};
|
Reference in New Issue
Block a user