public override async Task <int> ExecuteAsync(CommandContext context, T settings)
 => await _console.Progress()
 .Columns(Columns)
 .StartAsync(async ctx => await Run(ctx, settings));
Example #2
0
        public override async Task <int> ExecuteAsync(CommandContext context, BrentOptions settings)
        {
            var archives = new List <BrentArchive>()
            {
                new("https://downloads.brentozar.com/StackOverflow-SQL-Server-2010.torrent",
                    "Small: 10GB database as of 2010", "small"),
                new("https://downloads.brentozar.com/StackOverflow2013.torrent", "Medium: 50GB database as of 2013",
                    "medium"),
                new("https://downloads.brentozar.com/StackOverflowCore.torrent", "Large 150GB database as of 2019",
                    "large"),
                new("https://downloads.brentozar.com/StackOverflow-SQL-Server-202006.torrent",
                    "Extra-Large: current 381GB database as of 2020/06", "extra-large"),
            };

            var archiveName = settings.Archive;

            if (string.IsNullOrWhiteSpace(archiveName))
            {
                var choice = _console.Prompt(
                    new SelectionPrompt <BrentArchive>()
                    .PageSize(10)
                    .Title("Pick an archive to download")
                    .AddChoices(archives));
                archiveName = choice.ShortName;
            }

            var archive = archives.FirstOrDefault(a =>
                                                  a.ShortName.Equals(archiveName, StringComparison.InvariantCultureIgnoreCase));

            if (archive == null)
            {
                throw new SoddiException($"Could not find an archive matching \"{archiveName}\"");
            }

            var outputPath = settings.Output;

            if (string.IsNullOrWhiteSpace(outputPath))
            {
                outputPath = _fileSystem.Directory.GetCurrentDirectory();
            }

            if (!_fileSystem.Directory.Exists(outputPath))
            {
                throw new SoddiException($"Output path {outputPath} not found");
            }

            var downloadedFiles = await _torrentDownloader.Download(archive.Url, settings.EnablePortForwarding,
                                                                    outputPath,
                                                                    CancellationToken.None);

            var sevenZipFiles = downloadedFiles.Where(i =>
                                                      _fileSystem.Path.GetExtension(i).Equals(".7z", StringComparison.InvariantCultureIgnoreCase));

            var stopWatch = Stopwatch.StartNew();


            var progressBar = _console.Progress()
                              .AutoClear(false)
                              .Columns(new ProgressColumn[]
            {
                new SpinnerColumn {
                    CompletedText = Emoji.Known.CheckMark
                }, new TaskDescriptionColumn(),
                new ProgressBarColumn(), new PercentageColumn(), new TransferSpeedColumn(),
                new RemainingTimeColumn()
            });

            progressBar.Start(ctx =>
            {
                foreach (var sevenZipFile in sevenZipFiles)
                {
                    using var stream          = _fileSystem.File.OpenRead(sevenZipFile);
                    using var sevenZipArchive = SevenZipArchive.Open(stream);

                    var tasks = sevenZipArchive.Entries.ToImmutableDictionary(
                        e => e.Key,
                        e => ctx.AddTask(e.Key, new ProgressTaskSettings {
                        MaxValue = e.Size, AutoStart = false
                    }));

                    foreach (var entry in sevenZipArchive.Entries)
                    {
                        var currentTask = tasks[entry.Key];
                        currentTask.StartTask();
                        var totalRead = 0L;

                        void Handler(object?sender, CompressedBytesReadEventArgs args)
                        {
                            var diff = args.CurrentFilePartCompressedBytesRead - totalRead;
                            currentTask.Increment(diff);
                            totalRead = args.CurrentFilePartCompressedBytesRead;
                        }

                        sevenZipArchive.CompressedBytesRead += Handler;
                        entry.WriteToDirectory(outputPath, new ExtractionOptions {
                            Overwrite = true
                        });
                        sevenZipArchive.CompressedBytesRead -= Handler;
                    }
                }
            });

            stopWatch.Stop();
            _console.MarkupLine($"Extraction complete in [blue]{stopWatch.Elapsed.Humanize()}[/].");

            return(0);
        }
