コード例 #1
0
        /// <inheritdoc />
        public async Task <long> AppendDataAsync(string fileId, Stream stream, CancellationToken cancellationToken)
        {
            var  internalFileId = new InternalFileId(fileId);
            long bytesWritten   = 0;
            var  uploadLength   = await GetUploadLengthAsync(fileId, cancellationToken);

            using (var file = _fileRepFactory.Data(internalFileId).GetStream(FileMode.Append, FileAccess.Write, FileShare.None))
            {
                var fileLength = file.Length;
                if (uploadLength == fileLength)
                {
                    return(0);
                }

                var chunkStart    = _fileRepFactory.ChunkStartPosition(internalFileId);
                var chunkComplete = _fileRepFactory.ChunkComplete(internalFileId);

                if (chunkComplete.Exist())
                {
                    chunkStart.Delete();
                    chunkComplete.Delete();
                }

                if (!chunkStart.Exist())
                {
                    chunkStart.Write(fileLength.ToString());
                }

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

                    var buffer = new byte[ByteChunkSize];
                    bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);

                    fileLength += bytesRead;

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

                    await file.WriteAsync(buffer, 0, bytesRead);

                    bytesWritten += bytesRead;
                } while (bytesRead != 0);

                // Chunk is complete. Mark it as complete.
                chunkComplete.Write("1");

                return(bytesWritten);
            }
        }
コード例 #2
0
            private InternalFileRep Create(InternalFileId fileId, string extension)
            {
                var fileName = fileId.FileId;

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

                return(new InternalFileRep(fileId.FileId, System.IO.Path.Combine(_directoryPath, fileName)));
            }
コード例 #3
0
        /// <inheritdoc />
        public async Task <string> CreateFileAsync(long uploadLength, string metadata, CancellationToken cancellationToken)
        {
            var fileId = new InternalFileId();

            File.Create(_fileRepFactory.Data(fileId).Path).Dispose();
            if (uploadLength != -1)
            {
                await SetUploadLengthAsync(fileId.FileId, uploadLength, cancellationToken);
            }
            _fileRepFactory.Metadata(fileId).Write(metadata);
            return(fileId.FileId);
        }
コード例 #4
0
        /// <inheritdoc />
        public Task DeleteFileAsync(string fileId, CancellationToken cancellationToken)
        {
            var internalFileId = new InternalFileId(fileId);

            return(Task.Run(() =>
            {
                _fileRepFactory.Data(internalFileId).Delete();
                _fileRepFactory.UploadLength(internalFileId).Delete();
                _fileRepFactory.Metadata(internalFileId).Delete();
                _fileRepFactory.UploadConcat(internalFileId).Delete();
                _fileRepFactory.Expiration(internalFileId).Delete();
                _fileRepFactory.ChunkStartPosition(internalFileId).Delete();
                _fileRepFactory.ChunkComplete(internalFileId).Delete();
            }, cancellationToken));
        }
コード例 #5
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));

                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).Write(new FileConcatFinal(partialFiles).GetHeader());

            using (var finalFile = _fileRepFactory.Data(internalFileId).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, ByteChunkSize);
                    }
                }
            }

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

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

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

                var calculateSha1 = dataStream.CalculateSha1(chunkStartPosition);
                valid = checksum.SequenceEqual(calculateSha1);

                if (!valid)
                {
                    dataStream.Seek(0, SeekOrigin.Begin);
                    dataStream.SetLength(chunkStartPosition);
                    chunkPositionFile.Delete();
                    _fileRepFactory.ChunkComplete(internalFileId).Delete();
                }
            }

            return(Task.FromResult(valid));
        }
コード例 #7
0
 public InternalFileRep ChunkStartPosition(InternalFileId fileId) => Create(fileId, "chunkstart");
コード例 #8
0
 public InternalFileRep ChunkComplete(InternalFileId fileId) => Create(fileId, "chunkcomplete");
コード例 #9
0
 public InternalFileRep Expiration(InternalFileId fileId) => Create(fileId, "expiration");
コード例 #10
0
 public InternalFileRep Metadata(InternalFileId fileId) => Create(fileId, "metadata");
コード例 #11
0
 public InternalFileRep UploadConcat(InternalFileId fileId) => Create(fileId, "uploadconcat");
コード例 #12
0
 public InternalFileRep UploadLength(InternalFileId fileId) => Create(fileId, "uploadlength");
コード例 #13
0
 public InternalFileRep Data(InternalFileId fileId) => Create(fileId, "");