コード例 #1
0
        public async Task CreateFileAsync_Throws_An_Exception_If_The_File_Id_Already_Exist()
        {
            var expectedFileId = Guid.NewGuid().ToString();

            var nonUniqueFileIdProvider = Substitute.For <ITusFileIdProvider>();

            nonUniqueFileIdProvider.CreateId(null).ReturnsForAnyArgs(expectedFileId);
            nonUniqueFileIdProvider.ValidateId(null).ReturnsForAnyArgs(true);

            var store = new TusDiskStore(_fixture.Path, false, TusDiskBufferSize.Default, nonUniqueFileIdProvider);

            var fileId = await store.CreateFileAsync(1, null, CancellationToken.None);

            fileId.ShouldBe(expectedFileId);

            await store.AppendDataAsync(fileId, new MemoryStream(new[] { (byte)1 }), CancellationToken.None);

            var filePath = Path.Combine(_fixture.Path, fileId);

            File.Exists(filePath).ShouldBeTrue();
            new FileInfo(filePath).Length.ShouldBe(1);

            await Assert.ThrowsAnyAsync <Exception>(async() => await store.CreateFileAsync(1, null, CancellationToken.None));

            File.Exists(filePath).ShouldBeTrue();
            new FileInfo(filePath).Length.ShouldBe(1);
        }
コード例 #2
0
        public async Task AppendDataAsync_Uses_The_Read_And_Write_Buffers_Correctly(int readBufferSize, int writeBufferSize, int fileSize, int expectedNumberOfWrites, int expectedNumberOfReads)
        {
            int readsPerWrite = (int)Math.Ceiling((double)writeBufferSize / readBufferSize);

            var store = new TusDiskStore(_fixture.Path, false, new TusDiskBufferSize(writeBufferSize, readBufferSize));

            var totalNumberOfWrites         = 0;
            var totalNumberOfReads          = 0;
            var numberOfReadsSinceLastWrite = 0;
            var firstWrite   = true;
            int bytesWritten = 0;

            var fileId = await store.CreateFileAsync(fileSize, null, CancellationToken.None);

            var requestStream = new RequestStreamFake(async(RequestStreamFake stream,
                                                            byte[] bufferToFill,
                                                            int offset,
                                                            int count,
                                                            CancellationToken cancellationToken)
                                                      =>
            {
                count.ShouldBe(readBufferSize);
                numberOfReadsSinceLastWrite++;

                var bytesRead = await stream.ReadBackingStreamAsync(bufferToFill, offset, count, cancellationToken);

                // Need to subtract from readsPerWrite due to this expression being checked _after_ the write has happened.
                var previousReadShouldHaveTriggeredWrite = numberOfReadsSinceLastWrite == readsPerWrite - (firstWrite ? 0 : 1) + 1;

                if (bytesRead != 0 && previousReadShouldHaveTriggeredWrite)
                {
                    numberOfReadsSinceLastWrite = 0;
                    firstWrite = false;

                    GetLengthFromFileOnDisk().ShouldBe(bytesWritten);
                    totalNumberOfWrites++;
                }

                totalNumberOfReads++;

                bytesWritten += bytesRead;

                return(bytesRead);
            }, new byte[fileSize]);

            await store.AppendDataAsync(fileId, requestStream, CancellationToken.None);

            GetLengthFromFileOnDisk().ShouldBe(fileSize);

            totalNumberOfWrites++;

            // -1 due to the last read returning 0 bytes as the stream is then drained
            Assert.Equal(expectedNumberOfReads, totalNumberOfReads - 1);
            Assert.Equal(expectedNumberOfWrites, totalNumberOfWrites);

            long GetLengthFromFileOnDisk()
            {
                return(new FileInfo(Path.Combine(_fixture.Path, fileId)).Length);
            }
        }
コード例 #3
0
        public TusDiskStoreFixture()
        {
            Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName().Replace(".", ""));
            ClearPath();

            Store = new TusDiskStore(Path);
        }
