UNPKG

ravendb

Version:
231 lines 8.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RavenCommand = void 0; const StatusCode_js_1 = require("./StatusCode.js"); const node_stream_1 = require("node:stream"); const LogUtil_js_1 = require("../Utility/LogUtil.js"); const index_js_1 = require("../Exceptions/index.js"); const HttpUtil_js_1 = require("../Utility/HttpUtil.js"); const Serializer_js_1 = require("../Mapping/Json/Serializer.js"); const RavenCommandResponsePipeline_js_1 = require("./RavenCommandResponsePipeline.js"); const ObjectUtil_js_1 = require("../Utility/ObjectUtil.js"); const Constants_js_1 = require("../Constants.js"); const DefaultCommandResponseBehavior_js_1 = require("./Behaviors/DefaultCommandResponseBehavior.js"); const log = (0, LogUtil_js_1.getLogger)({ module: "RavenCommand" }); class RavenCommand { // protected final Class<TResult> resultClass; result; statusCode; failedNodes; _responseType; timeout; _canCache; _canCacheAggressively; _canReadFromCache = true; _selectedNodeTag; _selectedShardNumber; _numberOfAttempts; failoverTopologyEtag = -2; _etag; get responseBehavior() { return DefaultCommandResponseBehavior_js_1.DefaultCommandResponseBehavior.INSTANCE; } get responseType() { return this._responseType; } set etag(value) { this._etag = value; } get canCache() { return this._canCache; } get canCacheAggressively() { return this._canCacheAggressively; } get selectedNodeTag() { return this._selectedNodeTag; } set selectedNodeTag(nodeTag) { this._selectedNodeTag = nodeTag; } get selectedShardNumber() { return this._selectedShardNumber; } set selectedShardNumber(value) { this._selectedShardNumber = value; } get numberOfAttempts() { return this._numberOfAttempts; } set numberOfAttempts(value) { this._numberOfAttempts = value; } constructor(copy) { if (copy instanceof RavenCommand) { this._canCache = copy._canCache; this._canReadFromCache = copy._canReadFromCache; this._canCacheAggressively = copy._canCacheAggressively; this._selectedNodeTag = copy._selectedNodeTag; this._selectedShardNumber = copy.selectedShardNumber; this._responseType = copy._responseType; } else { this._responseType = "Object"; this._canCache = true; this._canCacheAggressively = true; } } get _serializer() { return Serializer_js_1.JsonSerializer.getDefaultForCommandPayload(); } async setResponseFromCache(cachedValue) { if (!cachedValue) { this.result = null; return; } const readable = new node_stream_1.Readable(); readable.push(cachedValue); readable.push(null); await this.setResponseAsync(readable, true); } _defaultPipeline(bodyCallback) { return this._pipeline() .parseJsonSync() .collectBody(bodyCallback) .objectKeysTransform(ObjectUtil_js_1.ObjectUtil.camel); } async setResponseAsync(bodyStream, fromCache) { if (this._responseType === "Empty" || this._responseType === "Raw") { this._throwInvalidResponse(); } return (0, index_js_1.throwError)("NotSupportedException", this.constructor.name + " command must override the setResponseAsync()" + " method which expects response with the following type: " + this._responseType); } async send(agent, requestOptions) { const { body, uri, fetcher, ...restOptions } = requestOptions; log.info(`Send command ${this.constructor.name} to ${uri}${body ? " with body " + body : ""}.`); if (requestOptions.dispatcher) { // support for fiddler agent = requestOptions.dispatcher; } const bodyToUse = fetcher ? RavenCommand.maybeWrapBody(body) : body; const optionsToUse = { body: bodyToUse, ...restOptions, dispatcher: agent }; const passthrough = new node_stream_1.PassThrough(); passthrough.pause(); const fetchFn = fetcher ?? fetch; // support for custom fetcher const response = await fetchFn(uri, optionsToUse); const effectiveStream = response.body ? node_stream_1.Readable.fromWeb(response.body) : new node_stream_1.Stream(); effectiveStream .pipe(passthrough); return { response, bodyStream: passthrough }; } static maybeWrapBody(body) { if (body instanceof node_stream_1.Readable) { throw new Error("Requests using stream.Readable as payload are not yet supported!"); } return body; } setResponseRaw(response, body) { (0, index_js_1.throwError)("NotSupportedException", "When _responseType is set to RAW then please override this method to handle the response."); } _urlEncode(value) { return encodeURIComponent(value); } static ensureIsNotNullOrEmpty(value, name) { if (!value) { (0, index_js_1.throwError)("InvalidArgumentException", name + " cannot be null or empty"); } } isFailedWithNode(node) { return this.failedNodes && !!this.failedNodes.get(node); } async processResponse(cache, response, bodyStream, url) { if (!response) { return "Automatic"; } if (this._responseType === "Empty" || response.status === StatusCode_js_1.StatusCodes.NoContent) { return "Automatic"; } try { if (this._responseType === "Object") { const contentLength = Number.parseInt(response.headers.get("content-length"), 10); if (contentLength === 0) { (0, HttpUtil_js_1.closeHttpResponse)(response); return "Automatic"; } const bodyPromise = this.setResponseAsync(bodyStream, false); bodyStream.resume(); const body = await bodyPromise; if (cache) { this._cacheResponse(cache, url, response, body); } return "Automatic"; } else { const bodyPromise = this.setResponseAsync(bodyStream, false); bodyStream.resume(); await bodyPromise; } return "Automatic"; } catch (err) { log.error(err, `Error processing command ${this.constructor.name} response.`); (0, index_js_1.throwError)("RavenException", `Error processing command ${this.constructor.name} response: ${err.stack}`, err); } finally { (0, HttpUtil_js_1.closeHttpResponse)(response); // response.destroy(); // since we're calling same hosts and port a lot, we might not want to destroy sockets explicitly // they're going to get back to Agent's pool and reused } return "Automatic"; } _cacheResponse(cache, url, response, responseJson) { if (!this.canCache) { return; } const changeVector = (0, HttpUtil_js_1.getEtagHeader)(response); if (!changeVector) { return; } cache.set(url, changeVector, responseJson); } _addChangeVectorIfNotNull(changeVector, req) { if (changeVector) { req.headers[Constants_js_1.HEADERS.IF_MATCH] = `"${changeVector}"`; } } _reviveResultTypes(raw, conventions, typeInfo, knownTypes) { return conventions.objectMapper.fromObjectLiteral(raw, typeInfo, knownTypes); } async _parseResponseDefaultAsync(bodyStream) { let body = null; this.result = await this._defaultPipeline(_ => body = _).process(bodyStream); return body; } _headers() { return HttpUtil_js_1.HeadersBuilder.create(); } _throwInvalidResponse() { (0, index_js_1.throwError)("InvalidOperationException", "Response is invalid"); } static _throwInvalidResponse(cause) { (0, index_js_1.throwError)("InvalidOperationException", "Response is invalid: " + cause, cause.message, cause); } onResponseFailure(response) { // empty } _pipeline() { return RavenCommandResponsePipeline_js_1.RavenCommandResponsePipeline.create(); } } exports.RavenCommand = RavenCommand; //# sourceMappingURL=RavenCommand.js.map