예제 #1
0
        /// <summary>
        /// Handles post configuration setup
        /// </summary>
        public override void AfterConfigure()
        {
            base.AfterConfigure();
            if (!Directory.Exists(SourceFolder))
            {
                Directory.CreateDirectory(SourceFolder);
            }

            m_filecache = new LRUCache <DateTime>(
                sizelimit: MaxMirrorCacheSize,
                countlimit: MaxMirrorCacheCount,
                expirationHandler: TryDeleteAsync,
                sizeHandler: TryFileSizeAsync
                );

            foreach (var f in Directory.EnumerateFiles(SourceFolder, "*", SearchOption.AllDirectories))
            {
                m_filecache.AddOrReplaceAsync(f, DateTime.Now + StartupMirrorCacheAgeSeconds).Wait();
            }

            m_404cache = new LRUCache <DateTime>(countlimit: Max404CacheCount);
        }
예제 #2
0
        /// <summary>
        /// Downloads the file from the remote URL, signalling the progress task along the way
        /// </summary>
        /// <returns>An awaitable task.</returns>
        /// <param name="context">The request context.</param>
        /// <param name="localpath">The path to store the file at.</param>
        private async Task DownloadRemoteFileAsync(IHttpContext context, string localpath, TaskCompletionSource <long> signal)
        {
            try
            {
                using (var resp = await GetRemoteStream(context))
                {
                    lock (m_statuslock)
                    {
                        // Signal all others that we now know the full source length
                        m_activeTransferSizes[localpath] = resp.Size;

                        // And ensure the target folder exists
                        if (!Directory.Exists(Path.GetDirectoryName(localpath)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(localpath));
                        }
                    }

                    var pg = 0L;
                    using (var remote = resp.Stream)
                        using (var local = new FileStream(localpath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                        {
                            // Note: Since we write to the actual file,
                            // we may interfere with active downloads of
                            // the file...

                            int r;
                            var buffer = new byte[8 * 1024];

                            // Read some data
                            while ((r = await remote.ReadAsync(buffer, 0, buffer.Length)) > 0)
                            {
                                // Write it to the local file
                                await local.WriteAsync(buffer, 0, r);

                                await local.FlushAsync();

                                pg += r;

                                // Swap around and notify of the progress
                                var oldsignal = signal;
                                lock (m_statuslock)
                                    m_activeTransfers[localpath] = (signal = new TaskCompletionSource <long>()).Task;
                                oldsignal.TrySetResult(pg);
                            }
                        }

                    // Update the file timestamp if possible
                    if (resp.LastModified.Ticks != 0)
                    {
                        try { File.SetLastWriteTime(localpath, resp.LastModified); }
                        catch { }
                    }

                    // Register that the file is now available as a normal file
                    await m_filecache.AddOrReplaceAsync(localpath, DateTime.Now);

                    // Now the cache returns the results, so we can unregister our callback
                    lock (m_statuslock)
                    {
                        m_activeTransferSizes.Remove(localpath);
                        m_activeTransfers.Remove(localpath);
                    }

                    // Prevent hanging followers
                    signal.TrySetResult(pg);
                }
            }
            catch (Exception ex)
            {
                if (ex is HttpException he && he.StatusCode == HttpStatusCode.NotFound)
                {
                    await m_404cache.AddOrReplaceAsync(localpath, DateTime.Now);
                }

                lock (m_statuslock)
                {
                    m_activeTransferSizes.Remove(localpath);
                    m_activeTransfers.Remove(localpath);
                }

                signal.TrySetException(ex);
            }
        }