Example #3
0
        public async Task <ImmutableList <string> > Download(string url,
                                                             List <string>?potentialArchives,
                                                             bool enablePortForwarding,
                                                             string outputPath,
                                                             CancellationToken cancellationToken)
        {
            var stopWatch = Stopwatch.StartNew();

            var paddingFolder = _fileSystem.Path.Combine(outputPath, ".____padding_file");
            var doesPaddingFolderExistToStart = _fileSystem.Directory.Exists(paddingFolder);

            var progressBar = _console.Progress()
                              .AutoClear(false)
                              .Columns(new ProgressColumn[]
            {
                new SpinnerColumn {
                    CompletedText = Emoji.Known.CheckMark
                }, new DownloadedColumnExtended(),
                new TaskDescriptionColumn(), new TorrentProgressBarColumn(), new PercentageColumn(),
                new TransferSpeedColumn(), new RemainingTimeColumn()
            });

            ImmutableList <TorrentFile>?downloadedFiles = null;
            await progressBar.StartAsync(async ctx =>
            {
                _console.WriteLine("Loading torrent...");

                var httpClient      = new HttpClient();
                var torrentContents = await httpClient.GetByteArrayAsync(url, cancellationToken);
                var settings        = new EngineSettings
                {
                    AllowedEncryption = EncryptionTypes.All, SavePath = outputPath, MaximumHalfOpenConnections = 16
                };


                _console.WriteLine("Initializing BitTorrent engine...");
                var engine = new ClientEngine(settings);

                if (enablePortForwarding)
                {
                    _console.WriteLine("Attempting to forward ports");
                    await engine.EnablePortForwardingAsync(cancellationToken);
                }

                var torrent = await Torrent.LoadAsync(torrentContents);
                if (potentialArchives != null)
                {
                    foreach (var torrentFile in torrent.Files)
                    {
                        if (!potentialArchives.Contains(torrentFile.Path))
                        {
                            torrentFile.Priority = Priority.DoNotDownload;
                        }
                    }
                }

                var manager = new TorrentManager(
                    torrent,
                    outputPath,
                    new TorrentSettings {
                    MaximumConnections = 250
                }, string.Empty);

                await engine.Register(manager);
                await engine.StartAll();


                downloadedFiles = manager.Torrent.Files
                                  .Where(i => i.Priority != Priority.DoNotDownload).ToImmutableList();

                var fileTasks = downloadedFiles
                                .ToDictionary(
                    i => i.Path,
                    file => ctx.AddTask(file.Path,
                                        new ProgressTaskSettings {
                    MaxValue = file.Length, AutoStart = false
                })
                    );

                while (manager.State != TorrentState.Stopped && manager.State != TorrentState.Seeding)
                {
                    foreach (var torrentFile in downloadedFiles)
                    {
                        var progressTask = fileTasks[torrentFile.Path];
                        if (torrentFile.BytesDownloaded > 0 && progressTask.IsStarted == false)
                        {
                            progressTask.StartTask();
                        }

                        progressTask.Increment(torrentFile.BytesDownloaded - progressTask.Value);
                        progressTask.State.Update <BitSmuggler>("torrentBits",
                                                                _ => new BitSmuggler(torrentFile.BitField));
                    }

                    await Task.Delay(100, cancellationToken);
                }

                await manager.StopAsync();
                await engine.StopAllAsync();

                try
                {
                    // the stackoverflow torrent files, and I think all of archive.org
                    // seem to have these padding files that sneak into the download even
                    // if they aren't included in the file list. not quite sure how to prevent that
                    // so I'm gonna delete them after the fact I guess
                    if (!doesPaddingFolderExistToStart && _fileSystem.Directory.Exists(paddingFolder))
                    {
                        _fileSystem.Directory.Delete(paddingFolder, true);
                    }
                }
                catch
                {
                    /* swallow */
                }

                foreach (var progressTask in fileTasks)
                {
                    progressTask.Value.StopTask();
                }
            });


            stopWatch.Stop();
            _console.MarkupLine($"Download complete in [blue]{stopWatch.Elapsed.Humanize()}[/].");

            return(downloadedFiles?.Select(i => _fileSystem.Path.Combine(outputPath, i.Path)).ToImmutableList() ??
                   ImmutableList <string> .Empty);
        }
        public override async Task <int> ExecuteAsync(CommandContext context, ImportOptions request)
        {
            var cancellationToken = CancellationToken.None;

            var requestPath = await CheckAndFixupPath(request.Path, cancellationToken);

            var dbName = _databaseHelper.GetDbNameFromPathOption(request.DatabaseName, requestPath);
            var tasks  = new Queue <(string name, ITask task)>();

            var(masterConnectionString, databaseConnectionString) =
                _databaseHelper.GetMasterAndDbConnectionStrings(request.ConnectionString, dbName);

            ImmutableDictionary <string, long>?insertReport = null;

            var processor = _processorFactory.VerifyAndCreateProcessor(requestPath);

            if (request.DropAndRecreate)
            {
                tasks.Enqueue(("Create new database", new CreateDatabase(masterConnectionString, dbName)));
            }
            else
            {
                tasks.Enqueue(("Verify database exists", new VerifyDatabaseExists(masterConnectionString, dbName)));
            }

            tasks.Enqueue(("Create schema", new CreateSchema(databaseConnectionString, !request.SkipTags)));
            if (!request.SkipPrimaryKeys)
            {
                tasks.Enqueue(("Add constraints", new AddConstraints(databaseConnectionString)));
            }

            tasks.Enqueue(("Insert type values", new InsertTypeValues(databaseConnectionString)));
            tasks.Enqueue(("Insert data from archive",
                           new InsertData(
                               databaseConnectionString,
                               dbName,
                               processor,
                               !request.SkipTags,
                               d => insertReport = d,
                               request.BlockSize)));

            var progressBar = _console.Progress()
                              .AutoClear(false)
                              .Columns(new ProgressColumn[]
            {
                new SpinnerColumn {
                    CompletedText = Emoji.Known.CheckMark
                }, new FixedTaskDescriptionColumn(40),
                new ProgressBarColumn(), new PercentageColumn(), new RemainingTimeColumn(),
            });


            var stopWatch = Stopwatch.StartNew();

            progressBar.Start(ctx =>
            {
                foreach (var(description, task) in tasks)
                {
                    var progressTasks = new ConcurrentDictionary <string, ProgressTask>();
                    var progress      = new Progress <(string taskId, string message, double weight, double maxValue)>(i =>
                    {
                        var(taskId, message, weight, maxValue) = i;
                        var progressBarTask = progressTasks.GetOrAdd(taskId, _ => ctx.AddTask(description));

                        progressBarTask.MaxValue(maxValue);
                        progressBarTask.Increment(weight);
                        progressBarTask.Description(message);
                    });

                    task.Go(progress);

                    foreach (var progressTask in progressTasks.Values)
                    {
                        progressTask.Increment(progressTask.MaxValue - progressTask.Value);
                    }
                }
            });

            stopWatch.Stop();

            if (insertReport != null)
            {
                var counter = 1;
                var chart   = new BreakdownChart()
                              .Compact()
                              .Width(60)
                              .UseValueFormatter(d => d.ToMetric())
                              .FullSize()
                              .AddItems(insertReport,
                                        pair => new BreakdownChartItem(pair.Key, pair.Value, counter++)
                                        );

                _console.MarkupLine("[blue]Rows inserted[/]");
                _console.Render(chart);
            }

            _console.WriteLine();
            _console.MarkupLine($"Import complete in [blue]{stopWatch.Elapsed.Humanize()}[/].");

            return(0);
        }
