コード例 #1
0
        /// <inheritdoc />
        public Task <bool> VerifyChecksumAsync(string fileId, string algorithm, byte[] checksum, CancellationToken _)
        {
            var valid          = false;
            var internalFileId = new InternalFileId(fileId);

            using (var dataStream = _fileRepFactory.Data(internalFileId, _config).GetStream(FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
            {
                var chunkPositionFile  = _fileRepFactory.ChunkStartPosition(internalFileId, _config);
                var chunkStartPosition = chunkPositionFile.ReadFirstLineAsLong(true, 0);
                var chunkCompleteFile  = _fileRepFactory.ChunkComplete(internalFileId, _config);

                // Only verify the checksum if the entire lastest chunk has been written.
                // If not, just discard the last chunk as it won't match the checksum anyway.
                if (chunkCompleteFile.Exist())
                {
                    var calculateSha1 = dataStream.CalculateSha1(chunkStartPosition);
                    valid = checksum.SequenceEqual(calculateSha1);
                }

                if (!valid)
                {
                    dataStream.Seek(0, SeekOrigin.Begin);
                    dataStream.SetLength(chunkStartPosition);
                }
            }

            return(Task.FromResult(valid));
        }
コード例 #2
0
        private InternalFileRep InitializeChunk(InternalFileId internalFileId, long totalDiskFileLength)
        {
            var chunkComplete = _fileRepFactory.ChunkComplete(internalFileId, _config);

            chunkComplete.Delete();
            _fileRepFactory.ChunkStartPosition(internalFileId, _config).Write(totalDiskFileLength.ToString());

            return(chunkComplete);
        }
コード例 #3
0
        /// <inheritdoc />
        public Task <ITusFile> GetFileAsync(string fileId, CancellationToken _)
        {
            var internalFileId = new InternalFileId(fileId);
            var data           = _fileRepFactory.Data(internalFileId, _config);

            return(Task.FromResult <ITusFile>(data.Exist()
                ? new TusDiskFile(data, _fileRepFactory.Metadata(internalFileId, _config))
                : null));
        }
コード例 #4
0
        private async Task FlushFileToDisk(InternalFileId internalFileId, byte[] fileWriteBuffer, Stream stream, int writeBufferNextFreeIndex)
        {
            var path = _fileRepFactory.Data(internalFileId, _config).Path;

            var client = new FtpClient(_config.Value.ServerUri, _config.Value.ServerPort, _config.Value.ServerUsername, _config.Value.ServerPassword);

            await stream.WriteAsync(fileWriteBuffer, 0, writeBufferNextFreeIndex);

            await stream.FlushAsync();
        }
コード例 #5
0
            private InternalFileRep Create(InternalFileId fileId, string extension, IOptions <FtpServerSettings> config)
            {
                var fileName = fileId.FileId;

                if (!string.IsNullOrEmpty(extension))
                {
                    fileName += "." + extension;
                }

                return(new InternalFileRep(fileId.FileId, System.IO.Path.Combine(_directoryPath, fileName), config));
            }
コード例 #6
0
        /// <inheritdoc />
        public Task DeleteFileAsync(string fileId, CancellationToken _)
        {
            var internalFileId = new InternalFileId(fileId);

            return(Task.Run(() =>
            {
                _fileRepFactory.Data(internalFileId, _config).Delete();
                _fileRepFactory.UploadLength(internalFileId, _config).Delete();
                _fileRepFactory.Metadata(internalFileId, _config).Delete();
                _fileRepFactory.UploadConcat(internalFileId, _config).Delete();
                _fileRepFactory.ChunkStartPosition(internalFileId, _config).Delete();
                _fileRepFactory.ChunkComplete(internalFileId, _config).Delete();
                _fileRepFactory.Expiration(internalFileId, _config).Delete();
            }));
        }
コード例 #7
0
        /// <inheritdoc />
        public async Task <string> CreateFileAsync(long uploadLength, string metadata, CancellationToken cancellationToken)
        {
            var fileId = new InternalFileId();
            var client = new FtpClient(_config.Value.ServerUri, _config.Value.ServerPort, _config.Value.ServerUsername, _config.Value.ServerPassword);

            client.OpenWrite(_fileRepFactory.Data(fileId, _config).Path).Dispose();

            if (uploadLength != -1)
            {
                await SetUploadLengthAsync(fileId.FileId, uploadLength, cancellationToken);
            }
            _fileRepFactory.Metadata(fileId, _config).Write(metadata);

            return(fileId.FileId);
        }
コード例 #8
0
        /// <inheritdoc />
        public async Task <string> CreateFinalFileAsync(string[] partialFiles, string metadata, CancellationToken cancellationToken)
        {
            var partialInternalFileReps = partialFiles.Select(f =>
            {
                var partialData = _fileRepFactory.Data(new InternalFileId(f), _config);

                if (!partialData.Exist())
                {
                    throw new TusStoreException($"File {f} does not exist");
                }

                return(partialData);
            }).ToArray();

            var length = partialInternalFileReps.Sum(f => f.GetLength());

            var fileId = await CreateFileAsync(length, metadata, cancellationToken);

            var internalFileId = new InternalFileId(fileId);

            _fileRepFactory.UploadConcat(internalFileId, _config).Write(new FileConcatFinal(partialFiles).GetHeader());

            using (var finalFile = _fileRepFactory.Data(internalFileId, _config).GetStream(FileMode.Open, FileAccess.Write, FileShare.None))
            {
                foreach (var partialFile in partialInternalFileReps)
                {
                    using var partialStream = partialFile.GetStream(FileMode.Open, FileAccess.Read, FileShare.Read);
                    await partialStream.CopyToAsync(finalFile);
                }
            }

            if (_deletePartialFilesOnConcat)
            {
                await Task.WhenAll(partialInternalFileReps.Select(f => DeleteFileAsync(f.FileId, cancellationToken)));
            }

            return(fileId);
        }
コード例 #9
0
        /// <inheritdoc />
        public async Task <long> AppendDataAsync(string fileId, Stream stream, CancellationToken cancellationToken)
        {
            var client         = new FtpClient(_config.Value.ServerUri, _config.Value.ServerPort, _config.Value.ServerUsername, _config.Value.ServerPassword);
            var internalFileId = new InternalFileId(fileId);

            var httpReadBuffer  = _bufferPool.Rent(_maxReadBufferSize);
            var fileWriteBuffer = _bufferPool.Rent(Math.Max(_maxWriteBufferSize, _maxReadBufferSize));

            try
            {
                var fileUploadLengthProvidedDuringCreate = await GetUploadLengthAsync(fileId, cancellationToken);

                using var diskFileStream = await client.OpenAppendAsync(_fileRepFactory.Data (internalFileId, _config).Path);

                var totalDiskFileLength = diskFileStream.Length;
                if (fileUploadLengthProvidedDuringCreate == totalDiskFileLength)
                {
                    return(0);
                }

                var chunkCompleteFile = InitializeChunk(internalFileId, totalDiskFileLength);

                int numberOfbytesReadFromClient;
                var bytesWrittenThisRequest      = 0L;
                var clientDisconnectedDuringRead = false;
                var writeBufferNextFreeIndex     = 0;

                do
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }

                    numberOfbytesReadFromClient = await stream.ReadAsync(httpReadBuffer, 0, _maxReadBufferSize, cancellationToken);

                    clientDisconnectedDuringRead = cancellationToken.IsCancellationRequested;

                    totalDiskFileLength += numberOfbytesReadFromClient;

                    if (totalDiskFileLength > fileUploadLengthProvidedDuringCreate)
                    {
                        throw new TusStoreException($"Stream contains more data than the file's upload length. Stream data: {totalDiskFileLength}, upload length: {fileUploadLengthProvidedDuringCreate}.");
                    }

                    // Can we fit the read data into the write buffer? If not flush it now.
                    if (writeBufferNextFreeIndex + numberOfbytesReadFromClient > _maxWriteBufferSize)
                    {
                        await FlushFileToDisk(internalFileId, fileWriteBuffer, diskFileStream, writeBufferNextFreeIndex);

                        writeBufferNextFreeIndex = 0;
                    }

                    Array.Copy(
                        sourceArray: httpReadBuffer,
                        sourceIndex: 0,
                        destinationArray: fileWriteBuffer,
                        destinationIndex: writeBufferNextFreeIndex,
                        length: numberOfbytesReadFromClient);

                    writeBufferNextFreeIndex += numberOfbytesReadFromClient;
                    bytesWrittenThisRequest  += numberOfbytesReadFromClient;
                } while (numberOfbytesReadFromClient != 0);

                // Flush the remaining buffer to disk.
                if (writeBufferNextFreeIndex != 0)
                {
                    await FlushFileToDisk(internalFileId, fileWriteBuffer, diskFileStream, writeBufferNextFreeIndex);
                }

                if (!clientDisconnectedDuringRead)
                {
                    MarkChunkComplete(chunkCompleteFile);
                }

                return(bytesWrittenThisRequest);
            }
            finally
            {
                _bufferPool.Return(httpReadBuffer);
                _bufferPool.Return(fileWriteBuffer);
            }
        }
コード例 #10
0
 public InternalFileRep ChunkComplete(InternalFileId fileId, IOptions <FtpServerSettings> config) => Create(fileId, "chunkcomplete", config);
コード例 #11
0
 public InternalFileRep ChunkStartPosition(InternalFileId fileId, IOptions <FtpServerSettings> config) => Create(fileId, "chunkstart", config);
コード例 #12
0
 public InternalFileRep Expiration(InternalFileId fileId, IOptions <FtpServerSettings> config) => Create(fileId, "expiration", config);
コード例 #13
0
 public InternalFileRep Metadata(InternalFileId fileId, IOptions <FtpServerSettings> config) => Create(fileId, "metadata", config);
コード例 #14
0
 public InternalFileRep UploadConcat(InternalFileId fileId, IOptions <FtpServerSettings> config) => Create(fileId, "uploadconcat", config);
コード例 #15
0
 public InternalFileRep UploadLength(InternalFileId fileId, IOptions <FtpServerSettings> config) => Create(fileId, "uploadlength", config);