コード例 #4
0
        public async Task CreateFinalFileAsync_Deletes_Partial_Files_If_Configuration_Says_So()
        {
            // Use default constructor (implying cleanup = false)
            var store = new TusDiskStore(_fixture.Path);

            var p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            var p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None);

            await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None);

            _ = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None);

            (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue();
            (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue();

            // Cleanup = true
            store = new TusDiskStore(_fixture.Path, true);

            p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None);

            await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None);

            _ = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None);

            (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeFalse();
            (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeFalse();

            // Assert that all files are gone (regression on bug)
            var p1Files = Directory.EnumerateFiles(_fixture.Path, p1 + "*");

            p1Files.Any().ShouldBeFalse("Meta files for partial file 1 has not been deleted");

            var p2Files = Directory.EnumerateFiles(_fixture.Path, p2 + "*");

            p2Files.Any().ShouldBeFalse("Meta files for partial file 1 has not been deleted");

            // Cleanup = false
            store = new TusDiskStore(_fixture.Path, false);

            p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None);

            await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None);

            _ = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None);

            (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue();
            (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue();
        }
コード例 #5
0
        public async Task CreateFinalFileAsync_Deletes_Partial_Files_If_Configuration_Says_So()
        {
            // Use default constructor.
            var store = new TusDiskStore(_fixture.Path);

            var p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            var p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None);

            await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None);

            var f = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None);

            f.ShouldNotBeNullOrWhiteSpace();
            (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue();
            (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue();

            // Cleanup = true
            store = new TusDiskStore(_fixture.Path, true);

            p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            p1.ShouldNotBeNullOrWhiteSpace();
            p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            p2.ShouldNotBeNullOrWhiteSpace();

            await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None);

            await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None);

            f = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None);

            f.ShouldNotBeNullOrWhiteSpace();
            (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeFalse();
            (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeFalse();

            // Cleanup = false
            store = new TusDiskStore(_fixture.Path, false);

            p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None);

            await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None);

            await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None);

            f = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None);

            f.ShouldNotBeNullOrWhiteSpace();
            (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue();
            (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue();
        }
コード例 #6
0
        public async Task CreateFileAsync_Uses_The_Provided_TusFileIdProvider_To_Create_Ids()
        {
            var customProvider = Substitute.For <ITusFileIdProvider>();

            var customFileId  = 0;
            var createIdCalls = 0;

            customProvider.CreateId(null).ReturnsForAnyArgs(_ => (++customFileId).ToString()).AndDoes(_ => createIdCalls++);
            customProvider.ValidateId(null).ReturnsForAnyArgs(true);

            var store = new TusDiskStore(_fixture.Path, true, TusDiskBufferSize.Default, customProvider);

            for (var i = 0; i < 10; i++)
            {
                var fileId = await store.CreateFileAsync(i, null, CancellationToken.None);

                fileId.ShouldBe(customFileId.ToString());
                var filePath = Path.Combine(_fixture.Path, fileId);
                File.Exists(filePath).ShouldBeTrue();
                createIdCalls.ShouldBe(i + 1);
            }
        }
コード例 #7
0
 public void CreateNewStore()
 {
     Store = new TusDiskStore(Path);
 }
コード例 #8
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            //app.UseCors(options => options.WithOrigins("https://*****:*****@"C:\Users\chunc\Documents\RuneLaboratory\Freelance\FileUploadService\StoredFiles\"),
                // On what url should we listen for uploads?
                UrlPath = "/tusUpload",
                Events  = new Events
                {
                    OnAuthorizeAsync = eventContext =>
                    {
                        // if (!eventContext.HttpContext.User.Identity.IsAuthenticated)
                        // {
                        //     System.Console.WriteLine("DEBUG XXX 2");
                        //     eventContext.FailRequest(HttpStatusCode.Unauthorized);
                        //     return Task.CompletedTask;
                        // }

                        // Do other verification on the user; claims, roles, etc. In this case, check the username.
                        // if (eventContext.HttpContext.User.Identity.Name != "test")
                        // {
                        //     System.Console.WriteLine("DEBUG XXX 3 Identity name = " + eventContext.HttpContext.User.Identity.Name);
                        //     eventContext.FailRequest(HttpStatusCode.Forbidden, "'test' is the only allowed user");
                        //     return Task.CompletedTask;
                        // }

                        // Verify different things depending on the intent of the request.
                        // E.g.:
                        //   Does the file about to be written belong to this user?
                        //   Is the current user allowed to create new files or have they reached their quota?
                        //   etc etc
                        switch (eventContext.Intent)
                        {
                        case IntentType.CreateFile:
                            System.Console.WriteLine("This is Create File API");
                            break;

                        case IntentType.ConcatenateFiles:
                            System.Console.WriteLine("This is Concatenate Files API");
                            break;

                        case IntentType.WriteFile:
                            System.Console.WriteLine("This is Write Files API");
                            break;

                        case IntentType.DeleteFile:
                            System.Console.WriteLine("This is Delete File API");
                            break;

                        case IntentType.GetFileInfo:
                            System.Console.WriteLine("This is Get File Info API");
                            break;

                        case IntentType.GetOptions:
                            System.Console.WriteLine("This is Get Options Files API");
                            break;

                        default:
                            break;
                        }

                        return(Task.CompletedTask);
                    },
                    OnFileCompleteAsync = async eventContext =>
                    {
                        // eventContext.FileId is the id of the file that was uploaded.
                        // eventContext.Store is the data store that was used (in this case an instance of the TusDiskStore)

                        // A normal use case here would be to read the file and do some processing on it.
                        ITusFile file = await eventContext.GetFileAsync();
                        var result    = await DoSomeProcessing(file, eventContext.CancellationToken);
                        System.Console.WriteLine("Tus File upload complete YEah l " + file.Id);

                        async Task <string> DoSomeProcessing(ITusFile file, CancellationToken eventContext)
                        {
                            System.Console.WriteLine();
                            System.Console.WriteLine("Tus File upload complete YEah :" + file.Id);
                            return("success");
                        }

                        if (result != "success")
                        {
                            //throw new MyProcessingException("Something went wrong during processing");
                        }
                    }
                }
            });