Example #5
0
        public override async Task <int> ExecuteAsync(CommandContext context, DownloadOptions request)
        {
            var cancellationToken = CancellationToken.None;

            var outputPath = request.Output;

            if (string.IsNullOrWhiteSpace(outputPath))
            {
                outputPath = _fileSystem.Directory.GetCurrentDirectory();
            }

            if (!_fileSystem.Directory.Exists(outputPath))
            {
                throw new SoddiException($"Output path {outputPath} not found");
            }

            var archiveUrl =
                await _availableArchiveParser.FindOrPickArchive(request.Archive, request.Pick, cancellationToken);

            var stopWatch = Stopwatch.StartNew();

            await _console.Progress()
            .AutoClear(false)
            .Columns(new ProgressColumn[]
            {
                new SpinnerColumn {
                    CompletedText = Emoji.Known.CheckMark
                }, new DownloadedColumn(),
                new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn(),
                new TransferSpeedColumn(), new RemainingTimeColumn(),
            }).StartAsync(async ctx =>
            {
                var tasks = new List <(ProgressTask Task, Archive.UriWithSize UriWithSize)>();
                foreach (var archive in archiveUrl)
                {
                    tasks.AddRange(archive.Uris
                                   .Select(uriWithSize => (ctx.AddTask(uriWithSize.Description(false)), uriWithSize))
                                   .ToList());
                }

                while (!ctx.IsFinished)
                {
                    foreach (var(task, uriWithSize) in tasks)
                    {
                        var progress = new Progress <(int downloadedInBytes, int totalSizeInBytes)>(i =>
                        {
                            var progressTask = task;
                            var(downloadedInBytes, totalSizeInBytes) = i;

                            progressTask.Increment(downloadedInBytes);
                            progressTask.MaxValue(totalSizeInBytes);
                        }
                                                                                                    );

                        var downloader = new ArchiveDownloader(outputPath, progress);
                        await downloader.Go(uriWithSize.Uri, cancellationToken);
                    }
                }
            });

            stopWatch.Stop();
            _console.MarkupLine($"Download complete in [blue]{stopWatch.Elapsed.Humanize()}[/].");

            return(await Task.FromResult(0));
        }