public static async Task <int> GetDataLimit(string group, CancellationToken cancellationToken = default)
        {
            var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken);

            if (loadNodesErrMsg is not null)
            {
                Console.WriteLine(loadNodesErrMsg);
                return(1);
            }
            using var nodes = loadedNodes;

            if (nodes.Groups.TryGetValue(group, out var targetGroup))
            {
                Console.WriteLine($"{"Group",-24}{group,-32}");
                if (targetGroup.DataLimitInBytes != 0UL)
                {
                    Console.WriteLine($"{"Global data limit",-24}{InteractionHelper.HumanReadableDataString1024(targetGroup.DataLimitInBytes),-32}");
                }
                if (targetGroup.PerUserDataLimitInBytes != 0UL)
                {
                    Console.WriteLine($"{"Per-user data limit",-24}{InteractionHelper.HumanReadableDataString1024(targetGroup.PerUserDataLimitInBytes),-32}");
                }

                var outlineAccessKeyCustomLimits = targetGroup.OutlineAccessKeys?.Where(x => x.DataLimit is not null).Select(x => (x.Name, x.DataLimit !.Bytes));

                if (outlineAccessKeyCustomLimits is null || !outlineAccessKeyCustomLimits.Any())
                {
                    return(0);
                }

                var maxNameLength = outlineAccessKeyCustomLimits.Select(x => x.Name.Length)
                                    .DefaultIfEmpty()
                                    .Max();
                var nameFieldWidth = maxNameLength > 4 ? maxNameLength + 2 : 6;

                ConsoleHelper.PrintTableBorder(nameFieldWidth, 19);
                Console.WriteLine($"|{"User".PadRight(nameFieldWidth)}|{"Custom Data Limit",19}|");
                ConsoleHelper.PrintTableBorder(nameFieldWidth, 19);

                foreach ((var username, var dataLimitInBytes) in outlineAccessKeyCustomLimits)
                {
                    Console.WriteLine($"|{username.PadRight(nameFieldWidth)}|{InteractionHelper.HumanReadableDataString1024(dataLimitInBytes),19}|");
                }

                ConsoleHelper.PrintTableBorder(nameFieldWidth, 19);

                return(0);
            }
            else
            {
                Console.WriteLine($"Error: group {group} doesn't exist.");
                return(-2);
            }
        }
        public static async Task <int> GetDataLimit(string username, CancellationToken cancellationToken = default)
        {
            var(users, loadUsersErrMsg) = await Users.LoadUsersAsync(cancellationToken);

            if (loadUsersErrMsg is not null)
            {
                Console.WriteLine(loadUsersErrMsg);
                return(1);
            }

            if (users.UserDict.TryGetValue(username, out var user))
            {
                Console.WriteLine($"{"User",-24}{username,-32}");
                if (user.DataLimitInBytes != 0UL)
                {
                    Console.WriteLine($"{"Global data limit",-24}{InteractionHelper.HumanReadableDataString1024(user.DataLimitInBytes),-32}");
                }
                if (user.PerGroupDataLimitInBytes != 0UL)
                {
                    Console.WriteLine($"{"Per-group data limit",-24}{InteractionHelper.HumanReadableDataString1024(user.PerGroupDataLimitInBytes),-32}");
                }

                var customLimits = user.Memberships.Where(x => x.Value.DataLimitInBytes > 0UL).Select(x => (x.Key, x.Value.DataLimitInBytes));

                if (!customLimits.Any())
                {
                    return(0);
                }

                var maxNameLength = customLimits.Select(x => x.Key.Length)
                                    .DefaultIfEmpty()
                                    .Max();
                var nameFieldWidth = maxNameLength > 5 ? maxNameLength + 2 : 7;

                ConsoleHelper.PrintTableBorder(nameFieldWidth, 19);
                Console.WriteLine($"|{"Group".PadRight(nameFieldWidth)}|{"Custom Data Limit",19}|");
                ConsoleHelper.PrintTableBorder(nameFieldWidth, 19);

                foreach ((var group, var dataLimitInBytes) in customLimits)
                {
                    Console.WriteLine($"|{group.PadRight(nameFieldWidth)}|{InteractionHelper.HumanReadableDataString1024(dataLimitInBytes),19}|");
                }

                ConsoleHelper.PrintTableBorder(nameFieldWidth, 19);

                return(0);
            }
            else
            {
                Console.WriteLine($"Error: user {username} doesn't exist.");
                return(-2);
            }
        }
        public static async Task <int> GetDataUsage(string group, SortBy?sortBy, CancellationToken cancellationToken = default)
        {
            var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken);

            if (loadNodesErrMsg is not null)
            {
                Console.WriteLine(loadNodesErrMsg);
                return(1);
            }
            using var nodes = loadedNodes;

            var(settings, loadSettingsErrMsg) = await Settings.LoadSettingsAsync(cancellationToken);

            if (loadSettingsErrMsg is not null)
            {
                Console.WriteLine(loadSettingsErrMsg);
                return(1);
            }

            var records = nodes.GetGroupDataUsage(group);

            if (records is null)
            {
                Console.WriteLine($"Error: group {group} doesn't exist.");
                return(-2);
            }

            var maxNameLength = records.Select(x => x.username.Length)
                                .DefaultIfEmpty()
                                .Max();
            var nameFieldWidth = maxNameLength > 4 ? maxNameLength + 2 : 6;

            var sortByInEffect = settings.GroupDataUsageDefaultSortBy;

            if (sortBy is SortBy currentRunSortBy)
            {
                sortByInEffect = currentRunSortBy;
            }
            switch (sortByInEffect)
            {
            case SortBy.DefaultAscending:
                break;

            case SortBy.DefaultDescending:
                records.Reverse();
                break;

            case SortBy.NameAscending:
                records = records.OrderBy(x => x.username).ToList();
                break;

            case SortBy.NameDescending:
                records = records.OrderByDescending(x => x.username).ToList();
                break;

            case SortBy.DataUsedAscending:
                records = records.OrderBy(x => x.bytesUsed).ToList();
                break;

            case SortBy.DataUsedDescending:
                records = records.OrderByDescending(x => x.bytesUsed).ToList();
                break;

            case SortBy.DataRemainingAscending:
                records = records.OrderBy(x => x.bytesRemaining).ToList();
                break;

            case SortBy.DataRemainingDescending:
                records = records.OrderByDescending(x => x.bytesRemaining).ToList();
                break;
            }

            Console.WriteLine($"{"Group",-16}{group,-32}");

            if (nodes.Groups.TryGetValue(group, out var targetGroup))
            {
                Console.WriteLine($"{"Data used",-16}{InteractionHelper.HumanReadableDataString1024(targetGroup.BytesUsed),-32}");
                if (targetGroup.BytesRemaining != 0UL)
                {
                    Console.WriteLine($"{"Data remaining",-16}{InteractionHelper.HumanReadableDataString1024(targetGroup.BytesRemaining),-32}");
                }
                if (targetGroup.DataLimitInBytes != 0UL)
                {
                    Console.WriteLine($"{"Data limit",-16}{InteractionHelper.HumanReadableDataString1024(targetGroup.DataLimitInBytes),-32}");
                }
            }

            if (records.All(x => x.bytesRemaining == 0UL)) // Omit data remaining column if no data.
            {
                ConsoleHelper.PrintTableBorder(nameFieldWidth, 11);
                Console.WriteLine($"|{"User".PadRight(nameFieldWidth)}|{"Data Used",11}|");
                ConsoleHelper.PrintTableBorder(nameFieldWidth, 11);

                foreach (var(username, bytesUsed, _) in records)
                {
                    Console.WriteLine($"|{username.PadRight(nameFieldWidth)}|{InteractionHelper.HumanReadableDataString1024(bytesUsed),11}|");
                }

                ConsoleHelper.PrintTableBorder(nameFieldWidth, 11);
            }
            else
            {
                ConsoleHelper.PrintTableBorder(nameFieldWidth, 11, 16);
                Console.WriteLine($"|{"User".PadRight(nameFieldWidth)}|{"Data Used",11}|{"Data Remaining",16}|");
                ConsoleHelper.PrintTableBorder(nameFieldWidth, 11, 16);

                foreach (var(username, bytesUsed, bytesRemaining) in records)
                {
                    Console.Write($"|{username.PadRight(nameFieldWidth)}|{InteractionHelper.HumanReadableDataString1024(bytesUsed),11}|");

                    if (bytesRemaining != 0UL)
                    {
                        Console.WriteLine($"{InteractionHelper.HumanReadableDataString1024(bytesRemaining),16}|");
                    }
                    else
                    {
                        Console.WriteLine($"{string.Empty,16}|");
                    }
                }

                ConsoleHelper.PrintTableBorder(nameFieldWidth, 11, 16);
            }

            return(0);
        }
