@solid/community-server
Version:
Community Solid Server: an open and modular implementation of the Solid specifications
74 lines • 4.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BinarySliceResourceStore = void 0;
const global_logger_factory_1 = require("global-logger-factory");
const InternalServerError_1 = require("../util/errors/InternalServerError");
const RangeNotSatisfiedHttpError_1 = require("../util/errors/RangeNotSatisfiedHttpError");
const GuardedStream_1 = require("../util/GuardedStream");
const QuadUtil_1 = require("../util/QuadUtil");
const SliceStream_1 = require("../util/SliceStream");
const TermUtil_1 = require("../util/TermUtil");
const Vocabularies_1 = require("../util/Vocabularies");
const PassthroughStore_1 = require("./PassthroughStore");
/**
* Resource store that slices the data stream if there are range preferences.
* Only works for `bytes` range preferences on binary data streams.
* Does not support multipart range requests.
*
* If the slice happens, unit/start/end values will be written to the metadata to indicate such.
* The values are dependent on the preferences we got as an input,
* as we don't know the actual size of the data stream.
*
* The `defaultSliceSize` parameter can be used to set how large a slice should be if the end of a range is not defined.
* Setting this to 0, which is the default, will cause the end of the stream to be used as the end of the slice.
*/
class BinarySliceResourceStore extends PassthroughStore_1.PassthroughStore {
logger = (0, global_logger_factory_1.getLoggerFor)(this);
defaultSliceSize;
constructor(source, defaultSliceSize = 0) {
super(source);
this.defaultSliceSize = defaultSliceSize;
}
async getRepresentation(identifier, preferences, conditions) {
const result = await this.source.getRepresentation(identifier, preferences, conditions);
if (!preferences.range || preferences.range.unit !== 'bytes' || preferences.range.parts.length === 0) {
return result;
}
if (result.metadata.has(Vocabularies_1.SOLID_HTTP.unit)) {
this.logger.debug('Not slicing stream that has already been sliced.');
return result;
}
if (!result.binary) {
throw new InternalServerError_1.InternalServerError('Trying to slice a non-binary stream.');
}
if (preferences.range.parts.length > 1) {
throw new RangeNotSatisfiedHttpError_1.RangeNotSatisfiedHttpError('Multipart range requests are not supported.');
}
let [{ start, end }] = preferences.range.parts;
const size = (0, QuadUtil_1.termToInt)(result.metadata.get(Vocabularies_1.POSIX.terms.size));
// Set the default end size if not set already
if (this.defaultSliceSize > 0 && typeof end !== 'number' && typeof size === 'number' && start >= 0) {
end = Math.min(size, start + this.defaultSliceSize) - 1;
}
result.metadata.set(Vocabularies_1.SOLID_HTTP.terms.unit, preferences.range.unit);
result.metadata.set(Vocabularies_1.SOLID_HTTP.terms.start, (0, TermUtil_1.toLiteral)(start, Vocabularies_1.XSD.terms.integer));
if (typeof end === 'number') {
result.metadata.set(Vocabularies_1.SOLID_HTTP.terms.end, (0, TermUtil_1.toLiteral)(end, Vocabularies_1.XSD.terms.integer));
}
try {
// The reason we don't determine the object mode based on the object mode of the parent stream
// is that `guardedStreamFrom` does not create object streams when inputting streams/buffers.
// Something to potentially update in the future.
result.data = (0, GuardedStream_1.guardStream)(new SliceStream_1.SliceStream(result.data, { start, end, size, objectMode: false }));
}
catch (error) {
// Creating the slice stream can throw an error if some of the parameters are unacceptable.
// Need to make sure the stream is closed in that case.
result.data.destroy();
throw error;
}
return result;
}
}
exports.BinarySliceResourceStore = BinarySliceResourceStore;
//# sourceMappingURL=BinarySliceResourceStore.js.map