Initial commit
This commit is contained in:
80
src/clientOperations/appendToStreamOperation.js
Normal file
80
src/clientOperations/appendToStreamOperation.js
Normal file
@ -0,0 +1,80 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var WriteResult = require('../results').WriteResult;
|
||||
var Position = require('../results').Position;
|
||||
|
||||
var OperationBase = require('../clientOperations/operationBase');
|
||||
|
||||
function AppendToStreamOperation(log, cb, requireMaster, stream, expectedVersion, events, userCredentials) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.WriteEvents, TcpCommand.WriteEventsCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.WriteEventsCompleted;
|
||||
|
||||
this._requireMaster = requireMaster;
|
||||
this._stream = stream;
|
||||
this._expectedVersion = expectedVersion;
|
||||
this._events = events;
|
||||
}
|
||||
util.inherits(AppendToStreamOperation, OperationBase);
|
||||
|
||||
AppendToStreamOperation.prototype._createRequestDto = function() {
|
||||
var dtos = this._events.map(function(ev) {
|
||||
var eventId = new Buffer(uuid.parse(ev.eventId));
|
||||
return new ClientMessage.NewEvent({
|
||||
event_id: eventId, event_type: ev.type,
|
||||
data_content_type: ev.isJson ? 1 : 0, metadata_content_type: 0,
|
||||
data: ev.data, metadata: ev.metadata});
|
||||
});
|
||||
return new ClientMessage.WriteEvents({
|
||||
event_stream_id: this._stream,
|
||||
expected_version: this._expectedVersion,
|
||||
events: dtos,
|
||||
require_master: this._requireMaster});
|
||||
};
|
||||
|
||||
AppendToStreamOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.OperationResult.Success:
|
||||
if (this._wasCommitTimeout)
|
||||
this.log.debug("IDEMPOTENT WRITE SUCCEEDED FOR %s.", this);
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.OperationResult.PrepareTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "PrepareTimeout");
|
||||
case ClientMessage.OperationResult.ForwardTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout");
|
||||
case ClientMessage.OperationResult.CommitTimeout:
|
||||
this._wasCommitTimeout = true;
|
||||
return new InspectionResult(InspectionDecision.Retry, "CommitTimeout");
|
||||
case ClientMessage.OperationResult.WrongExpectedVersion:
|
||||
var err = ["Append failed due to WrongExpectedVersion. Stream: ", this._stream,", Expected version: ", this._expectedVersion].join('');
|
||||
this.fail(new Error(err));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion");
|
||||
case ClientMessage.OperationResult.StreamDeleted:
|
||||
this.fail(new Error("Stream deleted. Stream: " + this._stream));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.OperationResult.InvalidTransaction:
|
||||
this.fail(new Error("Invalid transaction."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction");
|
||||
case ClientMessage.OperationResult.AccessDenied:
|
||||
this.fail(new Error(["Write access denied for stream '", this._stream, "'."].join('')));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error("Unexpected OperationResult: " + response.result);
|
||||
}
|
||||
};
|
||||
|
||||
AppendToStreamOperation.prototype._transformResponse = function(response) {
|
||||
return new WriteResult(response.last_event_number, new Position(response.prepare_position || -1, response.commit_position || -1));
|
||||
};
|
||||
|
||||
AppendToStreamOperation.prototype.toString = function() {
|
||||
return util.format("Stream: %s, ExpectedVersion: %d", this._stream, this._expectedVersion);
|
||||
};
|
||||
|
||||
module.exports = AppendToStreamOperation;
|
65
src/clientOperations/commitTransactionOperation.js
Normal file
65
src/clientOperations/commitTransactionOperation.js
Normal file
@ -0,0 +1,65 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('../clientOperations/operationBase');
|
||||
|
||||
|
||||
function CommitTransactionOperation(log, cb, requireMaster, transactionId, userCredentials) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.TransactionCommit, TcpCommand.TransactionCommitCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.TransactionCommitCompleted;
|
||||
|
||||
this._requireMaster = requireMaster;
|
||||
this._transactionId = transactionId;
|
||||
}
|
||||
util.inherits(CommitTransactionOperation, OperationBase);
|
||||
|
||||
CommitTransactionOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.TransactionCommit(this._transactionId, this._requireMaster);
|
||||
};
|
||||
|
||||
CommitTransactionOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.OperationResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.OperationResult.PrepareTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "PrepareTimeout");
|
||||
case ClientMessage.OperationResult.CommitTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "CommitTimeout");
|
||||
case ClientMessage.OperationResult.ForwardTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout");
|
||||
case ClientMessage.OperationResult.WrongExpectedVersion:
|
||||
var err = util.format("Commit transaction failed due to WrongExpectedVersion. TransactionID: %d.", this._transactionId);
|
||||
this.fail(new Error(err));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion");
|
||||
case ClientMessage.OperationResult.StreamDeleted:
|
||||
this.fail(new Error("Stream deleted."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.OperationResult.InvalidTransaction:
|
||||
this.fail(new Error("Invalid transaction."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction");
|
||||
case ClientMessage.OperationResult.AccessDenied:
|
||||
this.fail(new Error("Write access denied."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected OperationResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
CommitTransactionOperation.prototype._transformResponse = function(response) {
|
||||
var logPosition = new results.Position(response.prepare_position || -1, response.commit_position || -1);
|
||||
return new results.WriteResult(response.last_event_number, logPosition);
|
||||
};
|
||||
|
||||
CommitTransactionOperation.prototype.toString = function() {
|
||||
return util.format("TransactionId: %s", this._transactionId);
|
||||
};
|
||||
|
||||
module.exports = CommitTransactionOperation;
|
66
src/clientOperations/deleteStreamOperation.js
Normal file
66
src/clientOperations/deleteStreamOperation.js
Normal file
@ -0,0 +1,66 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('../clientOperations/operationBase');
|
||||
|
||||
|
||||
function DeleteStreamOperation(log, cb, requireMaster, stream, expectedVersion, hardDelete, userCredentials) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.DeleteStream, TcpCommand.DeleteStreamCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.DeleteStreamCompleted;
|
||||
|
||||
this._requireMaster = requireMaster;
|
||||
this._stream = stream;
|
||||
this._expectedVersion = expectedVersion;
|
||||
this._hardDelete = hardDelete;
|
||||
}
|
||||
util.inherits(DeleteStreamOperation, OperationBase);
|
||||
|
||||
DeleteStreamOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.DeleteStream(this._stream, this._expectedVersion, this._requireMaster, this._hardDelete);
|
||||
};
|
||||
|
||||
DeleteStreamOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.OperationResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.OperationResult.PrepareTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "PrepareTimeout");
|
||||
case ClientMessage.OperationResult.CommitTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "CommitTimeout");
|
||||
case ClientMessage.OperationResult.ForwardTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout");
|
||||
case ClientMessage.OperationResult.WrongExpectedVersion:
|
||||
var err = util.format("Delete stream failed due to WrongExpectedVersion. Stream: %s, Expected version: %d.", this._stream, this._expectedVersion);
|
||||
this.fail(new Error("Wrong expected version: " + err));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion");
|
||||
case ClientMessage.OperationResult.StreamDeleted:
|
||||
this.fail(new Error("Stream deleted: " + this._stream));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.OperationResult.InvalidTransaction:
|
||||
this.fail(new Error("Invalid transaction."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction");
|
||||
case ClientMessage.OperationResult.AccessDenied:
|
||||
this.fail(new Error(util.format("Write access denied for stream '%s'.", this._stream)));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected OperationResult: %d.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
DeleteStreamOperation.prototype._transformResponse = function(response) {
|
||||
return new results.DeleteResult(new results.Position(response.prepare_position || -1, response.commit_position || -1));
|
||||
};
|
||||
|
||||
DeleteStreamOperation.prototype.toString = function() {
|
||||
return util.format("Stream: %s, ExpectedVersion: %s.", this._stream, this._expectedVersion);
|
||||
};
|
||||
|
||||
module.exports = DeleteStreamOperation;
|
148
src/clientOperations/operationBase.js
Normal file
148
src/clientOperations/operationBase.js
Normal file
@ -0,0 +1,148 @@
|
||||
var util = require('util');
|
||||
|
||||
var TcpPackage = require('../systemData/tcpPackage');
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var TcpFlags = require('../systemData/tcpFlags');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var createInspectionResult = require('./../systemData/inspectionResult');
|
||||
var createBufferSegment = require('../common/bufferSegment');
|
||||
|
||||
function OperationBase(log, cb, requestCommand, responseCommand, userCredentials) {
|
||||
this.log = log;
|
||||
this._cb = cb;
|
||||
this._requestCommand = requestCommand;
|
||||
this._responseCommand = responseCommand;
|
||||
this.userCredentials = userCredentials;
|
||||
|
||||
this._completed = false;
|
||||
this._response = null;
|
||||
|
||||
this._responseType = null;
|
||||
}
|
||||
|
||||
OperationBase.prototype._createRequestDto = function() {
|
||||
throw new Error('_createRequestDto not implemented.');
|
||||
};
|
||||
|
||||
OperationBase.prototype._inspectResponse = function() {
|
||||
throw new Error('_inspectResponse not implemented.');
|
||||
};
|
||||
|
||||
OperationBase.prototype._transformResponse = function() {
|
||||
throw new Error('_transformResponse not implemented.');
|
||||
};
|
||||
|
||||
OperationBase.prototype.fail = function(error) {
|
||||
this._completed = true;
|
||||
this._cb(error);
|
||||
};
|
||||
|
||||
OperationBase.prototype._succeed = function() {
|
||||
if (!this._completed) {
|
||||
this._completed = true;
|
||||
|
||||
if (this._response != null)
|
||||
this._cb(null, this._transformResponse(this._response));
|
||||
else
|
||||
this._cb(new Error("No result."))
|
||||
}
|
||||
};
|
||||
|
||||
OperationBase.prototype.createNetworkPackage = function(correlationId) {
|
||||
var dto = this._createRequestDto();
|
||||
var buf = dto.encode().toBuffer();
|
||||
return new TcpPackage(
|
||||
this._requestCommand,
|
||||
this.userCredentials ? TcpFlags.Authenticated : TcpFlags.None,
|
||||
correlationId,
|
||||
this.userCredentials ? this.userCredentials.username : null,
|
||||
this.userCredentials ? this.userCredentials.password : null,
|
||||
createBufferSegment(buf));
|
||||
};
|
||||
|
||||
OperationBase.prototype.inspectPackage = function(pkg) {
|
||||
try {
|
||||
if (pkg.command === this._responseCommand) {
|
||||
this._response = this._responseType.decode(pkg.data.toBuffer());
|
||||
return this._inspectResponse(this._response);
|
||||
}
|
||||
switch (pkg.command) {
|
||||
case TcpCommand.NotAuthenticated:
|
||||
return this._inspectNotAuthenticated(pkg);
|
||||
case TcpCommand.BadRequest:
|
||||
return this._inspectBadRequest(pkg);
|
||||
case TcpCommand.NotHandled:
|
||||
return this._inspectNotHandled(pkg);
|
||||
default:
|
||||
return this._inspectUnexpectedCommand(package, this._responseCommand);
|
||||
}
|
||||
} catch(e) {
|
||||
this.fail(e);
|
||||
return createInspectionResult(InspectionDecision.EndOperation, "Error - " + e.message);
|
||||
}
|
||||
};
|
||||
|
||||
OperationBase.prototype._inspectNotAuthenticated = function(pkg)
|
||||
{
|
||||
var message = '';
|
||||
try {
|
||||
message = pkg.data.toString();
|
||||
} catch(e) {}
|
||||
//TODO typed error
|
||||
this.fail(new Error("Authentication error: " + message));
|
||||
return createInspectionResult(InspectionDecision.EndOperation, "NotAuthenticated");
|
||||
};
|
||||
|
||||
OperationBase.prototype._inspectBadRequest = function(pkg)
|
||||
{
|
||||
var message = '';
|
||||
try {
|
||||
message = pkg.data.toString();
|
||||
} catch(e) {}
|
||||
//TODO typed error
|
||||
this.fail(new Error("Bad request: " + message));
|
||||
return createInspectionResult(InspectionDecision.EndOperation, "BadRequest - " + message);
|
||||
};
|
||||
|
||||
OperationBase.prototype._inspectNotHandled = function(pkg)
|
||||
{
|
||||
var message = ClientMessage.NotHandled.decode(pkg.data.toBuffer());
|
||||
switch (message.reason)
|
||||
{
|
||||
case ClientMessage.NotHandled.NotHandledReason.NotReady:
|
||||
return createInspectionResult(InspectionDecision.Retry, "NotHandled - NotReady");
|
||||
|
||||
case ClientMessage.NotHandled.NotHandledReason.TooBusy:
|
||||
return createInspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy");
|
||||
|
||||
case ClientMessage.NotHandled.NotHandledReason.NotMaster:
|
||||
var masterInfo = ClientMessage.NotHandled.MasterInfo.decode(message.additional_info);
|
||||
return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotMaster",
|
||||
{host: masterInfo.external_tcp_address, port: masterInfo.external_tcp_port},
|
||||
{host: masterInfo.external_secure_tcp_address, port: masterInfo.external_secure_tcp_port});
|
||||
|
||||
default:
|
||||
this.log.error("Unknown NotHandledReason: %s.", message.reason);
|
||||
return createInspectionResult(InspectionDecision.Retry, "NotHandled - <unknown>");
|
||||
}
|
||||
};
|
||||
|
||||
OperationBase.prototype._inspectUnexpectedCommand = function(pkg, expectedCommand)
|
||||
{
|
||||
if (pkg.command == expectedCommand)
|
||||
throw new Error("Command shouldn't be " + TcpCommand.getName(pkg.command));
|
||||
|
||||
this.log.error("Unexpected TcpCommand received.\n"
|
||||
+ "Expected: %s, Actual: %s, Flags: %s, CorrelationId: %s\n"
|
||||
+ "Operation (%s): %s\n"
|
||||
+"TcpPackage Data Dump:\n%j",
|
||||
expectedCommand, TcpCommand.getName(pkg.command), pkg.flags, pkg.correlationId,
|
||||
this.constructor.name, this, pkg.data);
|
||||
|
||||
this.fail(new Error(util.format("Unexpected command. Expecting %s got %s.", TcpCommand.getName(expectedCommand), TcpCommand.getName(pkg.command))));
|
||||
return createInspectionResult(InspectionDecision.EndOperation, "Unexpected command - " + TcpCommand.getName(pkg.command));
|
||||
};
|
||||
|
||||
|
||||
module.exports = OperationBase;
|
61
src/clientOperations/readAllEventsBackwardOperation.js
Normal file
61
src/clientOperations/readAllEventsBackwardOperation.js
Normal file
@ -0,0 +1,61 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var ReadDirection = require('../readDirection');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('./operationBase');
|
||||
|
||||
function ReadAllEventsBackwardOperation(
|
||||
log, cb, position, maxCount, resolveLinkTos, requireMaster, userCredentials
|
||||
) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.ReadAllEventsBackward, TcpCommand.ReadAllEventsBackwardCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.ReadAllEventsCompleted;
|
||||
|
||||
this._position = position;
|
||||
this._maxCount = maxCount;
|
||||
this._resolveLinkTos = resolveLinkTos;
|
||||
this._requireMaster = requireMaster;
|
||||
}
|
||||
util.inherits(ReadAllEventsBackwardOperation, OperationBase);
|
||||
|
||||
ReadAllEventsBackwardOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.ReadAllEvents(this._position.commitPosition, this._position.preparePosition, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
ReadAllEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.ReadAllEventsCompleted.ReadAllResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.ReadAllEventsCompleted.ReadAllResult.Error:
|
||||
this.fail(new Error("Server error: " + response.error));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Error");
|
||||
case ClientMessage.ReadAllEventsCompleted.ReadAllResult.AccessDenied:
|
||||
this.fail(new Error("Read access denied for $all."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected ReadStreamResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
ReadAllEventsBackwardOperation.prototype._transformResponse = function(response) {
|
||||
return new results.AllEventsSlice(
|
||||
ReadDirection.Backward,
|
||||
new results.Position(response.commit_position, response.prepare_position),
|
||||
new results.Position(response.next_commit_position, response.next_prepare_position),
|
||||
response.events
|
||||
)
|
||||
};
|
||||
|
||||
ReadAllEventsBackwardOperation.prototype.toString = function() {
|
||||
return util.format("Position: %j, MaxCount: %d, ResolveLinkTos: %s, RequireMaster: %s",
|
||||
this._position, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
module.exports = ReadAllEventsBackwardOperation;
|
61
src/clientOperations/readAllEventsForwardOperation.js
Normal file
61
src/clientOperations/readAllEventsForwardOperation.js
Normal file
@ -0,0 +1,61 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var ReadDirection = require('../readDirection');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('./operationBase');
|
||||
|
||||
function ReadAllEventsForwardOperation(
|
||||
log, cb, position, maxCount, resolveLinkTos, requireMaster, userCredentials
|
||||
) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.ReadAllEventsForward, TcpCommand.ReadAllEventsForwardCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.ReadAllEventsCompleted;
|
||||
|
||||
this._position = position;
|
||||
this._maxCount = maxCount;
|
||||
this._resolveLinkTos = resolveLinkTos;
|
||||
this._requireMaster = requireMaster;
|
||||
}
|
||||
util.inherits(ReadAllEventsForwardOperation, OperationBase);
|
||||
|
||||
ReadAllEventsForwardOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.ReadAllEvents(this._position.commitPosition, this._position.preparePosition, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
ReadAllEventsForwardOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.ReadAllEventsCompleted.ReadAllResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.ReadAllEventsCompleted.ReadAllResult.Error:
|
||||
this.fail(new Error("Server error: " + response.error));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Error");
|
||||
case ClientMessage.ReadAllEventsCompleted.ReadAllResult.AccessDenied:
|
||||
this.fail(new Error("Read access denied for $all."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected ReadStreamResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
ReadAllEventsForwardOperation.prototype._transformResponse = function(response) {
|
||||
return new results.AllEventsSlice(
|
||||
ReadDirection.Forward,
|
||||
new results.Position(response.commit_position, response.prepare_position),
|
||||
new results.Position(response.next_commit_position, response.next_prepare_position),
|
||||
response.events
|
||||
)
|
||||
};
|
||||
|
||||
ReadAllEventsForwardOperation.prototype.toString = function() {
|
||||
return util.format("Position: %j, MaxCount: %d, ResolveLinkTos: %s, RequireMaster: %s",
|
||||
this._position, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
module.exports = ReadAllEventsForwardOperation;
|
79
src/clientOperations/readEventOperation.js
Normal file
79
src/clientOperations/readEventOperation.js
Normal file
@ -0,0 +1,79 @@
|
||||
var util = require('util');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('./operationBase');
|
||||
|
||||
function ReadEventOperation(log, cb, stream, eventNumber, resolveLinkTos, requireMaster, userCredentials) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.ReadEvent, TcpCommand.ReadEventCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.ReadEventCompleted;
|
||||
|
||||
this._stream = stream;
|
||||
this._eventNumber = eventNumber;
|
||||
this._resolveLinkTos = resolveLinkTos;
|
||||
this._requireMaster = requireMaster;
|
||||
}
|
||||
util.inherits(ReadEventOperation, OperationBase);
|
||||
|
||||
ReadEventOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.ReadEvent(this._stream, this._eventNumber, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
ReadEventOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.NotFound:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "NotFound");
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.NoStream:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "NoStream");
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.StreamDeleted:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.Error:
|
||||
this.fail(new Error("Server error: " + response.error));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Error");
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.AccessDenied:
|
||||
this.fail(new Error(util.format("Read access denied for stream '%s'.", this._stream)));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected ReadEventResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
ReadEventOperation.prototype._transformResponse = function(response) {
|
||||
return new results.EventReadResult(convert(response.result), this._stream, this._eventNumber, response.event);
|
||||
};
|
||||
|
||||
|
||||
function convert(result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.Success:
|
||||
return results.EventReadStatus.Success;
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.NotFound:
|
||||
return results.EventReadStatus.NotFound;
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.NoStream:
|
||||
return results.EventReadStatus.NoStream;
|
||||
case ClientMessage.ReadEventCompleted.ReadEventResult.StreamDeleted:
|
||||
return results.EventReadStatus.StreamDeleted;
|
||||
default:
|
||||
throw new Error(util.format("Unexpected ReadEventResult: %s.", result));
|
||||
}
|
||||
}
|
||||
|
||||
ReadEventOperation.prototype.toString = function() {
|
||||
return util.format("Stream: %s, EventNumber: %s, ResolveLinkTo: %s, RequireMaster: %s",
|
||||
this._stream, this._eventNumber, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
module.exports = ReadEventOperation;
|
73
src/clientOperations/readStreamEventsBackwardOperation.js
Normal file
73
src/clientOperations/readStreamEventsBackwardOperation.js
Normal file
@ -0,0 +1,73 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var ReadDirection = require('../readDirection');
|
||||
var StatusCode = require('../systemData/statusCode');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('./operationBase');
|
||||
|
||||
function ReadStreamEventsBackwardOperation(
|
||||
log, cb, stream, fromEventNumber, maxCount, resolveLinkTos, requireMaster, userCredentials
|
||||
) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.ReadStreamEventsBackward, TcpCommand.ReadStreamEventsBackwardCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.ReadStreamEventsCompleted;
|
||||
|
||||
this._stream = stream;
|
||||
this._fromEventNumber = fromEventNumber;
|
||||
this._maxCount = maxCount;
|
||||
this._resolveLinkTos = resolveLinkTos;
|
||||
this._requireMaster = requireMaster;
|
||||
}
|
||||
util.inherits(ReadStreamEventsBackwardOperation, OperationBase);
|
||||
|
||||
ReadStreamEventsBackwardOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.ReadStreamEvents(this._stream, this._fromEventNumber, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
ReadStreamEventsBackwardOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.StreamDeleted:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.NoStream:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "NoStream");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.Error:
|
||||
this.fail(new Error("Server error: " + response.error));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Error");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.AccessDenied:
|
||||
this.fail(new Error(util.format("Read access denied for stream '%s'.", this._stream)));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected ReadStreamResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
ReadStreamEventsBackwardOperation.prototype._transformResponse = function(response) {
|
||||
return new results.StreamEventsSlice(
|
||||
StatusCode.convert(response.result),
|
||||
this._stream,
|
||||
this._fromEventNumber,
|
||||
ReadDirection.Backward,
|
||||
response.events,
|
||||
response.next_event_number,
|
||||
response.last_event_number,
|
||||
response.is_end_of_stream
|
||||
)
|
||||
};
|
||||
|
||||
ReadStreamEventsBackwardOperation.prototype.toString = function() {
|
||||
return util.format("Stream: %s, FromEventNumber: %d, MaxCount: %d, ResolveLinkTos: %s, RequireMaster: %s",
|
||||
this._stream, this._fromEventNumber, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
module.exports = ReadStreamEventsBackwardOperation;
|
73
src/clientOperations/readStreamEventsForwardOperation.js
Normal file
73
src/clientOperations/readStreamEventsForwardOperation.js
Normal file
@ -0,0 +1,73 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var ReadDirection = require('../readDirection');
|
||||
var StatusCode = require('../systemData/statusCode');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('./operationBase');
|
||||
|
||||
function ReadStreamEventsForwardOperation(
|
||||
log, cb, stream, fromEventNumber, maxCount, resolveLinkTos, requireMaster, userCredentials
|
||||
) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.ReadStreamEventsForward, TcpCommand.ReadStreamEventsForwardCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.ReadStreamEventsCompleted;
|
||||
|
||||
this._stream = stream;
|
||||
this._fromEventNumber = fromEventNumber;
|
||||
this._maxCount = maxCount;
|
||||
this._resolveLinkTos = resolveLinkTos;
|
||||
this._requireMaster = requireMaster;
|
||||
}
|
||||
util.inherits(ReadStreamEventsForwardOperation, OperationBase);
|
||||
|
||||
ReadStreamEventsForwardOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.ReadStreamEvents(this._stream, this._fromEventNumber, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
ReadStreamEventsForwardOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.StreamDeleted:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.NoStream:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "NoStream");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.Error:
|
||||
this.fail(new Error("Server error: " + response.error));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Error");
|
||||
case ClientMessage.ReadStreamEventsCompleted.ReadStreamResult.AccessDenied:
|
||||
this.fail(new Error(util.format("Read access denied for stream '%s'.", this._stream)));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected ReadStreamResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
ReadStreamEventsForwardOperation.prototype._transformResponse = function(response) {
|
||||
return new results.StreamEventsSlice(
|
||||
StatusCode.convert(response.result),
|
||||
this._stream,
|
||||
this._fromEventNumber,
|
||||
ReadDirection.Forward,
|
||||
response.events,
|
||||
response.next_event_number,
|
||||
response.last_event_number,
|
||||
response.is_end_of_stream
|
||||
)
|
||||
};
|
||||
|
||||
ReadStreamEventsForwardOperation.prototype.toString = function() {
|
||||
return util.format("Stream: %s, FromEventNumber: %d, MaxCount: %d, ResolveLinkTos: %s, RequireMaster: %s",
|
||||
this._stream, this._fromEventNumber, this._maxCount, this._resolveLinkTos, this._requireMaster);
|
||||
};
|
||||
|
||||
module.exports = ReadStreamEventsForwardOperation;
|
66
src/clientOperations/startTransactionOperation.js
Normal file
66
src/clientOperations/startTransactionOperation.js
Normal file
@ -0,0 +1,66 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var EventStoreTransaction = require('../eventStoreTransaction');
|
||||
var results = require('../results');
|
||||
|
||||
var OperationBase = require('../clientOperations/operationBase');
|
||||
|
||||
function StartTransactionOperation(log, cb, requireMaster, stream, expectedVersion, parentConnection, userCredentials) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.TransactionStart, TcpCommand.TransactionStartCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.TransactionStartCompleted;
|
||||
|
||||
this._requireMaster = requireMaster;
|
||||
this._stream = stream;
|
||||
this._expectedVersion = expectedVersion;
|
||||
this._parentConnection = parentConnection;
|
||||
}
|
||||
util.inherits(StartTransactionOperation, OperationBase);
|
||||
|
||||
StartTransactionOperation.prototype._createRequestDto = function() {
|
||||
return new ClientMessage.TransactionStart(this._stream, this._expectedVersion, this._requireMaster);
|
||||
};
|
||||
|
||||
StartTransactionOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.OperationResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.OperationResult.PrepareTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "PrepareTimeout");
|
||||
case ClientMessage.OperationResult.CommitTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "CommitTimeout");
|
||||
case ClientMessage.OperationResult.ForwardTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout");
|
||||
case ClientMessage.OperationResult.WrongExpectedVersion:
|
||||
var err = util.format("Start transaction failed due to WrongExpectedVersion. Stream: %s, Expected version: %d.", this._stream, this._expectedVersion);
|
||||
this.fail(new Error(err));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "WrongExpectedVersion");
|
||||
case ClientMessage.OperationResult.StreamDeleted:
|
||||
this.fail(new Error("Stream deleted: " + this._stream));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "StreamDeleted");
|
||||
case ClientMessage.OperationResult.InvalidTransaction:
|
||||
this.fail(new Error("Invalid transaction."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "InvalidTransaction");
|
||||
case ClientMessage.OperationResult.AccessDenied:
|
||||
this.fail(new Error(util.format("Write access denied for stream '%s'.", this._stream)));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected OperationResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
StartTransactionOperation.prototype._transformResponse = function(response) {
|
||||
return new EventStoreTransaction(results.toNumber(response.transaction_id), this.userCredentials, this._parentConnection);
|
||||
};
|
||||
|
||||
StartTransactionOperation.prototype.toString = function() {
|
||||
return util.format("Stream: %s, ExpectedVersion: %d", this._stream, this._expectedVersion);
|
||||
};
|
||||
|
||||
module.exports = StartTransactionOperation;
|
265
src/clientOperations/subscriptionOperation.js
Normal file
265
src/clientOperations/subscriptionOperation.js
Normal file
@ -0,0 +1,265 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var TcpFlags = require('../systemData/tcpFlags');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var TcpPackage = require('../systemData/tcpPackage');
|
||||
var BufferSegment = require('../common/bufferSegment');
|
||||
var results = require('../results');
|
||||
var SubscriptionDropReason = require('../subscriptionDropReason');
|
||||
|
||||
//TODO: nodify eventAppeared and subscriptionDropped, should be emit on subscription
|
||||
function SubscriptionOperation(
|
||||
log, cb, streamId, resolveLinkTos, userCredentials, eventAppeared,
|
||||
subscriptionDropped, verboseLogging, getConnection
|
||||
) {
|
||||
//TODO: validations
|
||||
//Ensure.NotNull(log, "log");
|
||||
//Ensure.NotNull(source, "source");
|
||||
//Ensure.NotNull(eventAppeared, "eventAppeared");
|
||||
//Ensure.NotNull(getConnection, "getConnection");
|
||||
|
||||
this._log = log;
|
||||
this._cb = cb;
|
||||
this._streamId = streamId || '';
|
||||
this._resolveLinkTos = resolveLinkTos;
|
||||
this._userCredentials = userCredentials;
|
||||
this._eventAppeared = eventAppeared;
|
||||
this._subscriptionDropped = subscriptionDropped || function() {};
|
||||
this._verboseLogging = verboseLogging;
|
||||
this._getConnection = getConnection;
|
||||
|
||||
this._correlationId = null;
|
||||
this._unsubscribed = false;
|
||||
this._subscription = null;
|
||||
this._actionExecuting = false;
|
||||
this._actionQueue = [];
|
||||
}
|
||||
|
||||
SubscriptionOperation.prototype.subscribe = function(correlationId, connection) {
|
||||
if (connection === null) throw new TypeError("connection is null.");
|
||||
|
||||
if (this._subscription != null || this._unsubscribed != 0)
|
||||
return false;
|
||||
|
||||
this._correlationId = correlationId;
|
||||
connection.enqueueSend(this._createSubscriptionPackage());
|
||||
return true;
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._createSubscriptionPackage = function() {
|
||||
throw new Error("SubscriptionOperation._createSubscriptionPackage abstract method called. " + this.constructor.name);
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype.unsubscribe = function() {
|
||||
this.dropSubscription(SubscriptionDropReason.UserInitiated, null, this._getConnection());
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._createUnsubscriptionPackage = function() {
|
||||
var msg = new ClientMessage.UnsubscribeFromStream();
|
||||
var data = new BufferSegment(msg.encode().toBuffer());
|
||||
return new TcpPackage(TcpCommand.UnsubscribeFromStream, TcpFlags.None, this._correlationId, null, null, data);
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
||||
throw new Error("SubscriptionOperation._inspectPackage abstract method called." + this.constructor.name);
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype.inspectPackage = function(pkg) {
|
||||
try
|
||||
{
|
||||
var result = this._inspectPackage(pkg);
|
||||
if (result !== null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (pkg.command)
|
||||
{
|
||||
case TcpCommand.StreamEventAppeared:
|
||||
{
|
||||
var dto = ClientMessage.StreamEventAppeared.decode(pkg.data.toBuffer());
|
||||
this._onEventAppeared(new results.ResolvedEvent(dto.event));
|
||||
return new InspectionResult(InspectionDecision.DoNothing, "StreamEventAppeared");
|
||||
}
|
||||
|
||||
case TcpCommand.SubscriptionDropped:
|
||||
{
|
||||
var dto = ClientMessage.SubscriptionDropped.decode(pkg.data.toBuffer());
|
||||
switch (dto.reason)
|
||||
{
|
||||
case ClientMessage.SubscriptionDropped.SubscriptionDropReason.Unsubscribed:
|
||||
this.dropSubscription(SubscriptionDropReason.UserInitiated, null);
|
||||
break;
|
||||
case ClientMessage.SubscriptionDropped.SubscriptionDropReason.AccessDenied:
|
||||
this.dropSubscription(SubscriptionDropReason.AccessDenied,
|
||||
new Error(util.format("Subscription to '%s' failed due to access denied.", this._streamId || "<all>")));
|
||||
break;
|
||||
default:
|
||||
if (this._verboseLogging) this._log.debug("Subscription dropped by server. Reason: %s.", dto.reason);
|
||||
this.dropSubscription(SubscriptionDropReason.Unknown,
|
||||
new Error(util.format("Unsubscribe reason: '%s'.", dto.reason)));
|
||||
break;
|
||||
}
|
||||
return new InspectionResult(InspectionDecision.EndOperation, util.format("SubscriptionDropped: %s", dto.reason));
|
||||
}
|
||||
|
||||
case TcpCommand.NotAuthenticated:
|
||||
{
|
||||
var message = pkg.data.toString();
|
||||
this.dropSubscription(SubscriptionDropReason.NotAuthenticated,
|
||||
new Error(message || "Authentication error"));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "NotAuthenticated");
|
||||
}
|
||||
|
||||
case TcpCommand.BadRequest:
|
||||
{
|
||||
var message = pkg.data.toString();
|
||||
this.dropSubscription(SubscriptionDropReason.ServerError,
|
||||
new Error("Server error: " + (message || "<no message>")));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, util.format("BadRequest: %s", message));
|
||||
}
|
||||
|
||||
case TcpCommand.NotHandled:
|
||||
{
|
||||
if (this._subscription != null)
|
||||
throw new Error("NotHandled command appeared while we already subscribed.");
|
||||
|
||||
var message = ClientMessage.NotHandled.decode(pkg.data.toBuffer());
|
||||
switch (message.reason)
|
||||
{
|
||||
case ClientMessage.NotHandled.NotHandledReason.NotReady:
|
||||
return new InspectionResult(InspectionDecision.Retry, "NotHandled - NotReady");
|
||||
|
||||
case ClientMessage.NotHandled.NotHandledReason.TooBusy:
|
||||
return new InspectionResult(InspectionDecision.Retry, "NotHandled - TooBusy");
|
||||
|
||||
case ClientMessage.NotHandled.NotHandledReason.NotMaster:
|
||||
var masterInfo = ClientMessage.NotHandled.MasterInfo.decode(message.additional_info);
|
||||
return new InspectionResult(InspectionDecision.Reconnect, "NotHandled - NotMaster",
|
||||
{host: masterInfo.external_tcp_address, port: masterInfo.external_tcp_port},
|
||||
{host: masterInfo.external_secure_tcp_address, port: masterInfo.external_secure_tcp_port});
|
||||
|
||||
default:
|
||||
this._log.error("Unknown NotHandledReason: %s.", message.reason);
|
||||
return new InspectionResult(InspectionDecision.Retry, "NotHandled - <unknown>");
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
this.dropSubscription(SubscriptionDropReason.ServerError,
|
||||
new Error("Command not expected: " + TcpCommand.getName(pkg.command)));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, pkg.command);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this.dropSubscription(SubscriptionDropReason.Unknown, e);
|
||||
return new InspectionResult(InspectionDecision.EndOperation, util.format("Exception - %s", e.Message));
|
||||
}
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype.connectionClosed = function() {
|
||||
this.dropSubscription(SubscriptionDropReason.ConnectionClosed, new Error("Connection was closed."));
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype.timeOutSubscription = function() {
|
||||
if (this._subscription !== null)
|
||||
return false;
|
||||
this.dropSubscription(SubscriptionDropReason.SubscribingError, null);
|
||||
return true;
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype.dropSubscription = function(reason, err, connection) {
|
||||
if (!this._unsubscribed)
|
||||
{
|
||||
this._unsubscribed = true;
|
||||
if (this._verboseLogging)
|
||||
this._log.debug("Subscription %s to %s: closing subscription, reason: %s, exception: %s...",
|
||||
this._correlationId, this._streamId || "<all>", reason, err);
|
||||
|
||||
if (reason !== SubscriptionDropReason.UserInitiated)
|
||||
{
|
||||
if (err === null) throw new Error(util.format("No exception provided for subscription drop reason '%s", reason));
|
||||
//TODO: this should be last thing to execute
|
||||
this._cb(err);
|
||||
}
|
||||
|
||||
if (reason === SubscriptionDropReason.UserInitiated && this._subscription !== null && connection !== null)
|
||||
connection.enqueueSend(this._createUnsubscriptionPackage());
|
||||
|
||||
var self = this;
|
||||
if (this._subscription !== null)
|
||||
this._executeAction(function() { self._subscriptionDropped(self._subscription, reason, err); });
|
||||
}
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._confirmSubscription = function(lastCommitPosition, lastEventNumber) {
|
||||
if (lastCommitPosition < -1)
|
||||
throw new Error(util.format("Invalid lastCommitPosition %s on subscription confirmation.", lastCommitPosition));
|
||||
if (this._subscription !== null)
|
||||
throw new Error("Double confirmation of subscription.");
|
||||
|
||||
if (this._verboseLogging)
|
||||
this._log.debug("Subscription %s to %s: subscribed at CommitPosition: %d, EventNumber: %d.",
|
||||
this._correlationId, this._streamId || "<all>", lastCommitPosition, lastEventNumber);
|
||||
|
||||
this._subscription = this._createSubscriptionObject(lastCommitPosition, lastEventNumber);
|
||||
this._cb(null, this._subscription);
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._createSubscriptionObject = function(lastCommitPosition, lastEventNumber) {
|
||||
throw new Error("SubscriptionOperation._createSubscriptionObject abstract method called. " + this.constructor.name);
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._onEventAppeared = function(e) {
|
||||
if (this._unsubscribed)
|
||||
return;
|
||||
|
||||
if (this._subscription === null) throw new Error("Subscription not confirmed, but event appeared!");
|
||||
|
||||
if (this._verboseLogging)
|
||||
this._log.debug("Subscription %s to %s: event appeared (%s, %d, %s @ %j).",
|
||||
this._correlationId, this._streamId || "<all>",
|
||||
e.originalStreamId, e.originalEventNumber, e.originalEvent.eventType, e.originalPosition);
|
||||
|
||||
var self = this;
|
||||
this._executeAction(function() { self._eventAppeared(self._subscription, e); });
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._executeAction = function(action) {
|
||||
this._actionQueue.push(action);
|
||||
if (!this._actionExecuting) {
|
||||
this._actionExecuting = true;
|
||||
setImmediate(this._executeActions.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype._executeActions = function() {
|
||||
//TODO: possible blocking loop for node.js
|
||||
var action = this._actionQueue.shift();
|
||||
while (action)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
this._log.error(err, "Exception during executing user callback: %s.", err.Message);
|
||||
}
|
||||
action = this._actionQueue.shift();
|
||||
}
|
||||
this._actionExecuting = false;
|
||||
};
|
||||
|
||||
SubscriptionOperation.prototype.toString = function() {
|
||||
return this.constructor.name;
|
||||
};
|
||||
|
||||
|
||||
module.exports = SubscriptionOperation;
|
62
src/clientOperations/transactionalWriteOperation.js
Normal file
62
src/clientOperations/transactionalWriteOperation.js
Normal file
@ -0,0 +1,62 @@
|
||||
var util = require('util');
|
||||
var uuid = require('uuid');
|
||||
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
|
||||
var OperationBase = require('../clientOperations/operationBase');
|
||||
|
||||
|
||||
function TransactionalWriteOperation(log, cb, requireMaster, transactionId, events, userCredentials) {
|
||||
OperationBase.call(this, log, cb, TcpCommand.TransactionWrite, TcpCommand.TransactionWriteCompleted, userCredentials);
|
||||
this._responseType = ClientMessage.TransactionWriteCompleted;
|
||||
|
||||
this._requireMaster = requireMaster;
|
||||
this._transactionId = transactionId;
|
||||
this._events = events;
|
||||
}
|
||||
util.inherits(TransactionalWriteOperation, OperationBase);
|
||||
|
||||
TransactionalWriteOperation.prototype._createRequestDto = function() {
|
||||
var dtos = this._events.map(function(ev) {
|
||||
var eventId = new Buffer(uuid.parse(ev.eventId));
|
||||
return new ClientMessage.NewEvent({
|
||||
event_id: eventId, event_type: ev.type,
|
||||
data_content_type: ev.isJson ? 1 : 0, metadata_content_type: 0,
|
||||
data: ev.data, metadata: ev.metadata});
|
||||
});
|
||||
return new ClientMessage.TransactionWrite(this._transactionId, dtos, this._requireMaster);
|
||||
};
|
||||
|
||||
TransactionalWriteOperation.prototype._inspectResponse = function(response) {
|
||||
switch (response.result)
|
||||
{
|
||||
case ClientMessage.OperationResult.Success:
|
||||
this._succeed();
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "Success");
|
||||
case ClientMessage.OperationResult.PrepareTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "PrepareTimeout");
|
||||
case ClientMessage.OperationResult.CommitTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "CommitTimeout");
|
||||
case ClientMessage.OperationResult.ForwardTimeout:
|
||||
return new InspectionResult(InspectionDecision.Retry, "ForwardTimeout");
|
||||
case ClientMessage.OperationResult.AccessDenied:
|
||||
this.fail(new Error("Write access denied."));
|
||||
return new InspectionResult(InspectionDecision.EndOperation, "AccessDenied");
|
||||
default:
|
||||
throw new Error(util.format("Unexpected OperationResult: %s.", response.result));
|
||||
}
|
||||
};
|
||||
|
||||
TransactionalWriteOperation.prototype._transformResponse = function(response) {
|
||||
return null;
|
||||
};
|
||||
|
||||
TransactionalWriteOperation.prototype.toString = function() {
|
||||
return util.format("TransactionId: %s", this._transactionId);
|
||||
};
|
||||
|
||||
module.exports = TransactionalWriteOperation;
|
||||
|
55
src/clientOperations/volatileSubscriptionOperation.js
Normal file
55
src/clientOperations/volatileSubscriptionOperation.js
Normal file
@ -0,0 +1,55 @@
|
||||
var util = require('util');
|
||||
|
||||
var SubscriptionOperation = require('./subscriptionOperation');
|
||||
var ClientMessage = require('../messages/clientMessage');
|
||||
var TcpPackage = require('../systemData/tcpPackage');
|
||||
var TcpCommand = require('../systemData/tcpCommand');
|
||||
var TcpFlags = require('../systemData/tcpFlags');
|
||||
var BufferSegment = require('../common/bufferSegment');
|
||||
var InspectionDecision = require('../systemData/inspectionDecision');
|
||||
var InspectionResult = require('./../systemData/inspectionResult');
|
||||
var results = require('../results');
|
||||
var VolatileEventStoreSubscription = require('../volatileEventStoreConnection');
|
||||
|
||||
function VolatileSubscriptionOperation(
|
||||
log, cb, streamId, resolveLinkTos, userCredentials, eventAppeared,
|
||||
subscriptionDropped, verboseLogging, getConnection
|
||||
) {
|
||||
SubscriptionOperation.call(this, log, cb, streamId, resolveLinkTos, userCredentials, eventAppeared, subscriptionDropped, verboseLogging, getConnection);
|
||||
}
|
||||
util.inherits(VolatileSubscriptionOperation, SubscriptionOperation);
|
||||
|
||||
VolatileSubscriptionOperation.prototype._createSubscriptionPackage = function() {
|
||||
var dto = new ClientMessage.SubscribeToStream(this._streamId, this._resolveLinkTos);
|
||||
return new TcpPackage(TcpCommand.SubscribeToStream,
|
||||
this._userCredentials != null ? TcpFlags.Authenticated : TcpFlags.None,
|
||||
this._correlationId,
|
||||
this._userCredentials != null ? this._userCredentials.username : null,
|
||||
this._userCredentials != null ? this._userCredentials.password : null,
|
||||
new BufferSegment(dto.encode().toBuffer()));
|
||||
};
|
||||
|
||||
VolatileSubscriptionOperation.prototype._inspectPackage = function(pkg) {
|
||||
try {
|
||||
if (pkg.command == TcpCommand.SubscriptionConfirmation) {
|
||||
var dto = ClientMessage.SubscriptionConfirmation.decode(pkg.data.toBuffer());
|
||||
this._confirmSubscription(dto.last_commit_position, dto.last_event_number);
|
||||
return new InspectionResult(InspectionDecision.Subscribed, "SubscriptionConfirmation");
|
||||
}
|
||||
if (pkg.command == TcpCommand.StreamEventAppeared) {
|
||||
var dto = ClientMessage.StreamEventAppeared.decode(pkg.data.toBuffer());
|
||||
this._onEventAppeared(new results.ResolvedEvent(dto.event));
|
||||
return new InspectionResult(InspectionDecision.DoNothing, "StreamEventAppeared");
|
||||
}
|
||||
return null;
|
||||
} catch(e) {
|
||||
console.log(e.stack);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
VolatileSubscriptionOperation.prototype._createSubscriptionObject = function(lastCommitPosition, lastEventNumber) {
|
||||
return new VolatileEventStoreSubscription(this, this._streamId, lastCommitPosition, lastEventNumber);
|
||||
};
|
||||
|
||||
module.exports = VolatileSubscriptionOperation;
|
Reference in New Issue
Block a user