示例#4
0
        public static async Task <int> Generate(SortBy?groupSortBy, SortBy?userSortBy, string?csvOutdir, CancellationToken cancellationToken = default)
        {
            var(users, loadUsersErrMsg) = await Users.LoadUsersAsync(cancellationToken);

            if (loadUsersErrMsg is not null)
            {
                Console.WriteLine(loadUsersErrMsg);
                return(1);
            }

            var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken);

            if (loadNodesErrMsg is not null)
            {
                Console.WriteLine(loadNodesErrMsg);
                return(1);
            }
            using var nodes = loadedNodes;

            var(settings, loadSettingsErrMsg) = await Settings.LoadSettingsAsync(cancellationToken);

            if (loadSettingsErrMsg is not null)
            {
                Console.WriteLine(loadSettingsErrMsg);
                return(1);
            }

            // collect data
            var totalBytesUsed      = nodes.Groups.Select(x => x.Value.BytesUsed).Aggregate(0UL, (x, y) => x + y);
            var totalBytesRemaining = nodes.Groups.All(x => x.Value.DataLimitInBytes > 0UL)
                ? nodes.Groups.Select(x => x.Value.BytesRemaining).Aggregate(0UL, (x, y) => x + y)
                : 0UL;

            var recordsByGroup = nodes.GetDataUsageByGroup();
            var recordsByUser  = users.GetDataUsageByUser();

            // calculate column width
            var maxGroupNameLength = recordsByGroup.Select(x => x.group.Length)
                                     .DefaultIfEmpty()
                                     .Max();
            var groupNameFieldWidth = maxGroupNameLength > 5 ? maxGroupNameLength + 2 : 7;
            var maxUsernameLength   = recordsByUser.Select(x => x.username.Length)
                                      .DefaultIfEmpty()
                                      .Max();
            var usernameFieldWidth = maxUsernameLength > 4 ? maxUsernameLength + 2 : 6;

            // sort
            var groupSortByInEffect = groupSortBy ?? settings.GroupDataUsageDefaultSortBy;

            recordsByGroup = groupSortByInEffect switch
            {
                SortBy.DefaultAscending => recordsByGroup,
                SortBy.DefaultDescending => recordsByGroup.Reverse(),
                SortBy.NameAscending => recordsByGroup.OrderBy(x => x.group),
                SortBy.NameDescending => recordsByGroup.OrderByDescending(x => x.group),
                SortBy.DataUsedAscending => recordsByGroup.OrderBy(x => x.bytesUsed),
                SortBy.DataUsedDescending => recordsByGroup.OrderByDescending(x => x.bytesUsed),
                SortBy.DataRemainingAscending => recordsByGroup.OrderBy(x => x.bytesRemaining),
                SortBy.DataRemainingDescending => recordsByGroup.OrderByDescending(x => x.bytesRemaining),
                _ => throw new NotImplementedException("This sort method is not implemented!"),
            };

            var userSortByInEffect = userSortBy ?? settings.UserDataUsageDefaultSortBy;

            recordsByUser = userSortByInEffect switch
            {
                SortBy.DefaultAscending => recordsByUser,
                SortBy.DefaultDescending => recordsByUser.Reverse(),
                SortBy.NameAscending => recordsByUser.OrderBy(x => x.username),
                SortBy.NameDescending => recordsByUser.OrderByDescending(x => x.username),
                SortBy.DataUsedAscending => recordsByUser.OrderBy(x => x.bytesUsed),
                SortBy.DataUsedDescending => recordsByUser.OrderByDescending(x => x.bytesUsed),
                SortBy.DataRemainingAscending => recordsByUser.OrderBy(x => x.bytesRemaining),
                SortBy.DataRemainingDescending => recordsByUser.OrderByDescending(x => x.bytesRemaining),
                _ => throw new NotImplementedException("This sort method is not implemented!"),
            };

            // total
            Console.WriteLine("In the last 30 days:");
            Console.WriteLine();

            if (totalBytesUsed != 0UL)
            {
                Console.WriteLine($"{"Total data used",-24}{InteractionHelper.HumanReadableDataString1024(totalBytesUsed)}");
            }

            if (totalBytesRemaining != 0UL)
            {
                Console.WriteLine($"{"Total data remaining",-24}{InteractionHelper.HumanReadableDataString1024(totalBytesRemaining)}");
            }

            Console.WriteLine();

            // by group
            Console.WriteLine("Data usage by group");

            if (recordsByGroup.All(x => x.bytesRemaining == 0UL)) // Omit data remaining column if no data.
            {
                ConsoleHelper.PrintTableBorder(groupNameFieldWidth, 11);
                Console.WriteLine($"|{"Group".PadRight(groupNameFieldWidth)}|{"Data Used",11}|");
                ConsoleHelper.PrintTableBorder(groupNameFieldWidth, 11);

                foreach (var(group, bytesUsed, _) in recordsByGroup)
                {
                    Console.Write($"|{group.PadRight(groupNameFieldWidth)}|");

                    if (bytesUsed != 0UL)
                    {
                        Console.WriteLine($"{InteractionHelper.HumanReadableDataString1024(bytesUsed),11}|");
                    }
                    else
                    {
                        Console.WriteLine($"{string.Empty,11}|");
                    }
                }

                ConsoleHelper.PrintTableBorder(groupNameFieldWidth, 11);
            }
            else
            {
                ConsoleHelper.PrintTableBorder(groupNameFieldWidth, 11, 16);
                Console.WriteLine($"|{"Group".PadRight(groupNameFieldWidth)}|{"Data Used",11}|{"Data Remaining",16}|");
                ConsoleHelper.PrintTableBorder(groupNameFieldWidth, 11, 16);

                foreach (var(group, bytesUsed, bytesRemaining) in recordsByGroup)
                {
                    Console.Write($"|{group.PadRight(groupNameFieldWidth)}|");

                    if (bytesUsed != 0UL)
                    {
                        Console.Write($"{InteractionHelper.HumanReadableDataString1024(bytesUsed),11}|");
                    }
                    else
                    {
                        Console.Write($"{string.Empty,11}|");
                    }

                    if (bytesRemaining != 0UL)
                    {
                        Console.WriteLine($"{InteractionHelper.HumanReadableDataString1024(bytesRemaining),16}|");
                    }
                    else
                    {
                        Console.WriteLine($"{string.Empty,16}|");
                    }
                }

                ConsoleHelper.PrintTableBorder(groupNameFieldWidth, 11, 16);
            }

            Console.WriteLine();

            // by user
            Console.WriteLine("Data usage by user");

            if (recordsByUser.All(x => x.bytesRemaining == 0UL)) // Omit data remaining column if no data.
            {
                ConsoleHelper.PrintTableBorder(usernameFieldWidth, 11);
                Console.WriteLine($"|{"User".PadRight(usernameFieldWidth)}|{"Data Used",11}|");
                ConsoleHelper.PrintTableBorder(usernameFieldWidth, 11);

                foreach (var(username, bytesUsed, _) in recordsByUser)
                {
                    Console.Write($"|{username.PadRight(usernameFieldWidth)}|");

                    if (bytesUsed != 0UL)
                    {
                        Console.WriteLine($"{InteractionHelper.HumanReadableDataString1024(bytesUsed),11}|");
                    }
                    else
                    {
                        Console.WriteLine($"{string.Empty,11}|");
                    }
                }

                ConsoleHelper.PrintTableBorder(usernameFieldWidth, 11);
            }
            else
            {
                ConsoleHelper.PrintTableBorder(usernameFieldWidth, 11, 16);
                Console.WriteLine($"|{"User".PadRight(usernameFieldWidth)}|{"Data Used",11}|{"Data Remaining",16}|");
                ConsoleHelper.PrintTableBorder(usernameFieldWidth, 11, 16);

                foreach (var(username, bytesUsed, bytesRemaining) in recordsByUser)
                {
                    Console.Write($"|{username.PadRight(usernameFieldWidth)}|");

                    if (bytesUsed != 0UL)
                    {
                        Console.Write($"{InteractionHelper.HumanReadableDataString1024(bytesUsed),11}|");
                    }
                    else
                    {
                        Console.Write($"{string.Empty,11}|");
                    }

                    if (bytesRemaining != 0UL)
                    {
                        Console.WriteLine($"{InteractionHelper.HumanReadableDataString1024(bytesRemaining),16}|");
                    }
                    else
                    {
                        Console.WriteLine($"{string.Empty,16}|");
                    }
                }

                ConsoleHelper.PrintTableBorder(usernameFieldWidth, 11, 16);
            }

            // CSV
            if (!string.IsNullOrEmpty(csvOutdir))
            {
                var(dataUsageByGroup, dataUsageByUser) = ReportHelper.GenerateDataUsageCSV(recordsByGroup, recordsByUser);

                try
                {
                    _ = Directory.CreateDirectory(csvOutdir);

                    var writeDataUsageByGroupTask = File.WriteAllTextAsync($"{csvOutdir}/data-usage-by-group.csv", dataUsageByGroup, cancellationToken);
                    var writeDataUsageByUserTask  = File.WriteAllTextAsync($"{csvOutdir}/data-usage-by-user.csv", dataUsageByUser, cancellationToken);

                    await Task.WhenAll(writeDataUsageByGroupTask, writeDataUsageByUserTask);

                    Console.WriteLine();
                    Console.WriteLine($"Written to {csvOutdir}/data-usage-by-group.csv");
                    Console.WriteLine($"Written to {csvOutdir}/data-usage-by-user.csv");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error when saving CSV: {ex.Message}");
                }
            }

            return(0);
        }