コード例 #9
0
        public async Task AppendDataAsync_Uses_The_Read_And_Write_Buffers_Correctly(int readBufferSize, int writeBufferSize, int fileSize, int expectedNumberOfWrites, int expectedNumberOfReads)
        {
            int numberOfReadsPerWrite = (int)Math.Ceiling((double)writeBufferSize / readBufferSize);

            var store = new TusDiskStore(_fixture.Path, false, new TusDiskBufferSize(writeBufferSize, readBufferSize));

            var totalNumberOfWrites         = 0;
            var totalNumberOfReads          = 0;
            var numberOfReadsSinceLastWrite = 0;
            int totalBytesWritten           = 0;

            var fileId = await store.CreateFileAsync(fileSize, null, CancellationToken.None);

            var requestStream = new RequestStreamFake(async(RequestStreamFake stream,
                                                            byte[] bufferToFill,
                                                            int offset,
                                                            int count,
                                                            CancellationToken cancellationToken)
                                                      =>
            {
                count.ShouldBe(readBufferSize);

                var bytesReadFromStream = await stream.ReadBackingStreamAsync(bufferToFill, offset, count, cancellationToken);

                // There should have been a write after the previous read.
                if (numberOfReadsSinceLastWrite > numberOfReadsPerWrite)
                {
                    // Calculate the amount of data that should have been written to disk so far.
                    var expectedFileSizeRightNow = CalculateExpectedFileSize(totalNumberOfReads, readBufferSize, writeBufferSize);

                    // Assert that the size on disk is correct.
                    GetLengthFromFileOnDisk().ShouldBe(expectedFileSizeRightNow);

                    totalNumberOfWrites++;

                    // Set to one as the write happened on the previous write, making this the second read since that write.
                    numberOfReadsSinceLastWrite = 1;
                }

                numberOfReadsSinceLastWrite++;
                totalNumberOfReads++;

                totalBytesWritten += bytesReadFromStream;

                return(bytesReadFromStream);
            }, new byte[fileSize]);

            await store.AppendDataAsync(fileId, requestStream, CancellationToken.None);

            GetLengthFromFileOnDisk().ShouldBe(fileSize);

            totalNumberOfWrites++;

            // -1 due to the last read returning 0 bytes as the stream is then drained
            Assert.Equal(expectedNumberOfReads, totalNumberOfReads - 1);
            Assert.Equal(expectedNumberOfWrites, totalNumberOfWrites);

            long GetLengthFromFileOnDisk()
            {
                return(new FileInfo(Path.Combine(_fixture.Path, fileId)).Length);
            }
        }